From ba1c49e23abcf138a4e048e25c6c0d01cf17a885 Mon Sep 17 00:00:00 2001 From: Faryan Rezagholi Date: Fri, 28 Dec 2018 18:11:26 +0100 Subject: [PATCH 001/157] rearranged items and added/replaced icons --- mRemoteV1/Properties/Resources.Designer.cs | 30 ++ mRemoteV1/Properties/Resources.resx | 9 + mRemoteV1/Resources/Images/tab_add.png | Bin 0 -> 488 bytes mRemoteV1/Resources/Images/tab_delete.png | Bin 0 -> 493 bytes mRemoteV1/Resources/Images/tab_edit.png | Bin 0 -> 580 bytes .../UI/Window/ConnectionWindow.Designer.cs | 437 +++++++++--------- mRemoteV1/UI/Window/ConnectionWindow.resx | 68 +-- mRemoteV1/mRemoteV1.csproj | 3 + 8 files changed, 295 insertions(+), 252 deletions(-) create mode 100644 mRemoteV1/Resources/Images/tab_add.png create mode 100644 mRemoteV1/Resources/Images/tab_delete.png create mode 100644 mRemoteV1/Resources/Images/tab_edit.png diff --git a/mRemoteV1/Properties/Resources.Designer.cs b/mRemoteV1/Properties/Resources.Designer.cs index 1b038fe66..023c329f1 100644 --- a/mRemoteV1/Properties/Resources.Designer.cs +++ b/mRemoteV1/Properties/Resources.Designer.cs @@ -1347,6 +1347,36 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tab_add { + get { + object obj = ResourceManager.GetObject("tab_add", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tab_delete { + get { + object obj = ResourceManager.GetObject("tab_delete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tab_edit { + get { + object obj = ResourceManager.GetObject("tab_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// diff --git a/mRemoteV1/Properties/Resources.resx b/mRemoteV1/Properties/Resources.resx index 3289c14e0..00ca3ee3c 100644 --- a/mRemoteV1/Properties/Resources.resx +++ b/mRemoteV1/Properties/Resources.resx @@ -547,4 +547,13 @@ ..\Resources\Images\mRemoteNG.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Images\tab_add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Images\tab_delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Images\tab_edit.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/tab_add.png b/mRemoteV1/Resources/Images/tab_add.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b99364a0625f00a764993293f615cc5679b72a GIT binary patch literal 488 zcmVP)a!RbZ^nygOjY zvaEgmwz2N_`+TjfUI2su5O03fI=3GN zO-DxyfY)uofj}vRZ5#J+ElHI?A*K4L!FxreG+Of^;j>jrB82=(AcRCIi81=y>WNH@ z%WRC|bAfWDj8}GRun?h8$n^AdF*G#bidPlPiBA#-q@JRT_(tjU^l_TnC4PNQQ?cK< zK{}l!ozDLFW@ou==4Pg`rH#LBisPFd#s??Z*^7WN=GQg5GHfE(Tc#HK$)FiqXft*F z#C#!FO5Mi@99aMa4lQnTNq|ya1TW@gEuM_gfac(8lLn!QCe8qYqTX>HUu+Km^FSj| e1UBOv_sg$~0hzRbE)Q}50000VjOibLw0u`97udk^oE-nJ*FfxKk zC>udT*o+LXU%yp4efr{5AO~)Mh>#FJ!=pzp8Gir%3-KEh6I>Gr!}u&LEDX}p!eBjc zFF*hz12Z!-!{5LE;fj$BK^VXcWHY0N0nA2bW)`3V1{4kGG&3`ZX2LW8BnXoH|DOe` z?Z1w%Vfc1rIm54K4;WsHN-*$Bn*;SGGBD1YH}AiKf-Hlco;E!25CI0^zuC2r;rrQ* z4662l4D5>94Bs#9Vz_o>FT;IqU5EjM;!J!~6@z1HDFf%-0}KpLk1#Os3oyK4k!Lu4 z>^cJjC@&Dgdz@JQ{X4tvKQee9-48WwCz=RY_ZJ~6X0ynn~YaOWu_Fv1z8F%p}dk4DHUL_z|9*cLd@B00000NkvXXu0mjfcQ48A literal 0 HcmV?d00001 diff --git a/mRemoteV1/Resources/Images/tab_edit.png b/mRemoteV1/Resources/Images/tab_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..4c09c0fd702ab11802c4b14cf51aa478ab8e3504 GIT binary patch literal 580 zcmV-K0=xZ*P)GaTv$cZ`CS^eoMHio&-;eKy=l49%&jMKf1j|1aEQ}pE z9vwP~`nZefyGNMm+u!`#;l+tPjhbL(W%en2%J6Y^6!}W+d-KxaaMT#QHQ;AF8}1+% zx=3kp98K({7<|N+gp1(4HhoJF_WNbhY1Jf?sW87uY=q^|1a;A#G{vLic;vEaqaB!F2-Lh}}&E>lF*Y?BG6Ki$V|MM6AieLky^#zer STRB|-00002.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 17, 17 - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAmlJREFUOE+lVN1L - k1EcPv9Ft06mzOF0m27qdHOb040cRpubc3PEyKQhTktbVuJAWkUKUr5FkWXSh5pObKTmJK1WYFdjBnVR - 7MXogwIvkurCi552DpwoCBK8eC6f3/PFOQQA2Q3IjVv3ri6vJrdXn61h5ekaEo+fYz7xBPcXHmE6voQ7 - M/MYm5jDlZvTuHjtLgYvjSM6PIq+s8J2e3d/iGTJP1/u24t3sT0wzxnw6s3Gf/H67QY+fdlE6NTgCFlN - vsDX5Yf48V7Agw9xfPy8uSNsffuO4PEzAqGWVSoV1Go1SkpKUFpaCo1GA61Wi7KyMlRUVKCyshJVVVXQ - 6/Worq6GyWRCTU0NWrsiAllaSTJSTk4OJBIJcnNzIZVKkZeXh/z8fMhkMsjlchQWFkKhUKC4uJgJ1tXV - oTsyLBBaGD+QSqUwOTm54wPZDgQSX1xhNrliJpNBT0/PP1VpTB6xvr4eh8NRgczEEyxbQUEB0uk0YrEY - ioqKflvlJN5JeXk5dDodGhoacLCzXyATswswm82MoFQqWT5eJiVRcBItk4pROBwOHGjvFcj4VBxWq/Uv - Em+fKvEFDAYDW8BoNLIVXC4XfG3dAhm9PQuah6rQLijpz8n4bNQlhcViQW1tLZqamuAOhARyeWyK5eHW - uBJVoQS6NyfR6ShsNhu8Xi+c/qBAzo9c36J5nE4nGhsbmTW3280UKDweD5qbmxnB5/OhpaWFwe/3w+4O - DJHO3oHOvuiF9b7oiBgeGBaP9g+JHSfOicFjp8VDXREx0HFS9AfDorf1iJi1LGZVxf3eNtHuCqxb7C7j - rp4y/QZ+AXhAQe1Sf9VzAAAAAElFTkSuQmCC - - + - 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 + TkSuQmCC + + + 59 \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 60aec3310..2befb3206 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -1032,6 +1032,9 @@ + + + Designer PreserveNewest From 8c91b37dc8e08864e71392b859dd30a92f0b6822 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Sat, 29 Dec 2018 01:40:18 -0500 Subject: [PATCH 002/157] First removal Magic library is removed, basic tabbing functions are on, but all other functions are commented. Some code is lifted from DockPanelSuite in MremoteNGAutoHideStrip to change the behavior and looks for Mremote . --- mRemoteNG.Specs/App.config | 2 +- mRemoteV1/Connection/ConnectionInitiator.cs | 77 +- mRemoteV1/Connection/IConnectionInitiator.cs | 5 +- .../Http/Connection.Protocol.HTTPBase.cs | 12 +- .../Connection/Protocol/IntegratedProgram.cs | 4 +- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 73 +- mRemoteV1/Connection/Protocol/PuttyBase.cs | 4 +- .../Connection/Protocol/RDP/RdpProtocol.cs | 11 +- mRemoteV1/Properties/Resources.Designer.cs | 30 + mRemoteV1/Properties/Resources.resx | 9 + mRemoteV1/Resources/Images/TabExit.png | Bin 0 -> 2933 bytes mRemoteV1/Resources/Images/TabOption.png | Bin 0 -> 256 bytes mRemoteV1/Resources/Images/TabOverflow.png | Bin 0 -> 259 bytes mRemoteV1/Themes/MremoteNGThemeBase.cs | 14 +- mRemoteV1/Tools/MiscTools.cs | 4 +- mRemoteV1/Tree/PreviousSessionOpener.cs | 4 +- mRemoteV1/UI/Forms/frmMain.cs | 28 +- mRemoteV1/UI/Menu/MainFileMenu.cs | 14 +- mRemoteV1/UI/Panels/PanelAdder.cs | 17 +- mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs | 38 + mRemoteV1/UI/Tabs/ConnectionTab.cs | 106 ++ mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 1585 +++++++++++++++++ mRemoteV1/UI/Tabs/Enums.cs | 376 ++++ mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs | 544 ++++++ .../UI/Window/ConnectionWindow.Designer.cs | 27 +- mRemoteV1/UI/Window/ConnectionWindow.cs | 226 ++- mRemoteV1/app.config | 4 +- mRemoteV1/mRemoteV1.csproj | 16 +- 28 files changed, 2982 insertions(+), 248 deletions(-) create mode 100644 mRemoteV1/Resources/Images/TabExit.png create mode 100644 mRemoteV1/Resources/Images/TabOption.png create mode 100644 mRemoteV1/Resources/Images/TabOverflow.png create mode 100644 mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs create mode 100644 mRemoteV1/UI/Tabs/ConnectionTab.cs create mode 100644 mRemoteV1/UI/Tabs/DockPaneStripNG.cs create mode 100644 mRemoteV1/UI/Tabs/Enums.cs create mode 100644 mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs diff --git a/mRemoteNG.Specs/App.config b/mRemoteNG.Specs/App.config index 7695b8383..902fa1f5f 100644 --- a/mRemoteNG.Specs/App.config +++ b/mRemoteNG.Specs/App.config @@ -7,7 +7,7 @@ - + diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 62099995c..817d1d2ea 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -8,7 +8,7 @@ using mRemoteNG.UI.Window; using System; using System.Collections.Generic; using System.Windows.Forms; -using TabPage = Crownwood.Magic.Controls.TabPage; + namespace mRemoteNG.Connection @@ -18,10 +18,35 @@ namespace mRemoteNG.Connection private readonly PanelAdder _panelAdder = new PanelAdder(); private readonly List _activeConnections = new List(); - /// - /// List of unique IDs of the currently active connections - /// public IEnumerable ActiveConnections => _activeConnections; + public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) + { + OpenConnection(containerInfo, force, null); + } + + public void OpenConnection(ConnectionInfo connectionInfo) + { + try + { + OpenConnection(connectionInfo, ConnectionInfo.Force.None); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); + } + } + + public void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force) + { + try + { + OpenConnection(connectionInfo, force, null); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); + } + } public bool SwitchToOpenConnection(ConnectionInfo connectionInfo) { @@ -30,13 +55,12 @@ namespace mRemoteNG.Connection var connectionWindow = (ConnectionWindow)interfaceControl.FindForm(); connectionWindow?.Focus(); var findForm = (ConnectionWindow)interfaceControl.FindForm(); - findForm?.Show(FrmMain.Default.pnlDock); - var tabPage = (TabPage)interfaceControl.Parent; - tabPage.Selected = true; + findForm?.Show(FrmMain.Default.pnlDock); return true; } - public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force) + #region Private + private void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm) { var children = containerInfo.Children; if (children.Count == 0) return; @@ -44,13 +68,13 @@ namespace mRemoteNG.Connection { var childAsContainer = child as ContainerInfo; if (childAsContainer != null) - OpenConnection(childAsContainer, force); + OpenConnection(childAsContainer, force, conForm); else - OpenConnection(child, force); + OpenConnection(child, force, conForm); } } - public void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) + private void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm) { try { @@ -73,7 +97,7 @@ namespace mRemoteNG.Connection var connectionPanel = SetConnectionPanel(connectionInfo, force); if (string.IsNullOrEmpty(connectionPanel)) return; - var connectionForm = SetConnectionForm(connectionPanel); + var connectionForm = SetConnectionForm(conForm, connectionPanel); var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm); SetConnectionFormEventHandlers(newProtocol, connectionForm); SetConnectionEventHandlers(newProtocol); @@ -102,8 +126,7 @@ namespace mRemoteNG.Connection Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); } } - - #region Private + private static void StartPreConnectionExternalApp(ConnectionInfo connectionInfo) { if (connectionInfo.PreExtApp == "") return; @@ -118,7 +141,7 @@ namespace mRemoteNG.Connection { var window = Runtime.WindowList[i] as ConnectionWindow; var connectionWindow = window; - if (connectionWindow?.TabController == null) continue; + /* if (connectionWindow?.TabController == null) continue; foreach (TabPage t in connectionWindow.TabController.TabPages) { var ic = t.Controls[0] as InterfaceControl; @@ -127,7 +150,7 @@ namespace mRemoteNG.Connection { return ic; } - } + }*/ } return null; } @@ -154,22 +177,22 @@ namespace mRemoteNG.Connection return connectionPanel; } - private ConnectionWindow SetConnectionForm(string connectionPanelName) + private Form SetConnectionForm(Form conForm, string connectionPanel) { - var connectionForm = Runtime.WindowList.FromString(connectionPanelName) as ConnectionWindow; + var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel); if (connectionForm == null) - connectionForm = _panelAdder.AddPanel(connectionPanelName); + connectionForm = _panelAdder.AddPanel(connectionPanel); else - connectionForm.Show(FrmMain.Default.pnlDock); + ((ConnectionWindow)connectionForm).Show(FrmMain.Default.pnlDock); connectionForm.Focus(); return connectionForm; } - private static Control SetConnectionContainer(ConnectionInfo connectionInfo, ConnectionWindow connectionForm) + private static Control SetConnectionContainer(ConnectionInfo connectionInfo, Form connectionForm) { - Control connectionContainer = connectionForm.AddConnectionTab(connectionInfo); + Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo); if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer; @@ -177,18 +200,18 @@ namespace mRemoteNG.Connection if(extT == null) return connectionContainer; - if (extT.Icon != null) - ((TabPage)connectionContainer).Icon = extT.Icon; + if(extT.Icon != null) + ((ConnectionWindow)connectionContainer).Icon = extT.Icon; return connectionContainer; } - private static void SetConnectionFormEventHandlers(ProtocolBase newProtocol, ConnectionWindow connectionForm) + private static void SetConnectionFormEventHandlers(ProtocolBase newProtocol, Form connectionForm) { - newProtocol.Closed += connectionForm.Prot_Event_Closed; + newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed; } - private void SetConnectionEventHandlers(ProtocolBase newProtocol) + private void SetConnectionEventHandlers(ProtocolBase newProtocol) { newProtocol.Disconnected += Prot_Event_Disconnected; newProtocol.Connected += Prot_Event_Connected; diff --git a/mRemoteV1/Connection/IConnectionInitiator.cs b/mRemoteV1/Connection/IConnectionInitiator.cs index 0023d27a8..5a0ff1d32 100644 --- a/mRemoteV1/Connection/IConnectionInitiator.cs +++ b/mRemoteV1/Connection/IConnectionInitiator.cs @@ -1,15 +1,14 @@ using mRemoteNG.Container; -using System.Collections.Generic; namespace mRemoteNG.Connection { public interface IConnectionInitiator { - IEnumerable ActiveConnections { get; } + void OpenConnection(ConnectionInfo connectionInfo); void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None); - void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None); + void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force); bool SwitchToOpenConnection(ConnectionInfo connectionInfo); } diff --git a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs index 75206bacb..6b7f9ba36 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs @@ -3,7 +3,7 @@ using System.Windows.Forms; using Gecko; using mRemoteNG.Tools; using mRemoteNG.App; -using TabPage = Crownwood.Magic.Controls.TabPage; + namespace mRemoteNG.Connection.Protocol.Http { @@ -47,7 +47,7 @@ namespace mRemoteNG.Connection.Protocol.Http try { var objTabPage = InterfaceControl.Parent as TabPage; - if (objTabPage != null) tabTitle = objTabPage.Title; + // if (objTabPage != null) tabTitle = objTabPage.Title; } catch (Exception) { @@ -204,14 +204,14 @@ namespace mRemoteNG.Connection.Protocol.Http } } - if (!string.IsNullOrEmpty(tabTitle)) + /* if (!string.IsNullOrEmpty(tabTitle)) { tabP.Title = tabTitle + @" - " + shortTitle; } else { tabP.Title = shortTitle; - } + }*/ } catch (Exception ex) { @@ -252,14 +252,14 @@ namespace mRemoteNG.Connection.Protocol.Http } } - if (!string.IsNullOrEmpty(tabTitle)) + /* if (!string.IsNullOrEmpty(tabTitle)) { tabP.Title = tabTitle + @" - " + shortTitle; } else { tabP.Title = shortTitle; - } + }*/ } catch (Exception ex) { diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index 0911dd519..d3c27c0c8 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -115,8 +115,8 @@ namespace mRemoteNG.Connection.Protocol Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex); } } - - protected override void Resize(object sender, EventArgs e) + + public override void Resize(object sender, EventArgs e) { try { diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 1a90c77e5..022d532d6 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -7,7 +7,7 @@ using System.Windows.Forms; namespace mRemoteNG.Connection.Protocol { - public abstract class ProtocolBase: IDisposable + public abstract class ProtocolBase { #region Private Variables @@ -27,8 +27,8 @@ namespace mRemoteNG.Connection.Protocol protected UI.Window.ConnectionWindow ConnectionWindow { - get => _connectionWindow; - private set + get { return _connectionWindow; } + private set { _connectionWindow = value; _connectionWindow.ResizeBegin += ResizeBegin; @@ -39,11 +39,12 @@ namespace mRemoteNG.Connection.Protocol public InterfaceControl InterfaceControl { - get => _interfaceControl; - set + get { return _interfaceControl; } + set { _interfaceControl = value; - ConnectionWindow = _interfaceControl.GetContainerControl() as UI.Window.ConnectionWindow; + //This is ugly + ConnectionWindow = _interfaceControl.Parent.Parent.Parent.Parent.Parent as UI.Window.ConnectionWindow; } } @@ -82,15 +83,15 @@ namespace mRemoteNG.Connection.Protocol } } - protected virtual void ResizeBegin(object sender, EventArgs e) + public virtual void ResizeBegin(object sender, EventArgs e) { } - protected virtual void Resize(object sender, EventArgs e) + public virtual void Resize(object sender, EventArgs e) { } - protected virtual void ResizeEnd(object sender, EventArgs e) + public virtual void ResizeEnd(object sender, EventArgs e) { } @@ -222,64 +223,50 @@ namespace mRemoteNG.Connection.Protocol Control.Dispose(); } } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - tmrReconnect.Dispose(); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } #endregion - + #region Events - public delegate void ConnectingEventHandler(object sender); + public delegate void ConnectingEventHandler(object sender); public event ConnectingEventHandler Connecting { - add => ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); - remove => ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); - } + add { ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); } + remove { ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); } + } public delegate void ConnectedEventHandler(object sender); public event ConnectedEventHandler Connected { - add => ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); - remove => ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); - } + add { ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); } + remove { ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); } + } public delegate void DisconnectedEventHandler(object sender, string disconnectedMessage, int? reasonCode); public event DisconnectedEventHandler Disconnected { - add => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); - remove => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); - } + add { DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); } + remove { DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); } + } public delegate void ErrorOccuredEventHandler(object sender, string errorMessage, int? errorCode); public event ErrorOccuredEventHandler ErrorOccured { - add => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); - remove => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); - } + add { ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); } + remove { ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); } + } public delegate void ClosingEventHandler(object sender); public event ClosingEventHandler Closing { - add => ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); - remove => ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); - } + add { ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); } + remove { ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); } + } public delegate void ClosedEventHandler(object sender); public event ClosedEventHandler Closed { - add => ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); - remove => ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); - } + add { ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); } + remove { ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); } + } public void Event_Closing(object sender) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index dc9805194..665d75177 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -193,8 +193,8 @@ namespace mRemoteNG.Connection.Protocol Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyFocusFailed + Environment.NewLine + ex.Message, true); } } - - protected override void Resize(object sender, EventArgs e) + + public override void Resize(object sender, EventArgs e) { try { diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs index 5420315a0..40317306c 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs @@ -251,13 +251,12 @@ namespace mRemoteNG.Connection.Protocol.RDP } private Size _controlBeginningSize; - - protected override void ResizeBegin(object sender, EventArgs e) + public override void ResizeBegin(object sender, EventArgs e) { _controlBeginningSize = Control.Size; } - - protected override void Resize(object sender, EventArgs e) + + public override void Resize(object sender, EventArgs e) { if (DoResize() && _controlBeginningSize.IsEmpty) { @@ -265,8 +264,8 @@ namespace mRemoteNG.Connection.Protocol.RDP } base.Resize(sender, e); } - - protected override void ResizeEnd(object sender, EventArgs e) + + public override void ResizeEnd(object sender, EventArgs e) { DoResize(); if (!(Control.Size == _controlBeginningSize)) diff --git a/mRemoteV1/Properties/Resources.Designer.cs b/mRemoteV1/Properties/Resources.Designer.cs index 1b038fe66..7cc5a2a0b 100644 --- a/mRemoteV1/Properties/Resources.Designer.cs +++ b/mRemoteV1/Properties/Resources.Designer.cs @@ -1357,6 +1357,36 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap TabExit { + get { + object obj = ResourceManager.GetObject("TabExit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap TabOption { + get { + object obj = ResourceManager.GetObject("TabOption", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap TabOverflow { + get { + object obj = ResourceManager.GetObject("TabOverflow", 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 3289c14e0..4b2b35b80 100644 --- a/mRemoteV1/Properties/Resources.resx +++ b/mRemoteV1/Properties/Resources.resx @@ -538,6 +538,15 @@ ..\Resources\Icons\Tab_Icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Images\TabOption.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Images\TabOverflow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Images\TabExit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\Icons\Update_Icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/mRemoteV1/Resources/Images/TabExit.png b/mRemoteV1/Resources/Images/TabExit.png new file mode 100644 index 0000000000000000000000000000000000000000..a70a2aba4ed4786234b7cab95f5a7bc1231863f2 GIT binary patch literal 2933 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 f)d(JIiJfq;Ix00000NkvXXu0mjfp?`DZ literal 0 HcmV?d00001 diff --git a/mRemoteV1/Resources/Images/TabOption.png b/mRemoteV1/Resources/Images/TabOption.png new file mode 100644 index 0000000000000000000000000000000000000000..455c453a48d649c681b1c7504a7680ef24c3d1f0 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q2qYMeauhWIDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadRT z_H=O!;kcgsLD-%mA19M#i6DtD)!K>SzplHa=PsvQH#H}HrgD(Q8fx*+& K&t;ucLK6TA^F&Vo literal 0 HcmV?d00001 diff --git a/mRemoteV1/Resources/Images/TabOverflow.png b/mRemoteV1/Resources/Images/TabOverflow.png new file mode 100644 index 0000000000000000000000000000000000000000..84619ba1396d9eed499873acd1732efd0b32ba7a GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q2qYMeauhWIDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadRT z^K@|x;kcgs !(node is ContainerInfo)); - var previouslyOpenedConnections = connectionInfoList + /* var previouslyOpenedConnections = connectionInfoList .Where(item => item.PleaseConnect && // ignore items that have already connected @@ -30,7 +30,7 @@ namespace mRemoteNG.Tree foreach (var connectionInfo in previouslyOpenedConnections) { _connectionInitiator.OpenConnection(connectionInfo); - } + }*/ } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 9cb3d3831..5fefe61ff 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -178,8 +178,13 @@ namespace mRemoteNG.UI.Forms ApplyLanguage(); Opacity = 1; + //Fix MagicRemove , revision on panel strategy for mdi + + //Fix MagicRemove, this is a setting + pnlDock.ShowDocumentIcon = true; + //Fix missing general panel at the first run - if (Settings.Default.CreateEmptyPanelOnStartUp) + /* if (Settings.Default.CreateEmptyPanelOnStartUp) { var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) ? Settings.Default.StartUpPanelName @@ -188,7 +193,7 @@ namespace mRemoteNG.UI.Forms var panelAdder = new PanelAdder(); if (!panelAdder.DoesPanelExist(panelName)) panelAdder.AddPanel(panelName); - } + }*/ FrmSplashScreen frmSplashScreen = FrmSplashScreen.getInstance(); frmSplashScreen.Close(); @@ -339,8 +344,9 @@ namespace mRemoteNG.UI.Forms foreach (BaseWindow window in Runtime.WindowList) { var connectionWindow = window as ConnectionWindow; + //fix MagicRemove, this is not working as per internal agregation of documents if (connectionWindow != null) - openConnections = openConnections + connectionWindow.TabController.TabPages.Count; + openConnections = pnlDock.DocumentsCount; } if (openConnections > 0 && (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All | (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & openConnections > 1) || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Exit)) @@ -445,9 +451,9 @@ namespace mRemoteNG.UI.Forms } else if (controlThatWasClicked.CanSelect || controlThatWasClicked is MenuStrip || - controlThatWasClicked is ToolStrip || + controlThatWasClicked is ToolStrip )/*|| controlThatWasClicked is Crownwood.Magic.Controls.TabControl || - controlThatWasClicked is Crownwood.Magic.Controls.InertButton) + controlThatWasClicked is Crownwood.Magic.Controls.InertButton)*/ { // Simulate a mouse event since one wasn't generated by Windows SimulateClick(controlThatWasClicked); @@ -511,15 +517,15 @@ namespace mRemoteNG.UI.Forms private void ActivateConnection() { - var w = pnlDock.ActiveDocument as ConnectionWindow; - if (w?.TabController.SelectedTab == null) return; - var tab = w.TabController.SelectedTab; - var ifc = (InterfaceControl)tab.Tag; - + var w = pnlDock.Controls[0] as DockPanel; + if (w?.ActiveDocument == null) return; + var tab = w.ActiveDocument as ConnectionTab; + var ifc = (InterfaceControl)tab.ActiveControl; if (ifc == null) return; ifc.Protocol.Focus(); - ((ConnectionWindow) ifc.FindForm())?.RefreshInterfaceController(); + var conFormWindow = ifc.FindForm(); + ((ConnectionTab)conFormWindow)?.RefreshInterfaceController(); } private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) diff --git a/mRemoteV1/UI/Menu/MainFileMenu.cs b/mRemoteV1/UI/Menu/MainFileMenu.cs index 85e08c88c..da0e13162 100644 --- a/mRemoteV1/UI/Menu/MainFileMenu.cs +++ b/mRemoteV1/UI/Menu/MainFileMenu.cs @@ -450,14 +450,14 @@ namespace mRemoteNG.UI.Menu return; var icList = new List(); - foreach (Crownwood.Magic.Controls.TabPage tab in connectionWindow.TabController.TabPages) - { - var tag = tab.Tag as InterfaceControl; - if (tag != null) + /* foreach (Crownwood.Magic.Controls.TabPage tab in connectionWindow.TabController.TabPages) { - icList.Add(tag); - } - } + var tag = tab.Tag as InterfaceControl; + if (tag != null) + { + icList.Add(tag); + } + }*/ foreach (var i in icList) { diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index f835275dc..ec7a43986 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -13,7 +13,7 @@ namespace mRemoteNG.UI.Panels { public class PanelAdder { - public ConnectionWindow AddPanel(string title = "", bool noTabber = false) + public Form AddPanel(string title = "", bool noTabber = false) { try { @@ -44,9 +44,9 @@ namespace mRemoteNG.UI.Panels private static void PrepareTabControllerSupport(bool noTabber, ConnectionWindow connectionForm) { - if (noTabber) + /* if (noTabber) connectionForm.TabController.Dispose(); - else + else*/ Runtime.WindowList.Add(connectionForm); } @@ -96,12 +96,13 @@ namespace mRemoteNG.UI.Panels try { var conW = (ConnectionWindow)((ToolStripMenuItem)sender).Tag; - var nTitle = ""; - using (FrmInputBox frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle + ":", ref nTitle)) + + var nTitle = ""; + new FrmInputBox(Language.strNewTitle, Language.strNewTitle + ":", ref nTitle); + + if (!string.IsNullOrEmpty(nTitle)) { - DialogResult dr = frmInputBox.ShowDialog(); - if (dr == DialogResult.OK && string.IsNullOrEmpty(frmInputBox.returnValue)) - conW.SetFormText(frmInputBox.returnValue); + conW.SetFormText(nTitle.Replace("&", "&&")); } } catch (Exception ex) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs new file mode 100644 index 000000000..644cd91c7 --- /dev/null +++ b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs @@ -0,0 +1,38 @@ +namespace mRemoteNG.UI.Forms +{ + partial class ConnectionTab + { + /// + /// Required designer variable. + /// + 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 Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Text = "ConnectionTab"; + } + + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs new file mode 100644 index 000000000..4cd1ce65d --- /dev/null +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -0,0 +1,106 @@ +using mRemoteNG.App; +using mRemoteNG.App.Info; +using mRemoteNG.Config; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.VNC; +using mRemoteNG.UI.TaskDialog; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Security.Permissions; +using System.Text; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; + + +namespace mRemoteNG.UI.Forms +{ + public partial class ConnectionTab : DockContent + { + + public ConnectionTab() + { + InitializeComponent(); + this.FormClosing += formClosingEventHandler; + } + + + + + #region TabEvents + private void formClosingEventHandler(object sender, FormClosingEventArgs e) + { + + try + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, this.TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + return; + } + } + var interfaceControl = (InterfaceControl)this.Tag; + interfaceControl.Protocol.Close(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.CloseConnectionTab() failed", ex); + } + + } + + + /* [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) + { + base.WndProc(ref m); + + int index = HitTest(); + if (DockPane.DockPanel.AllowEndUserDocking && index != -1) + { + IDockContent content = Tabs[index].Content; + if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) + content.DockHandler.IsFloat = !content.DockHandler.IsFloat; + } + + return; + } + + base.WndProc(ref m); + return; + } + */ + + + + #endregion + + #region HelperFunctions + public void RefreshInterfaceController() + { + try + { + var interfaceControl = this.Tag as InterfaceControl; + if (interfaceControl?.Info.Protocol == ProtocolType.VNC) + ((ProtocolVNC)interfaceControl.Protocol).RefreshScreen(); + } + catch (Exception ex) + { + App.Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); + } + } + #endregion + } +} diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs new file mode 100644 index 000000000..2d60e95c7 --- /dev/null +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -0,0 +1,1585 @@ +using mRemoteNG.Themes; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; + + +namespace mRemoteNG.UI.Tabs +{ + /// + /// This class is lifted from VS2005DockPaneStrip from DockPanelSuite and customized for MremoteNG + /// + internal class DockPaneStripNG : DockPaneStripBase + { + private class MremoteNGTab : Tab + { + public MremoteNGTab(IDockContent content) + : base(content) + { + } + + private int m_tabX; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + private int m_maxWidth; + public int MaxWidth + { + get { return m_maxWidth; } + set { m_maxWidth = value; } + } + + private bool m_flag; + protected internal bool Flag + { + get { return m_flag; } + set { m_flag = value; } + } + + private Rectangle? _rect; + + + } + + + protected override DockPaneStripBase.Tab CreateTab(IDockContent content) + { + return new MremoteNGTab(content); + } + + private sealed class InertButton : InertButtonBase + { + private Bitmap m_image0, m_image1; + + public InertButton(Bitmap image0, Bitmap image1) + : base() + { + m_image0 = image0; + m_image1 = image1; + } + + private int m_imageCategory = 0; + public int ImageCategory + { + get { return m_imageCategory; } + set + { + if (m_imageCategory == value) + return; + + m_imageCategory = value; + Invalidate(); + } + } + + public override Bitmap Image + { + get { return ImageCategory == 0 ? m_image0 : m_image1; } + } + + public override Bitmap HoverImage + { + get { return null; } + } + + public override Bitmap PressImage + { + get { return null; } + } + } + + #region Constants + + private const int _ToolWindowStripGapTop = 0; + private const int _ToolWindowStripGapBottom = 1; + private const int _ToolWindowStripGapLeft = 0; + private const int _ToolWindowStripGapRight = 0; + private const int _ToolWindowImageHeight = 16; + private const int _ToolWindowImageWidth = 16; + private const int _ToolWindowImageGapTop = 3; + private const int _ToolWindowImageGapBottom = 1; + private const int _ToolWindowImageGapLeft = 2; + private const int _ToolWindowImageGapRight = 0; + private const int _ToolWindowTextGapRight = 3; + private const int _ToolWindowTabSeperatorGapTop = 3; + private const int _ToolWindowTabSeperatorGapBottom = 3; + + private const int _DocumentStripGapTop = 0; + private const int _DocumentStripGapBottom = 1; + private const int _DocumentTabMaxWidth = 200; + private const int _DocumentButtonGapTop = 4; + private const int _DocumentButtonGapBottom = 4; + private const int _DocumentButtonGapBetween = 0; + private const int _DocumentButtonGapRight = 3; + private const int _DocumentTabGapTop = 3; + private const int _DocumentTabGapLeft = 3; + private const int _DocumentTabGapRight = 3; + private const int _DocumentIconGapBottom = 2; + private const int _DocumentIconGapLeft = 8; + private const int _DocumentIconGapRight = 0; + private const int _DocumentIconHeight = 16; + private const int _DocumentIconWidth = 16; + private const int _DocumentTextGapRight = 3; + + #endregion + + #region Members + + private ContextMenuStrip m_selectMenu; + private static Bitmap m_imageButtonClose; + private InertButton m_buttonClose; + private static Bitmap m_imageButtonWindowList; + private static Bitmap m_imageButtonWindowListOverflow; + private InertButton m_buttonWindowList; + private IContainer m_components; + private ToolTip m_toolTip; + private Font m_font; + private Font m_boldFont; + private int m_startDisplayingTab = 0; + private int m_endDisplayingTab = 0; + private int m_firstDisplayingTab = 0; + private bool m_documentTabsOverflow = false; + private static string m_toolTipSelect; + private static string m_toolTipClose; + private bool m_closeButtonVisible = false; + private int _selectMenuMargin = 5; + + #endregion + + #region Properties + + private Rectangle TabStripRectangle + { + get + { + if (Appearance == DockPane.AppearanceStyle.Document) + return TabStripRectangle_Document; + else + return TabStripRectangle_ToolWindow; + } + } + + private Rectangle TabStripRectangle_ToolWindow + { + get + { + Rectangle rect = ClientRectangle; + return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); + } + } + + private Rectangle TabStripRectangle_Document + { + get + { + Rectangle rect = ClientRectangle; + return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height - DocumentStripGapTop - ToolWindowStripGapBottom); + } + } + + private Rectangle TabsRectangle + { + get + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return TabStripRectangle; + + Rectangle rectWindow = TabStripRectangle; + int x = rectWindow.X; + int y = rectWindow.Y; + int width = rectWindow.Width; + int height = rectWindow.Height; + + x += DocumentTabGapLeft; + width -= DocumentTabGapLeft + + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonClose.Width + + ButtonWindowList.Width + + 2 * DocumentButtonGapBetween; + + return new Rectangle(x, y, width, height); + } + } + + private ContextMenuStrip SelectMenu + { + get { return m_selectMenu; } + } + + public int SelectMenuMargin + { + get { return _selectMenuMargin; } + set { _selectMenuMargin = value; } + } + + private static Bitmap ImageButtonClose + { + get + { + if (m_imageButtonClose == null) + m_imageButtonClose = Resources.TabExit; + + return m_imageButtonClose; + } + } + + private InertButton ButtonClose + { + get + { + if (m_buttonClose == null) + { + m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += new EventHandler(Close_Click); + Controls.Add(m_buttonClose); + } + + return m_buttonClose; + } + } + + private static Bitmap ImageButtonWindowList + { + get + { + if (m_imageButtonWindowList == null) + m_imageButtonWindowList = Resources.TabOption; + + return m_imageButtonWindowList; + } + } + + private static Bitmap ImageButtonWindowListOverflow + { + get + { + if (m_imageButtonWindowListOverflow == null) + m_imageButtonWindowListOverflow = Resources.TabOverflow; + + return m_imageButtonWindowListOverflow; + } + } + + private InertButton ButtonWindowList + { + get + { + if (m_buttonWindowList == null) + { + m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); + m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); + m_buttonWindowList.Click += new EventHandler(WindowList_Click); + Controls.Add(m_buttonWindowList); + } + + return m_buttonWindowList; + } + } + + private static GraphicsPath GraphicsPath + { + get { return MremoteNGAutoHideStrip.GraphicsPath; } + } + + private IContainer Components + { + get { return m_components; } + } + + public Font TextFont + { + get { return DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; } + } + + private Font BoldFont + { + get + { + if (IsDisposed) + return null; + + if (m_boldFont == null) + { + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + else if (m_font != TextFont) + { + m_boldFont.Dispose(); + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + + return m_boldFont; + } + } + + private int StartDisplayingTab + { + get { return m_startDisplayingTab; } + set + { + m_startDisplayingTab = value; + Invalidate(); + } + } + + private int EndDisplayingTab + { + get { return m_endDisplayingTab; } + set { m_endDisplayingTab = value; } + } + + private int FirstDisplayingTab + { + get { return m_firstDisplayingTab; } + set { m_firstDisplayingTab = value; } + } + + private bool DocumentTabsOverflow + { + set + { + if (m_documentTabsOverflow == value) + return; + + m_documentTabsOverflow = value; + if (value) + ButtonWindowList.ImageCategory = 1; + else + ButtonWindowList.ImageCategory = 0; + } + } + + #region Customizable Properties + + private static int ToolWindowStripGapTop + { + get { return _ToolWindowStripGapTop; } + } + + private static int ToolWindowStripGapBottom + { + get { return _ToolWindowStripGapBottom; } + } + + private static int ToolWindowStripGapLeft + { + get { return _ToolWindowStripGapLeft; } + } + + private static int ToolWindowStripGapRight + { + get { return _ToolWindowStripGapRight; } + } + + private static int ToolWindowImageHeight + { + get { return _ToolWindowImageHeight; } + } + + private static int ToolWindowImageWidth + { + get { return _ToolWindowImageWidth; } + } + + private static int ToolWindowImageGapTop + { + get { return _ToolWindowImageGapTop; } + } + + private static int ToolWindowImageGapBottom + { + get { return _ToolWindowImageGapBottom; } + } + + private static int ToolWindowImageGapLeft + { + get { return _ToolWindowImageGapLeft; } + } + + private static int ToolWindowImageGapRight + { + get { return _ToolWindowImageGapRight; } + } + + private static int ToolWindowTextGapRight + { + get { return _ToolWindowTextGapRight; } + } + + private static int ToolWindowTabSeperatorGapTop + { + get { return _ToolWindowTabSeperatorGapTop; } + } + + private static int ToolWindowTabSeperatorGapBottom + { + get { return _ToolWindowTabSeperatorGapBottom; } + } + + private static string ToolTipClose + { + get + { + if (m_toolTipClose == null) + m_toolTipClose = Language.strRadioCloseWarnExit; + return m_toolTipClose; + } + } + + private static string ToolTipSelect + { + get + { + if (m_toolTipSelect == null) + m_toolTipSelect = Language.strTabsAndPanels; + return m_toolTipSelect; + } + } + + private TextFormatFlags ToolWindowTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + else + return textFormat; + } + } + + private static int DocumentStripGapTop + { + get { return _DocumentStripGapTop; } + } + + private static int DocumentStripGapBottom + { + get { return _DocumentStripGapBottom; } + } + + private TextFormatFlags DocumentTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft; + else + return textFormat; + } + } + + private static int DocumentTabMaxWidth + { + get { return _DocumentTabMaxWidth; } + } + + private static int DocumentButtonGapTop + { + get { return _DocumentButtonGapTop; } + } + + private static int DocumentButtonGapBottom + { + get { return _DocumentButtonGapBottom; } + } + + private static int DocumentButtonGapBetween + { + get { return _DocumentButtonGapBetween; } + } + + private static int DocumentButtonGapRight + { + get { return _DocumentButtonGapRight; } + } + + private static int DocumentTabGapTop + { + get { return _DocumentTabGapTop; } + } + + private static int DocumentTabGapLeft + { + get { return _DocumentTabGapLeft; } + } + + private static int DocumentTabGapRight + { + get { return _DocumentTabGapRight; } + } + + private static int DocumentIconGapBottom + { + get { return _DocumentIconGapBottom; } + } + + private static int DocumentIconGapLeft + { + get { return _DocumentIconGapLeft; } + } + + private static int DocumentIconGapRight + { + get { return _DocumentIconGapRight; } + } + + private static int DocumentIconWidth + { + get { return _DocumentIconWidth; } + } + + private static int DocumentIconHeight + { + get { return _DocumentIconHeight; } + } + + private static int DocumentTextGapRight + { + get { return _DocumentTextGapRight; } + } + + private static Pen PenToolWindowTabBorder + { + get { return SystemPens.GrayText; } + } + + private static Pen PenDocumentTabActiveBorder + { + get { return SystemPens.ControlDarkDark; } + } + + private static Pen PenDocumentTabInactiveBorder + { + get { return SystemPens.GrayText; } + } + + #endregion + + #endregion + + public DockPaneStripNG(DockPane pane) + : base(pane) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + + SuspendLayout(); + + + + m_components = new System.ComponentModel.Container(); + m_toolTip = new ToolTip(Components); + m_selectMenu = new ContextMenuStrip(Components); + pane.DockPanel.Theme.ApplyTo(m_selectMenu); + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Components.Dispose(); + if (m_boldFont != null) + { + m_boldFont.Dispose(); + m_boldFont = null; + } + } + base.Dispose(disposing); + } + + protected override int MeasureHeight() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return MeasureHeight_ToolWindow(); + else + return MeasureHeight_Document(); + } + + private int MeasureHeight_ToolWindow() + { + if (DockPane.IsAutoHide || Tabs.Count <= 1) + return 0; + + int height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + + ToolWindowStripGapTop + ToolWindowStripGapBottom; + + return height; + } + + private int MeasureHeight_Document() + { + int height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + + DocumentStripGapBottom + DocumentStripGapTop; + + return height; + } + + protected override void OnPaint(PaintEventArgs e) + { + Rectangle rect = TabsRectangle; + DockPanelGradient gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient; + if (Appearance == DockPane.AppearanceStyle.Document) + { + rect.X -= DocumentTabGapLeft; + + // Add these values back in so that the DockStrip color is drawn + // beneath the close button and window list button. + // It is possible depending on the DockPanel DocumentStyle to have + // a Document without a DockStrip. + rect.Width += DocumentTabGapLeft + + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonClose.Width + + ButtonWindowList.Width; + } + else + { + gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient; + } + //Fix MagicRemove , missing gradient implementation in themes + //Also coloring in tabs in not correct in some themes + Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); + Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); + LinearGradientMode gradientMode = gradient.LinearGradientMode; + + DrawingRoutines.SafelyDrawLinearGradient(rect, startColor, endColor, gradientMode, e.Graphics); + base.OnPaint(e); + CalculateTabs(); + if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null) + { + if (EnsureDocumentTabVisible(DockPane.ActiveContent, false)) + CalculateTabs(); + } + + DrawTabStrip(e.Graphics); + } + + protected override void OnRefreshChanges() + { + SetInertButtons(); + Invalidate(); + } + + public override GraphicsPath GetOutline(int index) + { + + if (Appearance == DockPane.AppearanceStyle.Document) + return GetOutline_Document(index); + else + return GetOutline_ToolWindow(index); + + } + + private GraphicsPath GetOutline_Document(int index) + { + Rectangle rectTab = Tabs[index].Rectangle.Value; + rectTab.X -= rectTab.Height / 2; + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + path.AddPath(pathTab, true); + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + path.AddLine(rectTab.Right, rectTab.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectTab.Right, rectTab.Top); + } + else + { + path.AddLine(rectTab.Right, rectTab.Bottom, rectPaneClient.Right, rectTab.Bottom); + path.AddLine(rectPaneClient.Right, rectTab.Bottom, rectPaneClient.Right, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Right, rectPaneClient.Bottom, rectPaneClient.Left, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom); + path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); + } + return path; + } + + private GraphicsPath GetOutline_ToolWindow(int index) + { + Rectangle rectTab = Tabs[index].Rectangle.Value; + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); + path.AddPath(pathTab, true); + path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); + return path; + } + + private void CalculateTabs() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + CalculateTabs_ToolWindow(); + else + CalculateTabs_Document(); + } + + private void CalculateTabs_ToolWindow() + { + if (Tabs.Count <= 1 || DockPane.IsAutoHide) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Calculate tab widths + int countTabs = Tabs.Count; + foreach (MremoteNGTab tab in Tabs) + { + tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); + tab.Flag = false; + } + + // Set tab whose max width less than average width + bool anyWidthWithinAverage = true; + int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + int totalAllocatedWidth = 0; + int averageWidth = totalWidth / countTabs; + int remainedTabs = countTabs; + for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0;) + { + anyWidthWithinAverage = false; + foreach (MremoteNGTab tab in Tabs) + { + if (tab.Flag) + continue; + + if (tab.MaxWidth <= averageWidth) + { + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; + } + } + if (remainedTabs != 0) + averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; + } + + // If any tab width not set yet, set it to the average width + if (remainedTabs > 0) + { + int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + foreach (MremoteNGTab tab in Tabs) + { + if (tab.Flag) + continue; + + tab.Flag = true; + if (roundUpWidth > 0) + { + tab.TabWidth = averageWidth + 1; + roundUpWidth--; + } + else + tab.TabWidth = averageWidth; + } + } + + // Set the X position of the tabs + int x = rectTabStrip.X + ToolWindowStripGapLeft; + foreach (MremoteNGTab tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + + private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) + { + bool overflow = false; + + MremoteNGTab tab = Tabs[index] as MremoteNGTab; + tab.MaxWidth = GetMaxTabWidth(index); + int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + if (x + width < rectTabStrip.Right || index == StartDisplayingTab) + { + tab.TabX = x; + tab.TabWidth = width; + EndDisplayingTab = index; + } + else + { + tab.TabX = 0; + tab.TabWidth = 0; + overflow = true; + } + x += width; + + return overflow; + } + + /// + /// Calculate which tabs are displayed and in what order. + /// + private void CalculateTabs_Document() + { + if (m_startDisplayingTab >= Tabs.Count) + m_startDisplayingTab = 0; + + Rectangle rectTabStrip = TabsRectangle; + + int x = rectTabStrip.X + rectTabStrip.Height / 2; + bool overflow = false; + + // Originally all new documents that were considered overflow + // (not enough pane strip space to show all tabs) were added to + // the far left (assuming not right to left) and the tabs on the + // right were dropped from view. If StartDisplayingTab is not 0 + // then we are dealing with making sure a specific tab is kept in focus. + if (m_startDisplayingTab > 0) + { + int tempX = x; + MremoteNGTab tab = Tabs[m_startDisplayingTab] as MremoteNGTab; + tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + + // Add the active tab and tabs to the left + for (int i = StartDisplayingTab; i >= 0; i--) + CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // Store which tab is the first one displayed so that it + // will be drawn correctly (without part of the tab cut off) + FirstDisplayingTab = EndDisplayingTab; + + tempX = x; // Reset X location because we are starting over + + // Start with the first tab displayed - name is a little misleading. + // Loop through each tab and set its location. If there is not enough + // room for all of them overflow will be returned. + for (int i = EndDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // If not all tabs are shown then we have an overflow. + if (FirstDisplayingTab != 0) + overflow = true; + } + else + { + for (int i = StartDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + for (int i = 0; i < StartDisplayingTab; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + + FirstDisplayingTab = StartDisplayingTab; + } + + if (!overflow) + { + m_startDisplayingTab = 0; + FirstDisplayingTab = 0; + x = rectTabStrip.X + rectTabStrip.Height / 2; + foreach (MremoteNGTab tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + DocumentTabsOverflow = overflow; + } + + protected override void EnsureTabVisible(IDockContent content) + { + if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content)) + return; + + CalculateTabs(); + EnsureDocumentTabVisible(content, true); + } + + private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) + { + int index = Tabs.IndexOf(content); + if (index == -1) + { + //somehow we've lost the content from the Tab collection + return false; + } + MremoteNGTab tab = Tabs[index] as MremoteNGTab; + if (tab.TabWidth != 0) + return false; + + StartDisplayingTab = index; + if (repaint) + Invalidate(); + + return true; + } + + private int GetMaxTabWidth(int index) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetMaxTabWidth_ToolWindow(index); + else + return GetMaxTabWidth_Document(index); + } + + private int GetMaxTabWidth_ToolWindow(int index) + { + IDockContent content = Tabs[index].Content; + Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + + ToolWindowImageGapRight + ToolWindowTextGapRight; + } + + private int GetMaxTabWidth_Document(int index) + { + IDockContent content = Tabs[index].Content; + + int height = GetTabRectangle_Document(index).Height; + + Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + + if (DockPane.DockPanel.ShowDocumentIcon) + return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; + else + return sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; + } + + private void DrawTabStrip(Graphics g) + { + if (Appearance == DockPane.AppearanceStyle.Document) + DrawTabStrip_Document(g); + else + DrawTabStrip_ToolWindow(g); + } + + private void DrawTabStrip_Document(Graphics g) + { + int count = Tabs.Count; + if (count == 0) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Draw the tabs + Rectangle rectTabOnly = TabsRectangle; + Rectangle rectTab = Rectangle.Empty; + MremoteNGTab tabActive = null; + g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); + for (int i = 0; i < count; i++) + { + rectTab = GetTabRectangle(i); + if (Tabs[i].Content == DockPane.ActiveContent) + { + tabActive = Tabs[i] as MremoteNGTab; + tabActive.Rectangle = rectTab; + continue; + } + + if (rectTab.IntersectsWith(rectTabOnly)) + { + var tab = Tabs[i] as MremoteNGTab; + tab.Rectangle = rectTab; + DrawTab(g, tab); + } + } + + g.SetClip(rectTabStrip); + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Top + 1, + rectTabStrip.Right, rectTabStrip.Top + 1); + else + g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Bottom - 1, + rectTabStrip.Right, rectTabStrip.Bottom - 1); + + g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); + if (tabActive != null) + { + rectTab = tabActive.Rectangle.Value; + if (rectTab.IntersectsWith(rectTabOnly)) + { + rectTab.Intersect(rectTabOnly); + tabActive.Rectangle = rectTab; + DrawTab(g, tabActive); + } + } + } + + private void DrawTabStrip_ToolWindow(Graphics g) + { + Rectangle rectTabStrip = TabStripRectangle; + + g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top, + rectTabStrip.Right, rectTabStrip.Top); + + for (int i = 0; i < Tabs.Count; i++) + { + var tab = Tabs[i] as MremoteNGTab; + tab.Rectangle = GetTabRectangle(i); + DrawTab(g, tab); + } + } + + private Rectangle GetTabRectangle(int index) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabRectangle_ToolWindow(index); + else + return GetTabRectangle_Document(index); + } + + private Rectangle GetTabRectangle_ToolWindow(int index) + { + Rectangle rectTabStrip = TabStripRectangle; + + MremoteNGTab tab = (MremoteNGTab)(Tabs[index]); + return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height); + } + + private Rectangle GetTabRectangle_Document(int index) + { + Rectangle rectTabStrip = TabStripRectangle; + MremoteNGTab tab = (MremoteNGTab)Tabs[index]; + + Rectangle rect = new Rectangle(); + rect.X = tab.TabX; + rect.Width = tab.TabWidth; + rect.Height = rectTabStrip.Height - DocumentTabGapTop; + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + rect.Y = rectTabStrip.Y + DocumentStripGapBottom; + else + rect.Y = rectTabStrip.Y + DocumentTabGapTop; + + return rect; + } + + private void DrawTab(Graphics g, MremoteNGTab tab) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + DrawTab_ToolWindow(g, tab); + else + DrawTab_Document(g, tab); + } + + private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); + else + return GetTabOutline_Document(tab, rtlTransform, toScreen, false); + } + + private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) + { + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + if (rtlTransform) + rect = DrawHelper.RtlTransform(this, rect); + if (toScreen) + rect = RectangleToScreen(rect); + + DrawHelper.GetRoundedCornerTab(GraphicsPath, rect, false); + return GraphicsPath; + } + + private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full) + { + int curveSize = 6; + + GraphicsPath.Reset(); + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + + // Shorten TabOutline so it doesn't get overdrawn by icons next to it + rect.Intersect(TabsRectangle); + rect.Width--; + + if (rtlTransform) + rect = DrawHelper.RtlTransform(this, rect); + if (toScreen) + rect = RectangleToScreen(rect); + + // Draws the full angle piece for active content (or first tab) + if (tab.Content == DockPane.ActiveContent || full || Tabs.IndexOf(tab) == FirstDisplayingTab) + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. + // It is not needed so it has been commented out. + //GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Top, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Bottom, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. + // It is not needed so it has been commented out. + //GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left - rect.Height / 2, rect.Top); + GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Top, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left - rect.Height / 2, rect.Bottom); + GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Bottom, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); + } + } + } + // Draws the partial angle for non-active content + else + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); + } + } + } + + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom); + + // Drawing the rounded corner is not necessary. The path is automatically connected + //GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + } + else + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Top, rect.Left + curveSize / 2, rect.Top); + GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + // Draws the bottom horizontal line (short side) + GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Bottom, rect.Right - curveSize / 2, rect.Bottom); + + // Drawing the rounded corner is not necessary. The path is automatically connected + //GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom, curveSize, curveSize), 90, -90); + } + else + { + // Draws the top horizontal line (short side) + GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); + + // Draws the rounded corner oppposite the angled side + GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); + } + } + + if (Tabs.IndexOf(tab) != EndDisplayingTab && + (Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent) + && !full) + { + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2, rect.Top); + } + else + { + GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2, rect.Bottom); + } + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Bottom - rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2, rect.Top); + } + else + { + GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Top + rect.Height / 2); + GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2, rect.Bottom); + } + } + } + else + { + // Draw the vertical line opposite the angled side + if (RightToLeft == RightToLeft.Yes) + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top); + else + GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Bottom); + } + else + { + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Top); + else + GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom); + } + } + + return GraphicsPath; + } + + private void DrawTab_ToolWindow(Graphics g, MremoteNGTab tab) + { + var rect = tab.Rectangle.Value; + Rectangle rectIcon = new Rectangle( + rect.X + ToolWindowImageGapLeft, + rect.Y + rect.Height - 1 - ToolWindowImageGapBottom - ToolWindowImageHeight, + ToolWindowImageWidth, ToolWindowImageHeight); + Rectangle rectText = PatchController.EnableHighDpi == true + ? new Rectangle( + rect.X + ToolWindowImageGapLeft, + rect.Y - 1 + rect.Height - ToolWindowImageGapBottom - TextFont.Height, + ToolWindowImageWidth, TextFont.Height) + : rectIcon; + rectText.X += rectIcon.Width + ToolWindowImageGapRight; + rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - + ToolWindowImageGapRight - ToolWindowTextGapRight; + + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + rectText = DrawHelper.RtlTransform(this, rectText); + rectIcon = DrawHelper.RtlTransform(this, rectIcon); + GraphicsPath path = GetTabOutline(tab, true, false); + if (DockPane.ActiveContent == tab.Content) + { + Color startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); + g.DrawPath(PenToolWindowTabBorder, path); + + Color textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor; + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + } + else + { + Color startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor; + Color endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); + + if (Tabs.IndexOf(DockPane.ActiveContent) != Tabs.IndexOf(tab) + 1) + { + Point pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop); + Point pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); + g.DrawLine(PenToolWindowTabBorder, DrawHelper.RtlTransform(this, pt1), DrawHelper.RtlTransform(this, pt2)); + } + + Color textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor; + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + } + + if (rectTab.Contains(rectIcon)) + g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon); + } + + private void DrawTab_Document(Graphics g, MremoteNGTab tab) + { + var rect = tab.Rectangle.Value; + if (tab.TabWidth == 0) + return; + + Rectangle rectIcon = new Rectangle( + rect.X + DocumentIconGapLeft, + rect.Y + rect.Height - 1 - DocumentIconGapBottom - DocumentIconHeight, + DocumentIconWidth, DocumentIconHeight); + Rectangle rectText = PatchController.EnableHighDpi == true + ? new Rectangle( + rect.X + DocumentIconGapLeft, + rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, + DocumentIconWidth, TextFont.Height) + : rectIcon; + if (DockPane.DockPanel.ShowDocumentIcon) + { + rectText.X += rectIcon.Width + DocumentIconGapRight; + rectText.Y = rect.Y; + rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - + DocumentIconGapRight - DocumentTextGapRight; + rectText.Height = rect.Height; + } + else + rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight; + + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + Rectangle rectBack = DrawHelper.RtlTransform(this, rect); + rectBack.Width += DocumentIconGapLeft; + rectBack.X -= DocumentIconGapLeft; + + rectText = DrawHelper.RtlTransform(this, rectText); + rectIcon = DrawHelper.RtlTransform(this, rectIcon); + GraphicsPath path = GetTabOutline(tab, true, false); + if (DockPane.ActiveContent == tab.Content) + { + Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); + g.DrawPath(PenDocumentTabActiveBorder, path); + + Color textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); + if (DockPane.IsActiveDocumentPane) + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, textColor, DocumentTextFormat); + else + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + } + else + { + Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); + Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); + LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); + g.DrawPath(PenDocumentTabInactiveBorder, path); + + Color textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Foreground"); + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + } + + if (rectTab.Contains(rectIcon) && DockPane.DockPanel.ShowDocumentIcon) + g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon); + } + + private void WindowList_Click(object sender, EventArgs e) + { + SelectMenu.Items.Clear(); + foreach (MremoteNGTab tab in Tabs) + { + IDockContent content = tab.Content; + ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); + item.Tag = tab.Content; + item.Click += new EventHandler(ContextMenuItem_Click); + } + + var workingArea = Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, ButtonWindowList.Height / 2))); + var menu = new Rectangle(ButtonWindowList.PointToScreen(new Point(0, ButtonWindowList.Location.Y + ButtonWindowList.Height)), SelectMenu.Size); + var menuMargined = new Rectangle(menu.X - SelectMenuMargin, menu.Y - SelectMenuMargin, menu.Width + SelectMenuMargin, menu.Height + SelectMenuMargin); + if (workingArea.Contains(menuMargined)) + { + SelectMenu.Show(menu.Location); + } + else + { + var newPoint = menu.Location; + newPoint.X = DrawHelper.Balance(SelectMenu.Width, SelectMenuMargin, newPoint.X, workingArea.Left, workingArea.Right); + newPoint.Y = DrawHelper.Balance(SelectMenu.Size.Height, SelectMenuMargin, newPoint.Y, workingArea.Top, workingArea.Bottom); + var button = ButtonWindowList.PointToScreen(new Point(0, ButtonWindowList.Height)); + if (newPoint.Y < button.Y) + { + // flip the menu up to be above the button. + newPoint.Y = button.Y - ButtonWindowList.Height; + SelectMenu.Show(newPoint, ToolStripDropDownDirection.AboveRight); + } + else + { + SelectMenu.Show(newPoint); + } + } + } + + private void ContextMenuItem_Click(object sender, EventArgs e) + { + ToolStripMenuItem item = sender as ToolStripMenuItem; + if (item != null) + { + IDockContent content = (IDockContent)item.Tag; + DockPane.ActiveContent = content; + } + } + + private void SetInertButtons() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + { + if (m_buttonClose != null) + m_buttonClose.Left = -m_buttonClose.Width; + + if (m_buttonWindowList != null) + m_buttonWindowList.Left = -m_buttonWindowList.Width; + } + else + { + ButtonClose.Enabled = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton; + m_closeButtonVisible = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButtonVisible; + ButtonClose.Visible = m_closeButtonVisible; + ButtonClose.RefreshChanges(); + ButtonWindowList.RefreshChanges(); + } + } + + protected override void OnLayout(LayoutEventArgs levent) + { + if (Appearance == DockPane.AppearanceStyle.Document) + { + LayoutButtons(); + OnRefreshChanges(); + } + + base.OnLayout(levent); + } + + private void LayoutButtons() + { + Rectangle rectTabStrip = TabStripRectangle; + + // Set position and size of the buttons + int buttonWidth = ButtonClose.Image.Width; + int buttonHeight = ButtonClose.Image.Height; + int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; + if (buttonHeight < height) + { + buttonWidth = buttonWidth * height / buttonHeight; + buttonHeight = height; + } + Size buttonSize = new Size(buttonWidth, buttonHeight); + + int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft + - DocumentButtonGapRight - buttonWidth; + int y = rectTabStrip.Y + DocumentButtonGapTop; + Point point = new Point(x, y); + ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + + // If the close button is not visible draw the window list button overtop. + // Otherwise it is drawn to the left of the close button. + if (m_closeButtonVisible) + point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0); + + ButtonWindowList.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + } + + private void Close_Click(object sender, EventArgs e) + { + DockPane.CloseActiveContent(); + if (PatchController.EnableMemoryLeakFix == true) + { + ContentClosed(); + } + } + + protected override int HitTest(Point point) + { + if (!TabsRectangle.Contains(point)) + return -1; + + foreach (Tab tab in Tabs) + { + GraphicsPath path = GetTabOutline(tab, true, false); + if (path.IsVisible(point)) + return Tabs.IndexOf(tab); + } + return -1; + } + + protected override Rectangle GetTabBounds(Tab tab) + { + GraphicsPath path = GetTabOutline(tab, true, false); + RectangleF rectangle = path.GetBounds(); + return new Rectangle((int)rectangle.Left, (int)rectangle.Top, (int)rectangle.Width, (int)rectangle.Height); + } + + protected override void OnMouseHover(EventArgs e) + { + int index = HitTest(PointToClient(Control.MousePosition)); + string toolTip = string.Empty; + + base.OnMouseHover(e); + + if (index != -1) + { + MremoteNGTab tab = Tabs[index] as MremoteNGTab; + if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) + toolTip = tab.Content.DockHandler.ToolTipText; + else if (tab.MaxWidth > tab.TabWidth) + toolTip = tab.Content.DockHandler.TabText; + } + + if (m_toolTip.GetToolTip(this) != toolTip) + { + m_toolTip.Active = false; + m_toolTip.SetToolTip(this, toolTip); + m_toolTip.Active = true; + } + + // requires further tracking of mouse hover behavior, + ResetMouseEventArgs(); + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + PerformLayout(); + } + } +} diff --git a/mRemoteV1/UI/Tabs/Enums.cs b/mRemoteV1/UI/Tabs/Enums.cs new file mode 100644 index 000000000..46afbc369 --- /dev/null +++ b/mRemoteV1/UI/Tabs/Enums.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace mRemoteNG.UI.Tabs +{ + + [Flags] + internal enum FlagsSetWindowPos : uint + { + SWP_NOSIZE = 0x0001, + SWP_NOMOVE = 0x0002, + SWP_NOZORDER = 0x0004, + SWP_NOREDRAW = 0x0008, + SWP_NOACTIVATE = 0x0010, + SWP_FRAMECHANGED = 0x0020, + SWP_SHOWWINDOW = 0x0040, + SWP_HIDEWINDOW = 0x0080, + SWP_NOCOPYBITS = 0x0100, + SWP_NOOWNERZORDER = 0x0200, + SWP_NOSENDCHANGING = 0x0400, + SWP_DRAWFRAME = 0x0020, + SWP_NOREPOSITION = 0x0200, + SWP_DEFERERASE = 0x2000, + SWP_ASYNCWINDOWPOS = 0x4000 + } + + internal enum ShowWindowStyles : short + { + SW_HIDE = 0, + SW_SHOWNORMAL = 1, + SW_NORMAL = 1, + SW_SHOWMINIMIZED = 2, + SW_SHOWMAXIMIZED = 3, + SW_MAXIMIZE = 3, + SW_SHOWNOACTIVATE = 4, + SW_SHOW = 5, + SW_MINIMIZE = 6, + SW_SHOWMINNOACTIVE = 7, + SW_SHOWNA = 8, + SW_RESTORE = 9, + SW_SHOWDEFAULT = 10, + SW_FORCEMINIMIZE = 11, + SW_MAX = 11 + } + + internal enum WindowStyles : uint + { + WS_OVERLAPPED = 0x00000000, + WS_POPUP = 0x80000000, + WS_CHILD = 0x40000000, + WS_MINIMIZE = 0x20000000, + WS_VISIBLE = 0x10000000, + WS_DISABLED = 0x08000000, + WS_CLIPSIBLINGS = 0x04000000, + WS_CLIPCHILDREN = 0x02000000, + WS_MAXIMIZE = 0x01000000, + WS_CAPTION = 0x00C00000, + WS_BORDER = 0x00800000, + WS_DLGFRAME = 0x00400000, + WS_VSCROLL = 0x00200000, + WS_HSCROLL = 0x00100000, + WS_SYSMENU = 0x00080000, + WS_THICKFRAME = 0x00040000, + WS_GROUP = 0x00020000, + WS_TABSTOP = 0x00010000, + WS_MINIMIZEBOX = 0x00020000, + WS_MAXIMIZEBOX = 0x00010000, + WS_TILED = 0x00000000, + WS_ICONIC = 0x20000000, + WS_SIZEBOX = 0x00040000, + WS_POPUPWINDOW = 0x80880000, + WS_OVERLAPPEDWINDOW = 0x00CF0000, + WS_TILEDWINDOW = 0x00CF0000, + WS_CHILDWINDOW = 0x40000000 + } + + [Flags] + internal enum WindowExStyles + { + WS_EX_DLGMODALFRAME = 0x00000001, + WS_EX_NOPARENTNOTIFY = 0x00000004, + WS_EX_TOPMOST = 0x00000008, + WS_EX_ACCEPTFILES = 0x00000010, + WS_EX_TRANSPARENT = 0x00000020, + WS_EX_MDICHILD = 0x00000040, + WS_EX_TOOLWINDOW = 0x00000080, + WS_EX_WINDOWEDGE = 0x00000100, + WS_EX_CLIENTEDGE = 0x00000200, + WS_EX_CONTEXTHELP = 0x00000400, + WS_EX_RIGHT = 0x00001000, + WS_EX_LEFT = 0x00000000, + WS_EX_RTLREADING = 0x00002000, + WS_EX_LTRREADING = 0x00000000, + WS_EX_LEFTSCROLLBAR = 0x00004000, + WS_EX_RIGHTSCROLLBAR = 0x00000000, + WS_EX_CONTROLPARENT = 0x00010000, + WS_EX_STATICEDGE = 0x00020000, + WS_EX_APPWINDOW = 0x00040000, + WS_EX_OVERLAPPEDWINDOW = 0x00000300, + WS_EX_PALETTEWINDOW = 0x00000188, + WS_EX_LAYERED = 0x00080000, + WS_EX_NOACTIVATE = 0x08000000 + } + + internal enum Msgs + { + WM_NULL = 0x0000, + WM_CREATE = 0x0001, + WM_DESTROY = 0x0002, + WM_MOVE = 0x0003, + WM_SIZE = 0x0005, + WM_ACTIVATE = 0x0006, + WM_SETFOCUS = 0x0007, + WM_KILLFOCUS = 0x0008, + WM_ENABLE = 0x000A, + WM_SETREDRAW = 0x000B, + WM_SETTEXT = 0x000C, + WM_GETTEXT = 0x000D, + WM_GETTEXTLENGTH = 0x000E, + WM_PAINT = 0x000F, + WM_CLOSE = 0x0010, + WM_QUERYENDSESSION = 0x0011, + WM_QUIT = 0x0012, + WM_QUERYOPEN = 0x0013, + WM_ERASEBKGND = 0x0014, + WM_SYSCOLORCHANGE = 0x0015, + WM_ENDSESSION = 0x0016, + WM_SHOWWINDOW = 0x0018, + WM_WININICHANGE = 0x001A, + WM_SETTINGCHANGE = 0x001A, + WM_DEVMODECHANGE = 0x001B, + WM_ACTIVATEAPP = 0x001C, + WM_FONTCHANGE = 0x001D, + WM_TIMECHANGE = 0x001E, + WM_CANCELMODE = 0x001F, + WM_SETCURSOR = 0x0020, + WM_MOUSEACTIVATE = 0x0021, + WM_CHILDACTIVATE = 0x0022, + WM_QUEUESYNC = 0x0023, + WM_GETMINMAXINFO = 0x0024, + WM_PAINTICON = 0x0026, + WM_ICONERASEBKGND = 0x0027, + WM_NEXTDLGCTL = 0x0028, + WM_SPOOLERSTATUS = 0x002A, + WM_DRAWITEM = 0x002B, + WM_MEASUREITEM = 0x002C, + WM_DELETEITEM = 0x002D, + WM_VKEYTOITEM = 0x002E, + WM_CHARTOITEM = 0x002F, + WM_SETFONT = 0x0030, + WM_GETFONT = 0x0031, + WM_SETHOTKEY = 0x0032, + WM_GETHOTKEY = 0x0033, + WM_QUERYDRAGICON = 0x0037, + WM_COMPAREITEM = 0x0039, + WM_GETOBJECT = 0x003D, + WM_COMPACTING = 0x0041, + WM_COMMNOTIFY = 0x0044, + WM_WINDOWPOSCHANGING = 0x0046, + WM_WINDOWPOSCHANGED = 0x0047, + WM_POWER = 0x0048, + WM_COPYDATA = 0x004A, + WM_CANCELJOURNAL = 0x004B, + WM_NOTIFY = 0x004E, + WM_INPUTLANGCHANGEREQUEST = 0x0050, + WM_INPUTLANGCHANGE = 0x0051, + WM_TCARD = 0x0052, + WM_HELP = 0x0053, + WM_USERCHANGED = 0x0054, + WM_NOTIFYFORMAT = 0x0055, + WM_CONTEXTMENU = 0x007B, + WM_STYLECHANGING = 0x007C, + WM_STYLECHANGED = 0x007D, + WM_DISPLAYCHANGE = 0x007E, + WM_GETICON = 0x007F, + WM_SETICON = 0x0080, + WM_NCCREATE = 0x0081, + WM_NCDESTROY = 0x0082, + WM_NCCALCSIZE = 0x0083, + WM_NCHITTEST = 0x0084, + WM_NCPAINT = 0x0085, + WM_NCACTIVATE = 0x0086, + WM_GETDLGCODE = 0x0087, + WM_SYNCPAINT = 0x0088, + WM_NCMOUSEMOVE = 0x00A0, + WM_NCLBUTTONDOWN = 0x00A1, + WM_NCLBUTTONUP = 0x00A2, + WM_NCLBUTTONDBLCLK = 0x00A3, + WM_NCRBUTTONDOWN = 0x00A4, + WM_NCRBUTTONUP = 0x00A5, + WM_NCRBUTTONDBLCLK = 0x00A6, + WM_NCMBUTTONDOWN = 0x00A7, + WM_NCMBUTTONUP = 0x00A8, + WM_NCMBUTTONDBLCLK = 0x00A9, + WM_KEYDOWN = 0x0100, + WM_KEYUP = 0x0101, + WM_CHAR = 0x0102, + WM_DEADCHAR = 0x0103, + WM_SYSKEYDOWN = 0x0104, + WM_SYSKEYUP = 0x0105, + WM_SYSCHAR = 0x0106, + WM_SYSDEADCHAR = 0x0107, + WM_KEYLAST = 0x0108, + WM_IME_STARTCOMPOSITION = 0x010D, + WM_IME_ENDCOMPOSITION = 0x010E, + WM_IME_COMPOSITION = 0x010F, + WM_IME_KEYLAST = 0x010F, + WM_INITDIALOG = 0x0110, + WM_COMMAND = 0x0111, + WM_SYSCOMMAND = 0x0112, + WM_TIMER = 0x0113, + WM_HSCROLL = 0x0114, + WM_VSCROLL = 0x0115, + WM_INITMENU = 0x0116, + WM_INITMENUPOPUP = 0x0117, + WM_MENUSELECT = 0x011F, + WM_MENUCHAR = 0x0120, + WM_ENTERIDLE = 0x0121, + WM_MENURBUTTONUP = 0x0122, + WM_MENUDRAG = 0x0123, + WM_MENUGETOBJECT = 0x0124, + WM_UNINITMENUPOPUP = 0x0125, + WM_MENUCOMMAND = 0x0126, + WM_CTLCOLORMSGBOX = 0x0132, + WM_CTLCOLOREDIT = 0x0133, + WM_CTLCOLORLISTBOX = 0x0134, + WM_CTLCOLORBTN = 0x0135, + WM_CTLCOLORDLG = 0x0136, + WM_CTLCOLORSCROLLBAR = 0x0137, + WM_CTLCOLORSTATIC = 0x0138, + WM_MOUSEMOVE = 0x0200, + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_LBUTTONDBLCLK = 0x0203, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205, + WM_RBUTTONDBLCLK = 0x0206, + WM_MBUTTONDOWN = 0x0207, + WM_MBUTTONUP = 0x0208, + WM_MBUTTONDBLCLK = 0x0209, + WM_MOUSEWHEEL = 0x020A, + WM_PARENTNOTIFY = 0x0210, + WM_ENTERMENULOOP = 0x0211, + WM_EXITMENULOOP = 0x0212, + WM_NEXTMENU = 0x0213, + WM_SIZING = 0x0214, + WM_CAPTURECHANGED = 0x0215, + WM_MOVING = 0x0216, + WM_DEVICECHANGE = 0x0219, + WM_MDICREATE = 0x0220, + WM_MDIDESTROY = 0x0221, + WM_MDIACTIVATE = 0x0222, + WM_MDIRESTORE = 0x0223, + WM_MDINEXT = 0x0224, + WM_MDIMAXIMIZE = 0x0225, + WM_MDITILE = 0x0226, + WM_MDICASCADE = 0x0227, + WM_MDIICONARRANGE = 0x0228, + WM_MDIGETACTIVE = 0x0229, + WM_MDISETMENU = 0x0230, + WM_ENTERSIZEMOVE = 0x0231, + WM_EXITSIZEMOVE = 0x0232, + WM_DROPFILES = 0x0233, + WM_MDIREFRESHMENU = 0x0234, + WM_IME_SETCONTEXT = 0x0281, + WM_IME_NOTIFY = 0x0282, + WM_IME_CONTROL = 0x0283, + WM_IME_COMPOSITIONFULL = 0x0284, + WM_IME_SELECT = 0x0285, + WM_IME_CHAR = 0x0286, + WM_IME_REQUEST = 0x0288, + WM_IME_KEYDOWN = 0x0290, + WM_IME_KEYUP = 0x0291, + WM_MOUSEHOVER = 0x02A1, + WM_MOUSELEAVE = 0x02A3, + WM_CUT = 0x0300, + WM_COPY = 0x0301, + WM_PASTE = 0x0302, + WM_CLEAR = 0x0303, + WM_UNDO = 0x0304, + WM_RENDERFORMAT = 0x0305, + WM_RENDERALLFORMATS = 0x0306, + WM_DESTROYCLIPBOARD = 0x0307, + WM_DRAWCLIPBOARD = 0x0308, + WM_PAINTCLIPBOARD = 0x0309, + WM_VSCROLLCLIPBOARD = 0x030A, + WM_SIZECLIPBOARD = 0x030B, + WM_ASKCBFORMATNAME = 0x030C, + WM_CHANGECBCHAIN = 0x030D, + WM_HSCROLLCLIPBOARD = 0x030E, + WM_QUERYNEWPALETTE = 0x030F, + WM_PALETTEISCHANGING = 0x0310, + WM_PALETTECHANGED = 0x0311, + WM_HOTKEY = 0x0312, + WM_PRINT = 0x0317, + WM_PRINTCLIENT = 0x0318, + WM_HANDHELDFIRST = 0x0358, + WM_HANDHELDLAST = 0x035F, + WM_AFXFIRST = 0x0360, + WM_AFXLAST = 0x037F, + WM_PENWINFIRST = 0x0380, + WM_PENWINLAST = 0x038F, + WM_APP = 0x8000, + WM_USER = 0x0400 + } + + internal enum HitTest + { + HTERROR = -2, + HTTRANSPARENT = -1, + HTNOWHERE = 0, + HTCLIENT = 1, + HTCAPTION = 2, + HTSYSMENU = 3, + HTGROWBOX = 4, + HTSIZE = 4, + HTMENU = 5, + HTHSCROLL = 6, + HTVSCROLL = 7, + HTMINBUTTON = 8, + HTMAXBUTTON = 9, + HTLEFT = 10, + HTRIGHT = 11, + HTTOP = 12, + HTTOPLEFT = 13, + HTTOPRIGHT = 14, + HTBOTTOM = 15, + HTBOTTOMLEFT = 16, + HTBOTTOMRIGHT = 17, + HTBORDER = 18, + HTREDUCE = 8, + HTZOOM = 9, + HTSIZEFIRST = 10, + HTSIZELAST = 17, + HTOBJECT = 19, + HTCLOSE = 20, + HTHELP = 21 + } + + internal enum ScrollBars : uint + { + SB_HORZ = 0, + SB_VERT = 1, + SB_CTL = 2, + SB_BOTH = 3 + } + + internal enum GetWindowLongIndex + { + GWL_STYLE = -16, + GWL_EXSTYLE = -20 + } + + // Hook Types + internal enum HookType + { + WH_JOURNALRECORD = 0, + WH_JOURNALPLAYBACK = 1, + WH_KEYBOARD = 2, + WH_GETMESSAGE = 3, + WH_CALLWNDPROC = 4, + WH_CBT = 5, + WH_SYSMSGFILTER = 6, + WH_MOUSE = 7, + WH_HARDWARE = 8, + WH_DEBUG = 9, + WH_SHELL = 10, + WH_FOREGROUNDIDLE = 11, + WH_CALLWNDPROCRET = 12, + WH_KEYBOARD_LL = 13, + WH_MOUSE_LL = 14 + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs new file mode 100644 index 000000000..a1c8d425c --- /dev/null +++ b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs @@ -0,0 +1,544 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; + +namespace mRemoteNG.UI.Tabs +{ + class MremoteNGAutoHideStrip : AutoHideStripBase + { + private class TabNG : Tab + { + internal TabNG(IDockContent content) + : base(content) + { + } + + private int m_tabX = 0; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth = 0; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + } + + private const int _ImageHeight = 16; + private const int _ImageWidth = 16; + private const int _ImageGapTop = 2; + private const int _ImageGapLeft = 4; + private const int _ImageGapRight = 2; + private const int _ImageGapBottom = 2; + private const int _TextGapLeft = 0; + private const int _TextGapRight = 0; + private const int _TabGapTop = 3; + private const int _TabGapLeft = 4; + private const int _TabGapBetween = 10; + + #region Customizable Properties + public Font TextFont + { + get { return DockPanel.Theme.Skin.AutoHideStripSkin.TextFont; } + } + + private static StringFormat _stringFormatTabHorizontal; + private StringFormat StringFormatTabHorizontal + { + get + { + if (_stringFormatTabHorizontal == null) + { + _stringFormatTabHorizontal = new StringFormat(); + _stringFormatTabHorizontal.Alignment = StringAlignment.Near; + _stringFormatTabHorizontal.LineAlignment = StringAlignment.Center; + _stringFormatTabHorizontal.FormatFlags = StringFormatFlags.NoWrap; + _stringFormatTabHorizontal.Trimming = StringTrimming.None; + } + + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabHorizontal.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabHorizontal.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabHorizontal; + } + } + + private static StringFormat _stringFormatTabVertical; + private StringFormat StringFormatTabVertical + { + get + { + if (_stringFormatTabVertical == null) + { + _stringFormatTabVertical = new StringFormat(); + _stringFormatTabVertical.Alignment = StringAlignment.Near; + _stringFormatTabVertical.LineAlignment = StringAlignment.Center; + _stringFormatTabVertical.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical; + _stringFormatTabVertical.Trimming = StringTrimming.None; + } + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabVertical.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabVertical.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabVertical; + } + } + + private static int ImageHeight + { + get { return _ImageHeight; } + } + + private static int ImageWidth + { + get { return _ImageWidth; } + } + + private static int ImageGapTop + { + get { return _ImageGapTop; } + } + + private static int ImageGapLeft + { + get { return _ImageGapLeft; } + } + + private static int ImageGapRight + { + get { return _ImageGapRight; } + } + + private static int ImageGapBottom + { + get { return _ImageGapBottom; } + } + + private static int TextGapLeft + { + get { return _TextGapLeft; } + } + + private static int TextGapRight + { + get { return _TextGapRight; } + } + + private static int TabGapTop + { + get { return _TabGapTop; } + } + + private static int TabGapLeft + { + get { return _TabGapLeft; } + } + + private static int TabGapBetween + { + get { return _TabGapBetween; } + } + + private static Pen PenTabBorder + { + get { return SystemPens.GrayText; } + } + #endregion + + private static Matrix _matrixIdentity = new Matrix(); + private static Matrix MatrixIdentity + { + get { return _matrixIdentity; } + } + + private static DockState[] _dockStates; + private static DockState[] DockStates + { + get + { + if (_dockStates == null) + { + _dockStates = new DockState[4]; + _dockStates[0] = DockState.DockLeftAutoHide; + _dockStates[1] = DockState.DockRightAutoHide; + _dockStates[2] = DockState.DockTopAutoHide; + _dockStates[3] = DockState.DockBottomAutoHide; + } + return _dockStates; + } + } + + private static GraphicsPath _graphicsPath; + internal static GraphicsPath GraphicsPath + { + get + { + if (_graphicsPath == null) + _graphicsPath = new GraphicsPath(); + + return _graphicsPath; + } + } + + public MremoteNGAutoHideStrip(DockPanel panel) + : base(panel) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + BackColor = SystemColors.ControlLight; + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + Graphics g = e.Graphics; + + Color startColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.StartColor; + Color endColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + g.FillRectangle(brush, ClientRectangle); + } + + DrawTabStrip(g); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + CalculateTabs(); + base.OnLayout(levent); + } + + private void DrawTabStrip(Graphics g) + { + DrawTabStrip(g, DockState.DockTopAutoHide); + DrawTabStrip(g, DockState.DockBottomAutoHide); + DrawTabStrip(g, DockState.DockLeftAutoHide); + DrawTabStrip(g, DockState.DockRightAutoHide); + } + + private void DrawTabStrip(Graphics g, DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return; + + Matrix matrixIdentity = g.Transform; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + { + Matrix matrixRotated = new Matrix(); + matrixRotated.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + g.Transform = matrixRotated; + } + + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabNG tab in pane.AutoHideTabs) + DrawTab(g, tab); + } + g.Transform = matrixIdentity; + } + + private void CalculateTabs() + { + CalculateTabs(DockState.DockTopAutoHide); + CalculateTabs(DockState.DockBottomAutoHide); + CalculateTabs(DockState.DockLeftAutoHide); + CalculateTabs(DockState.DockRightAutoHide); + } + + private void CalculateTabs(DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + int imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight / ImageHeight); + + int x = TabGapLeft + rectTabStrip.X; + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabNG tab in pane.AutoHideTabs) + { + int width = imageWidth + ImageGapLeft + ImageGapRight + + TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + + TextGapLeft + TextGapRight; + tab.TabX = x; + tab.TabWidth = width; + x += width; + } + + x += TabGapBetween; + } + } + + private Rectangle RtlTransform(Rectangle rect, DockState dockState) + { + Rectangle rectTransformed; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + rectTransformed = rect; + else + rectTransformed = DrawHelper.RtlTransform(this, rect); + + return rectTransformed; + } + + private GraphicsPath GetTabOutline(TabNG tab, bool transformed, bool rtlTransform) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTab = GetTabRectangle(tab, transformed); + if (rtlTransform) + rectTab = RtlTransform(rectTab, dockState); + bool upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide); + DrawHelper.GetRoundedCornerTab(GraphicsPath, rectTab, upTab); + + return GraphicsPath; + } + + private void DrawTab(Graphics g, TabNG tab) + { + Rectangle rectTabOrigin = GetTabRectangle(tab); + if (rectTabOrigin.IsEmpty) + return; + + DockState dockState = tab.Content.DockHandler.DockState; + IDockContent content = tab.Content; + + GraphicsPath path = GetTabOutline(tab, false, true); + Color startColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.StartColor; + Color endColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTabOrigin, startColor, endColor, gradientMode), path); + g.DrawPath(PenTabBorder, path); + + // Set no rotate for drawing icon and text + using (Matrix matrixRotate = g.Transform) + { + g.Transform = MatrixIdentity; + + // Draw the icon + Rectangle rectImage = rectTabOrigin; + rectImage.X += ImageGapLeft; + rectImage.Y += ImageGapTop; + int imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight / ImageHeight); + rectImage.Height = imageHeight; + rectImage.Width = imageWidth; + rectImage = GetTransformedRectangle(dockState, rectImage); + + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + { + // The DockState is DockLeftAutoHide or DockRightAutoHide, so rotate the image 90 degrees to the right. + Rectangle rectTransform = RtlTransform(rectImage, dockState); + Point[] rotationPoints = + { + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y), + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y + rectTransform.Height), + new Point(rectTransform.X, rectTransform.Y) + }; + + using (Icon rotatedIcon = new Icon(((Form)content).Icon, 16, 16)) + { + g.DrawImage(rotatedIcon.ToBitmap(), rotationPoints); + } + } + else + { + // Draw the icon normally without any rotation. + g.DrawIcon(((Form)content).Icon, RtlTransform(rectImage, dockState)); + } + + // Draw the text + Rectangle rectText = rectTabOrigin; + rectText.X += ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText.Width -= ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText = RtlTransform(GetTransformedRectangle(dockState, rectText), dockState); + + Color textColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.TextColor; + + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical); + else + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabHorizontal); + + // Set rotate back + g.Transform = matrixRotate; + } + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState) + { + return GetLogicalTabStripRectangle(dockState, false); + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState, bool transformed) + { + if (!DockHelper.IsDockStateAutoHide(dockState)) + return Rectangle.Empty; + + int leftPanes = GetPanes(DockState.DockLeftAutoHide).Count; + int rightPanes = GetPanes(DockState.DockRightAutoHide).Count; + int topPanes = GetPanes(DockState.DockTopAutoHide).Count; + int bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count; + + int x, y, width, height; + + height = MeasureHeight(); + if (dockState == DockState.DockLeftAutoHide && leftPanes > 0) + { + x = 0; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockRightAutoHide && rightPanes > 0) + { + x = Width - height; + if (leftPanes != 0 && x < height) + x = height; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockTopAutoHide && topPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = 0; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockBottomAutoHide && bottomPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = Height - height; + if (topPanes != 0 && y < height) + y = height; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else + return Rectangle.Empty; + + if (width == 0 || height == 0) + { + return Rectangle.Empty; + } + + var rect = new Rectangle(x, y, width, height); + return transformed ? GetTransformedRectangle(dockState, rect) : rect; + } + + private Rectangle GetTabRectangle(TabNG tab) + { + return GetTabRectangle(tab, false); + } + + private Rectangle GetTabRectangle(TabNG tab, bool transformed) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return Rectangle.Empty; + + int x = tab.TabX; + int y = rectTabStrip.Y + + (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ? + 0 : TabGapTop); + int width = tab.TabWidth; + int height = rectTabStrip.Height - TabGapTop; + + if (!transformed) + return new Rectangle(x, y, width, height); + else + return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height)); + } + + private Rectangle GetTransformedRectangle(DockState dockState, Rectangle rect) + { + if (dockState != DockState.DockLeftAutoHide && dockState != DockState.DockRightAutoHide) + return rect; + + PointF[] pts = new PointF[1]; + // the center of the rectangle + pts[0].X = (float)rect.X + (float)rect.Width / 2; + pts[0].Y = (float)rect.Y + (float)rect.Height / 2; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + using (var matrix = new Matrix()) + { + matrix.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + matrix.TransformPoints(pts); + } + + return new Rectangle((int)(pts[0].X - (float)rect.Height / 2 + .5F), + (int)(pts[0].Y - (float)rect.Width / 2 + .5F), + rect.Height, rect.Width); + } + + protected override IDockContent HitTest(Point point) + { + foreach (DockState state in DockStates) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(state, true); + if (!rectTabStrip.Contains(point)) + continue; + + foreach (Pane pane in GetPanes(state)) + { + foreach (TabNG tab in pane.AutoHideTabs) + { + GraphicsPath path = GetTabOutline(tab, true, true); + if (path.IsVisible(point)) + return tab.Content; + } + } + } + + return null; + } + + protected override Rectangle GetTabBounds(Tab tab) + { + GraphicsPath path = GetTabOutline((TabNG)tab, true, true); + RectangleF bounds = path.GetBounds(); + return new Rectangle((int)bounds.Left, (int)bounds.Top, (int)bounds.Width, (int)bounds.Height); + } + + protected override int MeasureHeight() + { + return Math.Max(ImageGapBottom + + ImageGapTop + ImageHeight, + TextFont.Height) + TabGapTop; + } + + protected override void OnRefreshChanges() + { + CalculateTabs(); + Invalidate(); + } + + protected override AutoHideStripBase.Tab CreateTab(IDockContent content) + { + return new TabNG(content); + } + } +} diff --git a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs index 5b4a97325..cfcea143c 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.Windows.Forms; -using TabControl = Crownwood.Magic.Controls.TabControl; namespace mRemoteNG.UI.Window @@ -36,7 +35,7 @@ namespace mRemoteNG.UI.Window { components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConnectionWindow)); - TabController = new TabControl(); + this.connDock = new WeifenLuo.WinFormsUI.Docking.DockPanel(); cmenTab = new ContextMenuStrip(components); cmenTabFullscreen = new ToolStripMenuItem(); cmenTabSmartSize = new ToolStripMenuItem(); @@ -63,7 +62,7 @@ namespace mRemoteNG.UI.Window // //TabController // - TabController.Anchor = ((AnchorStyles.Top | AnchorStyles.Bottom) + /* TabController.Anchor = ((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right; TabController.Appearance = TabControl.VisualAppearance.MultiDocument; @@ -74,7 +73,7 @@ namespace mRemoteNG.UI.Window TabController.Location = new Point(0, -1); TabController.Name = "TabController"; TabController.Size = new Size(632, 454); - TabController.TabIndex = 0; + TabController.TabIndex = 0;*/ // //cmenTab // @@ -102,7 +101,19 @@ namespace mRemoteNG.UI.Window cmenTab.Name = "cmenTab"; cmenTab.RenderMode = ToolStripRenderMode.Professional; cmenTab.Size = new Size(202, 346); - // + // + // pnlDock + // + this.connDock.Dock = System.Windows.Forms.DockStyle.Fill; + this.connDock.DockBackColor = System.Drawing.SystemColors.Control; + this.connDock.DockLeftPortion = 230D; + this.connDock.DockRightPortion = 230D; + this.connDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi; + this.connDock.Location = new System.Drawing.Point(0, 0); + this.connDock.Margin = new System.Windows.Forms.Padding(4); + this.connDock.Name = "pnlDock"; + this.connDock.Size = new System.Drawing.Size(1288, 594); + this.connDock.TabIndex = 13; //cmenTabFullscreen // cmenTabFullscreen.Image = Resources.arrow_out; @@ -243,14 +254,18 @@ namespace mRemoteNG.UI.Window //Connection // ClientSize = new Size(632, 453); - Controls.Add(TabController); + //Controls.Add(TabController); + this.Controls.Add(this.connDock); Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, Convert.ToByte(0)); Icon = Resources.mRemoteNG_Icon; Name = "Connection"; TabText = @"UI.Window.Connection"; Text = @"UI.Window.Connection"; + this.Load += new System.EventHandler(this.ConnectionWindow_Load); cmenTab.ResumeLayout(false); ResumeLayout(false); } + + internal WeifenLuo.WinFormsUI.Docking.DockPanel connDock; } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 0cf51244f..ec5d62b5e 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -18,17 +18,14 @@ using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.TaskDialog; using WeifenLuo.WinFormsUI.Docking; -using Message = System.Windows.Forms.Message; -using TabControl = Crownwood.Magic.Controls.TabControl; -using TabPage = Crownwood.Magic.Controls.TabPage; +using Message = System.Windows.Forms.Message; namespace mRemoteNG.UI.Window { public partial class ConnectionWindow : BaseWindow { - public TabControl TabController; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - private VisualStudioToolStripExtender vsToolStripExtender; + private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender; private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); #region Public Methods @@ -46,6 +43,7 @@ namespace mRemoteNG.UI.Window // ReSharper disable once VirtualMemberCallInConstructor Text = formText; TabText = formText; + connDock.DocumentStyle = DocumentStyle.DockingWindow; } private void SetEventHandlers() @@ -64,17 +62,17 @@ namespace mRemoteNG.UI.Window private void SetTabControllerEventHandlers() { - TabController.ClosePressed += TabController_ClosePressed; - TabController.DoubleClickTab += TabController_DoubleClickTab; - TabController.DragDrop += TabController_DragDrop; - TabController.DragOver += TabController_DragOver; - TabController.SelectionChanged += TabController_SelectionChanged; - TabController.MouseUp += TabController_MouseUp; - TabController.PageDragEnd += TabController_PageDragStart; - TabController.PageDragStart += TabController_PageDragStart; - TabController.PageDragMove += TabController_PageDragMove; - TabController.PageDragEnd += TabController_PageDragEnd; - TabController.PageDragQuit += TabController_PageDragEnd; + //TabController.ClosePressed += TabController_ClosePressed; + // TabController.DoubleClickTab += TabController_DoubleClickTab; + // TabController.DragDrop += TabController_DrouagDrop; + // TabController.DragOver += TabController_DragOver; + // TabController.SelectionChanged += TabController_SelectionChanged; + DockPnl.MouseUp += TabController_MouseUp; + // TabController.PageDragEnd += TabController_PageDragStart; + // TabController.PageDragStart += TabController_PageDragStart; + // TabController.PageDragMove += TabController_PageDragMove; + // TabController.PageDragEnd += TabController_PageDragEnd; + // TabController.PageDragQuit += TabController_PageDragEnd; } private void SetContextMenuEventHandlers() @@ -97,53 +95,53 @@ namespace mRemoteNG.UI.Window cmenTabPuttySettings.Click += (sender, args) => ShowPuttySettingsDialog(); } - public TabPage AddConnectionTab(ConnectionInfo connectionInfo) + public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo) { try { - var nTab = new TabPage - { - Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top - }; + ConnectionTab conTab = new ConnectionTab(); + //Tag the tab + conTab.Tag = connectionInfo; + + //Set the connection text based on name and preferences + string titleText = ""; if (Settings.Default.ShowProtocolOnTabs) - nTab.Title = connectionInfo.Protocol + @": "; + titleText = connectionInfo.Protocol + @": "; else - nTab.Title = ""; + titleText = ""; - nTab.Title += connectionInfo.Name; + titleText += connectionInfo.Name; if (Settings.Default.ShowLogonInfoOnTabs) { - nTab.Title += @" ("; + titleText += @" ("; if (connectionInfo.Domain != "") - nTab.Title += connectionInfo.Domain; + titleText += connectionInfo.Domain; if (connectionInfo.Username != "") { if (connectionInfo.Domain != "") - nTab.Title += @"\"; - nTab.Title += connectionInfo.Username; + titleText += @"\"; + titleText += connectionInfo.Username; } - nTab.Title += @")"; + titleText += @")"; } - nTab.Title = nTab.Title.Replace("&", "&&"); + conTab.TabText = titleText; + conTab.TabPageContextMenuStrip = cmenTab; + titleText = titleText.Replace("&", "&&"); + //Fix MagicRemove, i dont see no icons -.- var conIcon = ConnectionIcon.FromString(connectionInfo.Icon); if (conIcon != null) - nTab.Icon = conIcon; + conTab.Icon = conIcon; - if (Settings.Default.OpenTabsRightOfSelected) - TabController.TabPages.Insert(TabController.SelectedIndex + 1, nTab); - else - TabController.TabPages.Add(nTab); - - nTab.Selected = true; - _ignoreChangeSelectedTabClick = false; - - return nTab; + //Show the tab + conTab.Show(connDock, DockState.Document); + conTab.Focus(); + return conTab; } catch (Exception ex) { @@ -155,7 +153,7 @@ namespace mRemoteNG.UI.Window public void UpdateSelectedConnection() { - if (TabController.SelectedTab == null) + /* if (TabController.SelectedTab == null) { FrmMain.Default.SelectedConnection = null; } @@ -163,7 +161,7 @@ namespace mRemoteNG.UI.Window { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; FrmMain.Default.SelectedConnection = interfaceControl?.Info; - } + }*/ } #endregion @@ -177,15 +175,14 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if(ThemeManager.getInstance().ThemingActive) + if (ThemeManager.getInstance().ThemingActive) { base.ApplyTheme(); + this.connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); - TabController.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - TabController.TextColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); - TabController.TextInactiveColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Foreground"); + connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } } @@ -243,9 +240,9 @@ namespace mRemoteNG.UI.Window private void Connection_FormClosing(object sender, FormClosingEventArgs e) { - if (!FrmMain.Default.IsClosing && - (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & TabController.TabPages.Count > 0 || - Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & TabController.TabPages.Count > 1)) + if (!FrmMain.Default.IsClosing && + (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & connDock.Documents.Count() > 0 || + Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & connDock.Documents.Count() > 1)) { var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, Text), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); if (CTaskDialog.VerificationChecked) @@ -261,7 +258,7 @@ namespace mRemoteNG.UI.Window try { - foreach (TabPage tabP in TabController.TabPages) + foreach (ConnectionTab tabP in connDock.Documents) { if (tabP.Tag == null) continue; var interfaceControl = (InterfaceControl)tabP.Tag; @@ -290,17 +287,17 @@ namespace mRemoteNG.UI.Window #region TabController private void TabController_ClosePressed(object sender, EventArgs e) { - if (TabController.SelectedTab == null) + /* if (TabController.SelectedTab == null) { return; - } + }*/ CloseConnectionTab(); } private void CloseConnectionTab() { - try + /* try { var selectedTab = TabController.SelectedTab; if (selectedTab == null) return; @@ -332,7 +329,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.CloseConnectionTab() failed", ex); } - UpdateSelectedConnection(); + UpdateSelectedConnection();*/ } private void TabController_DoubleClickTab(TabControl sender, TabPage page) @@ -378,7 +375,7 @@ namespace mRemoteNG.UI.Window { try { - var interfaceControl = (InterfaceControl)TabController.SelectedTab?.Tag; + var interfaceControl = (InterfaceControl)connDock.ActivePane?.Tag; if (interfaceControl == null) return; if (interfaceControl.Info.Protocol == ProtocolType.RDP) @@ -441,7 +438,7 @@ namespace mRemoteNG.UI.Window #region Tab Actions private void ToggleSmartSize() - { + {/* try { if (!(TabController.SelectedTab?.Tag is InterfaceControl)) return; @@ -462,12 +459,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleSmartSize (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void TransferFile() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; if (interfaceControl == null) return; @@ -480,12 +477,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("TransferFile (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void SshTransferFile() { - try + /*try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; if (interfaceControl == null) return; @@ -501,12 +498,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("SSHTransferFile (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void VncTransferFile() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; var vnc = interfaceControl?.Protocol as ProtocolVNC; @@ -515,12 +512,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("VNCTransferFile (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void ToggleViewOnly() { - try + /*try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; var vnc = interfaceControl?.Protocol as ProtocolVNC; @@ -531,12 +528,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleViewOnly (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void StartChat() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; var vnc = interfaceControl?.Protocol as ProtocolVNC; @@ -545,12 +542,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("StartChat (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void RefreshScreen() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; var vnc = interfaceControl?.Protocol as ProtocolVNC; @@ -559,11 +556,11 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("RefreshScreen (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void SendSpecialKeys(ProtocolVNC.SpecialKeys keys) - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -573,11 +570,11 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("SendSpecialKeys (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void ToggleFullscreen() - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -587,11 +584,11 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleFullscreen (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void ShowPuttySettingsDialog() - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -601,7 +598,7 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void AddExternalApps() @@ -641,7 +638,7 @@ namespace mRemoteNG.UI.Window private void StartExternalApp(ExternalTool externalTool) { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; externalTool.Start(interfaceControl?.Info); @@ -649,12 +646,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)", ex); - } + }*/ } private void CloseTabMenu() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; interfaceControl?.Protocol.Close(); @@ -662,12 +659,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void CloseOtherTabs() { - try + /* try { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) { @@ -705,12 +702,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void CloseOtherTabsToTheRight() { - try + /* try { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) { @@ -748,12 +745,12 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void DuplicateTab() { - try + /* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; if (interfaceControl == null) return; @@ -763,11 +760,11 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("DuplicateTab (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void Reconnect() - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -778,25 +775,22 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("Reconnect (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void RenameTab() - { + {/* try { - var title = TabController.SelectedTab.Title; - using (FrmInputBox frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle + ":", ref title)) - { - DialogResult dr = frmInputBox.ShowDialog(); - if (dr == DialogResult.OK && !string.IsNullOrEmpty(frmInputBox.returnValue)) - TabController.SelectedTab.Title = frmInputBox.returnValue;// newTitle.Replace("&", "&&"); - } + var newTitle = TabController.SelectedTab.Title; + if (new InputBox().ShowAsDialog(Language.strNewTitle, Language.strNewTitle + ":", ref newTitle) == DialogResult.OK && + !string.IsNullOrEmpty(newTitle)) + TabController.SelectedTab.Title = newTitle.Replace("&", "&&"); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("RenameTab (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } private void CreateScreenshot() @@ -820,7 +814,7 @@ namespace mRemoteNG.UI.Window #region Tabs private delegate void CloseTabDelegate(TabPage tabToBeClosed); private void CloseTab(TabPage tabToBeClosed) - { + {/* if (tabToBeClosed.Disposing || tabToBeClosed.IsDisposed) return; @@ -861,7 +855,7 @@ namespace mRemoteNG.UI.Window { Close(); } - } + }*/ } private bool _ignoreChangeSelectedTabClick; @@ -881,11 +875,11 @@ namespace mRemoteNG.UI.Window { if (!(NativeMethods.GetForegroundWindow() == FrmMain.Default.Handle) && !_ignoreChangeSelectedTabClick) { - var clickedTab = TabController.TabPageFromPoint(e.Location); - if (clickedTab != null && TabController.SelectedTab != clickedTab) + var clickedTab = connDock.ActivePane.GetChildAtPoint(e.Location); + if (clickedTab != null && connDock.ActivePane != clickedTab) { NativeMethods.SetForegroundWindow(Handle); - TabController.SelectedTab = clickedTab; + //connDock.active = clickedTab; //Fix MagicRemove , this doesnt work this way now } } _ignoreChangeSelectedTabClick = false; @@ -901,19 +895,19 @@ namespace mRemoteNG.UI.Window _doubleClickRectangle = new Rectangle(MousePosition.X - SystemInformation.DoubleClickSize.Width / 2, MousePosition.Y - SystemInformation.DoubleClickSize.Height / 2, SystemInformation.DoubleClickSize.Width, SystemInformation.DoubleClickSize.Height); FocusInterfaceController(); } - else + /* else { TabController.OnDoubleClickTab(TabController.SelectedTab); - } + }*/ break; case MouseButtons.Middle: CloseConnectionTab(); break; case MouseButtons.Right: - if (TabController.SelectedTab?.Tag == null) return; + if (connDock.ActivePane?.Tag == null) return; ShowHideMenuButtons(); NativeMethods.SetForegroundWindow(Handle); - cmenTab.Show(TabController, e.Location); + cmenTab.Show(connDock, e.Location); break; } } @@ -924,7 +918,7 @@ namespace mRemoteNG.UI.Window } private void FocusInterfaceController() - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -933,11 +927,11 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("FocusIC (UI.Window.ConnectionWindow) failed", ex); - } + }*/ } public void RefreshInterfaceController() - { + {/* try { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; @@ -947,7 +941,7 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); - } + }*/ } #endregion @@ -958,7 +952,7 @@ namespace mRemoteNG.UI.Window { if (m.Msg == NativeMethods.WM_MOUSEACTIVATE) { - var selectedTab = TabController.SelectedTab; + var selectedTab = connDock.ActivePane; if (selectedTab == null) return; { var tabClientRectangle = selectedTab.RectangleToScreen(selectedTab.ClientRectangle); @@ -992,7 +986,7 @@ namespace mRemoteNG.UI.Window } private void TabController_PageDragMove(object sender, MouseEventArgs e) - { + {/* InTabDrag = true; // For some reason PageDragStart gets raised again after PageDragEnd so set this here instead var sourceTab = TabController.SelectedTab; @@ -1007,16 +1001,20 @@ namespace mRemoteNG.UI.Window TabController.TabPages.Remove(sourceTab); TabController.TabPages.Insert(targetIndex, sourceTab); TabController.SelectedTab = sourceTab; - TabController.TabPages.ResumeEvents(); + TabController.TabPages.ResumeEvents();*/ } private void TabController_PageDragEnd(object sender, MouseEventArgs e) - { + {/* Cursor = Cursors.Default; InTabDrag = false; var interfaceControl = TabController?.SelectedTab?.Tag as InterfaceControl; - interfaceControl?.Protocol.Focus(); + interfaceControl?.Protocol.Focus();*/ } #endregion + private void ConnectionWindow_Load(object sender, EventArgs e) + { + + } } } \ No newline at end of file diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index bf6ccc794..7b842136f 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -725,8 +725,8 @@ - - + + diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 734b439cf..65a5180fa 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -63,11 +63,6 @@ ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll - - False - References\MagicLibrary.dll - True - ..\packages\ObjectListView.Official.2.9.1\lib\net20\ObjectListView.dll @@ -686,6 +681,17 @@ Component + + + Form + + + + Component + + + Component + Component From 2d9cc286f0920f36a86ecef09d395efb7fa348d7 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 19:53:05 -0500 Subject: [PATCH 003/157] syntax clean up and null checks mostly from ReSharper --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 585 ++++++++++----------------- 1 file changed, 221 insertions(+), 364 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 2d60e95c7..4fc4de802 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -29,29 +29,29 @@ namespace mRemoteNG.UI.Tabs private int m_tabX; public int TabX { - get { return m_tabX; } - set { m_tabX = value; } + get => m_tabX; + set => m_tabX = value; } private int m_tabWidth; public int TabWidth { - get { return m_tabWidth; } - set { m_tabWidth = value; } + get => m_tabWidth; + set => m_tabWidth = value; } private int m_maxWidth; public int MaxWidth { - get { return m_maxWidth; } - set { m_maxWidth = value; } + get => m_maxWidth; + set => m_maxWidth = value; } private bool m_flag; protected internal bool Flag { - get { return m_flag; } - set { m_flag = value; } + get => m_flag; + set => m_flag = value; } private Rectangle? _rect; @@ -60,7 +60,7 @@ namespace mRemoteNG.UI.Tabs } - protected override DockPaneStripBase.Tab CreateTab(IDockContent content) + protected override Tab CreateTab(IDockContent content) { return new MremoteNGTab(content); } @@ -79,7 +79,7 @@ namespace mRemoteNG.UI.Tabs private int m_imageCategory = 0; public int ImageCategory { - get { return m_imageCategory; } + get => m_imageCategory; set { if (m_imageCategory == value) @@ -90,20 +90,11 @@ namespace mRemoteNG.UI.Tabs } } - public override Bitmap Image - { - get { return ImageCategory == 0 ? m_image0 : m_image1; } - } + public override Bitmap Image => ImageCategory == 0 ? m_image0 : m_image1; - public override Bitmap HoverImage - { - get { return null; } - } + public override Bitmap HoverImage => null; - public override Bitmap PressImage - { - get { return null; } - } + public override Bitmap PressImage => null; } #region Constants @@ -181,7 +172,7 @@ namespace mRemoteNG.UI.Tabs { get { - Rectangle rect = ClientRectangle; + var rect = ClientRectangle; return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); } } @@ -190,7 +181,7 @@ namespace mRemoteNG.UI.Tabs { get { - Rectangle rect = ClientRectangle; + var rect = ClientRectangle; return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height - DocumentStripGapTop - ToolWindowStripGapBottom); } } @@ -202,11 +193,11 @@ namespace mRemoteNG.UI.Tabs if (Appearance == DockPane.AppearanceStyle.ToolWindow) return TabStripRectangle; - Rectangle rectWindow = TabStripRectangle; - int x = rectWindow.X; - int y = rectWindow.Y; - int width = rectWindow.Width; - int height = rectWindow.Height; + var rectWindow = TabStripRectangle; + var x = rectWindow.X; + var y = rectWindow.Y; + var width = rectWindow.Width; + var height = rectWindow.Height; x += DocumentTabGapLeft; width -= DocumentTabGapLeft + @@ -220,15 +211,12 @@ namespace mRemoteNG.UI.Tabs } } - private ContextMenuStrip SelectMenu - { - get { return m_selectMenu; } - } + private ContextMenuStrip SelectMenu => m_selectMenu; public int SelectMenuMargin { - get { return _selectMenuMargin; } - set { _selectMenuMargin = value; } + get => _selectMenuMargin; + set => _selectMenuMargin = value; } private static Bitmap ImageButtonClose @@ -246,28 +234,17 @@ namespace mRemoteNG.UI.Tabs { get { - if (m_buttonClose == null) - { - m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); - m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); - m_buttonClose.Click += new EventHandler(Close_Click); - Controls.Add(m_buttonClose); - } + if (m_buttonClose != null) return m_buttonClose; + m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += Close_Click; + Controls.Add(m_buttonClose); return m_buttonClose; } } - private static Bitmap ImageButtonWindowList - { - get - { - if (m_imageButtonWindowList == null) - m_imageButtonWindowList = Resources.TabOption; - - return m_imageButtonWindowList; - } - } + private static Bitmap ImageButtonWindowList => m_imageButtonWindowList ?? (m_imageButtonWindowList = Resources.TabOption); private static Bitmap ImageButtonWindowListOverflow { @@ -288,7 +265,7 @@ namespace mRemoteNG.UI.Tabs { m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); - m_buttonWindowList.Click += new EventHandler(WindowList_Click); + m_buttonWindowList.Click += WindowList_Click; Controls.Add(m_buttonWindowList); } @@ -296,20 +273,11 @@ namespace mRemoteNG.UI.Tabs } } - private static GraphicsPath GraphicsPath - { - get { return MremoteNGAutoHideStrip.GraphicsPath; } - } + private static GraphicsPath GraphicsPath => MremoteNGAutoHideStrip.GraphicsPath; - private IContainer Components - { - get { return m_components; } - } + private IContainer Components => m_components; - public Font TextFont - { - get { return DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; } - } + public Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; private Font BoldFont { @@ -336,7 +304,7 @@ namespace mRemoteNG.UI.Tabs private int StartDisplayingTab { - get { return m_startDisplayingTab; } + get => m_startDisplayingTab; set { m_startDisplayingTab = value; @@ -346,14 +314,14 @@ namespace mRemoteNG.UI.Tabs private int EndDisplayingTab { - get { return m_endDisplayingTab; } - set { m_endDisplayingTab = value; } + get => m_endDisplayingTab; + set => m_endDisplayingTab = value; } private int FirstDisplayingTab { - get { return m_firstDisplayingTab; } - set { m_firstDisplayingTab = value; } + get => m_firstDisplayingTab; + set => m_firstDisplayingTab = value; } private bool DocumentTabsOverflow @@ -373,70 +341,31 @@ namespace mRemoteNG.UI.Tabs #region Customizable Properties - private static int ToolWindowStripGapTop - { - get { return _ToolWindowStripGapTop; } - } + private static int ToolWindowStripGapTop => _ToolWindowStripGapTop; - private static int ToolWindowStripGapBottom - { - get { return _ToolWindowStripGapBottom; } - } + private static int ToolWindowStripGapBottom => _ToolWindowStripGapBottom; - private static int ToolWindowStripGapLeft - { - get { return _ToolWindowStripGapLeft; } - } + private static int ToolWindowStripGapLeft => _ToolWindowStripGapLeft; - private static int ToolWindowStripGapRight - { - get { return _ToolWindowStripGapRight; } - } + private static int ToolWindowStripGapRight => _ToolWindowStripGapRight; - private static int ToolWindowImageHeight - { - get { return _ToolWindowImageHeight; } - } + private static int ToolWindowImageHeight => _ToolWindowImageHeight; - private static int ToolWindowImageWidth - { - get { return _ToolWindowImageWidth; } - } + private static int ToolWindowImageWidth => _ToolWindowImageWidth; - private static int ToolWindowImageGapTop - { - get { return _ToolWindowImageGapTop; } - } + private static int ToolWindowImageGapTop => _ToolWindowImageGapTop; - private static int ToolWindowImageGapBottom - { - get { return _ToolWindowImageGapBottom; } - } + private static int ToolWindowImageGapBottom => _ToolWindowImageGapBottom; - private static int ToolWindowImageGapLeft - { - get { return _ToolWindowImageGapLeft; } - } + private static int ToolWindowImageGapLeft => _ToolWindowImageGapLeft; - private static int ToolWindowImageGapRight - { - get { return _ToolWindowImageGapRight; } - } + private static int ToolWindowImageGapRight => _ToolWindowImageGapRight; - private static int ToolWindowTextGapRight - { - get { return _ToolWindowTextGapRight; } - } + private static int ToolWindowTextGapRight => _ToolWindowTextGapRight; - private static int ToolWindowTabSeperatorGapTop - { - get { return _ToolWindowTabSeperatorGapTop; } - } + private static int ToolWindowTabSeperatorGapTop => _ToolWindowTabSeperatorGapTop; - private static int ToolWindowTabSeperatorGapBottom - { - get { return _ToolWindowTabSeperatorGapBottom; } - } + private static int ToolWindowTabSeperatorGapBottom => _ToolWindowTabSeperatorGapBottom; private static string ToolTipClose { @@ -462,7 +391,7 @@ namespace mRemoteNG.UI.Tabs { get { - TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + var textFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter; @@ -473,21 +402,15 @@ namespace mRemoteNG.UI.Tabs } } - private static int DocumentStripGapTop - { - get { return _DocumentStripGapTop; } - } + private static int DocumentStripGapTop => _DocumentStripGapTop; - private static int DocumentStripGapBottom - { - get { return _DocumentStripGapBottom; } - } + private static int DocumentStripGapBottom => _DocumentStripGapBottom; private TextFormatFlags DocumentTextFormat { get { - TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + var textFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter; @@ -498,90 +421,39 @@ namespace mRemoteNG.UI.Tabs } } - private static int DocumentTabMaxWidth - { - get { return _DocumentTabMaxWidth; } - } + private static int DocumentTabMaxWidth => _DocumentTabMaxWidth; - private static int DocumentButtonGapTop - { - get { return _DocumentButtonGapTop; } - } + private static int DocumentButtonGapTop => _DocumentButtonGapTop; - private static int DocumentButtonGapBottom - { - get { return _DocumentButtonGapBottom; } - } + private static int DocumentButtonGapBottom => _DocumentButtonGapBottom; - private static int DocumentButtonGapBetween - { - get { return _DocumentButtonGapBetween; } - } + private static int DocumentButtonGapBetween => _DocumentButtonGapBetween; - private static int DocumentButtonGapRight - { - get { return _DocumentButtonGapRight; } - } + private static int DocumentButtonGapRight => _DocumentButtonGapRight; - private static int DocumentTabGapTop - { - get { return _DocumentTabGapTop; } - } + private static int DocumentTabGapTop => _DocumentTabGapTop; - private static int DocumentTabGapLeft - { - get { return _DocumentTabGapLeft; } - } + private static int DocumentTabGapLeft => _DocumentTabGapLeft; - private static int DocumentTabGapRight - { - get { return _DocumentTabGapRight; } - } + private static int DocumentTabGapRight => _DocumentTabGapRight; - private static int DocumentIconGapBottom - { - get { return _DocumentIconGapBottom; } - } + private static int DocumentIconGapBottom => _DocumentIconGapBottom; - private static int DocumentIconGapLeft - { - get { return _DocumentIconGapLeft; } - } + private static int DocumentIconGapLeft => _DocumentIconGapLeft; - private static int DocumentIconGapRight - { - get { return _DocumentIconGapRight; } - } + private static int DocumentIconGapRight => _DocumentIconGapRight; - private static int DocumentIconWidth - { - get { return _DocumentIconWidth; } - } + private static int DocumentIconWidth => _DocumentIconWidth; - private static int DocumentIconHeight - { - get { return _DocumentIconHeight; } - } + private static int DocumentIconHeight => _DocumentIconHeight; - private static int DocumentTextGapRight - { - get { return _DocumentTextGapRight; } - } + private static int DocumentTextGapRight => _DocumentTextGapRight; - private static Pen PenToolWindowTabBorder - { - get { return SystemPens.GrayText; } - } + private static Pen PenToolWindowTabBorder => SystemPens.GrayText; - private static Pen PenDocumentTabActiveBorder - { - get { return SystemPens.ControlDarkDark; } - } + private static Pen PenDocumentTabActiveBorder => SystemPens.ControlDarkDark; - private static Pen PenDocumentTabInactiveBorder - { - get { return SystemPens.GrayText; } - } + private static Pen PenDocumentTabInactiveBorder => SystemPens.GrayText; #endregion @@ -634,7 +506,7 @@ namespace mRemoteNG.UI.Tabs if (DockPane.IsAutoHide || Tabs.Count <= 1) return 0; - int height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + var height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + ToolWindowStripGapTop + ToolWindowStripGapBottom; @@ -643,7 +515,7 @@ namespace mRemoteNG.UI.Tabs private int MeasureHeight_Document() { - int height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + var height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + DocumentStripGapBottom + DocumentStripGapTop; @@ -652,8 +524,8 @@ namespace mRemoteNG.UI.Tabs protected override void OnPaint(PaintEventArgs e) { - Rectangle rect = TabsRectangle; - DockPanelGradient gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient; + var rect = TabsRectangle; + var gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient; if (Appearance == DockPane.AppearanceStyle.Document) { rect.X -= DocumentTabGapLeft; @@ -674,9 +546,9 @@ namespace mRemoteNG.UI.Tabs } //Fix MagicRemove , missing gradient implementation in themes //Also coloring in tabs in not correct in some themes - Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); - Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); - LinearGradientMode gradientMode = gradient.LinearGradientMode; + var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); + var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); + var gradientMode = gradient.LinearGradientMode; DrawingRoutines.SafelyDrawLinearGradient(rect, startColor, endColor, gradientMode, e.Graphics); base.OnPaint(e); @@ -708,14 +580,16 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetOutline_Document(int index) { - Rectangle rectTab = Tabs[index].Rectangle.Value; + var rectangle = Tabs[index].Rectangle; + if (rectangle == null) return null; + var rectTab = rectangle.Value; rectTab.X -= rectTab.Height / 2; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - GraphicsPath path = new GraphicsPath(); - GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + var path = new GraphicsPath(); + var pathTab = GetTabOutline_Document(Tabs[index], true, true, true); path.AddPath(pathTab, true); if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) @@ -735,17 +609,20 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); } return path; + } private GraphicsPath GetOutline_ToolWindow(int index) { - Rectangle rectTab = Tabs[index].Rectangle.Value; + var rectangle = Tabs[index].Rectangle; + if (rectangle == null) return null; + var rectTab = rectangle.Value; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - GraphicsPath path = new GraphicsPath(); - GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); + var path = new GraphicsPath(); + var pathTab = GetTabOutline(Tabs[index], true, true); path.AddPath(pathTab, true); path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); @@ -753,6 +630,7 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); return path; + } private void CalculateTabs() @@ -768,10 +646,10 @@ namespace mRemoteNG.UI.Tabs if (Tabs.Count <= 1 || DockPane.IsAutoHide) return; - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; // Calculate tab widths - int countTabs = Tabs.Count; + var countTabs = Tabs.Count; foreach (MremoteNGTab tab in Tabs) { tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); @@ -779,11 +657,11 @@ namespace mRemoteNG.UI.Tabs } // Set tab whose max width less than average width - bool anyWidthWithinAverage = true; - int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; - int totalAllocatedWidth = 0; - int averageWidth = totalWidth / countTabs; - int remainedTabs = countTabs; + var anyWidthWithinAverage = true; + var totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + var totalAllocatedWidth = 0; + var averageWidth = totalWidth / countTabs; + var remainedTabs = countTabs; for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0;) { anyWidthWithinAverage = false; @@ -792,14 +670,12 @@ namespace mRemoteNG.UI.Tabs if (tab.Flag) continue; - if (tab.MaxWidth <= averageWidth) - { - tab.Flag = true; - tab.TabWidth = tab.MaxWidth; - totalAllocatedWidth += tab.TabWidth; - anyWidthWithinAverage = true; - remainedTabs--; - } + if (tab.MaxWidth > averageWidth) continue; + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; } if (remainedTabs != 0) averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; @@ -808,7 +684,7 @@ namespace mRemoteNG.UI.Tabs // If any tab width not set yet, set it to the average width if (remainedTabs > 0) { - int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + var roundUpWidth = totalWidth - totalAllocatedWidth - averageWidth * remainedTabs; foreach (MremoteNGTab tab in Tabs) { if (tab.Flag) @@ -826,7 +702,7 @@ namespace mRemoteNG.UI.Tabs } // Set the X position of the tabs - int x = rectTabStrip.X + ToolWindowStripGapLeft; + var x = rectTabStrip.X + ToolWindowStripGapLeft; foreach (MremoteNGTab tab in Tabs) { tab.TabX = x; @@ -836,11 +712,11 @@ namespace mRemoteNG.UI.Tabs private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) { - bool overflow = false; + var overflow = false; - MremoteNGTab tab = Tabs[index] as MremoteNGTab; + if (!(Tabs[index] is MremoteNGTab tab)) return false; tab.MaxWidth = GetMaxTabWidth(index); - int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + var width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); if (x + width < rectTabStrip.Right || index == StartDisplayingTab) { tab.TabX = x; @@ -853,6 +729,7 @@ namespace mRemoteNG.UI.Tabs tab.TabWidth = 0; overflow = true; } + x += width; return overflow; @@ -866,10 +743,10 @@ namespace mRemoteNG.UI.Tabs if (m_startDisplayingTab >= Tabs.Count) m_startDisplayingTab = 0; - Rectangle rectTabStrip = TabsRectangle; + var rectTabStrip = TabsRectangle; - int x = rectTabStrip.X + rectTabStrip.Height / 2; - bool overflow = false; + var x = rectTabStrip.X + rectTabStrip.Height / 2; + var overflow = false; // Originally all new documents that were considered overflow // (not enough pane strip space to show all tabs) were added to @@ -878,12 +755,11 @@ namespace mRemoteNG.UI.Tabs // then we are dealing with making sure a specific tab is kept in focus. if (m_startDisplayingTab > 0) { - int tempX = x; - MremoteNGTab tab = Tabs[m_startDisplayingTab] as MremoteNGTab; - tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + var tempX = x; + if (Tabs[m_startDisplayingTab] is MremoteNGTab tab) tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); // Add the active tab and tabs to the left - for (int i = StartDisplayingTab; i >= 0; i--) + for (var i = StartDisplayingTab; i >= 0; i--) CalculateDocumentTab(rectTabStrip, ref tempX, i); // Store which tab is the first one displayed so that it @@ -895,7 +771,7 @@ namespace mRemoteNG.UI.Tabs // Start with the first tab displayed - name is a little misleading. // Loop through each tab and set its location. If there is not enough // room for all of them overflow will be returned. - for (int i = EndDisplayingTab; i < Tabs.Count; i++) + for (var i = EndDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); // If not all tabs are shown then we have an overflow. @@ -904,9 +780,9 @@ namespace mRemoteNG.UI.Tabs } else { - for (int i = StartDisplayingTab; i < Tabs.Count; i++) + for (var i = StartDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); - for (int i = 0; i < StartDisplayingTab; i++) + for (var i = 0; i < StartDisplayingTab; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); FirstDisplayingTab = StartDisplayingTab; @@ -937,14 +813,14 @@ namespace mRemoteNG.UI.Tabs private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) { - int index = Tabs.IndexOf(content); + var index = Tabs.IndexOf(content); if (index == -1) { //somehow we've lost the content from the Tab collection return false; } - MremoteNGTab tab = Tabs[index] as MremoteNGTab; - if (tab.TabWidth != 0) + + if (Tabs[index] is MremoteNGTab tab && tab.TabWidth != 0) return false; StartDisplayingTab = index; @@ -956,32 +832,28 @@ namespace mRemoteNG.UI.Tabs private int GetMaxTabWidth(int index) { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return GetMaxTabWidth_ToolWindow(index); - else - return GetMaxTabWidth_Document(index); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetMaxTabWidth_ToolWindow(index) : GetMaxTabWidth_Document(index); } private int GetMaxTabWidth_ToolWindow(int index) { - IDockContent content = Tabs[index].Content; - Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + var content = Tabs[index].Content; + var sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + ToolWindowImageGapRight + ToolWindowTextGapRight; } private int GetMaxTabWidth_Document(int index) { - IDockContent content = Tabs[index].Content; + var content = Tabs[index].Content; - int height = GetTabRectangle_Document(index).Height; + var height = GetTabRectangle_Document(index).Height; - Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + var sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); - if (DockPane.DockPanel.ShowDocumentIcon) - return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; - else - return sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; + return DockPane.DockPanel.ShowDocumentIcon + ? sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight + : sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; } private void DrawTabStrip(Graphics g) @@ -994,33 +866,31 @@ namespace mRemoteNG.UI.Tabs private void DrawTabStrip_Document(Graphics g) { - int count = Tabs.Count; + var count = Tabs.Count; if (count == 0) return; - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; // Draw the tabs - Rectangle rectTabOnly = TabsRectangle; - Rectangle rectTab = Rectangle.Empty; + var rectTabOnly = TabsRectangle; + Rectangle rectTab; MremoteNGTab tabActive = null; g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { rectTab = GetTabRectangle(i); if (Tabs[i].Content == DockPane.ActiveContent) { tabActive = Tabs[i] as MremoteNGTab; - tabActive.Rectangle = rectTab; + if (tabActive != null) tabActive.Rectangle = rectTab; continue; } - if (rectTab.IntersectsWith(rectTabOnly)) - { - var tab = Tabs[i] as MremoteNGTab; - tab.Rectangle = rectTab; - DrawTab(g, tab); - } + if (!rectTab.IntersectsWith(rectTabOnly)) continue; + if (!(Tabs[i] is MremoteNGTab tab)) continue; + tab.Rectangle = rectTab; + DrawTab(g, tab); } g.SetClip(rectTabStrip); @@ -1033,28 +903,24 @@ namespace mRemoteNG.UI.Tabs rectTabStrip.Right, rectTabStrip.Bottom - 1); g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - if (tabActive != null) - { - rectTab = tabActive.Rectangle.Value; - if (rectTab.IntersectsWith(rectTabOnly)) - { - rectTab.Intersect(rectTabOnly); - tabActive.Rectangle = rectTab; - DrawTab(g, tabActive); - } - } + if (tabActive == null) return; + rectTab = tabActive.Rectangle.Value; + if (!rectTab.IntersectsWith(rectTabOnly)) return; + rectTab.Intersect(rectTabOnly); + tabActive.Rectangle = rectTab; + DrawTab(g, tabActive); } private void DrawTabStrip_ToolWindow(Graphics g) { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top, rectTabStrip.Right, rectTabStrip.Top); - for (int i = 0; i < Tabs.Count; i++) + for (var i = 0; i < Tabs.Count; i++) { - var tab = Tabs[i] as MremoteNGTab; + if (!(Tabs[i] is MremoteNGTab tab)) continue; tab.Rectangle = GetTabRectangle(i); DrawTab(g, tab); } @@ -1062,29 +928,26 @@ namespace mRemoteNG.UI.Tabs private Rectangle GetTabRectangle(int index) { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return GetTabRectangle_ToolWindow(index); - else - return GetTabRectangle_Document(index); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabRectangle_ToolWindow(index) : GetTabRectangle_Document(index); } private Rectangle GetTabRectangle_ToolWindow(int index) { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; - MremoteNGTab tab = (MremoteNGTab)(Tabs[index]); + var tab = (MremoteNGTab)Tabs[index]; return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height); } private Rectangle GetTabRectangle_Document(int index) { - Rectangle rectTabStrip = TabStripRectangle; - MremoteNGTab tab = (MremoteNGTab)Tabs[index]; + var rectTabStrip = TabStripRectangle; + var tab = (MremoteNGTab)Tabs[index]; - Rectangle rect = new Rectangle(); - rect.X = tab.TabX; - rect.Width = tab.TabWidth; - rect.Height = rectTabStrip.Height - DocumentTabGapTop; + var rect = new Rectangle + { + X = tab.TabX, Width = tab.TabWidth, Height = rectTabStrip.Height - DocumentTabGapTop + }; if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) rect.Y = rectTabStrip.Y + DocumentStripGapBottom; @@ -1104,15 +967,12 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); - else - return GetTabOutline_Document(tab, rtlTransform, toScreen, false); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabOutline_ToolWindow(tab, rtlTransform, toScreen) : GetTabOutline_Document(tab, rtlTransform, toScreen, false); } private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) { - Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + var rect = GetTabRectangle(Tabs.IndexOf(tab)); if (rtlTransform) rect = DrawHelper.RtlTransform(this, rect); if (toScreen) @@ -1124,10 +984,10 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full) { - int curveSize = 6; + const int curveSize = 6; GraphicsPath.Reset(); - Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + var rect = GetTabRectangle(Tabs.IndexOf(tab)); // Shorten TabOutline so it doesn't get overdrawn by icons next to it rect.Intersect(TabsRectangle); @@ -1240,9 +1100,7 @@ namespace mRemoteNG.UI.Tabs } } - if (Tabs.IndexOf(tab) != EndDisplayingTab && - (Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent) - && !full) + if (Tabs.IndexOf(tab) != EndDisplayingTab && Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent && !full) { if (RightToLeft == RightToLeft.Yes) { @@ -1295,12 +1153,13 @@ namespace mRemoteNG.UI.Tabs private void DrawTab_ToolWindow(Graphics g, MremoteNGTab tab) { + if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; - Rectangle rectIcon = new Rectangle( + var rectIcon = new Rectangle( rect.X + ToolWindowImageGapLeft, rect.Y + rect.Height - 1 - ToolWindowImageGapBottom - ToolWindowImageHeight, ToolWindowImageWidth, ToolWindowImageHeight); - Rectangle rectText = PatchController.EnableHighDpi == true + var rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + ToolWindowImageGapLeft, rect.Y - 1 + rect.Height - ToolWindowImageGapBottom - TextFont.Height, @@ -1308,38 +1167,38 @@ namespace mRemoteNG.UI.Tabs : rectIcon; rectText.X += rectIcon.Width + ToolWindowImageGapRight; rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - - ToolWindowImageGapRight - ToolWindowTextGapRight; + ToolWindowImageGapRight - ToolWindowTextGapRight; - Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + var rectTab = DrawHelper.RtlTransform(this, rect); rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - GraphicsPath path = GetTabOutline(tab, true, false); + var path = GetTabOutline(tab, true, false); if (DockPane.ActiveContent == tab.Content) { - Color startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor; - Color endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor; - LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode; + var startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor; + var endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor; + var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode; g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); g.DrawPath(PenToolWindowTabBorder, path); - Color textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor; + var textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor; TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); } else { - Color startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor; - Color endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor; - LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode; + var startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor; + var endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor; + var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode; g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); if (Tabs.IndexOf(DockPane.ActiveContent) != Tabs.IndexOf(tab) + 1) { - Point pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop); - Point pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); + var pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop); + var pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); g.DrawLine(PenToolWindowTabBorder, DrawHelper.RtlTransform(this, pt1), DrawHelper.RtlTransform(this, pt2)); } - Color textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor; + var textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor; TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); } @@ -1349,15 +1208,16 @@ namespace mRemoteNG.UI.Tabs private void DrawTab_Document(Graphics g, MremoteNGTab tab) { + if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; if (tab.TabWidth == 0) return; - Rectangle rectIcon = new Rectangle( + var rectIcon = new Rectangle( rect.X + DocumentIconGapLeft, rect.Y + rect.Height - 1 - DocumentIconGapBottom - DocumentIconHeight, DocumentIconWidth, DocumentIconHeight); - Rectangle rectText = PatchController.EnableHighDpi == true + var rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + DocumentIconGapLeft, rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, @@ -1368,29 +1228,29 @@ namespace mRemoteNG.UI.Tabs rectText.X += rectIcon.Width + DocumentIconGapRight; rectText.Y = rect.Y; rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - - DocumentIconGapRight - DocumentTextGapRight; + DocumentIconGapRight - DocumentTextGapRight; rectText.Height = rect.Height; } else rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight; - Rectangle rectTab = DrawHelper.RtlTransform(this, rect); - Rectangle rectBack = DrawHelper.RtlTransform(this, rect); + var rectTab = DrawHelper.RtlTransform(this, rect); + var rectBack = DrawHelper.RtlTransform(this, rect); rectBack.Width += DocumentIconGapLeft; rectBack.X -= DocumentIconGapLeft; rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - GraphicsPath path = GetTabOutline(tab, true, false); + var path = GetTabOutline(tab, true, false); if (DockPane.ActiveContent == tab.Content) { - Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode; + var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode; g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); g.DrawPath(PenDocumentTabActiveBorder, path); - Color textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); + var textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); if (DockPane.IsActiveDocumentPane) TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, textColor, DocumentTextFormat); else @@ -1398,13 +1258,13 @@ namespace mRemoteNG.UI.Tabs } else { - Color startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); - Color endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); - LinearGradientMode gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode; + var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); + var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); + var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode; g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); g.DrawPath(PenDocumentTabInactiveBorder, path); - Color textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Foreground"); + var textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Foreground"); TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); } @@ -1417,10 +1277,10 @@ namespace mRemoteNG.UI.Tabs SelectMenu.Items.Clear(); foreach (MremoteNGTab tab in Tabs) { - IDockContent content = tab.Content; - ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); + var content = tab.Content; + var item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); item.Tag = tab.Content; - item.Click += new EventHandler(ContextMenuItem_Click); + item.Click += ContextMenuItem_Click; } var workingArea = Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, ButtonWindowList.Height / 2))); @@ -1451,12 +1311,9 @@ namespace mRemoteNG.UI.Tabs private void ContextMenuItem_Click(object sender, EventArgs e) { - ToolStripMenuItem item = sender as ToolStripMenuItem; - if (item != null) - { - IDockContent content = (IDockContent)item.Tag; - DockPane.ActiveContent = content; - } + if (!(sender is ToolStripMenuItem item)) return; + var content = (IDockContent)item.Tag; + DockPane.ActiveContent = content; } private void SetInertButtons() @@ -1471,8 +1328,8 @@ namespace mRemoteNG.UI.Tabs } else { - ButtonClose.Enabled = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton; - m_closeButtonVisible = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButtonVisible; + ButtonClose.Enabled = DockPane.ActiveContent == null || DockPane.ActiveContent.DockHandler.CloseButton; + m_closeButtonVisible = DockPane.ActiveContent == null || DockPane.ActiveContent.DockHandler.CloseButtonVisible; ButtonClose.Visible = m_closeButtonVisible; ButtonClose.RefreshChanges(); ButtonWindowList.RefreshChanges(); @@ -1492,23 +1349,23 @@ namespace mRemoteNG.UI.Tabs private void LayoutButtons() { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; // Set position and size of the buttons - int buttonWidth = ButtonClose.Image.Width; - int buttonHeight = ButtonClose.Image.Height; - int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; + var buttonWidth = ButtonClose.Image.Width; + var buttonHeight = ButtonClose.Image.Height; + var height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; if (buttonHeight < height) { buttonWidth = buttonWidth * height / buttonHeight; buttonHeight = height; } - Size buttonSize = new Size(buttonWidth, buttonHeight); + var buttonSize = new Size(buttonWidth, buttonHeight); - int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft + var x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft - DocumentButtonGapRight - buttonWidth; - int y = rectTabStrip.Y + DocumentButtonGapTop; - Point point = new Point(x, y); + var y = rectTabStrip.Y + DocumentButtonGapTop; + var point = new Point(x, y); ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); // If the close button is not visible draw the window list button overtop. @@ -1533,9 +1390,9 @@ namespace mRemoteNG.UI.Tabs if (!TabsRectangle.Contains(point)) return -1; - foreach (Tab tab in Tabs) + foreach (var tab in Tabs) { - GraphicsPath path = GetTabOutline(tab, true, false); + var path = GetTabOutline(tab, true, false); if (path.IsVisible(point)) return Tabs.IndexOf(tab); } @@ -1544,22 +1401,22 @@ namespace mRemoteNG.UI.Tabs protected override Rectangle GetTabBounds(Tab tab) { - GraphicsPath path = GetTabOutline(tab, true, false); - RectangleF rectangle = path.GetBounds(); + var path = GetTabOutline(tab, true, false); + var rectangle = path.GetBounds(); return new Rectangle((int)rectangle.Left, (int)rectangle.Top, (int)rectangle.Width, (int)rectangle.Height); } protected override void OnMouseHover(EventArgs e) { - int index = HitTest(PointToClient(Control.MousePosition)); - string toolTip = string.Empty; + var index = HitTest(PointToClient(MousePosition)); + var toolTip = string.Empty; base.OnMouseHover(e); if (index != -1) { - MremoteNGTab tab = Tabs[index] as MremoteNGTab; - if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) + if (!(Tabs[index] is MremoteNGTab tab)) return; + if (!string.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) toolTip = tab.Content.DockHandler.ToolTipText; else if (tab.MaxWidth > tab.TabWidth) toolTip = tab.Content.DockHandler.TabText; From bb9d2a0a69175aceb9e2a22ef3a811d769151137 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 19:58:58 -0500 Subject: [PATCH 004/157] move to correct namespace --- mRemoteV1/UI/Forms/frmMain.cs | 13 ++++++------- mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs | 2 +- mRemoteV1/UI/Tabs/ConnectionTab.cs | 16 ++++------------ mRemoteV1/UI/Window/ConnectionWindow.cs | 5 ++--- 4 files changed, 13 insertions(+), 23 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 5fefe61ff..22ad6020c 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -23,7 +23,7 @@ using mRemoteNG.Messages.MessageWriters; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Menu; -using mRemoteNG.UI.Panels; +using mRemoteNG.UI.Tabs; using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.Window; using WeifenLuo.WinFormsUI.Docking; @@ -518,15 +518,14 @@ namespace mRemoteNG.UI.Forms private void ActivateConnection() { var w = pnlDock.Controls[0] as DockPanel; - if (w?.ActiveDocument == null) return; - var tab = w.ActiveDocument as ConnectionTab; - var ifc = (InterfaceControl)tab.ActiveControl; - if (ifc == null) return; + if (!(w?.ActiveDocument is ConnectionTab tab)) return; + var ifc = (InterfaceControl)tab.ActiveControl; + if (ifc == null) return; - ifc.Protocol.Focus(); + ifc.Protocol.Focus(); var conFormWindow = ifc.FindForm(); ((ConnectionTab)conFormWindow)?.RefreshInterfaceController(); - } + } private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs index 644cd91c7..f1262d7d1 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs @@ -1,4 +1,4 @@ -namespace mRemoteNG.UI.Forms +namespace mRemoteNG.UI.Tabs { partial class ConnectionTab { diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 4cd1ce65d..1cbc9fd9e 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -1,23 +1,15 @@ -using mRemoteNG.App; +using System; +using System.Windows.Forms; +using mRemoteNG.App; using mRemoteNG.App.Info; using mRemoteNG.Config; using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.UI.TaskDialog; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Security.Permissions; -using System.Text; -using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; - -namespace mRemoteNG.UI.Forms +namespace mRemoteNG.UI.Tabs { public partial class ConnectionTab : DockContent { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index ec5d62b5e..0ed5e923a 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.Linq; -using System.Runtime.InteropServices; using System.Windows.Forms; using BrightIdeasSoftware; using mRemoteNG.App; @@ -15,9 +14,9 @@ using mRemoteNG.Container; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Forms; -using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.TaskDialog; using WeifenLuo.WinFormsUI.Docking; +using ConnectionTab = mRemoteNG.UI.Tabs.ConnectionTab; using Message = System.Windows.Forms.Message; namespace mRemoteNG.UI.Window @@ -25,7 +24,7 @@ namespace mRemoteNG.UI.Window public partial class ConnectionWindow : BaseWindow { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender; + private VisualStudioToolStripExtender vsToolStripExtender; private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); #region Public Methods From 172f7f70857923a372a09a9e737053921deb1f15 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:01:43 -0500 Subject: [PATCH 005/157] minor code cleanup --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 10 +++++----- mRemoteV1/UI/Window/ConnectionWindow.cs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 1cbc9fd9e..c751f7323 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -17,7 +17,7 @@ namespace mRemoteNG.UI.Tabs public ConnectionTab() { InitializeComponent(); - this.FormClosing += formClosingEventHandler; + FormClosing += formClosingEventHandler; } @@ -31,7 +31,7 @@ namespace mRemoteNG.UI.Tabs { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, this.TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); if (CTaskDialog.VerificationChecked) { Settings.Default.ConfirmCloseConnection--; @@ -41,7 +41,7 @@ namespace mRemoteNG.UI.Tabs return; } } - var interfaceControl = (InterfaceControl)this.Tag; + var interfaceControl = (InterfaceControl)Tag; interfaceControl.Protocol.Close(); } catch (Exception ex) @@ -84,13 +84,13 @@ namespace mRemoteNG.UI.Tabs { try { - var interfaceControl = this.Tag as InterfaceControl; + var interfaceControl = Tag as InterfaceControl; if (interfaceControl?.Info.Protocol == ProtocolType.VNC) ((ProtocolVNC)interfaceControl.Protocol).RefreshScreen(); } catch (Exception ex) { - App.Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); + Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); } } #endregion diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 0ed5e923a..fed9e1b3e 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -104,7 +104,7 @@ namespace mRemoteNG.UI.Window conTab.Tag = connectionInfo; //Set the connection text based on name and preferences - string titleText = ""; + string titleText; if (Settings.Default.ShowProtocolOnTabs) titleText = connectionInfo.Protocol + @": "; else @@ -174,15 +174,15 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (ThemeManager.getInstance().ThemingActive) + if (!ThemeManager.getInstance().ThemingActive) return; + base.ApplyTheme(); + connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; + vsToolStripExtender = new VisualStudioToolStripExtender(components) { - base.ApplyTheme(); - this.connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; - this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); - vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; - vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); - connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - } + DefaultRenderer = _toolStripProfessionalRenderer + }; + vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } private bool _documentHandlersAdded; From aefee9c92b5dd20abd126889defcd40d3d0674e0 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:04:57 -0500 Subject: [PATCH 006/157] code cleanup --- mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs | 221 ++++++++------------ 1 file changed, 83 insertions(+), 138 deletions(-) diff --git a/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs index a1c8d425c..265b88915 100644 --- a/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs +++ b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs @@ -1,16 +1,12 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Tabs { - class MremoteNGAutoHideStrip : AutoHideStripBase + internal sealed class MremoteNGAutoHideStrip : AutoHideStripBase { private class TabNG : Tab { @@ -19,20 +15,9 @@ namespace mRemoteNG.UI.Tabs { } - private int m_tabX = 0; - public int TabX - { - get { return m_tabX; } - set { m_tabX = value; } - } - - private int m_tabWidth = 0; - public int TabWidth - { - get { return m_tabWidth; } - set { m_tabWidth = value; } - } + public int TabX { get; set; } + public int TabWidth { get; set; } } private const int _ImageHeight = 16; @@ -48,10 +33,7 @@ namespace mRemoteNG.UI.Tabs private const int _TabGapBetween = 10; #region Customizable Properties - public Font TextFont - { - get { return DockPanel.Theme.Skin.AutoHideStripSkin.TextFont; } - } + public Font TextFont => DockPanel.Theme.Skin.AutoHideStripSkin.TextFont; private static StringFormat _stringFormatTabHorizontal; private StringFormat StringFormatTabHorizontal @@ -60,11 +42,13 @@ namespace mRemoteNG.UI.Tabs { if (_stringFormatTabHorizontal == null) { - _stringFormatTabHorizontal = new StringFormat(); - _stringFormatTabHorizontal.Alignment = StringAlignment.Near; - _stringFormatTabHorizontal.LineAlignment = StringAlignment.Center; - _stringFormatTabHorizontal.FormatFlags = StringFormatFlags.NoWrap; - _stringFormatTabHorizontal.Trimming = StringTrimming.None; + _stringFormatTabHorizontal = new StringFormat + { + Alignment = StringAlignment.Near, + LineAlignment = StringAlignment.Center, + FormatFlags = StringFormatFlags.NoWrap, + Trimming = StringTrimming.None + }; } if (RightToLeft == RightToLeft.Yes) @@ -98,72 +82,33 @@ namespace mRemoteNG.UI.Tabs } } - private static int ImageHeight - { - get { return _ImageHeight; } - } + private static int ImageHeight => _ImageHeight; - private static int ImageWidth - { - get { return _ImageWidth; } - } + private static int ImageWidth => _ImageWidth; - private static int ImageGapTop - { - get { return _ImageGapTop; } - } + private static int ImageGapTop => _ImageGapTop; - private static int ImageGapLeft - { - get { return _ImageGapLeft; } - } + private static int ImageGapLeft => _ImageGapLeft; - private static int ImageGapRight - { - get { return _ImageGapRight; } - } + private static int ImageGapRight => _ImageGapRight; - private static int ImageGapBottom - { - get { return _ImageGapBottom; } - } + private static int ImageGapBottom => _ImageGapBottom; - private static int TextGapLeft - { - get { return _TextGapLeft; } - } + private static int TextGapLeft => _TextGapLeft; - private static int TextGapRight - { - get { return _TextGapRight; } - } + private static int TextGapRight => _TextGapRight; - private static int TabGapTop - { - get { return _TabGapTop; } - } + private static int TabGapTop => _TabGapTop; - private static int TabGapLeft - { - get { return _TabGapLeft; } - } + private static int TabGapLeft => _TabGapLeft; - private static int TabGapBetween - { - get { return _TabGapBetween; } - } + private static int TabGapBetween => _TabGapBetween; + + private static Pen PenTabBorder => SystemPens.GrayText; - private static Pen PenTabBorder - { - get { return SystemPens.GrayText; } - } #endregion - private static Matrix _matrixIdentity = new Matrix(); - private static Matrix MatrixIdentity - { - get { return _matrixIdentity; } - } + private static Matrix MatrixIdentity { get; } = new Matrix(); private static DockState[] _dockStates; private static DockState[] DockStates @@ -207,12 +152,12 @@ namespace mRemoteNG.UI.Tabs protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); - Graphics g = e.Graphics; + var g = e.Graphics; - Color startColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.StartColor; - Color endColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.EndColor; - LinearGradientMode gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode; - using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + var startColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.StartColor; + var endColor = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.EndColor; + var gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode; + using (var brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) { g.FillRectangle(brush, ClientRectangle); } @@ -236,21 +181,21 @@ namespace mRemoteNG.UI.Tabs private void DrawTabStrip(Graphics g, DockState dockState) { - Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + var rectTabStrip = GetLogicalTabStripRectangle(dockState); if (rectTabStrip.IsEmpty) return; - Matrix matrixIdentity = g.Transform; + var matrixIdentity = g.Transform; if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) { - Matrix matrixRotated = new Matrix(); - matrixRotated.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, - (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + var matrixRotated = new Matrix(); + matrixRotated.RotateAt(90, new PointF(rectTabStrip.X + (float)rectTabStrip.Height / 2, + rectTabStrip.Y + (float)rectTabStrip.Height / 2)); g.Transform = matrixRotated; } - foreach (Pane pane in GetPanes(dockState)) + foreach (var pane in GetPanes(dockState)) { foreach (TabNG tab in pane.AutoHideTabs) DrawTab(g, tab); @@ -268,19 +213,19 @@ namespace mRemoteNG.UI.Tabs private void CalculateTabs(DockState dockState) { - Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + var rectTabStrip = GetLogicalTabStripRectangle(dockState); - int imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom; - int imageWidth = ImageWidth; + var imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom; + var imageWidth = ImageWidth; if (imageHeight > ImageHeight) imageWidth = ImageWidth * (imageHeight / ImageHeight); - int x = TabGapLeft + rectTabStrip.X; - foreach (Pane pane in GetPanes(dockState)) + var x = TabGapLeft + rectTabStrip.X; + foreach (var pane in GetPanes(dockState)) { foreach (TabNG tab in pane.AutoHideTabs) { - int width = imageWidth + ImageGapLeft + ImageGapRight + + var width = imageWidth + ImageGapLeft + ImageGapRight + TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + TextGapLeft + TextGapRight; tab.TabX = x; @@ -305,11 +250,11 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline(TabNG tab, bool transformed, bool rtlTransform) { - DockState dockState = tab.Content.DockHandler.DockState; - Rectangle rectTab = GetTabRectangle(tab, transformed); + var dockState = tab.Content.DockHandler.DockState; + var rectTab = GetTabRectangle(tab, transformed); if (rtlTransform) rectTab = RtlTransform(rectTab, dockState); - bool upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide); + var upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide); DrawHelper.GetRoundedCornerTab(GraphicsPath, rectTab, upTab); return GraphicsPath; @@ -317,31 +262,31 @@ namespace mRemoteNG.UI.Tabs private void DrawTab(Graphics g, TabNG tab) { - Rectangle rectTabOrigin = GetTabRectangle(tab); + var rectTabOrigin = GetTabRectangle(tab); if (rectTabOrigin.IsEmpty) return; - DockState dockState = tab.Content.DockHandler.DockState; - IDockContent content = tab.Content; + var dockState = tab.Content.DockHandler.DockState; + var content = tab.Content; - GraphicsPath path = GetTabOutline(tab, false, true); - Color startColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.StartColor; - Color endColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.EndColor; - LinearGradientMode gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode; + var path = GetTabOutline(tab, false, true); + var startColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.StartColor; + var endColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.EndColor; + var gradientMode = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode; g.FillPath(new LinearGradientBrush(rectTabOrigin, startColor, endColor, gradientMode), path); g.DrawPath(PenTabBorder, path); // Set no rotate for drawing icon and text - using (Matrix matrixRotate = g.Transform) + using (var matrixRotate = g.Transform) { g.Transform = MatrixIdentity; // Draw the icon - Rectangle rectImage = rectTabOrigin; + var rectImage = rectTabOrigin; rectImage.X += ImageGapLeft; rectImage.Y += ImageGapTop; - int imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom; - int imageWidth = ImageWidth; + var imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom; + var imageWidth = ImageWidth; if (imageHeight > ImageHeight) imageWidth = ImageWidth * (imageHeight / ImageHeight); rectImage.Height = imageHeight; @@ -351,7 +296,7 @@ namespace mRemoteNG.UI.Tabs if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) { // The DockState is DockLeftAutoHide or DockRightAutoHide, so rotate the image 90 degrees to the right. - Rectangle rectTransform = RtlTransform(rectImage, dockState); + var rectTransform = RtlTransform(rectImage, dockState); Point[] rotationPoints = { new Point(rectTransform.X + rectTransform.Width, rectTransform.Y), @@ -359,7 +304,7 @@ namespace mRemoteNG.UI.Tabs new Point(rectTransform.X, rectTransform.Y) }; - using (Icon rotatedIcon = new Icon(((Form)content).Icon, 16, 16)) + using (var rotatedIcon = new Icon(((Form)content).Icon, 16, 16)) { g.DrawImage(rotatedIcon.ToBitmap(), rotationPoints); } @@ -371,12 +316,12 @@ namespace mRemoteNG.UI.Tabs } // Draw the text - Rectangle rectText = rectTabOrigin; + var rectText = rectTabOrigin; rectText.X += ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; rectText.Width -= ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; rectText = RtlTransform(GetTransformedRectangle(dockState, rectText), dockState); - Color textColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.TextColor; + var textColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.TextColor; if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical); @@ -398,10 +343,10 @@ namespace mRemoteNG.UI.Tabs if (!DockHelper.IsDockStateAutoHide(dockState)) return Rectangle.Empty; - int leftPanes = GetPanes(DockState.DockLeftAutoHide).Count; - int rightPanes = GetPanes(DockState.DockRightAutoHide).Count; - int topPanes = GetPanes(DockState.DockTopAutoHide).Count; - int bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count; + var leftPanes = GetPanes(DockState.DockLeftAutoHide).Count; + var rightPanes = GetPanes(DockState.DockRightAutoHide).Count; + var topPanes = GetPanes(DockState.DockTopAutoHide).Count; + var bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count; int x, y, width, height; @@ -453,18 +398,18 @@ namespace mRemoteNG.UI.Tabs private Rectangle GetTabRectangle(TabNG tab, bool transformed) { - DockState dockState = tab.Content.DockHandler.DockState; - Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + var dockState = tab.Content.DockHandler.DockState; + var rectTabStrip = GetLogicalTabStripRectangle(dockState); if (rectTabStrip.IsEmpty) return Rectangle.Empty; - int x = tab.TabX; - int y = rectTabStrip.Y + + var x = tab.TabX; + var y = rectTabStrip.Y + (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ? 0 : TabGapTop); - int width = tab.TabWidth; - int height = rectTabStrip.Height - TabGapTop; + var width = tab.TabWidth; + var height = rectTabStrip.Height - TabGapTop; if (!transformed) return new Rectangle(x, y, width, height); @@ -477,15 +422,15 @@ namespace mRemoteNG.UI.Tabs if (dockState != DockState.DockLeftAutoHide && dockState != DockState.DockRightAutoHide) return rect; - PointF[] pts = new PointF[1]; + var pts = new PointF[1]; // the center of the rectangle - pts[0].X = (float)rect.X + (float)rect.Width / 2; - pts[0].Y = (float)rect.Y + (float)rect.Height / 2; - Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + pts[0].X = rect.X + (float)rect.Width / 2; + pts[0].Y = rect.Y + (float)rect.Height / 2; + var rectTabStrip = GetLogicalTabStripRectangle(dockState); using (var matrix = new Matrix()) { - matrix.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, - (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + matrix.RotateAt(90, new PointF(rectTabStrip.X + (float)rectTabStrip.Height / 2, + rectTabStrip.Y + (float)rectTabStrip.Height / 2)); matrix.TransformPoints(pts); } @@ -496,17 +441,17 @@ namespace mRemoteNG.UI.Tabs protected override IDockContent HitTest(Point point) { - foreach (DockState state in DockStates) + foreach (var state in DockStates) { - Rectangle rectTabStrip = GetLogicalTabStripRectangle(state, true); + var rectTabStrip = GetLogicalTabStripRectangle(state, true); if (!rectTabStrip.Contains(point)) continue; - foreach (Pane pane in GetPanes(state)) + foreach (var pane in GetPanes(state)) { foreach (TabNG tab in pane.AutoHideTabs) { - GraphicsPath path = GetTabOutline(tab, true, true); + var path = GetTabOutline(tab, true, true); if (path.IsVisible(point)) return tab.Content; } @@ -518,8 +463,8 @@ namespace mRemoteNG.UI.Tabs protected override Rectangle GetTabBounds(Tab tab) { - GraphicsPath path = GetTabOutline((TabNG)tab, true, true); - RectangleF bounds = path.GetBounds(); + var path = GetTabOutline((TabNG)tab, true, true); + var bounds = path.GetBounds(); return new Rectangle((int)bounds.Left, (int)bounds.Top, (int)bounds.Width, (int)bounds.Height); } @@ -536,7 +481,7 @@ namespace mRemoteNG.UI.Tabs Invalidate(); } - protected override AutoHideStripBase.Tab CreateTab(IDockContent content) + protected override Tab CreateTab(IDockContent content) { return new TabNG(content); } From c322946c32a3dc744b7caf1799eda32641bc3659 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:06:42 -0500 Subject: [PATCH 007/157] minor cleanup --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 4fc4de802..e75b52de4 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -1,13 +1,8 @@ using mRemoteNG.Themes; using System; -using System.Collections; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; @@ -367,25 +362,9 @@ namespace mRemoteNG.UI.Tabs private static int ToolWindowTabSeperatorGapBottom => _ToolWindowTabSeperatorGapBottom; - private static string ToolTipClose - { - get - { - if (m_toolTipClose == null) - m_toolTipClose = Language.strRadioCloseWarnExit; - return m_toolTipClose; - } - } + private static string ToolTipClose => m_toolTipClose ?? (m_toolTipClose = Language.strRadioCloseWarnExit); - private static string ToolTipSelect - { - get - { - if (m_toolTipSelect == null) - m_toolTipSelect = Language.strTabsAndPanels; - return m_toolTipSelect; - } - } + private static string ToolTipSelect => m_toolTipSelect ?? (m_toolTipSelect = Language.strTabsAndPanels); private TextFormatFlags ToolWindowTextFormat { From 2b5a327e533bb67cd73e1f6bb85e57aa77e2f73c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:10:41 -0500 Subject: [PATCH 008/157] auto properties --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 75 +++++++--------------------- 1 file changed, 19 insertions(+), 56 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index e75b52de4..abc9f3cf9 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -21,33 +21,13 @@ namespace mRemoteNG.UI.Tabs { } - private int m_tabX; - public int TabX - { - get => m_tabX; - set => m_tabX = value; - } + public int TabX { get; set; } - private int m_tabWidth; - public int TabWidth - { - get => m_tabWidth; - set => m_tabWidth = value; - } + public int TabWidth { get; set; } - private int m_maxWidth; - public int MaxWidth - { - get => m_maxWidth; - set => m_maxWidth = value; - } + public int MaxWidth { get; set; } - private bool m_flag; - protected internal bool Flag - { - get => m_flag; - set => m_flag = value; - } + protected internal bool Flag { get; set; } private Rectangle? _rect; @@ -71,7 +51,7 @@ namespace mRemoteNG.UI.Tabs m_image1 = image1; } - private int m_imageCategory = 0; + private int m_imageCategory; public int ImageCategory { get => m_imageCategory; @@ -129,24 +109,19 @@ namespace mRemoteNG.UI.Tabs #region Members - private ContextMenuStrip m_selectMenu; private static Bitmap m_imageButtonClose; private InertButton m_buttonClose; private static Bitmap m_imageButtonWindowList; private static Bitmap m_imageButtonWindowListOverflow; private InertButton m_buttonWindowList; - private IContainer m_components; - private ToolTip m_toolTip; + private readonly ToolTip m_toolTip; private Font m_font; private Font m_boldFont; - private int m_startDisplayingTab = 0; - private int m_endDisplayingTab = 0; - private int m_firstDisplayingTab = 0; - private bool m_documentTabsOverflow = false; + private int m_startDisplayingTab; + private bool m_documentTabsOverflow; private static string m_toolTipSelect; private static string m_toolTipClose; - private bool m_closeButtonVisible = false; - private int _selectMenuMargin = 5; + private bool m_closeButtonVisible; #endregion @@ -206,13 +181,9 @@ namespace mRemoteNG.UI.Tabs } } - private ContextMenuStrip SelectMenu => m_selectMenu; + private ContextMenuStrip SelectMenu { get; } - public int SelectMenuMargin - { - get => _selectMenuMargin; - set => _selectMenuMargin = value; - } + public int SelectMenuMargin { get; set; } = 5; private static Bitmap ImageButtonClose { @@ -270,7 +241,7 @@ namespace mRemoteNG.UI.Tabs private static GraphicsPath GraphicsPath => MremoteNGAutoHideStrip.GraphicsPath; - private IContainer Components => m_components; + private IContainer Components { get; } public Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; @@ -286,7 +257,7 @@ namespace mRemoteNG.UI.Tabs m_font = TextFont; m_boldFont = new Font(TextFont, FontStyle.Bold); } - else if (m_font != TextFont) + else if (!Equals(m_font, TextFont)) { m_boldFont.Dispose(); m_font = TextFont; @@ -307,17 +278,9 @@ namespace mRemoteNG.UI.Tabs } } - private int EndDisplayingTab - { - get => m_endDisplayingTab; - set => m_endDisplayingTab = value; - } + private int EndDisplayingTab { get; set; } - private int FirstDisplayingTab - { - get => m_firstDisplayingTab; - set => m_firstDisplayingTab = value; - } + private int FirstDisplayingTab { get; set; } private bool DocumentTabsOverflow { @@ -450,10 +413,10 @@ namespace mRemoteNG.UI.Tabs - m_components = new System.ComponentModel.Container(); + Components = new System.ComponentModel.Container(); m_toolTip = new ToolTip(Components); - m_selectMenu = new ContextMenuStrip(Components); - pane.DockPanel.Theme.ApplyTo(m_selectMenu); + SelectMenu = new ContextMenuStrip(Components); + pane.DockPanel.Theme.ApplyTo(SelectMenu); ResumeLayout(); } @@ -636,7 +599,7 @@ namespace mRemoteNG.UI.Tabs } // Set tab whose max width less than average width - var anyWidthWithinAverage = true; + bool anyWidthWithinAverage; var totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; var totalAllocatedWidth = 0; var averageWidth = totalWidth / countTabs; From 325bd510ff089789378b194557419e7bd38b0449 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:14:55 -0500 Subject: [PATCH 009/157] minor clean up --- mRemoteV1/UI/Window/ConfigWindow.cs | 910 ++++++++++++++-------------- 1 file changed, 448 insertions(+), 462 deletions(-) diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 0e2b97f89..65ecb04e3 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -46,7 +46,7 @@ namespace mRemoteNG.UI.Window private AbstractConnectionRecord _selectedTreeNode; public AbstractConnectionRecord SelectedTreeNode { - get { return _selectedTreeNode; } + get => _selectedTreeNode; set { _selectedTreeNode = value; @@ -207,11 +207,8 @@ namespace mRemoteNG.UI.Window #region Public Properties public bool PropertiesVisible { - get - { - return _btnShowProperties.Checked; - } - set + get => _btnShowProperties.Checked; + set { _btnShowProperties.Checked = value; if (!value) return; @@ -223,11 +220,8 @@ namespace mRemoteNG.UI.Window public bool InheritanceVisible { - get - { - return _btnShowInheritance.Checked; - } - set + get => _btnShowInheritance.Checked; + set { _btnShowInheritance.Checked = value; if (!value) return; @@ -239,11 +233,8 @@ namespace mRemoteNG.UI.Window public bool DefaultPropertiesVisible { - get - { - return _btnShowDefaultProperties.Checked; - } - set + get => _btnShowDefaultProperties.Checked; + set { _btnShowDefaultProperties.Checked = value; if (!value) return; @@ -255,8 +246,8 @@ namespace mRemoteNG.UI.Window public bool DefaultInheritanceVisible { - get { return _btnShowDefaultInheritance.Checked; } - set + get => _btnShowDefaultInheritance.Checked; + set { _btnShowDefaultInheritance.Checked = value; if (!value) return; @@ -617,20 +608,18 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (Themes.ThemeManager.getInstance().ThemingActive) - { - _pGrid.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - _pGrid.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - _pGrid.ViewBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Background"); - _pGrid.ViewForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); - _pGrid.LineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Border"); - _pGrid.HelpBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - _pGrid.HelpForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - _pGrid.CategoryForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); - _pGrid.CommandsDisabledLinkColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); - _pGrid.CommandsBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); - _pGrid.CommandsForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); - } + if (!ThemeManager.getInstance().ThemingActive) return; + _pGrid.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + _pGrid.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + _pGrid.ViewBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Background"); + _pGrid.ViewForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); + _pGrid.LineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Border"); + _pGrid.HelpBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + _pGrid.HelpForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + _pGrid.CategoryForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); + _pGrid.CommandsDisabledLinkColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); + _pGrid.CommandsBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); + _pGrid.CommandsForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); } private void AddToolStripItems() @@ -748,8 +737,7 @@ namespace mRemoteNG.UI.Window private void UpdateRootInfoNode(PropertyValueChangedEventArgs e) { - var rootInfo = _pGrid.SelectedObject as RootNodeInfo; - if (rootInfo == null) + if (!(_pGrid.SelectedObject is RootNodeInfo rootInfo)) return; if (e.ChangedItem.PropertyDescriptor?.Name != "Password") @@ -795,8 +783,7 @@ namespace mRemoteNG.UI.Window try { var strHide = new List(); - var o = _pGrid.SelectedObject as RootNodeInfo; - if (o != null) + if (_pGrid.SelectedObject is RootNodeInfo o) { var rootInfo = o; if (rootInfo.Type == RootNodeType.PuttySessions) @@ -860,496 +847,495 @@ namespace mRemoteNG.UI.Window strHide.Add("SoundQuality"); strHide.Add("CredentialRecord"); } - else if (_pGrid.SelectedObject is ConnectionInfo) - { - var conI = (ConnectionInfo)_pGrid.SelectedObject; - // ReSharper disable once SwitchStatementMissingSomeCases - switch (conI.Protocol) - { - case ProtocolType.RDP: - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("PuttySession"); - strHide.Add("RenderingEngine"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + else if (_pGrid.SelectedObject is ConnectionInfo conI) + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (conI.Protocol) + { + case ProtocolType.RDP: + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("PuttySession"); + strHide.Add("RenderingEngine"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); if (conI.RDPMinutesToIdleTimeout <= 0) { strHide.Add("RDPAlertIdleTimeout"); } - if (conI.RDGatewayUsageMethod == RdpProtocol.RDGatewayUsageMethod.Never) - { - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - } + if (conI.RDGatewayUsageMethod == RdpProtocol.RDGatewayUsageMethod.Never) + { + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + } else if (conI.RDGatewayUseConnectionCredentials == RdpProtocol.RDGatewayUseConnectionCredentials.Yes) - { - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsername"); - } - if (!(conI.Resolution == RdpProtocol.RDPResolutions.FitToWindow || conI.Resolution == RdpProtocol.RDPResolutions.Fullscreen)) - { - strHide.Add("AutomaticResize"); - } - if (conI.RedirectSound != RdpProtocol.RDPSounds.BringToThisComputer) - { + { + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsername"); + } + if (!(conI.Resolution == RdpProtocol.RDPResolutions.FitToWindow || conI.Resolution == RdpProtocol.RDPResolutions.Fullscreen)) + { + strHide.Add("AutomaticResize"); + } + if (conI.RedirectSound != RdpProtocol.RDPSounds.BringToThisComputer) + { strHide.Add("SoundQuality"); } - break; - case ProtocolType.VNC: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("PuttySession"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + break; + case ProtocolType.VNC: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("PuttySession"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - if (conI.VNCAuthMode == ProtocolVNC.AuthMode.AuthVNC) - { - strHide.Add("Username"); - strHide.Add("Domain"); - } - if (conI.VNCProxyType == ProtocolVNC.ProxyType.ProxyNone) - { - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyUsername"); - } + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + if (conI.VNCAuthMode == ProtocolVNC.AuthMode.AuthVNC) + { + strHide.Add("Username"); + strHide.Add("Domain"); + } + if (conI.VNCProxyType == ProtocolVNC.ProxyType.ProxyNone) + { + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyUsername"); + } strHide.Add("SoundQuality"); break; - case ProtocolType.SSH1: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.SSH1: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.SSH2: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.SSH2: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.Telnet: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("Password"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.Telnet: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("Password"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("Username"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("Username"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.Rlogin: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("Password"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.Rlogin: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("Password"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("Username"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("Username"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.RAW: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("Password"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.RAW: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("Password"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("Username"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("Username"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.HTTP: - case ProtocolType.HTTPS: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("PuttySession"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.HTTP: + case ProtocolType.HTTPS: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("Domain"); + strHide.Add("ExtApp"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("PuttySession"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.ICA: - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("ExtApp"); - strHide.Add("Port"); - strHide.Add("PuttySession"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.ICA: + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("ExtApp"); + strHide.Add("Port"); + strHide.Add("PuttySession"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - case ProtocolType.IntApp: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("PuttySession"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); + case ProtocolType.IntApp: + strHide.Add("CacheBitmaps"); + strHide.Add("Colors"); + strHide.Add("DisplayThemes"); + strHide.Add("DisplayWallpaper"); + strHide.Add("EnableFontSmoothing"); + strHide.Add("EnableDesktopComposition"); + strHide.Add("ICAEncryptionStrength"); + strHide.Add("PuttySession"); + strHide.Add("RDGatewayDomain"); + strHide.Add("RDGatewayHostname"); + strHide.Add("RDGatewayPassword"); + strHide.Add("RDGatewayUsageMethod"); + strHide.Add("RDGatewayUseConnectionCredentials"); + strHide.Add("RDGatewayUsername"); + strHide.Add("RDPAuthenticationLevel"); strHide.Add("RDPMinutesToIdleTimeout"); strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); + strHide.Add("RedirectDiskDrives"); + strHide.Add("RedirectKeys"); + strHide.Add("RedirectPorts"); + strHide.Add("RedirectPrinters"); strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("RenderingEngine"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); + strHide.Add("RedirectSound"); + strHide.Add("RenderingEngine"); + strHide.Add("Resolution"); + strHide.Add("AutomaticResize"); + strHide.Add("UseConsoleSession"); + strHide.Add("UseCredSsp"); + strHide.Add("VNCAuthMode"); + strHide.Add("VNCColors"); + strHide.Add("VNCCompression"); + strHide.Add("VNCEncoding"); + strHide.Add("VNCProxyIP"); + strHide.Add("VNCProxyPassword"); + strHide.Add("VNCProxyPort"); + strHide.Add("VNCProxyType"); + strHide.Add("VNCProxyUsername"); + strHide.Add("VNCSmartSizeMode"); + strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; - } - - if (!(conI is DefaultConnectionInfo)) - { - if (conI.Inheritance.CacheBitmaps) - strHide.Add("CacheBitmaps"); - if (conI.Inheritance.Colors) - strHide.Add("Colors"); - if (conI.Inheritance.Description) - strHide.Add("Description"); - if (conI.Inheritance.DisplayThemes) - strHide.Add("DisplayThemes"); - if (conI.Inheritance.DisplayWallpaper) - strHide.Add("DisplayWallpaper"); - if (conI.Inheritance.EnableFontSmoothing) - strHide.Add("EnableFontSmoothing"); - if (conI.Inheritance.EnableDesktopComposition) - strHide.Add("EnableDesktopComposition"); - if (conI.Inheritance.Domain) - strHide.Add("Domain"); - if (conI.Inheritance.Icon) - strHide.Add("Icon"); - if (conI.Inheritance.Password) - strHide.Add("Password"); - if (conI.Inheritance.Port) - strHide.Add("Port"); - if (conI.Inheritance.Protocol) - strHide.Add("Protocol"); - if (conI.Inheritance.PuttySession) - strHide.Add("PuttySession"); - if (conI.Inheritance.RedirectDiskDrives) + } + + if (!(conI is DefaultConnectionInfo)) + { + if (conI.Inheritance.CacheBitmaps) + strHide.Add("CacheBitmaps"); + if (conI.Inheritance.Colors) + strHide.Add("Colors"); + if (conI.Inheritance.Description) + strHide.Add("Description"); + if (conI.Inheritance.DisplayThemes) + strHide.Add("DisplayThemes"); + if (conI.Inheritance.DisplayWallpaper) + strHide.Add("DisplayWallpaper"); + if (conI.Inheritance.EnableFontSmoothing) + strHide.Add("EnableFontSmoothing"); + if (conI.Inheritance.EnableDesktopComposition) + strHide.Add("EnableDesktopComposition"); + if (conI.Inheritance.Domain) + strHide.Add("Domain"); + if (conI.Inheritance.Icon) + strHide.Add("Icon"); + if (conI.Inheritance.Password) + strHide.Add("Password"); + if (conI.Inheritance.Port) + strHide.Add("Port"); + if (conI.Inheritance.Protocol) + strHide.Add("Protocol"); + if (conI.Inheritance.PuttySession) + strHide.Add("PuttySession"); + if (conI.Inheritance.RedirectDiskDrives) strHide.Add("RedirectDiskDrives"); if (conI.Inheritance.RedirectKeys) strHide.Add("RedirectKeys"); @@ -1435,15 +1421,15 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); if (conI.Inheritance.RDGatewayHostname) strHide.Add("RDGatewayHostname"); - if(conI.Inheritance.SoundQuality) + if (conI.Inheritance.SoundQuality) strHide.Add("SoundQuality"); } - else - { - strHide.Add("Hostname"); - strHide.Add("Name"); - } - } + else + { + strHide.Add("Hostname"); + strHide.Add("Name"); + } + } _pGrid.HiddenProperties = strHide.ToArray(); _pGrid.Refresh(); From 3e0ed5b0af54c0de650d34b89c0ed793cf77b17a Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:18:38 -0500 Subject: [PATCH 010/157] minor clean up --- mRemoteV1/UI/Window/ConnectionWindow.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index fed9e1b3e..19a4a1fe7 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -240,7 +240,7 @@ namespace mRemoteNG.UI.Window private void Connection_FormClosing(object sender, FormClosingEventArgs e) { if (!FrmMain.Default.IsClosing && - (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & connDock.Documents.Count() > 0 || + (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & connDock.Documents.Any() || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & connDock.Documents.Count() > 1)) { var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, Text), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); @@ -343,8 +343,7 @@ namespace mRemoteNG.UI.Window #region Drag and Drop private void TabController_DragDrop(object sender, DragEventArgs e) { - var dropDataAsOlvDataObject = e.Data as OLVDataObject; - if (dropDataAsOlvDataObject == null) return; + if (!(e.Data is OLVDataObject dropDataAsOlvDataObject)) return; var modelObjects = dropDataAsOlvDataObject.ModelObjects; foreach (var model in modelObjects) { From 277817575213014ffd96c77b972cc428c0fde859 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 20:21:48 -0500 Subject: [PATCH 011/157] minor cleanup --- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 44 +++++++++---------- .../Protocol/SSH/Connection.Protocol.SSH1.cs | 4 +- .../Protocol/SSH/Connection.Protocol.SSH2.cs | 4 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 022d532d6..8044c8e7a 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -27,8 +27,8 @@ namespace mRemoteNG.Connection.Protocol protected UI.Window.ConnectionWindow ConnectionWindow { - get { return _connectionWindow; } - private set + get => _connectionWindow; + private set { _connectionWindow = value; _connectionWindow.ResizeBegin += ResizeBegin; @@ -39,8 +39,8 @@ namespace mRemoteNG.Connection.Protocol public InterfaceControl InterfaceControl { - get { return _interfaceControl; } - set + get => _interfaceControl; + set { _interfaceControl = value; //This is ugly @@ -229,44 +229,44 @@ namespace mRemoteNG.Connection.Protocol public delegate void ConnectingEventHandler(object sender); public event ConnectingEventHandler Connecting { - add { ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); } - remove { ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); } - } + add => ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); + remove => ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); + } public delegate void ConnectedEventHandler(object sender); public event ConnectedEventHandler Connected { - add { ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); } - remove { ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); } - } + add => ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); + remove => ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); + } public delegate void DisconnectedEventHandler(object sender, string disconnectedMessage, int? reasonCode); public event DisconnectedEventHandler Disconnected { - add { DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); } - remove { DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); } - } + add => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); + remove => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); + } public delegate void ErrorOccuredEventHandler(object sender, string errorMessage, int? errorCode); public event ErrorOccuredEventHandler ErrorOccured { - add { ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); } - remove { ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); } - } + add => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); + remove => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); + } public delegate void ClosingEventHandler(object sender); public event ClosingEventHandler Closing { - add { ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); } - remove { ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); } - } + add => ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); + remove => ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); + } public delegate void ClosedEventHandler(object sender); public event ClosedEventHandler Closed { - add { ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); } - remove { ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); } - } + add => ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); + remove => ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); + } public void Event_Closing(object sender) diff --git a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs index 53d59a282..d5e99500b 100644 --- a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs +++ b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs @@ -7,8 +7,8 @@ namespace mRemoteNG.Connection.Protocol.SSH public ProtocolSSH1() { - this.PuttyProtocol = Putty_Protocol.ssh; - this.PuttySSHVersion = Putty_SSHVersion.ssh1; + PuttyProtocol = Putty_Protocol.ssh; + PuttySSHVersion = Putty_SSHVersion.ssh1; } public enum Defaults diff --git a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs index 2fa12b4f7..9bd6adf84 100644 --- a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs +++ b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs @@ -5,8 +5,8 @@ namespace mRemoteNG.Connection.Protocol.SSH public ProtocolSSH2() { - this.PuttyProtocol = Putty_Protocol.ssh; - this.PuttySSHVersion = Putty_SSHVersion.ssh2; + PuttyProtocol = Putty_Protocol.ssh; + PuttySSHVersion = Putty_SSHVersion.ssh2; } public enum Defaults From 1f93ca1cf83be1c704c3ca6100b8f90be0488ecd Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 21:47:06 -0500 Subject: [PATCH 012/157] white space and log message --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index c751f7323..5272235b0 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -16,17 +16,15 @@ namespace mRemoteNG.UI.Tabs public ConnectionTab() { - InitializeComponent(); + InitializeComponent(); FormClosing += formClosingEventHandler; } - #region TabEvents private void formClosingEventHandler(object sender, FormClosingEventArgs e) { - try { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) @@ -42,11 +40,11 @@ namespace mRemoteNG.UI.Tabs } } var interfaceControl = (InterfaceControl)Tag; - interfaceControl.Protocol.Close(); + interfaceControl.Protocol.Close(); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.CloseConnectionTab() failed", ex); + Runtime.MessageCollector.AddExceptionMessage("UI.Tab.CloseConnectionTab() failed", ex); } } From 28580103f3f2a2266519a3d28b044617a815b2d5 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 21:50:23 -0500 Subject: [PATCH 013/157] Initial tab close implemtnation PuttyProcess.Dispose() seems to hang in my initial testing, so it's been disabled for now... --- mRemoteV1/Connection/Protocol/PuttyBase.cs | 3 +- mRemoteV1/UI/Window/ConnectionWindow.cs | 48 ++++------------------ 2 files changed, 11 insertions(+), 40 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index 665d75177..8772c8ef1 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -236,7 +236,8 @@ namespace mRemoteNG.Connection.Protocol try { - PuttyProcess.Dispose(); + Console.WriteLine(@"Skipping Dispose for now!"); + //PuttyProcess.Dispose(); } catch (Exception ex) { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 19a4a1fe7..111f7ea30 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -803,57 +803,27 @@ namespace mRemoteNG.UI.Window public void Prot_Event_Closed(object sender) { var protocolBase = sender as ProtocolBase; - var tabPage = protocolBase?.InterfaceControl.Parent as TabPage; - if (tabPage != null) + if (protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage) CloseTab(tabPage); } #endregion #region Tabs - private delegate void CloseTabDelegate(TabPage tabToBeClosed); - private void CloseTab(TabPage tabToBeClosed) - {/* + private delegate void CloseTabDelegate(ConnectionTab tabToBeClosed); + private void CloseTab(ConnectionTab tabToBeClosed) + { if (tabToBeClosed.Disposing || tabToBeClosed.IsDisposed) return; - if (TabController.InvokeRequired) + if (tabToBeClosed.InvokeRequired) { - CloseTabDelegate s = CloseTab; - - try - { - TabController.Invoke(s, tabToBeClosed); - } - catch (COMException) - { - TabController.Invoke(s, tabToBeClosed); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("Couldn't close tab", ex); - } + CloseTabDelegate ctd = CloseTab; + tabToBeClosed.Invoke(ctd, tabToBeClosed); } else { - try - { - TabController.TabPages.Remove(tabToBeClosed); - _ignoreChangeSelectedTabClick = false; - } - catch (COMException) - { - CloseTab(tabToBeClosed); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("Couldn't close tab", ex); - } - - if (TabController.TabPages.Count == 0) - { - Close(); - } - }*/ + tabToBeClosed.Close(); + } } private bool _ignoreChangeSelectedTabClick; From 9c81766b78e5497bfc53a3a2bac80cd26ab789ac Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sun, 30 Dec 2018 22:27:42 -0500 Subject: [PATCH 014/157] Find the correct connection and switch to it If a connection is open, double clicking on it in the connection tree should switch to that connection... --- mRemoteV1/Connection/ConnectionInitiator.cs | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 817d1d2ea..7a86a8048 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -8,7 +8,8 @@ using mRemoteNG.UI.Window; using System; using System.Collections.Generic; using System.Windows.Forms; - +using mRemoteNG.UI.Tabs; +using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Connection @@ -139,25 +140,20 @@ namespace mRemoteNG.Connection if (connectionInfo.OpenConnections.Count <= 0) return null; for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) { - var window = Runtime.WindowList[i] as ConnectionWindow; - var connectionWindow = window; - /* if (connectionWindow?.TabController == null) continue; - foreach (TabPage t in connectionWindow.TabController.TabPages) - { - var ic = t.Controls[0] as InterfaceControl; - if (ic == null) continue; - if (ic.Info == connectionInfo) - { - return ic; - } - }*/ + // the new structure is ConnectionWindow.Controls[0].ActiveDocument.Controls[0] + // DockPanel InterfaceControl + if (!(Runtime.WindowList[i] is ConnectionWindow connectionWindow)) continue; + if (!(connectionWindow.Controls[0] is DockPanel cwDp)) continue; + if (!(cwDp.ActiveDocument is ConnectionTab ct)) continue; + if (ct.Controls[0] is InterfaceControl ic) + return ic; } return null; } private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force) { - var connectionPanel = ""; + string connectionPanel; if (connectionInfo.Panel == "" || force.HasFlag(ConnectionInfo.Force.OverridePanel) || Settings.Default.AlwaysShowPanelSelectionDlg) { var frmPnl = new FrmChoosePanel(); From 362bf7b141df2a9bf7b0b0fb7daab9d5226f7de4 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 09:16:01 -0500 Subject: [PATCH 015/157] Close is successful - so at least we can reelase some resources for now... Added a log message also... --- mRemoteV1/Connection/Protocol/PuttyBase.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index 8772c8ef1..ebbc76048 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -237,8 +237,11 @@ namespace mRemoteNG.Connection.Protocol try { Console.WriteLine(@"Skipping Dispose for now!"); + PuttyProcess.Close(); + // TODO: Figure out why this hangs... //PuttyProcess.Dispose(); - } + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + @"SKIPPING DISPOSE - CAUSES HANG IN THIS BUILD!!!", true); + } catch (Exception ex) { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + ex.Message, true); From d458bb9a4574db405878348dbc3eaf7956d3b7e2 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 09:39:07 -0500 Subject: [PATCH 016/157] minor cleanup --- mRemoteV1/UI/Window/ConnectionWindow.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 111f7ea30..add39045e 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -416,14 +416,7 @@ namespace mRemoteNG.UI.Window cmenTabTransferFile.Visible = true; } - if (interfaceControl.Protocol is PuttyBase) - { - cmenTabPuttySettings.Visible = true; - } - else - { - cmenTabPuttySettings.Visible = false; - } + cmenTabPuttySettings.Visible = interfaceControl.Protocol is PuttyBase; AddExternalApps(); } From 87f8317b97d41d300e3993df2e728091e2d2992d Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 31 Dec 2018 10:12:32 -0500 Subject: [PATCH 017/157] Update ConnectionWindow.cs Resolved tabs getting into dock panel positions . Tabs are now restricted to DockAreas.Document | DockAreas.Float. Menu hook no on opening event insteaed of mouse events . --- mRemoteV1/UI/Window/ConnectionWindow.cs | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 111f7ea30..573901c4e 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -61,17 +62,19 @@ namespace mRemoteNG.UI.Window private void SetTabControllerEventHandlers() { + //Menu handle + cmenTab.Opening += new CancelEventHandler(ShowHideMenuButtons); //TabController.ClosePressed += TabController_ClosePressed; // TabController.DoubleClickTab += TabController_DoubleClickTab; // TabController.DragDrop += TabController_DrouagDrop; // TabController.DragOver += TabController_DragOver; // TabController.SelectionChanged += TabController_SelectionChanged; - DockPnl.MouseUp += TabController_MouseUp; - // TabController.PageDragEnd += TabController_PageDragStart; - // TabController.PageDragStart += TabController_PageDragStart; - // TabController.PageDragMove += TabController_PageDragMove; - // TabController.PageDragEnd += TabController_PageDragEnd; - // TabController.PageDragQuit += TabController_PageDragEnd; + //MouseUp += TabController_MouseUp; + // TabController.PageDragEnd += TabController_PageDragStart; + // TabController.PageDragStart += TabController_PageDragStart; + // TabController.PageDragMove += TabController_PageDragMove; + // TabController.PageDragEnd += TabController_PageDragEnd; + // TabController.PageDragQuit += TabController_PageDragEnd; } private void SetContextMenuEventHandlers() @@ -138,7 +141,8 @@ namespace mRemoteNG.UI.Window conTab.Icon = conIcon; //Show the tab - conTab.Show(connDock, DockState.Document); + conTab.DockAreas = DockAreas.Document | DockAreas.Float; + conTab.Show(connDock,DockState.Document); conTab.Focus(); return conTab; } @@ -174,15 +178,23 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - base.ApplyTheme(); - connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; - vsToolStripExtender = new VisualStudioToolStripExtender(components) + if (ThemeManager.getInstance().ThemingActive) { - DefaultRenderer = _toolStripProfessionalRenderer - }; - vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); - connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + base.ApplyTheme(); + try + { + this.connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; + }catch(Exception ex) + { + //consume the exception + } + + + this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); + vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; + vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + } } private bool _documentHandlersAdded; @@ -369,7 +381,7 @@ namespace mRemoteNG.UI.Window #endregion #region Tab Menu - private void ShowHideMenuButtons() + private void ShowHideMenuButtons(object sender, System.ComponentModel.CancelEventArgs e) { try { @@ -873,7 +885,7 @@ namespace mRemoteNG.UI.Window break; case MouseButtons.Right: if (connDock.ActivePane?.Tag == null) return; - ShowHideMenuButtons(); + // ShowHideMenuButtons(); NativeMethods.SetForegroundWindow(Handle); cmenTab.Show(connDock, e.Location); break; From c24b79cb9de34b80ae46223f5f9520c2ffea85f5 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 10:34:44 -0500 Subject: [PATCH 018/157] FindInterfaceControl(DockPanel DockPnl) --- mRemoteV1/Connection/ConnectionInitiator.cs | 5 ++--- mRemoteV1/Connection/InterfaceControl.cs | 11 +++++++++++ mRemoteV1/UI/Window/ConnectionWindow.cs | 8 ++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 7a86a8048..86fbe18f8 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -144,9 +144,8 @@ namespace mRemoteNG.Connection // DockPanel InterfaceControl if (!(Runtime.WindowList[i] is ConnectionWindow connectionWindow)) continue; if (!(connectionWindow.Controls[0] is DockPanel cwDp)) continue; - if (!(cwDp.ActiveDocument is ConnectionTab ct)) continue; - if (ct.Controls[0] is InterfaceControl ic) - return ic; + + return InterfaceControl.FindInterfaceControl(cwDp); } return null; } diff --git a/mRemoteV1/Connection/InterfaceControl.cs b/mRemoteV1/Connection/InterfaceControl.cs index 185d5023e..0c4846e1d 100644 --- a/mRemoteV1/Connection/InterfaceControl.cs +++ b/mRemoteV1/Connection/InterfaceControl.cs @@ -3,6 +3,8 @@ using mRemoteNG.Connection.Protocol; using System; using System.Drawing; using System.Windows.Forms; +using mRemoteNG.UI.Tabs; +using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Connection @@ -30,5 +32,14 @@ namespace mRemoteNG.Connection Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t create new InterfaceControl" + Environment.NewLine + ex.Message); } } + + public static InterfaceControl FindInterfaceControl(DockPanel DockPnl) + { + if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null; + if (ct.Controls[0] is InterfaceControl ic) + return ic; + + return null; + } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 41dff6442..c551b6d1c 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -183,14 +183,14 @@ namespace mRemoteNG.UI.Window base.ApplyTheme(); try { - this.connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; + connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; }catch(Exception ex) { //consume the exception } - this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); + vsToolStripExtender = new VisualStudioToolStripExtender(components); vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); @@ -381,11 +381,11 @@ namespace mRemoteNG.UI.Window #endregion #region Tab Menu - private void ShowHideMenuButtons(object sender, System.ComponentModel.CancelEventArgs e) + private void ShowHideMenuButtons(object sender, CancelEventArgs e) { try { - var interfaceControl = (InterfaceControl)connDock.ActivePane?.Tag; + var interfaceControl = InterfaceControl.FindInterfaceControl(connDock); if (interfaceControl == null) return; if (interfaceControl.Info.Protocol == ProtocolType.RDP) From 5cecd2be81e5dad37bce5225cf83e9488758fe8d Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 10:47:33 -0500 Subject: [PATCH 019/157] enable more right click methods --- mRemoteV1/UI/Window/ConnectionWindow.cs | 108 ++++++++++++------------ 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index c551b6d1c..194803f1e 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -46,6 +46,11 @@ namespace mRemoteNG.UI.Window connDock.DocumentStyle = DocumentStyle.DockingWindow; } + private InterfaceControl GetInterfaceControl() + { + return InterfaceControl.FindInterfaceControl(connDock); + } + private void SetEventHandlers() { SetFormEventHandlers(); @@ -385,7 +390,7 @@ namespace mRemoteNG.UI.Window { try { - var interfaceControl = InterfaceControl.FindInterfaceControl(connDock); + var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; if (interfaceControl.Info.Protocol == ProtocolType.RDP) @@ -441,35 +446,32 @@ namespace mRemoteNG.UI.Window #region Tab Actions private void ToggleSmartSize() - {/* + { try { - if (!(TabController.SelectedTab?.Tag is InterfaceControl)) return; - var interfaceControl = (InterfaceControl)TabController.SelectedTab?.Tag; + var interfaceControl = GetInterfaceControl(); - var protocol = interfaceControl.Protocol as RdpProtocol; - if (protocol != null) + switch (interfaceControl.Protocol) { - var rdp = protocol; - rdp.ToggleSmartSize(); - } - else if (interfaceControl.Protocol is ProtocolVNC) - { - var vnc = (ProtocolVNC)interfaceControl.Protocol; - vnc.ToggleSmartSize(); + case RdpProtocol rdp: + rdp.ToggleSmartSize(); + break; + case ProtocolVNC vnc: + vnc.ToggleSmartSize(); + break; } } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleSmartSize (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void TransferFile() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; if (interfaceControl.Info.Protocol == ProtocolType.SSH1 | interfaceControl.Info.Protocol == ProtocolType.SSH2) @@ -480,14 +482,14 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("TransferFile (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void SshTransferFile() { - /*try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; Windows.Show(WindowType.SSHTransfer); @@ -501,28 +503,28 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("SSHTransferFile (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void VncTransferFile() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var vnc = interfaceControl?.Protocol as ProtocolVNC; vnc?.StartFileTransfer(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("VNCTransferFile (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void ToggleViewOnly() { - /*try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var vnc = interfaceControl?.Protocol as ProtocolVNC; if (vnc == null) return; cmenTabViewOnly.Checked = !cmenTabViewOnly.Checked; @@ -531,77 +533,77 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleViewOnly (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void StartChat() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var vnc = interfaceControl?.Protocol as ProtocolVNC; vnc?.StartChat(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("StartChat (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void RefreshScreen() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var vnc = interfaceControl?.Protocol as ProtocolVNC; vnc?.RefreshScreen(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("RefreshScreen (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void SendSpecialKeys(ProtocolVNC.SpecialKeys keys) - {/* + { try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var vnc = interfaceControl?.Protocol as ProtocolVNC; vnc?.SendSpecialKeys(keys); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("SendSpecialKeys (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void ToggleFullscreen() - {/* + { try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var rdp = interfaceControl?.Protocol as RdpProtocol; rdp?.ToggleFullscreen(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ToggleFullscreen (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void ShowPuttySettingsDialog() - {/* + { try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); var puttyBase = interfaceControl?.Protocol as PuttyBase; puttyBase?.ShowSettingsDialog(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void AddExternalApps() @@ -641,28 +643,28 @@ namespace mRemoteNG.UI.Window private void StartExternalApp(ExternalTool externalTool) { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); externalTool.Start(interfaceControl?.Info); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)", ex); - }*/ + } } private void CloseTabMenu() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); interfaceControl?.Protocol.Close(); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void CloseOtherTabs() @@ -753,9 +755,9 @@ namespace mRemoteNG.UI.Window private void DuplicateTab() { - /* try + try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); _ignoreChangeSelectedTabClick = false; @@ -763,14 +765,14 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("DuplicateTab (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void Reconnect() - {/* + { try { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; + var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; interfaceControl.Protocol.Close(); _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); @@ -778,7 +780,7 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("Reconnect (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void RenameTab() From 8f5c40487c0fdf868e6b960d26d2bcc8b196428e Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 11:05:53 -0500 Subject: [PATCH 020/157] minor fixes/cleanup --- mRemoteV1/UI/Window/ConnectionWindow.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 194803f1e..8affd36d5 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -106,10 +106,7 @@ namespace mRemoteNG.UI.Window { try { - ConnectionTab conTab = new ConnectionTab(); - - //Tag the tab - conTab.Tag = connectionInfo; + var conTab = new ConnectionTab {Tag = connectionInfo}; //Set the connection text based on name and preferences string titleText; @@ -136,14 +133,13 @@ namespace mRemoteNG.UI.Window titleText += @")"; } - conTab.TabText = titleText; - conTab.TabPageContextMenuStrip = cmenTab; titleText = titleText.Replace("&", "&&"); + conTab.TabText = titleText; + conTab.TabPageContextMenuStrip = cmenTab; + //Fix MagicRemove, i dont see no icons -.- - var conIcon = ConnectionIcon.FromString(connectionInfo.Icon); - if (conIcon != null) - conTab.Icon = conIcon; + conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); //Show the tab conTab.DockAreas = DockAreas.Document | DockAreas.Float; From 4f0237209afd5dc8d96016a9dca690d273189cbf Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 11:37:57 -0500 Subject: [PATCH 021/157] Enable DPS 2015 Themes Rename themes to show that they are the DPS out of the box themes. --- mRemoteV1/Themes/ThemeManager.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 8b0c38351..901aa5a88 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -106,22 +106,28 @@ namespace mRemoteNG.Themes //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme - var vs2003 = new ThemeInfo("Vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + var vs2003 = new ThemeInfo("DPSvs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); themes.Add(vs2003.Name, vs2003); - var vs2005 = new ThemeInfo("Vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + var vs2005 = new ThemeInfo("DPSvs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); themes.Add(vs2005.Name, vs2005); - var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + var vs2012Light = new ThemeInfo("DPSvs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); themes.Add(vs2012Light.Name, vs2012Light); - var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + var vs2012Dark = new ThemeInfo("DPSvs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); themes.Add(vs2012Dark.Name, vs2012Dark); - var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + var vs2012Blue = new ThemeInfo("DPSvs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); themes.Add(vs2012Blue.Name, vs2012Blue); - var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + var vs2013Light = new ThemeInfo("DPSvs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); themes.Add(vs2013Light.Name, vs2013Light); - var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + var vs2013Dark = new ThemeInfo("DPSvs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); themes.Add(vs2013Dark.Name, vs2013Dark); - var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + var vs2013Blue = new ThemeInfo("DPSvs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); themes.Add(vs2013Blue.Name, vs2013Blue); + var vs2015Light = new ThemeInfo("DPSvs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + themes.Add(vs2015Light.Name, vs2015Light); + var vs2015Dark = new ThemeInfo("DPSvs2015Dark", new VS2015DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + themes.Add(vs2015Dark.Name, vs2015Dark); + var vs2015Blue = new ThemeInfo("DPSvs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + themes.Add(vs2015Blue.Name, vs2015Blue); } } catch(Exception ex) From 710fdef0fb9ddce0e5cf7b5aa113d2db1b94c525 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 11:38:56 -0500 Subject: [PATCH 022/157] avoid exception When clicking on a cell after switching from an extensable theme to a non-extensable one. --- .../Forms/OptionsPages/ThemePage.Designer.cs | 2 +- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 12 +- .../UI/Forms/OptionsPages/ThemePage.resx | 120 ++++++++++++++++++ mRemoteV1/mRemoteV1.csproj | 3 + 4 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 mRemoteV1/UI/Forms/OptionsPages/ThemePage.resx diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs index f83434737..f7035cf50 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class ThemePage : OptionsPage + public sealed partial class ThemePage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index b26c59c77..39f3288fe 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -3,20 +3,19 @@ using System.Windows.Forms; using mRemoteNG.Themes; using System.Linq; using System.Collections.Generic; -using System.Drawing; using BrightIdeasSoftware; using mRemoteNG.UI.Forms.Input; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class ThemePage + public sealed partial class ThemePage { #region Private Fields - private ThemeManager _themeManager; - private ThemeInfo _oriTheme; - private bool _oriActiveTheming; - List modifiedThemes = new List(); + private readonly ThemeManager _themeManager; + private readonly ThemeInfo _oriTheme; + private readonly bool _oriActiveTheming; + readonly List modifiedThemes = new List(); #endregion public ThemePage() @@ -125,6 +124,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages btnThemeNew.Enabled = true; listPalette.ClearObjects(); listPalette.Enabled = false; + listPalette.CellClick -= ListPalette_CellClick; ColorMeList(); if (_themeManager.ActiveTheme.IsThemeBase) return; listPalette.Enabled = true; diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.resx b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 65a5180fa..8af75ea5f 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -821,6 +821,9 @@ FrmInputBox.cs + + ThemePage.cs + PasswordForm.cs Designer From 21b3ca0b2ff94708447072e5dfe27df35e190050 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 12:01:02 -0500 Subject: [PATCH 023/157] cleanup --- mRemoteV1/UI/Window/ConnectionWindow.cs | 36 +++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 8affd36d5..f94f90b96 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -68,7 +68,7 @@ namespace mRemoteNG.UI.Window private void SetTabControllerEventHandlers() { //Menu handle - cmenTab.Opening += new CancelEventHandler(ShowHideMenuButtons); + cmenTab.Opening += ShowHideMenuButtons; //TabController.ClosePressed += TabController_ClosePressed; // TabController.DoubleClickTab += TabController_DoubleClickTab; // TabController.DragDrop += TabController_DrouagDrop; @@ -179,23 +179,24 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (ThemeManager.getInstance().ThemingActive) + if (!ThemeManager.getInstance().ThemingActive) return; + base.ApplyTheme(); + try { - base.ApplyTheme(); - try - { - connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; - }catch(Exception ex) - { - //consume the exception - } - - - vsToolStripExtender = new VisualStudioToolStripExtender(components); - vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; - vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); - connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + connDock.Theme = ThemeManager.getInstance().ActiveTheme.Theme; } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ConnectionWindow.ApplyTheme() failed", ex); + } + + + vsToolStripExtender = new VisualStudioToolStripExtender(components) + { + DefaultRenderer = _toolStripProfessionalRenderer + }; + vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } private bool _documentHandlersAdded; @@ -270,8 +271,9 @@ namespace mRemoteNG.UI.Window try { - foreach (ConnectionTab tabP in connDock.Documents) + foreach (var dockContent in connDock.Documents) { + var tabP = (ConnectionTab) dockContent; if (tabP.Tag == null) continue; var interfaceControl = (InterfaceControl)tabP.Tag; interfaceControl.Protocol.Close(); From 19765848d5ea172c9e19c2ec3b122e901e66291e Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 31 Dec 2018 12:31:50 -0500 Subject: [PATCH 024/157] Update ConnectionWindow.cs Restored rename tab functionality --- mRemoteV1/UI/Window/ConnectionWindow.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index f94f90b96..5f5b953f5 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -15,6 +15,7 @@ using mRemoteNG.Container; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Forms; +using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.TaskDialog; using WeifenLuo.WinFormsUI.Docking; using ConnectionTab = mRemoteNG.UI.Tabs.ConnectionTab; @@ -782,18 +783,26 @@ namespace mRemoteNG.UI.Window } private void RenameTab() - {/* + { try { - var newTitle = TabController.SelectedTab.Title; - if (new InputBox().ShowAsDialog(Language.strNewTitle, Language.strNewTitle + ":", ref newTitle) == DialogResult.OK && - !string.IsNullOrEmpty(newTitle)) - TabController.SelectedTab.Title = newTitle.Replace("&", "&&"); + var interfaceControl = GetInterfaceControl(); + if (interfaceControl == null) return; + var newTitle = ((ConnectionTab)interfaceControl.Parent).TabText; + using (FrmInputBox frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ref newTitle)) + { + DialogResult dr = frmInputBox.ShowDialog(); + if (dr == DialogResult.OK) + { + if(!string.IsNullOrEmpty(frmInputBox.returnValue)) + ((ConnectionTab)interfaceControl.Parent).TabText = frmInputBox.returnValue.Replace("&", "&&"); + } + } } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("RenameTab (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void CreateScreenshot() From 80864c7ca4d54de2888c54dc346237a2b7afe9d9 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 12:39:05 -0500 Subject: [PATCH 025/157] code clean up / fix invalid cast exception would be thrown when attempting to start an external app as a connection. --- mRemoteV1/Connection/ConnectionInitiator.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 86fbe18f8..613eca5a1 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -67,8 +67,7 @@ namespace mRemoteNG.Connection if (children.Count == 0) return; foreach (var child in children) { - var childAsContainer = child as ContainerInfo; - if (childAsContainer != null) + if (child is ContainerInfo childAsContainer) OpenConnection(childAsContainer, force, conForm); else OpenConnection(child, force, conForm); @@ -196,7 +195,7 @@ namespace mRemoteNG.Connection if(extT == null) return connectionContainer; if(extT.Icon != null) - ((ConnectionWindow)connectionContainer).Icon = extT.Icon; + ((ConnectionTab)connectionContainer).Icon = extT.Icon; return connectionContainer; } From 3ea94fc5e0512d91b21045323693d04f980d1152 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 31 Dec 2018 14:53:22 -0500 Subject: [PATCH 026/157] fixed failing tests --- .../Connection/Protocol/IntegratedProgramTests.cs | 4 ++-- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs b/mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs index 1dc68ae45..86a9cd30f 100644 --- a/mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs +++ b/mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs @@ -51,8 +51,8 @@ namespace mRemoteNGTests.Connection.Protocol private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut) { var connectionWindow = new ConnectionWindow(new DockContent()); - var connectionInfo = new ConnectionInfo {ExtApp = extAppName}; - return new InterfaceControl(connectionWindow, sut, connectionInfo); + var connectionInfo = new ConnectionInfo {ExtApp = extAppName, Protocol = ProtocolType.IntApp}; + return new InterfaceControl(connectionWindow, sut, connectionInfo); } } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 8044c8e7a..73fad8102 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -3,6 +3,7 @@ using mRemoteNG.Tools; using System; using System.Threading; using System.Windows.Forms; +using mRemoteNG.UI.Window; namespace mRemoteNG.Connection.Protocol @@ -43,8 +44,9 @@ namespace mRemoteNG.Connection.Protocol set { _interfaceControl = value; - //This is ugly - ConnectionWindow = _interfaceControl.Parent.Parent.Parent.Parent.Parent as UI.Window.ConnectionWindow; + + if(_interfaceControl.Parent is ConnectionWindow window) + ConnectionWindow = window; } } From f124ec7131b5ea96cea55f810fd3dd95377750af Mon Sep 17 00:00:00 2001 From: David Sparer Date: Tue, 1 Jan 2019 11:55:14 -0600 Subject: [PATCH 027/157] fixed failing test of the PreviousSessionOpener and readded necessary interface property --- mRemoteV1/Connection/IConnectionInitiator.cs | 3 +++ mRemoteV1/Tree/PreviousSessionOpener.cs | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mRemoteV1/Connection/IConnectionInitiator.cs b/mRemoteV1/Connection/IConnectionInitiator.cs index 5a0ff1d32..c29a15d45 100644 --- a/mRemoteV1/Connection/IConnectionInitiator.cs +++ b/mRemoteV1/Connection/IConnectionInitiator.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; using mRemoteNG.Container; namespace mRemoteNG.Connection { public interface IConnectionInitiator { + IEnumerable ActiveConnections { get; } + void OpenConnection(ConnectionInfo connectionInfo); void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None); diff --git a/mRemoteV1/Tree/PreviousSessionOpener.cs b/mRemoteV1/Tree/PreviousSessionOpener.cs index 1792e98b6..810296b64 100644 --- a/mRemoteV1/Tree/PreviousSessionOpener.cs +++ b/mRemoteV1/Tree/PreviousSessionOpener.cs @@ -21,16 +21,16 @@ namespace mRemoteNG.Tree public void Execute(IConnectionTree connectionTree) { var connectionInfoList = connectionTree.GetRootConnectionNode().GetRecursiveChildList().Where(node => !(node is ContainerInfo)); - /* var previouslyOpenedConnections = connectionInfoList - .Where(item => - item.PleaseConnect && - // ignore items that have already connected + var previouslyOpenedConnections = connectionInfoList + .Where(item => + item.PleaseConnect && + //ignore items that have already connected !_connectionInitiator.ActiveConnections.Contains(item.ConstantID)); foreach (var connectionInfo in previouslyOpenedConnections) { _connectionInitiator.OpenConnection(connectionInfo); - }*/ + } } } } \ No newline at end of file From a08454a09acb3c6361821bd087848adebf5f977a Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 1 Jan 2019 19:26:52 -0500 Subject: [PATCH 028/157] Tab close , other and right restored Reorganized the close event to the connectionTab class, restore the close from the tab X icon functionality , close all other and close left --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 78 ++++---- mRemoteV1/UI/Window/ConnectionWindow.cs | 237 ++++++++++-------------- 2 files changed, 141 insertions(+), 174 deletions(-) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 5272235b0..7579faadb 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -13,69 +13,67 @@ namespace mRemoteNG.UI.Tabs { public partial class ConnectionTab : DockContent { + public bool silentClose { get; set; } = false; public ConnectionTab() { InitializeComponent(); - FormClosing += formClosingEventHandler; } - - #region TabEvents - private void formClosingEventHandler(object sender, FormClosingEventArgs e) + protected override void OnFormClosing(FormClosingEventArgs e) { - try - { + if(!silentClose) + { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); if (CTaskDialog.VerificationChecked) { Settings.Default.ConfirmCloseConnection--; } if (result == DialogResult.No) { - return; + e.Cancel = true; + } + else + { + ((InterfaceControl)Tag).Protocol.Close(); } - } - var interfaceControl = (InterfaceControl)Tag; - interfaceControl.Protocol.Close(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Tab.CloseConnectionTab() failed", ex); - } - - } - - - /* [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override void WndProc(ref Message m) - { - if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) - { - base.WndProc(ref m); - - int index = HitTest(); - if (DockPane.DockPanel.AllowEndUserDocking && index != -1) - { - IDockContent content = Tabs[index].Content; - if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) - content.DockHandler.IsFloat = !content.DockHandler.IsFloat; } - - return; } - - base.WndProc(ref m); - return; + else + { + ((InterfaceControl)Tag).Protocol.Close(); + } + base.OnFormClosing(e); } - */ + + /* [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) + { + base.WndProc(ref m); + + int index = HitTest(); + if (DockPane.DockPanel.AllowEndUserDocking && index != -1) + { + IDockContent content = Tabs[index].Content; + if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) + content.DockHandler.IsFloat = !content.DockHandler.IsFloat; + } + + return; + } + + base.WndProc(ref m); + return; + } + */ - #endregion #region HelperFunctions public void RefreshInterfaceController() diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 5f5b953f5..f1e823acd 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; @@ -29,6 +30,10 @@ namespace mRemoteNG.UI.Window private VisualStudioToolStripExtender vsToolStripExtender; private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); + + private List tabsReferences = new List(); + + #region Public Methods public ConnectionWindow(DockContent panel, string formText = "") { @@ -139,9 +144,14 @@ namespace mRemoteNG.UI.Window conTab.TabText = titleText; conTab.TabPageContextMenuStrip = cmenTab; + + //Fix MagicRemove, i dont see no icons -.- conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); + //Add to the references as is easier to keep track of the tabs than connTab + tabsReferences.Add(conTab); + //Show the tab conTab.DockAreas = DockAreas.Document | DockAreas.Float; conTab.Show(connDock,DockState.Document); @@ -276,8 +286,8 @@ namespace mRemoteNG.UI.Window { var tabP = (ConnectionTab) dockContent; if (tabP.Tag == null) continue; - var interfaceControl = (InterfaceControl)tabP.Tag; - interfaceControl.Protocol.Close(); + tabP.silentClose = true; + tabP.Close(); } } catch (Exception ex) @@ -298,61 +308,17 @@ namespace mRemoteNG.UI.Window ResizeEnd?.Invoke(sender, e); } #endregion + #region TabController - private void TabController_ClosePressed(object sender, EventArgs e) - { - /* if (TabController.SelectedTab == null) - { - return; - }*/ - - CloseConnectionTab(); - } - - private void CloseConnectionTab() - { - /* try - { - var selectedTab = TabController.SelectedTab; - if (selectedTab == null) return; - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) - { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, selectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - return; - } - } - - if (selectedTab.Tag != null) - { - var interfaceControl = (InterfaceControl)selectedTab.Tag; - interfaceControl.Protocol.Close(); - } - else - { - CloseTab(selectedTab); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.CloseConnectionTab() failed", ex); - } - - UpdateSelectedConnection();*/ - } + private void TabController_DoubleClickTab(TabControl sender, TabPage page) { _firstClickTicks = 0; if (Settings.Default.DoubleClickOnTabClosesIt) { - CloseConnectionTab(); + // CloseConnectionTab(); } } @@ -653,12 +619,15 @@ namespace mRemoteNG.UI.Window } } - private void CloseTabMenu() + + private void CloseTabMenu() { + var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (selectedTab == null) return; + try { - var interfaceControl = GetInterfaceControl(); - interfaceControl?.Protocol.Close(); + selectedTab.Close(); } catch (Exception ex) { @@ -668,89 +637,99 @@ namespace mRemoteNG.UI.Window private void CloseOtherTabs() { - /* try + var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (selectedTab == null) return; + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionOthersInstruction, selectedTab.TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionOthersInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - return; - } + Settings.Default.ConfirmCloseConnection--; } - foreach (TabPage tab in TabController.TabPages) + if (result == DialogResult.No) { - if (TabController.TabPages.IndexOf(tab) != TabController.TabPages.IndexOf(TabController.SelectedTab)) - { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) - { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - continue; - } - } - var interfaceControl = tab.Tag as InterfaceControl; - interfaceControl?.Protocol.Close(); - } + return; } } - catch (Exception ex) + + foreach (ConnectionTab tab in tabsReferences ) { - Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - }*/ + if (selectedTab != tab) + { + tab.Close(); + } + } } private void CloseOtherTabsToTheRight() { - /* try - { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) + + try + { + var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (selectedTab == null) return; + var dockPane = (DockPane)selectedTab.Pane; + + bool pastTabToKeepAlive= false; + List connectionsToClose = new List(); + foreach (ConnectionTab tab in dockPane.Contents ) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionRightInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - return; - } + if (pastTabToKeepAlive) + connectionsToClose.Add(tab); + + if (selectedTab == tab) + pastTabToKeepAlive = true; } - foreach (TabPage tab in TabController.TabPages) + foreach (ConnectionTab tab in connectionsToClose) { - if (TabController.TabPages.IndexOf(tab) > TabController.TabPages.IndexOf(TabController.SelectedTab)) - { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) - { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - continue; - } - } - var interfaceControl = tab.Tag as InterfaceControl; - interfaceControl?.Protocol.Close(); - } + tab.Close(); } } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - }*/ - } + } + + /* try + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionRightInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + return; + } + } + foreach (TabPage tab in TabController.TabPages) + { + if (TabController.TabPages.IndexOf(tab) > TabController.TabPages.IndexOf(TabController.SelectedTab)) + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + continue; + } + } + var interfaceControl = tab.Tag as InterfaceControl; + interfaceControl?.Protocol.Close(); + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); + }*/ + } private void DuplicateTab() { @@ -818,27 +797,16 @@ namespace mRemoteNG.UI.Window { var protocolBase = sender as ProtocolBase; if (protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage) - CloseTab(tabPage); + if(!tabPage.Disposing) + { + tabPage.silentClose = true; + Invoke(new Action(() => tabPage.Close())); + } + } #endregion #region Tabs - private delegate void CloseTabDelegate(ConnectionTab tabToBeClosed); - private void CloseTab(ConnectionTab tabToBeClosed) - { - if (tabToBeClosed.Disposing || tabToBeClosed.IsDisposed) - return; - - if (tabToBeClosed.InvokeRequired) - { - CloseTabDelegate ctd = CloseTab; - tabToBeClosed.Invoke(ctd, tabToBeClosed); - } - else - { - tabToBeClosed.Close(); - } - } private bool _ignoreChangeSelectedTabClick; private void TabController_SelectionChanged(object sender, EventArgs e) @@ -883,7 +851,8 @@ namespace mRemoteNG.UI.Window }*/ break; case MouseButtons.Middle: - CloseConnectionTab(); + var activeTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (activeTab != null) activeTab.Close(); break; case MouseButtons.Right: if (connDock.ActivePane?.Tag == null) return; From 5cfee0974ebdbcb978721e580163035b22509fa7 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 1 Jan 2019 19:30:20 -0500 Subject: [PATCH 029/157] Cleanup unused code in CloseOtherTabsToTheRight Cleanup unused code in CloseOtherTabsToTheRight --- mRemoteV1/UI/Window/ConnectionWindow.cs | 42 +------------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index f1e823acd..c3f779253 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -688,47 +688,7 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - } - - /* try - { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) - { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionRightInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - return; - } - } - foreach (TabPage tab in TabController.TabPages) - { - if (TabController.TabPages.IndexOf(tab) > TabController.TabPages.IndexOf(TabController.SelectedTab)) - { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) - { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - continue; - } - } - var interfaceControl = tab.Tag as InterfaceControl; - interfaceControl?.Protocol.Close(); - } - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - }*/ + } } private void DuplicateTab() From 269bbb71f333a8caa5daa1a33ed68b5c07564981 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 1 Jan 2019 19:37:40 -0500 Subject: [PATCH 030/157] Removed drag events Drag events are already implemented in the MDI mode of DockPanelSuite. --- mRemoteV1/UI/Window/ConnectionWindow.cs | 48 ++----------------------- 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index c3f779253..5ac52eb88 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -75,17 +75,11 @@ namespace mRemoteNG.UI.Window { //Menu handle cmenTab.Opening += ShowHideMenuButtons; - //TabController.ClosePressed += TabController_ClosePressed; // TabController.DoubleClickTab += TabController_DoubleClickTab; // TabController.DragDrop += TabController_DrouagDrop; // TabController.DragOver += TabController_DragOver; // TabController.SelectionChanged += TabController_SelectionChanged; - //MouseUp += TabController_MouseUp; - // TabController.PageDragEnd += TabController_PageDragStart; - // TabController.PageDragStart += TabController_PageDragStart; - // TabController.PageDragMove += TabController_PageDragMove; - // TabController.PageDragEnd += TabController_PageDragEnd; - // TabController.PageDragQuit += TabController_PageDragEnd; + //MouseUp += TabController_MouseUp; } private void SetContextMenuEventHandlers() @@ -888,44 +882,6 @@ namespace mRemoteNG.UI.Window } #endregion - #region Tab drag and drop - public bool InTabDrag { get; set; } - - private void TabController_PageDragStart(object sender, MouseEventArgs e) - { - Cursor = Cursors.SizeWE; - } - - private void TabController_PageDragMove(object sender, MouseEventArgs e) - {/* - InTabDrag = true; // For some reason PageDragStart gets raised again after PageDragEnd so set this here instead - - var sourceTab = TabController.SelectedTab; - var destinationTab = TabController.TabPageFromPoint(e.Location); - - if (!TabController.TabPages.Contains(destinationTab) || sourceTab == destinationTab) - return; - - var targetIndex = TabController.TabPages.IndexOf(destinationTab); - - TabController.TabPages.SuspendEvents(); - TabController.TabPages.Remove(sourceTab); - TabController.TabPages.Insert(targetIndex, sourceTab); - TabController.SelectedTab = sourceTab; - TabController.TabPages.ResumeEvents();*/ - } - - private void TabController_PageDragEnd(object sender, MouseEventArgs e) - {/* - Cursor = Cursors.Default; - InTabDrag = false; - var interfaceControl = TabController?.SelectedTab?.Tag as InterfaceControl; - interfaceControl?.Protocol.Focus();*/ - } - #endregion - private void ConnectionWindow_Load(object sender, EventArgs e) - { - - } + } } \ No newline at end of file From e8e70bc81b92e4a1a9069cba9911989475795e7b Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 1 Jan 2019 20:38:49 -0500 Subject: [PATCH 031/157] Resolved broken build, references to drag events Removed event handlers caused broken build. --- mRemoteV1/Connection/Protocol/IntegratedProgram.cs | 2 +- mRemoteV1/Connection/Protocol/PuttyBase.cs | 4 ++-- mRemoteV1/UI/Window/ConnectionWindow.Designer.cs | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index d3c27c0c8..18a223409 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -107,7 +107,7 @@ namespace mRemoteNG.Connection.Protocol { try { - if (ConnectionWindow.InTabDrag) return; + //if (ConnectionWindow.InTabDrag) return; NativeMethods.SetForegroundWindow(_handle); } catch (Exception ex) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index ebbc76048..fccd6819d 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -182,10 +182,10 @@ namespace mRemoteNG.Connection.Protocol { try { - if (ConnectionWindow.InTabDrag) + /*if (ConnectionWindow.InTabDrag) { return; - } + }*/ NativeMethods.SetForegroundWindow(PuttyHandle); } catch (Exception ex) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs index cfcea143c..3e945cda8 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs @@ -261,7 +261,6 @@ namespace mRemoteNG.UI.Window Name = "Connection"; TabText = @"UI.Window.Connection"; Text = @"UI.Window.Connection"; - this.Load += new System.EventHandler(this.ConnectionWindow_Load); cmenTab.ResumeLayout(false); ResumeLayout(false); } From 6edb94758e64bfa4485cc906e44e0426aac1e2e0 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 2 Jan 2019 08:57:59 -0500 Subject: [PATCH 032/157] minor cleanup --- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 73fad8102..d11622a1f 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -12,7 +12,7 @@ namespace mRemoteNG.Connection.Protocol { #region Private Variables - private UI.Window.ConnectionWindow _connectionWindow; + private ConnectionWindow _connectionWindow; private InterfaceControl _interfaceControl; private ConnectingEventHandler ConnectingEvent; private ConnectedEventHandler ConnectedEvent; @@ -26,10 +26,10 @@ namespace mRemoteNG.Connection.Protocol #region Control private string Name { get; } - protected UI.Window.ConnectionWindow ConnectionWindow + private ConnectionWindow ConnectionWindow { get => _connectionWindow; - private set + set { _connectionWindow = value; _connectionWindow.ResizeBegin += ResizeBegin; From 3bb6962cccff0991de9750fafc03e106b8531f77 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 2 Jan 2019 10:40:32 -0500 Subject: [PATCH 033/157] minor cleanup --- mRemoteV1/App/NativeMethods.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/App/NativeMethods.cs b/mRemoteV1/App/NativeMethods.cs index aaac65bdd..dd1df64af 100644 --- a/mRemoteV1/App/NativeMethods.cs +++ b/mRemoteV1/App/NativeMethods.cs @@ -4,6 +4,7 @@ using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Text; +#pragma warning disable 649 #pragma warning disable 169 namespace mRemoteNG.App @@ -78,7 +79,7 @@ namespace mRemoteNG.App internal static extern IntPtr WindowFromPoint(Point point); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount); + internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int GetDlgCtrlID(IntPtr hwndCtl); From efad824fe3171c3240ab4acdee994251fd373122 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 2 Jan 2019 10:42:01 -0500 Subject: [PATCH 034/157] Speed up Theme Option Page load Fixes #1245 The CheckChanged event was causing load settings to be called more than once on form load. --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 39f3288fe..288a44e0f 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -55,6 +55,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { + themeEnableCombo.CheckedChanged -= themeEnableCombo_CheckedChanged; base.SaveSettings(); //At first we cannot create or delete themes, depends later on the type of selected theme btnThemeNew.Enabled = false; @@ -80,6 +81,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages // reset to the default theme when disabling theme support _themeManager.ActiveTheme = _themeManager.DefaultTheme; } + themeEnableCombo.CheckedChanged += themeEnableCombo_CheckedChanged; } private void ListPalette_FormatCell(object sender, FormatCellEventArgs e) From 2c3aace7a977d2429145fd905ae6a23a775d0ac9 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Wed, 2 Jan 2019 12:40:55 -0500 Subject: [PATCH 035/157] Tool forms restricted from entering document area Avoid mixing tool and connection forms in the document area, as they behave and look different. --- mRemoteV1/Connection/Protocol/IntegratedProgram.cs | 1 - mRemoteV1/Connection/Protocol/PuttyBase.cs | 4 ---- mRemoteV1/UI/Forms/frmMain.cs | 3 +++ 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index 18a223409..02c314a8c 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -107,7 +107,6 @@ namespace mRemoteNG.Connection.Protocol { try { - //if (ConnectionWindow.InTabDrag) return; NativeMethods.SetForegroundWindow(_handle); } catch (Exception ex) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index fccd6819d..ed93e4654 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -182,10 +182,6 @@ namespace mRemoteNG.Connection.Protocol { try { - /*if (ConnectionWindow.InTabDrag) - { - return; - }*/ NativeMethods.SetForegroundWindow(PuttyHandle); } catch (Exception ex) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 22ad6020c..e317dfcec 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -640,9 +640,12 @@ namespace mRemoteNG.UI.Forms pnlDock.DockTopPortion = pnlDock.Height * 0.25; pnlDock.DockBottomPortion = pnlDock.Height * 0.25; + Windows.TreeForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; Windows.TreeForm.Show(pnlDock, DockState.DockLeft); + Windows.ConfigForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; Windows.ConfigForm.Show(pnlDock); Windows.ConfigForm.DockTo(Windows.TreeForm.Pane, DockStyle.Bottom, -1); + Windows.ErrorsForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; Windows.ErrorsForm.Show( pnlDock, DockState.DockBottomAutoHide ); Windows.ScreenshotForm.Hide(); From 0f315f414d40c59bc8d9bdb20db5f499e53cf311 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 2 Jan 2019 17:11:23 -0500 Subject: [PATCH 036/157] typo --- mRemoteV1/Connection/Protocol/IntegratedProgram.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index 02c314a8c..c4fa56306 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -131,7 +131,7 @@ namespace mRemoteNG.Connection.Protocol public override void Close() { /* only attempt this if we have a valid process object - * Non-integated tools will still call base.Close() and don't have a valid process object. + * Non-integrated tools will still call base.Close() and don't have a valid process object. * See Connect() above... This just muddies up the log. */ if (_process != null) From 42befd9ce7b787b343f5413c9ee27655e009e9bf Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 2 Jan 2019 17:40:31 -0500 Subject: [PATCH 037/157] count open documents on main form close --- mRemoteV1/UI/Forms/frmMain.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index e317dfcec..05bf1523b 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -341,15 +341,18 @@ namespace mRemoteNG.UI.Forms if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0)) { var openConnections = 0; - foreach (BaseWindow window in Runtime.WindowList) + if (pnlDock.Contents.Count > 0) { - var connectionWindow = window as ConnectionWindow; - //fix MagicRemove, this is not working as per internal agregation of documents - if (connectionWindow != null) - openConnections = pnlDock.DocumentsCount; + foreach (var dc in pnlDock.Contents) + { + if (!(dc is ConnectionWindow cw)) continue; + if (!(cw.Controls[0] is DockPanel dp)) continue; + if (dp.Contents.Count > 0) + openConnections += dp.Contents.Count; + } } - if (openConnections > 0 && (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All | (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & openConnections > 1) || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Exit)) + if (openConnections > 0 && (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All | (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & openConnections > 1) || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Exit)) { var result = CTaskDialog.MessageBox(this, Application.ProductName, Language.strConfirmExitMainInstruction, "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); if (CTaskDialog.VerificationChecked) From 469e6b301c1a40a33f70e7f9c2d5074c5207b7f0 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 13:13:56 -0500 Subject: [PATCH 038/157] code clean up --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 91 +++++++++------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index abc9f3cf9..0ca1265c1 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -29,7 +29,7 @@ namespace mRemoteNG.UI.Tabs protected internal bool Flag { get; set; } - private Rectangle? _rect; + //private Rectangle? _rect; } @@ -45,7 +45,6 @@ namespace mRemoteNG.UI.Tabs private Bitmap m_image0, m_image1; public InertButton(Bitmap image0, Bitmap image1) - : base() { m_image0 = image0; m_image1 = image1; @@ -131,10 +130,7 @@ namespace mRemoteNG.UI.Tabs { get { - if (Appearance == DockPane.AppearanceStyle.Document) - return TabStripRectangle_Document; - else - return TabStripRectangle_ToolWindow; + return Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; } } @@ -185,16 +181,7 @@ namespace mRemoteNG.UI.Tabs public int SelectMenuMargin { get; set; } = 5; - private static Bitmap ImageButtonClose - { - get - { - if (m_imageButtonClose == null) - m_imageButtonClose = Resources.TabExit; - - return m_imageButtonClose; - } - } + private static Bitmap ImageButtonClose => m_imageButtonClose ?? (m_imageButtonClose = Resources.TabExit); private InertButton ButtonClose { @@ -212,28 +199,17 @@ namespace mRemoteNG.UI.Tabs private static Bitmap ImageButtonWindowList => m_imageButtonWindowList ?? (m_imageButtonWindowList = Resources.TabOption); - private static Bitmap ImageButtonWindowListOverflow - { - get - { - if (m_imageButtonWindowListOverflow == null) - m_imageButtonWindowListOverflow = Resources.TabOverflow; - - return m_imageButtonWindowListOverflow; - } - } + private static Bitmap ImageButtonWindowListOverflow => m_imageButtonWindowListOverflow ?? (m_imageButtonWindowListOverflow = Resources.TabOverflow); private InertButton ButtonWindowList { get { - if (m_buttonWindowList == null) - { - m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); - m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); - m_buttonWindowList.Click += WindowList_Click; - Controls.Add(m_buttonWindowList); - } + if (m_buttonWindowList != null) return m_buttonWindowList; + m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); + m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); + m_buttonWindowList.Click += WindowList_Click; + Controls.Add(m_buttonWindowList); return m_buttonWindowList; } @@ -243,7 +219,7 @@ namespace mRemoteNG.UI.Tabs private IContainer Components { get; } - public Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; + private Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; private Font BoldFont { @@ -290,10 +266,7 @@ namespace mRemoteNG.UI.Tabs return; m_documentTabsOverflow = value; - if (value) - ButtonWindowList.ImageCategory = 1; - else - ButtonWindowList.ImageCategory = 0; + ButtonWindowList.ImageCategory = value ? 1 : 0; } } @@ -435,12 +408,9 @@ namespace mRemoteNG.UI.Tabs base.Dispose(disposing); } - protected override int MeasureHeight() + protected override int MeasureHeight() { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return MeasureHeight_ToolWindow(); - else - return MeasureHeight_Document(); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? MeasureHeight_ToolWindow() : MeasureHeight_Document(); } private int MeasureHeight_ToolWindow() @@ -492,7 +462,7 @@ namespace mRemoteNG.UI.Tabs var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); var gradientMode = gradient.LinearGradientMode; - DrawingRoutines.SafelyDrawLinearGradient(rect, startColor, endColor, gradientMode, e.Graphics); + rect.SafelyDrawLinearGradient(startColor, endColor, gradientMode, e.Graphics); base.OnPaint(e); CalculateTabs(); if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null) @@ -512,12 +482,7 @@ namespace mRemoteNG.UI.Tabs public override GraphicsPath GetOutline(int index) { - - if (Appearance == DockPane.AppearanceStyle.Document) - return GetOutline_Document(index); - else - return GetOutline_ToolWindow(index); - + return Appearance == DockPane.AppearanceStyle.Document ? GetOutline_Document(index) : GetOutline_ToolWindow(index); } private GraphicsPath GetOutline_Document(int index) @@ -592,8 +557,9 @@ namespace mRemoteNG.UI.Tabs // Calculate tab widths var countTabs = Tabs.Count; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); tab.Flag = false; } @@ -607,8 +573,9 @@ namespace mRemoteNG.UI.Tabs for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0;) { anyWidthWithinAverage = false; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; @@ -627,8 +594,9 @@ namespace mRemoteNG.UI.Tabs if (remainedTabs > 0) { var roundUpWidth = totalWidth - totalAllocatedWidth - averageWidth * remainedTabs; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; @@ -645,8 +613,9 @@ namespace mRemoteNG.UI.Tabs // Set the X position of the tabs var x = rectTabStrip.X + ToolWindowStripGapLeft; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } @@ -735,8 +704,9 @@ namespace mRemoteNG.UI.Tabs m_startDisplayingTab = 0; FirstDisplayingTab = 0; x = rectTabStrip.X + rectTabStrip.Height / 2; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } @@ -1037,7 +1007,7 @@ namespace mRemoteNG.UI.Tabs // Draws the top horizontal line (short side) GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); - // Draws the rounded corner oppposite the angled side + // Draws the rounded corner opposite the angled side GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); } } @@ -1193,10 +1163,8 @@ namespace mRemoteNG.UI.Tabs g.DrawPath(PenDocumentTabActiveBorder, path); var textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); - if (DockPane.IsActiveDocumentPane) - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, textColor, DocumentTextFormat); - else - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, + DockPane.IsActiveDocumentPane ? BoldFont : TextFont, rectText, textColor, DocumentTextFormat); } else { @@ -1217,8 +1185,9 @@ namespace mRemoteNG.UI.Tabs private void WindowList_Click(object sender, EventArgs e) { SelectMenu.Items.Clear(); - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; var content = tab.Content; var item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); item.Tag = tab.Content; From 3581f2c81894a4ab8236ab280f81758c46fbd8ec Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 14:58:57 -0500 Subject: [PATCH 039/157] code cleanup --- mRemoteV1/UI/Window/ConnectionWindow.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 9954bfcbb..51195f0a9 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -646,7 +646,7 @@ namespace mRemoteNG.UI.Window } } - foreach (ConnectionTab tab in tabsReferences ) + foreach (var tab in tabsReferences ) { if (selectedTab != tab) { @@ -662,19 +662,20 @@ namespace mRemoteNG.UI.Window { var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; if (selectedTab == null) return; - var dockPane = (DockPane)selectedTab.Pane; + var dockPane = selectedTab.Pane; - bool pastTabToKeepAlive= false; - List connectionsToClose = new List(); - foreach (ConnectionTab tab in dockPane.Contents ) + var pastTabToKeepAlive= false; + var connectionsToClose = new List(); + foreach (var dockContent in dockPane.Contents ) { + var tab = (ConnectionTab) dockContent; if (pastTabToKeepAlive) connectionsToClose.Add(tab); if (selectedTab == tab) pastTabToKeepAlive = true; } - foreach (ConnectionTab tab in connectionsToClose) + foreach (var tab in connectionsToClose) { tab.Close(); } @@ -722,9 +723,9 @@ namespace mRemoteNG.UI.Window var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; var newTitle = ((ConnectionTab)interfaceControl.Parent).TabText; - using (FrmInputBox frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ref newTitle)) + using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ref newTitle)) { - DialogResult dr = frmInputBox.ShowDialog(); + var dr = frmInputBox.ShowDialog(); if (dr == DialogResult.OK) { if(!string.IsNullOrEmpty(frmInputBox.returnValue)) From aa0be76c6b0821982ebf454f52fbc239773ec86a Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 15:36:31 -0500 Subject: [PATCH 040/157] remove old MagicLib related code --- mRemoteV1/UI/Forms/frmMain.cs | 34 +--- mRemoteV1/UI/Window/ConnectionWindow.cs | 216 ++---------------------- 2 files changed, 11 insertions(+), 239 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 05bf1523b..9945bf23b 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -454,9 +454,7 @@ namespace mRemoteNG.UI.Forms } else if (controlThatWasClicked.CanSelect || controlThatWasClicked is MenuStrip || - controlThatWasClicked is ToolStrip )/*|| - controlThatWasClicked is Crownwood.Magic.Controls.TabControl || - controlThatWasClicked is Crownwood.Magic.Controls.InertButton)*/ + controlThatWasClicked is ToolStrip ) { // Simulate a mouse event since one wasn't generated by Windows SimulateClick(controlThatWasClicked); @@ -533,8 +531,6 @@ namespace mRemoteNG.UI.Forms private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) { ActivateConnection(); - var connectionWindow = pnlDock.ActiveDocument as ConnectionWindow; - connectionWindow?.UpdateSelectedConnection(); } internal void UpdateWindowTitle() @@ -603,34 +599,6 @@ namespace mRemoteNG.UI.Forms pnlDock.DocumentStyle = newDocumentStyle; pnlDock.Size = new Size(1, 1); } - -#if false - private void SelectTabRelative(int relativeIndex) - { - if (!(pnlDock.ActiveDocument is ConnectionWindow)) - { - return; - } - - var connectionWindow = (ConnectionWindow)pnlDock.ActiveDocument; - var tabController = connectionWindow.TabController; - - var newIndex = tabController.SelectedIndex + relativeIndex; - while (newIndex < 0 | newIndex >= tabController.TabPages.Count) - { - if (newIndex < 0) - { - newIndex = tabController.TabPages.Count + newIndex; - } - if (newIndex >= tabController.TabPages.Count) - { - newIndex = newIndex - tabController.TabPages.Count; - } - } - - tabController.SelectedIndex = newIndex; - } -#endif #endregion #region Screen Stuff diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 51195f0a9..7c4cca982 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; using System.Linq; using System.Windows.Forms; -using BrightIdeasSoftware; using mRemoteNG.App; using mRemoteNG.App.Info; using mRemoteNG.Config; @@ -12,7 +10,6 @@ using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol.RDP; using mRemoteNG.Connection.Protocol.VNC; -using mRemoteNG.Container; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Forms; @@ -20,7 +17,6 @@ using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.TaskDialog; using WeifenLuo.WinFormsUI.Docking; using ConnectionTab = mRemoteNG.UI.Tabs.ConnectionTab; -using Message = System.Windows.Forms.Message; namespace mRemoteNG.UI.Window { @@ -31,7 +27,7 @@ namespace mRemoteNG.UI.Window private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); - private List tabsReferences = new List(); + private readonly List tabsReferences = new List(); #region Public Methods @@ -75,11 +71,6 @@ namespace mRemoteNG.UI.Window { //Menu handle cmenTab.Opening += ShowHideMenuButtons; - // TabController.DoubleClickTab += TabController_DoubleClickTab; - // TabController.DragDrop += TabController_DrouagDrop; - // TabController.DragOver += TabController_DragOver; - // TabController.SelectionChanged += TabController_SelectionChanged; - //MouseUp += TabController_MouseUp; } private void SetContextMenuEventHandlers() @@ -138,8 +129,6 @@ namespace mRemoteNG.UI.Window conTab.TabText = titleText; conTab.TabPageContextMenuStrip = cmenTab; - - //Fix MagicRemove, i dont see no icons -.- conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); @@ -159,19 +148,6 @@ namespace mRemoteNG.UI.Window return null; } - - public void UpdateSelectedConnection() - { - /* if (TabController.SelectedTab == null) - { - FrmMain.Default.SelectedConnection = null; - } - else - { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; - FrmMain.Default.SelectedConnection = interfaceControl?.Info; - }*/ - } #endregion #region Form @@ -195,7 +171,6 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddExceptionMessage("UI.Window.ConnectionWindow.ApplyTheme() failed", ex); } - vsToolStripExtender = new VisualStudioToolStripExtender(components) { DefaultRenderer = _toolStripProfessionalRenderer @@ -302,47 +277,6 @@ namespace mRemoteNG.UI.Window ResizeEnd?.Invoke(sender, e); } #endregion - - - #region TabController - - - private void TabController_DoubleClickTab(TabControl sender, TabPage page) - { - _firstClickTicks = 0; - if (Settings.Default.DoubleClickOnTabClosesIt) - { - // CloseConnectionTab(); - } - } - - #region Drag and Drop - private void TabController_DragDrop(object sender, DragEventArgs e) - { - if (!(e.Data is OLVDataObject dropDataAsOlvDataObject)) return; - var modelObjects = dropDataAsOlvDataObject.ModelObjects; - foreach (var model in modelObjects) - { - var modelAsContainer = model as ContainerInfo; - var modelAsConnection = model as ConnectionInfo; - if (modelAsContainer != null) - _connectionInitiator.OpenConnection(modelAsContainer); - else if (modelAsConnection != null) - _connectionInitiator.OpenConnection(modelAsConnection); - } - } - - private void TabController_DragOver(object sender, DragEventArgs e) - { - e.Effect = DragDropEffects.None; - var dropDataAsOlvDataObject = e.Data as OLVDataObject; - var modelObjects = dropDataAsOlvDataObject?.ModelObjects; - if (modelObjects == null) return; - if (!modelObjects.OfType().Any()) return; - e.Effect = DragDropEffects.Move; - } - #endregion - #endregion #region Tab Menu private void ShowHideMenuButtons(object sender, CancelEventArgs e) @@ -484,8 +418,7 @@ namespace mRemoteNG.UI.Window try { var interfaceControl = GetInterfaceControl(); - var vnc = interfaceControl?.Protocol as ProtocolVNC; - if (vnc == null) return; + if (!(interfaceControl?.Protocol is ProtocolVNC vnc)) return; cmenTabViewOnly.Checked = !cmenTabViewOnly.Checked; vnc.ToggleViewOnly(); } @@ -693,7 +626,6 @@ namespace mRemoteNG.UI.Window var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); - _ignoreChangeSelectedTabClick = false; } catch (Exception ex) { @@ -726,11 +658,9 @@ namespace mRemoteNG.UI.Window using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ref newTitle)) { var dr = frmInputBox.ShowDialog(); - if (dr == DialogResult.OK) - { - if(!string.IsNullOrEmpty(frmInputBox.returnValue)) - ((ConnectionTab)interfaceControl.Parent).TabText = frmInputBox.returnValue.Replace("&", "&&"); - } + if (dr != DialogResult.OK) return; + if(!string.IsNullOrEmpty(frmInputBox.returnValue)) + ((ConnectionTab)interfaceControl.Parent).TabText = frmInputBox.returnValue.Replace("&", "&&"); } } catch (Exception ex) @@ -751,138 +681,12 @@ namespace mRemoteNG.UI.Window public void Prot_Event_Closed(object sender) { var protocolBase = sender as ProtocolBase; - if (protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage) - if(!tabPage.Disposing) - { - tabPage.silentClose = true; - Invoke(new Action(() => tabPage.Close())); - } - + if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return; + if (tabPage.Disposing) return; + tabPage.silentClose = true; + Invoke(new Action(() => tabPage.Close())); + } #endregion - - #region Tabs - - private bool _ignoreChangeSelectedTabClick; - private void TabController_SelectionChanged(object sender, EventArgs e) - { - _ignoreChangeSelectedTabClick = true; - UpdateSelectedConnection(); - FocusInterfaceController(); - RefreshInterfaceController(); - } - - private int _firstClickTicks; - private Rectangle _doubleClickRectangle; - private void TabController_MouseUp(object sender, MouseEventArgs e) - { - try - { - if (!(NativeMethods.GetForegroundWindow() == FrmMain.Default.Handle) && !_ignoreChangeSelectedTabClick) - { - var clickedTab = connDock.ActivePane.GetChildAtPoint(e.Location); - if (clickedTab != null && connDock.ActivePane != clickedTab) - { - NativeMethods.SetForegroundWindow(Handle); - //connDock.active = clickedTab; //Fix MagicRemove , this doesnt work this way now - } - } - _ignoreChangeSelectedTabClick = false; - - switch (e.Button) - { - case MouseButtons.Left: - var currentTicks = Environment.TickCount; - var elapsedTicks = currentTicks - _firstClickTicks; - if (elapsedTicks > SystemInformation.DoubleClickTime || !_doubleClickRectangle.Contains(MousePosition)) - { - _firstClickTicks = currentTicks; - _doubleClickRectangle = new Rectangle(MousePosition.X - SystemInformation.DoubleClickSize.Width / 2, MousePosition.Y - SystemInformation.DoubleClickSize.Height / 2, SystemInformation.DoubleClickSize.Width, SystemInformation.DoubleClickSize.Height); - FocusInterfaceController(); - } - /* else - { - TabController.OnDoubleClickTab(TabController.SelectedTab); - }*/ - break; - case MouseButtons.Middle: - var activeTab = (ConnectionTab)GetInterfaceControl()?.Parent; - if (activeTab != null) activeTab.Close(); - break; - case MouseButtons.Right: - if (connDock.ActivePane?.Tag == null) return; - // ShowHideMenuButtons(); - NativeMethods.SetForegroundWindow(Handle); - cmenTab.Show(connDock, e.Location); - break; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("TabController_MouseUp (UI.Window.ConnectionWindow) failed", ex); - } - } - - private void FocusInterfaceController() - {/* - try - { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; - interfaceControl?.Protocol?.Focus(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("FocusIC (UI.Window.ConnectionWindow) failed", ex); - }*/ - } - - public void RefreshInterfaceController() - {/* - try - { - var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; - if (interfaceControl?.Info.Protocol == ProtocolType.VNC) - ((ProtocolVNC)interfaceControl.Protocol).RefreshScreen(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); - }*/ - } - #endregion - - #region Window Overrides - protected override void WndProc(ref Message m) - { - try - { - if (m.Msg == NativeMethods.WM_MOUSEACTIVATE) - { - var selectedTab = connDock.ActivePane; - if (selectedTab == null) return; - { - var tabClientRectangle = selectedTab.RectangleToScreen(selectedTab.ClientRectangle); - if (tabClientRectangle.Contains(MousePosition)) - { - var interfaceControl = selectedTab.Tag as InterfaceControl; - if (interfaceControl?.Info?.Protocol == ProtocolType.RDP) - { - interfaceControl.Protocol.Focus(); - return; // Do not pass to base class - } - } - } - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.WndProc() failed.", ex); - } - - base.WndProc(ref m); - } - #endregion - - } } \ No newline at end of file From a45772bceb2fd4881a57b67c08de23ddef384646 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 15:41:03 -0500 Subject: [PATCH 041/157] remove the magiclib dll... --- mRemoteV1/References/MagicLibrary.dll | Bin 405504 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mRemoteV1/References/MagicLibrary.dll diff --git a/mRemoteV1/References/MagicLibrary.dll b/mRemoteV1/References/MagicLibrary.dll deleted file mode 100644 index 24cfa5d0a26dc1ca17c231b4cddd595028e33ed8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 405504 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
6`d-wMrlJks(MkE{e#lclGkPpQeK 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 Date: Thu, 3 Jan 2019 16:06:59 -0500 Subject: [PATCH 042/157] code clean up --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 38 ++++++++++------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 0ca1265c1..2bdbb6b55 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -126,13 +126,7 @@ namespace mRemoteNG.UI.Tabs #region Properties - private Rectangle TabStripRectangle - { - get - { - return Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; - } - } + private Rectangle TabStripRectangle => Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; private Rectangle TabStripRectangle_ToolWindow { @@ -306,14 +300,13 @@ namespace mRemoteNG.UI.Tabs { get { - var textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.HorizontalCenter | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter; - if (RightToLeft == RightToLeft.Yes) - return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; - else - return textFormat; + const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; + return RightToLeft == RightToLeft.Yes + ? textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right + : textFormat; } } @@ -325,14 +318,11 @@ namespace mRemoteNG.UI.Tabs { get { - var textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter | - TextFormatFlags.HorizontalCenter; - if (RightToLeft == RightToLeft.Yes) - return textFormat | TextFormatFlags.RightToLeft; - else - return textFormat; + const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; + return RightToLeft == RightToLeft.Yes ? textFormat | TextFormatFlags.RightToLeft : textFormat; } } @@ -384,8 +374,6 @@ namespace mRemoteNG.UI.Tabs SuspendLayout(); - - Components = new System.ComponentModel.Container(); m_toolTip = new ToolTip(Components); SelectMenu = new ContextMenuStrip(Components); From 69216c8902250db414813b88552447bfdfb18fef Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 16:23:31 -0500 Subject: [PATCH 043/157] minor cleanup --- mRemoteV1/Themes/MremoteNGThemeBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index ef23a1519..69ef11d98 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -1,6 +1,6 @@ namespace mRemoteNG.Themes { - using mRemoteNG.UI.Tabs; + using UI.Tabs; using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.ThemeVS2015; @@ -23,7 +23,7 @@ } - public class MremoteDockPaneStripFactory : WeifenLuo.WinFormsUI.Docking.DockPanelExtender.IDockPaneStripFactory + public class MremoteDockPaneStripFactory : DockPanelExtender.IDockPaneStripFactory { public DockPaneStripBase CreateDockPaneStrip(DockPane pane) { From 3b35e5a44d93748b6d39f24ea02ec5d7c01b7528 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 17:06:44 -0500 Subject: [PATCH 044/157] minor clean up and default to modern theme --- mRemoteV1/Themes/ThemeManager.cs | 9 +++------ mRemoteV1/Themes/ThemeSerializer.cs | 2 +- mRemoteV1/UI/Forms/frmMain.cs | 6 +++++- mRemoteV1/UI/Window/ConnectionWindow.cs | 6 +++++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 901aa5a88..ecf6c2849 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -57,7 +57,7 @@ namespace mRemoteNG.Themes return null; } - //THe manager precharges all the themes at once + //The manager precharges all the themes at once public List LoadThemes() { if (themes != null) return themes.Values.OfType().ToList(); @@ -83,8 +83,6 @@ namespace mRemoteNG.Themes file.CopyTo(Path.Combine(themePath, file.Name), true); } - - //Check that theme folder exist before trying to load themes if (Directory.Exists(themePath)) { @@ -104,7 +102,6 @@ namespace mRemoteNG.Themes } } - //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme var vs2003 = new ThemeInfo("DPSvs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); themes.Add(vs2003.Name, vs2003); @@ -223,7 +220,7 @@ namespace mRemoteNG.Themes } } - public ThemeInfo DefaultTheme => (ThemeInfo) themes["vs2015light"]; + public ThemeInfo DefaultTheme => (ThemeInfo) themes["DPSvs2015Light"]; public ThemeInfo ActiveTheme { @@ -231,7 +228,7 @@ namespace mRemoteNG.Themes get => ThemingActive == false ? DefaultTheme : _activeTheme; set { - //You can only enable theming if there are themes laoded + //You can only enable theming if there are themes loaded if (value == null) return; _activeTheme = value; Settings.Default.ThemeName = value.Name; diff --git a/mRemoteV1/Themes/ThemeSerializer.cs b/mRemoteV1/Themes/ThemeSerializer.cs index 25eacc971..2754f65a8 100644 --- a/mRemoteV1/Themes/ThemeSerializer.cs +++ b/mRemoteV1/Themes/ThemeSerializer.cs @@ -48,7 +48,7 @@ namespace mRemoteNG.Themes { var bytes = File.ReadAllBytes(filename); //Load the dockpanel part - var themeBaseLoad= new MremoteNGThemeBase(bytes); + var themeBaseLoad = new MremoteNGThemeBase(bytes); //Load the mremote part //Cause we cannot default the theme for the default theme var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette); diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 9945bf23b..f63734192 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -260,7 +260,11 @@ namespace mRemoteNG.UI.Forms //Theming support private void ApplyTheme() { - if (!_themeManager.ThemingActive) return; + if (!_themeManager.ThemingActive) + { + pnlDock.Theme = _themeManager.DefaultTheme.Theme; + return; + } try { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 7c4cca982..af18b7291 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -160,7 +160,11 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ThemingActive) + { + connDock.Theme = ThemeManager.getInstance().DefaultTheme.Theme; + return; + } base.ApplyTheme(); try { From df8613f6be7bad174be92fa12e92ebf50b288832 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 21:46:33 -0500 Subject: [PATCH 045/157] minor refactoring --- mRemoteV1/UI/Window/ConnectionWindow.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index af18b7291..15edc81d5 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -56,7 +56,6 @@ namespace mRemoteNG.UI.Window private void SetEventHandlers() { SetFormEventHandlers(); - SetTabControllerEventHandlers(); SetContextMenuEventHandlers(); } @@ -67,14 +66,12 @@ namespace mRemoteNG.UI.Window FormClosing += Connection_FormClosing; } - private void SetTabControllerEventHandlers() - { - //Menu handle - cmenTab.Opening += ShowHideMenuButtons; - } - private void SetContextMenuEventHandlers() { + // event handler to adjust the items within the context menu + cmenTab.Opening += ShowHideMenuButtons; + + // event handlers for all context menu items... cmenTabFullscreen.Click += (sender, args) => ToggleFullscreen(); cmenTabSmartSize.Click += (sender, args) => ToggleSmartSize(); cmenTabViewOnly.Click += (sender, args) => ToggleViewOnly(); From c07e2e48d02813e960b131394dd11c7ac66bd7a2 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 3 Jan 2019 22:07:28 -0500 Subject: [PATCH 046/157] RDP resize (fit and smartsize) are working now --- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index d11622a1f..8b204f045 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -3,8 +3,8 @@ using mRemoteNG.Tools; using System; using System.Threading; using System.Windows.Forms; -using mRemoteNG.UI.Window; - +using mRemoteNG.UI.Tabs; +// ReSharper disable UnusedMember.Local namespace mRemoteNG.Connection.Protocol { @@ -12,7 +12,7 @@ namespace mRemoteNG.Connection.Protocol { #region Private Variables - private ConnectionWindow _connectionWindow; + private ConnectionTab _connectionTab; private InterfaceControl _interfaceControl; private ConnectingEventHandler ConnectingEvent; private ConnectedEventHandler ConnectedEvent; @@ -26,15 +26,15 @@ namespace mRemoteNG.Connection.Protocol #region Control private string Name { get; } - private ConnectionWindow ConnectionWindow + private ConnectionTab ConnectionTab { - get => _connectionWindow; + get => _connectionTab; set { - _connectionWindow = value; - _connectionWindow.ResizeBegin += ResizeBegin; - _connectionWindow.Resize += Resize; - _connectionWindow.ResizeEnd += ResizeEnd; + _connectionTab = value; + _connectionTab.ResizeBegin += ResizeBegin; + _connectionTab.Resize += Resize; + _connectionTab.ResizeEnd += ResizeEnd; } } @@ -45,8 +45,8 @@ namespace mRemoteNG.Connection.Protocol { _interfaceControl = value; - if(_interfaceControl.Parent is ConnectionWindow window) - ConnectionWindow = window; + if(_interfaceControl.Parent is ConnectionTab ct) + ConnectionTab = ct; } } From edfbad2432b5dc20ac980187caa105a8c3ecec62 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sat, 5 Jan 2019 19:58:56 -0500 Subject: [PATCH 047/157] Implement screen shot functionality. --- mRemoteV1/Tools/MiscTools.cs | 41 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index 68e92fa94..ff66d8676 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -84,29 +84,24 @@ namespace mRemoteNG.Tools public static Image TakeScreenshot(ConnectionWindow sender) - { - /*try - { - var LeftStart = sender.TabController.SelectedTab.PointToScreen(new Point(sender.TabController.SelectedTab.Left)).X; //Me.Left + Splitter.SplitterDistance + 11 - var TopStart = sender.TabController.SelectedTab.PointToScreen(new Point(sender.TabController.SelectedTab.Top)).Y; //Me.Top + Splitter.Top + TabController.Top + TabController.SelectedTab.Top * 2 - 3 - var LeftWidth = sender.TabController.SelectedTab.Width; //Me.Width - (Splitter.SplitterDistance + 16) - var TopHeight = sender.TabController.SelectedTab.Height; //Me.Height - (Splitter.Top + TabController.Top + TabController.SelectedTab.Top * 2 + 2) - - var currentFormSize = new Size(LeftWidth, TopHeight); - var ScreenToBitmap = new Bitmap(LeftWidth, TopHeight); - var gGraphics = Graphics.FromImage(ScreenToBitmap); - - gGraphics.CopyFromScreen(new Point(LeftStart, TopStart), new Point(0, 0), currentFormSize); - - return ScreenToBitmap; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("Taking Screenshot failed", ex); - } - */ - return null; - } + { + try + { + var ac = sender.ActiveControl; + if (ac != null) + { + var bmp = new Bitmap(ac.Width, ac.Height); + ac.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height)); + return bmp; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Taking Screenshot failed", ex); + } + + return null; + } public class EnumTypeConverter : EnumConverter { From 85aeb059fc9f4ffb5cd84d5cdd11afda7af47226 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Sat, 5 Jan 2019 20:47:33 -0500 Subject: [PATCH 048/157] find the correct InterfaceControl on conn change --- mRemoteV1/Connection/InterfaceControl.cs | 10 +++++++++- mRemoteV1/UI/Forms/frmMain.cs | 8 +++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mRemoteV1/Connection/InterfaceControl.cs b/mRemoteV1/Connection/InterfaceControl.cs index 0c4846e1d..87596e81c 100644 --- a/mRemoteV1/Connection/InterfaceControl.cs +++ b/mRemoteV1/Connection/InterfaceControl.cs @@ -41,5 +41,13 @@ namespace mRemoteNG.Connection return null; } - } + + public static InterfaceControl FindInterfaceControl(ConnectionTab tab) + { + if (tab.Controls[0] is InterfaceControl ic) + return ic; + + return null; + } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index f63734192..343c9c956 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -522,9 +522,11 @@ namespace mRemoteNG.UI.Forms private void ActivateConnection() { - var w = pnlDock.Controls[0] as DockPanel; - if (!(w?.ActiveDocument is ConnectionTab tab)) return; - var ifc = (InterfaceControl)tab.ActiveControl; + var cw = pnlDock.ActiveDocument as ConnectionWindow; + var dp = cw?.ActiveControl as DockPane; + + if (!(dp?.ActiveContent is ConnectionTab tab)) return; + var ifc = InterfaceControl.FindInterfaceControl(tab); if (ifc == null) return; ifc.Protocol.Focus(); From 52ef0c8bcb466eaddcd15c6f465766dcd4cfeadc Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Sun, 6 Jan 2019 21:17:12 -0500 Subject: [PATCH 049/157] Fix darcula theme tab colors Fix color to match theme --- mRemoteV1/Resources/Themes/darcula.vstheme | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Resources/Themes/darcula.vstheme b/mRemoteV1/Resources/Themes/darcula.vstheme index 9958fff5f..cd40e78bb 100644 --- a/mRemoteV1/Resources/Themes/darcula.vstheme +++ b/mRemoteV1/Resources/Themes/darcula.vstheme @@ -106,8 +106,8 @@ - - + + From 20f3b19f2991377bec5e8e156a37543e049b1610 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Sun, 6 Jan 2019 22:32:16 -0500 Subject: [PATCH 050/157] Restored reconnect all, correct tab collection now used instaed of custom one Reconnect all from main file menu restored, tabsReferences in ConnectionWindow deleted in favor of connDock.DocumentsToArray() --- mRemoteV1/UI/Menu/MainFileMenu.cs | 20 +------------ mRemoteV1/UI/Window/ConnectionWindow.cs | 37 ++++++++++++++++++------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/mRemoteV1/UI/Menu/MainFileMenu.cs b/mRemoteV1/UI/Menu/MainFileMenu.cs index 18cdfb42a..300dcdb3e 100644 --- a/mRemoteV1/UI/Menu/MainFileMenu.cs +++ b/mRemoteV1/UI/Menu/MainFileMenu.cs @@ -448,25 +448,7 @@ namespace mRemoteNG.UI.Menu if (!(window is ConnectionWindow connectionWindow)) return; - var icList = new List(); - /* foreach (Crownwood.Magic.Controls.TabPage tab in connectionWindow.TabController.TabPages) - { - var tag = tab.Tag as InterfaceControl; - if (tag != null) - { - icList.Add(tag); - } - }*/ - - foreach (var i in icList) - { - i.Protocol.Close(); - ConnectionInitiator.OpenConnection(i.Info, ConnectionInfo.Force.DoNotJump); - } - - // throw it on the garbage collector - // ReSharper disable once RedundantAssignment - icList = null; + connectionWindow.reconnectAll(ConnectionInitiator); } } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 15edc81d5..226b69a63 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -24,11 +24,7 @@ namespace mRemoteNG.UI.Window { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private VisualStudioToolStripExtender vsToolStripExtender; - private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); - - - private readonly List tabsReferences = new List(); - + private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); #region Public Methods public ConnectionWindow(DockContent panel, string formText = "") @@ -127,10 +123,7 @@ namespace mRemoteNG.UI.Window conTab.TabPageContextMenuStrip = cmenTab; //Fix MagicRemove, i dont see no icons -.- - conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); - - //Add to the references as is easier to keep track of the tabs than connTab - tabsReferences.Add(conTab); + conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); //Show the tab conTab.DockAreas = DockAreas.Document | DockAreas.Float; @@ -147,6 +140,30 @@ namespace mRemoteNG.UI.Window } #endregion + public void reconnectAll(IConnectionInitiator initiator) + { + List controlList = new List(); + try + { + foreach (ConnectionTab tab in connDock.DocumentsToArray()) + { + controlList.Add((InterfaceControl)tab.Tag); + + } + foreach (InterfaceControl iControl in controlList) + { + iControl.Protocol.Close(); + initiator.OpenConnection(iControl.Info, ConnectionInfo.Force.DoNotJump); + } + + } + catch(Exception ex) + { + + } + controlList = null; + } + #region Form private void Connection_Load(object sender, EventArgs e) { @@ -580,7 +597,7 @@ namespace mRemoteNG.UI.Window } } - foreach (var tab in tabsReferences ) + foreach (ConnectionTab tab in connDock.DocumentsToArray()) { if (selectedTab != tab) { From d8cdba262bcf6fd345d81514f5e51713da6b2ed2 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Sun, 6 Jan 2019 22:43:57 -0500 Subject: [PATCH 051/157] Remove tabcontroller references Remove commented tab controller references --- mRemoteV1/UI/Panels/PanelAdder.cs | 3 --- mRemoteV1/UI/Window/ConnectionWindow.Designer.cs | 15 --------------- 2 files changed, 18 deletions(-) diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index b843d01b1..042de3769 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -44,9 +44,6 @@ namespace mRemoteNG.UI.Panels private static void PrepareTabControllerSupport(bool noTabber, ConnectionWindow connectionForm) { - /* if (noTabber) - connectionForm.TabController.Dispose(); - else*/ Runtime.WindowList.Add(connectionForm); } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs index 3e945cda8..377e71365 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs @@ -60,21 +60,6 @@ namespace mRemoteNG.UI.Window cmenTab.SuspendLayout(); SuspendLayout(); // - //TabController - // - /* TabController.Anchor = ((AnchorStyles.Top | AnchorStyles.Bottom) - | AnchorStyles.Left) - | AnchorStyles.Right; - TabController.Appearance = TabControl.VisualAppearance.MultiDocument; - TabController.Cursor = Cursors.Hand; - TabController.DragFromControl = false; - TabController.IDEPixelArea = true; - TabController.IDEPixelBorder = false; - TabController.Location = new Point(0, -1); - TabController.Name = "TabController"; - TabController.Size = new Size(632, 454); - TabController.TabIndex = 0;*/ - // //cmenTab // cmenTab.Items.AddRange(new ToolStripItem[] From eda60a714262c55f100554ee9fc7c4a4a1b534b3 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 09:27:19 -0500 Subject: [PATCH 052/157] resharper fixes & exception logging --- mRemoteV1/UI/Window/ConnectionWindow.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 226b69a63..361def12a 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -142,15 +142,16 @@ namespace mRemoteNG.UI.Window public void reconnectAll(IConnectionInitiator initiator) { - List controlList = new List(); + var controlList = new List(); try - { - foreach (ConnectionTab tab in connDock.DocumentsToArray()) + { + foreach (var dockContent in connDock.DocumentsToArray()) { + var tab = (ConnectionTab)dockContent; controlList.Add((InterfaceControl)tab.Tag); - - } - foreach (InterfaceControl iControl in controlList) + } + + foreach (var iControl in controlList) { iControl.Protocol.Close(); initiator.OpenConnection(iControl.Info, ConnectionInfo.Force.DoNotJump); @@ -159,8 +160,10 @@ namespace mRemoteNG.UI.Window } catch(Exception ex) { - + Runtime.MessageCollector.AddExceptionMessage("reconnectAll (UI.Window.ConnectionWindow) failed", ex); } + + // ReSharper disable once RedundantAssignment controlList = null; } @@ -597,8 +600,9 @@ namespace mRemoteNG.UI.Window } } - foreach (ConnectionTab tab in connDock.DocumentsToArray()) + foreach (var dockContent in connDock.DocumentsToArray()) { + var tab = (ConnectionTab) dockContent; if (selectedTab != tab) { tab.Close(); From ecb2b05c5a396a8a2511d9e28293374b092fc8b2 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 10:17:52 -0500 Subject: [PATCH 053/157] connection panel rename not working other misc fixes/cleanup --- mRemoteV1/UI/Forms/Input/FrmInputBox.Designer.cs | 2 +- mRemoteV1/UI/Forms/Input/FrmInputBox.cs | 5 ++--- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 3 +-- mRemoteV1/UI/Forms/frmChoosePanel.cs | 3 +-- mRemoteV1/UI/Menu/MainFileMenu.cs | 1 - mRemoteV1/UI/Panels/PanelAdder.cs | 16 ++++++---------- mRemoteV1/UI/Window/ConnectionWindow.cs | 3 +-- 7 files changed, 12 insertions(+), 21 deletions(-) diff --git a/mRemoteV1/UI/Forms/Input/FrmInputBox.Designer.cs b/mRemoteV1/UI/Forms/Input/FrmInputBox.Designer.cs index daf744f81..461365469 100644 --- a/mRemoteV1/UI/Forms/Input/FrmInputBox.Designer.cs +++ b/mRemoteV1/UI/Forms/Input/FrmInputBox.Designer.cs @@ -1,6 +1,6 @@ namespace mRemoteNG.UI.Forms.Input { - partial class FrmInputBox + sealed partial class FrmInputBox { /// public const int WM_CHANGECBCHAIN = 0x30D; + #endregion #region Window Styles + public const int WS_MAXIMIZE = 0x1000000; public const int WS_VISIBLE = 0x10000000; public const int WS_CHILD = 0x40000000; public const int WS_EX_MDICHILD = 0x40; + #endregion #region Virtual Key Codes + public const int VK_CONTROL = 0x11; public const int VK_C = 0x67; + #endregion #region EM + public const uint ECM_FIRST = 0x1500; public const uint EM_SETCUEBANNER = ECM_FIRST + 1; public const uint EM_GETCUEBANNER = ECM_FIRST + 2; + #endregion #region LB + public const int LB_ERR = -1; public const int LB_SELECTSTRING = 0x18C; + #endregion #region TCM diff --git a/mRemoteV1/App/ProgramRoot.cs b/mRemoteV1/App/ProgramRoot.cs index b2fcd4a73..5906d2e09 100644 --- a/mRemoteV1/App/ProgramRoot.cs +++ b/mRemoteV1/App/ProgramRoot.cs @@ -67,9 +67,12 @@ namespace mRemoteNG.App var currentProcess = Process.GetCurrentProcess(); foreach (var enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName)) { - if (enumeratedProcess.Id != currentProcess.Id && enumeratedProcess.MainModule.FileName == currentProcess.MainModule.FileName && enumeratedProcess.MainWindowHandle != IntPtr.Zero) + if (enumeratedProcess.Id != currentProcess.Id && + enumeratedProcess.MainModule.FileName == currentProcess.MainModule.FileName && + enumeratedProcess.MainWindowHandle != IntPtr.Zero) windowHandle = enumeratedProcess.MainWindowHandle; } + return windowHandle; } diff --git a/mRemoteV1/App/Runtime.cs b/mRemoteV1/App/Runtime.cs index 0481796b9..2c86269c8 100644 --- a/mRemoteV1/App/Runtime.cs +++ b/mRemoteV1/App/Runtime.cs @@ -41,11 +41,17 @@ namespace mRemoteNG.App public static MessageCollector MessageCollector { get; } = new MessageCollector(); public static NotificationAreaIcon NotificationAreaIcon { get; set; } public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService(); - public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(); + + public static SecureString EncryptionKey { get; set; } = + new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(); + public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList(); - public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance); + + public static ConnectionsService ConnectionsService { get; } = + new ConnectionsService(PuttySessionsManager.Instance); #region Connections Loading/Saving + public static void LoadConnectionsAsync() { var t = new Thread(LoadConnectionsBGd); @@ -106,8 +112,14 @@ namespace mRemoteNG.App if (Settings.Default.UseSQLServer) { MessageCollector.AddExceptionMessage(Language.strLoadFromSqlFailed, ex); - var commandButtons = string.Join("|", Language.strCommandTryAgain, Language.strCommandOpenConnectionFile, string.Format(Language.strCommandExitProgram, Application.ProductName)); - CTaskDialog.ShowCommandBox(Application.ProductName, Language.strLoadFromSqlFailed, Language.strLoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error); + var commandButtons = string.Join("|", Language.strCommandTryAgain, + Language.strCommandOpenConnectionFile, + string.Format(Language.strCommandExitProgram, + Application.ProductName)); + CTaskDialog.ShowCommandBox(Application.ProductName, Language.strLoadFromSqlFailed, + Language.strLoadFromSqlFailedContent, + MiscTools.GetExceptionMessageRecursive(ex), "", "", + commandButtons, false, ESysIcons.Error, ESysIcons.Error); switch (CTaskDialog.CommandButtonResult) { case 0: @@ -122,9 +134,13 @@ namespace mRemoteNG.App return; } } + if (ex is FileNotFoundException && !withDialog) { - MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), ex, MessageClass.InformationMsg); + MessageCollector.AddExceptionMessage( + string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, + connectionFileName), ex, + MessageClass.InformationMsg); string[] commandButtons = { @@ -140,13 +156,13 @@ namespace mRemoteNG.App try { CTaskDialog.ShowTaskDialogBox( - GeneralAppInfo.ProductName, - Language.ConnectionFileNotFound, - "", "", "", "", "", - string.Join(" | ", commandButtons), - ETaskDialogButtons.None, - ESysIcons.Question, - ESysIcons.Question); + GeneralAppInfo.ProductName, + Language.ConnectionFileNotFound, + "", "", "", "", "", + string.Join(" | ", commandButtons), + ETaskDialogButtons.None, + ESysIcons.Question, + ESysIcons.Question); switch (CTaskDialog.CommandButtonResult) { @@ -167,17 +183,24 @@ namespace mRemoteNG.App Application.Exit(); answered = true; break; - } + } } catch (Exception exc) { - MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg); + MessageCollector.AddExceptionMessage( + string + .Format(Language.strConnectionsFileCouldNotBeLoadedNew, + connectionFileName), exc, + MessageClass.InformationMsg); } } + return; } - MessageCollector.AddExceptionStackTrace(string.Format(Language.strConnectionsFileCouldNotBeLoaded, connectionFileName), ex); + MessageCollector.AddExceptionStackTrace( + string.Format(Language.strConnectionsFileCouldNotBeLoaded, + connectionFileName), ex); if (connectionFileName != ConnectionsService.GetStartupConnectionFileName()) { LoadConnections(withDialog); @@ -185,12 +208,16 @@ namespace mRemoteNG.App else { MessageBox.Show(FrmMain.Default, - string.Format(Language.strErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, ConnectionsService.GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)), - @"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error); + string.Format(Language.strErrorStartupConnectionFileLoad, Environment.NewLine, + Application.ProductName, + ConnectionsService.GetStartupConnectionFileName(), + MiscTools.GetExceptionMessageRecursive(ex)), + @"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error); Application.Exit(); } } } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/App/Shutdown.cs b/mRemoteV1/App/Shutdown.cs index 56977bba7..817d451ad 100644 --- a/mRemoteV1/App/Shutdown.cs +++ b/mRemoteV1/App/Shutdown.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using mRemoteNG.Config.Putty; using mRemoteNG.UI.Controls; using mRemoteNG.UI.Forms; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.App @@ -25,7 +26,10 @@ namespace mRemoteNG.App ProgramRoot.CloseSingletonInstanceMutex(); } - public static void Cleanup(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain) + public static void Cleanup(Control quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + FrmMain frmMain) { try { @@ -58,9 +62,13 @@ namespace mRemoteNG.App Runtime.ConnectionsService.SaveConnections(); } - private static void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain) + private static void SaveSettings(Control quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + FrmMain frmMain) { - Config.Settings.SettingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, frmMain); + Config.Settings.SettingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, + frmMain); } private static void UnregisterBrowsers() diff --git a/mRemoteV1/App/Startup.cs b/mRemoteV1/App/Startup.cs index 77b62b942..531190bff 100644 --- a/mRemoteV1/App/Startup.cs +++ b/mRemoteV1/App/Startup.cs @@ -37,15 +37,16 @@ namespace mRemoteNG.App public void InitializeProgram(MessageCollector messageCollector) { - Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); + Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); var startupLogger = new StartupDataLogger(messageCollector); startupLogger.LogStartupData(); CompatibilityChecker.CheckCompatibility(messageCollector); ParseCommandLineArgs(messageCollector); IeBrowserEmulation.Register(); _connectionIconLoader.GetConnectionIcons(); - DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, a=>"ConDefault"+a); - DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, a=>"InhDefault"+a); + DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, a => "ConDefault" + a); + DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, a => "InhDefault" + a); } private static void ParseCommandLineArgs(MessageCollector messageCollector) @@ -59,7 +60,8 @@ namespace mRemoteNG.App messageCollector.AddMessage(MessageClass.DebugMsg, "Determining if we need a database syncronizer"); if (!Settings.Default.UseSQLServer) return; messageCollector.AddMessage(MessageClass.DebugMsg, "Creating database syncronizer"); - Runtime.ConnectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker()); + Runtime.ConnectionsService.RemoteConnectionsSyncronizer = + new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker()); Runtime.ConnectionsService.RemoteConnectionsSyncronizer.Enable(); } @@ -74,7 +76,12 @@ namespace mRemoteNG.App return; } - var nextUpdateCheck = Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays)))); + var nextUpdateCheck = + Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add( + TimeSpan + .FromDays(Convert.ToDouble(Settings + .Default + .CheckForUpdatesFrequencyDays)))); if (!Settings.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck) { return; @@ -100,6 +107,7 @@ namespace mRemoteNG.App { return; } + if (e.Error != null) { throw e.Error; diff --git a/mRemoteV1/App/SupportedCultures.cs b/mRemoteV1/App/SupportedCultures.cs index 37ebc34a9..1ee522610 100644 --- a/mRemoteV1/App/SupportedCultures.cs +++ b/mRemoteV1/App/SupportedCultures.cs @@ -10,7 +10,7 @@ namespace mRemoteNG.App { [Serializable] public sealed class SupportedCultures : Dictionary - { + { private static SupportedCultures _Instance; private static SupportedCultures SingletonInstance @@ -19,7 +19,7 @@ namespace mRemoteNG.App } - private SupportedCultures() + private SupportedCultures() { foreach (var CultureName in Settings.Default.SupportedUICultures.Split(',')) { @@ -30,7 +30,8 @@ namespace mRemoteNG.App } catch (Exception ex) { - Debug.Print($"An exception occurred while adding the culture {CultureName} to the list of supported cultures. {ex.StackTrace}"); + Debug.Print( + $"An exception occurred while adding the culture {CultureName} to the list of supported cultures. {ex.StackTrace}"); } } } @@ -41,51 +42,52 @@ namespace mRemoteNG.App throw new NotImplementedException(); } - public static bool IsNameSupported(string CultureName) - { - return SingletonInstance.ContainsKey(CultureName); - } - - public static bool IsNativeNameSupported(string CultureNativeName) - { - return SingletonInstance.ContainsValue(CultureNativeName); - } - - public static string get_CultureName(string CultureNativeName) - { - var Names = new string[SingletonInstance.Count + 1]; - var NativeNames = new string[SingletonInstance.Count + 1]; + public static bool IsNameSupported(string CultureName) + { + return SingletonInstance.ContainsKey(CultureName); + } + + public static bool IsNativeNameSupported(string CultureNativeName) + { + return SingletonInstance.ContainsValue(CultureNativeName); + } + + public static string get_CultureName(string CultureNativeName) + { + var Names = new string[SingletonInstance.Count + 1]; + var NativeNames = new string[SingletonInstance.Count + 1]; SingletonInstance.Keys.CopyTo(Names, 0); SingletonInstance.Values.CopyTo(NativeNames, 0); - - for (var Index = 0; Index <= SingletonInstance.Count; Index++) - { - if (NativeNames[Index] == CultureNativeName) - { - return Names[Index]; - } - } - - throw (new KeyNotFoundException()); - } - - public static string get_CultureNativeName(string CultureName) - { - return SingletonInstance[CultureName]; - } - + + for (var Index = 0; Index <= SingletonInstance.Count; Index++) + { + if (NativeNames[Index] == CultureNativeName) + { + return Names[Index]; + } + } + + throw (new KeyNotFoundException()); + } + + public static string get_CultureNativeName(string CultureName) + { + return SingletonInstance[CultureName]; + } + public static List CultureNativeNames - { - get - { - var ValueList = new List(); - foreach (var Value in SingletonInstance.Values) - { - ValueList.Add(Value); - } - return ValueList; - } - } - } + { + get + { + var ValueList = new List(); + foreach (var Value in SingletonInstance.Values) + { + ValueList.Add(Value); + } + + return ValueList; + } + } + } } \ No newline at end of file diff --git a/mRemoteV1/App/Update/AppUpdater.cs b/mRemoteV1/App/Update/AppUpdater.cs index 2e7282919..3532a5964 100644 --- a/mRemoteV1/App/Update/AppUpdater.cs +++ b/mRemoteV1/App/Update/AppUpdater.cs @@ -10,8 +10,9 @@ using System.Security.Cryptography; #if !PORTABLE using mRemoteNG.Tools; -#else +#else using System.Windows.Forms; + #endif // ReSharper disable ArrangeAccessorOwnerBody @@ -66,7 +67,12 @@ namespace mRemoteNG.App.Update SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password); } - public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password) + public void SetProxySettings(bool useProxy, + string address, + int port, + bool useAuthentication, + string username, + string password) { if (useProxy && !string.IsNullOrEmpty(address)) { @@ -107,7 +113,8 @@ namespace mRemoteNG.App.Update { if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) { - throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."); + throw new InvalidOperationException( + "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."); } if (IsGetChangeLogRunning) @@ -131,27 +138,29 @@ namespace mRemoteNG.App.Update if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) { throw new InvalidOperationException( - "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); + "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); } #if !PORTABLE - CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); + CurrentUpdateInfo.UpdateFilePath = + Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); #else - var sfd = new SaveFileDialog - { - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), + var sfd = new SaveFileDialog + { + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), FileName = CurrentUpdateInfo.FileName, - RestoreDirectory = true - }; - if (sfd.ShowDialog() == DialogResult.OK) - { + RestoreDirectory = true + }; + if (sfd.ShowDialog() == DialogResult.OK) + { CurrentUpdateInfo.UpdateFilePath = sfd.FileName; } - else - { - return; - } + else + { + return; + } #endif - DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, CurrentUpdateInfo.UpdateFilePath); + DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, + CurrentUpdateInfo.UpdateFilePath); } #endregion @@ -191,7 +200,9 @@ namespace mRemoteNG.App.Update } private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, - Exception exception, bool cancelled, object userToken) + Exception exception, + bool cancelled, + object userToken) { var type = typeof(DownloadStringCompletedEventArgs); const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; @@ -201,7 +212,7 @@ namespace mRemoteNG.App.Update if (constructor == null) return null; - return (DownloadStringCompletedEventArgs) constructor.Invoke(arguments); + return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments); } private DownloadStringCompletedEventArgs DownloadString(Uri address) @@ -326,11 +337,13 @@ namespace mRemoteNG.App.Update { add { - GetUpdateInfoCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Combine(GetUpdateInfoCompletedEventEvent, value); + GetUpdateInfoCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Combine(GetUpdateInfoCompletedEventEvent, value); } remove { - GetUpdateInfoCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(GetUpdateInfoCompletedEventEvent, value); + GetUpdateInfoCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Remove(GetUpdateInfoCompletedEventEvent, value); } } @@ -340,11 +353,13 @@ namespace mRemoteNG.App.Update { add { - GetChangeLogCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Combine(GetChangeLogCompletedEventEvent, value); + GetChangeLogCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Combine(GetChangeLogCompletedEventEvent, value); } remove { - GetChangeLogCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(GetChangeLogCompletedEventEvent, value); + GetChangeLogCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Remove(GetChangeLogCompletedEventEvent, value); } } @@ -354,11 +369,15 @@ namespace mRemoteNG.App.Update { add { - DownloadUpdateProgressChangedEventEvent = (DownloadProgressChangedEventHandler)Delegate.Combine(DownloadUpdateProgressChangedEventEvent, value); + DownloadUpdateProgressChangedEventEvent = + (DownloadProgressChangedEventHandler)Delegate.Combine(DownloadUpdateProgressChangedEventEvent, + value); } remove { - DownloadUpdateProgressChangedEventEvent = (DownloadProgressChangedEventHandler)Delegate.Remove(DownloadUpdateProgressChangedEventEvent, value); + DownloadUpdateProgressChangedEventEvent = + (DownloadProgressChangedEventHandler)Delegate.Remove(DownloadUpdateProgressChangedEventEvent, + value); } } @@ -368,11 +387,13 @@ namespace mRemoteNG.App.Update { add { - DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Combine(DownloadUpdateCompletedEventEvent, value); + DownloadUpdateCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Combine(DownloadUpdateCompletedEventEvent, value); } remove { - DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value); + DownloadUpdateCompletedEventEvent = + (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value); } } diff --git a/mRemoteV1/App/Update/UpdateFile.cs b/mRemoteV1/App/Update/UpdateFile.cs index b5ea64e6a..fae08418b 100644 --- a/mRemoteV1/App/Update/UpdateFile.cs +++ b/mRemoteV1/App/Update/UpdateFile.cs @@ -7,12 +7,16 @@ namespace mRemoteNG.App.Update public class UpdateFile { #region Public Properties + // ReSharper disable MemberCanBePrivate.Local // ReSharper disable once MemberCanBePrivate.Global - public Dictionary Items { get; } = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + public Dictionary Items { get; } = + new Dictionary(StringComparer.InvariantCultureIgnoreCase); + #endregion #region Public Methods + public UpdateFile(string content) { FromString(content); @@ -24,8 +28,8 @@ namespace mRemoteNG.App.Update { if (string.IsNullOrEmpty(content)) return; - char[] keyValueSeparators = { ':', '=' }; - char[] commentCharacters = { '#', ';', '\'' }; + char[] keyValueSeparators = {':', '='}; + char[] commentCharacters = {'#', ';', '\''}; // no separators means no valid update data... if (content.Trim().IndexOfAny(keyValueSeparators) == -1) return; @@ -47,7 +51,7 @@ namespace mRemoteNG.App.Update continue; // make sure we have valid data in both parts before adding to the collection. If either part is empty, then it's not valid data. - if(string.IsNullOrEmpty(parts[0].Trim()) || string.IsNullOrEmpty(parts[1].Trim())) + if (string.IsNullOrEmpty(parts[0].Trim()) || string.IsNullOrEmpty(parts[1].Trim())) continue; Items.Add(parts[0].Trim(), parts[1].Trim()); @@ -83,13 +87,14 @@ namespace mRemoteNG.App.Update { var value = GetString("dURL"); var sv = value.Split('/'); - return sv[sv.Length-1]; + return sv[sv.Length - 1]; } public string GetChecksum(string key = "Checksum") { return GetString(key).Replace(" ", "").ToUpperInvariant(); } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/App/Update/UpdateInfo.cs b/mRemoteV1/App/Update/UpdateInfo.cs index 9255ef16e..0d2ad4c60 100644 --- a/mRemoteV1/App/Update/UpdateInfo.cs +++ b/mRemoteV1/App/Update/UpdateInfo.cs @@ -1,4 +1,5 @@ using System; + // ReSharper disable UnusedAutoPropertyAccessor.Local namespace mRemoteNG.App.Update @@ -43,6 +44,7 @@ namespace mRemoteNG.App.Update newInfo.Checksum = updateFile.GetChecksum(); newInfo.IsValid = newInfo.CheckIfValid(); } + return newInfo; } @@ -50,11 +52,11 @@ namespace mRemoteNG.App.Update { if (string.IsNullOrEmpty(Version.ToString())) return false; - if(string.IsNullOrEmpty(DownloadAddress.AbsoluteUri)) + if (string.IsNullOrEmpty(DownloadAddress.AbsoluteUri)) return false; if (string.IsNullOrEmpty(ChangeLogAddress.AbsoluteUri)) return false; -#if false +#if false if (string.IsNullOrEmpty(ImageAddress.AbsoluteUri)) return false; if (string.IsNullOrEmpty(ImageLinkAddress.AbsoluteUri)) diff --git a/mRemoteV1/App/Windows.cs b/mRemoteV1/App/Windows.cs index 6304b75b6..d4ec8c9ae 100644 --- a/mRemoteV1/App/Windows.cs +++ b/mRemoteV1/App/Windows.cs @@ -31,7 +31,6 @@ namespace mRemoteNG.App internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow(); - public static void Show(WindowType windowType) { try @@ -55,6 +54,7 @@ namespace mRemoteNG.App { optionsForm.ShowDialog(dockPanel); } + break; case WindowType.SSHTransfer: if (SshtransferForm == null || SshtransferForm.IsDisposed) @@ -90,7 +90,8 @@ namespace mRemoteNG.App _ultravncscForm.Show(dockPanel); break; case WindowType.ComponentsCheck: - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Showing ComponentsCheck window", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Showing ComponentsCheck window", true); if (_componentscheckForm == null || _componentscheckForm.IsDisposed) _componentscheckForm = new ComponentsCheckWindow(); _componentscheckForm.Show(dockPanel); diff --git a/mRemoteV1/Config/ConfirmCloseEnum.cs b/mRemoteV1/Config/ConfirmCloseEnum.cs index b990822a0..ff4e615ee 100644 --- a/mRemoteV1/Config/ConfirmCloseEnum.cs +++ b/mRemoteV1/Config/ConfirmCloseEnum.cs @@ -1,11 +1,11 @@ namespace mRemoteNG.Config { - public enum ConfirmCloseEnum - { - Unspecified = 0, - Never = 1, - Exit = 2, - Multiple = 3, - All = 4 - } + public enum ConfirmCloseEnum + { + Unspecified = 0, + Never = 1, + Exit = 2, + Multiple = 3, + All = 4 + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs b/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs index f6faaae2d..3d136faf4 100644 --- a/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs +++ b/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs @@ -36,10 +36,11 @@ namespace mRemoteNG.Config.Connections /// public string NewSourcePath { get; } - public ConnectionsLoadedEventArgs( - Optional previousTreeModelModel, ConnectionTreeModel newTreeModelModel, - bool previousSourceWasDatabase, bool newSourceIsDatabase, - string newSourcePath) + public ConnectionsLoadedEventArgs(Optional previousTreeModelModel, + ConnectionTreeModel newTreeModelModel, + bool previousSourceWasDatabase, + bool newSourceIsDatabase, + string newSourcePath) { if (previousTreeModelModel == null) throw new ArgumentNullException(nameof(previousTreeModelModel)); @@ -55,4 +56,4 @@ namespace mRemoteNG.Config.Connections NewSourcePath = newSourcePath; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/ConnectionsSavedEventArgs.cs b/mRemoteV1/Config/Connections/ConnectionsSavedEventArgs.cs index a1386b79a..0522cd7f1 100644 --- a/mRemoteV1/Config/Connections/ConnectionsSavedEventArgs.cs +++ b/mRemoteV1/Config/Connections/ConnectionsSavedEventArgs.cs @@ -10,7 +10,10 @@ namespace mRemoteNG.Config.Connections public bool UsingDatabase { get; } public string ConnectionFileName { get; } - public ConnectionsSavedEventArgs(ConnectionTreeModel modelThatWasSaved, bool previouslyUsingDatabase, bool usingDatabase, string connectionFileName) + public ConnectionsSavedEventArgs(ConnectionTreeModel modelThatWasSaved, + bool previouslyUsingDatabase, + bool usingDatabase, + string connectionFileName) { if (modelThatWasSaved == null) throw new ArgumentNullException(nameof(modelThatWasSaved)); @@ -21,4 +24,4 @@ namespace mRemoteNG.Config.Connections ConnectionFileName = connectionFileName; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs b/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs index 598cea19f..e49a293e2 100644 --- a/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs @@ -26,10 +26,11 @@ namespace mRemoteNG.Config.Connections public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "") { - var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog); + var csvConnectionsSerializer = + new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog); var dataProvider = new FileDataProvider(_connectionFileName); var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel); dataProvider.Save(csvContent); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/Multiuser/ConnectionsUpdateAvailableEventArgs.cs b/mRemoteV1/Config/Connections/Multiuser/ConnectionsUpdateAvailableEventArgs.cs index 4440d03c0..589bd4db2 100644 --- a/mRemoteV1/Config/Connections/Multiuser/ConnectionsUpdateAvailableEventArgs.cs +++ b/mRemoteV1/Config/Connections/Multiuser/ConnectionsUpdateAvailableEventArgs.cs @@ -3,7 +3,8 @@ using mRemoteNG.Config.DatabaseConnectors; namespace mRemoteNG.Config.Connections.Multiuser { - public delegate void ConnectionsUpdateAvailableEventHandler(object sender, ConnectionsUpdateAvailableEventArgs args); + public delegate void + ConnectionsUpdateAvailableEventHandler(object sender, ConnectionsUpdateAvailableEventArgs args); public class ConnectionsUpdateAvailableEventArgs : EventArgs { diff --git a/mRemoteV1/Config/Connections/Multiuser/RemoteConnectionsSyncronizer.cs b/mRemoteV1/Config/Connections/Multiuser/RemoteConnectionsSyncronizer.cs index 1a4c2075c..36fd5352b 100644 --- a/mRemoteV1/Config/Connections/Multiuser/RemoteConnectionsSyncronizer.cs +++ b/mRemoteV1/Config/Connections/Multiuser/RemoteConnectionsSyncronizer.cs @@ -27,7 +27,8 @@ namespace mRemoteNG.Config.Connections.Multiuser { _updateChecker.UpdateCheckStarted += OnUpdateCheckStarted; _updateChecker.UpdateCheckFinished += OnUpdateCheckFinished; - _updateChecker.ConnectionsUpdateAvailable += (sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args); + _updateChecker.ConnectionsUpdateAvailable += + (sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args); _updateTimer.Elapsed += (sender, args) => _updateChecker.IsUpdateAvailableAsync(); ConnectionsUpdateAvailable += Load; } @@ -81,6 +82,7 @@ namespace mRemoteNG.Config.Connections.Multiuser Dispose(true); GC.SuppressFinalize(this); } + private void Dispose(bool itIsSafeToAlsoFreeManagedObjects) { if (!itIsSafeToAlsoFreeManagedObjects) return; diff --git a/mRemoteV1/Config/Connections/Multiuser/SqlConnectionsUpdateChecker.cs b/mRemoteV1/Config/Connections/Multiuser/SqlConnectionsUpdateChecker.cs index af3ab56fe..66d8978ef 100644 --- a/mRemoteV1/Config/Connections/Multiuser/SqlConnectionsUpdateChecker.cs +++ b/mRemoteV1/Config/Connections/Multiuser/SqlConnectionsUpdateChecker.cs @@ -48,9 +48,11 @@ namespace mRemoteNG.Config.Connections { _sqlConnector.Connect(); } - catch(Exception e) + catch (Exception e) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Unable to connect to Sql DB to check for updates." + Environment.NewLine + e.Message, true); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "Unable to connect to Sql DB to check for updates." + + Environment.NewLine + e.Message, true); } } @@ -63,7 +65,9 @@ namespace mRemoteNG.Config.Connections private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb) { - DateTime lastSqlUpdateWithoutMilliseconds = new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), LastUpdateTime.Kind); + DateTime lastSqlUpdateWithoutMilliseconds = + new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), + LastUpdateTime.Kind); return lastUpdateInDb == lastSqlUpdateWithoutMilliseconds; } @@ -80,20 +84,25 @@ namespace mRemoteNG.Config.Connections } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Error executing Sql query to get updates from the DB." + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "Error executing Sql query to get updates from the DB." + + Environment.NewLine + ex.Message, true); } + _lastDatabaseUpdateTime = lastUpdateInDb; return lastUpdateInDb; } public event EventHandler UpdateCheckStarted; + private void RaiseUpdateCheckStartedEvent() { UpdateCheckStarted?.Invoke(this, EventArgs.Empty); } public event UpdateCheckFinishedEventHandler UpdateCheckFinished; + private void RaiseUpdateCheckFinishedEvent(bool updateAvailable) { var args = new ConnectionsUpdateCheckFinishedEventArgs {UpdateAvailable = updateAvailable}; @@ -101,6 +110,7 @@ namespace mRemoteNG.Config.Connections } public event ConnectionsUpdateAvailableEventHandler ConnectionsUpdateAvailable; + private void RaiseConnectionsUpdateAvailableEvent() { Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Remote connection update is available"); diff --git a/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs b/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs index d36648af3..cbf001a31 100644 --- a/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs +++ b/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs @@ -19,9 +19,11 @@ namespace mRemoteNG.Config.Connections connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded; } - private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) + private void ConnectionsServiceOnConnectionsLoaded(object sender, + ConnectionsLoadedEventArgs connectionsLoadedEventArgs) { - connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged; + connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += + ConnectionTreeModelOnCollectionChanged; connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged; foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel) @@ -31,12 +33,15 @@ namespace mRemoteNG.Config.Connections } } - private void ConnectionTreeModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + private void ConnectionTreeModelOnPropertyChanged(object sender, + PropertyChangedEventArgs propertyChangedEventArgs) { SaveConnectionOnEdit(propertyChangedEventArgs.PropertyName); } - private void ConnectionTreeModelOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) + private void ConnectionTreeModelOnCollectionChanged(object sender, + NotifyCollectionChangedEventArgs + notifyCollectionChangedEventArgs) { SaveConnectionOnEdit(); } @@ -51,4 +56,4 @@ namespace mRemoteNG.Config.Connections _connectionsService.SaveConnectionsAsync(propertyName); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/SaveFormat.cs b/mRemoteV1/Config/Connections/SaveFormat.cs index 0ca1d9b05..fa577f417 100644 --- a/mRemoteV1/Config/Connections/SaveFormat.cs +++ b/mRemoteV1/Config/Connections/SaveFormat.cs @@ -7,4 +7,4 @@ mRCSV, SQL } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/SqlConnectionsLoader.cs b/mRemoteV1/Config/Connections/SqlConnectionsLoader.cs index ed566424e..424fde058 100644 --- a/mRemoteV1/Config/Connections/SqlConnectionsLoader.cs +++ b/mRemoteV1/Config/Connections/SqlConnectionsLoader.cs @@ -19,17 +19,20 @@ namespace mRemoteNG.Config.Connections { public class SqlConnectionsLoader : IConnectionsLoader { - private readonly IDeserializer> _localConnectionPropertiesDeserializer; + private readonly IDeserializer> + _localConnectionPropertiesDeserializer; + private readonly IDataProvider _dataProvider; public Func> AuthenticationRequestor { get; set; } = () => MiscTools.PasswordDialog("", false); public SqlConnectionsLoader( - IDeserializer> localConnectionPropertiesDeserializer, + IDeserializer> localConnectionPropertiesDeserializer, IDataProvider dataProvider) { - _localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer)); + _localConnectionPropertiesDeserializer = + localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer)); _dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider)); } @@ -60,7 +63,9 @@ namespace mRemoteNG.Config.Connections var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); var cipherText = metaData.Protected; var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor); - var authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString()); + var authenticated = + authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword + .ConvertToSecureString()); if (authenticated) return authenticator.LastAuthenticatedPassword; @@ -74,10 +79,10 @@ namespace mRemoteNG.Config.Connections rootNode .GetRecursiveChildList() - .Join(localConnectionProperties, - con => con.ConstantID, - locals => locals.ConnectionId, - (con, locals) => new {Connection = con, LocalProperties = locals}) + .Join(localConnectionProperties, + con => con.ConstantID, + locals => locals.ConnectionId, + (con, locals) => new {Connection = con, LocalProperties = locals}) .ForEach(x => { x.Connection.PleaseConnect = x.LocalProperties.Connected; diff --git a/mRemoteV1/Config/Connections/SqlConnectionsSaver.cs b/mRemoteV1/Config/Connections/SqlConnectionsSaver.cs index 922bee10f..69e3caf88 100644 --- a/mRemoteV1/Config/Connections/SqlConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/SqlConnectionsSaver.cs @@ -29,10 +29,10 @@ namespace mRemoteNG.Config.Connections private readonly ISerializer, string> _localPropertiesSerializer; private readonly IDataProvider _dataProvider; - public SqlConnectionsSaver( - SaveFilter saveFilter, - ISerializer, string> localPropertieSerializer, - IDataProvider localPropertiesDataProvider) + public SqlConnectionsSaver(SaveFilter saveFilter, + ISerializer, string> + localPropertieSerializer, + IDataProvider localPropertiesDataProvider) { if (saveFilter == null) throw new ArgumentNullException(nameof(saveFilter)); @@ -49,14 +49,15 @@ namespace mRemoteNG.Config.Connections if (PropertyIsLocalOnly(propertyNameTrigger)) { - Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, - $"Property {propertyNameTrigger} is local only. Not saving to database."); + Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, + $"Property {propertyNameTrigger} is local only. Not saving to database."); return; } if (SqlUserIsReadOnly()) { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to save connection tree but the SQL read only checkbox is checked, aborting!"); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Trying to save connection tree but the SQL read only checkbox is checked, aborting!"); return; } @@ -69,7 +70,8 @@ namespace mRemoteNG.Config.Connections if (!databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion)) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strErrorConnectionListSaveFailed); return; } @@ -137,22 +139,25 @@ namespace mRemoteNG.Config.Connections { sqlQuery = new SqlCommand( - "INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES(\'" + - MiscTools.PrepareValueForDB(rootTreeNode.Name) + "\', 0, \'" + strProtected + "\'," + - ConnectionsFileInfo.ConnectionFileVersion.ToString(CultureInfo.InvariantCulture) + ")", - sqlDatabaseConnector.SqlConnection); + "INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES(\'" + + MiscTools.PrepareValueForDB(rootTreeNode.Name) + "\', 0, \'" + strProtected + "\'," + + ConnectionsFileInfo.ConnectionFileVersion.ToString(CultureInfo.InvariantCulture) + + ")", + sqlDatabaseConnector.SqlConnection); sqlQuery.ExecuteNonQuery(); } else { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"UpdateRootNodeTable: rootTreeNode was null. Could not insert!"); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + $"UpdateRootNodeTable: rootTreeNode was null. Could not insert!"); } } private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector) { var cryptoProvider = new LegacyRijndaelCryptographyProvider(); - var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString()); + var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, + rootTreeNode.PasswordString.ConvertToSecureString()); var dataTable = serializer.Serialize(rootTreeNode); var dataProvider = new SqlDataProvider(sqlDatabaseConnector); @@ -165,14 +170,16 @@ namespace mRemoteNG.Config.Connections { var sqlQuery = new SqlCommand("DELETE FROM tblUpdate", sqlDatabaseConnector.SqlConnection); sqlQuery.ExecuteNonQuery(); - sqlQuery = new SqlCommand("INSERT INTO tblUpdate (LastUpdate) VALUES(\'" + MiscTools.DBDate(DateTime.Now) + "\')", sqlDatabaseConnector.SqlConnection); + sqlQuery = new SqlCommand( + "INSERT INTO tblUpdate (LastUpdate) VALUES(\'" + MiscTools.DBDate(DateTime.Now) + + "\')", + sqlDatabaseConnector.SqlConnection); sqlQuery.ExecuteNonQuery(); } private bool SqlUserIsReadOnly() { return mRemoteNG.Settings.Default.SQLReadOnly; - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs b/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs index 71a02ebee..a02e9f470 100644 --- a/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs +++ b/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs @@ -37,4 +37,4 @@ namespace mRemoteNG.Config.Connections return password; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs b/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs index 6dad366d4..c9d9352dd 100644 --- a/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs @@ -33,13 +33,17 @@ namespace mRemoteNG.Config.Connections { var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); var connectionNodeSerializer = new XmlConnectionNodeSerializer27( - cryptographyProvider, - connectionTreeModel.RootNodes.OfType().First().PasswordString.ConvertToSecureString(), - _saveFilter); - var xmlConnectionsSerializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer) - { - UseFullEncryption = mRemoteNG.Settings.Default.EncryptCompleteConnectionsFile - }; + cryptographyProvider, + connectionTreeModel + .RootNodes.OfType() + .First().PasswordString + .ConvertToSecureString(), + _saveFilter); + var xmlConnectionsSerializer = + new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer) + { + UseFullEncryption = mRemoteNG.Settings.Default.EncryptCompleteConnectionsFile + }; var xml = xmlConnectionsSerializer.Serialize(connectionTreeModel); var fileDataProvider = new FileDataProviderWithRollingBackup(_connectionFileName); @@ -51,4 +55,4 @@ namespace mRemoteNG.Config.Connections } } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/CredentialHarvester.cs b/mRemoteV1/Config/CredentialHarvester.cs index 38dd53597..c1e19c429 100644 --- a/mRemoteV1/Config/CredentialHarvester.cs +++ b/mRemoteV1/Config/CredentialHarvester.cs @@ -14,13 +14,14 @@ namespace mRemoteNG.Config private readonly IEqualityComparer _credentialComparer = new CredentialDomainUserComparer(); // maps a connectioninfo (by its id) to the credential object that was harvested - public Dictionary ConnectionToCredentialMap { get; } = new Dictionary(); + public Dictionary ConnectionToCredentialMap { get; } = + new Dictionary(); public IEnumerable Harvest(XDocument xDocument, SecureString decryptionKey) { if (xDocument == null) throw new ArgumentNullException(nameof(xDocument)); - + var cryptoProvider = new CryptoProviderFactoryFromXml(xDocument.Root).Build(); foreach (var element in xDocument.Descendants("Node")) @@ -37,7 +38,9 @@ namespace mRemoteNG.Config if (ConnectionToCredentialMap.Values.Contains(newCredential, _credentialComparer)) { - var existingCredential = ConnectionToCredentialMap.Values.First(record => _credentialComparer.Equals(newCredential, record)); + var existingCredential = + ConnectionToCredentialMap.Values.First(record => + _credentialComparer.Equals(newCredential, record)); ConnectionToCredentialMap.Add(connectionId, existingCredential); } else @@ -47,21 +50,24 @@ namespace mRemoteNG.Config return ConnectionToCredentialMap.Values.Distinct(_credentialComparer); } - private ICredentialRecord BuildCredential(XElement element, ICryptographyProvider cryptographyProvider, SecureString decryptionKey) + private ICredentialRecord BuildCredential(XElement element, + ICryptographyProvider cryptographyProvider, + SecureString decryptionKey) { var credential = new CredentialRecord { Title = $"{element.Attribute("Username")?.Value}\\{element.Attribute("Domain")?.Value}", Username = element.Attribute("Username")?.Value, Domain = element.Attribute("Domain")?.Value, - Password = cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey).ConvertToSecureString() + Password = cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey) + .ConvertToSecureString() }; return credential; } private static bool EntryHasSomeCredentialData(XElement e) { - return e.Attribute("Username")?.Value != "" || + return e.Attribute("Username")?.Value != "" || e.Attribute("Domain")?.Value != "" || e.Attribute("Password")?.Value != ""; } diff --git a/mRemoteV1/Config/CredentialRecordLoader.cs b/mRemoteV1/Config/CredentialRecordLoader.cs index 8fe6d83e9..f74525bdd 100644 --- a/mRemoteV1/Config/CredentialRecordLoader.cs +++ b/mRemoteV1/Config/CredentialRecordLoader.cs @@ -13,7 +13,8 @@ namespace mRemoteNG.Config private readonly IDataProvider _dataProvider; private readonly ISecureDeserializer> _deserializer; - public CredentialRecordLoader(IDataProvider dataProvider, ISecureDeserializer> deserializer) + public CredentialRecordLoader(IDataProvider dataProvider, + ISecureDeserializer> deserializer) { if (dataProvider == null) throw new ArgumentNullException(nameof(dataProvider)); diff --git a/mRemoteV1/Config/CredentialRecordSaver.cs b/mRemoteV1/Config/CredentialRecordSaver.cs index 9a9b52d76..5f7d70ae9 100644 --- a/mRemoteV1/Config/CredentialRecordSaver.cs +++ b/mRemoteV1/Config/CredentialRecordSaver.cs @@ -13,7 +13,8 @@ namespace mRemoteNG.Config private readonly IDataProvider _dataProvider; private readonly ISecureSerializer, string> _serializer; - public CredentialRecordSaver(IDataProvider dataProvider, ISecureSerializer, string> serializer) + public CredentialRecordSaver(IDataProvider dataProvider, + ISecureSerializer, string> serializer) { if (dataProvider == null) throw new ArgumentNullException(nameof(dataProvider)); diff --git a/mRemoteV1/Config/CredentialRepositoryListLoader.cs b/mRemoteV1/Config/CredentialRepositoryListLoader.cs index cd9088f03..be0bd72f2 100644 --- a/mRemoteV1/Config/CredentialRepositoryListLoader.cs +++ b/mRemoteV1/Config/CredentialRepositoryListLoader.cs @@ -11,7 +11,8 @@ namespace mRemoteNG.Config private readonly IDataProvider _dataProvider; private readonly CredentialRepositoryListDeserializer _deserializer; - public CredentialRepositoryListLoader(IDataProvider dataProvider, CredentialRepositoryListDeserializer deserializer) + public CredentialRepositoryListLoader(IDataProvider dataProvider, + CredentialRepositoryListDeserializer deserializer) { if (dataProvider == null) throw new ArgumentNullException(nameof(dataProvider)); diff --git a/mRemoteV1/Config/CredentialRepositoryListSaver.cs b/mRemoteV1/Config/CredentialRepositoryListSaver.cs index 6200eb729..6a4a549d7 100644 --- a/mRemoteV1/Config/CredentialRepositoryListSaver.cs +++ b/mRemoteV1/Config/CredentialRepositoryListSaver.cs @@ -25,4 +25,4 @@ namespace mRemoteNG.Config _dataProvider.Save(data); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/DataProviders/FileBackupCreator.cs b/mRemoteV1/Config/DataProviders/FileBackupCreator.cs index 25b09b98a..453eaeaf0 100644 --- a/mRemoteV1/Config/DataProviders/FileBackupCreator.cs +++ b/mRemoteV1/Config/DataProviders/FileBackupCreator.cs @@ -14,12 +14,14 @@ namespace mRemoteNG.Config.DataProviders if (WeDontNeedToBackup(fileName)) return; - var backupFileName = string.Format(mRemoteNG.Settings.Default.BackupFileNameFormat, fileName, DateTime.Now); + var backupFileName = + string.Format(mRemoteNG.Settings.Default.BackupFileNameFormat, fileName, DateTime.Now); File.Copy(fileName, backupFileName); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(Language.strConnectionsFileBackupFailed, ex, MessageClass.WarningMsg); + Runtime.MessageCollector.AddExceptionMessage(Language.strConnectionsFileBackupFailed, ex, + MessageClass.WarningMsg); throw; } } diff --git a/mRemoteV1/Config/DataProviders/FileBackupPruner.cs b/mRemoteV1/Config/DataProviders/FileBackupPruner.cs index 5572a3456..a85ce1f9f 100644 --- a/mRemoteV1/Config/DataProviders/FileBackupPruner.cs +++ b/mRemoteV1/Config/DataProviders/FileBackupPruner.cs @@ -20,8 +20,8 @@ namespace mRemoteNG.Config.DataProviders return; var filesToDelete = files - .OrderByDescending(s => s) - .Skip(maxBackupsToKeep); + .OrderByDescending(s => s) + .Skip(maxBackupsToKeep); foreach (var file in filesToDelete) { diff --git a/mRemoteV1/Config/DataProviders/FileDataProvider.cs b/mRemoteV1/Config/DataProviders/FileDataProvider.cs index 4798fee15..093f81054 100644 --- a/mRemoteV1/Config/DataProviders/FileDataProvider.cs +++ b/mRemoteV1/Config/DataProviders/FileDataProvider.cs @@ -22,12 +22,15 @@ namespace mRemoteNG.Config.DataProviders } catch (FileNotFoundException ex) { - Runtime.MessageCollector.AddExceptionStackTrace($"Could not load file. File does not exist '{FilePath}'", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + $"Could not load file. File does not exist '{FilePath}'", + ex); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionStackTrace($"Failed to load file {FilePath}", ex); } + return fileContents; } diff --git a/mRemoteV1/Config/DataProviders/IDataProvider.cs b/mRemoteV1/Config/DataProviders/IDataProvider.cs index 1f665f17a..b6e529886 100644 --- a/mRemoteV1/Config/DataProviders/IDataProvider.cs +++ b/mRemoteV1/Config/DataProviders/IDataProvider.cs @@ -1,5 +1,4 @@ - -namespace mRemoteNG.Config.DataProviders +namespace mRemoteNG.Config.DataProviders { public interface IDataProvider { diff --git a/mRemoteV1/Config/DataProviders/SqlDataProvider.cs b/mRemoteV1/Config/DataProviders/SqlDataProvider.cs index cb70977c7..4b8cbe69a 100644 --- a/mRemoteV1/Config/DataProviders/SqlDataProvider.cs +++ b/mRemoteV1/Config/DataProviders/SqlDataProvider.cs @@ -34,7 +34,8 @@ namespace mRemoteNG.Config.DataProviders { if (SqlUserIsReadOnly()) { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to save connections but the SQL read only checkbox is checked, aborting!"); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Trying to save connections but the SQL read only checkbox is checked, aborting!"); return; } @@ -62,7 +63,6 @@ namespace mRemoteNG.Config.DataProviders private bool SqlUserIsReadOnly() { return mRemoteNG.Settings.Default.SQLReadOnly; - } } } \ No newline at end of file diff --git a/mRemoteV1/Config/DatabaseConnectors/ConnectionTestResult.cs b/mRemoteV1/Config/DatabaseConnectors/ConnectionTestResult.cs index 0426a2cd8..23bcbbb5d 100644 --- a/mRemoteV1/Config/DatabaseConnectors/ConnectionTestResult.cs +++ b/mRemoteV1/Config/DatabaseConnectors/ConnectionTestResult.cs @@ -8,4 +8,4 @@ CredentialsRejected, UnknownError } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/DatabaseConnectors/DatabaseConnectorFactory.cs b/mRemoteV1/Config/DatabaseConnectors/DatabaseConnectorFactory.cs index f8e8a1496..39d7bcf4b 100644 --- a/mRemoteV1/Config/DatabaseConnectors/DatabaseConnectorFactory.cs +++ b/mRemoteV1/Config/DatabaseConnectors/DatabaseConnectorFactory.cs @@ -15,4 +15,4 @@ namespace mRemoteNG.Config.DatabaseConnectors return new SqlDatabaseConnector(sqlHost, sqlCatalog, sqlUsername, sqlPassword); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnectionTester.cs b/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnectionTester.cs index 69c433758..2100920a4 100644 --- a/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnectionTester.cs +++ b/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnectionTester.cs @@ -9,7 +9,10 @@ namespace mRemoteNG.Config.DatabaseConnectors /// public class SqlDatabaseConnectionTester { - public async Task TestConnectivity(string server, string database, string username, string password) + public async Task TestConnectivity(string server, + string database, + string username, + string password) { using (var sqlConnector = new SqlDatabaseConnector(server, database, username, password)) { @@ -35,4 +38,4 @@ namespace mRemoteNG.Config.DatabaseConnectors } } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnector.cs b/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnector.cs index 6aaeb4135..e55bfb0a4 100644 --- a/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnector.cs +++ b/mRemoteV1/Config/DatabaseConnectors/SqlDatabaseConnector.cs @@ -8,7 +8,7 @@ namespace mRemoteNG.Config.DatabaseConnectors { public class SqlDatabaseConnector : IDatabaseConnector { - public SqlConnection SqlConnection { get; private set; } = default(SqlConnection); + public SqlConnection SqlConnection { get; private set; } = default(SqlConnection); private string _sqlConnectionString = ""; private readonly string _sqlHost; private readonly string _sqlCatalog; @@ -45,7 +45,8 @@ namespace mRemoteNG.Config.DatabaseConnectors private void BuildSqlConnectionStringWithCustomCredentials() { - _sqlConnectionString = $"Data Source={_sqlHost};Initial Catalog={_sqlCatalog};User Id={_sqlUsername};Password={_sqlPassword}"; + _sqlConnectionString = + $"Data Source={_sqlHost};Initial Catalog={_sqlCatalog};User Id={_sqlUsername};Password={_sqlPassword}"; } private void BuildSqlConnectionStringWithDefaultCredentials() @@ -77,6 +78,7 @@ namespace mRemoteNG.Config.DatabaseConnectors { Dispose(true); } + private void Dispose(bool itIsSafeToFreeManagedObjects) { if (!itIsSafeToFreeManagedObjects) return; diff --git a/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs b/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs index 9c59b3850..32b1e9d9c 100644 --- a/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs +++ b/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs @@ -7,29 +7,29 @@ using mRemoteNG.Tools; namespace mRemoteNG.Config.Import { - public class ActiveDirectoryImporter : IConnectionImporter - { + public class ActiveDirectoryImporter : IConnectionImporter + { public void Import(string ldapPath, ContainerInfo destinationContainer) { Import(ldapPath, destinationContainer, false); } - public static void Import(string ldapPath, ContainerInfo destinationContainer, bool importSubOu) - { - try - { - ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath)); - var deserializer = new ActiveDirectoryDeserializer(ldapPath, importSubOu); - var connectionTreeModel = deserializer.Deserialize(); + public static void Import(string ldapPath, ContainerInfo destinationContainer, bool importSubOu) + { + try + { + ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath)); + var deserializer = new ActiveDirectoryDeserializer(ldapPath, importSubOu); + var connectionTreeModel = deserializer.Deserialize(); var importedRootNode = connectionTreeModel.RootNodes.First(); if (importedRootNode == null) return; var childrenToAdd = importedRootNode.Children.ToArray(); destinationContainer.AddChildRange(childrenToAdd); } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("Config.Import.ActiveDirectory.Import() failed.", ex); - } - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("Config.Import.ActiveDirectory.Import() failed.", ex); + } + } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs b/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs index 821a711a4..58f4983de 100644 --- a/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs +++ b/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs @@ -19,16 +19,17 @@ namespace mRemoteNG.Config.Import } if (!File.Exists(filePath)) - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {filePath}"); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + $"Unable to import file. File does not exist. Path: {filePath}"); var dataProvider = new FileDataProvider(filePath); var xmlString = dataProvider.Load(); var xmlConnectionsDeserializer = new CsvConnectionsDeserializerMremotengFormat(); var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString); - var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(filePath) }; + var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(filePath)}; rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray()); destinationContainer.AddChild(rootImportContainer); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs b/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs index 13c0fe449..2ee1f5e34 100644 --- a/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs +++ b/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs @@ -10,28 +10,29 @@ using mRemoteNG.Messages; namespace mRemoteNG.Config.Import { - // ReSharper disable once InconsistentNaming - public class MRemoteNGXmlImporter : IConnectionImporter - { - public void Import(string fileName, ContainerInfo destinationContainer) - { - if (fileName == null) - { + // ReSharper disable once InconsistentNaming + public class MRemoteNGXmlImporter : IConnectionImporter + { + public void Import(string fileName, ContainerInfo destinationContainer) + { + if (fileName == null) + { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File path is null."); return; } - if(!File.Exists(fileName)) - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {fileName}"); + if (!File.Exists(fileName)) + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + $"Unable to import file. File does not exist. Path: {fileName}"); - var dataProvider = new FileDataProvider(fileName); - var xmlString = dataProvider.Load(); - var xmlConnectionsDeserializer = new XmlConnectionsDeserializer(); - var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true); + var dataProvider = new FileDataProvider(fileName); + var xmlString = dataProvider.Load(); + var xmlConnectionsDeserializer = new XmlConnectionsDeserializer(); + var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true); - var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) }; - rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray()); - destinationContainer.AddChild(rootImportContainer); + var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(fileName)}; + rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray()); + destinationContainer.AddChild(rootImportContainer); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/PortScanImporter.cs b/mRemoteV1/Config/Import/PortScanImporter.cs index aa0c9442e..738710f13 100644 --- a/mRemoteV1/Config/Import/PortScanImporter.cs +++ b/mRemoteV1/Config/Import/PortScanImporter.cs @@ -8,18 +8,18 @@ using mRemoteNG.Tools; namespace mRemoteNG.Config.Import { - public class PortScanImporter : IConnectionImporter> - { - private readonly ProtocolType _targetProtocolType; + public class PortScanImporter : IConnectionImporter> + { + private readonly ProtocolType _targetProtocolType; - public PortScanImporter(ProtocolType targetProtocolType) - { - _targetProtocolType = targetProtocolType; - } + public PortScanImporter(ProtocolType targetProtocolType) + { + _targetProtocolType = targetProtocolType; + } public void Import(IEnumerable hosts, ContainerInfo destinationContainer) - { - var deserializer = new PortScanDeserializer(_targetProtocolType); + { + var deserializer = new PortScanDeserializer(_targetProtocolType); var connectionTreeModel = deserializer.Deserialize(hosts); var importedRootNode = connectionTreeModel.RootNodes.First(); @@ -27,5 +27,5 @@ namespace mRemoteNG.Config.Import var childrenToAdd = importedRootNode.Children.ToArray(); destinationContainer.AddChildRange(childrenToAdd); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs b/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs index e147556c9..594ebe67e 100644 --- a/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs +++ b/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs @@ -6,10 +6,10 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class PuttyConnectionManagerImporter : IConnectionImporter - { + public class PuttyConnectionManagerImporter : IConnectionImporter + { public void Import(string filePath, ContainerInfo destinationContainer) - { + { var dataProvider = new FileDataProvider(filePath); var xmlContent = dataProvider.Load(); @@ -21,5 +21,5 @@ namespace mRemoteNG.Config.Import var childrenToAdd = importedRootNode.Children.ToArray(); destinationContainer.AddChildRange(childrenToAdd); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs b/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs index a46da5f61..15af3e526 100644 --- a/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs +++ b/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs @@ -7,10 +7,10 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class RemoteDesktopConnectionImporter : IConnectionImporter - { + public class RemoteDesktopConnectionImporter : IConnectionImporter + { public void Import(string fileName, ContainerInfo destinationContainer) - { + { var dataProvider = new FileDataProvider(fileName); var content = dataProvider.Load(); @@ -18,10 +18,10 @@ namespace mRemoteNG.Config.Import var connectionTreeModel = deserializer.Deserialize(content); var importedConnection = connectionTreeModel.RootNodes.First().Children.First(); - + if (importedConnection == null) return; importedConnection.Name = Path.GetFileNameWithoutExtension(fileName); destinationContainer.AddChild(importedConnection); - } + } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs b/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs index fe6001916..c4db3252c 100644 --- a/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs +++ b/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs @@ -6,10 +6,10 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class RemoteDesktopConnectionManagerImporter : IConnectionImporter - { - public void Import(string filePath, ContainerInfo destinationContainer) - { + public class RemoteDesktopConnectionManagerImporter : IConnectionImporter + { + public void Import(string filePath, ContainerInfo destinationContainer) + { var dataProvider = new FileDataProvider(filePath); var fileContent = dataProvider.Load(); @@ -21,5 +21,5 @@ namespace mRemoteNG.Config.Import var childrenToAdd = importedRootNode.Children.ToArray(); destinationContainer.AddChildRange(childrenToAdd); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Putty/AbstractPuttySessionsProvider.cs b/mRemoteV1/Config/Putty/AbstractPuttySessionsProvider.cs index 2c5d55c63..38da3533a 100644 --- a/mRemoteV1/Config/Putty/AbstractPuttySessionsProvider.cs +++ b/mRemoteV1/Config/Putty/AbstractPuttySessionsProvider.cs @@ -5,37 +5,42 @@ using System.Web; using mRemoteNG.Connection; using mRemoteNG.Tree.Root; using System.Text; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Config.Putty { public abstract class AbstractPuttySessionsProvider - { + { public virtual RootPuttySessionsNodeInfo RootInfo { get; } = new RootPuttySessionsNodeInfo(); + protected virtual List Sessions { get { return RootInfo.Children.OfType().ToList(); } } - #region Public Methods + #region Public Methods + public abstract string[] GetSessionNames(bool raw = false); - public abstract PuttySessionInfo GetSession(string sessionName); - - public virtual IEnumerable GetSessions() - { - var sessionNamesFromProvider = GetSessionNames(true); + public abstract PuttySessionInfo GetSession(string sessionName); + + public virtual IEnumerable GetSessions() + { + var sessionNamesFromProvider = GetSessionNames(true); foreach (var sessionName in GetSessionNamesToAdd(sessionNamesFromProvider)) - { - var sessionInfo = GetSession(sessionName); - AddSession(sessionInfo); - } - foreach (var session in GetSessionToRemove(sessionNamesFromProvider)) - { - RemoveSession(session); - } + { + var sessionInfo = GetSession(sessionName); + AddSession(sessionInfo); + } + + foreach (var session in GetSessionToRemove(sessionNamesFromProvider)) + { + RemoveSession(session); + } + RootInfo.SortRecursive(); - return Sessions; - } + return Sessions; + } private IEnumerable GetSessionNamesToAdd(IEnumerable sessionNamesFromProvider) { @@ -47,7 +52,9 @@ namespace mRemoteNG.Config.Putty private IEnumerable GetSessionToRemove(IEnumerable sessionNamesFromProvider) { var currentlyKnownSessionNames = Sessions.Select(session => session.Name); - var normalizedSessionNames = sessionNamesFromProvider.Select(name => HttpUtility.UrlDecode(name, Encoding.GetEncoding("iso-8859-1"))); + var normalizedSessionNames = + sessionNamesFromProvider.Select(name => + HttpUtility.UrlDecode(name, Encoding.GetEncoding("iso-8859-1"))); var sessionNamesToRemove = currentlyKnownSessionNames.Except(normalizedSessionNames); return Sessions.Where(session => sessionNamesToRemove.Contains(session.Name)); } @@ -57,29 +64,43 @@ namespace mRemoteNG.Config.Putty if (string.IsNullOrEmpty(sessionInfo?.Name) || Sessions.Any(child => child.Name == sessionInfo.Name)) return; RootInfo.AddChild(sessionInfo); - RaisePuttySessionCollectionChangedEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sessionInfo)); + RaisePuttySessionCollectionChangedEvent( + new + NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + sessionInfo)); } protected virtual void RemoveSession(PuttySessionInfo sessionInfo) { if (!Sessions.Contains(sessionInfo)) return; RootInfo.RemoveChild(sessionInfo); - RaisePuttySessionCollectionChangedEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, sessionInfo)); + RaisePuttySessionCollectionChangedEvent( + new + NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + sessionInfo)); } - - public virtual void StartWatcher() { } - - public virtual void StopWatcher() { } + + public virtual void StartWatcher() + { + } + + public virtual void StopWatcher() + { + } + #endregion - - public delegate void PuttySessionChangedEventHandler(object sender, PuttySessionChangedEventArgs e); + + public delegate void PuttySessionChangedEventHandler(object sender, PuttySessionChangedEventArgs e); + public event PuttySessionChangedEventHandler PuttySessionChanged; - protected virtual void RaiseSessionChangedEvent(PuttySessionChangedEventArgs args) - { + + protected virtual void RaiseSessionChangedEvent(PuttySessionChangedEventArgs args) + { PuttySessionChanged?.Invoke(this, args); - } + } public event NotifyCollectionChangedEventHandler PuttySessionsCollectionChanged; + protected void RaisePuttySessionCollectionChangedEvent(NotifyCollectionChangedEventArgs args) { PuttySessionsCollectionChanged?.Invoke(this, args); diff --git a/mRemoteV1/Config/Putty/PuttySessionsManager.cs b/mRemoteV1/Config/Putty/PuttySessionsManager.cs index 72e9a1ce0..4286e60d3 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsManager.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsManager.cs @@ -3,74 +3,80 @@ using System.Collections.Specialized; using System.ComponentModel; using mRemoteNG.Tools; using mRemoteNG.Tree.Root; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Config.Putty { public class PuttySessionsManager - { + { public static PuttySessionsManager Instance { get; } = new PuttySessionsManager(); private readonly List _providers = new List(); + public IEnumerable Providers { get { return _providers; } } - public List RootPuttySessionsNodes { get; } = new List(); + public List RootPuttySessionsNodes { get; } = new List(); - private PuttySessionsManager() - { - AddProvider(new PuttySessionsRegistryProvider()); + private PuttySessionsManager() + { + AddProvider(new PuttySessionsRegistryProvider()); AddProvider(new PuttySessionsXmingProvider()); - } + } #region Public Methods - public void AddSessions() - { - foreach (var provider in Providers) - { - AddSessionsFromProvider(provider); - } - } - private void AddSessionsFromProvider(AbstractPuttySessionsProvider puttySessionProvider) - { - puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider)); + public void AddSessions() + { + foreach (var provider in Providers) + { + AddSessionsFromProvider(provider); + } + } + + private void AddSessionsFromProvider(AbstractPuttySessionsProvider puttySessionProvider) + { + puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider)); var rootTreeNode = puttySessionProvider.RootInfo; - puttySessionProvider.GetSessions(); + puttySessionProvider.GetSessions(); if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren()) RootPuttySessionsNodes.Add(rootTreeNode); rootTreeNode.SortRecursive(); } - - public void StartWatcher() - { - foreach (var provider in Providers) - { - provider.StartWatcher(); - provider.PuttySessionChanged += PuttySessionChanged; - } - } - - public void StopWatcher() - { - foreach (var provider in Providers) - { - provider.StopWatcher(); - provider.PuttySessionChanged -= PuttySessionChanged; - } - } + + public void StartWatcher() + { + foreach (var provider in Providers) + { + provider.StartWatcher(); + provider.PuttySessionChanged += PuttySessionChanged; + } + } + + public void StopWatcher() + { + foreach (var provider in Providers) + { + provider.StopWatcher(); + provider.PuttySessionChanged -= PuttySessionChanged; + } + } public void AddProvider(AbstractPuttySessionsProvider newProvider) { if (_providers.Contains(newProvider)) return; _providers.Add(newProvider); newProvider.PuttySessionsCollectionChanged += RaisePuttySessionCollectionChangedEvent; - RaiseSessionProvidersCollectionChangedEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newProvider)); + RaiseSessionProvidersCollectionChangedEvent( + new + NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + newProvider)); } public void AddProviders(IEnumerable newProviders) @@ -84,48 +90,58 @@ namespace mRemoteNG.Config.Putty if (!_providers.Contains(providerToRemove)) return; _providers.Remove(providerToRemove); providerToRemove.PuttySessionsCollectionChanged -= RaisePuttySessionCollectionChangedEvent; - RaiseSessionProvidersCollectionChangedEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, providerToRemove)); + RaiseSessionProvidersCollectionChangedEvent( + new + NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + providerToRemove)); } public void PuttySessionChanged(object sender, PuttySessionChangedEventArgs e) - { - AddSessions(); - } + { + AddSessions(); + } + #endregion #region Private Methods - private string[] GetSessionNames(bool raw = false) - { - var sessionNames = new List(); - foreach (var provider in Providers) - { - if (!IsProviderEnabled(provider)) - { - continue; - } - sessionNames.AddRange(provider.GetSessionNames(raw)); - } - return sessionNames.ToArray(); - } - - private bool IsProviderEnabled(AbstractPuttySessionsProvider puttySessionsProvider) - { + + private string[] GetSessionNames(bool raw = false) + { + var sessionNames = new List(); + foreach (var provider in Providers) + { + if (!IsProviderEnabled(provider)) + { + continue; + } + + sessionNames.AddRange(provider.GetSessionNames(raw)); + } + + return sessionNames.ToArray(); + } + + private bool IsProviderEnabled(AbstractPuttySessionsProvider puttySessionsProvider) + { var enabled = true; - if (PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.Xming) - { - if (puttySessionsProvider is PuttySessionsRegistryProvider) - enabled = false; - } - else - { - if (puttySessionsProvider is PuttySessionsXmingProvider) - enabled = false; - } - return enabled; - } + if (PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.Xming) + { + if (puttySessionsProvider is PuttySessionsRegistryProvider) + enabled = false; + } + else + { + if (puttySessionsProvider is PuttySessionsXmingProvider) + enabled = false; + } + + return enabled; + } + #endregion - + #region Public Classes + public class SessionList : StringConverter { public static string[] Names @@ -134,29 +150,32 @@ namespace mRemoteNG.Config.Putty } public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) - { - return new StandardValuesCollection(Names); - } - - public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) - { - return true; - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) - { - return true; - } + { + return new StandardValuesCollection(Names); + } + + public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) + { + return true; + } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { + return true; + } } + #endregion public event NotifyCollectionChangedEventHandler PuttySessionsCollectionChanged; + protected void RaisePuttySessionCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) { PuttySessionsCollectionChanged?.Invoke(sender, args); } public event NotifyCollectionChangedEventHandler SessionProvidersCollectionChanged; + protected void RaiseSessionProvidersCollectionChangedEvent(NotifyCollectionChangedEventArgs args) { SessionProvidersCollectionChanged?.Invoke(this, args); diff --git a/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs b/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs index 929b66be4..663279d3d 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs @@ -14,30 +14,34 @@ using mRemoteNG.Messages; namespace mRemoteNG.Config.Putty { public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider - { + { private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions"; private static ManagementEventWatcher _eventWatcher; #region Public Methods - public override string[] GetSessionNames(bool raw = false) - { + + public override string[] GetSessionNames(bool raw = false) + { var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey); - if (sessionsKey == null) return new string[] {}; + if (sessionsKey == null) return new string[] { }; var sessionNames = new List(); - foreach (var sessionName in sessionsKey.GetSubKeyNames()) - { - sessionNames.Add(raw ? sessionName : HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"), Encoding.GetEncoding("iso-8859-1"))); - } - - if (raw && !sessionNames.Contains("Default%20Settings")) - sessionNames.Insert(0, "Default%20Settings"); - else if (!raw && !sessionNames.Contains("Default Settings")) - sessionNames.Insert(0, "Default Settings"); - - return sessionNames.ToArray(); - } - + foreach (var sessionName in sessionsKey.GetSubKeyNames()) + { + sessionNames.Add(raw + ? sessionName + : HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"), + Encoding.GetEncoding("iso-8859-1"))); + } + + if (raw && !sessionNames.Contains("Default%20Settings")) + sessionNames.Insert(0, "Default%20Settings"); + else if (!raw && !sessionNames.Contains("Default Settings")) + sessionNames.Insert(0, "Default Settings"); + + return sessionNames.ToArray(); + } + public override PuttySessionInfo GetSession(string sessionName) { if (string.IsNullOrEmpty(sessionName)) @@ -45,35 +49,35 @@ namespace mRemoteNG.Config.Putty var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey); var sessionKey = sessionsKey?.OpenSubKey(sessionName); - if (sessionKey == null) return null; + if (sessionKey == null) return null; sessionName = HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"), Encoding.GetEncoding("iso-8859-1")); - - var sessionInfo = new PuttySessionInfo - { - PuttySession = sessionName, - Name = sessionName, - Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "", - Username = sessionKey.GetValue("UserName")?.ToString() ?? "" - }; + + var sessionInfo = new PuttySessionInfo + { + PuttySession = sessionName, + Name = sessionName, + Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "", + Username = sessionKey.GetValue("UserName")?.ToString() ?? "" + }; - var protocol = string.IsNullOrEmpty(sessionKey.GetValue("Protocol")?.ToString()) - ? "ssh" + var protocol = string.IsNullOrEmpty(sessionKey.GetValue("Protocol")?.ToString()) + ? "ssh" : sessionKey.GetValue("Protocol").ToString(); - switch (protocol.ToLowerInvariant()) - { - case "raw": - sessionInfo.Protocol = ProtocolType.RAW; - break; - case "rlogin": - sessionInfo.Protocol = ProtocolType.Rlogin; - break; - case "serial": - return null; - case "ssh": - int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion); + switch (protocol.ToLowerInvariant()) + { + case "raw": + sessionInfo.Protocol = ProtocolType.RAW; + break; + case "rlogin": + sessionInfo.Protocol = ProtocolType.Rlogin; + break; + case "serial": + return null; + case "ssh": + int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion); /* Per PUTTY.H in PuTTYNG & PuTTYNG Upstream (PuTTY proper currently) * expect 0 for SSH1, 3 for SSH2 ONLY * 1 for SSH1 with a 2 fallback @@ -82,53 +86,56 @@ namespace mRemoteNG.Config.Putty * default to SSH2 if any other value is received */ sessionInfo.Protocol = sshVersion == 1 || sshVersion == 0 ? ProtocolType.SSH1 : ProtocolType.SSH2; - break; - case "telnet": - sessionInfo.Protocol = ProtocolType.Telnet; - break; - default: - return null; - } + break; + case "telnet": + sessionInfo.Protocol = ProtocolType.Telnet; + break; + default: + return null; + } int.TryParse(sessionKey.GetValue("PortNumber")?.ToString(), out var portNumber); if (portNumber == default(int)) sessionInfo.SetDefaultPort(); else sessionInfo.Port = portNumber; - - return sessionInfo; - } - - public override void StartWatcher() - { - if (_eventWatcher != null) return; - - try - { + + return sessionInfo; + } + + public override void StartWatcher() + { + if (_eventWatcher != null) return; + + try + { var currentUserSid = WindowsIdentity.GetCurrent().User?.Value; var key = string.Join("\\", currentUserSid, PuttySessionsKey).Replace("\\", "\\\\"); - var query = new WqlEventQuery($"SELECT * FROM RegistryTreeChangeEvent WHERE Hive = \'HKEY_USERS\' AND RootPath = \'{key}\'"); - _eventWatcher = new ManagementEventWatcher(query); - _eventWatcher.EventArrived += OnManagementEventArrived; - _eventWatcher.Start(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("PuttySessions.Watcher.StartWatching() failed.", ex, MessageClass.WarningMsg); - } - } - - public override void StopWatcher() - { - if (_eventWatcher == null) return; - _eventWatcher.Stop(); - _eventWatcher.Dispose(); - } + var query = new WqlEventQuery( + $"SELECT * FROM RegistryTreeChangeEvent WHERE Hive = \'HKEY_USERS\' AND RootPath = \'{key}\'"); + _eventWatcher = new ManagementEventWatcher(query); + _eventWatcher.EventArrived += OnManagementEventArrived; + _eventWatcher.Start(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("PuttySessions.Watcher.StartWatching() failed.", ex, + MessageClass.WarningMsg); + } + } + + public override void StopWatcher() + { + if (_eventWatcher == null) return; + _eventWatcher.Stop(); + _eventWatcher.Dispose(); + } + #endregion - - private void OnManagementEventArrived(object sender, EventArrivedEventArgs e) - { - RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); - } + + private void OnManagementEventArrived(object sender, EventArrivedEventArgs e) + { + RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); + } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs index 4b99a02a8..2c4267f0b 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs @@ -12,339 +12,374 @@ using mRemoteNG.Tree.Root; namespace mRemoteNG.Config.Putty { - public class PuttySessionsXmingProvider : AbstractPuttySessionsProvider - { - public override RootPuttySessionsNodeInfo RootInfo { get; } = new RootPuttySessionsNodeInfo { Name = "Xming Putty Sessions" }; + public class PuttySessionsXmingProvider : AbstractPuttySessionsProvider + { + public override RootPuttySessionsNodeInfo RootInfo { get; } = + new RootPuttySessionsNodeInfo {Name = "Xming Putty Sessions"}; + private const string RegistrySessionNameFormat = "{0} [registry]"; private const string RegistrySessionNamePattern = "(.*)\\ \\[registry\\]"; - private static readonly PuttySessionsRegistryProvider PuttySessionsRegistryProvider = new PuttySessionsRegistryProvider(); + + private static readonly PuttySessionsRegistryProvider PuttySessionsRegistryProvider = + new PuttySessionsRegistryProvider(); + private static FileSystemWatcher _eventWatcher; #region Public Methods - public override string[] GetSessionNames(bool raw = false) - { - var sessionsFolderPath = GetSessionsFolderPath(); - if (!Directory.Exists(sessionsFolderPath)) - { - return new string[] {}; - } + + public override string[] GetSessionNames(bool raw = false) + { + var sessionsFolderPath = GetSessionsFolderPath(); + if (!Directory.Exists(sessionsFolderPath)) + { + return new string[] { }; + } var sessionNames = new List(); - foreach (var sessionName in Directory.GetFiles(sessionsFolderPath)) - { - var sessionFileName = Path.GetFileName(sessionName); - // ReSharper disable once ConstantConditionalAccessQualifier - sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B"))); - } + foreach (var sessionName in Directory.GetFiles(sessionsFolderPath)) + { + var sessionFileName = Path.GetFileName(sessionName); + // ReSharper disable once ConstantConditionalAccessQualifier + sessionNames.Add(raw + ? sessionFileName + : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B"))); + } - if (raw) - { - if (!sessionNames.Contains("Default%20Settings")) // Do not localize - { - sessionNames.Insert(0, "Default%20Settings"); - } - } - else - { - if (!sessionNames.Contains("Default Settings")) - { - sessionNames.Insert(0, "Default Settings"); - } - } + if (raw) + { + if (!sessionNames.Contains("Default%20Settings")) // Do not localize + { + sessionNames.Insert(0, "Default%20Settings"); + } + } + else + { + if (!sessionNames.Contains("Default Settings")) + { + sessionNames.Insert(0, "Default Settings"); + } + } - var registrySessionNames = PuttySessionsRegistryProvider.GetSessionNames(raw).Select(sessionName => string.Format(RegistrySessionNameFormat, sessionName)).ToList(); + var registrySessionNames = PuttySessionsRegistryProvider.GetSessionNames(raw) + .Select(sessionName => + string + .Format(RegistrySessionNameFormat, + sessionName)).ToList(); - sessionNames.AddRange(registrySessionNames); - sessionNames.Sort(); - - return sessionNames.ToArray(); - } - - public override PuttySessionInfo GetSession(string sessionName) - { + sessionNames.AddRange(registrySessionNames); + sessionNames.Sort(); + + return sessionNames.ToArray(); + } + + public override PuttySessionInfo GetSession(string sessionName) + { var registrySessionName = GetRegistrySessionName(sessionName); - if (!string.IsNullOrEmpty(registrySessionName)) - { - return ModifyRegistrySessionInfo(PuttySessionsRegistryProvider.GetSession(registrySessionName)); - } + if (!string.IsNullOrEmpty(registrySessionName)) + { + return ModifyRegistrySessionInfo(PuttySessionsRegistryProvider.GetSession(registrySessionName)); + } var sessionsFolderPath = GetSessionsFolderPath(); - if (!Directory.Exists(sessionsFolderPath)) - { - return null; - } + if (!Directory.Exists(sessionsFolderPath)) + { + return null; + } var sessionFile = Path.Combine(sessionsFolderPath, sessionName); - if (!File.Exists(sessionFile)) - { - return null; - } - - sessionName = System.Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B")); + if (!File.Exists(sessionFile)) + { + return null; + } + + sessionName = System.Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B")); var sessionFileReader = new SessionFileReader(sessionFile); - var sessionInfo = new PuttySessionInfo - { - PuttySession = sessionName, - Name = sessionName, - Hostname = sessionFileReader.GetValue("HostName"), - Username = sessionFileReader.GetValue("UserName") - }; - var protocol = sessionFileReader.GetValue("Protocol") ?? "ssh"; - switch (protocol.ToLowerInvariant()) - { - case "raw": - sessionInfo.Protocol = ProtocolType.RAW; - break; - case "rlogin": - sessionInfo.Protocol = ProtocolType.Rlogin; - break; - case "serial": - return null; - case "ssh": - object sshVersionObject = sessionFileReader.GetValue("SshProt"); - if (sshVersionObject != null) - { - var sshVersion = Convert.ToInt32(sshVersionObject); - sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1; - } - else - { - sessionInfo.Protocol = ProtocolType.SSH2; - } - break; - case "telnet": - sessionInfo.Protocol = ProtocolType.Telnet; - break; - default: - return null; - } - sessionInfo.Port = Convert.ToInt32(sessionFileReader.GetValue("PortNumber")); - - return sessionInfo; - } - - public override void StartWatcher() - { - if (_eventWatcher != null) - { - return; - } - - try - { + var sessionInfo = new PuttySessionInfo + { + PuttySession = sessionName, + Name = sessionName, + Hostname = sessionFileReader.GetValue("HostName"), + Username = sessionFileReader.GetValue("UserName") + }; + var protocol = sessionFileReader.GetValue("Protocol") ?? "ssh"; + switch (protocol.ToLowerInvariant()) + { + case "raw": + sessionInfo.Protocol = ProtocolType.RAW; + break; + case "rlogin": + sessionInfo.Protocol = ProtocolType.Rlogin; + break; + case "serial": + return null; + case "ssh": + object sshVersionObject = sessionFileReader.GetValue("SshProt"); + if (sshVersionObject != null) + { + var sshVersion = Convert.ToInt32(sshVersionObject); + sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1; + } + else + { + sessionInfo.Protocol = ProtocolType.SSH2; + } + + break; + case "telnet": + sessionInfo.Protocol = ProtocolType.Telnet; + break; + default: + return null; + } + + sessionInfo.Port = Convert.ToInt32(sessionFileReader.GetValue("PortNumber")); + + return sessionInfo; + } + + public override void StartWatcher() + { + if (_eventWatcher != null) + { + return; + } + + try + { var sessionsFolderPath = GetSessionsFolderPath(); - if (!Directory.Exists(sessionsFolderPath)) - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", true); - return; - } + if (!Directory.Exists(sessionsFolderPath)) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", + true); + return; + } + + _eventWatcher = new FileSystemWatcher(sessionsFolderPath) + { + NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite + }; + _eventWatcher.Changed += OnFileSystemEventArrived; + _eventWatcher.Created += OnFileSystemEventArrived; + _eventWatcher.Deleted += OnFileSystemEventArrived; + _eventWatcher.Renamed += OnFileSystemEventArrived; + _eventWatcher.EnableRaisingEvents = true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + "XmingPortablePuttySessions.Watcher.StartWatching() failed.", + ex, MessageClass.WarningMsg); + } + } + + public override void StopWatcher() + { + PuttySessionsRegistryProvider.StopWatcher(); + PuttySessionsRegistryProvider.PuttySessionChanged -= OnRegistrySessionChanged; + + if (_eventWatcher == null) + { + return; + } + + _eventWatcher.EnableRaisingEvents = false; + _eventWatcher.Dispose(); + } - _eventWatcher = new FileSystemWatcher(sessionsFolderPath) - { - NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite - }; - _eventWatcher.Changed += OnFileSystemEventArrived; - _eventWatcher.Created += OnFileSystemEventArrived; - _eventWatcher.Deleted += OnFileSystemEventArrived; - _eventWatcher.Renamed += OnFileSystemEventArrived; - _eventWatcher.EnableRaisingEvents = true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("XmingPortablePuttySessions.Watcher.StartWatching() failed.", ex, MessageClass.WarningMsg); - } - } - - public override void StopWatcher() - { - PuttySessionsRegistryProvider.StopWatcher(); - PuttySessionsRegistryProvider.PuttySessionChanged -= OnRegistrySessionChanged; - - if (_eventWatcher == null) - { - return; - } - _eventWatcher.EnableRaisingEvents = false; - _eventWatcher.Dispose(); - } #endregion - + #region Private Methods - private static string GetPuttyConfPath() - { - var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath; - puttyPath = Path.GetDirectoryName(puttyPath); + + private static string GetPuttyConfPath() + { + var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath + ? mRemoteNG.Settings.Default.CustomPuttyPath + : App.Info.GeneralAppInfo.PuttyPath; + puttyPath = Path.GetDirectoryName(puttyPath); return string.IsNullOrEmpty(puttyPath) ? null : Path.Combine(puttyPath, "putty.conf"); - } - - private static string GetSessionsFolderPath() - { + } + + private static string GetSessionsFolderPath() + { var puttyConfPath = GetPuttyConfPath(); var sessionFileReader = new PuttyConfFileReader(puttyConfPath); var basePath = Environment.ExpandEnvironmentVariables(sessionFileReader.GetValue("sshk&sess")); - return Path.Combine(basePath, "sessions"); - } - - private static string GetRegistrySessionName(string sessionName) - { + return Path.Combine(basePath, "sessions"); + } + + private static string GetRegistrySessionName(string sessionName) + { var regex = new Regex(RegistrySessionNamePattern); var matches = regex.Matches(sessionName); - if (matches.Count < 1) - { - return string.Empty; - } + if (matches.Count < 1) + { + return string.Empty; + } var groups = matches[0].Groups; - return groups.Count < 1 ? string.Empty : groups[1].Value; - } - - private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo) - { - if (sessionInfo == null) - return null; + return groups.Count < 1 ? string.Empty : groups[1].Value; + } + + private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo) + { + if (sessionInfo == null) + return null; + + sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name); + sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession); + return sessionInfo; + } + + private void OnFileSystemEventArrived(object sender, FileSystemEventArgs e) + { + RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); + } + + private void OnRegistrySessionChanged(object sender, PuttySessionChangedEventArgs e) + { + RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); + } - sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name); - sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession); - return sessionInfo; - } - - private void OnFileSystemEventArrived(object sender, FileSystemEventArgs e) - { - RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); - } - - private void OnRegistrySessionChanged(object sender, PuttySessionChangedEventArgs e) - { - RaiseSessionChangedEvent(new PuttySessionChangedEventArgs()); - } #endregion - + #region Private Classes - private class PuttyConfFileReader - { - public PuttyConfFileReader(string puttyConfFile) - { - _puttyConfFile = puttyConfFile; - } - - private string _puttyConfFile; - private bool _configurationLoaded; - private Dictionary _configuration = new Dictionary(); - - private void LoadConfiguration() - { - _configurationLoaded = true; - try - { - if (!File.Exists(_puttyConfFile)) - { - return; - } - using (var streamReader = new StreamReader(_puttyConfFile)) - { - do - { - var line = streamReader.ReadLine(); - if (line == null) - { - break; - } - line = line.Trim(); - if (line == string.Empty) - { - continue; // Blank line - } - if (line.Substring(0, 1) == ";") - { - continue; // Comment - } + + private class PuttyConfFileReader + { + public PuttyConfFileReader(string puttyConfFile) + { + _puttyConfFile = puttyConfFile; + } + + private string _puttyConfFile; + private bool _configurationLoaded; + private Dictionary _configuration = new Dictionary(); + + private void LoadConfiguration() + { + _configurationLoaded = true; + try + { + if (!File.Exists(_puttyConfFile)) + { + return; + } + + using (var streamReader = new StreamReader(_puttyConfFile)) + { + do + { + var line = streamReader.ReadLine(); + if (line == null) + { + break; + } + + line = line.Trim(); + if (line == string.Empty) + { + continue; // Blank line + } + + if (line.Substring(0, 1) == ";") + { + continue; // Comment + } + var parts = line.Split(new[] {'='}, 2); - if (parts.Length < 2) - { - continue; - } - if (_configuration.ContainsKey(parts[0])) - { - continue; // As per http://www.straightrunning.com/XmingNotes/portableputty.php only first entry is used - } - _configuration.Add(parts[0], parts[1]); - } while (true); - } - - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("PuttyConfFileReader.LoadConfiguration() failed.", ex); - } - } - - public string GetValue(string setting) - { - if (!_configurationLoaded) - { - LoadConfiguration(); - } - return !_configuration.ContainsKey(setting) ? string.Empty : _configuration[setting]; - } - } - - private class SessionFileReader - { - public SessionFileReader(string sessionFile) - { - _sessionFile = sessionFile; - } - - private string _sessionFile; - private bool _sessionInfoLoaded; - private Dictionary _sessionInfo = new Dictionary(); - - private void LoadSessionInfo() - { - _sessionInfoLoaded = true; - try - { - if (!File.Exists(_sessionFile)) - { - return; - } - using (var streamReader = new StreamReader(_sessionFile)) - { - do - { - var line = streamReader.ReadLine(); - if (line == null) - { - break; - } + if (parts.Length < 2) + { + continue; + } + + if (_configuration.ContainsKey(parts[0])) + { + continue; // As per http://www.straightrunning.com/XmingNotes/portableputty.php only first entry is used + } + + _configuration.Add(parts[0], parts[1]); + } while (true); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("PuttyConfFileReader.LoadConfiguration() failed.", ex); + } + } + + public string GetValue(string setting) + { + if (!_configurationLoaded) + { + LoadConfiguration(); + } + + return !_configuration.ContainsKey(setting) ? string.Empty : _configuration[setting]; + } + } + + private class SessionFileReader + { + public SessionFileReader(string sessionFile) + { + _sessionFile = sessionFile; + } + + private string _sessionFile; + private bool _sessionInfoLoaded; + private Dictionary _sessionInfo = new Dictionary(); + + private void LoadSessionInfo() + { + _sessionInfoLoaded = true; + try + { + if (!File.Exists(_sessionFile)) + { + return; + } + + using (var streamReader = new StreamReader(_sessionFile)) + { + do + { + var line = streamReader.ReadLine(); + if (line == null) + { + break; + } + var parts = line.Split('\\'); - if (parts.Length < 2) - { - continue; - } - _sessionInfo.Add(parts[0], parts[1]); - } while (true); - } - - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("SessionFileReader.LoadSessionInfo() failed.", ex); - } - } - - public string GetValue(string setting) - { - if (!_sessionInfoLoaded) - { - LoadSessionInfo(); - } - return !_sessionInfo.ContainsKey(setting) ? string.Empty : _sessionInfo[setting]; - } - } + if (parts.Length < 2) + { + continue; + } + + _sessionInfo.Add(parts[0], parts[1]); + } while (true); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("SessionFileReader.LoadSessionInfo() failed.", ex); + } + } + + public string GetValue(string setting) + { + if (!_sessionInfoLoaded) + { + LoadSessionInfo(); + } + + return !_sessionInfo.ContainsKey(setting) ? string.Empty : _sessionInfo[setting]; + } + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs index 0bef17557..afc18bd7f 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs @@ -17,7 +17,7 @@ namespace mRemoteNG.Config.Serializers.Csv { public ConnectionTreeModel Deserialize(string serializedData) { - var lines = serializedData.Split(new []{"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries); + var lines = serializedData.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries); var csvHeaders = new List(); // used to map a connectioninfo to it's parent's GUID var parentMapping = new Dictionary(); @@ -55,9 +55,9 @@ namespace mRemoteNG.Config.Serializers.Csv // search for parent in the list by GUID var parent = parentMapping - .Keys - .OfType() - .FirstOrDefault(info => info.ConstantID == node.Value); + .Keys + .OfType() + .FirstOrDefault(info => info.ConstantID == node.Value); if (parent != null) { @@ -75,7 +75,7 @@ namespace mRemoteNG.Config.Serializers.Csv private ConnectionInfo ParseConnectionInfo(IList headers, string[] connectionCsv) { var nodeType = headers.Contains("NodeType") - ? (TreeNodeType)Enum.Parse(typeof(TreeNodeType), connectionCsv[headers.IndexOf("NodeType")], true) + ? (TreeNodeType)Enum.Parse(typeof(TreeNodeType), connectionCsv[headers.IndexOf("NodeType")], true) : TreeNodeType.Connection; var nodeId = headers.Contains("Id") @@ -87,27 +87,48 @@ namespace mRemoteNG.Config.Serializers.Csv : new ContainerInfo(nodeId); connectionRecord.Name = headers.Contains("Name") ? connectionCsv[headers.IndexOf("Name")] : ""; - connectionRecord.Description = headers.Contains("Description") ? connectionCsv[headers.IndexOf("Description")] : ""; + connectionRecord.Description = + headers.Contains("Description") ? connectionCsv[headers.IndexOf("Description")] : ""; connectionRecord.Icon = headers.Contains("Icon") ? connectionCsv[headers.IndexOf("Icon")] : ""; connectionRecord.Panel = headers.Contains("Panel") ? connectionCsv[headers.IndexOf("Panel")] : ""; connectionRecord.Username = headers.Contains("Username") ? connectionCsv[headers.IndexOf("Username")] : ""; connectionRecord.Password = headers.Contains("Password") ? connectionCsv[headers.IndexOf("Password")] : ""; connectionRecord.Domain = headers.Contains("Domain") ? connectionCsv[headers.IndexOf("Domain")] : ""; connectionRecord.Hostname = headers.Contains("Hostname") ? connectionCsv[headers.IndexOf("Hostname")] : ""; - connectionRecord.PuttySession = headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : ""; - connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo") ? connectionCsv[headers.IndexOf("LoadBalanceInfo")] : ""; - connectionRecord.PreExtApp = headers.Contains("PreExtApp") ? connectionCsv[headers.IndexOf("PreExtApp")] : ""; - connectionRecord.PostExtApp = headers.Contains("PostExtApp") ? connectionCsv[headers.IndexOf("PostExtApp")] : ""; - connectionRecord.MacAddress = headers.Contains("MacAddress") ? connectionCsv[headers.IndexOf("MacAddress")] : ""; - connectionRecord.UserField = headers.Contains("UserField") ? connectionCsv[headers.IndexOf("UserField")] : ""; + connectionRecord.PuttySession = + headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : ""; + connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo") + ? connectionCsv[headers.IndexOf("LoadBalanceInfo")] + : ""; + connectionRecord.PreExtApp = + headers.Contains("PreExtApp") ? connectionCsv[headers.IndexOf("PreExtApp")] : ""; + connectionRecord.PostExtApp = + headers.Contains("PostExtApp") ? connectionCsv[headers.IndexOf("PostExtApp")] : ""; + connectionRecord.MacAddress = + headers.Contains("MacAddress") ? connectionCsv[headers.IndexOf("MacAddress")] : ""; + connectionRecord.UserField = + headers.Contains("UserField") ? connectionCsv[headers.IndexOf("UserField")] : ""; connectionRecord.ExtApp = headers.Contains("ExtApp") ? connectionCsv[headers.IndexOf("ExtApp")] : ""; - connectionRecord.VNCProxyUsername = headers.Contains("VNCProxyUsername") ? connectionCsv[headers.IndexOf("VNCProxyUsername")] : ""; - connectionRecord.VNCProxyPassword = headers.Contains("VNCProxyPassword") ? connectionCsv[headers.IndexOf("VNCProxyPassword")] : ""; - connectionRecord.RDGatewayUsername = headers.Contains("RDGatewayUsername") ? connectionCsv[headers.IndexOf("RDGatewayUsername")] : ""; - connectionRecord.RDGatewayPassword = headers.Contains("RDGatewayPassword") ? connectionCsv[headers.IndexOf("RDGatewayPassword")] : ""; - connectionRecord.RDGatewayDomain = headers.Contains("RDGatewayDomain") ? connectionCsv[headers.IndexOf("RDGatewayDomain")] : ""; - connectionRecord.VNCProxyIP = headers.Contains("VNCProxyIP") ? connectionCsv[headers.IndexOf("VNCProxyIP")] : ""; - connectionRecord.RDGatewayHostname = headers.Contains("RDGatewayHostname") ? connectionCsv[headers.IndexOf("RDGatewayHostname")] : ""; + connectionRecord.VNCProxyUsername = headers.Contains("VNCProxyUsername") + ? connectionCsv[headers.IndexOf("VNCProxyUsername")] + : ""; + connectionRecord.VNCProxyPassword = headers.Contains("VNCProxyPassword") + ? connectionCsv[headers.IndexOf("VNCProxyPassword")] + : ""; + connectionRecord.RDGatewayUsername = headers.Contains("RDGatewayUsername") + ? connectionCsv[headers.IndexOf("RDGatewayUsername")] + : ""; + connectionRecord.RDGatewayPassword = headers.Contains("RDGatewayPassword") + ? connectionCsv[headers.IndexOf("RDGatewayPassword")] + : ""; + connectionRecord.RDGatewayDomain = headers.Contains("RDGatewayDomain") + ? connectionCsv[headers.IndexOf("RDGatewayDomain")] + : ""; + connectionRecord.VNCProxyIP = + headers.Contains("VNCProxyIP") ? connectionCsv[headers.IndexOf("VNCProxyIP")] : ""; + connectionRecord.RDGatewayHostname = headers.Contains("RDGatewayHostname") + ? connectionCsv[headers.IndexOf("RDGatewayHostname")] + : ""; if (headers.Contains("Protocol")) { @@ -234,6 +255,7 @@ namespace mRemoteNG.Config.Serializers.Csv if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectPrinters")], out value)) connectionRecord.RedirectPrinters = value; } + if (headers.Contains("RedirectClipboard")) { bool value; @@ -333,6 +355,7 @@ namespace mRemoteNG.Config.Serializers.Csv } #region Inheritance + if (headers.Contains("InheritCacheBitmaps")) { bool value; @@ -672,7 +695,8 @@ namespace mRemoteNG.Config.Serializers.Csv if (headers.Contains("InheritRDGatewayUseConnectionCredentials")) { bool value; - if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayUseConnectionCredentials")], out value)) + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayUseConnectionCredentials")], + out value)) connectionRecord.Inheritance.RDGatewayUseConnectionCredentials = value; } @@ -717,9 +741,10 @@ namespace mRemoteNG.Config.Serializers.Csv if (bool.TryParse(connectionCsv[headers.IndexOf("InheritSoundQuality")], out value)) connectionRecord.Inheritance.SoundQuality = value; } + #endregion return connectionRecord; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs index bd0a6f296..62e3afc53 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs @@ -11,14 +11,15 @@ using System.Text; namespace mRemoteNG.Config.Serializers.Csv { - public class CsvConnectionsSerializerMremotengFormat : ISerializer + public class CsvConnectionsSerializerMremotengFormat : ISerializer { private readonly SaveFilter _saveFilter; private readonly ICredentialRepositoryList _credentialRepositoryList; public Version Version { get; } = new Version(2, 7); - public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList) + public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, + ICredentialRepositoryList credentialRepositoryList) { saveFilter.ThrowIfNull(nameof(saveFilter)); credentialRepositoryList.ThrowIfNull(nameof(credentialRepositoryList)); @@ -54,9 +55,11 @@ namespace mRemoteNG.Config.Serializers.Csv sb.Append("Password;"); if (_saveFilter.SaveDomain) sb.Append("Domain;"); - sb.Append("Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;"); + sb.Append( + "Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;"); if (_saveFilter.SaveInheritance) - sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality"); + sb.Append( + "InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality"); } private void SerializeNodesRecursive(ConnectionInfo node, StringBuilder sb) @@ -81,12 +84,12 @@ namespace mRemoteNG.Config.Serializers.Csv { sb.AppendLine(); sb.Append(FormatForCsv(con.Name)) - .Append(FormatForCsv(con.ConstantID)) - .Append(FormatForCsv(con.Parent?.ConstantID ?? "")) - .Append(FormatForCsv(con.GetTreeNodeType())) - .Append(FormatForCsv(con.Description)) - .Append(FormatForCsv(con.Icon)) - .Append(FormatForCsv(con.Panel)); + .Append(FormatForCsv(con.ConstantID)) + .Append(FormatForCsv(con.Parent?.ConstantID ?? "")) + .Append(FormatForCsv(con.GetTreeNodeType())) + .Append(FormatForCsv(con.Description)) + .Append(FormatForCsv(con.Icon)) + .Append(FormatForCsv(con.Panel)); if (_saveFilter.SaveUsername) sb.Append(FormatForCsv(con.Username)); @@ -98,112 +101,112 @@ namespace mRemoteNG.Config.Serializers.Csv sb.Append(FormatForCsv(con.Domain)); sb.Append(FormatForCsv(con.Hostname)) - .Append(FormatForCsv(con.Protocol)) - .Append(FormatForCsv(con.PuttySession)) - .Append(FormatForCsv(con.Port)) - .Append(FormatForCsv(con.UseConsoleSession)) - .Append(FormatForCsv(con.UseCredSsp)) - .Append(FormatForCsv(con.RenderingEngine)) - .Append(FormatForCsv(con.ICAEncryptionStrength)) - .Append(FormatForCsv(con.RDPAuthenticationLevel)) - .Append(FormatForCsv(con.LoadBalanceInfo)) - .Append(FormatForCsv(con.Colors)) - .Append(FormatForCsv(con.Resolution)) - .Append(FormatForCsv(con.AutomaticResize)) - .Append(FormatForCsv(con.DisplayWallpaper)) - .Append(FormatForCsv(con.DisplayThemes)) - .Append(FormatForCsv(con.EnableFontSmoothing)) - .Append(FormatForCsv(con.EnableDesktopComposition)) - .Append(FormatForCsv(con.CacheBitmaps)) - .Append(FormatForCsv(con.RedirectDiskDrives)) - .Append(FormatForCsv(con.RedirectPorts)) - .Append(FormatForCsv(con.RedirectPrinters)) - .Append(FormatForCsv(con.RedirectClipboard)) - .Append(FormatForCsv(con.RedirectSmartCards)) - .Append(FormatForCsv(con.RedirectSound)) - .Append(FormatForCsv(con.RedirectKeys)) - .Append(FormatForCsv(con.PreExtApp)) - .Append(FormatForCsv(con.PostExtApp)) - .Append(FormatForCsv(con.MacAddress)) - .Append(FormatForCsv(con.UserField)) - .Append(FormatForCsv(con.ExtApp)) - .Append(FormatForCsv(con.VNCCompression)) - .Append(FormatForCsv(con.VNCEncoding)) - .Append(FormatForCsv(con.VNCAuthMode)) - .Append(FormatForCsv(con.VNCProxyType)) - .Append(FormatForCsv(con.VNCProxyIP)) - .Append(FormatForCsv(con.VNCProxyPort)) - .Append(FormatForCsv(con.VNCProxyUsername)) - .Append(FormatForCsv(con.VNCProxyPassword)) - .Append(FormatForCsv(con.VNCColors)) - .Append(FormatForCsv(con.VNCSmartSizeMode)) - .Append(FormatForCsv(con.VNCViewOnly)) - .Append(FormatForCsv(con.RDGatewayUsageMethod)) - .Append(FormatForCsv(con.RDGatewayHostname)) - .Append(FormatForCsv(con.RDGatewayUseConnectionCredentials)) - .Append(FormatForCsv(con.RDGatewayUsername)) - .Append(FormatForCsv(con.RDGatewayPassword)) - .Append(FormatForCsv(con.RDGatewayDomain)); + .Append(FormatForCsv(con.Protocol)) + .Append(FormatForCsv(con.PuttySession)) + .Append(FormatForCsv(con.Port)) + .Append(FormatForCsv(con.UseConsoleSession)) + .Append(FormatForCsv(con.UseCredSsp)) + .Append(FormatForCsv(con.RenderingEngine)) + .Append(FormatForCsv(con.ICAEncryptionStrength)) + .Append(FormatForCsv(con.RDPAuthenticationLevel)) + .Append(FormatForCsv(con.LoadBalanceInfo)) + .Append(FormatForCsv(con.Colors)) + .Append(FormatForCsv(con.Resolution)) + .Append(FormatForCsv(con.AutomaticResize)) + .Append(FormatForCsv(con.DisplayWallpaper)) + .Append(FormatForCsv(con.DisplayThemes)) + .Append(FormatForCsv(con.EnableFontSmoothing)) + .Append(FormatForCsv(con.EnableDesktopComposition)) + .Append(FormatForCsv(con.CacheBitmaps)) + .Append(FormatForCsv(con.RedirectDiskDrives)) + .Append(FormatForCsv(con.RedirectPorts)) + .Append(FormatForCsv(con.RedirectPrinters)) + .Append(FormatForCsv(con.RedirectClipboard)) + .Append(FormatForCsv(con.RedirectSmartCards)) + .Append(FormatForCsv(con.RedirectSound)) + .Append(FormatForCsv(con.RedirectKeys)) + .Append(FormatForCsv(con.PreExtApp)) + .Append(FormatForCsv(con.PostExtApp)) + .Append(FormatForCsv(con.MacAddress)) + .Append(FormatForCsv(con.UserField)) + .Append(FormatForCsv(con.ExtApp)) + .Append(FormatForCsv(con.VNCCompression)) + .Append(FormatForCsv(con.VNCEncoding)) + .Append(FormatForCsv(con.VNCAuthMode)) + .Append(FormatForCsv(con.VNCProxyType)) + .Append(FormatForCsv(con.VNCProxyIP)) + .Append(FormatForCsv(con.VNCProxyPort)) + .Append(FormatForCsv(con.VNCProxyUsername)) + .Append(FormatForCsv(con.VNCProxyPassword)) + .Append(FormatForCsv(con.VNCColors)) + .Append(FormatForCsv(con.VNCSmartSizeMode)) + .Append(FormatForCsv(con.VNCViewOnly)) + .Append(FormatForCsv(con.RDGatewayUsageMethod)) + .Append(FormatForCsv(con.RDGatewayHostname)) + .Append(FormatForCsv(con.RDGatewayUseConnectionCredentials)) + .Append(FormatForCsv(con.RDGatewayUsername)) + .Append(FormatForCsv(con.RDGatewayPassword)) + .Append(FormatForCsv(con.RDGatewayDomain)); if (!_saveFilter.SaveInheritance) return; sb.Append(FormatForCsv(con.Inheritance.CacheBitmaps)) - .Append(FormatForCsv(con.Inheritance.Colors)) - .Append(FormatForCsv(con.Inheritance.Description)) - .Append(FormatForCsv(con.Inheritance.DisplayThemes)) - .Append(FormatForCsv(con.Inheritance.DisplayWallpaper)) - .Append(FormatForCsv(con.Inheritance.EnableFontSmoothing)) - .Append(FormatForCsv(con.Inheritance.EnableDesktopComposition)) - .Append(FormatForCsv(con.Inheritance.Domain)) - .Append(FormatForCsv(con.Inheritance.Icon)) - .Append(FormatForCsv(con.Inheritance.Panel)) - .Append(FormatForCsv(con.Inheritance.Password)) - .Append(FormatForCsv(con.Inheritance.Port)) - .Append(FormatForCsv(con.Inheritance.Protocol)) - .Append(FormatForCsv(con.Inheritance.PuttySession)) - .Append(FormatForCsv(con.Inheritance.RedirectDiskDrives)) - .Append(FormatForCsv(con.Inheritance.RedirectKeys)) - .Append(FormatForCsv(con.Inheritance.RedirectPorts)) - .Append(FormatForCsv(con.Inheritance.RedirectPrinters)) - .Append(FormatForCsv(con.Inheritance.RedirectClipboard)) - .Append(FormatForCsv(con.Inheritance.RedirectSmartCards)) - .Append(FormatForCsv(con.Inheritance.RedirectSound)) - .Append(FormatForCsv(con.Inheritance.Resolution)) - .Append(FormatForCsv(con.Inheritance.AutomaticResize)) - .Append(FormatForCsv(con.Inheritance.UseConsoleSession)) - .Append(FormatForCsv(con.Inheritance.UseCredSsp)) - .Append(FormatForCsv(con.Inheritance.RenderingEngine)) - .Append(FormatForCsv(con.Inheritance.Username)) - .Append(FormatForCsv(con.Inheritance.ICAEncryptionStrength)) - .Append(FormatForCsv(con.Inheritance.RDPAuthenticationLevel)) - .Append(FormatForCsv(con.Inheritance.LoadBalanceInfo)) - .Append(FormatForCsv(con.Inheritance.PreExtApp)) - .Append(FormatForCsv(con.Inheritance.PostExtApp)) - .Append(FormatForCsv(con.Inheritance.MacAddress)) - .Append(FormatForCsv(con.Inheritance.UserField)) - .Append(FormatForCsv(con.Inheritance.ExtApp)) - .Append(FormatForCsv(con.Inheritance.VNCCompression)) - .Append(FormatForCsv(con.Inheritance.VNCEncoding)) - .Append(FormatForCsv(con.Inheritance.VNCAuthMode)) - .Append(FormatForCsv(con.Inheritance.VNCProxyType)) - .Append(FormatForCsv(con.Inheritance.VNCProxyIP)) - .Append(FormatForCsv(con.Inheritance.VNCProxyPort)) - .Append(FormatForCsv(con.Inheritance.VNCProxyUsername)) - .Append(FormatForCsv(con.Inheritance.VNCProxyPassword)) - .Append(FormatForCsv(con.Inheritance.VNCColors)) - .Append(FormatForCsv(con.Inheritance.VNCSmartSizeMode)) - .Append(FormatForCsv(con.Inheritance.VNCViewOnly)) - .Append(FormatForCsv(con.Inheritance.RDGatewayUsageMethod)) - .Append(FormatForCsv(con.Inheritance.RDGatewayHostname)) - .Append(FormatForCsv(con.Inheritance.RDGatewayUseConnectionCredentials)) - .Append(FormatForCsv(con.Inheritance.RDGatewayUsername)) - .Append(FormatForCsv(con.Inheritance.RDGatewayPassword)) - .Append(FormatForCsv(con.Inheritance.RDGatewayDomain)) - .Append(FormatForCsv(con.Inheritance.RDPAlertIdleTimeout)) - .Append(FormatForCsv(con.Inheritance.RDPMinutesToIdleTimeout)) - .Append(FormatForCsv(con.Inheritance.SoundQuality)); + .Append(FormatForCsv(con.Inheritance.Colors)) + .Append(FormatForCsv(con.Inheritance.Description)) + .Append(FormatForCsv(con.Inheritance.DisplayThemes)) + .Append(FormatForCsv(con.Inheritance.DisplayWallpaper)) + .Append(FormatForCsv(con.Inheritance.EnableFontSmoothing)) + .Append(FormatForCsv(con.Inheritance.EnableDesktopComposition)) + .Append(FormatForCsv(con.Inheritance.Domain)) + .Append(FormatForCsv(con.Inheritance.Icon)) + .Append(FormatForCsv(con.Inheritance.Panel)) + .Append(FormatForCsv(con.Inheritance.Password)) + .Append(FormatForCsv(con.Inheritance.Port)) + .Append(FormatForCsv(con.Inheritance.Protocol)) + .Append(FormatForCsv(con.Inheritance.PuttySession)) + .Append(FormatForCsv(con.Inheritance.RedirectDiskDrives)) + .Append(FormatForCsv(con.Inheritance.RedirectKeys)) + .Append(FormatForCsv(con.Inheritance.RedirectPorts)) + .Append(FormatForCsv(con.Inheritance.RedirectPrinters)) + .Append(FormatForCsv(con.Inheritance.RedirectClipboard)) + .Append(FormatForCsv(con.Inheritance.RedirectSmartCards)) + .Append(FormatForCsv(con.Inheritance.RedirectSound)) + .Append(FormatForCsv(con.Inheritance.Resolution)) + .Append(FormatForCsv(con.Inheritance.AutomaticResize)) + .Append(FormatForCsv(con.Inheritance.UseConsoleSession)) + .Append(FormatForCsv(con.Inheritance.UseCredSsp)) + .Append(FormatForCsv(con.Inheritance.RenderingEngine)) + .Append(FormatForCsv(con.Inheritance.Username)) + .Append(FormatForCsv(con.Inheritance.ICAEncryptionStrength)) + .Append(FormatForCsv(con.Inheritance.RDPAuthenticationLevel)) + .Append(FormatForCsv(con.Inheritance.LoadBalanceInfo)) + .Append(FormatForCsv(con.Inheritance.PreExtApp)) + .Append(FormatForCsv(con.Inheritance.PostExtApp)) + .Append(FormatForCsv(con.Inheritance.MacAddress)) + .Append(FormatForCsv(con.Inheritance.UserField)) + .Append(FormatForCsv(con.Inheritance.ExtApp)) + .Append(FormatForCsv(con.Inheritance.VNCCompression)) + .Append(FormatForCsv(con.Inheritance.VNCEncoding)) + .Append(FormatForCsv(con.Inheritance.VNCAuthMode)) + .Append(FormatForCsv(con.Inheritance.VNCProxyType)) + .Append(FormatForCsv(con.Inheritance.VNCProxyIP)) + .Append(FormatForCsv(con.Inheritance.VNCProxyPort)) + .Append(FormatForCsv(con.Inheritance.VNCProxyUsername)) + .Append(FormatForCsv(con.Inheritance.VNCProxyPassword)) + .Append(FormatForCsv(con.Inheritance.VNCColors)) + .Append(FormatForCsv(con.Inheritance.VNCSmartSizeMode)) + .Append(FormatForCsv(con.Inheritance.VNCViewOnly)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUsageMethod)) + .Append(FormatForCsv(con.Inheritance.RDGatewayHostname)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUseConnectionCredentials)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUsername)) + .Append(FormatForCsv(con.Inheritance.RDGatewayPassword)) + .Append(FormatForCsv(con.Inheritance.RDGatewayDomain)) + .Append(FormatForCsv(con.Inheritance.RDPAlertIdleTimeout)) + .Append(FormatForCsv(con.Inheritance.RDPMinutesToIdleTimeout)) + .Append(FormatForCsv(con.Inheritance.SoundQuality)); } private string FormatForCsv(object value) diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs index ad01d1a27..d4edaeba2 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs @@ -54,20 +54,21 @@ namespace mRemoteNG.Config.Serializers.MsSql break; } } + return nodeList; } private ConnectionInfo DeserializeConnectionInfo(DataRow row) { - var connectionId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); - var connectionInfo = new ConnectionInfo(connectionId); + var connectionId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); + var connectionInfo = new ConnectionInfo(connectionId); PopulateConnectionInfoFromDatarow(row, connectionInfo); return connectionInfo; } private ContainerInfo DeserializeContainerInfo(DataRow row) { - var containerId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); + var containerId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); var containerInfo = new ContainerInfo(containerId); PopulateConnectionInfoFromDatarow(row, containerInfo); return containerInfo; @@ -93,14 +94,22 @@ namespace mRemoteNG.Config.Serializers.MsSql connectionInfo.Port = (int)dataRow["Port"]; connectionInfo.UseConsoleSession = (bool)dataRow["ConnectToConsole"]; connectionInfo.UseCredSsp = (bool)dataRow["UseCredSsp"]; - connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), (string)dataRow["RenderingEngine"]); - connectionInfo.ICAEncryptionStrength = (IcaProtocol.EncryptionStrength)Enum.Parse(typeof(IcaProtocol.EncryptionStrength), (string)dataRow["ICAEncryptionStrength"]); - connectionInfo.RDPAuthenticationLevel = (RdpProtocol.AuthenticationLevel)Enum.Parse(typeof(RdpProtocol.AuthenticationLevel), (string)dataRow["RDPAuthenticationLevel"]); + connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), + (string)dataRow["RenderingEngine"]); + connectionInfo.ICAEncryptionStrength = + (IcaProtocol.EncryptionStrength)Enum.Parse(typeof(IcaProtocol.EncryptionStrength), + (string)dataRow["ICAEncryptionStrength"]); + connectionInfo.RDPAuthenticationLevel = + (RdpProtocol.AuthenticationLevel)Enum.Parse(typeof(RdpProtocol.AuthenticationLevel), + (string)dataRow["RDPAuthenticationLevel"]); connectionInfo.RDPMinutesToIdleTimeout = (int)dataRow["RDPMinutesToIdleTimeout"]; connectionInfo.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"]; connectionInfo.LoadBalanceInfo = (string)dataRow["LoadBalanceInfo"]; - connectionInfo.Colors = (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors) ,(string)dataRow["Colors"]); - connectionInfo.Resolution = (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), (string)dataRow["Resolution"]); + connectionInfo.Colors = + (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), (string)dataRow["Colors"]); + connectionInfo.Resolution = + (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), + (string)dataRow["Resolution"]); connectionInfo.AutomaticResize = (bool)dataRow["AutomaticResize"]; connectionInfo.DisplayWallpaper = (bool)dataRow["DisplayWallpaper"]; connectionInfo.DisplayThemes = (bool)dataRow["DisplayThemes"]; @@ -112,28 +121,44 @@ namespace mRemoteNG.Config.Serializers.MsSql connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"]; connectionInfo.RedirectClipboard = (bool)dataRow["RedirectClipboard"]; connectionInfo.RedirectSmartCards = (bool)dataRow["RedirectSmartCards"]; - connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]); - connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]); + connectionInfo.RedirectSound = + (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]); + connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), + (string)dataRow["SoundQuality"]); connectionInfo.RedirectKeys = (bool)dataRow["RedirectKeys"]; connectionInfo.PreExtApp = (string)dataRow["PreExtApp"]; connectionInfo.PostExtApp = (string)dataRow["PostExtApp"]; connectionInfo.MacAddress = (string)dataRow["MacAddress"]; connectionInfo.UserField = (string)dataRow["UserField"]; connectionInfo.ExtApp = (string)dataRow["ExtApp"]; - connectionInfo.VNCCompression = (ProtocolVNC.Compression)Enum.Parse(typeof(ProtocolVNC.Compression), (string)dataRow["VNCCompression"]); - connectionInfo.VNCEncoding = (ProtocolVNC.Encoding)Enum.Parse(typeof(ProtocolVNC.Encoding) ,(string)dataRow["VNCEncoding"]); - connectionInfo.VNCAuthMode = (ProtocolVNC.AuthMode)Enum.Parse(typeof(ProtocolVNC.AuthMode), (string)dataRow["VNCAuthMode"]); - connectionInfo.VNCProxyType = (ProtocolVNC.ProxyType)Enum.Parse(typeof(ProtocolVNC.ProxyType), (string)dataRow["VNCProxyType"]); + connectionInfo.VNCCompression = (ProtocolVNC.Compression)Enum.Parse(typeof(ProtocolVNC.Compression), + (string)dataRow["VNCCompression"]); + connectionInfo.VNCEncoding = + (ProtocolVNC.Encoding)Enum.Parse(typeof(ProtocolVNC.Encoding), (string)dataRow["VNCEncoding"]); + connectionInfo.VNCAuthMode = + (ProtocolVNC.AuthMode)Enum.Parse(typeof(ProtocolVNC.AuthMode), (string)dataRow["VNCAuthMode"]); + connectionInfo.VNCProxyType = + (ProtocolVNC.ProxyType)Enum.Parse(typeof(ProtocolVNC.ProxyType), (string)dataRow["VNCProxyType"]); connectionInfo.VNCProxyIP = (string)dataRow["VNCProxyIP"]; connectionInfo.VNCProxyPort = (int)dataRow["VNCProxyPort"]; connectionInfo.VNCProxyUsername = (string)dataRow["VNCProxyUsername"]; connectionInfo.VNCProxyPassword = DecryptValue((string)dataRow["VNCProxyPassword"]); - connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]); - connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), (string)dataRow["VNCSmartSizeMode"]); + connectionInfo.VNCColors = + (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]); + connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), + (string)dataRow + ["VNCSmartSizeMode"]); connectionInfo.VNCViewOnly = (bool)dataRow["VNCViewOnly"]; - connectionInfo.RDGatewayUsageMethod = (RdpProtocol.RDGatewayUsageMethod)Enum.Parse(typeof(RdpProtocol.RDGatewayUsageMethod), (string)dataRow["RDGatewayUsageMethod"]); + connectionInfo.RDGatewayUsageMethod = + (RdpProtocol.RDGatewayUsageMethod)Enum.Parse(typeof(RdpProtocol.RDGatewayUsageMethod), + (string)dataRow["RDGatewayUsageMethod"]); connectionInfo.RDGatewayHostname = (string)dataRow["RDGatewayHostname"]; - connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), (string)dataRow["RDGatewayUseConnectionCredentials"]); + connectionInfo.RDGatewayUseConnectionCredentials = + (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse( + typeof(RdpProtocol. + RDGatewayUseConnectionCredentials), + (string)dataRow + ["RDGatewayUseConnectionCredentials"]); connectionInfo.RDGatewayUsername = (string)dataRow["RDGatewayUsername"]; connectionInfo.RDGatewayPassword = DecryptValue((string)dataRow["RDGatewayPassword"]); connectionInfo.RDGatewayDomain = (string)dataRow["RDGatewayDomain"]; @@ -189,7 +214,8 @@ namespace mRemoteNG.Config.Serializers.MsSql connectionInfo.Inheritance.VNCViewOnly = (bool)dataRow["InheritVNCViewOnly"]; connectionInfo.Inheritance.RDGatewayUsageMethod = (bool)dataRow["InheritRDGatewayUsageMethod"]; connectionInfo.Inheritance.RDGatewayHostname = (bool)dataRow["InheritRDGatewayHostname"]; - connectionInfo.Inheritance.RDGatewayUseConnectionCredentials = (bool)dataRow["InheritRDGatewayUseConnectionCredentials"]; + connectionInfo.Inheritance.RDGatewayUseConnectionCredentials = + (bool)dataRow["InheritRDGatewayUseConnectionCredentials"]; connectionInfo.Inheritance.RDGatewayUsername = (bool)dataRow["InheritRDGatewayUsername"]; connectionInfo.Inheritance.RDGatewayPassword = (bool)dataRow["InheritRDGatewayPassword"]; connectionInfo.Inheritance.RDGatewayDomain = (bool)dataRow["InheritRDGatewayDomain"]; @@ -219,14 +245,16 @@ namespace mRemoteNG.Config.Serializers.MsSql foreach (DataRow row in dataTable.Rows) { - var id = (string) row["ConstantID"]; + var id = (string)row["ConstantID"]; var connectionInfo = connectionList.First(node => node.ConstantID == id); - var parentId = (string) row["ParentID"]; + var parentId = (string)row["ParentID"]; if (parentId == "0" || connectionList.All(node => node.ConstantID != parentId)) rootNode.AddChild(connectionInfo); else - (connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(connectionInfo); + (connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild( + connectionInfo); } + return connectionTreeModel; } } diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs index 91f8a8f35..944c3bd39 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs @@ -12,7 +12,7 @@ using System.Security; namespace mRemoteNG.Config.Serializers.MsSql { - public class DataTableSerializer : ISerializer + public class DataTableSerializer : ISerializer { private readonly ICryptographyProvider _cryptographyProvider; private readonly SecureString _encryptionKey; @@ -23,7 +23,9 @@ namespace mRemoteNG.Config.Serializers.MsSql public Version Version { get; } = new Version(2, 7); - public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey) + public DataTableSerializer(SaveFilter saveFilter, + ICryptographyProvider cryptographyProvider, + SecureString encryptionKey) { _saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter)); _cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider)); @@ -190,7 +192,7 @@ namespace mRemoteNG.Config.Serializers.MsSql private void SetPrimaryKey(DataTable dataTable) { - dataTable.PrimaryKey = new[] { dataTable.Columns["ConstantID"] }; + dataTable.PrimaryKey = new[] {dataTable.Columns["ConstantID"]}; } private void SerializeNodesRecursive(ConnectionInfo connectionInfo) @@ -214,14 +216,15 @@ namespace mRemoteNG.Config.Serializers.MsSql dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? ""; dataRow["PositionID"] = _currentNodeIndex; dataRow["LastChange"] = (SqlDateTime)DateTime.Now; - dataRow["Expanded"] = false; // TODO: this column can eventually be removed. we now save this property locally + dataRow["Expanded"] = + false; // TODO: this column can eventually be removed. we now save this property locally dataRow["Description"] = connectionInfo.Description; dataRow["Icon"] = connectionInfo.Icon; dataRow["Panel"] = connectionInfo.Panel; dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : ""; dataRow["DomainName"] = _saveFilter.SaveDomain ? connectionInfo.Domain : ""; - dataRow["Password"] = _saveFilter.SavePassword - ? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey) + dataRow["Password"] = _saveFilter.SavePassword + ? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey) : ""; dataRow["Hostname"] = connectionInfo.Hostname; dataRow["Protocol"] = connectionInfo.Protocol; @@ -251,7 +254,8 @@ namespace mRemoteNG.Config.Serializers.MsSql dataRow["RedirectSound"] = connectionInfo.RedirectSound; dataRow["SoundQuality"] = connectionInfo.SoundQuality; dataRow["RedirectKeys"] = connectionInfo.RedirectKeys; - dataRow["Connected"] = false; // TODO: this column can eventually be removed. we now save this property locally + dataRow["Connected"] = + false; // TODO: this column can eventually be removed. we now save this property locally dataRow["PreExtApp"] = connectionInfo.PreExtApp; dataRow["PostExtApp"] = connectionInfo.PostExtApp; dataRow["MacAddress"] = connectionInfo.MacAddress; @@ -264,14 +268,16 @@ namespace mRemoteNG.Config.Serializers.MsSql dataRow["VNCProxyIP"] = connectionInfo.VNCProxyIP; dataRow["VNCProxyPort"] = connectionInfo.VNCProxyPort; dataRow["VNCProxyUsername"] = connectionInfo.VNCProxyUsername; - dataRow["VNCProxyPassword"] = _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey); + dataRow["VNCProxyPassword"] = + _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey); dataRow["VNCColors"] = connectionInfo.VNCColors; dataRow["VNCSmartSizeMode"] = connectionInfo.VNCSmartSizeMode; dataRow["VNCViewOnly"] = connectionInfo.VNCViewOnly; dataRow["RDGatewayUsageMethod"] = connectionInfo.RDGatewayUsageMethod; dataRow["RDGatewayHostname"] = connectionInfo.RDGatewayHostname; dataRow["RDGatewayUseConnectionCredentials"] = connectionInfo.RDGatewayUseConnectionCredentials; - dataRow["RDGatewayUsername"] = _cryptographyProvider.Encrypt(connectionInfo.RDGatewayUsername, _encryptionKey); + dataRow["RDGatewayUsername"] = + _cryptographyProvider.Encrypt(connectionInfo.RDGatewayUsername, _encryptionKey); dataRow["RDGatewayPassword"] = connectionInfo.RDGatewayPassword; dataRow["RDGatewayDomain"] = connectionInfo.RDGatewayDomain; if (_saveFilter.SaveInheritance) @@ -327,7 +333,8 @@ namespace mRemoteNG.Config.Serializers.MsSql dataRow["InheritVNCViewOnly"] = connectionInfo.Inheritance.VNCViewOnly; dataRow["InheritRDGatewayUsageMethod"] = connectionInfo.Inheritance.RDGatewayUsageMethod; dataRow["InheritRDGatewayHostname"] = connectionInfo.Inheritance.RDGatewayHostname; - dataRow["InheritRDGatewayUseConnectionCredentials"] = connectionInfo.Inheritance.RDGatewayUseConnectionCredentials; + dataRow["InheritRDGatewayUseConnectionCredentials"] = + connectionInfo.Inheritance.RDGatewayUseConnectionCredentials; dataRow["InheritRDGatewayUsername"] = connectionInfo.Inheritance.RDGatewayUsername; dataRow["InheritRDGatewayPassword"] = connectionInfo.Inheritance.RDGatewayPassword; dataRow["InheritRDGatewayDomain"] = connectionInfo.Inheritance.RDGatewayDomain; @@ -390,6 +397,7 @@ namespace mRemoteNG.Config.Serializers.MsSql dataRow["InheritRDGatewayPassword"] = false; dataRow["InheritRDGatewayDomain"] = false; } + _dataTable.Rows.Add(dataRow); } } diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesModel.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesModel.cs index f8cdb35f4..696c60703 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesModel.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesModel.cs @@ -17,4 +17,4 @@ /// public bool Expanded { get; set; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesXmlSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesXmlSerializer.cs index da76a8dc6..3af6108d9 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesXmlSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/LocalConnectionPropertiesXmlSerializer.cs @@ -8,8 +8,8 @@ using System.Xml.Linq; namespace mRemoteNG.Config.Serializers.MsSql { - public class LocalConnectionPropertiesXmlSerializer : - ISerializer, string>, + public class LocalConnectionPropertiesXmlSerializer : + ISerializer, string>, IDeserializer> { public Version Version { get; } = new Version(1, 0); @@ -17,10 +17,10 @@ namespace mRemoteNG.Config.Serializers.MsSql public string Serialize(IEnumerable models) { var localConnections = models - .Select(m => new XElement("Node", - new XAttribute("ConnectionId", m.ConnectionId), - new XAttribute("Connected", m.Connected), - new XAttribute("Expanded", m.Expanded))); + .Select(m => new XElement("Node", + new XAttribute("ConnectionId", m.ConnectionId), + new XAttribute("Connected", m.Connected), + new XAttribute("Expanded", m.Expanded))); var root = new XElement("LocalConnections", localConnections); var xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), root); @@ -34,20 +34,21 @@ namespace mRemoteNG.Config.Serializers.MsSql var xdoc = XDocument.Parse(serializedData); return xdoc - .Descendants("Node") - .Where(e => e.Attribute("ConnectionId") != null) - .Select(e => new LocalConnectionPropertiesModel - { - ConnectionId = e.Attribute("ConnectionId")?.Value, - Connected = bool.Parse(e.Attribute("Connected")?.Value ?? "False"), - Expanded = bool.Parse(e.Attribute("Expanded")?.Value ?? "False") - }); + .Descendants("Node") + .Where(e => e.Attribute("ConnectionId") != null) + .Select(e => new LocalConnectionPropertiesModel + { + ConnectionId = e.Attribute("ConnectionId")?.Value, + Connected = bool.Parse(e.Attribute("Connected")?.Value ?? "False"), + Expanded = bool.Parse(e.Attribute("Expanded")?.Value ?? "False") + }); } private static string WriteXmlToString(XNode xmlDocument) { string xmlString; - var xmlWriterSettings = new XmlWriterSettings { Indent = true, IndentChars = " ", Encoding = Encoding.UTF8 }; + var xmlWriterSettings = new XmlWriterSettings + {Indent = true, IndentChars = " ", Encoding = Encoding.UTF8}; var memoryStream = new MemoryStream(); using (var xmlTextWriter = XmlWriter.Create(memoryStream, xmlWriterSettings)) { @@ -57,7 +58,8 @@ namespace mRemoteNG.Config.Serializers.MsSql memoryStream.Seek(0, SeekOrigin.Begin); xmlString = streamReader.ReadToEnd(); } + return xmlString; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlConnectionListMetaData.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlConnectionListMetaData.cs index 12e8ce86e..98d61ae42 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlConnectionListMetaData.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlConnectionListMetaData.cs @@ -10,4 +10,4 @@ namespace mRemoteNG.Config.Serializers.MsSql public bool Export { get; set; } public Version ConfVersion { get; set; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlDatabaseMetaDataRetriever.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlDatabaseMetaDataRetriever.cs index 8c97292d1..2bfa7ef66 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlDatabaseMetaDataRetriever.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/SqlDatabaseMetaDataRetriever.cs @@ -29,7 +29,8 @@ namespace mRemoteNG.Config.Serializers.MsSql Name = sqlDataReader["Name"] as string ?? "", Protected = sqlDataReader["Protected"] as string ?? "", Export = (bool)sqlDataReader["Export"], - ConfVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture)) + ConfVersion = + new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture)) }; } catch (Exception ex) @@ -42,6 +43,7 @@ namespace mRemoteNG.Config.Serializers.MsSql if (sqlDataReader != null && !sqlDataReader.IsClosed) sqlDataReader.Close(); } + return metaData; } } diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs index f935ae418..59a6fa72f 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs @@ -8,7 +8,7 @@ using System.Xml.Linq; namespace mRemoteNG.Config.Serializers.Xml { // ReSharper disable once InconsistentNaming - public class XmlConnectionNodeSerializer26 : ISerializer + public class XmlConnectionNodeSerializer26 : ISerializer { private readonly ICryptographyProvider _cryptographyProvider; private readonly SecureString _encryptionKey; @@ -16,7 +16,9 @@ namespace mRemoteNG.Config.Serializers.Xml public Version Version { get; } = new Version(2, 6); - public XmlConnectionNodeSerializer26(ICryptographyProvider cryptographyProvider, SecureString encryptionKey, SaveFilter saveFilter) + public XmlConnectionNodeSerializer26(ICryptographyProvider cryptographyProvider, + SecureString encryptionKey, + SaveFilter saveFilter) { if (cryptographyProvider == null) throw new ArgumentNullException(nameof(cryptographyProvider)); @@ -51,15 +53,16 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("Id", connectionInfo.ConstantID)); element.Add(_saveFilter.SaveUsername - ? new XAttribute("Username", connectionInfo.Username) - : new XAttribute("Username", "")); + ? new XAttribute("Username", connectionInfo.Username) + : new XAttribute("Username", "")); element.Add(_saveFilter.SaveDomain - ? new XAttribute("Domain", connectionInfo.Domain) - : new XAttribute("Domain", "")); + ? new XAttribute("Domain", connectionInfo.Domain) + : new XAttribute("Domain", "")); if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password) - element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); + element.Add(new XAttribute("Password", + _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); else element.Add(new XAttribute("Password", "")); @@ -67,31 +70,42 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("Protocol", connectionInfo.Protocol)); element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession)); element.Add(new XAttribute("Port", connectionInfo.Port)); - element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("ConnectToConsole", + connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant())); element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine)); element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength)); element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel)); element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout)); - element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RDPAlertIdleTimeout", + connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); element.Add(new XAttribute("Colors", connectionInfo.Colors)); element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); - element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); - element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("AutomaticResize", + connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayWallpaper", + connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant())); - element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); - element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableFontSmoothing", + connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableDesktopComposition", + connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectDiskDrives", + connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectClipboard", connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPrinters", + connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectClipboard", + connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSmartCards", + connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString())); element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString())); element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant())); - element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); + element.Add(new XAttribute("Connected", + (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp)); element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp)); element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress)); @@ -105,93 +119,163 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("VNCProxyPort", connectionInfo.VNCProxyPort)); element.Add(_saveFilter.SaveUsername - ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) - : new XAttribute("VNCProxyUsername", "")); + ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) + : new XAttribute("VNCProxyUsername", "")); element.Add(_saveFilter.SavePassword - ? new XAttribute("VNCProxyPassword", - _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) - : new XAttribute("VNCProxyPassword", "")); + ? new XAttribute("VNCProxyPassword", + _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, + _encryptionKey)) + : new XAttribute("VNCProxyPassword", "")); element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors)); element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode)); element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant())); element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod)); element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname)); - element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials)); + element.Add(new XAttribute("RDGatewayUseConnectionCredentials", + connectionInfo.RDGatewayUseConnectionCredentials)); element.Add(_saveFilter.SaveUsername - ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) - : new XAttribute("RDGatewayUsername", "")); + ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) + : new XAttribute("RDGatewayUsername", "")); element.Add(_saveFilter.SavePassword - ? new XAttribute("RDGatewayPassword", - _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey)) - : new XAttribute("RDGatewayPassword", "")); + ? new XAttribute("RDGatewayPassword", + _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, + _encryptionKey)) + : new XAttribute("RDGatewayPassword", "")); element.Add(_saveFilter.SaveDomain - ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) - : new XAttribute("RDGatewayDomain", "")); + ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) + : new XAttribute("RDGatewayDomain", "")); } private void SetInheritanceAttributes(XContainer element, IInheritable connectionInfo) { if (_saveFilter.SaveInheritance) { - element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritCacheBitmaps", + connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritColors", + connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDescription", + connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayThemes", + connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayWallpaper", + connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableFontSmoothing", + connectionInfo + .Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableDesktopComposition", + connectionInfo + .Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDomain", + connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); + element.Add( + new XAttribute("InheritIcon", + connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPanel", + connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPassword", + connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); + element.Add( + new XAttribute("InheritPort", + connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritProtocol", + connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPuttySession", + connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectDiskDrives", + connectionInfo + .Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectKeys", + connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPorts", + connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPrinters", + connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSmartCards", + connectionInfo + .Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSound", + connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritSoundQuality", + connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritResolution", + connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritAutomaticResize", + connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseConsoleSession", + connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseCredSsp", + connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRenderingEngine", + connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUsername", + connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritICAEncryptionStrength", + connectionInfo + .Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", + connectionInfo + .Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", + connectionInfo + .Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", + connectionInfo + .Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritLoadBalanceInfo", + connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPreExtApp", + connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPostExtApp", + connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritMacAddress", + connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUserField", + connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritExtApp", + connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCCompression", + connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCEncoding", + connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCAuthMode", + connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyType", + connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyIP", + connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPort", + connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyUsername", + connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPassword", + connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCColors", + connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCSmartSizeMode", + connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCViewOnly", + connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", + connectionInfo + .Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayHostname", + connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", + connectionInfo + .Inheritance.RDGatewayUseConnectionCredentials.ToString() + .ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsername", + connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayPassword", + connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayDomain", + connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); } else { @@ -213,7 +297,7 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("InheritRedirectDiskDrives", falseString)); element.Add(new XAttribute("InheritRedirectKeys", falseString)); element.Add(new XAttribute("InheritRedirectPorts", falseString)); - element.Add(new XAttribute("InheritRedirectPrinters", falseString)); + element.Add(new XAttribute("InheritRedirectPrinters", falseString)); element.Add(new XAttribute("InheritRedirectSmartCards", falseString)); element.Add(new XAttribute("InheritRedirectSound", falseString)); element.Add(new XAttribute("InheritSoundQuality", falseString)); diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs index 1dac76ea0..3eb4086df 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs @@ -9,7 +9,7 @@ using System.Xml.Linq; namespace mRemoteNG.Config.Serializers.Xml { // ReSharper disable once InconsistentNaming - public class XmlConnectionNodeSerializer27 : ISerializer + public class XmlConnectionNodeSerializer27 : ISerializer { private readonly ICryptographyProvider _cryptographyProvider; private readonly SecureString _encryptionKey; @@ -17,7 +17,9 @@ namespace mRemoteNG.Config.Serializers.Xml public Version Version { get; } = new Version(2, 7); - public XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider, SecureString encryptionKey, SaveFilter saveFilter) + public XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider, + SecureString encryptionKey, + SaveFilter saveFilter) { if (cryptographyProvider == null) throw new ArgumentNullException(nameof(cryptographyProvider)); @@ -54,15 +56,16 @@ namespace mRemoteNG.Config.Serializers.Xml if (!Runtime.UseCredentialManager) { element.Add(_saveFilter.SaveUsername - ? new XAttribute("Username", connectionInfo.Username) - : new XAttribute("Username", "")); + ? new XAttribute("Username", connectionInfo.Username) + : new XAttribute("Username", "")); element.Add(_saveFilter.SaveDomain - ? new XAttribute("Domain", connectionInfo.Domain) - : new XAttribute("Domain", "")); + ? new XAttribute("Domain", connectionInfo.Domain) + : new XAttribute("Domain", "")); if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password) - element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); + element.Add(new XAttribute("Password", + _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); else element.Add(new XAttribute("Password", "")); } @@ -71,31 +74,42 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("Protocol", connectionInfo.Protocol)); element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession)); element.Add(new XAttribute("Port", connectionInfo.Port)); - element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("ConnectToConsole", + connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant())); element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine)); element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength)); element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel)); element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout)); - element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RDPAlertIdleTimeout", + connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); element.Add(new XAttribute("Colors", connectionInfo.Colors)); element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); - element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); - element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("AutomaticResize", + connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayWallpaper", + connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant())); - element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); - element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableFontSmoothing", + connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableDesktopComposition", + connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectDiskDrives", + connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectClipboard", connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); - element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPrinters", + connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectClipboard", + connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSmartCards", + connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString())); element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString())); element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant())); - element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); + element.Add(new XAttribute("Connected", + (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp)); element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp)); element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress)); @@ -109,94 +123,165 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("VNCProxyPort", connectionInfo.VNCProxyPort)); element.Add(_saveFilter.SaveUsername - ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) - : new XAttribute("VNCProxyUsername", "")); + ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) + : new XAttribute("VNCProxyUsername", "")); element.Add(_saveFilter.SavePassword - ? new XAttribute("VNCProxyPassword", - _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) - : new XAttribute("VNCProxyPassword", "")); + ? new XAttribute("VNCProxyPassword", + _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, + _encryptionKey)) + : new XAttribute("VNCProxyPassword", "")); element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors)); element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode)); element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant())); element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod)); element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname)); - element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials)); + element.Add(new XAttribute("RDGatewayUseConnectionCredentials", + connectionInfo.RDGatewayUseConnectionCredentials)); element.Add(_saveFilter.SaveUsername - ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) - : new XAttribute("RDGatewayUsername", "")); + ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) + : new XAttribute("RDGatewayUsername", "")); element.Add(_saveFilter.SavePassword - ? new XAttribute("RDGatewayPassword", - _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey)) - : new XAttribute("RDGatewayPassword", "")); + ? new XAttribute("RDGatewayPassword", + _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, + _encryptionKey)) + : new XAttribute("RDGatewayPassword", "")); element.Add(_saveFilter.SaveDomain - ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) - : new XAttribute("RDGatewayDomain", "")); + ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) + : new XAttribute("RDGatewayDomain", "")); } private void SetInheritanceAttributes(XContainer element, IInheritable connectionInfo) { if (_saveFilter.SaveInheritance) { - element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectClipboard", connectionInfo.Inheritance.RedirectClipboard.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); - element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritCacheBitmaps", + connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritColors", + connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDescription", + connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayThemes", + connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayWallpaper", + connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableFontSmoothing", + connectionInfo + .Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableDesktopComposition", + connectionInfo + .Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDomain", + connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); + element.Add( + new XAttribute("InheritIcon", + connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPanel", + connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPassword", + connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); + element.Add( + new XAttribute("InheritPort", + connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritProtocol", + connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPuttySession", + connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectDiskDrives", + connectionInfo + .Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectKeys", + connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPorts", + connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPrinters", + connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectClipboard", + connectionInfo.Inheritance.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSmartCards", + connectionInfo + .Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSound", + connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritSoundQuality", + connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritResolution", + connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritAutomaticResize", + connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseConsoleSession", + connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseCredSsp", + connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRenderingEngine", + connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUsername", + connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritICAEncryptionStrength", + connectionInfo + .Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", + connectionInfo + .Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", + connectionInfo + .Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", + connectionInfo + .Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritLoadBalanceInfo", + connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPreExtApp", + connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPostExtApp", + connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritMacAddress", + connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUserField", + connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritExtApp", + connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCCompression", + connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCEncoding", + connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCAuthMode", + connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyType", + connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyIP", + connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPort", + connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyUsername", + connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPassword", + connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCColors", + connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCSmartSizeMode", + connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCViewOnly", + connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", + connectionInfo + .Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayHostname", + connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", + connectionInfo + .Inheritance.RDGatewayUseConnectionCredentials.ToString() + .ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsername", + connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayPassword", + connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayDomain", + connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); } else { @@ -218,8 +303,8 @@ namespace mRemoteNG.Config.Serializers.Xml element.Add(new XAttribute("InheritRedirectDiskDrives", falseString)); element.Add(new XAttribute("InheritRedirectKeys", falseString)); element.Add(new XAttribute("InheritRedirectPorts", falseString)); - element.Add(new XAttribute("InheritRedirectPrinters", falseString)); - element.Add(new XAttribute("InheritRedirectClipboard", falseString)); + element.Add(new XAttribute("InheritRedirectPrinters", falseString)); + element.Add(new XAttribute("InheritRedirectClipboard", falseString)); element.Add(new XAttribute("InheritRedirectSmartCards", falseString)); element.Add(new XAttribute("InheritRedirectSound", falseString)); element.Add(new XAttribute("InheritSoundQuality", falseString)); diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs index 2ddf4532d..916f1e4c0 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs @@ -56,11 +56,12 @@ namespace mRemoteNG.Config.Serializers.Xml var connectionTreeModel = new ConnectionTreeModel(); connectionTreeModel.AddRootNode(_rootNodeInfo); - + if (_confVersion > 1.3) { var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value; - if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString())) + if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, + _rootNodeInfo.PasswordString.ConvertToSecureString())) { return null; } @@ -103,7 +104,9 @@ namespace mRemoteNG.Config.Serializers.Xml private void ValidateConnectionFileVersion() { if (_xmlDocument.DocumentElement != null && _xmlDocument.DocumentElement.HasAttribute("ConfVersion")) - _confVersion = Convert.ToDouble(_xmlDocument.DocumentElement.Attributes["ConfVersion"].Value.Replace(",", "."), CultureInfo.InvariantCulture); + _confVersion = + Convert.ToDouble(_xmlDocument.DocumentElement.Attributes["ConfVersion"].Value.Replace(",", "."), + CultureInfo.InvariantCulture); else Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, Language.strOldConffile); @@ -115,19 +118,22 @@ namespace mRemoteNG.Config.Serializers.Xml private void ShowIncompatibleVersionDialogBox() { CTaskDialog.ShowTaskDialogBox( - FrmMain.Default, - Application.ProductName, - "Incompatible connection file format", - $"The format of this connection file is not supported. Please upgrade to a newer version of {Application.ProductName}.", - string.Format("{1}{0}File Format Version: {2}{0}Highest Supported Version: {3}", Environment.NewLine, ConnectionFileName, _confVersion, MaxSupportedConfVersion), - "", - "", - "", - "", - ETaskDialogButtons.Ok, - ESysIcons.Error, - ESysIcons.Error - ); + FrmMain.Default, + Application.ProductName, + "Incompatible connection file format", + $"The format of this connection file is not supported. Please upgrade to a newer version of {Application.ProductName}.", + string + .Format("{1}{0}File Format Version: {2}{0}Highest Supported Version: {3}", + Environment.NewLine, + ConnectionFileName, _confVersion, MaxSupportedConfVersion), + "", + "", + "", + "", + ETaskDialogButtons.Ok, + ESysIcons.Error, + ESysIcons.Error + ); } private void InitializeRootNode(XmlElement connectionsRootElement) @@ -152,7 +158,8 @@ namespace mRemoteNG.Config.Serializers.Xml } else { - _decryptor = new XmlConnectionsDecryptor(_rootNodeInfo) { AuthenticationRequestor = AuthenticationRequestor }; + _decryptor = new XmlConnectionsDecryptor(_rootNodeInfo) + {AuthenticationRequestor = AuthenticationRequestor}; } } @@ -174,7 +181,7 @@ namespace mRemoteNG.Config.Serializers.Xml break; case TreeNodeType.Container: var containerInfo = new ContainerInfo(); - + if (_confVersion >= 0.9) containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode)); if (_confVersion >= 0.8) @@ -200,10 +207,10 @@ namespace mRemoteNG.Config.Serializers.Xml if (xmlnode?.Attributes == null) return null; - var connectionId = xmlnode.GetAttributeAsString("Id"); + var connectionId = xmlnode.GetAttributeAsString("Id"); if (string.IsNullOrWhiteSpace(connectionId)) connectionId = Guid.NewGuid().ToString(); - var connectionInfo = new ConnectionInfo(connectionId); + var connectionInfo = new ConnectionInfo(connectionId); try { @@ -258,7 +265,7 @@ namespace mRemoteNG.Config.Serializers.Xml { if (_confVersion < 0.7) { - connectionInfo.Port = xmlnode.GetAttributeAsBool("UseVNC") + connectionInfo.Port = xmlnode.GetAttributeAsBool("UseVNC") ? xmlnode.GetAttributeAsInt("VNCPort") : xmlnode.GetAttributeAsInt("RDPPort"); } @@ -274,6 +281,7 @@ namespace mRemoteNG.Config.Serializers.Xml else connectionInfo.Port = (int)RdpProtocol.Defaults.Port; } + connectionInfo.UseConsoleSession = false; } @@ -287,7 +295,7 @@ namespace mRemoteNG.Config.Serializers.Xml else { connectionInfo.RedirectDiskDrives = false; - connectionInfo.RedirectPrinters = false; + connectionInfo.RedirectPrinters = false; connectionInfo.RedirectPorts = false; connectionInfo.RedirectSmartCards = false; } @@ -352,14 +360,17 @@ namespace mRemoteNG.Config.Serializers.Xml connectionInfo.Inheritance.Port = xmlnode.GetAttributeAsBool("InheritPort"); connectionInfo.Inheritance.Protocol = xmlnode.GetAttributeAsBool("InheritProtocol"); connectionInfo.Inheritance.PuttySession = xmlnode.GetAttributeAsBool("InheritPuttySession"); - connectionInfo.Inheritance.RedirectDiskDrives = xmlnode.GetAttributeAsBool("InheritRedirectDiskDrives"); + connectionInfo.Inheritance.RedirectDiskDrives = + xmlnode.GetAttributeAsBool("InheritRedirectDiskDrives"); connectionInfo.Inheritance.RedirectKeys = xmlnode.GetAttributeAsBool("InheritRedirectKeys"); connectionInfo.Inheritance.RedirectPorts = xmlnode.GetAttributeAsBool("InheritRedirectPorts"); connectionInfo.Inheritance.RedirectPrinters = xmlnode.GetAttributeAsBool("InheritRedirectPrinters"); - connectionInfo.Inheritance.RedirectSmartCards = xmlnode.GetAttributeAsBool("InheritRedirectSmartCards"); + connectionInfo.Inheritance.RedirectSmartCards = + xmlnode.GetAttributeAsBool("InheritRedirectSmartCards"); connectionInfo.Inheritance.RedirectSound = xmlnode.GetAttributeAsBool("InheritRedirectSound"); connectionInfo.Inheritance.Resolution = xmlnode.GetAttributeAsBool("InheritResolution"); - connectionInfo.Inheritance.UseConsoleSession = xmlnode.GetAttributeAsBool("InheritUseConsoleSession"); + connectionInfo.Inheritance.UseConsoleSession = + xmlnode.GetAttributeAsBool("InheritUseConsoleSession"); if (!Runtime.UseCredentialManager || _confVersion <= 2.6) // 1.3 - 2.6 { @@ -367,6 +378,7 @@ namespace mRemoteNG.Config.Serializers.Xml connectionInfo.Inheritance.Password = xmlnode.GetAttributeAsBool("InheritPassword"); connectionInfo.Inheritance.Username = xmlnode.GetAttributeAsBool("InheritUsername"); } + connectionInfo.Icon = xmlnode.GetAttributeAsString("Icon"); connectionInfo.Panel = xmlnode.GetAttributeAsString("Panel"); } @@ -385,8 +397,10 @@ namespace mRemoteNG.Config.Serializers.Xml if (_confVersion >= 1.6) { - connectionInfo.ICAEncryptionStrength = xmlnode.GetAttributeAsEnum("ICAEncryptionStrength"); - connectionInfo.Inheritance.ICAEncryptionStrength = xmlnode.GetAttributeAsBool("InheritICAEncryptionStrength"); + connectionInfo.ICAEncryptionStrength = + xmlnode.GetAttributeAsEnum("ICAEncryptionStrength"); + connectionInfo.Inheritance.ICAEncryptionStrength = + xmlnode.GetAttributeAsBool("InheritICAEncryptionStrength"); connectionInfo.PreExtApp = xmlnode.GetAttributeAsString("PreExtApp"); connectionInfo.PostExtApp = xmlnode.GetAttributeAsString("PostExtApp"); connectionInfo.Inheritance.PreExtApp = xmlnode.GetAttributeAsBool("InheritPreExtApp"); @@ -395,16 +409,19 @@ namespace mRemoteNG.Config.Serializers.Xml if (_confVersion >= 1.7) { - connectionInfo.VNCCompression = xmlnode.GetAttributeAsEnum("VNCCompression"); + connectionInfo.VNCCompression = + xmlnode.GetAttributeAsEnum("VNCCompression"); connectionInfo.VNCEncoding = xmlnode.GetAttributeAsEnum("VNCEncoding"); connectionInfo.VNCAuthMode = xmlnode.GetAttributeAsEnum("VNCAuthMode"); connectionInfo.VNCProxyType = xmlnode.GetAttributeAsEnum("VNCProxyType"); connectionInfo.VNCProxyIP = xmlnode.GetAttributeAsString("VNCProxyIP"); connectionInfo.VNCProxyPort = xmlnode.GetAttributeAsInt("VNCProxyPort"); connectionInfo.VNCProxyUsername = xmlnode.GetAttributeAsString("VNCProxyUsername"); - connectionInfo.VNCProxyPassword = _decryptor.Decrypt(xmlnode.GetAttributeAsString("VNCProxyPassword")); + connectionInfo.VNCProxyPassword = + _decryptor.Decrypt(xmlnode.GetAttributeAsString("VNCProxyPassword")); connectionInfo.VNCColors = xmlnode.GetAttributeAsEnum("VNCColors"); - connectionInfo.VNCSmartSizeMode = xmlnode.GetAttributeAsEnum("VNCSmartSizeMode"); + connectionInfo.VNCSmartSizeMode = + xmlnode.GetAttributeAsEnum("VNCSmartSizeMode"); connectionInfo.VNCViewOnly = xmlnode.GetAttributeAsBool("VNCViewOnly"); connectionInfo.Inheritance.VNCCompression = xmlnode.GetAttributeAsBool("InheritVNCCompression"); connectionInfo.Inheritance.VNCEncoding = xmlnode.GetAttributeAsBool("InheritVNCEncoding"); @@ -421,13 +438,16 @@ namespace mRemoteNG.Config.Serializers.Xml if (_confVersion >= 1.8) { - connectionInfo.RDPAuthenticationLevel = xmlnode.GetAttributeAsEnum("RDPAuthenticationLevel"); - connectionInfo.Inheritance.RDPAuthenticationLevel = xmlnode.GetAttributeAsBool("InheritRDPAuthenticationLevel"); + connectionInfo.RDPAuthenticationLevel = + xmlnode.GetAttributeAsEnum("RDPAuthenticationLevel"); + connectionInfo.Inheritance.RDPAuthenticationLevel = + xmlnode.GetAttributeAsBool("InheritRDPAuthenticationLevel"); } if (_confVersion >= 1.9) { - connectionInfo.RenderingEngine = xmlnode.GetAttributeAsEnum("RenderingEngine"); + connectionInfo.RenderingEngine = + xmlnode.GetAttributeAsEnum("RenderingEngine"); connectionInfo.MacAddress = xmlnode.GetAttributeAsString("MacAddress"); connectionInfo.Inheritance.RenderingEngine = xmlnode.GetAttributeAsBool("InheritRenderingEngine"); connectionInfo.Inheritance.MacAddress = xmlnode.GetAttributeAsBool("InheritMacAddress"); @@ -448,19 +468,28 @@ namespace mRemoteNG.Config.Serializers.Xml if (_confVersion >= 2.2) { // Get settings - connectionInfo.RDGatewayUsageMethod = xmlnode.GetAttributeAsEnum("RDGatewayUsageMethod"); + connectionInfo.RDGatewayUsageMethod = + xmlnode.GetAttributeAsEnum("RDGatewayUsageMethod"); connectionInfo.RDGatewayHostname = xmlnode.GetAttributeAsString("RDGatewayHostname"); - connectionInfo.RDGatewayUseConnectionCredentials = xmlnode.GetAttributeAsEnum("RDGatewayUseConnectionCredentials"); + connectionInfo.RDGatewayUseConnectionCredentials = + xmlnode.GetAttributeAsEnum( + "RDGatewayUseConnectionCredentials"); connectionInfo.RDGatewayUsername = xmlnode.GetAttributeAsString("RDGatewayUsername"); - connectionInfo.RDGatewayPassword = _decryptor.Decrypt(xmlnode.GetAttributeAsString("RDGatewayPassword")); + connectionInfo.RDGatewayPassword = + _decryptor.Decrypt(xmlnode.GetAttributeAsString("RDGatewayPassword")); connectionInfo.RDGatewayDomain = xmlnode.GetAttributeAsString("RDGatewayDomain"); // Get inheritance settings - connectionInfo.Inheritance.RDGatewayUsageMethod = xmlnode.GetAttributeAsBool("InheritRDGatewayUsageMethod"); - connectionInfo.Inheritance.RDGatewayHostname = xmlnode.GetAttributeAsBool("InheritRDGatewayHostname"); - connectionInfo.Inheritance.RDGatewayUseConnectionCredentials = xmlnode.GetAttributeAsBool("InheritRDGatewayUseConnectionCredentials"); - connectionInfo.Inheritance.RDGatewayUsername = xmlnode.GetAttributeAsBool("InheritRDGatewayUsername"); - connectionInfo.Inheritance.RDGatewayPassword = xmlnode.GetAttributeAsBool("InheritRDGatewayPassword"); + connectionInfo.Inheritance.RDGatewayUsageMethod = + xmlnode.GetAttributeAsBool("InheritRDGatewayUsageMethod"); + connectionInfo.Inheritance.RDGatewayHostname = + xmlnode.GetAttributeAsBool("InheritRDGatewayHostname"); + connectionInfo.Inheritance.RDGatewayUseConnectionCredentials = + xmlnode.GetAttributeAsBool("InheritRDGatewayUseConnectionCredentials"); + connectionInfo.Inheritance.RDGatewayUsername = + xmlnode.GetAttributeAsBool("InheritRDGatewayUsername"); + connectionInfo.Inheritance.RDGatewayPassword = + xmlnode.GetAttributeAsBool("InheritRDGatewayPassword"); connectionInfo.Inheritance.RDGatewayDomain = xmlnode.GetAttributeAsBool("InheritRDGatewayDomain"); } @@ -471,8 +500,10 @@ namespace mRemoteNG.Config.Serializers.Xml connectionInfo.EnableDesktopComposition = xmlnode.GetAttributeAsBool("EnableDesktopComposition"); // Get inheritance settings - connectionInfo.Inheritance.EnableFontSmoothing = xmlnode.GetAttributeAsBool("InheritEnableFontSmoothing"); - connectionInfo.Inheritance.EnableDesktopComposition = xmlnode.GetAttributeAsBool("InheritEnableDesktopComposition"); + connectionInfo.Inheritance.EnableFontSmoothing = + xmlnode.GetAttributeAsBool("InheritEnableFontSmoothing"); + connectionInfo.Inheritance.EnableDesktopComposition = + xmlnode.GetAttributeAsBool("InheritEnableDesktopComposition"); } if (_confVersion >= 2.4) @@ -491,22 +522,30 @@ namespace mRemoteNG.Config.Serializers.Xml if (_confVersion >= 2.6) { - connectionInfo.SoundQuality = xmlnode.GetAttributeAsEnum("SoundQuality"); + connectionInfo.SoundQuality = + xmlnode.GetAttributeAsEnum("SoundQuality"); connectionInfo.Inheritance.SoundQuality = xmlnode.GetAttributeAsBool("InheritSoundQuality"); connectionInfo.RDPMinutesToIdleTimeout = xmlnode.GetAttributeAsInt("RDPMinutesToIdleTimeout"); - connectionInfo.Inheritance.RDPMinutesToIdleTimeout = xmlnode.GetAttributeAsBool("InheritRDPMinutesToIdleTimeout"); + connectionInfo.Inheritance.RDPMinutesToIdleTimeout = + xmlnode.GetAttributeAsBool("InheritRDPMinutesToIdleTimeout"); connectionInfo.RDPAlertIdleTimeout = xmlnode.GetAttributeAsBool("RDPAlertIdleTimeout"); - connectionInfo.Inheritance.RDPAlertIdleTimeout = xmlnode.GetAttributeAsBool("InheritRDPAlertIdleTimeout"); + connectionInfo.Inheritance.RDPAlertIdleTimeout = + xmlnode.GetAttributeAsBool("InheritRDPAlertIdleTimeout"); } - if(_confVersion >= 2.7) + + if (_confVersion >= 2.7) { connectionInfo.RedirectClipboard = xmlnode.GetAttributeAsBool("RedirectClipboard"); - connectionInfo.Inheritance.RedirectClipboard = xmlnode.GetAttributeAsBool("InheritRedirectClipboard"); + connectionInfo.Inheritance.RedirectClipboard = + xmlnode.GetAttributeAsBool("InheritRedirectClipboard"); } } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strGetConnectionInfoFromXmlFailed, connectionInfo.Name, ConnectionFileName, ex.Message)); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + string.Format(Language.strGetConnectionInfoFromXmlFailed, + connectionInfo.Name, ConnectionFileName, + ex.Message)); } return connectionInfo; diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs index 95c35d4b4..acdde98cb 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs @@ -16,7 +16,8 @@ namespace mRemoteNG.Config.Serializers.Xml private SecureString _encryptionKey; private readonly ISerializer _connectionNodeSerializer; - public XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider, ISerializer connectionNodeSerializer) + public XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider, + ISerializer connectionNodeSerializer) { if (cryptographyProvider == null) throw new ArgumentNullException(nameof(cryptographyProvider)); @@ -43,7 +44,9 @@ namespace mRemoteNG.Config.Serializers.Xml var xmlDeclaration = new XDeclaration("1.0", "utf-8", null); var xmlDocument = new XDocument(xmlDeclaration, rootElement); if (fullFileEncryption) - xmlDocument = new XmlConnectionsDocumentEncryptor(_cryptographyProvider).EncryptDocument(xmlDocument, _encryptionKey); + xmlDocument = + new XmlConnectionsDocumentEncryptor(_cryptographyProvider).EncryptDocument(xmlDocument, + _encryptionKey); return xmlDocument; } @@ -55,6 +58,7 @@ namespace mRemoteNG.Config.Serializers.Xml newElement = CompileConnectionInfoNode(serializationTarget); parentElement.Add(newElement); } + var serializationTargetAsContainer = serializationTarget as ContainerInfo; if (serializationTargetAsContainer == null) return; foreach (var child in serializationTargetAsContainer.Children) @@ -79,7 +83,8 @@ namespace mRemoteNG.Config.Serializers.Xml private XElement CompileRootNode(RootNodeInfo rootNodeInfo, bool fullFileEncryption) { var rootNodeSerializer = new XmlRootNodeSerializer(); - return rootNodeSerializer.SerializeRootNodeInfo(rootNodeInfo, _cryptographyProvider, _connectionNodeSerializer.Version, fullFileEncryption); + return rootNodeSerializer.SerializeRootNodeInfo(rootNodeInfo, _cryptographyProvider, + _connectionNodeSerializer.Version, fullFileEncryption); } private XElement CompileConnectionInfoNode(ConnectionInfo connectionInfo) diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs index d4e32d313..83255876b 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs @@ -12,7 +12,8 @@ using System.Xml.Linq; namespace mRemoteNG.Config.Serializers.Xml { - public class XmlConnectionsSerializer : ISerializer, ISerializer + public class XmlConnectionsSerializer : ISerializer, + ISerializer { private readonly ICryptographyProvider _cryptographyProvider; private readonly ISerializer _connectionNodeSerializer; @@ -20,7 +21,8 @@ namespace mRemoteNG.Config.Serializers.Xml public Version Version => _connectionNodeSerializer.Version; public bool UseFullEncryption { get; set; } - public XmlConnectionsSerializer(ICryptographyProvider cryptographyProvider, ISerializer connectionNodeSerializer) + public XmlConnectionsSerializer(ICryptographyProvider cryptographyProvider, + ISerializer connectionNodeSerializer) { _cryptographyProvider = cryptographyProvider; _connectionNodeSerializer = connectionNodeSerializer; @@ -42,7 +44,8 @@ namespace mRemoteNG.Config.Serializers.Xml var xml = ""; try { - var documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, _connectionNodeSerializer); + var documentCompiler = + new XmlConnectionsDocumentCompiler(_cryptographyProvider, _connectionNodeSerializer); var xmlDocument = documentCompiler.CompileDocument(serializationTarget, UseFullEncryption); xml = WriteXmlToString(xmlDocument); } @@ -50,13 +53,15 @@ namespace mRemoteNG.Config.Serializers.Xml { Runtime.MessageCollector.AddExceptionStackTrace("SaveToXml failed", ex); } + return xml; } private static string WriteXmlToString(XNode xmlDocument) { string xmlString; - var xmlWriterSettings = new XmlWriterSettings { Indent = true, IndentChars = " ", Encoding = Encoding.UTF8 }; + var xmlWriterSettings = new XmlWriterSettings + {Indent = true, IndentChars = " ", Encoding = Encoding.UTF8}; var memoryStream = new MemoryStream(); using (var xmlTextWriter = XmlWriter.Create(memoryStream, xmlWriterSettings)) { @@ -66,6 +71,7 @@ namespace mRemoteNG.Config.Serializers.Xml memoryStream.Seek(0, SeekOrigin.Begin); xmlString = streamReader.ReadToEnd(); } + return xmlString; } } diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlExtensions.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlExtensions.cs index 71ecbff73..06520b1cd 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlExtensions.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlExtensions.cs @@ -17,7 +17,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml if (string.IsNullOrWhiteSpace(value)) return defaultValue; - return bool.TryParse(value, out var valueAsBool) + return bool.TryParse(value, out var valueAsBool) ? valueAsBool : defaultValue; } @@ -28,8 +28,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml if (string.IsNullOrWhiteSpace(value)) return defaultValue; - return int.TryParse(value, out var valueAsBool) - ? valueAsBool + return int.TryParse(value, out var valueAsBool) + ? valueAsBool : defaultValue; } @@ -45,4 +45,4 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml : defaultValue; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs index 9a9f9af93..75a4391e8 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs @@ -7,27 +7,28 @@ namespace mRemoteNG.Config.Serializers.Xml { public class XmlRootNodeSerializer { - public XElement SerializeRootNodeInfo( - RootNodeInfo rootNodeInfo, - ICryptographyProvider cryptographyProvider, - Version version, - bool fullFileEncryption = false) + public XElement SerializeRootNodeInfo(RootNodeInfo rootNodeInfo, + ICryptographyProvider cryptographyProvider, + Version version, + bool fullFileEncryption = false) { XNamespace xmlNamespace = "http://mremoteng.org"; var element = new XElement(xmlNamespace + "Connections"); - element.Add(new XAttribute(XNamespace.Xmlns+"mrng", xmlNamespace)); + element.Add(new XAttribute(XNamespace.Xmlns + "mrng", xmlNamespace)); element.Add(new XAttribute(XName.Get("Name"), rootNodeInfo.Name)); - element.Add(new XAttribute(XName.Get("Export"), "false")); - element.Add(new XAttribute(XName.Get("EncryptionEngine"), cryptographyProvider.CipherEngine)); + element.Add(new XAttribute(XName.Get("Export"), "false")); + element.Add(new XAttribute(XName.Get("EncryptionEngine"), cryptographyProvider.CipherEngine)); element.Add(new XAttribute(XName.Get("BlockCipherMode"), cryptographyProvider.CipherMode)); element.Add(new XAttribute(XName.Get("KdfIterations"), cryptographyProvider.KeyDerivationIterations)); - element.Add(new XAttribute(XName.Get("FullFileEncryption"), fullFileEncryption.ToString().ToLowerInvariant())); + element.Add(new XAttribute(XName.Get("FullFileEncryption"), + fullFileEncryption.ToString().ToLowerInvariant())); element.Add(CreateProtectedAttribute(rootNodeInfo, cryptographyProvider)); element.Add(new XAttribute(XName.Get("ConfVersion"), version.ToString(2))); return element; } - private XAttribute CreateProtectedAttribute(RootNodeInfo rootNodeInfo, ICryptographyProvider cryptographyProvider) + private XAttribute CreateProtectedAttribute(RootNodeInfo rootNodeInfo, + ICryptographyProvider cryptographyProvider) { var attribute = new XAttribute(XName.Get("Protected"), ""); var plainText = rootNodeInfo.Password ? "ThisIsProtected" : "ThisIsNotProtected"; diff --git a/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListDeserializer.cs b/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListDeserializer.cs index 618fe206f..6795d695a 100644 --- a/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListDeserializer.cs +++ b/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListDeserializer.cs @@ -12,7 +12,9 @@ namespace mRemoteNG.Config.Serializers.CredentialProviderSerializer private readonly ISecureSerializer, string> _serializer; private readonly ISecureDeserializer> _deserializer; - public CredentialRepositoryListDeserializer(ISecureSerializer, string> serializer, ISecureDeserializer> deserializer) + public CredentialRepositoryListDeserializer( + ISecureSerializer, string> serializer, + ISecureDeserializer> deserializer) { if (serializer == null) throw new ArgumentNullException(nameof(serializer)); diff --git a/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListSerializer.cs b/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListSerializer.cs index 793652284..ea755999c 100644 --- a/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListSerializer.cs +++ b/mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListSerializer.cs @@ -13,14 +13,14 @@ namespace mRemoteNG.Config.Serializers.CredentialProviderSerializer { var xmlDocument = new XDocument(new XDeclaration("1.0", "utf-8", null)); var rootElement = new XElement("CredentialRepositories", - from provider in credentialProviderCatalog - select new XElement("CredentialRepository", - new XAttribute("Id", provider.Config.Id), - new XAttribute("TypeName", provider.Config.TypeName), - new XAttribute("Title", provider.Config.Title), - new XAttribute("Source", provider.Config.Source) - ) - ); + from provider in credentialProviderCatalog + select new XElement("CredentialRepository", + new XAttribute("Id", provider.Config.Id), + new XAttribute("TypeName", provider.Config.TypeName), + new XAttribute("Title", provider.Config.Title), + new XAttribute("Source", provider.Config.Source) + ) + ); xmlDocument.Add(rootElement); var declaration = xmlDocument.Declaration.ToString(); var documentBody = xmlDocument.ToString(); diff --git a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordDecryptorDecorator.cs b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordDecryptorDecorator.cs index 3e6d58546..a89ea7556 100644 --- a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordDecryptorDecorator.cs +++ b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordDecryptorDecorator.cs @@ -12,7 +12,8 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer { private readonly IDeserializer> _baseDeserializer; - public XmlCredentialPasswordDecryptorDecorator(IDeserializer> baseDeserializer) + public XmlCredentialPasswordDecryptorDecorator( + IDeserializer> baseDeserializer) { if (baseDeserializer == null) throw new ArgumentNullException(nameof(baseDeserializer)); @@ -39,10 +40,13 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer var decryptedPassword = cryptoProvider.Decrypt(passwordAttribute.Value, key); passwordAttribute.SetValue(decryptedPassword); } + return xdoc.ToString(); } - private void DecryptAuthHeader(XElement rootElement, ICryptographyProvider cryptographyProvider, SecureString key) + private void DecryptAuthHeader(XElement rootElement, + ICryptographyProvider cryptographyProvider, + SecureString key) { var authAttribute = rootElement.Attribute("Auth"); if (authAttribute == null) diff --git a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordEncryptorDecorator.cs b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordEncryptorDecorator.cs index 8fc38ed8a..6b3db03ce 100644 --- a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordEncryptorDecorator.cs +++ b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialPasswordEncryptorDecorator.cs @@ -12,7 +12,9 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer private readonly ISerializer, string> _baseSerializer; private readonly ICryptographyProvider _cryptographyProvider; - public XmlCredentialPasswordEncryptorDecorator(ICryptographyProvider cryptographyProvider, ISerializer, string> baseSerializer) + public XmlCredentialPasswordEncryptorDecorator(ICryptographyProvider cryptographyProvider, + ISerializer, string> + baseSerializer) { if (baseSerializer == null) throw new ArgumentNullException(nameof(baseSerializer)); @@ -45,6 +47,7 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer var encryptedPassword = _cryptographyProvider.Encrypt(passwordAttribute.Value, encryptionKey); passwordAttribute.Value = encryptedPassword; } + return xdoc.Declaration + Environment.NewLine + xdoc; } @@ -53,7 +56,9 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer xdoc.Root?.SetAttributeValue("EncryptionEngine", _cryptographyProvider.CipherEngine); xdoc.Root?.SetAttributeValue("BlockCipherMode", _cryptographyProvider.CipherMode); xdoc.Root?.SetAttributeValue("KdfIterations", _cryptographyProvider.KeyDerivationIterations); - xdoc.Root?.SetAttributeValue("Auth", _cryptographyProvider.Encrypt(RandomGenerator.RandomString(20), encryptionKey)); + xdoc.Root?.SetAttributeValue("Auth", + _cryptographyProvider.Encrypt(RandomGenerator.RandomString(20), + encryptionKey)); } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordDeserializer.cs b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordDeserializer.cs index 7a7fe0d9a..3f071a9db 100644 --- a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordDeserializer.cs +++ b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordDeserializer.cs @@ -19,13 +19,14 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer ValidateSchemaVersion(rootElement); var credentials = from element in xdoc.Descendants("Credential") - select new CredentialRecord(Guid.Parse(element.Attribute("Id")?.Value ?? Guid.NewGuid().ToString())) - { - Title = element.Attribute("Title")?.Value ?? "", - Username = element.Attribute("Username")?.Value ?? "", - Password = element.Attribute("Password")?.Value.ConvertToSecureString(), - Domain = element.Attribute("Domain")?.Value ?? "" - }; + select new CredentialRecord(Guid.Parse(element.Attribute("Id")?.Value ?? + Guid.NewGuid().ToString())) + { + Title = element.Attribute("Title")?.Value ?? "", + Username = element.Attribute("Username")?.Value ?? "", + Password = element.Attribute("Password")?.Value.ConvertToSecureString(), + Domain = element.Attribute("Domain")?.Value ?? "" + }; return credentials.ToArray(); } @@ -33,7 +34,8 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer { var docSchemaVersion = rootElement?.Attribute("SchemaVersion")?.Value; if (docSchemaVersion != SchemaVersion) - throw new Exception($"The schema version of this document is not supported by this class. Document Version: {docSchemaVersion} Supported Version: {SchemaVersion}"); + throw new Exception( + $"The schema version of this document is not supported by this class. Document Version: {docSchemaVersion} Supported Version: {SchemaVersion}"); } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordSerializer.cs b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordSerializer.cs index 01d2e0e1c..eb421b273 100644 --- a/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordSerializer.cs +++ b/mRemoteV1/Config/Serializers/CredentialSerializer/XmlCredentialRecordSerializer.cs @@ -14,18 +14,20 @@ namespace mRemoteNG.Config.Serializers.CredentialSerializer public string Serialize(IEnumerable credentialRecords) { var xdoc = new XDocument( - new XElement("Credentials", - new XAttribute("SchemaVersion", Version.ToString(2)), - from r in credentialRecords - select new XElement("Credential", - new XAttribute("Id", r.Id), - new XAttribute("Title", r.Title), - new XAttribute("Username", r.Username), - new XAttribute("Domain", r.Domain), - new XAttribute("Password", r.Password.ConvertToUnsecureString()) - ) - ) - ) + new XElement("Credentials", + new XAttribute("SchemaVersion", Version.ToString(2)), + from r in credentialRecords + select new XElement("Credential", + new XAttribute("Id", r.Id), + new XAttribute("Title", r.Title), + new XAttribute("Username", r.Username), + new XAttribute("Domain", r.Domain), + new XAttribute("Password", + r.Password + .ConvertToUnsecureString()) + ) + ) + ) { Declaration = new XDeclaration("1.0", "utf-8", null) }; diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs index d9789f0fa..a042aa21a 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs @@ -55,7 +55,7 @@ namespace mRemoteNG.Config.Serializers ldapSearcher.SearchRoot = new DirectoryEntry(ldapPath); ldapSearcher.Filter = ldapFilter; ldapSearcher.SearchScope = SearchScope.OneLevel; - ldapSearcher.PropertiesToLoad.AddRange(new[] { "securityEquals", "cn", "objectClass" }); + ldapSearcher.PropertiesToLoad.AddRange(new[] {"securityEquals", "cn", "objectClass"}); var ldapResults = ldapSearcher.FindAll(); foreach (SearchResult ldapResult in ldapResults) @@ -65,7 +65,7 @@ namespace mRemoteNG.Config.Serializers if (directoryEntry.Properties["objectClass"].Contains("organizationalUnit")) { // check/continue here so we don't create empty connection objects - if(!_importSubOu) continue; + if (!_importSubOu) continue; // TODO - this is a circular call. A deserializer should not call an importer ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOu); @@ -79,7 +79,8 @@ namespace mRemoteNG.Config.Serializers } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("Config.Import.ActiveDirectory.ImportComputers() failed.", ex); + Runtime.MessageCollector.AddExceptionMessage("Config.Import.ActiveDirectory.ImportComputers() failed.", + ex); } } diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/PuttyConnectionManagerDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/PuttyConnectionManagerDeserializer.cs index a434fa57a..039f9a095 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/PuttyConnectionManagerDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/PuttyConnectionManagerDeserializer.cs @@ -28,7 +28,7 @@ namespace mRemoteNG.Config.Serializers { ImportRootOrContainer(rootNode, root); } - + return connectionTreeModel; } @@ -66,16 +66,19 @@ namespace mRemoteNG.Config.Serializers { throw (new FileFormatException($"Unrecognized root node type ({xmlNodeType}).")); } + break; case "container": if (string.Compare(xmlNodeType, "folder", StringComparison.OrdinalIgnoreCase) != 0) { throw (new FileFormatException($"Unrecognized root node type ({xmlNodeType}).")); } + break; default: // ReSharper disable once LocalizableElement - throw (new ArgumentException("Argument must be either a root or a container node.", nameof(xmlNode))); + throw (new ArgumentException("Argument must be either a root or a container node.", + nameof(xmlNode))); } } diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs index d59bcbc3a..ae605f4c1 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs @@ -18,7 +18,7 @@ namespace mRemoteNG.Config.Serializers var connectionInfo = new ConnectionInfo(); foreach (var line in rdcFileContent.Split(Environment.NewLine.ToCharArray())) { - var parts = line.Split(new[] { ':' }, 3); + var parts = line.Split(new[] {':'}, 3); if (parts.Length < 3) { continue; @@ -29,6 +29,7 @@ namespace mRemoteNG.Config.Serializers SetConnectionInfoParameter(connectionInfo, key, value); } + root.AddChild(connectionInfo); return connectionTreeModel; @@ -74,12 +75,15 @@ namespace mRemoteNG.Config.Serializers connectionInfo.Colors = RdpProtocol.RDPColors.Colors32Bit; break; } + break; case "bitmapcachepersistenable": connectionInfo.CacheBitmaps = value == "1"; break; case "screen mode id": - connectionInfo.Resolution = value == "2" ? RdpProtocol.RDPResolutions.Fullscreen : RdpProtocol.RDPResolutions.FitToWindow; + connectionInfo.Resolution = value == "2" + ? RdpProtocol.RDPResolutions.Fullscreen + : RdpProtocol.RDPResolutions.FitToWindow; break; case "connect to console": connectionInfo.UseConsoleSession = value == "1"; @@ -124,6 +128,7 @@ namespace mRemoteNG.Config.Serializers connectionInfo.RedirectSound = RdpProtocol.RDPSounds.DoNotPlay; break; } + break; case "loadbalanceinfo": connectionInfo.LoadBalanceInfo = value; diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs index 27c2b0300..53c1bc371 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs @@ -104,6 +104,7 @@ namespace mRemoteNG.Config.Serializers // Program Version 2.2 wraps all setting inside the Properties tags containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties"); } + var newContainer = new ContainerInfo(); var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode); newContainer.CopyFrom(connectionInfo); @@ -113,8 +114,10 @@ namespace mRemoteNG.Config.Serializers // Program Version 2.7 wraps these properties containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties"); } + newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder; - newContainer.IsExpanded = bool.Parse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText ?? "false"); + newContainer.IsExpanded = + bool.Parse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText ?? "false"); parentContainer.AddChild(newContainer); return newContainer; } @@ -131,9 +134,11 @@ namespace mRemoteNG.Config.Serializers var propertiesNode = xmlNode.SelectSingleNode("./properties"); - if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead + if (_schemaVersion == 1) + propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead connectionInfo.Hostname = propertiesNode?.SelectSingleNode("./name")?.InnerText ?? ""; - connectionInfo.Name = propertiesNode?.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname; + connectionInfo.Name = + propertiesNode?.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname; connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty; var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials"); @@ -144,8 +149,8 @@ namespace mRemoteNG.Config.Serializers var passwordNode = logonCredentialsNode.SelectSingleNode("./password"); if (_schemaVersion == 1) // Version 2.2 allows clear text passwords { - connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True" - ? passwordNode.InnerText + connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True" + ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText); } else @@ -165,7 +170,8 @@ namespace mRemoteNG.Config.Serializers var connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings"); if (connectionSettingsNode?.Attributes?["inherit"]?.Value == "None") { - connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false"); + connectionInfo.UseConsoleSession = + bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false"); // ./startProgram // ./workingDir connectionInfo.Port = Convert.ToInt32(connectionSettingsNode.SelectSingleNode("./port")?.InnerText); @@ -179,12 +185,17 @@ namespace mRemoteNG.Config.Serializers var gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings"); if (gatewaySettingsNode?.Attributes?["inherit"]?.Value == "None") { - connectionInfo.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" ? RdpProtocol.RDGatewayUsageMethod.Always : RdpProtocol.RDGatewayUsageMethod.Never; + connectionInfo.RDGatewayUsageMethod = + gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" + ? RdpProtocol.RDGatewayUsageMethod.Always + : RdpProtocol.RDGatewayUsageMethod.Never; connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText; connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName")?.InnerText; var passwordNode = gatewaySettingsNode.SelectSingleNode("./password"); - connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True" ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText); + connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True" + ? passwordNode.InnerText + : DecryptRdcManPassword(passwordNode?.InnerText); connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain")?.InnerText; // ./logonMethod @@ -206,7 +217,9 @@ namespace mRemoteNG.Config.Serializers var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", ""); try { - connectionInfo.Resolution = (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), "Res" + resolutionString); + connectionInfo.Resolution = + (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), + "Res" + resolutionString); } catch (ArgumentException) { @@ -225,7 +238,8 @@ namespace mRemoteNG.Config.Serializers var colorDepth = remoteDesktopNode.SelectSingleNode("./colorDepth")?.InnerText; if (colorDepth != null) - connectionInfo.Colors = (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), colorDepth); + connectionInfo.Colors = + (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), colorDepth); } else { @@ -274,11 +288,16 @@ namespace mRemoteNG.Config.Serializers } // ./redirectClipboard - connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText ?? "false"); - connectionInfo.RedirectPorts = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText ?? "false"); - connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false"); - connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false"); - connectionInfo.RedirectClipboard = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectClipboard")?.InnerText ?? "false"); + connectionInfo.RedirectDiskDrives = + bool.Parse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText ?? "false"); + connectionInfo.RedirectPorts = + bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText ?? "false"); + connectionInfo.RedirectPrinters = + bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false"); + connectionInfo.RedirectSmartCards = + bool.Parse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false"); + connectionInfo.RedirectClipboard = + bool.Parse(localResourcesNode?.SelectSingleNode("./redirectClipboard")?.InnerText ?? "false"); } else { @@ -330,7 +349,8 @@ namespace mRemoteNG.Config.Serializers try { - var plaintextData = ProtectedData.Unprotect(Convert.FromBase64String(ciphertext), new byte[] { }, DataProtectionScope.LocalMachine); + var plaintextData = ProtectedData.Unprotect(Convert.FromBase64String(ciphertext), new byte[] { }, + DataProtectionScope.LocalMachine); var charArray = Encoding.Unicode.GetChars(plaintextData); return new string(charArray); } diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs b/mRemoteV1/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs index 232914b0b..607512c81 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs @@ -36,7 +36,7 @@ namespace mRemoteNG.Config.Serializers.Versioning new SqlVersion23To24Upgrader(_sqlDatabaseConnector), new SqlVersion24To25Upgrader(_sqlDatabaseConnector), new SqlVersion25To26Upgrader(_sqlDatabaseConnector), - new SqlVersion26To27Upgrader(_sqlDatabaseConnector), + new SqlVersion26To27Upgrader(_sqlDatabaseConnector), }; foreach (var upgrader in dbUpgraders) @@ -52,11 +52,16 @@ namespace mRemoteNG.Config.Serializers.Versioning isVerified = true; if (isVerified == false) - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, string.Format(Language.strErrorBadDatabaseVersion, databaseVersion, GeneralAppInfo.ProductName)); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + string.Format(Language.strErrorBadDatabaseVersion, + databaseVersion, + GeneralAppInfo.ProductName)); } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorVerifyDatabaseVersionFailed, ex.Message)); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + string.Format(Language.strErrorVerifyDatabaseVersionFailed, + ex.Message)); } return isVerified; diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlVersion22To23Upgrader.cs b/mRemoteV1/Config/Serializers/Versioning/SqlVersion22To23Upgrader.cs index cf0e8865e..5f8cbbad7 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlVersion22To23Upgrader.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlVersion22To23Upgrader.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.Config.Serializers.Versioning public Version Upgrade() { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.2 to version 2.3."); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Upgrading database from version 2.2 to version 2.3."); const string sqlText = @" ALTER TABLE tblCons ADD EnableFontSmoothing bit NOT NULL DEFAULT 0, diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlVersion23To24Upgrader.cs b/mRemoteV1/Config/Serializers/Versioning/SqlVersion23To24Upgrader.cs index 03085c8ab..535dad238 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlVersion23To24Upgrader.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlVersion23To24Upgrader.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.Config.Serializers.Versioning public Version Upgrade() { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.3 to version 2.4."); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Upgrading database from version 2.3 to version 2.4."); const string sqlText = @" ALTER TABLE tblCons ADD UseCredSsp bit NOT NULL DEFAULT 1, diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlVersion24To25Upgrader.cs b/mRemoteV1/Config/Serializers/Versioning/SqlVersion24To25Upgrader.cs index 704fd8cfa..b51615db1 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlVersion24To25Upgrader.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlVersion24To25Upgrader.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.Config.Serializers.Versioning public Version Upgrade() { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.4 to version 2.5."); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Upgrading database from version 2.4 to version 2.5."); const string sqlText = @" ALTER TABLE tblCons ADD LoadBalanceInfo varchar (1024) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlVersion25To26Upgrader.cs b/mRemoteV1/Config/Serializers/Versioning/SqlVersion25To26Upgrader.cs index 7e6e232c5..cfde93f0a 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlVersion25To26Upgrader.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlVersion25To26Upgrader.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.Config.Serializers.Versioning public Version Upgrade() { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.5 to version 2.6."); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Upgrading database from version 2.5 to version 2.6."); const string sqlText = @" ALTER TABLE tblCons ADD RDPMinutesToIdleTimeout int NOT NULL DEFAULT 0, diff --git a/mRemoteV1/Config/Serializers/Versioning/SqlVersion26To27Upgrader.cs b/mRemoteV1/Config/Serializers/Versioning/SqlVersion26To27Upgrader.cs index 26d66b491..176c295c0 100644 --- a/mRemoteV1/Config/Serializers/Versioning/SqlVersion26To27Upgrader.cs +++ b/mRemoteV1/Config/Serializers/Versioning/SqlVersion26To27Upgrader.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.Config.Serializers.Versioning public Version Upgrade() { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.6 to version 2.7."); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "Upgrading database from version 2.6 to version 2.7."); const string sqlText = @" ALTER TABLE tblCons ADD RedirectClipboard bit NOT NULL DEFAULT 0, @@ -38,4 +39,4 @@ UPDATE tblRoot return new Version(2, 7); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs b/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs index efa0683a9..80332729d 100644 --- a/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs +++ b/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs @@ -29,7 +29,9 @@ namespace mRemoteNG.Config.Serializers _rootNodeInfo = rootNodeInfo; } - public XmlConnectionsDecryptor(BlockCipherEngines blockCipherEngine, BlockCipherModes blockCipherMode, RootNodeInfo rootNodeInfo) + public XmlConnectionsDecryptor(BlockCipherEngines blockCipherEngine, + BlockCipherModes blockCipherMode, + RootNodeInfo rootNodeInfo) { _cryptographyProvider = new CryptoProviderFactory(blockCipherEngine, blockCipherMode).Build(); _rootNodeInfo = rootNodeInfo; @@ -37,7 +39,9 @@ namespace mRemoteNG.Config.Serializers public string Decrypt(string plainText) { - return plainText == "" ? "" : _cryptographyProvider.Decrypt(plainText, _rootNodeInfo.PasswordString.ConvertToSecureString()); + return plainText == "" + ? "" + : _cryptographyProvider.Decrypt(plainText, _rootNodeInfo.PasswordString.ConvertToSecureString()); } public string LegacyFullFileDecrypt(string xml) @@ -50,7 +54,8 @@ namespace mRemoteNG.Config.Serializers try { - decryptedContent = _cryptographyProvider.Decrypt(xml, _rootNodeInfo.PasswordString.ConvertToSecureString()); + decryptedContent = + _cryptographyProvider.Decrypt(xml, _rootNodeInfo.PasswordString.ConvertToSecureString()); notDecr = decryptedContent == xml; } catch (Exception) @@ -62,7 +67,8 @@ namespace mRemoteNG.Config.Serializers { if (Authenticate(xml, _rootNodeInfo.PasswordString.ConvertToSecureString())) { - decryptedContent = _cryptographyProvider.Decrypt(xml, _rootNodeInfo.PasswordString.ConvertToSecureString()); + decryptedContent = + _cryptographyProvider.Decrypt(xml, _rootNodeInfo.PasswordString.ConvertToSecureString()); notDecr = false; } @@ -82,12 +88,17 @@ namespace mRemoteNG.Config.Serializers var connectionsFileIsNotEncrypted = false; try { - connectionsFileIsNotEncrypted = _cryptographyProvider.Decrypt(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()) == "ThisIsNotProtected"; + connectionsFileIsNotEncrypted = + _cryptographyProvider.Decrypt(protectedString, + _rootNodeInfo.PasswordString.ConvertToSecureString()) == + "ThisIsNotProtected"; } catch (EncryptionException) { } - return connectionsFileIsNotEncrypted || Authenticate(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()); + + return connectionsFileIsNotEncrypted || + Authenticate(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()); } private bool Authenticate(string cipherText, SecureString password) diff --git a/mRemoteV1/Config/Settings/DockPanelLayoutLoader.cs b/mRemoteV1/Config/Settings/DockPanelLayoutLoader.cs index d431a3d1c..4995384db 100644 --- a/mRemoteV1/Config/Settings/DockPanelLayoutLoader.cs +++ b/mRemoteV1/Config/Settings/DockPanelLayoutLoader.cs @@ -36,7 +36,8 @@ namespace mRemoteNG.Config.Settings } #if !PORTABLE - var oldPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + GeneralAppInfo.ProductName + "\\" + SettingsFileInfo.LayoutFileName; + var oldPath = + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + GeneralAppInfo.ProductName + "\\" + SettingsFileInfo.LayoutFileName; #endif var newPath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.LayoutFileName; if (File.Exists(newPath)) diff --git a/mRemoteV1/Config/Settings/DockPanelLayoutSaver.cs b/mRemoteV1/Config/Settings/DockPanelLayoutSaver.cs index 9779a7bd5..f5e2aae01 100644 --- a/mRemoteV1/Config/Settings/DockPanelLayoutSaver.cs +++ b/mRemoteV1/Config/Settings/DockPanelLayoutSaver.cs @@ -14,7 +14,8 @@ namespace mRemoteNG.Config.Settings private readonly ISerializer _dockPanelSerializer; private readonly IDataProvider _dataProvider; - public DockPanelLayoutSaver(ISerializer dockPanelSerializer, IDataProvider dataProvider) + public DockPanelLayoutSaver(ISerializer dockPanelSerializer, + IDataProvider dataProvider) { if (dockPanelSerializer == null) throw new ArgumentNullException(nameof(dockPanelSerializer)); diff --git a/mRemoteV1/Config/Settings/DockPanelLayoutSerializer.cs b/mRemoteV1/Config/Settings/DockPanelLayoutSerializer.cs index 0ee7d3c3c..e8e4be847 100644 --- a/mRemoteV1/Config/Settings/DockPanelLayoutSerializer.cs +++ b/mRemoteV1/Config/Settings/DockPanelLayoutSerializer.cs @@ -23,6 +23,7 @@ namespace mRemoteNG.Config.Settings memoryStream.Position = 0; xdoc = XDocument.Load(memoryStream, LoadOptions.SetBaseUri); } + return $"{xdoc.Declaration}{Environment.NewLine}{xdoc}"; } } diff --git a/mRemoteV1/Config/Settings/ExternalAppsLoader.cs b/mRemoteV1/Config/Settings/ExternalAppsLoader.cs index ee0645074..a81d4b090 100644 --- a/mRemoteV1/Config/Settings/ExternalAppsLoader.cs +++ b/mRemoteV1/Config/Settings/ExternalAppsLoader.cs @@ -16,7 +16,9 @@ namespace mRemoteNG.Config.Settings private readonly MessageCollector _messageCollector; private readonly ExternalToolsToolStrip _externalToolsToolStrip; - public ExternalAppsLoader(FrmMain mainForm, MessageCollector messageCollector, ExternalToolsToolStrip externalToolsToolStrip) + public ExternalAppsLoader(FrmMain mainForm, + MessageCollector messageCollector, + ExternalToolsToolStrip externalToolsToolStrip) { if (mainForm == null) throw new ArgumentNullException(nameof(mainForm)); @@ -34,13 +36,15 @@ namespace mRemoteNG.Config.Settings public void LoadExternalAppsFromXML() { #if !PORTABLE - var oldPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), GeneralAppInfo.ProductName, SettingsFileInfo.ExtAppsFilesName); + var oldPath = + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), GeneralAppInfo.ProductName, SettingsFileInfo.ExtAppsFilesName); #endif var newPath = Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.ExtAppsFilesName); var xDom = new XmlDocument(); if (File.Exists(newPath)) { - _messageCollector.AddMessage(MessageClass.InformationMsg, $"Loading External Apps from: {newPath}", true); + _messageCollector.AddMessage(MessageClass.InformationMsg, $"Loading External Apps from: {newPath}", + true); xDom.Load(newPath); } #if !PORTABLE @@ -53,13 +57,15 @@ namespace mRemoteNG.Config.Settings #endif else { - _messageCollector.AddMessage(MessageClass.WarningMsg, "Loading External Apps failed: Could not FIND file!"); + _messageCollector.AddMessage(MessageClass.WarningMsg, + "Loading External Apps failed: Could not FIND file!"); return; } if (xDom.DocumentElement == null) { - _messageCollector.AddMessage(MessageClass.WarningMsg, "Loading External Apps failed: Could not LOAD file!"); + _messageCollector.AddMessage(MessageClass.WarningMsg, + "Loading External Apps failed: Could not LOAD file!"); return; } @@ -93,7 +99,9 @@ namespace mRemoteNG.Config.Settings extA.ShowOnToolbar = bool.Parse(xEl.Attributes["ShowOnToolbar"].Value); } - _messageCollector.AddMessage(MessageClass.InformationMsg, $"Adding External App: {extA.DisplayName} {extA.FileName} {extA.Arguments}", true); + _messageCollector.AddMessage(MessageClass.InformationMsg, + $"Adding External App: {extA.DisplayName} {extA.FileName} {extA.Arguments}", + true); Runtime.ExternalToolsService.ExternalTools.Add(extA); } diff --git a/mRemoteV1/Config/Settings/ExternalAppsSaver.cs b/mRemoteV1/Config/Settings/ExternalAppsSaver.cs index 243f330af..000cc4c2a 100644 --- a/mRemoteV1/Config/Settings/ExternalAppsSaver.cs +++ b/mRemoteV1/Config/Settings/ExternalAppsSaver.cs @@ -22,7 +22,7 @@ namespace mRemoteNG.Config.Settings var xmlTextWriter = new XmlTextWriter(SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.ExtAppsFilesName, - Encoding.UTF8) + Encoding.UTF8) { Formatting = Formatting.Indented, Indentation = 4 diff --git a/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs b/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs index 10a1a342b..8a58cf8d6 100644 --- a/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs +++ b/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs @@ -9,5 +9,6 @@ namespace mRemoteNG.Config.Settings.Providers #else public class ChooseProvider : LocalFileSettingsProvider #endif - { } + { + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs index 28a91025d..fa79921fa 100644 --- a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs +++ b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs @@ -31,6 +31,7 @@ using System.Windows.Forms; using System.Collections.Specialized; using System.Xml; using System.IO; + //using mRemoteNG.App; namespace mRemoteNG.Config.Settings.Providers @@ -43,7 +44,9 @@ namespace mRemoteNG.Config.Settings.Providers private const string _className = "PortableSettingsProvider"; private XmlDocument _xmlDocument; - private string _filePath => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), $"{ApplicationName}.settings"); + private string _filePath => + Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), + $"{ApplicationName}.settings"); private XmlNode _localSettingsNode => GetSettingsNode(_localSettingsNodeName); @@ -109,7 +112,8 @@ namespace mRemoteNG.Config.Settings.Providers } } - public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) + public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, + SettingsPropertyCollection collection) { var values = new SettingsPropertyValueCollection(); diff --git a/mRemoteV1/Config/Settings/SettingsLoader.cs b/mRemoteV1/Config/Settings/SettingsLoader.cs index a730dac69..6e250a5b4 100644 --- a/mRemoteV1/Config/Settings/SettingsLoader.cs +++ b/mRemoteV1/Config/Settings/SettingsLoader.cs @@ -16,25 +16,24 @@ using mRemoteNG.UI.Forms; namespace mRemoteNG.Config.Settings { public class SettingsLoader - { + { private readonly ExternalAppsLoader _externalAppsLoader; private readonly MessageCollector _messageCollector; - private readonly MenuStrip _mainMenu; + private readonly MenuStrip _mainMenu; private readonly QuickConnectToolStrip _quickConnectToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip; - private readonly MultiSshToolStrip _multiSshToolStrip; + private readonly MultiSshToolStrip _multiSshToolStrip; private FrmMain MainForm { get; } - public SettingsLoader( - FrmMain mainForm, - MessageCollector messageCollector, - QuickConnectToolStrip quickConnectToolStrip, - ExternalToolsToolStrip externalToolsToolStrip, - MultiSshToolStrip multiSshToolStrip, - MenuStrip mainMenu) - { + public SettingsLoader(FrmMain mainForm, + MessageCollector messageCollector, + QuickConnectToolStrip quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + MenuStrip mainMenu) + { if (mainForm == null) throw new ArgumentNullException(nameof(mainForm)); if (messageCollector == null) @@ -45,45 +44,46 @@ namespace mRemoteNG.Config.Settings throw new ArgumentNullException(nameof(externalToolsToolStrip)); if (multiSshToolStrip == null) throw new ArgumentNullException(nameof(multiSshToolStrip)); - if (mainMenu == null) - throw new ArgumentNullException(nameof(mainMenu)); + if (mainMenu == null) + throw new ArgumentNullException(nameof(mainMenu)); MainForm = mainForm; - _messageCollector = messageCollector; - _quickConnectToolStrip = quickConnectToolStrip; - _externalToolsToolStrip = externalToolsToolStrip; - _multiSshToolStrip = multiSshToolStrip; - _mainMenu = mainMenu; - _externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip); + _messageCollector = messageCollector; + _quickConnectToolStrip = quickConnectToolStrip; + _externalToolsToolStrip = externalToolsToolStrip; + _multiSshToolStrip = multiSshToolStrip; + _mainMenu = mainMenu; + _externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip); } - + #region Public Methods + public void LoadSettings() - { - try - { + { + try + { EnsureSettingsAreSavedInNewestVersion(); - SetSupportedCulture(); + SetSupportedCulture(); SetApplicationWindowPositionAndSize(); SetKioskMode(); SetPuttyPath(); SetShowSystemTrayIcon(); SetAutoSave(); - LoadExternalAppsFromXml(); + LoadExternalAppsFromXml(); SetAlwaysShowPanelTabs(); - - if (mRemoteNG.Settings.Default.ResetToolbars) + + if (mRemoteNG.Settings.Default.ResetToolbars) SetToolbarsDefault(); - else + else LoadToolbarsFromSettings(); - } - catch (Exception ex) - { + } + catch (Exception ex) + { _messageCollector.AddExceptionMessage("Loading settings failed", ex); - } - } + } + } private static void SetAlwaysShowPanelTabs() { @@ -91,14 +91,15 @@ namespace mRemoteNG.Config.Settings FrmMain.Default.pnlDock.DocumentStyle = DocumentStyle.DockingWindow; } - private void SetSupportedCulture() { if (mRemoteNG.Settings.Default.OverrideUICulture == "" || !SupportedCultures.IsNameSupported(mRemoteNG.Settings.Default.OverrideUICulture)) return; Thread.CurrentThread.CurrentUICulture = new CultureInfo(mRemoteNG.Settings.Default.OverrideUICulture); - _messageCollector.AddMessage(MessageClass.InformationMsg, $"Override Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}", true); + _messageCollector.AddMessage(MessageClass.InformationMsg, + $"Override Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}", + true); } private void SetApplicationWindowPositionAndSize() @@ -163,7 +164,9 @@ namespace mRemoteNG.Config.Settings private static void SetPuttyPath() { - PuttyBase.PuttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : GeneralAppInfo.PuttyPath; + PuttyBase.PuttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath + ? mRemoteNG.Settings.Default.CustomPuttyPath + : GeneralAppInfo.PuttyPath; } private void EnsureSettingsAreSavedInNewestVersion() @@ -183,6 +186,7 @@ namespace mRemoteNG.Config.Settings { _messageCollector.AddExceptionMessage("Settings.Upgrade() failed", ex); } + mRemoteNG.Settings.Default.DoUpgrade = false; // Clear pending update flag @@ -191,21 +195,21 @@ namespace mRemoteNG.Config.Settings mRemoteNG.Settings.Default.UpdatePending = false; } - private void SetToolbarsDefault() - { - ToolStripPanelFromString("top").Join(_quickConnectToolStrip, new Point(300, 0)); + private void SetToolbarsDefault() + { + ToolStripPanelFromString("top").Join(_quickConnectToolStrip, new Point(300, 0)); _quickConnectToolStrip.Visible = true; - ToolStripPanelFromString("bottom").Join(_externalToolsToolStrip, new Point(3, 0)); + ToolStripPanelFromString("bottom").Join(_externalToolsToolStrip, new Point(3, 0)); _externalToolsToolStrip.Visible = false; - } + } - private void LoadToolbarsFromSettings() - { + private void LoadToolbarsFromSettings() + { ResetAllToolbarLocations(); - AddMainMenuPanel(); + AddMainMenuPanel(); AddExternalAppsPanel(); - AddQuickConnectPanel(); - AddMultiSshPanel(); + AddQuickConnectPanel(); + AddMultiSshPanel(); } /// @@ -213,74 +217,75 @@ namespace mRemoteNG.Config.Settings /// Since all toolbars start in this temp panel, no toolbar load /// can be blocked by pre-existing toolbars. /// - private void ResetAllToolbarLocations() - { - var tempToolStrip = new ToolStripPanel(); + private void ResetAllToolbarLocations() + { + var tempToolStrip = new ToolStripPanel(); tempToolStrip.Join(_mainMenu); - tempToolStrip.Join(_quickConnectToolStrip); - tempToolStrip.Join(_externalToolsToolStrip); - tempToolStrip.Join(_multiSshToolStrip); + tempToolStrip.Join(_quickConnectToolStrip); + tempToolStrip.Join(_externalToolsToolStrip); + tempToolStrip.Join(_multiSshToolStrip); } - private void AddMainMenuPanel() - { - SetToolstripGripStyle(_mainMenu); + private void AddMainMenuPanel() + { + SetToolstripGripStyle(_mainMenu); var toolStripPanel = ToolStripPanelFromString("top"); - toolStripPanel.Join(_mainMenu, new Point(3, 0)); + toolStripPanel.Join(_mainMenu, new Point(3, 0)); } - private void AddQuickConnectPanel() - { - SetToolstripGripStyle(_quickConnectToolStrip); + private void AddQuickConnectPanel() + { + SetToolstripGripStyle(_quickConnectToolStrip); _quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible; var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock); toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation); - } - - private void AddExternalAppsPanel() - { - SetToolstripGripStyle(_externalToolsToolStrip); + } + + private void AddExternalAppsPanel() + { + SetToolstripGripStyle(_externalToolsToolStrip); _externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible; var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock); toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation); - } + } - private void AddMultiSshPanel() - { - SetToolstripGripStyle(_multiSshToolStrip); - _multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible; + private void AddMultiSshPanel() + { + SetToolstripGripStyle(_multiSshToolStrip); + _multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible; var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.MultiSshToolbarParentDock); toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation); - } - - private void SetToolstripGripStyle(ToolStrip toolbar) - { - toolbar.GripStyle = mRemoteNG.Settings.Default.LockToolbars - ? ToolStripGripStyle.Hidden - : ToolStripGripStyle.Visible; } - - private ToolStripPanel ToolStripPanelFromString(string panel) - { - switch (panel.ToLower()) - { - case "top": - return MainForm.tsContainer.TopToolStripPanel; - case "bottom": - return MainForm.tsContainer.BottomToolStripPanel; - case "left": - return MainForm.tsContainer.LeftToolStripPanel; - case "right": - return MainForm.tsContainer.RightToolStripPanel; - default: - return MainForm.tsContainer.TopToolStripPanel; - } - } - private void LoadExternalAppsFromXml() - { + private void SetToolstripGripStyle(ToolStrip toolbar) + { + toolbar.GripStyle = mRemoteNG.Settings.Default.LockToolbars + ? ToolStripGripStyle.Hidden + : ToolStripGripStyle.Visible; + } + + private ToolStripPanel ToolStripPanelFromString(string panel) + { + switch (panel.ToLower()) + { + case "top": + return MainForm.tsContainer.TopToolStripPanel; + case "bottom": + return MainForm.tsContainer.BottomToolStripPanel; + case "left": + return MainForm.tsContainer.LeftToolStripPanel; + case "right": + return MainForm.tsContainer.RightToolStripPanel; + default: + return MainForm.tsContainer.TopToolStripPanel; + } + } + + private void LoadExternalAppsFromXml() + { _externalAppsLoader.LoadExternalAppsFromXML(); } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Config/Settings/SettingsSaver.cs b/mRemoteV1/Config/Settings/SettingsSaver.cs index 1d4c71d36..b8fe2b6bb 100644 --- a/mRemoteV1/Config/Settings/SettingsSaver.cs +++ b/mRemoteV1/Config/Settings/SettingsSaver.cs @@ -11,11 +11,10 @@ namespace mRemoteNG.Config.Settings { public static class SettingsSaver { - public static void SaveSettings( - Control quickConnectToolStrip, - ExternalToolsToolStrip externalToolsToolStrip, - MultiSshToolStrip multiSshToolStrip, - FrmMain frmMain) + public static void SaveSettings(Control quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + FrmMain frmMain) { try { @@ -100,9 +99,9 @@ namespace mRemoteNG.Config.Settings { var panelLayoutXmlFilePath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.LayoutFileName; var panelLayoutSaver = new DockPanelLayoutSaver( - new DockPanelLayoutSerializer(), - new FileDataProvider(panelLayoutXmlFilePath) - ); + new DockPanelLayoutSerializer(), + new FileDataProvider(panelLayoutXmlFilePath) + ); panelLayoutSaver.Save(); } diff --git a/mRemoteV1/Connection/AbstractConnectionRecord.cs b/mRemoteV1/Connection/AbstractConnectionRecord.cs index a7f8c6fba..b59173677 100644 --- a/mRemoteV1/Connection/AbstractConnectionRecord.cs +++ b/mRemoteV1/Connection/AbstractConnectionRecord.cs @@ -11,10 +11,11 @@ using mRemoteNG.Tools; namespace mRemoteNG.Connection { - [Obsolete("Valid for mRemoteNG v1.75 (confCons v2.6) or earlier")] + [Obsolete("Valid for mRemoteNG v1.75 (confCons v2.6) or earlier")] public abstract class AbstractConnectionRecord : INotifyPropertyChanged { #region Fields + private string _name; private string _description; private string _icon; @@ -79,10 +80,13 @@ namespace mRemoteNG.Connection private ProtocolVNC.Colors _vncColors; private ProtocolVNC.SmartSizeMode _vncSmartSizeMode; private bool _vncViewOnly; + #endregion #region Properties + #region Display + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), LocalizedAttributes.LocalizedDisplayName("strPropertyNameName"), LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")] @@ -93,8 +97,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameDescription"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameDescription"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")] public virtual string Description { get => GetPropertyValue("Description", _description); @@ -102,9 +106,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - TypeConverter(typeof(ConnectionIcon)), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameIcon"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")] + TypeConverter(typeof(ConnectionIcon)), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameIcon"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")] public virtual string Icon { get => GetPropertyValue("Icon", _icon); @@ -112,19 +116,21 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - LocalizedAttributes.LocalizedDisplayName("strPropertyNamePanel"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNamePanel"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")] public virtual string Panel { get => GetPropertyValue("Panel", _panel); set => SetField(ref _panel, value, "Panel"); } + #endregion #region Connection + [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameAddress"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameAddress"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")] public virtual string Hostname { get => _hostname.Trim(); @@ -132,8 +138,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameUsername"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameUsername"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")] public virtual string Username { get => GetPropertyValue("Username", _username); @@ -141,9 +147,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), - LocalizedAttributes.LocalizedDisplayName("strPropertyNamePassword"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPassword"), - PasswordPropertyText(true)] + LocalizedAttributes.LocalizedDisplayName("strPropertyNamePassword"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPassword"), + PasswordPropertyText(true)] public virtual string Password { get => GetPropertyValue("Password", _password); @@ -151,20 +157,22 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameDomain"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameDomain"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")] public string Domain { get => GetPropertyValue("Domain", _domain).Trim(); set => SetField(ref _domain, value?.Trim(), "Domain"); } + #endregion #region Protocol + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameProtocol"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionProtocol"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameProtocol"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionProtocol"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public virtual ProtocolType Protocol { get => GetPropertyValue("Protocol", _protocol); @@ -172,9 +180,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalTool"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalTool"), - TypeConverter(typeof(ExternalToolsTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalTool"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalTool"), + TypeConverter(typeof(ExternalToolsTypeConverter))] public string ExtApp { get => GetPropertyValue("ExtApp", _extApp); @@ -182,8 +190,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNamePort"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNamePort"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")] public virtual int Port { get => GetPropertyValue("Port", _port); @@ -191,9 +199,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNamePuttySession"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPuttySession"), - TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNamePuttySession"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPuttySession"), + TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))] public virtual string PuttySession { get => GetPropertyValue("PuttySession", _puttySession); @@ -201,9 +209,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameEncryptionStrength"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEncryptionStrength"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameEncryptionStrength"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEncryptionStrength"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public IcaProtocol.EncryptionStrength ICAEncryptionStrength { get => GetPropertyValue("ICAEncryptionStrength", _icaEncryption); @@ -211,9 +219,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameUseConsoleSession"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUseConsoleSession"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameUseConsoleSession"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUseConsoleSession"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool UseConsoleSession { get => GetPropertyValue("UseConsoleSession", _useConsoleSession); @@ -221,9 +229,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameAuthenticationLevel"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAuthenticationLevel"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameAuthenticationLevel"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAuthenticationLevel"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel { get => GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel); @@ -231,23 +239,24 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPMinutesToIdleTimeout"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPMinutesToIdleTimeout"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")] public virtual int RDPMinutesToIdleTimeout { get => GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); - set { - if(value < 0) + set + { + if (value < 0) value = 0; - else if(value > 240) + else if (value > 240) value = 240; SetField(ref _rdpMinutesToIdleTimeout, value, "RDPMinutesToIdleTimeout"); } } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPAlertIdleTimeout"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPAlertIdleTimeout"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")] public bool RDPAlertIdleTimeout { get => GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); @@ -255,8 +264,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameLoadBalanceInfo"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameLoadBalanceInfo"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")] public string LoadBalanceInfo { get => GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim(); @@ -264,9 +273,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRenderingEngine"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRenderingEngine"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRenderingEngine"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRenderingEngine"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public HTTPBase.RenderingEngine RenderingEngine { get => GetPropertyValue("RenderingEngine", _renderingEngine); @@ -274,21 +283,23 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameUseCredSsp"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUseCredSsp"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameUseCredSsp"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUseCredSsp"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool UseCredSsp { get => GetPropertyValue("UseCredSsp", _useCredSsp); set => SetField(ref _useCredSsp, value, "UseCredSsp"); } + #endregion #region RD Gateway + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUsageMethod"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsageMethod"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUsageMethod"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsageMethod"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod { get => GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod); @@ -296,8 +307,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayHostname"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayHostname"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")] public string RDGatewayHostname { get => GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim(); @@ -305,9 +316,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUseConnectionCredentials"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUseConnectionCredentials"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUseConnectionCredentials"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUseConnectionCredentials"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials { get => GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials); @@ -315,8 +326,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUsername"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayUsername"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")] public string RDGatewayUsername { get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim(); @@ -324,9 +335,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayPassword"), - LocalizedAttributes.LocalizedDescription("strPropertyNameRDGatewayPassword"), - PasswordPropertyText(true)] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayPassword"), + LocalizedAttributes.LocalizedDescription("strPropertyNameRDGatewayPassword"), + PasswordPropertyText(true)] public string RDGatewayPassword { get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword); @@ -334,20 +345,22 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayDomain"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDGatewayDomain"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")] public string RDGatewayDomain { get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim(); set => SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain"); } + #endregion #region Appearance + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameResolution"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionResolution"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameResolution"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionResolution"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDPResolutions Resolution { get => GetPropertyValue("Resolution", _resolution); @@ -355,9 +368,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameAutomaticResize"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAutomaticResize"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameAutomaticResize"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAutomaticResize"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool AutomaticResize { get => GetPropertyValue("AutomaticResize", _automaticResize); @@ -365,9 +378,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameColors"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionColors"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameColors"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionColors"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDPColors Colors { get => GetPropertyValue("Colors", _colors); @@ -375,9 +388,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameCacheBitmaps"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionCacheBitmaps"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameCacheBitmaps"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionCacheBitmaps"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool CacheBitmaps { get => GetPropertyValue("CacheBitmaps", _cacheBitmaps); @@ -385,9 +398,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameDisplayWallpaper"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDisplayWallpaper"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameDisplayWallpaper"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDisplayWallpaper"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool DisplayWallpaper { get => GetPropertyValue("DisplayWallpaper", _displayWallpaper); @@ -395,9 +408,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameDisplayThemes"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDisplayThemes"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameDisplayThemes"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDisplayThemes"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool DisplayThemes { get => GetPropertyValue("DisplayThemes", _displayThemes); @@ -405,9 +418,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameEnableFontSmoothing"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEnableFontSmoothing"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameEnableFontSmoothing"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEnableFontSmoothing"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool EnableFontSmoothing { get => GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing); @@ -415,21 +428,23 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameEnableDesktopComposition"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEnableDesktopComposition"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameEnableDesktopComposition"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEnableDesktopComposition"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool EnableDesktopComposition { get => GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition); set => SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition"); } + #endregion #region Redirect + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectKeys"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectKeys"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectKeys"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectKeys"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectKeys { get => GetPropertyValue("RedirectKeys", _redirectKeys); @@ -437,9 +452,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectDrives"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectDrives"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectDrives"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectDrives"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectDiskDrives { get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); @@ -447,9 +462,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectPrinters"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectPrinters"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectPrinters"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectPrinters"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectPrinters { get => GetPropertyValue("RedirectPrinters", _redirectPrinters); @@ -457,9 +472,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectClipboard"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectClipboard"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectClipboard"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectClipboard"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectClipboard { get { return GetPropertyValue("RedirectClipboard", _redirectClipboard); } @@ -467,9 +482,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectPorts"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectPorts"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectPorts"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectPorts"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectPorts { get => GetPropertyValue("RedirectPorts", _redirectPorts); @@ -477,9 +492,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectSmartCards"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectSmartCards"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectSmartCards"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectSmartCards"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectSmartCards { get => GetPropertyValue("RedirectSmartCards", _redirectSmartCards); @@ -487,9 +502,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectSounds"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectSounds"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectSounds"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectSounds"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDPSounds RedirectSound { get => GetPropertyValue("RedirectSound", _redirectSound); @@ -497,24 +512,25 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameSoundQuality"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionSoundQuality"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameSoundQuality"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionSoundQuality"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public RdpProtocol.RDPSoundQuality SoundQuality { get => GetPropertyValue("SoundQuality", _soundQuality); set => SetField(ref _soundQuality, value, "SoundQuality"); } + #endregion #region Misc - [Browsable(false)] - public string ConstantID { get; /*set;*/ } + + [Browsable(false)] public string ConstantID { get; /*set;*/ } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalToolBefore"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalToolBefore"), - TypeConverter(typeof(ExternalToolsTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalToolBefore"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalToolBefore"), + TypeConverter(typeof(ExternalToolsTypeConverter))] public virtual string PreExtApp { get => GetPropertyValue("PreExtApp", _preExtApp); @@ -522,9 +538,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalToolAfter"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalToolAfter"), - TypeConverter(typeof(ExternalToolsTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalToolAfter"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionExternalToolAfter"), + TypeConverter(typeof(ExternalToolsTypeConverter))] public virtual string PostExtApp { get => GetPropertyValue("PostExtApp", _postExtApp); @@ -532,8 +548,8 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameMACAddress"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameMACAddress"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")] public virtual string MacAddress { get => GetPropertyValue("MacAddress", _macAddress); @@ -541,21 +557,23 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameUser1"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameUser1"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")] public virtual string UserField { get => GetPropertyValue("UserField", _userField); set => SetField(ref _userField, value, "UserField"); } + #endregion #region VNC + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameCompression"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionCompression"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameCompression"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionCompression"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.Compression VNCCompression { get => GetPropertyValue("VNCCompression", _vncCompression); @@ -563,10 +581,10 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameEncoding"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEncoding"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameEncoding"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionEncoding"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.Encoding VNCEncoding { get => GetPropertyValue("VNCEncoding", _vncEncoding); @@ -574,10 +592,10 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameAuthenticationMode"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAuthenticationMode"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameAuthenticationMode"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAuthenticationMode"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.AuthMode VNCAuthMode { get => GetPropertyValue("VNCAuthMode", _vncAuthMode); @@ -585,10 +603,10 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyType"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyType"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyType"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyType"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.ProxyType VNCProxyType { get => GetPropertyValue("VNCProxyType", _vncProxyType); @@ -596,9 +614,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyAddress"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyAddress"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")] public string VNCProxyIP { get => GetPropertyValue("VNCProxyIP", _vncProxyIp); @@ -606,9 +624,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyPort"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyPort"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")] public int VNCProxyPort { get => GetPropertyValue("VNCProxyPort", _vncProxyPort); @@ -616,9 +634,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyUsername"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyUsername"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")] public string VNCProxyUsername { get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername); @@ -626,10 +644,10 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyPassword"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPassword"), - PasswordPropertyText(true)] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameVNCProxyPassword"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPassword"), + PasswordPropertyText(true)] public string VNCProxyPassword { get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword); @@ -637,10 +655,10 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - Browsable(false), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameColors"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionColors"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + Browsable(false), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameColors"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionColors"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.Colors VNCColors { get => GetPropertyValue("VNCColors", _vncColors); @@ -648,9 +666,9 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameSmartSizeMode"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionSmartSizeMode"), - TypeConverter(typeof(MiscTools.EnumTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameSmartSizeMode"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionSmartSizeMode"), + TypeConverter(typeof(MiscTools.EnumTypeConverter))] public ProtocolVNC.SmartSizeMode VNCSmartSizeMode { get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode); @@ -658,21 +676,23 @@ namespace mRemoteNG.Connection } [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameViewOnly"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionViewOnly"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayName("strPropertyNameViewOnly"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionViewOnly"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool VNCViewOnly { get => GetPropertyValue("VNCViewOnly", _vncViewOnly); set => SetField(ref _vncViewOnly, value, "VNCViewOnly"); } - #endregion + #endregion - protected AbstractConnectionRecord(string uniqueId) - { - ConstantID = uniqueId.ThrowIfNullOrEmpty(nameof(uniqueId)); - } + #endregion + + protected AbstractConnectionRecord(string uniqueId) + { + ConstantID = uniqueId.ThrowIfNullOrEmpty(nameof(uniqueId)); + } protected virtual TPropertyType GetPropertyValue(string propertyName, TPropertyType value) { @@ -680,6 +700,7 @@ namespace mRemoteNG.Connection } public event PropertyChangedEventHandler PropertyChanged; + protected virtual void RaisePropertyChangedEvent(object sender, PropertyChangedEventArgs args) { PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName)); diff --git a/mRemoteV1/Connection/ConnectionIcon.cs b/mRemoteV1/Connection/ConnectionIcon.cs index fc4397c12..60bae3c18 100644 --- a/mRemoteV1/Connection/ConnectionIcon.cs +++ b/mRemoteV1/Connection/ConnectionIcon.cs @@ -6,43 +6,45 @@ using mRemoteNG.App.Info; namespace mRemoteNG.Connection { - public class ConnectionIcon : StringConverter - { - public static string[] Icons = {}; - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) - { - return new StandardValuesCollection(Icons); - } - - public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) - { - return true; - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) - { - return true; - } - - public static System.Drawing.Icon FromString(string iconName) - { - try - { - var iconPath = $"{GeneralAppInfo.HomePath}\\Icons\\{iconName}.ico"; - - if (System.IO.File.Exists(iconPath)) - { - var nI = new System.Drawing.Icon(iconPath); - return nI; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - $"Couldn\'t get Icon from String" + Environment.NewLine + ex.Message); - } - return null; - } - } -} + public class ConnectionIcon : StringConverter + { + public static string[] Icons = { }; + + public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) + { + return new StandardValuesCollection(Icons); + } + + public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) + { + return true; + } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { + return true; + } + + public static System.Drawing.Icon FromString(string iconName) + { + try + { + var iconPath = $"{GeneralAppInfo.HomePath}\\Icons\\{iconName}.ico"; + + if (System.IO.File.Exists(iconPath)) + { + var nI = new System.Drawing.Icon(iconPath); + return nI; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + $"Couldn\'t get Icon from String" + Environment.NewLine + + ex.Message); + } + + return null; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/ConnectionInfo.cs b/mRemoteV1/Connection/ConnectionInfo.cs index 46fe5ff87..2e1e38ae8 100644 --- a/mRemoteV1/Connection/ConnectionInfo.cs +++ b/mRemoteV1/Connection/ConnectionInfo.cs @@ -21,22 +21,18 @@ namespace mRemoteNG.Connection { [DefaultProperty("Name")] public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable - { + { #region Public Properties - [Browsable(false)] - public ConnectionInfoInheritance Inheritance { get; set; } - [Browsable(false)] - public ProtocolList OpenConnections { get; protected set; } + [Browsable(false)] public ConnectionInfoInheritance Inheritance { get; set; } - [Browsable(false)] - public virtual bool IsContainer { get; set; } + [Browsable(false)] public ProtocolList OpenConnections { get; protected set; } - [Browsable(false)] - public bool IsDefault { get; set; } + [Browsable(false)] public virtual bool IsContainer { get; set; } - [Browsable(false)] - public ContainerInfo Parent { get; internal set; } + [Browsable(false)] public bool IsDefault { get; set; } + + [Browsable(false)] public ContainerInfo Parent { get; internal set; } //[Browsable(false)] //private int PositionID { get; set; } @@ -45,20 +41,20 @@ namespace mRemoteNG.Connection // ReSharper disable once UnusedAutoPropertyAccessor.Global public bool IsQuickConnect { get; set; } - [Browsable(false)] - public bool PleaseConnect { get; set; } - #endregion + [Browsable(false)] public bool PleaseConnect { get; set; } + + #endregion #region Constructors - public ConnectionInfo() - : this(Guid.NewGuid().ToString()) - { - } + public ConnectionInfo() + : this(Guid.NewGuid().ToString()) + { + } public ConnectionInfo(string uniqueId) - : base(uniqueId) - { + : base(uniqueId) + { SetTreeDisplayDefaults(); SetConnectionDefaults(); SetProtocolDefaults(); @@ -69,56 +65,59 @@ namespace mRemoteNG.Connection SetVncDefaults(); SetNonBrowsablePropertiesDefaults(); SetDefaults(); - } + } + #endregion - + #region Public Methods - public virtual ConnectionInfo Clone() - { - var newConnectionInfo = new ConnectionInfo(); + + public virtual ConnectionInfo Clone() + { + var newConnectionInfo = new ConnectionInfo(); newConnectionInfo.CopyFrom(this); - newConnectionInfo.Inheritance = Inheritance.Clone(); + newConnectionInfo.Inheritance = Inheritance.Clone(); newConnectionInfo.Inheritance.Parent = newConnectionInfo; return newConnectionInfo; - } + } - public void CopyFrom(ConnectionInfo sourceConnectionInfo) - { - var properties = GetType().BaseType?.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); - if (properties == null) return; - foreach (var property in properties) - { - if (property.Name == nameof(Parent)) continue; - var remotePropertyValue = property.GetValue(sourceConnectionInfo, null); + public void CopyFrom(ConnectionInfo sourceConnectionInfo) + { + var properties = GetType().BaseType?.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); + if (properties == null) return; + foreach (var property in properties) + { + if (property.Name == nameof(Parent)) continue; + var remotePropertyValue = property.GetValue(sourceConnectionInfo, null); property.SetValue(this, remotePropertyValue, null); - } + } + var clonedInheritance = sourceConnectionInfo.Inheritance.Clone(); clonedInheritance.Parent = this; Inheritance = clonedInheritance; } - public virtual TreeNodeType GetTreeNodeType() - { - return TreeNodeType.Connection; - } + public virtual TreeNodeType GetTreeNodeType() + { + return TreeNodeType.Connection; + } private void SetDefaults() - { - if (Port == 0) - { - SetDefaultPort(); - } - } - - public int GetDefaultPort() - { - return GetDefaultPort(Protocol); - } - - public void SetDefaultPort() - { - Port = GetDefaultPort(); - } + { + if (Port == 0) + { + SetDefaultPort(); + } + } + + public int GetDefaultPort() + { + return GetDefaultPort(Protocol); + } + + public void SetDefaultPort() + { + Port = GetDefaultPort(); + } protected virtual IEnumerable GetProperties(string[] excludedPropertyNames) { @@ -127,60 +126,67 @@ namespace mRemoteNG.Connection return filteredProperties; } - public virtual IEnumerable GetSerializableProperties() - { - var excludedProperties = new[] { "Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections", - "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" }; + public virtual IEnumerable GetSerializableProperties() + { + var excludedProperties = new[] + { + "Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections", + "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" + }; - return GetProperties(excludedProperties); - } + return GetProperties(excludedProperties); + } - public virtual void SetParent(ContainerInfo newParent) - { + public virtual void SetParent(ContainerInfo newParent) + { RemoveParent(); - newParent?.AddChild(this); - } + newParent?.AddChild(this); + } public void RemoveParent() { Parent?.RemoveChild(this); } - public ConnectionInfo GetRootParent() - { - return Parent != null ? Parent.GetRootParent() : this; - } + public ConnectionInfo GetRootParent() + { + return Parent != null ? Parent.GetRootParent() : this; + } - #endregion + #endregion #region Public Enumerations + [Flags()] public enum Force - { - None = 0, - UseConsoleSession = 1, - Fullscreen = 2, - DoNotJump = 4, - OverridePanel = 8, - DontUseConsoleSession = 16, - NoCredentials = 32 - } + { + None = 0, + UseConsoleSession = 1, + Fullscreen = 2, + DoNotJump = 4, + OverridePanel = 8, + DontUseConsoleSession = 16, + NoCredentials = 32 + } + #endregion - + #region Private Methods + protected override TPropertyType GetPropertyValue(string propertyName, TPropertyType value) { if (!ShouldThisPropertyBeInherited(propertyName)) return value; - var couldGetInheritedValue = TryGetInheritedPropertyValue(propertyName, out var inheritedValue); + var couldGetInheritedValue = + TryGetInheritedPropertyValue(propertyName, out var inheritedValue); return couldGetInheritedValue ? inheritedValue : value; } - private bool ShouldThisPropertyBeInherited(string propertyName) + private bool ShouldThisPropertyBeInherited(string propertyName) { return ParentIsValidInheritanceTarget() && IsInheritanceTurnedOnForThisProperty(propertyName); } @@ -194,7 +200,8 @@ namespace mRemoteNG.Connection { var inheritType = Inheritance.GetType(); var inheritPropertyInfo = inheritType.GetProperty(propertyName); - var inheritPropertyValue = inheritPropertyInfo != null && Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null)); + var inheritPropertyValue = inheritPropertyInfo != null && + Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null)); return inheritPropertyValue; } @@ -205,24 +212,26 @@ namespace mRemoteNG.Connection var connectionInfoType = Parent.GetType(); var parentPropertyInfo = connectionInfoType.GetProperty(propertyName); if (parentPropertyInfo == null) - throw new NullReferenceException($"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'"); + throw new NullReferenceException( + $"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'"); inheritedValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null); return true; } catch (Exception e) { - Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e); + Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", + e); inheritedValue = default(TPropertyType); return false; } } - private static int GetDefaultPort(ProtocolType protocol) - { - try - { - // ReSharper disable once SwitchStatementMissingSomeCases + private static int GetDefaultPort(ProtocolType protocol) + { + try + { + // ReSharper disable once SwitchStatementMissingSomeCases switch (protocol) { case ProtocolType.RDP: @@ -248,14 +257,15 @@ namespace mRemoteNG.Connection case ProtocolType.IntApp: return (int)IntegratedProgram.Defaults.Port; } + return 0; - } - catch (Exception ex) - { + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionMessage(Language.strConnectionSetDefaultPortFailed, ex); return 0; - } - } + } + } private void SetTreeDisplayDefaults() { @@ -276,31 +286,54 @@ namespace mRemoteNG.Connection ExtApp = Settings.Default.ConDefaultExtApp; Port = 0; PuttySession = Settings.Default.ConDefaultPuttySession; - ICAEncryptionStrength = (IcaProtocol.EncryptionStrength) Enum.Parse(typeof(IcaProtocol.EncryptionStrength), Settings.Default.ConDefaultICAEncryptionStrength); + ICAEncryptionStrength = (IcaProtocol.EncryptionStrength)Enum.Parse(typeof(IcaProtocol.EncryptionStrength), + Settings + .Default + .ConDefaultICAEncryptionStrength); UseConsoleSession = Settings.Default.ConDefaultUseConsoleSession; - RDPAuthenticationLevel = (RdpProtocol.AuthenticationLevel) Enum.Parse(typeof(RdpProtocol.AuthenticationLevel), Settings.Default.ConDefaultRDPAuthenticationLevel); + RDPAuthenticationLevel = (RdpProtocol.AuthenticationLevel)Enum.Parse( + typeof(RdpProtocol.AuthenticationLevel + ), + Settings + .Default + .ConDefaultRDPAuthenticationLevel); RDPMinutesToIdleTimeout = Settings.Default.ConDefaultRDPMinutesToIdleTimeout; RDPAlertIdleTimeout = Settings.Default.ConDefaultRDPAlertIdleTimeout; LoadBalanceInfo = Settings.Default.ConDefaultLoadBalanceInfo; - RenderingEngine = (HTTPBase.RenderingEngine) Enum.Parse(typeof(HTTPBase.RenderingEngine), Settings.Default.ConDefaultRenderingEngine); + RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), + Settings.Default.ConDefaultRenderingEngine); UseCredSsp = Settings.Default.ConDefaultUseCredSsp; } private void SetRdGatewayDefaults() { - RDGatewayUsageMethod = (RdpProtocol.RDGatewayUsageMethod) Enum.Parse(typeof(RdpProtocol.RDGatewayUsageMethod), Settings.Default.ConDefaultRDGatewayUsageMethod); + RDGatewayUsageMethod = (RdpProtocol.RDGatewayUsageMethod)Enum.Parse( + typeof(RdpProtocol.RDGatewayUsageMethod + ), + Settings + .Default + .ConDefaultRDGatewayUsageMethod); RDGatewayHostname = Settings.Default.ConDefaultRDGatewayHostname; - RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials) Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), Settings.Default.ConDefaultRDGatewayUseConnectionCredentials); + RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse( + typeof( + RdpProtocol + .RDGatewayUseConnectionCredentials + ), + Settings + .Default + .ConDefaultRDGatewayUseConnectionCredentials); RDGatewayUsername = Settings.Default.ConDefaultRDGatewayUsername; RDGatewayPassword = Settings.Default.ConDefaultRDGatewayPassword; RDGatewayDomain = Settings.Default.ConDefaultRDGatewayDomain; } - private void SetAppearanceDefaults() + private void SetAppearanceDefaults() { - Resolution = (RdpProtocol.RDPResolutions) Enum.Parse(typeof(RdpProtocol.RDPResolutions), Settings.Default.ConDefaultResolution); + Resolution = (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), + Settings.Default.ConDefaultResolution); AutomaticResize = Settings.Default.ConDefaultAutomaticResize; - Colors = (RdpProtocol.RDPColors) Enum.Parse(typeof(RdpProtocol.RDPColors), Settings.Default.ConDefaultColors); + Colors = (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), + Settings.Default.ConDefaultColors); CacheBitmaps = Settings.Default.ConDefaultCacheBitmaps; DisplayWallpaper = Settings.Default.ConDefaultDisplayWallpaper; DisplayThemes = Settings.Default.ConDefaultDisplayThemes; @@ -316,8 +349,10 @@ namespace mRemoteNG.Connection RedirectClipboard = Settings.Default.ConDefaultRedirectClipboard; RedirectPorts = Settings.Default.ConDefaultRedirectPorts; RedirectSmartCards = Settings.Default.ConDefaultRedirectSmartCards; - RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound); - SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), Settings.Default.ConDefaultSoundQuality); + RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), + Settings.Default.ConDefaultRedirectSound); + SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), + Settings.Default.ConDefaultSoundQuality); } private void SetMiscDefaults() @@ -330,16 +365,22 @@ namespace mRemoteNG.Connection private void SetVncDefaults() { - VNCCompression = (ProtocolVNC.Compression) Enum.Parse(typeof(ProtocolVNC.Compression), Settings.Default.ConDefaultVNCCompression); - VNCEncoding = (ProtocolVNC.Encoding) Enum.Parse(typeof(ProtocolVNC.Encoding), Settings.Default.ConDefaultVNCEncoding); - VNCAuthMode = (ProtocolVNC.AuthMode) Enum.Parse(typeof(ProtocolVNC.AuthMode), Settings.Default.ConDefaultVNCAuthMode); - VNCProxyType = (ProtocolVNC.ProxyType) Enum.Parse(typeof(ProtocolVNC.ProxyType), Settings.Default.ConDefaultVNCProxyType); + VNCCompression = (ProtocolVNC.Compression)Enum.Parse(typeof(ProtocolVNC.Compression), + Settings.Default.ConDefaultVNCCompression); + VNCEncoding = + (ProtocolVNC.Encoding)Enum.Parse(typeof(ProtocolVNC.Encoding), Settings.Default.ConDefaultVNCEncoding); + VNCAuthMode = + (ProtocolVNC.AuthMode)Enum.Parse(typeof(ProtocolVNC.AuthMode), Settings.Default.ConDefaultVNCAuthMode); + VNCProxyType = (ProtocolVNC.ProxyType)Enum.Parse(typeof(ProtocolVNC.ProxyType), + Settings.Default.ConDefaultVNCProxyType); VNCProxyIP = Settings.Default.ConDefaultVNCProxyIP; VNCProxyPort = Settings.Default.ConDefaultVNCProxyPort; VNCProxyUsername = Settings.Default.ConDefaultVNCProxyUsername; VNCProxyPassword = Settings.Default.ConDefaultVNCProxyPassword; - VNCColors = (ProtocolVNC.Colors) Enum.Parse(typeof(ProtocolVNC.Colors), Settings.Default.ConDefaultVNCColors); - VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode) Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), Settings.Default.ConDefaultVNCSmartSizeMode); + VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), + Settings.Default.ConDefaultVNCColors); + VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), + Settings.Default.ConDefaultVNCSmartSizeMode); VNCViewOnly = Settings.Default.ConDefaultVNCViewOnly; } @@ -351,10 +392,12 @@ namespace mRemoteNG.Connection } private void SetNewOpenConnectionList() - { - OpenConnections = new ProtocolList(); - OpenConnections.CollectionChanged += (sender, args) => RaisePropertyChangedEvent(this, new PropertyChangedEventArgs("OpenConnections")); - } + { + OpenConnections = new ProtocolList(); + OpenConnections.CollectionChanged += (sender, args) => + RaisePropertyChangedEvent(this, new PropertyChangedEventArgs("OpenConnections")); + } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Connection/ConnectionInfoInheritance.cs b/mRemoteV1/Connection/ConnectionInfoInheritance.cs index c937f72a9..c14c7be7a 100644 --- a/mRemoteV1/Connection/ConnectionInfoInheritance.cs +++ b/mRemoteV1/Connection/ConnectionInfoInheritance.cs @@ -6,339 +6,412 @@ using mRemoteNG.Tools; namespace mRemoteNG.Connection { - public class ConnectionInfoInheritance - { + public class ConnectionInfoInheritance + { private ConnectionInfoInheritance _tempInheritanceStorage; #region Public Properties + #region General + [LocalizedAttributes.LocalizedCategory("strCategoryGeneral"), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAll"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAll"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAll"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAll"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool EverythingInherited - { - get { return EverythingIsInherited(); } + { + get { return EverythingIsInherited(); } set { SetAllValues(value); } - } + } + #endregion + #region Display - [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDescription"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDescription"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Description {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameIcon"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionIcon"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Icon {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePanel"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPanel"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Panel {get; set;} + + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDescription"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDescription"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Description { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameIcon"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionIcon"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Icon { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay", 2), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePanel"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPanel"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Panel { get; set; } + #endregion + #region Connection + [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 3), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUsername"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUsername"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUsername"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUsername"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] [Browsable(true)] public bool Username { get; set; } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 3), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePassword"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPassword"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePassword"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPassword"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] [Browsable(true)] public bool Password { get; set; } [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 3), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDomain"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDomain"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDomain"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDomain"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] [Browsable(true)] public bool Domain { get; set; } + #endregion + #region Protocol - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameProtocol"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionProtocol"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Protocol {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalTool"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalTool"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool ExtApp {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePort"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPort"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Port {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePuttySession"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPuttySession"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool PuttySession {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEncryptionStrength"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEncryptionStrength"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool ICAEncryptionStrength {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationLevel"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationLevel"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set; } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPMinutesToIdleTimeout"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPMinutesToIdleTimeout"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPMinutesToIdleTimeout { get; set; } + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameProtocol"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionProtocol"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Protocol { get; set; } [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPAlertIdleTimeout"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPAlertIdleTimeout"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RDPAlertIdleTimeout { get; set; } + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalTool"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalTool"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool ExtApp { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePort"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPort"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Port { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNamePuttySession"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionPuttySession"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool PuttySession { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEncryptionStrength"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEncryptionStrength"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool ICAEncryptionStrength { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationLevel"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationLevel"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDPAuthenticationLevel { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPMinutesToIdleTimeout"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPMinutesToIdleTimeout"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDPMinutesToIdleTimeout { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPAlertIdleTimeout"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPAlertIdleTimeout"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDPAlertIdleTimeout { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameLoadBalanceInfo"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionLoadBalanceInfo"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool LoadBalanceInfo { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRenderingEngine"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRenderingEngine"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RenderingEngine { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUseConsoleSession"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUseConsoleSession"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool UseConsoleSession { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUseCredSsp"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUseCredSsp"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool UseCredSsp { get; set; } - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameLoadBalanceInfo"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionLoadBalanceInfo"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool LoadBalanceInfo {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRenderingEngine"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRenderingEngine"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RenderingEngine {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUseConsoleSession"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUseConsoleSession"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool UseConsoleSession {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUseCredSsp"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUseCredSsp"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool UseCredSsp {get; set;} #endregion + #region RD Gateway - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUsageMethod"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayUsageMethod"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayUsageMethod {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayHostname"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayHostname"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayHostname {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUseConnectionCredentials"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayUseConnectionCredentials"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayUseConnectionCredentials {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUsername"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayUsername"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayUsername {get; set;} - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayPassword"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayPassword"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayPassword {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayDomain"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayDomain"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] - public bool RDGatewayDomain {get; set;} + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUsageMethod"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayUsageMethod"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayUsageMethod { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayHostname"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayHostname"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayHostname { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUseConnectionCredentials"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute( + "strPropertyDescriptionRDGatewayUseConnectionCredentials"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayUseConnectionCredentials { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayUsername"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayUsername"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayUsername { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayPassword"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayPassword"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayPassword { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 5), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDGatewayDomain"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDGatewayDomain"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RDGatewayDomain { get; set; } + #endregion + #region Appearance - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameResolution"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionResolution"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Resolution {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAutomaticResize"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAutomaticResize"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool AutomaticResize {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameColors"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionColors"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool Colors {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameCacheBitmaps"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionCacheBitmaps"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool CacheBitmaps {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDisplayWallpaper"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDisplayWallpaper"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool DisplayWallpaper {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDisplayThemes"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDisplayThemes"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool DisplayThemes {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEnableFontSmoothing"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEnableFontSmoothing"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool EnableFontSmoothing {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEnableDesktopComposition"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEnableEnableDesktopComposition"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool EnableDesktopComposition {get; set;} + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameResolution"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionResolution"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Resolution { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAutomaticResize"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAutomaticResize"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool AutomaticResize { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameColors"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionColors"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool Colors { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameCacheBitmaps"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionCacheBitmaps"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool CacheBitmaps { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDisplayWallpaper"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDisplayWallpaper"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool DisplayWallpaper { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameDisplayThemes"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionDisplayThemes"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool DisplayThemes { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEnableFontSmoothing"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEnableFontSmoothing"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool EnableFontSmoothing { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 6), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEnableDesktopComposition"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute( + "strPropertyDescriptionEnableEnableDesktopComposition"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool EnableDesktopComposition { get; set; } #endregion + #region Redirect - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectKeys"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectKeys"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectKeys {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectDrives"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectDrives"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectDiskDrives {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPrinters"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPrinters"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPrinters {get; set;} [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectClipboard"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectClipboard"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectClipboard { get; set; } - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPorts"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPorts"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPorts {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectSmartCards"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectSmartCards"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectSmartCards {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectSounds"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectSounds"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectSound {get; set;} + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectKeys"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectKeys"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectKeys { get; set; } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameSoundQuality"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionSoundQuality"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectDrives"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectDrives"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectDiskDrives { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPrinters"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPrinters"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectPrinters { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectClipboard"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectClipboard"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectClipboard { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPorts"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPorts"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectPorts { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectSmartCards"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectSmartCards"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectSmartCards { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectSounds"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectSounds"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectSound { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameSoundQuality"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionSoundQuality"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool SoundQuality { get; set; } + #endregion + #region Misc - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalToolBefore"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalToolBefore"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool PreExtApp {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalToolAfter"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalToolAfter"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool PostExtApp {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameMACAddress"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionMACAddress"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool MacAddress {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUser1"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUser1"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool UserField {get; set;} + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalToolBefore"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalToolBefore"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool PreExtApp { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameExternalToolAfter"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionExternalToolAfter"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool PostExtApp { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameMACAddress"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionMACAddress"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool MacAddress { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 8), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameUser1"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionUser1"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool UserField { get; set; } + #endregion + #region VNC - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameCompression"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionCompression"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCCompression {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEncoding"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEncoding"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCEncoding {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationMode"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationMode"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCAuthMode {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyType"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyType"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCProxyType {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyAddress"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyAddress"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCProxyIP {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyPort"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyPort"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCProxyPort {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyUsername"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyUsername"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCProxyUsername {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyPassword"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyPassword"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCProxyPassword {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameColors"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionColors"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCColors {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameSmartSizeMode"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionSmartSizeMode"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCSmartSizeMode {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), - LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameViewOnly"), - LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionViewOnly"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool VNCViewOnly {get; set;} - #endregion - - [Browsable(false)] - public object Parent {get; set;} - #endregion - - public ConnectionInfoInheritance(object parent, bool ignoreDefaultInheritance = false) - { + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameCompression"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionCompression"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCCompression { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameEncoding"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionEncoding"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCEncoding { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationMode"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationMode"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCAuthMode { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyType"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyType"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCProxyType { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyAddress"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyAddress"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCProxyIP { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyPort"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyPort"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCProxyPort { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyUsername"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyUsername"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCProxyUsername { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameVNCProxyPassword"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionVNCProxyPassword"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCProxyPassword { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameColors"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionColors"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCColors { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameSmartSizeMode"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionSmartSizeMode"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCSmartSizeMode { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 9), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameViewOnly"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionViewOnly"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool VNCViewOnly { get; set; } + + #endregion + + [Browsable(false)] public object Parent { get; set; } + + #endregion + + + public ConnectionInfoInheritance(object parent, bool ignoreDefaultInheritance = false) + { Parent = parent; - if (!ignoreDefaultInheritance) - SetAllValues(DefaultConnectionInheritance.Instance); - } + if (!ignoreDefaultInheritance) + SetAllValues(DefaultConnectionInheritance.Instance); + } - public ConnectionInfoInheritance Clone() - { - var newInheritance = (ConnectionInfoInheritance) MemberwiseClone(); - newInheritance._tempInheritanceStorage = null; + public ConnectionInfoInheritance Clone() + { + var newInheritance = (ConnectionInfoInheritance)MemberwiseClone(); + newInheritance._tempInheritanceStorage = null; return newInheritance; - } + } public void EnableInheritance() { @@ -364,14 +437,14 @@ namespace mRemoteNG.Connection } public void TurnOnInheritanceCompletely() - { - SetAllValues(true); - } - - public void TurnOffInheritanceCompletely() - { - SetAllValues(false); - } + { + SetAllValues(true); + } + + public void TurnOffInheritanceCompletely() + { + SetAllValues(false); + } private bool EverythingIsInherited() { @@ -389,13 +462,13 @@ namespace mRemoteNG.Connection private bool FilterProperty(PropertyInfo propertyInfo) { - var exclusions = new[] { "EverythingInherited", "Parent" }; + var exclusions = new[] {"EverythingInherited", "Parent"}; var valueShouldNotBeFiltered = !exclusions.Contains(propertyInfo.Name); return valueShouldNotBeFiltered; } - private void SetAllValues(bool value) - { + private void SetAllValues(bool value) + { var properties = GetProperties(); foreach (var property in properties) { @@ -404,7 +477,7 @@ namespace mRemoteNG.Connection } } - private void SetAllValues(ConnectionInfoInheritance otherInheritanceObject) + private void SetAllValues(ConnectionInfoInheritance otherInheritanceObject) { var properties = GetProperties(); foreach (var property in properties) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 3e61d3812..635ccaed5 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -20,6 +20,7 @@ namespace mRemoteNG.Connection private readonly List _activeConnections = new List(); public IEnumerable ActiveConnections => _activeConnections; + public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) { OpenConnection(containerInfo, force, null); @@ -61,6 +62,7 @@ namespace mRemoteNG.Connection } #region Private + private void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm) { var children = containerInfo.Children; @@ -80,7 +82,8 @@ namespace mRemoteNG.Connection { if (connectionInfo.Hostname == "" && connectionInfo.Protocol != ProtocolType.IntApp) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, Language.strConnectionOpenFailedNoHostname); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + Language.strConnectionOpenFailedNoHostname); return; } @@ -142,24 +145,26 @@ namespace mRemoteNG.Connection // the new structure is ConnectionWindow.Controls[0].ActiveDocument.Controls[0] // DockPanel InterfaceControl if (!(Runtime.WindowList[i] is ConnectionWindow connectionWindow)) continue; - if(connectionWindow.Controls.Count < 1) continue; + if (connectionWindow.Controls.Count < 1) continue; if (!(connectionWindow.Controls[0] is DockPanel cwDp)) continue; foreach (var dockContent in cwDp.Documents) { - var tab = (ConnectionTab) dockContent; + var tab = (ConnectionTab)dockContent; var ic = InterfaceControl.FindInterfaceControl(tab); if (ic == null) continue; if (ic.Info == connectionInfo) return ic; } } + return null; } private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force) { string connectionPanel; - if (connectionInfo.Panel == "" || force.HasFlag(ConnectionInfo.Force.OverridePanel) || Settings.Default.AlwaysShowPanelSelectionDlg) + if (connectionInfo.Panel == "" || force.HasFlag(ConnectionInfo.Force.OverridePanel) || + Settings.Default.AlwaysShowPanelSelectionDlg) { var frmPnl = new FrmChoosePanel(); if (frmPnl.ShowDialog() == DialogResult.OK) @@ -174,15 +179,16 @@ namespace mRemoteNG.Connection else { //Return the current panel if exist, if not return default panel - if(TabHelper.Instance.CurrentPanel != null) + if (TabHelper.Instance.CurrentPanel != null) { connectionPanel = TabHelper.Instance.CurrentPanel.TabText; } else { connectionPanel = connectionInfo.Panel; - } + } } + return connectionPanel; } @@ -207,9 +213,9 @@ namespace mRemoteNG.Connection var extT = Runtime.ExternalToolsService.GetExtAppByName(connectionInfo.ExtApp); - if(extT == null) return connectionContainer; + if (extT == null) return connectionContainer; - if(extT.Icon != null) + if (extT.Icon != null) ((ConnectionTab)connectionContainer).Icon = extT.Icon; return connectionContainer; @@ -220,7 +226,7 @@ namespace mRemoteNG.Connection newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed; } - private void SetConnectionEventHandlers(ProtocolBase newProtocol) + private void SetConnectionEventHandlers(ProtocolBase newProtocol) { newProtocol.Disconnected += Prot_Event_Disconnected; newProtocol.Connected += Prot_Event_Connected; @@ -228,13 +234,17 @@ namespace mRemoteNG.Connection newProtocol.ErrorOccured += Prot_Event_ErrorOccured; } - private static void BuildConnectionInterfaceController(ConnectionInfo connectionInfo, ProtocolBase newProtocol, Control connectionContainer) + private static void BuildConnectionInterfaceController(ConnectionInfo connectionInfo, + ProtocolBase newProtocol, + Control connectionContainer) { newProtocol.InterfaceControl = new InterfaceControl(connectionContainer, newProtocol, connectionInfo); } + #endregion #region Event handlers + private static void Prot_Event_Disconnected(object sender, string disconnectedMessage, int? reasonCode) { try @@ -251,11 +261,11 @@ namespace mRemoteNG.Connection } Runtime.MessageCollector.AddMessage(msgClass, - string.Format( - Language.strProtocolEventDisconnected, - disconnectedMessage, - prot.InterfaceControl.Info.Hostname, - prot.InterfaceControl.Info.Protocol.ToString())); + string.Format( + Language.strProtocolEventDisconnected, + disconnectedMessage, + prot.InterfaceControl.Info.Hostname, + prot.InterfaceControl.Info.Protocol.ToString())); } catch (Exception ex) { @@ -268,16 +278,21 @@ namespace mRemoteNG.Connection try { var prot = (ProtocolBase)sender; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent, true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent, + true); string connDetail; - if (prot.InterfaceControl.Info.Hostname == "" && prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp) + if (prot.InterfaceControl.Info.Hostname == "" && + prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp) connDetail = prot.InterfaceControl.Info.ExtApp; else if (prot.InterfaceControl.Info.Hostname != "") connDetail = prot.InterfaceControl.Info.Hostname; else connDetail = "UNKNOWN"; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, prot.InterfaceControl.Info.Protocol, Environment.UserName)); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strConnenctionClosedByUser, connDetail, + prot.InterfaceControl.Info.Protocol, + Environment.UserName)); prot.InterfaceControl.Info.OpenConnections.Remove(prot); if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID)) _activeConnections.Remove(prot.InterfaceControl.Info.ConstantID); @@ -295,21 +310,27 @@ namespace mRemoteNG.Connection private static void Prot_Event_Connected(object sender) { var prot = (ProtocolBase)sender; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected, true); - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strConnectionEventConnectedDetail, prot.InterfaceControl.Info.Hostname, prot.InterfaceControl.Info.Protocol, Environment.UserName, prot.InterfaceControl.Info.Description, prot.InterfaceControl.Info.UserField)); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected, + true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strConnectionEventConnectedDetail, + prot.InterfaceControl.Info.Hostname, + prot.InterfaceControl.Info.Protocol, Environment.UserName, + prot.InterfaceControl.Info.Description, + prot.InterfaceControl.Info.UserField)); } private static void Prot_Event_ErrorOccured(object sender, string errorMessage, int? errorCode) { try { - var prot = (ProtocolBase) sender; + var prot = (ProtocolBase)sender; var msg = string.Format( - Language.strConnectionEventErrorOccured, - errorMessage, - prot.InterfaceControl.Info.Hostname, - errorCode?.ToString() ?? "-"); + Language.strConnectionEventErrorOccured, + errorMessage, + prot.InterfaceControl.Info.Hostname, + errorCode?.ToString() ?? "-"); Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, msg); } catch (Exception ex) @@ -317,6 +338,7 @@ namespace mRemoteNG.Connection Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionEventConnectionFailed, ex); } } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Connection/ConnectionsService.cs b/mRemoteV1/Connection/ConnectionsService.cs index 5fe7c8550..fc6382a24 100644 --- a/mRemoteV1/Connection/ConnectionsService.cs +++ b/mRemoteV1/Connection/ConnectionsService.cs @@ -45,7 +45,8 @@ namespace mRemoteNG.Connection _puttySessionsManager = puttySessionsManager; var path = SettingsFileInfo.SettingsPath; - _localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml")); + _localConnectionPropertiesDataProvider = + new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml")); _localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer(); } @@ -76,7 +77,9 @@ namespace mRemoteNG.Connection var newConnectionInfo = new ConnectionInfo(); newConnectionInfo.CopyFrom(DefaultConnectionInfo.Instance); - newConnectionInfo.Name = Settings.Default.IdentifyQuickConnectTabs ? string.Format(Language.strQuick, uriBuilder.Host) : uriBuilder.Host; + newConnectionInfo.Name = Settings.Default.IdentifyQuickConnectTabs + ? string.Format(Language.strQuick, uriBuilder.Host) + : uriBuilder.Host; newConnectionInfo.Protocol = protocol; newConnectionInfo.Hostname = uriBuilder.Host; @@ -116,7 +119,8 @@ namespace mRemoteNG.Connection var oldIsUsingDatabaseValue = UsingDatabase; var connectionLoader = useDatabase - ? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer, _localConnectionPropertiesDataProvider) + ? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer, + _localConnectionPropertiesDataProvider) : new XmlConnectionsLoader(connectionFileName); var newConnectionTreeModel = connectionLoader.Load(); @@ -126,7 +130,8 @@ namespace mRemoteNG.Connection if (newConnectionTreeModel == null) { - DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded); + DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", + IsConnectionsFileLoaded); return; } @@ -142,8 +147,10 @@ namespace mRemoteNG.Connection ConnectionTreeModel = newConnectionTreeModel; UpdateCustomConsPathSetting(connectionFileName); - RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName); - Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Connections loaded using {connectionLoader.GetType().Name}"); + RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, + useDatabase, connectionFileName); + Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, + $"Connections loaded using {connectionLoader.GetType().Name}"); } /// @@ -168,7 +175,7 @@ namespace mRemoteNG.Connection if (_saveAsyncRequested) SaveConnectionsAsync(); - else if(_saveRequested) + else if (_saveRequested) SaveConnections(); } @@ -194,13 +201,12 @@ namespace mRemoteNG.Connection /// Optional. The name of the property that triggered /// this save. /// - public void SaveConnections( - ConnectionTreeModel connectionTreeModel, - bool useDatabase, - SaveFilter saveFilter, - string connectionFileName, - bool forceSave = false, - string propertyNameTrigger = "") + public void SaveConnections(ConnectionTreeModel connectionTreeModel, + bool useDatabase, + SaveFilter saveFilter, + string connectionFileName, + bool forceSave = false, + string propertyNameTrigger = "") { if (connectionTreeModel == null) return; @@ -222,8 +228,9 @@ namespace mRemoteNG.Connection var previouslyUsingDatabase = UsingDatabase; var saver = useDatabase - ? (ISaver)new SqlConnectionsSaver(saveFilter, _localConnectionPropertiesSerializer, - _localConnectionPropertiesDataProvider) + ? (ISaver)new SqlConnectionsSaver(saveFilter, + _localConnectionPropertiesSerializer, + _localConnectionPropertiesDataProvider) : new XmlConnectionsSaver(connectionFileName, saveFilter); saver.Save(connectionTreeModel, propertyNameTrigger); @@ -233,12 +240,15 @@ namespace mRemoteNG.Connection UsingDatabase = useDatabase; ConnectionFileName = connectionFileName; - RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName); + RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, + connectionFileName); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections"); } catch (Exception ex) { - Runtime.MessageCollector?.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotSaveAs, connectionFileName), ex, logOnly:false); + Runtime.MessageCollector?.AddExceptionMessage( + string.Format(Language.strConnectionsFileCouldNotSaveAs, + connectionFileName), ex, logOnly: false); } finally { @@ -266,11 +276,11 @@ namespace mRemoteNG.Connection lock (SaveLock) { SaveConnections( - ConnectionTreeModel, - UsingDatabase, - new SaveFilter(), - ConnectionFileName, - propertyNameTrigger: propertyNameTrigger); + ConnectionTreeModel, + UsingDatabase, + new SaveFilter(), + ConnectionFileName, + propertyNameTrigger: propertyNameTrigger); } }); t.SetApartmentState(ApartmentState.STA); @@ -279,15 +289,15 @@ namespace mRemoteNG.Connection public string GetStartupConnectionFileName() { - return Settings.Default.LoadConsFromCustomLocation == false - ? GetDefaultStartupConnectionFileName() + return Settings.Default.LoadConsFromCustomLocation == false + ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath; } public string GetDefaultStartupConnectionFileName() { - return Runtime.IsPortableEdition - ? GetDefaultStartupConnectionFileNamePortableEdition() + return Runtime.IsPortableEdition + ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition(); } @@ -307,9 +317,9 @@ namespace mRemoteNG.Connection private string GetDefaultStartupConnectionFileNameNormalEdition() { var appDataPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - Application.ProductName, - ConnectionsFileInfo.DefaultConnectionsFile); + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + Application.ProductName, + ConnectionsFileInfo.DefaultConnectionsFile); return File.Exists(appDataPath) ? appDataPath : GetDefaultStartupConnectionFileNamePortableEdition(); } @@ -319,25 +329,35 @@ namespace mRemoteNG.Connection } #region Events + public event EventHandler ConnectionsLoaded; public event EventHandler ConnectionsSaved; - private void RaiseConnectionsLoadedEvent(Optional previousTreeModel, ConnectionTreeModel newTreeModel, - bool previousSourceWasDatabase, bool newSourceIsDatabase, - string newSourcePath) + private void RaiseConnectionsLoadedEvent(Optional previousTreeModel, + ConnectionTreeModel newTreeModel, + bool previousSourceWasDatabase, + bool newSourceIsDatabase, + string newSourcePath) { ConnectionsLoaded?.Invoke(this, new ConnectionsLoadedEventArgs( - previousTreeModel, - newTreeModel, - previousSourceWasDatabase, - newSourceIsDatabase, - newSourcePath)); + previousTreeModel, + newTreeModel, + previousSourceWasDatabase, + newSourceIsDatabase, + newSourcePath)); } - private void RaiseConnectionsSavedEvent(ConnectionTreeModel modelThatWasSaved, bool previouslyUsingDatabase, bool usingDatabase, string connectionFileName) + private void RaiseConnectionsSavedEvent(ConnectionTreeModel modelThatWasSaved, + bool previouslyUsingDatabase, + bool usingDatabase, + string connectionFileName) { - ConnectionsSaved?.Invoke(this, new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase, usingDatabase, connectionFileName)); + ConnectionsSaved?.Invoke(this, + new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase, + usingDatabase, + connectionFileName)); } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Connection/DefaultConnectionInfo.cs b/mRemoteV1/Connection/DefaultConnectionInfo.cs index 9a4df225c..72a089b58 100644 --- a/mRemoteV1/Connection/DefaultConnectionInfo.cs +++ b/mRemoteV1/Connection/DefaultConnectionInfo.cs @@ -5,36 +5,38 @@ using mRemoteNG.App; namespace mRemoteNG.Connection { - public class DefaultConnectionInfo : ConnectionInfo + public class DefaultConnectionInfo : ConnectionInfo { public static DefaultConnectionInfo Instance { get; } = new DefaultConnectionInfo(); private DefaultConnectionInfo() { IsDefault = true; - Inheritance = DefaultConnectionInheritance.Instance; + Inheritance = DefaultConnectionInheritance.Instance; } public void LoadFrom(TSource sourceInstance, Func propertyNameMutator = null) { if (propertyNameMutator == null) - propertyNameMutator = a => a; + propertyNameMutator = a => a; var connectionProperties = GetSerializableProperties(); foreach (var property in connectionProperties) { try { - var expectedPropertyName = propertyNameMutator(property.Name); - var propertyFromSource = typeof(TSource).GetProperty(expectedPropertyName); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromSource = typeof(TSource).GetProperty(expectedPropertyName); if (propertyFromSource == null) - throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + throw new SettingsPropertyNotFoundException( + $"No property with name '{expectedPropertyName}' found."); + + var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); - var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); - if (property.PropertyType.IsEnum) { - property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), null); + property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), + null); continue; } @@ -42,15 +44,18 @@ namespace mRemoteNG.Connection } catch (Exception ex) { - Runtime.MessageCollector?.AddExceptionStackTrace($"Error loading default connectioninfo property {property.Name}", ex); + Runtime.MessageCollector?.AddExceptionStackTrace( + $"Error loading default connectioninfo property {property.Name}", + ex); } } } - public void SaveTo(TDestination destinationInstance, Func propertyNameMutator = null) + public void SaveTo(TDestination destinationInstance, + Func propertyNameMutator = null) { if (propertyNameMutator == null) - propertyNameMutator = (a) => a; + propertyNameMutator = (a) => a; var connectionProperties = GetSerializableProperties(); @@ -58,20 +63,24 @@ namespace mRemoteNG.Connection { try { - var expectedPropertyName = propertyNameMutator(property.Name); - var propertyFromDestination = typeof(TDestination).GetProperty(expectedPropertyName); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromDestination = typeof(TDestination).GetProperty(expectedPropertyName); - if (propertyFromDestination == null) - throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + if (propertyFromDestination == null) + throw new SettingsPropertyNotFoundException( + $"No property with name '{expectedPropertyName}' found."); - // ensure value is of correct type - var value = Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType); + // ensure value is of correct type + var value = Convert.ChangeType(property.GetValue(Instance, null), + propertyFromDestination.PropertyType); propertyFromDestination.SetValue(destinationInstance, value, null); } catch (Exception ex) { - Runtime.MessageCollector?.AddExceptionStackTrace($"Error saving default connectioninfo property {property.Name}", ex); + Runtime.MessageCollector?.AddExceptionStackTrace( + $"Error saving default connectioninfo property {property.Name}", + ex); } } } diff --git a/mRemoteV1/Connection/DefaultConnectionInheritance.cs b/mRemoteV1/Connection/DefaultConnectionInheritance.cs index b55ca8634..8e2d8e82b 100644 --- a/mRemoteV1/Connection/DefaultConnectionInheritance.cs +++ b/mRemoteV1/Connection/DefaultConnectionInheritance.cs @@ -13,10 +13,11 @@ namespace mRemoteNG.Connection } static DefaultConnectionInheritance() - { } + { + } - public void LoadFrom(TSource sourceInstance, Func propertyNameMutator = null) + public void LoadFrom(TSource sourceInstance, Func propertyNameMutator = null) { if (propertyNameMutator == null) propertyNameMutator = a => a; var inheritanceProperties = GetProperties(); @@ -26,15 +27,18 @@ namespace mRemoteNG.Connection if (propertyFromSettings == null) { Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - $"DefaultConInherit-LoadFrom: Could not load {property.Name}", true); + $"DefaultConInherit-LoadFrom: Could not load {property.Name}", + true); continue; } + var valueFromSettings = propertyFromSettings.GetValue(sourceInstance, null); property.SetValue(Instance, valueFromSettings, null); } } - public void SaveTo(TDestination destinationInstance, Func propertyNameMutator = null) + public void SaveTo(TDestination destinationInstance, + Func propertyNameMutator = null) { if (propertyNameMutator == null) propertyNameMutator = a => a; var inheritanceProperties = GetProperties(); @@ -45,9 +49,11 @@ namespace mRemoteNG.Connection if (propertyFromSettings == null) { Runtime.MessageCollector?.AddMessage(Messages.MessageClass.ErrorMsg, - $"DefaultConInherit-SaveTo: Could not load {property.Name}", true); + $"DefaultConInherit-SaveTo: Could not load {property.Name}", + true); continue; } + propertyFromSettings.SetValue(destinationInstance, localValue, null); } } diff --git a/mRemoteV1/Connection/InterfaceControl.cs b/mRemoteV1/Connection/InterfaceControl.cs index 733f03a9a..b21c31b8d 100644 --- a/mRemoteV1/Connection/InterfaceControl.cs +++ b/mRemoteV1/Connection/InterfaceControl.cs @@ -9,29 +9,31 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Connection { - public sealed partial class InterfaceControl + public sealed partial class InterfaceControl { public ProtocolBase Protocol { get; set; } - public ConnectionInfo Info { get; set; } + public ConnectionInfo Info { get; set; } - public InterfaceControl(Control parent, ProtocolBase protocol, ConnectionInfo info) - { - try - { - Protocol = protocol; - Info = info; + public InterfaceControl(Control parent, ProtocolBase protocol, ConnectionInfo info) + { + try + { + Protocol = protocol; + Info = info; Parent = parent; Location = new Point(0, 0); Size = Parent.Size; Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; - InitializeComponent(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t create new InterfaceControl" + Environment.NewLine + ex.Message); - } - } + InitializeComponent(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "Couldn\'t create new InterfaceControl" + Environment.NewLine + + ex.Message); + } + } public static InterfaceControl FindInterfaceControl(DockPanel DockPnl) { diff --git a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTP.cs b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTP.cs index cbdaca2fd..3ebf3007b 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTP.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTP.cs @@ -1,17 +1,16 @@ namespace mRemoteNG.Connection.Protocol.Http { - public class ProtocolHTTP : HTTPBase - { - - public ProtocolHTTP(RenderingEngine RenderingEngine) : base(RenderingEngine) - { + public class ProtocolHTTP : HTTPBase + { + public ProtocolHTTP(RenderingEngine RenderingEngine) : base(RenderingEngine) + { httpOrS = "http"; defaultPort = (int)Defaults.Port; } - - public enum Defaults - { - Port = 80 - } - } -} + + public enum Defaults + { + Port = 80 + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs index 6b7f9ba36..fb43826d5 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs @@ -7,60 +7,62 @@ using mRemoteNG.App; namespace mRemoteNG.Connection.Protocol.Http { - public class HTTPBase : ProtocolBase - { + public class HTTPBase : ProtocolBase + { #region Private Properties - private Control wBrowser; - protected string httpOrS; - protected int defaultPort; - private string tabTitle; + + private Control wBrowser; + protected string httpOrS; + protected int defaultPort; + private string tabTitle; + #endregion - + #region Public Methods - protected HTTPBase(RenderingEngine RenderingEngine) - { - try - { - if (RenderingEngine == RenderingEngine.Gecko) - { - if(!Xpcom.IsInitialized) + protected HTTPBase(RenderingEngine RenderingEngine) + { + try + { + if (RenderingEngine == RenderingEngine.Gecko) + { + if (!Xpcom.IsInitialized) Xpcom.Initialize("Firefox"); Control = new GeckoWebBrowser(); - } - else - { + } + else + { Control = new WebBrowser(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpConnectionFailed, ex); - } - } - - public override bool Initialize() - { - base.Initialize(); - - try - { - var objTabPage = InterfaceControl.Parent as TabPage; - // if (objTabPage != null) tabTitle = objTabPage.Title; - } - catch (Exception) - { + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpConnectionFailed, ex); + } + } + + public override bool Initialize() + { + base.Initialize(); + + try + { + var objTabPage = InterfaceControl.Parent as TabPage; + // if (objTabPage != null) tabTitle = objTabPage.Title; + } + catch (Exception) + { tabTitle = ""; - } - - try - { + } + + try + { wBrowser = Control; - - if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) - { - var GeckoBrowser = (GeckoWebBrowser) wBrowser; + + if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) + { + var GeckoBrowser = (GeckoWebBrowser)wBrowser; if (GeckoBrowser != null) { GeckoBrowser.DocumentTitleChanged += geckoBrowser_DocumentTitleChanged; @@ -72,31 +74,31 @@ namespace mRemoteNG.Connection.Protocol.Http } } else - { + { var objWebBrowser = (WebBrowser)wBrowser; - objWebBrowser.ScrollBarsEnabled = true; + objWebBrowser.ScrollBarsEnabled = true; // http://stackoverflow.com/questions/4655662/how-to-ignore-script-errors-in-webbrowser objWebBrowser.ScriptErrorsSuppressed = true; objWebBrowser.Navigated += wBrowser_Navigated; - objWebBrowser.DocumentTitleChanged += wBrowser_DocumentTitleChanged; - } - - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpSetPropsFailed, ex); - return false; - } - } - - public override bool Connect() - { - try - { - var strHost = InterfaceControl.Info.Hostname; + objWebBrowser.DocumentTitleChanged += wBrowser_DocumentTitleChanged; + } + + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpSetPropsFailed, ex); + return false; + } + } + + public override bool Connect() + { + try + { + var strHost = InterfaceControl.Info.Hostname; /* * Commenting out since this codes doesn't actually do anything at this time... * Possibly related to MR-221 and/or MR-533 ???? @@ -107,117 +109,120 @@ namespace mRemoteNG.Connection.Protocol.Http { strAuth = "Authorization: Basic " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(InterfaceControl.Info.Username + ":" + InterfaceControl.Info.Password)) + Environment.NewLine; } - */ - if (InterfaceControl.Info.Port != defaultPort) - { - if (strHost.EndsWith("/")) - { - strHost = strHost.Substring(0, strHost.Length - 1); - } - - if (strHost.Contains(httpOrS + "://") == false) - { - strHost = httpOrS + "://" + strHost; - } - - if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) - { + */ + if (InterfaceControl.Info.Port != defaultPort) + { + if (strHost.EndsWith("/")) + { + strHost = strHost.Substring(0, strHost.Length - 1); + } + + if (strHost.Contains(httpOrS + "://") == false) + { + strHost = httpOrS + "://" + strHost; + } + + if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) + { ((GeckoWebBrowser)wBrowser).Navigate(strHost + ":" + InterfaceControl.Info.Port); - } - else - { + } + else + { ((WebBrowser)wBrowser).Navigate(strHost + ":" + InterfaceControl.Info.Port); - } - } - else - { - if (strHost.Contains(httpOrS + "://") == false) - { - strHost = httpOrS + "://" + strHost; - } - - if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) - { - ((GeckoWebBrowser)wBrowser).Navigate(strHost); - } - else - { + } + } + else + { + if (strHost.Contains(httpOrS + "://") == false) + { + strHost = httpOrS + "://" + strHost; + } + + if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) + { + ((GeckoWebBrowser)wBrowser).Navigate(strHost); + } + else + { ((WebBrowser)wBrowser).Navigate(strHost); - } - } - - base.Connect(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpConnectFailed, ex); - return false; - } - } + } + } + + base.Connect(); + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpConnectFailed, ex); + return false; + } + } + #endregion - + #region Private Methods + #endregion - + #region Events - private void wBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e) - { - var objWebBrowser = wBrowser as WebBrowser; - if (objWebBrowser == null) return; - - // This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise. - objWebBrowser.AllowWebBrowserDrop = false; - - objWebBrowser.Navigated -= wBrowser_Navigated; - } + + private void wBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e) + { + var objWebBrowser = wBrowser as WebBrowser; + if (objWebBrowser == null) return; + + // This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise. + objWebBrowser.AllowWebBrowserDrop = false; + + objWebBrowser.Navigated -= wBrowser_Navigated; + } private void wBrowser_DocumentTitleChanged(object sender, EventArgs e) - { - try - { - var tabP = InterfaceControl.Parent as TabPage; + { + try + { + var tabP = InterfaceControl.Parent as TabPage; - if (tabP == null) return; - string shortTitle; - - if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) - { - if (((GeckoWebBrowser) wBrowser).DocumentTitle.Length >= 15) - { - shortTitle = ((GeckoWebBrowser) wBrowser).DocumentTitle.Substring(0, 10) + "..."; - } - else - { - shortTitle = ((GeckoWebBrowser) wBrowser).DocumentTitle; - } - } - else - { - if (((WebBrowser) wBrowser).DocumentTitle.Length >= 15) - { - shortTitle = ((WebBrowser) wBrowser).DocumentTitle.Substring(0, 10) + "..."; - } - else - { - shortTitle = ((WebBrowser) wBrowser).DocumentTitle; - } - } - - /* if (!string.IsNullOrEmpty(tabTitle)) - { - tabP.Title = tabTitle + @" - " + shortTitle; - } - else - { - tabP.Title = shortTitle; - }*/ - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpDocumentTileChangeFailed, ex); - } - } + if (tabP == null) return; + string shortTitle; + + if (InterfaceControl.Info.RenderingEngine == RenderingEngine.Gecko) + { + if (((GeckoWebBrowser)wBrowser).DocumentTitle.Length >= 15) + { + shortTitle = ((GeckoWebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "..."; + } + else + { + shortTitle = ((GeckoWebBrowser)wBrowser).DocumentTitle; + } + } + else + { + if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15) + { + shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "..."; + } + else + { + shortTitle = ((WebBrowser)wBrowser).DocumentTitle; + } + } + + /* if (!string.IsNullOrEmpty(tabTitle)) + { + tabP.Title = tabTitle + @" - " + shortTitle; + } + else + { + tabP.Title = shortTitle; + }*/ + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpDocumentTileChangeFailed, ex); + } + } private void geckoBrowser_DocumentTitleChanged(object sender, EventArgs e) @@ -233,50 +238,53 @@ namespace mRemoteNG.Connection.Protocol.Http { if (((GeckoWebBrowser)wBrowser).DocumentTitle.Length >= 15) { - shortTitle = ((GeckoWebBrowser) wBrowser).DocumentTitle.Substring(0, 10) + "..."; + shortTitle = ((GeckoWebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "..."; } else { - shortTitle = ((GeckoWebBrowser) wBrowser).DocumentTitle; + shortTitle = ((GeckoWebBrowser)wBrowser).DocumentTitle; } } else { - if (((WebBrowser) wBrowser).DocumentTitle.Length >= 15) + if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15) { - shortTitle = ((WebBrowser) wBrowser).DocumentTitle.Substring(0, 10) + "..."; + shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "..."; } else { - shortTitle = ((WebBrowser) wBrowser).DocumentTitle; + shortTitle = ((WebBrowser)wBrowser).DocumentTitle; } } - /* if (!string.IsNullOrEmpty(tabTitle)) - { - tabP.Title = tabTitle + @" - " + shortTitle; - } - else - { - tabP.Title = shortTitle; - }*/ + /* if (!string.IsNullOrEmpty(tabTitle)) + { + tabP.Title = tabTitle + @" - " + shortTitle; + } + else + { + tabP.Title = shortTitle; + }*/ } catch (Exception ex) { Runtime.MessageCollector.AddExceptionStackTrace(Language.strHttpDocumentTileChangeFailed, ex); } } -#endregion - -#region Enums - public enum RenderingEngine - { + + #endregion + + #region Enums + + public enum RenderingEngine + { [LocalizedAttributes.LocalizedDescription("strHttpInternetExplorer")] IE = 1, + [LocalizedAttributes.LocalizedDescription("strHttpGecko")] Gecko = 2 - } + } -#endregion - } -} + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.CertEvent.cs b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.CertEvent.cs index 086d8b495..5e9f13223 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.CertEvent.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.CertEvent.cs @@ -4,6 +4,7 @@ using mRemoteNG.App; using mRemoteNG.App.Info; using mRemoteNG.Messages; using mRemoteNG.UI.TaskDialog; + // ReSharper disable RedundantAssignment namespace mRemoteNG.Connection.Protocol.Http @@ -26,15 +27,17 @@ namespace mRemoteNG.Connection.Protocol.Http string[] commandButtons = { - Language.strHttpsInsecureAllowOnce, // 0 - Language.strHttpsInsecureAllowAlways, // 1 - Language.strHttpsInsecureDontAllow // 2 + Language.strHttpsInsecureAllowOnce, // 0 + Language.strHttpsInsecureAllowAlways, // 1 + Language.strHttpsInsecureDontAllow // 2 }; CTaskDialog.ShowTaskDialogBox(null, GeneralAppInfo.ProductName, Language.strHttpsInsecurePromptTitle, - string.Format(Language.strHttpsInsecurePrompt, e.Uri.AbsoluteUri), "", "", "", "", - string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question); - + string.Format(Language.strHttpsInsecurePrompt, e.Uri.AbsoluteUri), "", "", "", + "", + string.Join(" | ", commandButtons), ETaskDialogButtons.None, + ESysIcons.Question, ESysIcons.Question); + var allow = false; var temporary = true; // ReSharper disable once SwitchStatementMissingSomeCases @@ -53,10 +56,11 @@ namespace mRemoteNG.Connection.Protocol.Http temporary = true; // just to be safe break; } - + if (!allow) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"User did not allow navigation to {e.Uri.AbsoluteUri} with an insecure certificate: {e.Message}"); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + $"User did not allow navigation to {e.Uri.AbsoluteUri} with an insecure certificate: {e.Message}"); return; } @@ -65,10 +69,11 @@ namespace mRemoteNG.Connection.Protocol.Http * However, my testing was successful in Gecko 45.0.22 */ CertOverrideService.GetService().RememberValidityOverride(e.Uri, e.Certificate, - CertOverride.Mismatch | CertOverride.Time | CertOverride.Untrusted, temporary); + CertOverride.Mismatch | CertOverride.Time | + CertOverride.Untrusted, temporary); e.Handled = true; ((GeckoWebBrowser)sender).Navigate(e.Uri.AbsoluteUri); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.cs b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.cs index 08f28a927..90f35f5a1 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPS.cs @@ -1,17 +1,16 @@ namespace mRemoteNG.Connection.Protocol.Http { - public class ProtocolHTTPS : HTTPBase - { - - public ProtocolHTTPS(RenderingEngine RenderingEngine) : base(RenderingEngine) - { + public class ProtocolHTTPS : HTTPBase + { + public ProtocolHTTPS(RenderingEngine RenderingEngine) : base(RenderingEngine) + { httpOrS = "https"; defaultPort = (int)Defaults.Port; } - - public enum Defaults - { - Port = 443 - } - } -} + + public enum Defaults + { + Port = 443 + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/ICA/IcaProtocol.cs b/mRemoteV1/Connection/Protocol/ICA/IcaProtocol.cs index 795e6494c..fca5a6179 100644 --- a/mRemoteV1/Connection/Protocol/ICA/IcaProtocol.cs +++ b/mRemoteV1/Connection/Protocol/ICA/IcaProtocol.cs @@ -14,335 +14,369 @@ using System.Windows.Forms; namespace mRemoteNG.Connection.Protocol.ICA { public class IcaProtocol : ProtocolBase - { - private AxICAClient _icaClient; - private ConnectionInfo _info; + { + private AxICAClient _icaClient; + private ConnectionInfo _info; private readonly FrmMain _frmMain = FrmMain.Default; - + #region Public Methods - public IcaProtocol() - { - try - { - Control = new AxICAClient(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaControlFailed + Environment.NewLine + ex.Message, true); - } - } - - public override bool Initialize() - { - base.Initialize(); - - try - { - _icaClient = (AxICAClient)Control; - _info = InterfaceControl.Info; - _icaClient.CreateControl(); - - while (!_icaClient.Created) - { - Thread.Sleep(10); - Application.DoEvents(); - } - _icaClient.Address = _info.Hostname; - SetCredentials(); - SetResolution(); - SetColors(); - SetSecurity(); - - //Disable hotkeys for international users - _icaClient.Hotkey1Shift = null; - _icaClient.Hotkey1Char = null; - _icaClient.Hotkey2Shift = null; - _icaClient.Hotkey2Char = null; - _icaClient.Hotkey3Shift = null; - _icaClient.Hotkey3Char = null; - _icaClient.Hotkey4Shift = null; - _icaClient.Hotkey4Char = null; - _icaClient.Hotkey5Shift = null; - _icaClient.Hotkey5Char = null; - _icaClient.Hotkey6Shift = null; - _icaClient.Hotkey6Char = null; - _icaClient.Hotkey7Shift = null; - _icaClient.Hotkey7Char = null; - _icaClient.Hotkey8Shift = null; - _icaClient.Hotkey8Char = null; - _icaClient.Hotkey9Shift = null; - _icaClient.Hotkey9Char = null; - _icaClient.Hotkey10Shift = null; - _icaClient.Hotkey10Char = null; - _icaClient.Hotkey11Shift = null; - _icaClient.Hotkey11Char = null; - - _icaClient.PersistentCacheEnabled = _info.CacheBitmaps; - _icaClient.Title = _info.Name; - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaSetPropsFailed + Environment.NewLine + ex.Message, true); - return false; - } - } - - public override bool Connect() - { - SetEventHandlers(); - - try - { - _icaClient.Connect(); - base.Connect(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaConnectionFailed + Environment.NewLine + ex.Message); - return false; - } - } + public IcaProtocol() + { + try + { + Control = new AxICAClient(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaControlFailed + Environment.NewLine + ex.Message, + true); + } + } + + public override bool Initialize() + { + base.Initialize(); + + try + { + _icaClient = (AxICAClient)Control; + _info = InterfaceControl.Info; + _icaClient.CreateControl(); + + while (!_icaClient.Created) + { + Thread.Sleep(10); + Application.DoEvents(); + } + + _icaClient.Address = _info.Hostname; + SetCredentials(); + SetResolution(); + SetColors(); + SetSecurity(); + + //Disable hotkeys for international users + _icaClient.Hotkey1Shift = null; + _icaClient.Hotkey1Char = null; + _icaClient.Hotkey2Shift = null; + _icaClient.Hotkey2Char = null; + _icaClient.Hotkey3Shift = null; + _icaClient.Hotkey3Char = null; + _icaClient.Hotkey4Shift = null; + _icaClient.Hotkey4Char = null; + _icaClient.Hotkey5Shift = null; + _icaClient.Hotkey5Char = null; + _icaClient.Hotkey6Shift = null; + _icaClient.Hotkey6Char = null; + _icaClient.Hotkey7Shift = null; + _icaClient.Hotkey7Char = null; + _icaClient.Hotkey8Shift = null; + _icaClient.Hotkey8Char = null; + _icaClient.Hotkey9Shift = null; + _icaClient.Hotkey9Char = null; + _icaClient.Hotkey10Shift = null; + _icaClient.Hotkey10Char = null; + _icaClient.Hotkey11Shift = null; + _icaClient.Hotkey11Char = null; + + _icaClient.PersistentCacheEnabled = _info.CacheBitmaps; + _icaClient.Title = _info.Name; + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaSetPropsFailed + Environment.NewLine + ex.Message, + true); + return false; + } + } + + public override bool Connect() + { + SetEventHandlers(); + + try + { + _icaClient.Connect(); + base.Connect(); + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaConnectionFailed + Environment.NewLine + ex.Message); + return false; + } + } + #endregion - + #region Private Methods - private void SetCredentials() - { - try - { + + private void SetCredentials() + { + try + { if (Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - return; - } + { + return; + } - var user = _info?.Username ?? ""; - var pass = _info?.Password ?? ""; - var dom = _info?.Domain ?? ""; + var user = _info?.Username ?? ""; + var pass = _info?.Password ?? ""; + var dom = _info?.Domain ?? ""; - if (string.IsNullOrEmpty(user)) - { - if (Settings.Default.EmptyCredentials == "windows") - { - _icaClient.Username = Environment.UserName; - } - else if (Settings.Default.EmptyCredentials == "custom") - { - _icaClient.Username = Settings.Default.DefaultUsername; - } - } - else - { - _icaClient.Username = user; - } - - if (string.IsNullOrEmpty(pass)) - { - if (Settings.Default.EmptyCredentials == "custom") - { - if (Settings.Default.DefaultPassword != "") - { + if (string.IsNullOrEmpty(user)) + { + if (Settings.Default.EmptyCredentials == "windows") + { + _icaClient.Username = Environment.UserName; + } + else if (Settings.Default.EmptyCredentials == "custom") + { + _icaClient.Username = Settings.Default.DefaultUsername; + } + } + else + { + _icaClient.Username = user; + } + + if (string.IsNullOrEmpty(pass)) + { + if (Settings.Default.EmptyCredentials == "custom") + { + if (Settings.Default.DefaultPassword != "") + { var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - _icaClient.SetProp("ClearPassword", cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey)); - } - } - } - else - { - _icaClient.SetProp("ClearPassword", pass); - } - - if (string.IsNullOrEmpty(dom)) - { - if (Settings.Default.EmptyCredentials == "windows") - { - _icaClient.Domain = Environment.UserDomainName; - } - else if (Settings.Default.EmptyCredentials == "custom") - { - _icaClient.Domain = Settings.Default.DefaultDomain; - } - } - else - { - _icaClient.Domain = dom; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaSetCredentialsFailed + Environment.NewLine + ex.Message, true); - } - } - - private void SetResolution() - { - try - { - if (Force.HasFlag(ConnectionInfo.Force.Fullscreen)) - { - _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, Screen.FromControl(_frmMain).Bounds.Width, Screen.FromControl(_frmMain).Bounds.Height, 0); - _icaClient.FullScreenWindow(); - - return; - } - - if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.FitToWindow) - { - _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, InterfaceControl.Size.Width, InterfaceControl.Size.Height, 0); - } - else if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.SmartSize) - { - _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, InterfaceControl.Size.Width, InterfaceControl.Size.Height, 0); - } - else if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.Fullscreen) - { - _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, Screen.FromControl(_frmMain).Bounds.Width, Screen.FromControl(_frmMain).Bounds.Height, 0); - _icaClient.FullScreenWindow(); - } - else - { - var resolution = RdpProtocol.GetResolutionRectangle(_info.Resolution); - _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, resolution.Width, resolution.Height, 0); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaSetResolutionFailed + Environment.NewLine + ex.Message, true); - } - } - - private void SetColors() - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (_info.Colors) - { - case RdpProtocol.RDPColors.Colors256: - _icaClient.SetProp("DesiredColor", "2"); - break; - case RdpProtocol.RDPColors.Colors15Bit: - _icaClient.SetProp("DesiredColor", "4"); - break; - case RdpProtocol.RDPColors.Colors16Bit: - _icaClient.SetProp("DesiredColor", "4"); - break; - default: - _icaClient.SetProp("DesiredColor", "8"); - break; - } - } - - private void SetSecurity() - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (_info.ICAEncryptionStrength) - { - case EncryptionStrength.Encr128BitLogonOnly: - _icaClient.Encrypt = true; - _icaClient.EncryptionLevelSession = "EncRC5-0"; - break; - case EncryptionStrength.Encr40Bit: - _icaClient.Encrypt = true; - _icaClient.EncryptionLevelSession = "EncRC5-40"; - break; - case EncryptionStrength.Encr56Bit: - _icaClient.Encrypt = true; - _icaClient.EncryptionLevelSession = "EncRC5-56"; - break; - case EncryptionStrength.Encr128Bit: - _icaClient.Encrypt = true; - _icaClient.EncryptionLevelSession = "EncRC5-128"; - break; - } - } - - private void SetEventHandlers() - { - try - { - _icaClient.OnConnecting += ICAEvent_OnConnecting; - _icaClient.OnConnect += ICAEvent_OnConnected; - _icaClient.OnConnectFailed += ICAEvent_OnConnectFailed; - _icaClient.OnDisconnect += ICAEvent_OnDisconnect; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strIcaSetEventHandlersFailed + Environment.NewLine + ex.Message, true); - } - } - #endregion - - #region Private Events & Handlers - private void ICAEvent_OnConnecting(object sender, EventArgs e) - { - Event_Connecting(this); - } - - private void ICAEvent_OnConnected(object sender, EventArgs e) - { - Event_Connected(this); - } - - private void ICAEvent_OnConnectFailed(object sender, EventArgs e) - { - Event_ErrorOccured(this, e.ToString(), null); - } - - private void ICAEvent_OnDisconnect(object sender, EventArgs e) - { - Event_Disconnected(this, e.ToString(), null); - - if (Settings.Default.ReconnectOnDisconnect) - { - ReconnectGroup = new ReconnectGroup(); - //this.Load += ReconnectGroup_Load; - ReconnectGroup.Left = (int) (((double) Control.Width / 2) - ((double) ReconnectGroup.Width / 2)); - ReconnectGroup.Top = (int) (((double) Control.Height / 2) - ((double) ReconnectGroup.Height / 2)); - ReconnectGroup.Parent = Control; - ReconnectGroup.Show(); - tmrReconnect.Enabled = true; - } - else - { - Close(); - } - } - #endregion - - #region Reconnect Stuff - public void tmrReconnect_Elapsed(object sender, ElapsedEventArgs e) - { - var srvReady = PortScanner.IsPortOpen(_info.Hostname, Convert.ToString(_info.Port)); - - ReconnectGroup.ServerReady = srvReady; + _icaClient.SetProp("ClearPassword", + cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, + Runtime.EncryptionKey)); + } + } + } + else + { + _icaClient.SetProp("ClearPassword", pass); + } + + if (string.IsNullOrEmpty(dom)) + { + if (Settings.Default.EmptyCredentials == "windows") + { + _icaClient.Domain = Environment.UserDomainName; + } + else if (Settings.Default.EmptyCredentials == "custom") + { + _icaClient.Domain = Settings.Default.DefaultDomain; + } + } + else + { + _icaClient.Domain = dom; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaSetCredentialsFailed + Environment.NewLine + + ex.Message, true); + } + } + + private void SetResolution() + { + try + { + if (Force.HasFlag(ConnectionInfo.Force.Fullscreen)) + { + _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, + Screen.FromControl(_frmMain).Bounds.Width, + Screen.FromControl(_frmMain).Bounds.Height, 0); + _icaClient.FullScreenWindow(); + + return; + } + + if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.FitToWindow) + { + _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, InterfaceControl.Size.Width, + InterfaceControl.Size.Height, 0); + } + else if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.SmartSize) + { + _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, InterfaceControl.Size.Width, + InterfaceControl.Size.Height, 0); + } + else if (InterfaceControl.Info.Resolution == RdpProtocol.RDPResolutions.Fullscreen) + { + _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, + Screen.FromControl(_frmMain).Bounds.Width, + Screen.FromControl(_frmMain).Bounds.Height, 0); + _icaClient.FullScreenWindow(); + } + else + { + var resolution = RdpProtocol.GetResolutionRectangle(_info.Resolution); + _icaClient.SetWindowSize(WFICALib.ICAWindowType.WindowTypeClient, resolution.Width, + resolution.Height, 0); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaSetResolutionFailed + Environment.NewLine + + ex.Message, true); + } + } + + private void SetColors() + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (_info.Colors) + { + case RdpProtocol.RDPColors.Colors256: + _icaClient.SetProp("DesiredColor", "2"); + break; + case RdpProtocol.RDPColors.Colors15Bit: + _icaClient.SetProp("DesiredColor", "4"); + break; + case RdpProtocol.RDPColors.Colors16Bit: + _icaClient.SetProp("DesiredColor", "4"); + break; + default: + _icaClient.SetProp("DesiredColor", "8"); + break; + } + } + + private void SetSecurity() + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (_info.ICAEncryptionStrength) + { + case EncryptionStrength.Encr128BitLogonOnly: + _icaClient.Encrypt = true; + _icaClient.EncryptionLevelSession = "EncRC5-0"; + break; + case EncryptionStrength.Encr40Bit: + _icaClient.Encrypt = true; + _icaClient.EncryptionLevelSession = "EncRC5-40"; + break; + case EncryptionStrength.Encr56Bit: + _icaClient.Encrypt = true; + _icaClient.EncryptionLevelSession = "EncRC5-56"; + break; + case EncryptionStrength.Encr128Bit: + _icaClient.Encrypt = true; + _icaClient.EncryptionLevelSession = "EncRC5-128"; + break; + } + } + + private void SetEventHandlers() + { + try + { + _icaClient.OnConnecting += ICAEvent_OnConnecting; + _icaClient.OnConnect += ICAEvent_OnConnected; + _icaClient.OnConnectFailed += ICAEvent_OnConnectFailed; + _icaClient.OnDisconnect += ICAEvent_OnDisconnect; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strIcaSetEventHandlersFailed + Environment.NewLine + + ex.Message, true); + } + } - if (!ReconnectGroup.ReconnectWhenReady || !srvReady) return; - tmrReconnect.Enabled = false; - ReconnectGroup.DisposeReconnectGroup(); - _icaClient.Connect(); - } #endregion - + + #region Private Events & Handlers + + private void ICAEvent_OnConnecting(object sender, EventArgs e) + { + Event_Connecting(this); + } + + private void ICAEvent_OnConnected(object sender, EventArgs e) + { + Event_Connected(this); + } + + private void ICAEvent_OnConnectFailed(object sender, EventArgs e) + { + Event_ErrorOccured(this, e.ToString(), null); + } + + private void ICAEvent_OnDisconnect(object sender, EventArgs e) + { + Event_Disconnected(this, e.ToString(), null); + + if (Settings.Default.ReconnectOnDisconnect) + { + ReconnectGroup = new ReconnectGroup(); + //this.Load += ReconnectGroup_Load; + ReconnectGroup.Left = (int)(((double)Control.Width / 2) - ((double)ReconnectGroup.Width / 2)); + ReconnectGroup.Top = (int)(((double)Control.Height / 2) - ((double)ReconnectGroup.Height / 2)); + ReconnectGroup.Parent = Control; + ReconnectGroup.Show(); + tmrReconnect.Enabled = true; + } + else + { + Close(); + } + } + + #endregion + + #region Reconnect Stuff + + public void tmrReconnect_Elapsed(object sender, ElapsedEventArgs e) + { + var srvReady = PortScanner.IsPortOpen(_info.Hostname, Convert.ToString(_info.Port)); + + ReconnectGroup.ServerReady = srvReady; + + if (!ReconnectGroup.ReconnectWhenReady || !srvReady) return; + tmrReconnect.Enabled = false; + ReconnectGroup.DisposeReconnectGroup(); + _icaClient.Connect(); + } + + #endregion + #region Enums - public enum Defaults - { - Port = 1494, - EncryptionStrength = 0 - } - - public enum EncryptionStrength - { + + public enum Defaults + { + Port = 1494, + EncryptionStrength = 0 + } + + public enum EncryptionStrength + { [LocalizedAttributes.LocalizedDescription("strEncBasic")] EncrBasic = 1, + [LocalizedAttributes.LocalizedDescription("strEnc128BitLogonOnly")] Encr128BitLogonOnly = 127, + [LocalizedAttributes.LocalizedDescription("strEnc40Bit")] Encr40Bit = 40, + [LocalizedAttributes.LocalizedDescription("strEnc56Bit")] Encr56Bit = 56, + [LocalizedAttributes.LocalizedDescription("strEnc128Bit")] Encr128Bit = 128 - } + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index c4fa56306..2b296074d 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -9,174 +9,198 @@ using mRemoteNG.Tools; namespace mRemoteNG.Connection.Protocol { - public class IntegratedProgram : ProtocolBase - { + public class IntegratedProgram : ProtocolBase + { #region Private Fields + private ExternalTool _externalTool; private IntPtr _handle; private Process _process; + #endregion #region Public Methods - public override bool Initialize() - { - if (InterfaceControl.Info == null) - return base.Initialize(); - _externalTool = Runtime.ExternalToolsService.GetExtAppByName(InterfaceControl.Info.ExtApp); + public override bool Initialize() + { + if (InterfaceControl.Info == null) + return base.Initialize(); - if (_externalTool == null) - { - Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, string.Format(Language.CouldNotFindExternalTool, InterfaceControl.Info.ExtApp)); - return false; - } + _externalTool = Runtime.ExternalToolsService.GetExtAppByName(InterfaceControl.Info.ExtApp); - _externalTool.ConnectionInfo = InterfaceControl.Info; + if (_externalTool == null) + { + Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, + string.Format(Language.CouldNotFindExternalTool, + InterfaceControl.Info.ExtApp)); + return false; + } - return base.Initialize(); - } - - public override bool Connect() - { - try - { - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true); + _externalTool.ConnectionInfo = InterfaceControl.Info; + + return base.Initialize(); + } + + public override bool Connect() + { + try + { + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, + $"Attempting to start: {_externalTool.DisplayName}", true); if (_externalTool.TryIntegrate == false) - { - _externalTool.Start(InterfaceControl.Info); + { + _externalTool.Start(InterfaceControl.Info); /* Don't call close here... There's nothing for the override to do in this case since * _process is not created in this scenario. When returning false, ProtocolBase.Close() * will be called - which is just going to call IntegratedProgram.Close() again anyway... * Close(); */ - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", true); + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, + $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", + true); return false; - } + } var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo); - _process = new Process - { - StartInfo = - { - UseShellExecute = true, - FileName = argParser.ParseArguments(_externalTool.FileName), - Arguments = argParser.ParseArguments(_externalTool.Arguments) - }, - EnableRaisingEvents = true - }; + _process = new Process + { + StartInfo = + { + UseShellExecute = true, + FileName = argParser.ParseArguments(_externalTool.FileName), + Arguments = argParser.ParseArguments(_externalTool.Arguments) + }, + EnableRaisingEvents = true + }; - _process.Exited += ProcessExited; - - _process.Start(); + _process.Exited += ProcessExited; + + _process.Start(); _process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); var startTicks = Environment.TickCount; - while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) - { - _process.Refresh(); - if (_process.MainWindowTitle != "Default IME") - { - _handle = _process.MainWindowHandle; - } - if (_handle.ToInt32() == 0) - { - Thread.Sleep(0); - } - } - - NativeMethods.SetParent(_handle, InterfaceControl.Handle); - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true); - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle), true); - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true); - Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle), true); - - Resize(this, new EventArgs()); - base.Connect(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionMessage(Language.strIntAppConnectionFailed, ex); - return false; - } - } - - public override void Focus() - { - try - { - NativeMethods.SetForegroundWindow(_handle); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex); - } - } - - public override void Resize(object sender, EventArgs e) - { - try - { - if (InterfaceControl.Size == Size.Empty) return; - NativeMethods.MoveWindow(_handle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppResizeFailed, ex); - } - } - - public override void Close() - { + while (_handle.ToInt32() == 0 & + Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) + { + _process.Refresh(); + if (_process.MainWindowTitle != "Default IME") + { + _handle = _process.MainWindowHandle; + } + + if (_handle.ToInt32() == 0) + { + Thread.Sleep(0); + } + } + + NativeMethods.SetParent(_handle, InterfaceControl.Handle); + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true); + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strIntAppHandle, _handle), true); + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strIntAppTitle, _process.MainWindowTitle), + true); + Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strIntAppParentHandle, + InterfaceControl.Parent.Handle), true); + + Resize(this, new EventArgs()); + base.Connect(); + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionMessage(Language.strIntAppConnectionFailed, ex); + return false; + } + } + + public override void Focus() + { + try + { + NativeMethods.SetForegroundWindow(_handle); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex); + } + } + + public override void Resize(object sender, EventArgs e) + { + try + { + if (InterfaceControl.Size == Size.Empty) return; + NativeMethods.MoveWindow(_handle, -SystemInformation.FrameBorderSize.Width, + -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), + InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, + InterfaceControl.Height + SystemInformation.CaptionHeight + + SystemInformation.FrameBorderSize.Height * 2, true); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppResizeFailed, ex); + } + } + + public override void Close() + { /* only attempt this if we have a valid process object * Non-integrated tools will still call base.Close() and don't have a valid process object. * See Connect() above... This just muddies up the log. */ if (_process != null) - { - try - { - if (!_process.HasExited) - { - _process.Kill(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppKillFailed, ex); - } + { + try + { + if (!_process.HasExited) + { + _process.Kill(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppKillFailed, ex); + } - try - { - if (!_process.HasExited) - { - _process.Dispose(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppDisposeFailed, ex); - } - } + try + { + if (!_process.HasExited) + { + _process.Dispose(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppDisposeFailed, ex); + } + } + + base.Close(); + } - base.Close(); - } #endregion - + #region Private Methods - private void ProcessExited(object sender, EventArgs e) - { - Event_Closed(this); - } + + private void ProcessExited(object sender, EventArgs e) + { + Event_Closed(this); + } + #endregion - + #region Enumerations - public enum Defaults - { - Port = 0 - } + + public enum Defaults + { + Port = 0 + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 2a6082e05..a9c9023d8 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Windows.Forms; using mRemoteNG.UI.Tabs; + // ReSharper disable UnusedMember.Local namespace mRemoteNG.Connection.Protocol @@ -12,51 +13,54 @@ namespace mRemoteNG.Connection.Protocol { #region Private Variables - private ConnectionTab _connectionTab; + private ConnectionTab _connectionTab; private InterfaceControl _interfaceControl; - private ConnectingEventHandler ConnectingEvent; + private ConnectingEventHandler ConnectingEvent; private ConnectedEventHandler ConnectedEvent; private DisconnectedEventHandler DisconnectedEvent; private ErrorOccuredEventHandler ErrorOccuredEvent; private ClosingEventHandler ClosingEvent; private ClosedEventHandler ClosedEvent; + #endregion #region Public Properties + #region Control + private string Name { get; } private ConnectionTab ConnectionTab - { - get => _connectionTab; + { + get => _connectionTab; set - { - _connectionTab = value; - _connectionTab.ResizeBegin += ResizeBegin; - _connectionTab.Resize += Resize; - _connectionTab.ResizeEnd += ResizeEnd; - } - } + { + _connectionTab = value; + _connectionTab.ResizeBegin += ResizeBegin; + _connectionTab.Resize += Resize; + _connectionTab.ResizeEnd += ResizeEnd; + } + } public InterfaceControl InterfaceControl - { - get => _interfaceControl; + { + get => _interfaceControl; set - { - _interfaceControl = value; + { + _interfaceControl = value; - if(_interfaceControl.Parent is ConnectionTab ct) - ConnectionTab = ct; - } - } + if (_interfaceControl.Parent is ConnectionTab ct) + ConnectionTab = ct; + } + } protected Control Control { get; set; } - #endregion + #endregion public ConnectionInfo.Force Force { get; set; } - public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000); + public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000); protected ReconnectGroup ReconnectGroup; protected ProtocolBase(string name) @@ -71,240 +75,260 @@ namespace mRemoteNG.Connection.Protocol #endregion #region Methods + //public abstract int GetDefaultPort(); public virtual void Focus() - { - try - { - Control.Focus(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("Couldn't focus Control (Connection.Protocol.Base)", ex); - } - } + { + try + { + Control.Focus(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Couldn't focus Control (Connection.Protocol.Base)", + ex); + } + } public virtual void ResizeBegin(object sender, EventArgs e) - { - } + { + } public virtual void Resize(object sender, EventArgs e) - { - } + { + } public virtual void ResizeEnd(object sender, EventArgs e) - { - } + { + } - public virtual bool Initialize() - { - try - { - _interfaceControl.Parent.Tag = _interfaceControl; - _interfaceControl.Show(); + public virtual bool Initialize() + { + try + { + _interfaceControl.Parent.Tag = _interfaceControl; + _interfaceControl.Show(); - if (Control == null) return true; - Control.Name = Name; - Control.Parent = _interfaceControl; - Control.Location = _interfaceControl.Location; - Control.Size = InterfaceControl.Size; - Control.Anchor = _interfaceControl.Anchor; + if (Control == null) return true; + Control.Name = Name; + Control.Parent = _interfaceControl; + Control.Location = _interfaceControl.Location; + Control.Size = InterfaceControl.Size; + Control.Anchor = _interfaceControl.Anchor; - return true; - } - catch (Exception ex) - { + return true; + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionStackTrace("Couldn't SetProps (Connection.Protocol.Base)", ex); - return false; - } - } + return false; + } + } - public virtual bool Connect() - { - if (InterfaceControl.Info.Protocol == ProtocolType.RDP) return false; - if (ConnectedEvent == null) return false; - ConnectedEvent(this); - return true; - } + public virtual bool Connect() + { + if (InterfaceControl.Info.Protocol == ProtocolType.RDP) return false; + if (ConnectedEvent == null) return false; + ConnectedEvent(this); + return true; + } - public virtual void Disconnect() - { - Close(); - } + public virtual void Disconnect() + { + Close(); + } - public virtual void Close() - { - var t = new Thread(CloseBG); - t.SetApartmentState(ApartmentState.STA); - t.IsBackground = true; - t.Start(); - } + public virtual void Close() + { + var t = new Thread(CloseBG); + t.SetApartmentState(ApartmentState.STA); + t.IsBackground = true; + t.Start(); + } - private void CloseBG() - { - ClosedEvent?.Invoke(this); - try - { - tmrReconnect.Enabled = false; + private void CloseBG() + { + ClosedEvent?.Invoke(this); + try + { + tmrReconnect.Enabled = false; - if (Control != null) - { - try - { - DisposeControl(); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex); - } - } + if (Control != null) + { + try + { + DisposeControl(); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace( + "Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", + ex); + } + } - if (_interfaceControl == null) return; + if (_interfaceControl == null) return; - try - { - if (_interfaceControl.Parent == null) return; + try + { + if (_interfaceControl.Parent == null) return; - if (_interfaceControl.Parent.Tag != null) - { - SetTagToNothing(); - } + if (_interfaceControl.Parent.Tag != null) + { + SetTagToNothing(); + } - DisposeInterface(); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", ex); - } - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex); - } - } + DisposeInterface(); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace( + "Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", + ex); + } + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace( + "Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", + ex); + } + } - private delegate void DisposeInterfaceCB(); - private void DisposeInterface() - { - if (_interfaceControl.InvokeRequired) - { - var s = new DisposeInterfaceCB(DisposeInterface); - _interfaceControl.Invoke(s); - } - else - { - _interfaceControl.Dispose(); - } - } + private delegate void DisposeInterfaceCB(); - private delegate void SetTagToNothingCB(); - private void SetTagToNothing() - { - if (_interfaceControl.Parent.InvokeRequired) - { - var s = new SetTagToNothingCB(SetTagToNothing); - _interfaceControl.Parent.Invoke(s); - } - else - { - _interfaceControl.Parent.Tag = null; - } - } + private void DisposeInterface() + { + if (_interfaceControl.InvokeRequired) + { + var s = new DisposeInterfaceCB(DisposeInterface); + _interfaceControl.Invoke(s); + } + else + { + _interfaceControl.Dispose(); + } + } + + private delegate void SetTagToNothingCB(); + + private void SetTagToNothing() + { + if (_interfaceControl.Parent.InvokeRequired) + { + var s = new SetTagToNothingCB(SetTagToNothing); + _interfaceControl.Parent.Invoke(s); + } + else + { + _interfaceControl.Parent.Tag = null; + } + } + + private delegate void DisposeControlCB(); + + private void DisposeControl() + { + if (Control.InvokeRequired) + { + var s = new DisposeControlCB(DisposeControl); + Control.Invoke(s); + } + else + { + Control.Dispose(); + } + } - private delegate void DisposeControlCB(); - private void DisposeControl() - { - if (Control.InvokeRequired) - { - var s = new DisposeControlCB(DisposeControl); - Control.Invoke(s); - } - else - { - Control.Dispose(); - } - } #endregion #region Events - public delegate void ConnectingEventHandler(object sender); - public event ConnectingEventHandler Connecting - { - add => ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); - remove => ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); + + public delegate void ConnectingEventHandler(object sender); + + public event ConnectingEventHandler Connecting + { + add => ConnectingEvent = (ConnectingEventHandler)Delegate.Combine(ConnectingEvent, value); + remove => ConnectingEvent = (ConnectingEventHandler)Delegate.Remove(ConnectingEvent, value); } - public delegate void ConnectedEventHandler(object sender); - public event ConnectedEventHandler Connected - { - add => ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); - remove => ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); + public delegate void ConnectedEventHandler(object sender); + + public event ConnectedEventHandler Connected + { + add => ConnectedEvent = (ConnectedEventHandler)Delegate.Combine(ConnectedEvent, value); + remove => ConnectedEvent = (ConnectedEventHandler)Delegate.Remove(ConnectedEvent, value); } - public delegate void DisconnectedEventHandler(object sender, string disconnectedMessage, int? reasonCode); - public event DisconnectedEventHandler Disconnected - { - add => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); - remove => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); + public delegate void DisconnectedEventHandler(object sender, string disconnectedMessage, int? reasonCode); + + public event DisconnectedEventHandler Disconnected + { + add => DisconnectedEvent = (DisconnectedEventHandler)Delegate.Combine(DisconnectedEvent, value); + remove => DisconnectedEvent = (DisconnectedEventHandler)Delegate.Remove(DisconnectedEvent, value); } - public delegate void ErrorOccuredEventHandler(object sender, string errorMessage, int? errorCode); - public event ErrorOccuredEventHandler ErrorOccured - { - add => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); - remove => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); + public delegate void ErrorOccuredEventHandler(object sender, string errorMessage, int? errorCode); + + public event ErrorOccuredEventHandler ErrorOccured + { + add => ErrorOccuredEvent = (ErrorOccuredEventHandler)Delegate.Combine(ErrorOccuredEvent, value); + remove => ErrorOccuredEvent = (ErrorOccuredEventHandler)Delegate.Remove(ErrorOccuredEvent, value); } - public delegate void ClosingEventHandler(object sender); - public event ClosingEventHandler Closing - { - add => ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); - remove => ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); + public delegate void ClosingEventHandler(object sender); + + public event ClosingEventHandler Closing + { + add => ClosingEvent = (ClosingEventHandler)Delegate.Combine(ClosingEvent, value); + remove => ClosingEvent = (ClosingEventHandler)Delegate.Remove(ClosingEvent, value); } - public delegate void ClosedEventHandler(object sender); - public event ClosedEventHandler Closed - { - add => ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); - remove => ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); + public delegate void ClosedEventHandler(object sender); + + public event ClosedEventHandler Closed + { + add => ClosedEvent = (ClosedEventHandler)Delegate.Combine(ClosedEvent, value); + remove => ClosedEvent = (ClosedEventHandler)Delegate.Remove(ClosedEvent, value); } - public void Event_Closing(object sender) - { - ClosingEvent?.Invoke(sender); - } + public void Event_Closing(object sender) + { + ClosingEvent?.Invoke(sender); + } - protected void Event_Closed(object sender) - { - ClosedEvent?.Invoke(sender); - } + protected void Event_Closed(object sender) + { + ClosedEvent?.Invoke(sender); + } - protected void Event_Connecting(object sender) - { - ConnectingEvent?.Invoke(sender); - } + protected void Event_Connecting(object sender) + { + ConnectingEvent?.Invoke(sender); + } - protected void Event_Connected(object sender) - { - ConnectedEvent?.Invoke(sender); - } + protected void Event_Connected(object sender) + { + ConnectedEvent?.Invoke(sender); + } - protected void Event_Disconnected(object sender, string disconnectedMessage, int? reasonCode) - { - DisconnectedEvent?.Invoke(sender, disconnectedMessage, reasonCode); - } + protected void Event_Disconnected(object sender, string disconnectedMessage, int? reasonCode) + { + DisconnectedEvent?.Invoke(sender, disconnectedMessage, reasonCode); + } - protected void Event_ErrorOccured(object sender, string errorMsg, int? errorCode) - { - ErrorOccuredEvent?.Invoke(sender, errorMsg, errorCode); - } + protected void Event_ErrorOccured(object sender, string errorMsg, int? errorCode) + { + ErrorOccuredEvent?.Invoke(sender, errorMsg, errorCode); + } + + protected void Event_ReconnectGroupCloseClicked() + { + Close(); + } - protected void Event_ReconnectGroupCloseClicked() - { - Close(); - } #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/ProtocolFactory.cs b/mRemoteV1/Connection/Protocol/ProtocolFactory.cs index c4f6ca99f..6c7611f1a 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolFactory.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolFactory.cs @@ -16,51 +16,53 @@ namespace mRemoteNG.Connection.Protocol { var newProtocol = default(ProtocolBase); // ReSharper disable once SwitchStatementMissingSomeCases - switch (connectionInfo.Protocol) - { - case ProtocolType.RDP: - newProtocol = new RdpProtocol - { - LoadBalanceInfoUseUtf8 = Settings.Default.RdpLoadBalanceInfoUseUtf8 + switch (connectionInfo.Protocol) + { + case ProtocolType.RDP: + newProtocol = new RdpProtocol + { + LoadBalanceInfoUseUtf8 = Settings.Default.RdpLoadBalanceInfoUseUtf8 }; - ((RdpProtocol) newProtocol).tmrReconnect.Elapsed += ((RdpProtocol) newProtocol).tmrReconnect_Elapsed; - break; - case ProtocolType.VNC: - newProtocol = new ProtocolVNC(); - break; - case ProtocolType.SSH1: - newProtocol = new ProtocolSSH1(); - break; - case ProtocolType.SSH2: - newProtocol = new ProtocolSSH2(); - break; - case ProtocolType.Telnet: - newProtocol = new ProtocolTelnet(); - break; - case ProtocolType.Rlogin: - newProtocol = new ProtocolRlogin(); - break; - case ProtocolType.RAW: - newProtocol = new RawProtocol(); - break; - case ProtocolType.HTTP: - newProtocol = new ProtocolHTTP(connectionInfo.RenderingEngine); - break; - case ProtocolType.HTTPS: - newProtocol = new ProtocolHTTPS(connectionInfo.RenderingEngine); - break; - case ProtocolType.ICA: - newProtocol = new IcaProtocol(); - ((IcaProtocol) newProtocol).tmrReconnect.Elapsed += ((IcaProtocol) newProtocol).tmrReconnect_Elapsed; - break; - case ProtocolType.IntApp: - newProtocol = new IntegratedProgram(); - if (connectionInfo.ExtApp == "") - { - throw (new Exception(Language.strNoExtAppDefined)); - } - break; - } + ((RdpProtocol)newProtocol).tmrReconnect.Elapsed += ((RdpProtocol)newProtocol).tmrReconnect_Elapsed; + break; + case ProtocolType.VNC: + newProtocol = new ProtocolVNC(); + break; + case ProtocolType.SSH1: + newProtocol = new ProtocolSSH1(); + break; + case ProtocolType.SSH2: + newProtocol = new ProtocolSSH2(); + break; + case ProtocolType.Telnet: + newProtocol = new ProtocolTelnet(); + break; + case ProtocolType.Rlogin: + newProtocol = new ProtocolRlogin(); + break; + case ProtocolType.RAW: + newProtocol = new RawProtocol(); + break; + case ProtocolType.HTTP: + newProtocol = new ProtocolHTTP(connectionInfo.RenderingEngine); + break; + case ProtocolType.HTTPS: + newProtocol = new ProtocolHTTPS(connectionInfo.RenderingEngine); + break; + case ProtocolType.ICA: + newProtocol = new IcaProtocol(); + ((IcaProtocol)newProtocol).tmrReconnect.Elapsed += ((IcaProtocol)newProtocol).tmrReconnect_Elapsed; + break; + case ProtocolType.IntApp: + newProtocol = new IntegratedProgram(); + if (connectionInfo.ExtApp == "") + { + throw (new Exception(Language.strNoExtAppDefined)); + } + + break; + } + return newProtocol; } } diff --git a/mRemoteV1/Connection/Protocol/ProtocolList.cs b/mRemoteV1/Connection/Protocol/ProtocolList.cs index e3582b48d..0edbe3257 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolList.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolList.cs @@ -1,74 +1,82 @@ using System; using System.Collections; using System.Collections.Specialized; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Connection.Protocol { - public class ProtocolList : CollectionBase, INotifyCollectionChanged - { + public class ProtocolList : CollectionBase, INotifyCollectionChanged + { public ProtocolBase this[object index] - { - get - { - var @base = index as ProtocolBase; - if (@base != null) + { + get + { + var @base = index as ProtocolBase; + if (@base != null) return @base; - if (index is int) - return (ProtocolBase) List[Convert.ToInt32(index)]; - return null; - } - } - + if (index is int) + return (ProtocolBase)List[Convert.ToInt32(index)]; + return null; + } + } + public new int Count { get { return List.Count; } } - public void Add(ProtocolBase cProt) - { - List.Add(cProt); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, cProt)); + public void Add(ProtocolBase cProt) + { + List.Add(cProt); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, cProt)); } - - public void AddRange(ProtocolBase[] cProt) - { - foreach (var cP in cProt) - { - List.Add(cP); - } - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, cProt)); - } - - public void Remove(ProtocolBase cProt) - { - try - { + + public void AddRange(ProtocolBase[] cProt) + { + foreach (var cP in cProt) + { + List.Add(cP); + } + + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, cProt)); + } + + public void Remove(ProtocolBase cProt) + { + try + { if (!List.Contains(cProt)) return; - List.Remove(cProt); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, cProt)); + List.Remove(cProt); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + cProt)); } - catch (Exception) - { - } - } - - public new void Clear() - { + catch (Exception) + { + } + } + + public new void Clear() + { if (Count == 0) return; - List.Clear(); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } + List.Clear(); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } - public event NotifyCollectionChangedEventHandler CollectionChanged; - private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) - { - CollectionChanged?.Invoke(sender, args); - } + public event NotifyCollectionChangedEventHandler CollectionChanged; + + private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) + { + CollectionChanged?.Invoke(sender, args); + } } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/ProtocolType.cs b/mRemoteV1/Connection/Protocol/ProtocolType.cs index 69d4fa6f8..44aca2f96 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolType.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolType.cs @@ -2,29 +2,39 @@ using mRemoteNG.Tools; namespace mRemoteNG.Connection.Protocol { - public enum ProtocolType - { + public enum ProtocolType + { [LocalizedAttributes.LocalizedDescription("strRDP")] RDP = 0, + [LocalizedAttributes.LocalizedDescription("strVnc")] VNC = 1, + [LocalizedAttributes.LocalizedDescription("strSsh1")] SSH1 = 2, + [LocalizedAttributes.LocalizedDescription("strSsh2")] SSH2 = 3, + [LocalizedAttributes.LocalizedDescription("strTelnet")] Telnet = 4, + [LocalizedAttributes.LocalizedDescription("strRlogin")] Rlogin = 5, + [LocalizedAttributes.LocalizedDescription("strRAW")] RAW = 6, + [LocalizedAttributes.LocalizedDescription("strHttp")] HTTP = 7, + [LocalizedAttributes.LocalizedDescription("strHttps")] HTTPS = 8, + [LocalizedAttributes.LocalizedDescription("strICA")] ICA = 9, + [LocalizedAttributes.LocalizedDescription("strExtApp")] IntApp = 20 - } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index 39de44bcb..3897542df 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -15,9 +15,9 @@ using System.Windows.Forms; namespace mRemoteNG.Connection.Protocol { public class PuttyBase : ProtocolBase - { - private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID - private bool _isPuttyNg; + { + private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID + private bool _isPuttyNg; private readonly DisplayProperties _display = new DisplayProperties(); #region Public Properties @@ -26,176 +26,192 @@ namespace mRemoteNG.Connection.Protocol protected Putty_SSHVersion PuttySSHVersion { private get; set; } - public IntPtr PuttyHandle { get; set; } + public IntPtr PuttyHandle { get; set; } - private Process PuttyProcess { get; set; } + private Process PuttyProcess { get; set; } - public static string PuttyPath { get; set; } + public static string PuttyPath { get; set; } - public bool Focused - { - get { return NativeMethods.GetForegroundWindow() == PuttyHandle; } - } + public bool Focused + { + get { return NativeMethods.GetForegroundWindow() == PuttyHandle; } + } - #endregion + #endregion - #region Private Events & Handlers - private void ProcessExited(object sender, EventArgs e) - { + #region Private Events & Handlers + + private void ProcessExited(object sender, EventArgs e) + { Event_Closed(this); - } + } + #endregion #region Public Methods - public override bool Connect() - { - try - { - _isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg; - PuttyProcess = new Process - { - StartInfo = - { - UseShellExecute = false, - FileName = PuttyPath - } - }; + public override bool Connect() + { + try + { + _isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg; - var arguments = new CommandLineArguments {EscapeForShell = false}; + PuttyProcess = new Process + { + StartInfo = + { + UseShellExecute = false, + FileName = PuttyPath + } + }; - arguments.Add("-load", InterfaceControl.Info.PuttySession); + var arguments = new CommandLineArguments {EscapeForShell = false}; - if (!(InterfaceControl.Info is PuttySessionInfo)) - { - arguments.Add("-" + PuttyProtocol); + arguments.Add("-load", InterfaceControl.Info.PuttySession); - if (PuttyProtocol == Putty_Protocol.ssh) - { - var username = ""; - var password = ""; + if (!(InterfaceControl.Info is PuttySessionInfo)) + { + arguments.Add("-" + PuttyProtocol); - if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username)) - { - username = InterfaceControl.Info.Username; - } - else - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (Settings.Default.EmptyCredentials) - { - case "windows": - username = Environment.UserName; - break; - case "custom": - username = Settings.Default.DefaultUsername; - break; - } - } + if (PuttyProtocol == Putty_Protocol.ssh) + { + var username = ""; + var password = ""; - if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password)) - { - password = InterfaceControl.Info.Password; - } - else - { - if (Settings.Default.EmptyCredentials == "custom") - { + if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username)) + { + username = InterfaceControl.Info.Username; + } + else + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (Settings.Default.EmptyCredentials) + { + case "windows": + username = Environment.UserName; + break; + case "custom": + username = Settings.Default.DefaultUsername; + break; + } + } + + if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password)) + { + password = InterfaceControl.Info.Password; + } + else + { + if (Settings.Default.EmptyCredentials == "custom") + { var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); - } - } + password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, + Runtime.EncryptionKey); + } + } - arguments.Add("-" + (int)PuttySSHVersion); + arguments.Add("-" + (int)PuttySSHVersion); - if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - if (!string.IsNullOrEmpty(username)) - { - arguments.Add("-l", username); - } - if (!string.IsNullOrEmpty(password)) - { - arguments.Add("-pw", password); - } - } - } + if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials)) + { + if (!string.IsNullOrEmpty(username)) + { + arguments.Add("-l", username); + } - arguments.Add("-P", InterfaceControl.Info.Port.ToString()); - arguments.Add(InterfaceControl.Info.Hostname); - } + if (!string.IsNullOrEmpty(password)) + { + arguments.Add("-pw", password); + } + } + } - if (_isPuttyNg) - { - arguments.Add("-hwndparent", InterfaceControl.Handle.ToString()); - } + arguments.Add("-P", InterfaceControl.Info.Port.ToString()); + arguments.Add(InterfaceControl.Info.Hostname); + } - PuttyProcess.StartInfo.Arguments = arguments.ToString(); + if (_isPuttyNg) + { + arguments.Add("-hwndparent", InterfaceControl.Handle.ToString()); + } - PuttyProcess.EnableRaisingEvents = true; - PuttyProcess.Exited += ProcessExited; + PuttyProcess.StartInfo.Arguments = arguments.ToString(); - PuttyProcess.Start(); - PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); + PuttyProcess.EnableRaisingEvents = true; + PuttyProcess.Exited += ProcessExited; - var startTicks = Environment.TickCount; - while (PuttyHandle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) - { - if (_isPuttyNg) - { - PuttyHandle = NativeMethods.FindWindowEx( - InterfaceControl.Handle, new IntPtr(0), null, null); - } - else - { - PuttyProcess.Refresh(); - PuttyHandle = PuttyProcess.MainWindowHandle; - } - if (PuttyHandle.ToInt32() == 0) - { - Thread.Sleep(0); - } - } + PuttyProcess.Start(); + PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); - if (!_isPuttyNg) - { - NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle); - } + var startTicks = Environment.TickCount; + while (PuttyHandle.ToInt32() == 0 & + Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) + { + if (_isPuttyNg) + { + PuttyHandle = NativeMethods.FindWindowEx( + InterfaceControl.Handle, new IntPtr(0), null, null); + } + else + { + PuttyProcess.Refresh(); + PuttyHandle = PuttyProcess.MainWindowHandle; + } - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true); - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyHandle, PuttyHandle), true); - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle), true); - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyParentHandle, InterfaceControl.Parent.Handle), true); + if (PuttyHandle.ToInt32() == 0) + { + Thread.Sleep(0); + } + } - Resize(this, new EventArgs()); - base.Connect(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyConnectionFailed + Environment.NewLine + ex.Message); - return false; - } - } + if (!_isPuttyNg) + { + NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle); + } - public override void Focus() - { - try - { - NativeMethods.SetForegroundWindow(PuttyHandle); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyFocusFailed + Environment.NewLine + ex.Message, true); - } - } + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strPuttyHandle, PuttyHandle), true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle), + true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strPuttyParentHandle, + InterfaceControl.Parent.Handle), true); - public override void Resize(object sender, EventArgs e) - { - try - { - if (InterfaceControl.Size == Size.Empty) - return; + Resize(this, new EventArgs()); + base.Connect(); + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyConnectionFailed + Environment.NewLine + + ex.Message); + return false; + } + } + + public override void Focus() + { + try + { + NativeMethods.SetForegroundWindow(PuttyHandle); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyFocusFailed + Environment.NewLine + ex.Message, + true); + } + } + + public override void Resize(object sender, EventArgs e) + { + try + { + if (InterfaceControl.Size == Size.Empty) + return; if (_isPuttyNg) { @@ -208,74 +224,85 @@ namespace mRemoteNG.Connection.Protocol var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); NativeMethods.MoveWindow(PuttyHandle, -scaledFrameBorderWidth, - -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), - InterfaceControl.Width + scaledFrameBorderWidth * 2, - InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, - true); + -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), + InterfaceControl.Width + scaledFrameBorderWidth * 2, + InterfaceControl.Height + SystemInformation.CaptionHeight + + scaledFrameBorderHeight * 2, + true); } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyResizeFailed + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyResizeFailed + Environment.NewLine + ex.Message, + true); + } + } - public override void Close() - { - try - { - if (PuttyProcess.HasExited == false) - { - PuttyProcess.Kill(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyKillFailed + Environment.NewLine + ex.Message, true); - } + public override void Close() + { + try + { + if (PuttyProcess.HasExited == false) + { + PuttyProcess.Kill(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyKillFailed + Environment.NewLine + ex.Message, + true); + } - try - { + try + { PuttyProcess.Dispose(); } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + ex.Message, true); - } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyDisposeFailed + Environment.NewLine + ex.Message, + true); + } - base.Close(); - } + base.Close(); + } - public void ShowSettingsDialog() - { - try - { + public void ShowSettingsDialog() + { + try + { NativeMethods.PostMessage(PuttyHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, (IntPtr)0); NativeMethods.SetForegroundWindow(PuttyHandle); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyShowSettingsDialogFailed + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strPuttyShowSettingsDialogFailed + Environment.NewLine + + ex.Message, true); + } + } + #endregion #region Enums - protected enum Putty_Protocol - { - ssh = 0, - telnet = 1, - rlogin = 2, - raw = 3, - serial = 4 - } + protected enum Putty_Protocol + { + ssh = 0, + telnet = 1, + rlogin = 2, + raw = 3, + serial = 4 + } + + protected enum Putty_SSHVersion + { + ssh1 = 1, + ssh2 = 2 + } - protected enum Putty_SSHVersion - { - ssh1 = 1, - ssh2 = 2 - } #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/RAW/RawProtocol.cs b/mRemoteV1/Connection/Protocol/RAW/RawProtocol.cs index 4e9643e35..cb7f0a519 100644 --- a/mRemoteV1/Connection/Protocol/RAW/RawProtocol.cs +++ b/mRemoteV1/Connection/Protocol/RAW/RawProtocol.cs @@ -1,15 +1,15 @@ namespace mRemoteNG.Connection.Protocol.RAW { - public class RawProtocol : PuttyBase - { - public RawProtocol() - { - PuttyProtocol = Putty_Protocol.raw; - } - - public enum Defaults - { - Port = 23 - } - } + public class RawProtocol : PuttyBase + { + public RawProtocol() + { + PuttyProtocol = Putty_Protocol.raw; + } + + public enum Defaults + { + Port = 23 + } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/RDP/AzureLoadBalanceInfoEncoder.cs b/mRemoteV1/Connection/Protocol/RDP/AzureLoadBalanceInfoEncoder.cs index e0836053f..1f7a2e38f 100644 --- a/mRemoteV1/Connection/Protocol/RDP/AzureLoadBalanceInfoEncoder.cs +++ b/mRemoteV1/Connection/Protocol/RDP/AzureLoadBalanceInfoEncoder.cs @@ -37,4 +37,4 @@ namespace mRemoteNG.Connection.Protocol.RDP return Encoding.Unicode.GetString(bytes); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs index 53414dc10..08ed2f859 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs @@ -11,14 +11,14 @@ namespace mRemoteNG.Connection.Protocol.RDP class RdpClientWrap : AxMSTSCLib.AxMsRdpClient8NotSafeForScripting { public RdpClientWrap() - : base() + : base() { GotFocus += RdpClientWrap_GotFocus; } private void RdpClientWrap_GotFocus(object sender, EventArgs e) { - ((ConnectionTab)Parent.Parent).Focus(); + ((ConnectionTab)Parent.Parent).Focus(); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpErrorCodes.cs b/mRemoteV1/Connection/Protocol/RDP/RdpErrorCodes.cs index aa963ffd2..b20980c16 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpErrorCodes.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpErrorCodes.cs @@ -12,18 +12,18 @@ namespace mRemoteNG.Connection.Protocol.RDP { _description = new Hashtable { - { 0, "Language.strRdpErrorUnknown"}, - { 1, "Language.strRdpErrorCode1"}, - { 2, "Language.strRdpErrorOutOfMemory"}, - { 3, "Language.strRdpErrorWindowCreation"}, - { 4, "Language.strRdpErrorCode2"}, - { 5, "Language.strRdpErrorCode3"}, - { 6, "Language.strRdpErrorCode4"}, - { 7, "Language.strRdpErrorConnection"}, - { 100, "Language.strRdpErrorWinsock"} + {0, "Language.strRdpErrorUnknown"}, + {1, "Language.strRdpErrorCode1"}, + {2, "Language.strRdpErrorOutOfMemory"}, + {3, "Language.strRdpErrorWindowCreation"}, + {4, "Language.strRdpErrorCode2"}, + {5, "Language.strRdpErrorCode3"}, + {6, "Language.strRdpErrorCode4"}, + {7, "Language.strRdpErrorConnection"}, + {100, "Language.strRdpErrorWinsock"} }; } - + public static string GetError(int id) { try diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs index ce908a757..ade6e5a53 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs @@ -16,7 +16,7 @@ using System.Windows.Forms; namespace mRemoteNG.Connection.Protocol.RDP { public class RdpProtocol : ProtocolBase - { + { /* RDP v8 requires Windows 7 with: * https://support.microsoft.com/en-us/kb/2592687 * OR @@ -30,99 +30,104 @@ namespace mRemoteNG.Connection.Protocol.RDP private bool _loginComplete; private bool _redirectKeys; private bool _alertOnIdleDisconnect; - private readonly DisplayProperties _displayProperties; + private readonly DisplayProperties _displayProperties; private readonly FrmMain _frmMain = FrmMain.Default; #region Properties - public bool SmartSize - { - get => _rdpClient.AdvancedSettings2.SmartSizing; - private set - { - _rdpClient.AdvancedSettings2.SmartSizing = value; - ReconnectForResize(); - } - } - - public bool Fullscreen - { - get => _rdpClient.FullScreen; - private set - { - _rdpClient.FullScreen = value; - ReconnectForResize(); - } - } - private bool RedirectKeys - { + public bool SmartSize + { + get => _rdpClient.AdvancedSettings2.SmartSizing; + private set + { + _rdpClient.AdvancedSettings2.SmartSizing = value; + ReconnectForResize(); + } + } + + public bool Fullscreen + { + get => _rdpClient.FullScreen; + private set + { + _rdpClient.FullScreen = value; + ReconnectForResize(); + } + } + + private bool RedirectKeys + { /* get { return _redirectKeys; } */ - set - { - _redirectKeys = value; - try - { - if (!_redirectKeys) - { - return; - } - - Debug.Assert(Convert.ToBoolean(_rdpClient.SecuredSettingsEnabled)); + set + { + _redirectKeys = value; + try + { + if (!_redirectKeys) + { + return; + } + + Debug.Assert(Convert.ToBoolean(_rdpClient.SecuredSettingsEnabled)); var msRdpClientSecuredSettings = _rdpClient.SecuredSettings2; - msRdpClientSecuredSettings.KeyboardHookMode = 1; // Apply key combinations at the remote server. - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetRedirectKeysFailed, ex); - } - } - } + msRdpClientSecuredSettings.KeyboardHookMode = 1; // Apply key combinations at the remote server. + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetRedirectKeysFailed, ex); + } + } + } public bool LoadBalanceInfoUseUtf8 { get; set; } + #endregion #region Constructors + public RdpProtocol() { Control = new RdpClientWrap(); _displayProperties = new DisplayProperties(); } + #endregion #region Public Methods - public override bool Initialize() - { - base.Initialize(); - try - { - Control.CreateControl(); - _connectionInfo = InterfaceControl.Info; - - try - { - while (!Control.Created) - { - Thread.Sleep(0); - Application.DoEvents(); - } - _rdpClient = (MsRdpClient8NotSafeForScripting)((AxMsRdpClient8NotSafeForScripting)Control).GetOcx(); - } - catch (System.Runtime.InteropServices.COMException ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strRdpControlCreationFailed, ex); - Control.Dispose(); - return false; - } - - _rdpVersion = new Version(_rdpClient.Version); - - _rdpClient.Server = _connectionInfo.Hostname; + public override bool Initialize() + { + base.Initialize(); + try + { + Control.CreateControl(); + _connectionInfo = InterfaceControl.Info; + + try + { + while (!Control.Created) + { + Thread.Sleep(0); + Application.DoEvents(); + } + + _rdpClient = (MsRdpClient8NotSafeForScripting)((AxMsRdpClient8NotSafeForScripting)Control).GetOcx(); + } + catch (System.Runtime.InteropServices.COMException ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strRdpControlCreationFailed, ex); + Control.Dispose(); + return false; + } + + _rdpVersion = new Version(_rdpClient.Version); + + _rdpClient.Server = _connectionInfo.Hostname; SetCredentials(); SetResolution(); @@ -133,549 +138,577 @@ namespace mRemoteNG.Connection.Protocol.RDP //not user changeable _rdpClient.AdvancedSettings2.GrabFocusOnConnect = true; - _rdpClient.AdvancedSettings3.EnableAutoReconnect = true; - _rdpClient.AdvancedSettings3.MaxReconnectAttempts = Settings.Default.RdpReconnectionCount; - _rdpClient.AdvancedSettings2.keepAliveInterval = 60000; //in milliseconds (10,000 = 10 seconds) - _rdpClient.AdvancedSettings5.AuthenticationLevel = 0; - _rdpClient.AdvancedSettings2.EncryptionEnabled = 1; - - _rdpClient.AdvancedSettings2.overallConnectionTimeout = Settings.Default.ConRDPOverallConnectionTimeout; - - _rdpClient.AdvancedSettings2.BitmapPeristence = Convert.ToInt32(_connectionInfo.CacheBitmaps); - if (_rdpVersion >= Versions.RDC61) - { - _rdpClient.AdvancedSettings7.EnableCredSspSupport = _connectionInfo.UseCredSsp; - _rdpClient.AdvancedSettings8.AudioQualityMode = (uint)_connectionInfo.SoundQuality; - } + _rdpClient.AdvancedSettings3.EnableAutoReconnect = true; + _rdpClient.AdvancedSettings3.MaxReconnectAttempts = Settings.Default.RdpReconnectionCount; + _rdpClient.AdvancedSettings2.keepAliveInterval = 60000; //in milliseconds (10,000 = 10 seconds) + _rdpClient.AdvancedSettings5.AuthenticationLevel = 0; + _rdpClient.AdvancedSettings2.EncryptionEnabled = 1; + + _rdpClient.AdvancedSettings2.overallConnectionTimeout = Settings.Default.ConRDPOverallConnectionTimeout; + + _rdpClient.AdvancedSettings2.BitmapPeristence = Convert.ToInt32(_connectionInfo.CacheBitmaps); + if (_rdpVersion >= Versions.RDC61) + { + _rdpClient.AdvancedSettings7.EnableCredSspSupport = _connectionInfo.UseCredSsp; + _rdpClient.AdvancedSettings8.AudioQualityMode = (uint)_connectionInfo.SoundQuality; + } SetUseConsoleSession(); SetPort(); - RedirectKeys = _connectionInfo.RedirectKeys; + RedirectKeys = _connectionInfo.RedirectKeys; SetRedirection(); SetAuthenticationLevel(); - SetLoadBalanceInfo(); + SetLoadBalanceInfo(); SetRdGateway(); _rdpClient.ColorDepth = (int)_connectionInfo.Colors; SetPerformanceFlags(); - - _rdpClient.ConnectingText = Language.strConnecting; - - Control.Anchor = AnchorStyles.None; - - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPropsFailed, ex); - return false; - } - } - public override bool Connect() - { - _loginComplete = false; - SetEventHandlers(); + _rdpClient.ConnectingText = Language.strConnecting; + + Control.Anchor = AnchorStyles.None; + + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPropsFailed, ex); + return false; + } + } + + public override bool Connect() + { + _loginComplete = false; + SetEventHandlers(); try - { - _rdpClient.Connect(); - base.Connect(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); - } - - return false; - } - - public override void Disconnect() - { - try - { - _rdpClient.Disconnect(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpDisconnectFailed, ex); - Close(); - } - } - - public void ToggleFullscreen() - { - try - { - Fullscreen = !Fullscreen; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpToggleFullscreenFailed, ex); - } - } - - public void ToggleSmartSize() - { - try - { - SmartSize = !SmartSize; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpToggleSmartSizeFailed, ex); - } - } - - public override void Focus() - { - try - { - if (Control.ContainsFocus == false) - { - Control.Focus(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex); - } - } - - private Size _controlBeginningSize; - public override void ResizeBegin(object sender, EventArgs e) - { - _controlBeginningSize = Control.Size; - } - - public override void Resize(object sender, EventArgs e) - { - if (DoResize() && _controlBeginningSize.IsEmpty) - { - ReconnectForResize(); - } - base.Resize(sender, e); - } - - public override void ResizeEnd(object sender, EventArgs e) - { - DoResize(); - if (!(Control.Size == _controlBeginningSize)) - { - ReconnectForResize(); - } - _controlBeginningSize = Size.Empty; - } - #endregion - - #region Private Methods - private bool DoResize() - { - Control.Location = InterfaceControl.Location; - if (!(Control.Size == InterfaceControl.Size) && !(InterfaceControl.Size == Size.Empty)) // kmscode - this doesn't look right to me. But I'm not aware of any functionality issues with this currently... - { - Control.Size = InterfaceControl.Size; - return true; - } - else - { - return false; - } - } - - private void ReconnectForResize() - { - if (_rdpVersion < Versions.RDC80) - { - return; - } - - if (!_loginComplete) - { - return; - } - - if (!InterfaceControl.Info.AutomaticResize) - { - return; - } - - if (!(InterfaceControl.Info.Resolution == RDPResolutions.FitToWindow | InterfaceControl.Info.Resolution == RDPResolutions.Fullscreen)) - { - return; - } - - if (SmartSize) - { - return; - } + { + _rdpClient.Connect(); + base.Connect(); + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); + } - try - { - Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Resizing RDP connection to host '{_connectionInfo.Hostname}'"); - var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size; + return false; + } + + public override void Disconnect() + { + try + { + _rdpClient.Disconnect(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpDisconnectFailed, ex); + Close(); + } + } + + public void ToggleFullscreen() + { + try + { + Fullscreen = !Fullscreen; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpToggleFullscreenFailed, ex); + } + } + + public void ToggleSmartSize() + { + try + { + SmartSize = !SmartSize; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpToggleSmartSizeFailed, ex); + } + } + + public override void Focus() + { + try + { + if (Control.ContainsFocus == false) + { + Control.Focus(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex); + } + } + + private Size _controlBeginningSize; + + public override void ResizeBegin(object sender, EventArgs e) + { + _controlBeginningSize = Control.Size; + } + + public override void Resize(object sender, EventArgs e) + { + if (DoResize() && _controlBeginningSize.IsEmpty) + { + ReconnectForResize(); + } + + base.Resize(sender, e); + } + + public override void ResizeEnd(object sender, EventArgs e) + { + DoResize(); + if (!(Control.Size == _controlBeginningSize)) + { + ReconnectForResize(); + } + + _controlBeginningSize = Size.Empty; + } + + #endregion + + #region Private Methods + + private bool DoResize() + { + Control.Location = InterfaceControl.Location; + if (!(Control.Size == InterfaceControl.Size) && !(InterfaceControl.Size == Size.Empty) + ) // kmscode - this doesn't look right to me. But I'm not aware of any functionality issues with this currently... + { + Control.Size = InterfaceControl.Size; + return true; + } + else + { + return false; + } + } + + private void ReconnectForResize() + { + if (_rdpVersion < Versions.RDC80) + { + return; + } + + if (!_loginComplete) + { + return; + } + + if (!InterfaceControl.Info.AutomaticResize) + { + return; + } + + if (!(InterfaceControl.Info.Resolution == RDPResolutions.FitToWindow | + InterfaceControl.Info.Resolution == RDPResolutions.Fullscreen)) + { + return; + } + + if (SmartSize) + { + return; + } + + try + { + Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, + $"Resizing RDP connection to host '{_connectionInfo.Hostname}'"); + var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size; IMsRdpClient8 msRdpClient8 = _rdpClient; - msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.ChangeConnectionResolutionError, _connectionInfo.Hostname), - ex, MessageClass.WarningMsg, false); - } - } - - private void SetRdGateway() - { - try - { - if (_rdpClient.TransportSettings.GatewayIsSupported == 0) - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strRdpGatewayNotSupported, true); - return; - } - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strRdpGatewayIsSupported, true); + msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + string.Format(Language.ChangeConnectionResolutionError, + _connectionInfo.Hostname), + ex, MessageClass.WarningMsg, false); + } + } - if (_connectionInfo.RDGatewayUsageMethod != RDGatewayUsageMethod.Never) - { - _rdpClient.TransportSettings.GatewayUsageMethod = (uint)_connectionInfo.RDGatewayUsageMethod; - _rdpClient.TransportSettings.GatewayHostname = _connectionInfo.RDGatewayHostname; - _rdpClient.TransportSettings.GatewayProfileUsageMethod = 1; // TSC_PROXY_PROFILE_MODE_EXPLICIT - if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard) - { - _rdpClient.TransportSettings.GatewayCredsSource = 1; // TSC_PROXY_CREDS_MODE_SMARTCARD - } - if (_rdpVersion >= Versions.RDC61 && !Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes) - { - _rdpClient.TransportSettings2.GatewayUsername = _connectionInfo.Username; - _rdpClient.TransportSettings2.GatewayPassword = _connectionInfo.Password; - _rdpClient.TransportSettings2.GatewayDomain = _connectionInfo?.Domain; - } - else if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard) - { - _rdpClient.TransportSettings2.GatewayCredSharing = 0; - } - else - { + private void SetRdGateway() + { + try + { + if (_rdpClient.TransportSettings.GatewayIsSupported == 0) + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strRdpGatewayNotSupported, + true); + return; + } + + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strRdpGatewayIsSupported, + true); + + if (_connectionInfo.RDGatewayUsageMethod != RDGatewayUsageMethod.Never) + { + _rdpClient.TransportSettings.GatewayUsageMethod = (uint)_connectionInfo.RDGatewayUsageMethod; + _rdpClient.TransportSettings.GatewayHostname = _connectionInfo.RDGatewayHostname; + _rdpClient.TransportSettings.GatewayProfileUsageMethod = 1; // TSC_PROXY_PROFILE_MODE_EXPLICIT + if (_connectionInfo.RDGatewayUseConnectionCredentials == + RDGatewayUseConnectionCredentials.SmartCard) + { + _rdpClient.TransportSettings.GatewayCredsSource = 1; // TSC_PROXY_CREDS_MODE_SMARTCARD + } + + if (_rdpVersion >= Versions.RDC61 && !Force.HasFlag(ConnectionInfo.Force.NoCredentials)) + { + if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes) + { + _rdpClient.TransportSettings2.GatewayUsername = _connectionInfo.Username; + _rdpClient.TransportSettings2.GatewayPassword = _connectionInfo.Password; + _rdpClient.TransportSettings2.GatewayDomain = _connectionInfo?.Domain; + } + else if (_connectionInfo.RDGatewayUseConnectionCredentials == + RDGatewayUseConnectionCredentials.SmartCard) + { + _rdpClient.TransportSettings2.GatewayCredSharing = 0; + } + else + { _rdpClient.TransportSettings2.GatewayUsername = _connectionInfo.RDGatewayUsername; _rdpClient.TransportSettings2.GatewayPassword = _connectionInfo.RDGatewayPassword; _rdpClient.TransportSettings2.GatewayDomain = _connectionInfo.RDGatewayDomain; _rdpClient.TransportSettings2.GatewayCredSharing = 0; } - } - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetGatewayFailed, ex); - } - } - - private void SetUseConsoleSession() - { - try - { - bool value; - - if (Force.HasFlag(ConnectionInfo.Force.UseConsoleSession)) - { - value = true; - } - else if (Force.HasFlag(ConnectionInfo.Force.DontUseConsoleSession)) - { - value = false; - } - else - { - value = _connectionInfo.UseConsoleSession; - } - - if (_rdpVersion >= Versions.RDC61) - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strRdpSetConsoleSwitch, _rdpVersion), true); - _rdpClient.AdvancedSettings7.ConnectToAdministerServer = value; - } - else - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strRdpSetConsoleSwitch, _rdpVersion) + Environment.NewLine + "No longer supported in this RDP version. Reference: https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx", true); + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetGatewayFailed, ex); + } + } + + private void SetUseConsoleSession() + { + try + { + bool value; + + if (Force.HasFlag(ConnectionInfo.Force.UseConsoleSession)) + { + value = true; + } + else if (Force.HasFlag(ConnectionInfo.Force.DontUseConsoleSession)) + { + value = false; + } + else + { + value = _connectionInfo.UseConsoleSession; + } + + if (_rdpVersion >= Versions.RDC61) + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strRdpSetConsoleSwitch, _rdpVersion), + true); + _rdpClient.AdvancedSettings7.ConnectToAdministerServer = value; + } + else + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + string.Format(Language.strRdpSetConsoleSwitch, _rdpVersion) + + Environment.NewLine + + "No longer supported in this RDP version. Reference: https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx", + true); // ConnectToServerConsole is deprecated //https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx //_rdpClient.AdvancedSettings2.ConnectToServerConsole = value; } } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetConsoleSessionFailed, ex); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetConsoleSessionFailed, ex); + } + } - private object GetExtendedProperty(string property) - { - try - { - // ReSharper disable once UseIndexedProperty - return ((IMsRdpExtendedSettings)_rdpClient).get_Property(property); - } - catch (Exception e) - { - Runtime.MessageCollector.AddExceptionMessage($"Error getting extended RDP property '{property}'", - e, MessageClass.WarningMsg, false); - return null; - } - } + private object GetExtendedProperty(string property) + { + try + { + // ReSharper disable once UseIndexedProperty + return ((IMsRdpExtendedSettings)_rdpClient).get_Property(property); + } + catch (Exception e) + { + Runtime.MessageCollector.AddExceptionMessage($"Error getting extended RDP property '{property}'", + e, MessageClass.WarningMsg, false); + return null; + } + } private void SetExtendedProperty(string property, object value) - { - try - { - // ReSharper disable once UseIndexedProperty - ((IMsRdpExtendedSettings)_rdpClient).set_Property(property, ref value); - } - catch (Exception e) - { - Runtime.MessageCollector.AddExceptionMessage($"Error setting extended RDP property '{property}'", - e, MessageClass.WarningMsg, false); - } - } + { + try + { + // ReSharper disable once UseIndexedProperty + ((IMsRdpExtendedSettings)_rdpClient).set_Property(property, ref value); + } + catch (Exception e) + { + Runtime.MessageCollector.AddExceptionMessage($"Error setting extended RDP property '{property}'", + e, MessageClass.WarningMsg, false); + } + } - private void SetCredentials() - { - try - { - if (Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - return; - } + private void SetCredentials() + { + try + { + if (Force.HasFlag(ConnectionInfo.Force.NoCredentials)) + { + return; + } - var userName = _connectionInfo?.Username ?? ""; - var password = _connectionInfo?.Password ?? ""; - var domain = _connectionInfo?.Domain ?? ""; - - if (string.IsNullOrEmpty(userName)) - { - if (Settings.Default.EmptyCredentials == "windows") - { - _rdpClient.UserName = Environment.UserName; - } - else if (Settings.Default.EmptyCredentials == "custom") - { - _rdpClient.UserName = Settings.Default.DefaultUsername; - } - } - else - { - _rdpClient.UserName = userName; - } - - if (string.IsNullOrEmpty(password)) - { - if (Settings.Default.EmptyCredentials == "custom") - { - if (Settings.Default.DefaultPassword != "") - { + var userName = _connectionInfo?.Username ?? ""; + var password = _connectionInfo?.Password ?? ""; + var domain = _connectionInfo?.Domain ?? ""; + + if (string.IsNullOrEmpty(userName)) + { + if (Settings.Default.EmptyCredentials == "windows") + { + _rdpClient.UserName = Environment.UserName; + } + else if (Settings.Default.EmptyCredentials == "custom") + { + _rdpClient.UserName = Settings.Default.DefaultUsername; + } + } + else + { + _rdpClient.UserName = userName; + } + + if (string.IsNullOrEmpty(password)) + { + if (Settings.Default.EmptyCredentials == "custom") + { + if (Settings.Default.DefaultPassword != "") + { var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - _rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); - } - } - } - else - { - _rdpClient.AdvancedSettings2.ClearTextPassword = password; - } - - if (string.IsNullOrEmpty(domain)) - { - if (Settings.Default.EmptyCredentials == "windows") - { - _rdpClient.Domain = Environment.UserDomainName; - } - else if (Settings.Default.EmptyCredentials == "custom") - { - _rdpClient.Domain = Settings.Default.DefaultDomain; - } - } - else - { - _rdpClient.Domain = domain; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetCredentialsFailed, ex); - } - } - - private void SetResolution() - { - try - { - var scaleFactor = (uint)_displayProperties.ResolutionScalingFactor.Width * 100; - SetExtendedProperty("DesktopScaleFactor", scaleFactor); - SetExtendedProperty("DeviceScaleFactor", (uint)100); + _rdpClient.AdvancedSettings2.ClearTextPassword = + cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); + } + } + } + else + { + _rdpClient.AdvancedSettings2.ClearTextPassword = password; + } + + if (string.IsNullOrEmpty(domain)) + { + if (Settings.Default.EmptyCredentials == "windows") + { + _rdpClient.Domain = Environment.UserDomainName; + } + else if (Settings.Default.EmptyCredentials == "custom") + { + _rdpClient.Domain = Settings.Default.DefaultDomain; + } + } + else + { + _rdpClient.Domain = domain; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetCredentialsFailed, ex); + } + } + + private void SetResolution() + { + try + { + var scaleFactor = (uint)_displayProperties.ResolutionScalingFactor.Width * 100; + SetExtendedProperty("DesktopScaleFactor", scaleFactor); + SetExtendedProperty("DeviceScaleFactor", (uint)100); if (Force.HasFlag(ConnectionInfo.Force.Fullscreen)) - { - _rdpClient.FullScreen = true; + { + _rdpClient.FullScreen = true; _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; - - return; - } - - if ((InterfaceControl.Info.Resolution == RDPResolutions.FitToWindow) || (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize)) - { - _rdpClient.DesktopWidth = InterfaceControl.Size.Width; - _rdpClient.DesktopHeight = InterfaceControl.Size.Height; - if (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize) - { + return; + } + + if ((InterfaceControl.Info.Resolution == RDPResolutions.FitToWindow) || + (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize)) + { + _rdpClient.DesktopWidth = InterfaceControl.Size.Width; + _rdpClient.DesktopHeight = InterfaceControl.Size.Height; + + if (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize) + { _rdpClient.AdvancedSettings2.SmartSizing = true; } - } - else if (InterfaceControl.Info.Resolution == RDPResolutions.Fullscreen) - { - _rdpClient.FullScreen = true; + } + else if (InterfaceControl.Info.Resolution == RDPResolutions.Fullscreen) + { + _rdpClient.FullScreen = true; _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; - } - else - { - var resolution = GetResolutionRectangle(_connectionInfo.Resolution); - _rdpClient.DesktopWidth = resolution.Width; - _rdpClient.DesktopHeight = resolution.Height; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetResolutionFailed, ex); - } - } - - private void SetPort() - { - try - { - if (_connectionInfo.Port != (int)Defaults.Port) - { - _rdpClient.AdvancedSettings2.RDPPort = _connectionInfo.Port; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPortFailed, ex); - } - } - - private void SetRedirection() - { - try - { - _rdpClient.AdvancedSettings2.RedirectDrives = _connectionInfo.RedirectDiskDrives; - _rdpClient.AdvancedSettings2.RedirectPorts = _connectionInfo.RedirectPorts; - _rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters; - _rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards; - _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound; + } + else + { + var resolution = GetResolutionRectangle(_connectionInfo.Resolution); + _rdpClient.DesktopWidth = resolution.Width; + _rdpClient.DesktopHeight = resolution.Height; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetResolutionFailed, ex); + } + } + + private void SetPort() + { + try + { + if (_connectionInfo.Port != (int)Defaults.Port) + { + _rdpClient.AdvancedSettings2.RDPPort = _connectionInfo.Port; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPortFailed, ex); + } + } + + private void SetRedirection() + { + try + { + _rdpClient.AdvancedSettings2.RedirectDrives = _connectionInfo.RedirectDiskDrives; + _rdpClient.AdvancedSettings2.RedirectPorts = _connectionInfo.RedirectPorts; + _rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters; + _rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards; + _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound; _rdpClient.AdvancedSettings.DisableRdpdr = _connectionInfo.RedirectClipboard ? 0 : 1; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetRedirectionFailed, ex); - } - } - - private void SetPerformanceFlags() - { - try - { - var pFlags = 0; - if (_connectionInfo.DisplayThemes == false) - { - pFlags += Convert.ToInt32(RDPPerformanceFlags.DisableThemes); - } - - if (_connectionInfo.DisplayWallpaper == false) - { - pFlags += Convert.ToInt32(RDPPerformanceFlags.DisableWallpaper); - } - - if (_connectionInfo.EnableFontSmoothing) - { - pFlags += Convert.ToInt32(RDPPerformanceFlags.EnableFontSmoothing); - } - - if (_connectionInfo.EnableDesktopComposition) - { - pFlags += Convert.ToInt32(RDPPerformanceFlags.EnableDesktopComposition); - } - - _rdpClient.AdvancedSettings2.PerformanceFlags = pFlags; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPerformanceFlagsFailed, ex); - } - } - - private void SetAuthenticationLevel() - { - try - { - _rdpClient.AdvancedSettings5.AuthenticationLevel = (uint)_connectionInfo.RDPAuthenticationLevel; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetAuthenticationLevelFailed, ex); - } - } - - private void SetLoadBalanceInfo() - { - if (string.IsNullOrEmpty(_connectionInfo.LoadBalanceInfo)) - { - return; - } - try - { - _rdpClient.AdvancedSettings2.LoadBalanceInfo = LoadBalanceInfoUseUtf8 - ? new AzureLoadBalanceInfoEncoder().Encode(_connectionInfo.LoadBalanceInfo) + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetRedirectionFailed, ex); + } + } + + private void SetPerformanceFlags() + { + try + { + var pFlags = 0; + if (_connectionInfo.DisplayThemes == false) + { + pFlags += Convert.ToInt32(RDPPerformanceFlags.DisableThemes); + } + + if (_connectionInfo.DisplayWallpaper == false) + { + pFlags += Convert.ToInt32(RDPPerformanceFlags.DisableWallpaper); + } + + if (_connectionInfo.EnableFontSmoothing) + { + pFlags += Convert.ToInt32(RDPPerformanceFlags.EnableFontSmoothing); + } + + if (_connectionInfo.EnableDesktopComposition) + { + pFlags += Convert.ToInt32(RDPPerformanceFlags.EnableDesktopComposition); + } + + _rdpClient.AdvancedSettings2.PerformanceFlags = pFlags; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetPerformanceFlagsFailed, ex); + } + } + + private void SetAuthenticationLevel() + { + try + { + _rdpClient.AdvancedSettings5.AuthenticationLevel = (uint)_connectionInfo.RDPAuthenticationLevel; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetAuthenticationLevelFailed, ex); + } + } + + private void SetLoadBalanceInfo() + { + if (string.IsNullOrEmpty(_connectionInfo.LoadBalanceInfo)) + { + return; + } + + try + { + _rdpClient.AdvancedSettings2.LoadBalanceInfo = LoadBalanceInfoUseUtf8 + ? new AzureLoadBalanceInfoEncoder().Encode(_connectionInfo.LoadBalanceInfo) : _connectionInfo.LoadBalanceInfo; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("Unable to set load balance info.", ex); - } - } - - private void SetEventHandlers() - { - try - { - _rdpClient.OnConnecting += RDPEvent_OnConnecting; - _rdpClient.OnConnected += RDPEvent_OnConnected; - _rdpClient.OnLoginComplete += RDPEvent_OnLoginComplete; - _rdpClient.OnFatalError += RDPEvent_OnFatalError; - _rdpClient.OnDisconnected += RDPEvent_OnDisconnected; - _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Unable to set load balance info.", ex); + } + } + + private void SetEventHandlers() + { + try + { + _rdpClient.OnConnecting += RDPEvent_OnConnecting; + _rdpClient.OnConnected += RDPEvent_OnConnected; + _rdpClient.OnLoginComplete += RDPEvent_OnLoginComplete; + _rdpClient.OnFatalError += RDPEvent_OnFatalError; + _rdpClient.OnDisconnected += RDPEvent_OnDisconnected; + _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; _rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification; } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetEventHandlersFailed, ex); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetEventHandlersFailed, ex); + } + } + #endregion - + #region Private Events & Handlers + private void RDPEvent_OnIdleTimeoutNotification() { Close(); //Simply close the RDP Session if the idle timeout has been triggered. if (!_alertOnIdleDisconnect) return; - MessageBox.Show($"The {_connectionInfo.Name} session was disconnected due to inactivity", "Session Disconnected", MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show($"The {_connectionInfo.Name} session was disconnected due to inactivity", + "Session Disconnected", MessageBoxButtons.OK, MessageBoxIcon.Information); } @@ -683,233 +716,251 @@ namespace mRemoteNG.Connection.Protocol.RDP { var errorMsg = RdpErrorCodes.GetError(errorCode); Event_ErrorOccured(this, errorMsg, errorCode); - } - - private void RDPEvent_OnDisconnected(int discReason) - { - const int UI_ERR_NORMAL_DISCONNECT = 0xB08; - if (discReason != UI_ERR_NORMAL_DISCONNECT) - { - var reason = _rdpClient.GetErrorDescription((uint)discReason, (uint) _rdpClient.ExtendedDisconnectReason); - Event_Disconnected(this, reason, discReason); - } - - if (Settings.Default.ReconnectOnDisconnect) - { - ReconnectGroup = new ReconnectGroup(); - ReconnectGroup.CloseClicked += Event_ReconnectGroupCloseClicked; - ReconnectGroup.Left = (int) ((double) Control.Width / 2 - (double) ReconnectGroup.Width / 2); - ReconnectGroup.Top = (int) ((double) Control.Height / 2 - (double) ReconnectGroup.Height / 2); - ReconnectGroup.Parent = Control; - ReconnectGroup.Show(); - tmrReconnect.Enabled = true; - } - else - { - Close(); - } - } - - private void RDPEvent_OnConnecting() - { - Event_Connecting(this); - } - - private void RDPEvent_OnConnected() - { - Event_Connected(this); - } - - private void RDPEvent_OnLoginComplete() - { - _loginComplete = true; - } - - private void RDPEvent_OnLeaveFullscreenMode() - { - Fullscreen = false; + } + + private void RDPEvent_OnDisconnected(int discReason) + { + const int UI_ERR_NORMAL_DISCONNECT = 0xB08; + if (discReason != UI_ERR_NORMAL_DISCONNECT) + { + var reason = + _rdpClient.GetErrorDescription((uint)discReason, (uint)_rdpClient.ExtendedDisconnectReason); + Event_Disconnected(this, reason, discReason); + } + + if (Settings.Default.ReconnectOnDisconnect) + { + ReconnectGroup = new ReconnectGroup(); + ReconnectGroup.CloseClicked += Event_ReconnectGroupCloseClicked; + ReconnectGroup.Left = (int)((double)Control.Width / 2 - (double)ReconnectGroup.Width / 2); + ReconnectGroup.Top = (int)((double)Control.Height / 2 - (double)ReconnectGroup.Height / 2); + ReconnectGroup.Parent = Control; + ReconnectGroup.Show(); + tmrReconnect.Enabled = true; + } + else + { + Close(); + } + } + + private void RDPEvent_OnConnecting() + { + Event_Connecting(this); + } + + private void RDPEvent_OnConnected() + { + Event_Connected(this); + } + + private void RDPEvent_OnLoginComplete() + { + _loginComplete = true; + } + + private void RDPEvent_OnLeaveFullscreenMode() + { + Fullscreen = false; _leaveFullscreenEvent?.Invoke(this, new EventArgs()); } + #endregion - + #region Public Events & Handlers - public delegate void LeaveFullscreenEventHandler(object sender, EventArgs e); - private LeaveFullscreenEventHandler _leaveFullscreenEvent; - - public event LeaveFullscreenEventHandler LeaveFullscreen - { - add => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Combine(_leaveFullscreenEvent, value); - remove => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Remove(_leaveFullscreenEvent, value); + + public delegate void LeaveFullscreenEventHandler(object sender, EventArgs e); + + private LeaveFullscreenEventHandler _leaveFullscreenEvent; + + public event LeaveFullscreenEventHandler LeaveFullscreen + { + add => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Combine(_leaveFullscreenEvent, value); + remove => + _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Remove(_leaveFullscreenEvent, value); } + #endregion - + #region Enums - public enum Defaults - { - Colors = RDPColors.Colors16Bit, - Sounds = RDPSounds.DoNotPlay, - Resolution = RDPResolutions.FitToWindow, - Port = 3389 - } - - public enum RDPColors - { + + public enum Defaults + { + Colors = RDPColors.Colors16Bit, + Sounds = RDPSounds.DoNotPlay, + Resolution = RDPResolutions.FitToWindow, + Port = 3389 + } + + public enum RDPColors + { [LocalizedAttributes.LocalizedDescription("strRDP256Colors")] Colors256 = 8, + [LocalizedAttributes.LocalizedDescription("strRDP32768Colors")] Colors15Bit = 15, + [LocalizedAttributes.LocalizedDescription("strRDP65536Colors")] Colors16Bit = 16, + [LocalizedAttributes.LocalizedDescription("strRDP16777216Colors")] Colors24Bit = 24, + [LocalizedAttributes.LocalizedDescription("strRDP4294967296Colors")] Colors32Bit = 32 - } - - public enum RDPSounds - { + } + + public enum RDPSounds + { [LocalizedAttributes.LocalizedDescription("strRDPSoundBringToThisComputer")] BringToThisComputer = 0, + [LocalizedAttributes.LocalizedDescription("strRDPSoundLeaveAtRemoteComputer")] LeaveAtRemoteComputer = 1, + [LocalizedAttributes.LocalizedDescription("strRDPSoundDoNotPlay")] DoNotPlay = 2 - } + } - public enum RDPSoundQuality - { + public enum RDPSoundQuality + { [LocalizedAttributes.LocalizedDescription("strRDPSoundQualityDynamic")] Dynamic = 0, + [LocalizedAttributes.LocalizedDescription("strRDPSoundQualityMedium")] Medium = 1, + [LocalizedAttributes.LocalizedDescription("strRDPSoundQualityHigh")] High = 2 } private enum RDPPerformanceFlags - { - [Description("strRDPDisableWallpaper")]DisableWallpaper = 0x1, + { + [Description("strRDPDisableWallpaper")] + DisableWallpaper = 0x1, + // [Description("strRDPDisableFullWindowdrag")]DisableFullWindowDrag = 0x2, // [Description("strRDPDisableMenuAnimations")]DisableMenuAnimations = 0x4, - [Description("strRDPDisableThemes")]DisableThemes = 0x8, + [Description("strRDPDisableThemes")] DisableThemes = 0x8, + // [Description("strRDPDisableCursorShadow")]DisableCursorShadow = 0x20, // [Description("strRDPDisableCursorblinking")]DisableCursorBlinking = 0x40, - [Description("strRDPEnableFontSmoothing")]EnableFontSmoothing = 0x80, - [Description("strRDPEnableDesktopComposition")]EnableDesktopComposition = 0x100 - } + [Description("strRDPEnableFontSmoothing")] + EnableFontSmoothing = 0x80, + + [Description("strRDPEnableDesktopComposition")] + EnableDesktopComposition = 0x100 + } public enum RDPResolutions { [LocalizedAttributes.LocalizedDescription("strRDPFitToPanel")] FitToWindow, + [LocalizedAttributes.LocalizedDescription("strFullscreen")] Fullscreen, + [LocalizedAttributes.LocalizedDescription("strRDPSmartSize")] SmartSize, - [Description("800x600")] - Res800x600, - [Description("1024x768")] - Res1024x768, - [Description("1152x864")] - Res1152x864, - [Description("1280x800")] - Res1280x800, - [Description("1280x1024")] - Res1280x1024, - [Description("1366x768")] - Res1366x768, - [Description("1440x900")] - Res1440x900, - [Description("1600x900")] - Res1600x900, - [Description("1600x1200")] - Res1600x1200, - [Description("1680x1050")] - Res1680x1050, - [Description("1920x1080")] - Res1920x1080, - [Description("1920x1200")] - Res1920x1200, - [Description("2048x1536")] - Res2048x1536, - [Description("2560x1440")] - Res2560x1440, - [Description("2560x1600")] - Res2560x1600, - [Description("2560x2048")] - Res2560x2048, - [Description("3840x2160")] - Res3840x2160 + [Description("800x600")] Res800x600, + [Description("1024x768")] Res1024x768, + [Description("1152x864")] Res1152x864, + [Description("1280x800")] Res1280x800, + [Description("1280x1024")] Res1280x1024, + [Description("1366x768")] Res1366x768, + [Description("1440x900")] Res1440x900, + [Description("1600x900")] Res1600x900, + [Description("1600x1200")] Res1600x1200, + [Description("1680x1050")] Res1680x1050, + [Description("1920x1080")] Res1920x1080, + [Description("1920x1200")] Res1920x1200, + [Description("2048x1536")] Res2048x1536, + [Description("2560x1440")] Res2560x1440, + [Description("2560x1600")] Res2560x1600, + [Description("2560x2048")] Res2560x2048, + [Description("3840x2160")] Res3840x2160 } public enum AuthenticationLevel - { + { [LocalizedAttributes.LocalizedDescription("strAlwaysConnectEvenIfAuthFails")] NoAuth = 0, + [LocalizedAttributes.LocalizedDescription("strDontConnectWhenAuthFails")] AuthRequired = 1, + [LocalizedAttributes.LocalizedDescription("strWarnIfAuthFails")] WarnOnFailedAuth = 2 - } - - public enum RDGatewayUsageMethod - { + } + + public enum RDGatewayUsageMethod + { [LocalizedAttributes.LocalizedDescription("strNever")] Never = 0, // TSC_PROXY_MODE_NONE_DIRECT + [LocalizedAttributes.LocalizedDescription("strAlways")] Always = 1, // TSC_PROXY_MODE_DIRECT + [LocalizedAttributes.LocalizedDescription("strDetect")] Detect = 2 // TSC_PROXY_MODE_DETECT - } - - public enum RDGatewayUseConnectionCredentials - { + } + + public enum RDGatewayUseConnectionCredentials + { [LocalizedAttributes.LocalizedDescription("strUseDifferentUsernameAndPassword")] No = 0, + [LocalizedAttributes.LocalizedDescription("strUseSameUsernameAndPassword")] Yes = 1, + [LocalizedAttributes.LocalizedDescription("strUseSmartCard")] SmartCard = 2 - } + } + #endregion - + #region Resolution - public static Rectangle GetResolutionRectangle(RDPResolutions resolution) - { - string[] resolutionParts = null; - if (resolution != RDPResolutions.FitToWindow & resolution != RDPResolutions.Fullscreen & resolution != RDPResolutions.SmartSize) - { - resolutionParts = resolution.ToString().Replace("Res", "").Split('x'); - } - if (resolutionParts == null || resolutionParts.Length != 2) - { - return new Rectangle(0, 0, 0, 0); - } - else - { + + public static Rectangle GetResolutionRectangle(RDPResolutions resolution) + { + string[] resolutionParts = null; + if (resolution != RDPResolutions.FitToWindow & resolution != RDPResolutions.Fullscreen & + resolution != RDPResolutions.SmartSize) + { + resolutionParts = resolution.ToString().Replace("Res", "").Split('x'); + } + + if (resolutionParts == null || resolutionParts.Length != 2) + { + return new Rectangle(0, 0, 0, 0); + } + else + { return new Rectangle(0, 0, Convert.ToInt32(resolutionParts[0]), Convert.ToInt32(resolutionParts[1])); - } - } + } + } + #endregion public static class Versions - { - public static readonly Version RDC60 = new Version(6, 0, 6000); - public static readonly Version RDC61 = new Version(6, 0, 6001); - public static readonly Version RDC70 = new Version(6, 1, 7600); - public static readonly Version RDC80 = new Version(6, 2, 9200); + { + public static readonly Version RDC60 = new Version(6, 0, 6000); + public static readonly Version RDC61 = new Version(6, 0, 6001); + public static readonly Version RDC70 = new Version(6, 1, 7600); + public static readonly Version RDC80 = new Version(6, 2, 9200); public static readonly Version RDC81 = new Version(6, 3, 9600); - } - + } + #region Reconnect Stuff - public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - try - { - var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port)); - - ReconnectGroup.ServerReady = srvReady; + + public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + try + { + var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port)); + + ReconnectGroup.ServerReady = srvReady; if (!ReconnectGroup.ReconnectWhenReady || !srvReady) return; tmrReconnect.Enabled = false; @@ -917,12 +968,15 @@ namespace mRemoteNG.Connection.Protocol.RDP //SetProps() _rdpClient.Connect(); } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.AutomaticReconnectError, _connectionInfo.Hostname), - ex, MessageClass.WarningMsg, false); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + string.Format(Language.AutomaticReconnectError, + _connectionInfo.Hostname), + ex, MessageClass.WarningMsg, false); + } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Rlogin/Connection.Protocol.Rlogin.cs b/mRemoteV1/Connection/Protocol/Rlogin/Connection.Protocol.Rlogin.cs index 6a8b187b3..e3fcba198 100644 --- a/mRemoteV1/Connection/Protocol/Rlogin/Connection.Protocol.Rlogin.cs +++ b/mRemoteV1/Connection/Protocol/Rlogin/Connection.Protocol.Rlogin.cs @@ -1,16 +1,15 @@ namespace mRemoteNG.Connection.Protocol.Rlogin { - public class ProtocolRlogin : PuttyBase - { - - public ProtocolRlogin() - { - this.PuttyProtocol = Putty_Protocol.rlogin; - } - - public enum Defaults - { - Port = 513 - } - } + public class ProtocolRlogin : PuttyBase + { + public ProtocolRlogin() + { + this.PuttyProtocol = Putty_Protocol.rlogin; + } + + public enum Defaults + { + Port = 513 + } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs index d5e99500b..8472308d0 100644 --- a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs +++ b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH1.cs @@ -1,19 +1,16 @@ - - namespace mRemoteNG.Connection.Protocol.SSH { - public class ProtocolSSH1 : PuttyBase - { - - public ProtocolSSH1() - { - PuttyProtocol = Putty_Protocol.ssh; - PuttySSHVersion = Putty_SSHVersion.ssh1; - } - - public enum Defaults - { - Port = 22 - } - } -} + public class ProtocolSSH1 : PuttyBase + { + public ProtocolSSH1() + { + PuttyProtocol = Putty_Protocol.ssh; + PuttySSHVersion = Putty_SSHVersion.ssh1; + } + + public enum Defaults + { + Port = 22 + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs index 9bd6adf84..d05c40fef 100644 --- a/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs +++ b/mRemoteV1/Connection/Protocol/SSH/Connection.Protocol.SSH2.cs @@ -1,17 +1,16 @@ namespace mRemoteNG.Connection.Protocol.SSH { - public class ProtocolSSH2 : PuttyBase - { - - public ProtocolSSH2() - { - PuttyProtocol = Putty_Protocol.ssh; - PuttySSHVersion = Putty_SSHVersion.ssh2; - } - - public enum Defaults - { - Port = 22 - } - } -} + public class ProtocolSSH2 : PuttyBase + { + public ProtocolSSH2() + { + PuttyProtocol = Putty_Protocol.ssh; + PuttySSHVersion = Putty_SSHVersion.ssh2; + } + + public enum Defaults + { + Port = 22 + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Serial/Connection.Protocol.Serial.cs b/mRemoteV1/Connection/Protocol/Serial/Connection.Protocol.Serial.cs index 9e8d2ffd9..0f4ca94d1 100644 --- a/mRemoteV1/Connection/Protocol/Serial/Connection.Protocol.Serial.cs +++ b/mRemoteV1/Connection/Protocol/Serial/Connection.Protocol.Serial.cs @@ -1,16 +1,15 @@ namespace mRemoteNG.Connection.Protocol.Serial { - public class ProtocolSerial : PuttyBase - { - - public ProtocolSerial() - { - this.PuttyProtocol = Putty_Protocol.serial; - } - - public enum Defaults - { - Port = 9600 - } - } + public class ProtocolSerial : PuttyBase + { + public ProtocolSerial() + { + this.PuttyProtocol = Putty_Protocol.serial; + } + + public enum Defaults + { + Port = 9600 + } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/Telnet/Connection.Protocol.Telnet.cs b/mRemoteV1/Connection/Protocol/Telnet/Connection.Protocol.Telnet.cs index 7fc93cbfd..6f891c077 100644 --- a/mRemoteV1/Connection/Protocol/Telnet/Connection.Protocol.Telnet.cs +++ b/mRemoteV1/Connection/Protocol/Telnet/Connection.Protocol.Telnet.cs @@ -1,16 +1,15 @@ namespace mRemoteNG.Connection.Protocol.Telnet { - public class ProtocolTelnet : PuttyBase - { - - public ProtocolTelnet() - { - this.PuttyProtocol = Putty_Protocol.telnet; - } - - public enum Defaults - { - Port = 23 - } - } + public class ProtocolTelnet : PuttyBase + { + public ProtocolTelnet() + { + this.PuttyProtocol = Putty_Protocol.telnet; + } + + public enum Defaults + { + Port = 23 + } + } } \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs b/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs index 63db3a924..c948ca5da 100644 --- a/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs +++ b/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs @@ -3,280 +3,314 @@ using mRemoteNG.Tools; using mRemoteNG.UI.Forms; using System; using System.ComponentModel; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Connection.Protocol.VNC { public class ProtocolVNC : ProtocolBase - { + { #region Properties + public bool SmartSize { get { return _VNC.Scaled; } set { _VNC.Scaled = value; } } - public bool ViewOnly - { - get { return _VNC.ViewOnly; } - set { _VNC.ViewOnly = value; } - } + public bool ViewOnly + { + get { return _VNC.ViewOnly; } + set { _VNC.ViewOnly = value; } + } - #endregion - - #region Private Declarations - private VncSharp.RemoteDesktop _VNC; - private ConnectionInfo Info; #endregion - + + #region Private Declarations + + private VncSharp.RemoteDesktop _VNC; + private ConnectionInfo Info; + + #endregion + #region Public Methods - public ProtocolVNC() - { - Control = new VncSharp.RemoteDesktop(); - } - - public override bool Initialize() - { - base.Initialize(); - - try - { + + public ProtocolVNC() + { + Control = new VncSharp.RemoteDesktop(); + } + + public override bool Initialize() + { + base.Initialize(); + + try + { _VNC = (VncSharp.RemoteDesktop)Control; - - Info = InterfaceControl.Info; - - _VNC.VncPort = Info.Port; + + Info = InterfaceControl.Info; + + _VNC.VncPort = Info.Port; return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncSetPropsFailed + Environment.NewLine + ex.Message, true); - return false; - } - } - - public override bool Connect() - { - SetEventHandlers(); - - try - { - _VNC.Connect(Info.Hostname, Info.VNCViewOnly, Info.VNCSmartSizeMode != SmartSizeMode.SmartSNo); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message); - return false; - } - - return true; - } - - public override void Disconnect() - { - try - { - _VNC.Disconnect(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncConnectionDisconnectFailed + Environment.NewLine + ex.Message, true); - } - } - - public void SendSpecialKeys(SpecialKeys Keys) - { - try - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (Keys) - { - case SpecialKeys.CtrlAltDel: - _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlAltDel); - break; - case SpecialKeys.CtrlEsc: - _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlEsc); - break; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncSendSpecialKeysFailed + Environment.NewLine + ex.Message, true); - } - } - - public void ToggleSmartSize() - { - try - { - SmartSize = !SmartSize; - RefreshScreen(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncToggleSmartSizeFailed + Environment.NewLine + ex.Message, true); - } - } - - public void ToggleViewOnly() - { - try - { - ViewOnly = !ViewOnly; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncToggleViewOnlyFailed + Environment.NewLine + ex.Message, true); - } - } - - - public void StartChat() - { - throw new NotImplementedException(); - } - - public void StartFileTransfer() - { + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSetPropsFailed + Environment.NewLine + ex.Message, + true); + return false; + } + } + + public override bool Connect() + { + SetEventHandlers(); + + try + { + _VNC.Connect(Info.Hostname, Info.VNCViewOnly, Info.VNCSmartSizeMode != SmartSizeMode.SmartSNo); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strConnectionOpenFailed + Environment.NewLine + + ex.Message); + return false; + } + + return true; + } + + public override void Disconnect() + { + try + { + _VNC.Disconnect(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncConnectionDisconnectFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void SendSpecialKeys(SpecialKeys Keys) + { + try + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (Keys) + { + case SpecialKeys.CtrlAltDel: + _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlAltDel); + break; + case SpecialKeys.CtrlEsc: + _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlEsc); + break; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSendSpecialKeysFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void ToggleSmartSize() + { + try + { + SmartSize = !SmartSize; + RefreshScreen(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncToggleSmartSizeFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void ToggleViewOnly() + { + try + { + ViewOnly = !ViewOnly; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncToggleViewOnlyFailed + Environment.NewLine + + ex.Message, true); + } + } + + + public void StartChat() + { throw new NotImplementedException(); } - - public void RefreshScreen() - { - try - { - _VNC.FullScreenUpdate(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncRefreshFailed + Environment.NewLine + ex.Message, true); - } - } - #endregion - - #region Private Methods - private void SetEventHandlers() - { - try - { - _VNC.ConnectComplete += VNCEvent_Connected; - _VNC.ConnectionLost += VNCEvent_Disconnected; - FrmMain.ClipboardChanged += VNCEvent_ClipboardChanged; - if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials) && Info?.Password?.Length > 0) - { - _VNC.GetPassword = VNCEvent_Authenticate; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strVncSetEventHandlersFailed + Environment.NewLine + ex.Message, true); - } - } - #endregion - - #region Private Events & Handlers - private void VNCEvent_Connected(object sender, EventArgs e) - { - Event_Connected(this); - _VNC.AutoScroll = Info.VNCSmartSizeMode == SmartSizeMode.SmartSNo; - } - - private void VNCEvent_Disconnected(object sender, EventArgs e) - { - FrmMain.ClipboardChanged -= VNCEvent_ClipboardChanged; - Event_Disconnected(sender, @"VncSharp Disconnected.", null); - Close(); - } - - private void VNCEvent_ClipboardChanged() - { - _VNC.FillServerClipboard(); - } - - private string VNCEvent_Authenticate() - { - return Info.Password; - } - #endregion - + public void StartFileTransfer() + { + throw new NotImplementedException(); + } + + public void RefreshScreen() + { + try + { + _VNC.FullScreenUpdate(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncRefreshFailed + Environment.NewLine + ex.Message, + true); + } + } + + #endregion + + #region Private Methods + + private void SetEventHandlers() + { + try + { + _VNC.ConnectComplete += VNCEvent_Connected; + _VNC.ConnectionLost += VNCEvent_Disconnected; + FrmMain.ClipboardChanged += VNCEvent_ClipboardChanged; + if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials) && Info?.Password?.Length > 0) + { + _VNC.GetPassword = VNCEvent_Authenticate; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSetEventHandlersFailed + Environment.NewLine + + ex.Message, true); + } + } + + #endregion + + #region Private Events & Handlers + + private void VNCEvent_Connected(object sender, EventArgs e) + { + Event_Connected(this); + _VNC.AutoScroll = Info.VNCSmartSizeMode == SmartSizeMode.SmartSNo; + } + + private void VNCEvent_Disconnected(object sender, EventArgs e) + { + FrmMain.ClipboardChanged -= VNCEvent_ClipboardChanged; + Event_Disconnected(sender, @"VncSharp Disconnected.", null); + Close(); + } + + private void VNCEvent_ClipboardChanged() + { + _VNC.FillServerClipboard(); + } + + private string VNCEvent_Authenticate() + { + return Info.Password; + } + + #endregion + #region Enums - public enum Defaults - { - Port = 5900 - } - - public enum SpecialKeys - { - CtrlAltDel, - CtrlEsc - } - - public enum Compression - { - [LocalizedAttributes.LocalizedDescription("strNoCompression")]CompNone = 99, - [Description("0")]Comp0 = 0, - [Description("1")]Comp1 = 1, - [Description("2")]Comp2 = 2, - [Description("3")]Comp3 = 3, - [Description("4")]Comp4 = 4, - [Description("5")]Comp5 = 5, - [Description("6")]Comp6 = 6, - [Description("7")]Comp7 = 7, - [Description("8")]Comp8 = 8, - [Description("9")]Comp9 = 9 - } - - public enum Encoding - { - [Description("Raw")]EncRaw, - [Description("RRE")]EncRRE, - [Description("CoRRE")]EncCorre, - [Description("Hextile")]EncHextile, - [Description("Zlib")]EncZlib, - [Description("Tight")]EncTight, - [Description("ZlibHex")]EncZLibHex, - [Description("ZRLE")]EncZRLE - } - - public enum AuthMode - { + + public enum Defaults + { + Port = 5900 + } + + public enum SpecialKeys + { + CtrlAltDel, + CtrlEsc + } + + public enum Compression + { + [LocalizedAttributes.LocalizedDescription("strNoCompression")] + CompNone = 99, + [Description("0")] Comp0 = 0, + [Description("1")] Comp1 = 1, + [Description("2")] Comp2 = 2, + [Description("3")] Comp3 = 3, + [Description("4")] Comp4 = 4, + [Description("5")] Comp5 = 5, + [Description("6")] Comp6 = 6, + [Description("7")] Comp7 = 7, + [Description("8")] Comp8 = 8, + [Description("9")] Comp9 = 9 + } + + public enum Encoding + { + [Description("Raw")] EncRaw, + [Description("RRE")] EncRRE, + [Description("CoRRE")] EncCorre, + [Description("Hextile")] EncHextile, + [Description("Zlib")] EncZlib, + [Description("Tight")] EncTight, + [Description("ZlibHex")] EncZLibHex, + [Description("ZRLE")] EncZRLE + } + + public enum AuthMode + { [LocalizedAttributes.LocalizedDescription("VNC")] AuthVNC, + [LocalizedAttributes.LocalizedDescription("Windows")] AuthWin - } - - public enum ProxyType - { + } + + public enum ProxyType + { [LocalizedAttributes.LocalizedDescription("strNone")] ProxyNone, + [LocalizedAttributes.LocalizedDescription("strHttp")] ProxyHTTP, + [LocalizedAttributes.LocalizedDescription("strSocks5")] ProxySocks5, + [LocalizedAttributes.LocalizedDescription("strUltraVncRepeater")] ProxyUltra - } - - public enum Colors - { + } + + public enum Colors + { [LocalizedAttributes.LocalizedDescription("strNormal")] ColNormal, - [Description("8-bit")]Col8Bit - } - - public enum SmartSizeMode - { + [Description("8-bit")] Col8Bit + } + + public enum SmartSizeMode + { [LocalizedAttributes.LocalizedDescription("strNoSmartSize")] SmartSNo, + [LocalizedAttributes.LocalizedDescription("strFree")] SmartSFree, + [LocalizedAttributes.LocalizedDescription("strAspect")] SmartSAspect - } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/Protocol/VNC/VNCEnum.cs b/mRemoteV1/Connection/Protocol/VNC/VNCEnum.cs index c72676131..0ff96f113 100644 --- a/mRemoteV1/Connection/Protocol/VNC/VNCEnum.cs +++ b/mRemoteV1/Connection/Protocol/VNC/VNCEnum.cs @@ -4,77 +4,84 @@ using mRemoteNG.Tools; namespace mRemoteNG.Connection.Protocol.VNC { public enum Defaults - { - Port = 5900 - } - - public enum SpecialKeys - { - CtrlAltDel, - CtrlEsc - } - - public enum Compression - { - [LocalizedAttributes.LocalizedDescription("strNoCompression")]CompNone = 99, - [Description("0")]Comp0 = 0, - [Description("1")]Comp1 = 1, - [Description("2")]Comp2 = 2, - [Description("3")]Comp3 = 3, - [Description("4")]Comp4 = 4, - [Description("5")]Comp5 = 5, - [Description("6")]Comp6 = 6, - [Description("7")]Comp7 = 7, - [Description("8")]Comp8 = 8, - [Description("9")]Comp9 = 9 - } - - public enum Encoding - { - [Description("Raw")]EncRaw, - [Description("RRE")]EncRRE, - [Description("CoRRE")]EncCorre, - [Description("Hextile")]EncHextile, - [Description("Zlib")]EncZlib, - [Description("Tight")]EncTight, - [Description("ZlibHex")]EncZLibHex, - [Description("ZRLE")]EncZRLE - } - - public enum AuthMode - { - [LocalizedAttributes.LocalizedDescription("VNC")] - AuthVNC, - [LocalizedAttributes.LocalizedDescription("Windows")] - AuthWin - } - - public enum ProxyType - { - [LocalizedAttributes.LocalizedDescription("strNone")] - ProxyNone, - [LocalizedAttributes.LocalizedDescription("strHttp")] - ProxyHTTP, - [LocalizedAttributes.LocalizedDescription("strSocks5")] - ProxySocks5, - [LocalizedAttributes.LocalizedDescription("strUltraVncRepeater")] - ProxyUltra - } - - public enum Colors - { - [LocalizedAttributes.LocalizedDescription("strNormal")] - ColNormal, - [Description("8-bit")]Col8Bit - } - - public enum SmartSizeMode - { - [LocalizedAttributes.LocalizedDescription("strNoSmartSize")] - SmartSNo, - [LocalizedAttributes.LocalizedDescription("strFree")] - SmartSFree, - [LocalizedAttributes.LocalizedDescription("strAspect")] - SmartSAspect - } -} + { + Port = 5900 + } + + public enum SpecialKeys + { + CtrlAltDel, + CtrlEsc + } + + public enum Compression + { + [LocalizedAttributes.LocalizedDescription("strNoCompression")] + CompNone = 99, + [Description("0")] Comp0 = 0, + [Description("1")] Comp1 = 1, + [Description("2")] Comp2 = 2, + [Description("3")] Comp3 = 3, + [Description("4")] Comp4 = 4, + [Description("5")] Comp5 = 5, + [Description("6")] Comp6 = 6, + [Description("7")] Comp7 = 7, + [Description("8")] Comp8 = 8, + [Description("9")] Comp9 = 9 + } + + public enum Encoding + { + [Description("Raw")] EncRaw, + [Description("RRE")] EncRRE, + [Description("CoRRE")] EncCorre, + [Description("Hextile")] EncHextile, + [Description("Zlib")] EncZlib, + [Description("Tight")] EncTight, + [Description("ZlibHex")] EncZLibHex, + [Description("ZRLE")] EncZRLE + } + + public enum AuthMode + { + [LocalizedAttributes.LocalizedDescription("VNC")] + AuthVNC, + + [LocalizedAttributes.LocalizedDescription("Windows")] + AuthWin + } + + public enum ProxyType + { + [LocalizedAttributes.LocalizedDescription("strNone")] + ProxyNone, + + [LocalizedAttributes.LocalizedDescription("strHttp")] + ProxyHTTP, + + [LocalizedAttributes.LocalizedDescription("strSocks5")] + ProxySocks5, + + [LocalizedAttributes.LocalizedDescription("strUltraVncRepeater")] + ProxyUltra + } + + public enum Colors + { + [LocalizedAttributes.LocalizedDescription("strNormal")] + ColNormal, + [Description("8-bit")] Col8Bit + } + + public enum SmartSizeMode + { + [LocalizedAttributes.LocalizedDescription("strNoSmartSize")] + SmartSNo, + + [LocalizedAttributes.LocalizedDescription("strFree")] + SmartSFree, + + [LocalizedAttributes.LocalizedDescription("strAspect")] + SmartSAspect + } +} \ No newline at end of file diff --git a/mRemoteV1/Connection/PuttySessionInfo.cs b/mRemoteV1/Connection/PuttySessionInfo.cs index 4fd37e73f..e15d82f46 100644 --- a/mRemoteV1/Connection/PuttySessionInfo.cs +++ b/mRemoteV1/Connection/PuttySessionInfo.cs @@ -10,20 +10,17 @@ using mRemoteNG.Tree.Root; namespace mRemoteNG.Connection { - public sealed class PuttySessionInfo : ConnectionInfo, IComponent - { + public sealed class PuttySessionInfo : ConnectionInfo, IComponent + { #region Properties - [Browsable(false)] - public RootPuttySessionsNodeInfo RootRootPuttySessionsInfo { get; set; } - [ReadOnly(true)] - public override string PuttySession { get; set; } + [Browsable(false)] public RootPuttySessionsNodeInfo RootRootPuttySessionsInfo { get; set; } - [ReadOnly(true)] - public override string Name { get; set; } + [ReadOnly(true)] public override string PuttySession { get; set; } - [ReadOnly(true), Browsable(false)] - public override string Description { get; set; } + [ReadOnly(true)] public override string Name { get; set; } + + [ReadOnly(true), Browsable(false)] public override string Description { get; set; } [ReadOnly(true), Browsable(false)] public override string Icon @@ -39,56 +36,52 @@ namespace mRemoteNG.Connection set { } } - [ReadOnly(true)] - public override string Hostname { get; set; } + [ReadOnly(true)] public override string Hostname { get; set; } - [ReadOnly(true)] - public override string Username { get; set; } + [ReadOnly(true)] public override string Username { get; set; } - [ReadOnly(true), Browsable(false)] - public override string Password { get; set; } + [ReadOnly(true), Browsable(false)] public override string Password { get; set; } - [ReadOnly(true)] - public override ProtocolType Protocol { get; set; } + [ReadOnly(true)] public override ProtocolType Protocol { get; set; } - [ReadOnly(true)] - public override int Port { get; set; } + [ReadOnly(true)] public override int Port { get; set; } - [ReadOnly(true), Browsable(false)] - public override string PreExtApp { get; set; } + [ReadOnly(true), Browsable(false)] public override string PreExtApp { get; set; } - [ReadOnly(true), Browsable(false)] - public override string PostExtApp { get; set; } + [ReadOnly(true), Browsable(false)] public override string PostExtApp { get; set; } - [ReadOnly(true), Browsable(false)] - public override string MacAddress { get; set; } + [ReadOnly(true), Browsable(false)] public override string MacAddress { get; set; } + + [ReadOnly(true), Browsable(false)] public override string UserField { get; set; } - [ReadOnly(true), Browsable(false)] - public override string UserField { get; set; } #endregion - [Command(),LocalizedAttributes.LocalizedDisplayName("strPuttySessionSettings")] + [Command(), LocalizedAttributes.LocalizedDisplayName("strPuttySessionSettings")] public void SessionSettings() - { - try - { - var puttyProcess = new PuttyProcessController(); - if (!puttyProcess.Start()) - { - return; - } - if (puttyProcess.SelectListBoxItem(PuttySession)) - { - puttyProcess.ClickButton("&Load"); - } - puttyProcess.SetControlText("Button", "&Cancel", "&Close"); - puttyProcess.SetControlVisible("Button", "&Open", false); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorCouldNotLaunchPutty + Environment.NewLine + ex.Message); - } - } + { + try + { + var puttyProcess = new PuttyProcessController(); + if (!puttyProcess.Start()) + { + return; + } + + if (puttyProcess.SelectListBoxItem(PuttySession)) + { + puttyProcess.ClickButton("&Load"); + } + + puttyProcess.SetControlText("Button", "&Cancel", "&Close"); + puttyProcess.SetControlVisible("Button", "&Open", false); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strErrorCouldNotLaunchPutty + Environment.NewLine + + ex.Message); + } + } public override TreeNodeType GetTreeNodeType() { @@ -96,19 +89,21 @@ namespace mRemoteNG.Connection } #region IComponent + [Browsable(false)] public ISite Site - { - get => new PropertyGridCommandSite(this); + { + get => new PropertyGridCommandSite(this); set => throw (new NotImplementedException()); } public void Dispose() - { + { Disposed?.Invoke(this, EventArgs.Empty); } public event EventHandler Disposed; + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Container/ContainerInfo.cs b/mRemoteV1/Container/ContainerInfo.cs index 989fc9113..69c9c1dda 100644 --- a/mRemoteV1/Container/ContainerInfo.cs +++ b/mRemoteV1/Container/ContainerInfo.cs @@ -9,34 +9,37 @@ using mRemoteNG.Tree; namespace mRemoteNG.Container { - [DefaultProperty("Name")] + [DefaultProperty("Name")] public class ContainerInfo : ConnectionInfo, INotifyCollectionChanged - { - private bool _isExpanded; + { + private bool _isExpanded; - [Browsable(false)] - public List Children { get; } = new List(); + [Browsable(false)] public List Children { get; } = new List(); - [Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)] - public bool IsExpanded - { - get => _isExpanded; - set => SetField(ref _isExpanded, value, "IsExpanded"); - } + [Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)] + public bool IsExpanded + { + get => _isExpanded; + set => SetField(ref _isExpanded, value, "IsExpanded"); + } - [Browsable(false)] - public override bool IsContainer { get { return true; } set {} } + [Browsable(false)] + public override bool IsContainer + { + get { return true; } + set { } + } - public ContainerInfo(string uniqueId) - : base(uniqueId) + public ContainerInfo(string uniqueId) + : base(uniqueId) { SetDefaults(); } - public ContainerInfo() - : this(Guid.NewGuid().ToString()) - { - } + public ContainerInfo() + : this(Guid.NewGuid().ToString()) + { + } public override TreeNodeType GetTreeNodeType() { @@ -76,7 +79,9 @@ namespace mRemoteNG.Container newChildItem.Parent = this; Children.Insert(index, newChildItem); SubscribeToChildEvents(newChildItem); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newChildItem)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + newChildItem)); } public void AddChildRange(IEnumerable newChildren) @@ -93,7 +98,9 @@ namespace mRemoteNG.Container removalTarget.Parent = null; Children.Remove(removalTarget); UnsubscribeToChildEvents(removalTarget); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removalTarget)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + removalTarget)); } public void RemoveChildRange(IEnumerable removalTargets) @@ -111,7 +118,10 @@ namespace mRemoteNG.Container Children.Remove(child); if (newIndex > Children.Count) newIndex = Children.Count; Children.Insert(newIndex, child); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, child, newIndex, originalIndex)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, child, + newIndex, + originalIndex)); } public void SetChildAbove(ConnectionInfo childToPromote, ConnectionInfo reference) @@ -161,7 +171,8 @@ namespace mRemoteNG.Container SortOn(connectionInfo => connectionInfo.Name, sortDirection); } - public void SortOn(Func propertyToCompare, ListSortDirection sortDirection = ListSortDirection.Ascending) + public void SortOn(Func propertyToCompare, + ListSortDirection sortDirection = ListSortDirection.Ascending) where TProperty : IComparable { var connectionComparer = new ConnectionInfoComparer(propertyToCompare) @@ -169,7 +180,8 @@ namespace mRemoteNG.Container SortDirection = sortDirection }; Children.Sort(connectionComparer); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } public void SortRecursive(ListSortDirection sortDirection = ListSortDirection.Ascending) @@ -177,7 +189,8 @@ namespace mRemoteNG.Container SortOnRecursive(connectionInfo => connectionInfo.Name, sortDirection); } - public void SortOnRecursive(Func propertyToCompare, ListSortDirection sortDirection = ListSortDirection.Ascending) + public void SortOnRecursive(Func propertyToCompare, + ListSortDirection sortDirection = ListSortDirection.Ascending) where TProperty : IComparable { foreach (var child in Children.OfType()) @@ -187,7 +200,7 @@ namespace mRemoteNG.Container // Deep clone, recursive public override ConnectionInfo Clone() - { + { var newContainer = new ContainerInfo(); newContainer.CopyFrom(this); newContainer.OpenConnections = new ProtocolList(); @@ -198,14 +211,15 @@ namespace mRemoteNG.Container newChild.RemoveParent(); newContainer.AddChild(newChild); } + return newContainer; - } - - private void SetDefaults() - { - Name = "New Folder"; + } + + private void SetDefaults() + { + Name = "New Folder"; IsExpanded = true; - } + } public IEnumerable GetRecursiveChildList() { @@ -217,6 +231,7 @@ namespace mRemoteNG.Container if (childContainer != null) childList.AddRange(GetRecursiveChildList(childContainer)); } + return childList; } @@ -230,6 +245,7 @@ namespace mRemoteNG.Container if (childContainer != null) childList.AddRange(GetRecursiveChildList(childContainer)); } + return childList; } @@ -250,9 +266,10 @@ namespace mRemoteNG.Container } public event NotifyCollectionChangedEventHandler CollectionChanged; + private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) { CollectionChanged?.Invoke(sender, args); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Credential/CredentialDeletionMsgBoxConfirmer.cs b/mRemoteV1/Credential/CredentialDeletionMsgBoxConfirmer.cs index 7fe3dcd2b..f433371d7 100644 --- a/mRemoteV1/Credential/CredentialDeletionMsgBoxConfirmer.cs +++ b/mRemoteV1/Credential/CredentialDeletionMsgBoxConfirmer.cs @@ -11,7 +11,8 @@ namespace mRemoteNG.Credential { private readonly Func _confirmationFunc; - public CredentialDeletionMsgBoxConfirmer(Func confirmationFunc) + public CredentialDeletionMsgBoxConfirmer( + Func confirmationFunc) { if (confirmationFunc == null) throw new ArgumentNullException(nameof(confirmationFunc)); @@ -25,18 +26,19 @@ namespace mRemoteNG.Credential if (targetsArray.Length == 0) return false; if (targetsArray.Length > 1) return PromptUser( - string.Format( - "Are you sure you want to delete these {0} selected credentials?", - targetsArray.Length)); + string.Format( + "Are you sure you want to delete these {0} selected credentials?", + targetsArray.Length)); return PromptUser( - string.Format( - Language.strConfirmDeleteCredentialRecord, - targetsArray.First().Title)); + string.Format( + Language.strConfirmDeleteCredentialRecord, + targetsArray.First().Title)); } private bool PromptUser(string promptMessage) { - var msgBoxResponse = _confirmationFunc.Invoke(promptMessage, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question); + var msgBoxResponse = _confirmationFunc.Invoke(promptMessage, Application.ProductName, + MessageBoxButtons.YesNo, MessageBoxIcon.Question); return msgBoxResponse == DialogResult.Yes; } } diff --git a/mRemoteV1/Credential/CredentialRecordTypeConverter.cs b/mRemoteV1/Credential/CredentialRecordTypeConverter.cs index 357c38ca3..396c030fc 100644 --- a/mRemoteV1/Credential/CredentialRecordTypeConverter.cs +++ b/mRemoteV1/Credential/CredentialRecordTypeConverter.cs @@ -11,21 +11,24 @@ namespace mRemoteNG.Credential { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - return sourceType == typeof(Guid) || - base.CanConvertFrom(context, sourceType); + return sourceType == typeof(Guid) || + base.CanConvertFrom(context, sourceType); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(Guid) || - destinationType == typeof(ICredentialRecord) || - base.CanConvertTo(context, destinationType); + destinationType == typeof(ICredentialRecord) || + base.CanConvertTo(context, destinationType); } - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + public override object ConvertTo(ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destinationType) { if (value is ICredentialRecord && destinationType == typeof(Guid)) - return ((ICredentialRecord) value).Id; + return ((ICredentialRecord)value).Id; if (value is ICredentialRecord && destinationType == typeof(ICredentialRecord)) return value; return base.ConvertTo(context, culture, value, destinationType); @@ -34,7 +37,8 @@ namespace mRemoteNG.Credential public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (!(value is Guid)) return base.ConvertFrom(context, culture, value); - var matchedCredentials = Runtime.CredentialProviderCatalog.GetCredentialRecords().Where(record => record.Id.Equals(value)).ToArray(); + var matchedCredentials = Runtime.CredentialProviderCatalog.GetCredentialRecords() + .Where(record => record.Id.Equals(value)).ToArray(); return matchedCredentials.Any() ? matchedCredentials.First() : null; } } diff --git a/mRemoteV1/Credential/CredentialServiceFacade.cs b/mRemoteV1/Credential/CredentialServiceFacade.cs index a7e430eea..88a96d498 100644 --- a/mRemoteV1/Credential/CredentialServiceFacade.cs +++ b/mRemoteV1/Credential/CredentialServiceFacade.cs @@ -13,7 +13,9 @@ namespace mRemoteNG.Credential public IEnumerable CredentialRepositories => _repositoryList; - public CredentialServiceFacade(ICredentialRepositoryList repositoryList, ILoader> loader, ISaver> saver) + public CredentialServiceFacade(ICredentialRepositoryList repositoryList, + ILoader> loader, + ISaver> saver) { if (repositoryList == null) throw new ArgumentNullException(nameof(repositoryList)); @@ -62,22 +64,28 @@ namespace mRemoteNG.Credential } #region Setup + private void SetupEventHandlers() { _repositoryList.RepositoriesUpdated += HandleRepositoriesUpdatedEvent; _repositoryList.CredentialsUpdated += HandleCredentialsUpdatedEvent; } - private void HandleRepositoriesUpdatedEvent(object sender, CollectionUpdatedEventArgs collectionUpdatedEventArgs) + private void HandleRepositoriesUpdatedEvent(object sender, + CollectionUpdatedEventArgs + collectionUpdatedEventArgs) { SaveRepositoryList(); } - private void HandleCredentialsUpdatedEvent(object sender, CollectionUpdatedEventArgs collectionUpdatedEventArgs) + private void HandleCredentialsUpdatedEvent(object sender, + CollectionUpdatedEventArgs + collectionUpdatedEventArgs) { var repo = sender as ICredentialRepository; repo?.SaveCredentials(repo.Config.Key); } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Credential/CredentialServiceFactory.cs b/mRemoteV1/Credential/CredentialServiceFactory.cs index d45e0d607..d04b97190 100644 --- a/mRemoteV1/Credential/CredentialServiceFactory.cs +++ b/mRemoteV1/Credential/CredentialServiceFactory.cs @@ -16,15 +16,18 @@ namespace mRemoteNG.Credential { var cryptoFromSettings = new CryptoProviderFactoryFromSettings(); var credRepoSerializer = new XmlCredentialPasswordEncryptorDecorator( - cryptoFromSettings.Build(), - new XmlCredentialRecordSerializer()); - var credRepoDeserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer()); + cryptoFromSettings.Build(), + new XmlCredentialRecordSerializer()); + var credRepoDeserializer = + new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer()); var credentialRepoListPath = Path.Combine(SettingsFileInfo.SettingsPath, "credentialRepositories.xml"); var repoListDataProvider = new FileDataProvider(credentialRepoListPath); var repoListLoader = new CredentialRepositoryListLoader( - repoListDataProvider, - new CredentialRepositoryListDeserializer(credRepoSerializer, credRepoDeserializer)); + repoListDataProvider, + new + CredentialRepositoryListDeserializer(credRepoSerializer, + credRepoDeserializer)); var repoListSaver = new CredentialRepositoryListSaver(repoListDataProvider); return new CredentialServiceFacade(Runtime.CredentialProviderCatalog, repoListLoader, repoListSaver); diff --git a/mRemoteV1/Credential/PlaceholderCredentialRecord.cs b/mRemoteV1/Credential/PlaceholderCredentialRecord.cs index 6cff5abd0..ee4d5fdc9 100644 --- a/mRemoteV1/Credential/PlaceholderCredentialRecord.cs +++ b/mRemoteV1/Credential/PlaceholderCredentialRecord.cs @@ -12,17 +12,13 @@ namespace mRemoteNG.Credential public Guid Id { get; } - [ReadOnly(true)] - public string Title { get; set; } = Language.CredentialUnavailable; + [ReadOnly(true)] public string Title { get; set; } = Language.CredentialUnavailable; - [ReadOnly(true)] - public string Username { get; set; } = Language.CredentialUnavailable; + [ReadOnly(true)] public string Username { get; set; } = Language.CredentialUnavailable; - [ReadOnly(true)] - public SecureString Password { get; set; } = new SecureString(); + [ReadOnly(true)] public SecureString Password { get; set; } = new SecureString(); - [ReadOnly(true)] - public string Domain { get; set; } = Language.CredentialUnavailable; + [ReadOnly(true)] public string Domain { get; set; } = Language.CredentialUnavailable; public PlaceholderCredentialRecord(IEnumerable id) { @@ -31,4 +27,4 @@ namespace mRemoteNG.Credential public override string ToString() => Language.CredentialUnavailable; } -} +} \ No newline at end of file diff --git a/mRemoteV1/Credential/Repositories/CredentialRepositoryConfig.cs b/mRemoteV1/Credential/Repositories/CredentialRepositoryConfig.cs index 7a7575bd5..1b3575e8a 100644 --- a/mRemoteV1/Credential/Repositories/CredentialRepositoryConfig.cs +++ b/mRemoteV1/Credential/Repositories/CredentialRepositoryConfig.cs @@ -39,7 +39,7 @@ namespace mRemoteNG.Credential.Repositories get { return _source; } set { - _source = value; + _source = value; RaisePropertyChangedEvent(nameof(Source)); } } @@ -49,7 +49,7 @@ namespace mRemoteNG.Credential.Repositories get { return _key; } set { - _key = value; + _key = value; RaisePropertyChangedEvent(nameof(Key)); } } @@ -74,6 +74,7 @@ namespace mRemoteNG.Credential.Repositories } public event PropertyChangedEventHandler PropertyChanged; + protected virtual void RaisePropertyChangedEvent(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); diff --git a/mRemoteV1/Credential/Repositories/CredentialRepositoryList.cs b/mRemoteV1/Credential/Repositories/CredentialRepositoryList.cs index f73360cd0..a3305d2e4 100644 --- a/mRemoteV1/Credential/Repositories/CredentialRepositoryList.cs +++ b/mRemoteV1/Credential/Repositories/CredentialRepositoryList.cs @@ -19,7 +19,7 @@ namespace mRemoteNG.Credential.Repositories _credentialProviders.Add(credentialProvider); credentialProvider.CredentialsUpdated += RaiseCredentialsUpdatedEvent; credentialProvider.RepositoryConfigUpdated += OnRepoConfigChanged; - RaiseRepositoriesUpdatedEvent(ActionType.Added, new[] { credentialProvider }); + RaiseRepositoriesUpdatedEvent(ActionType.Added, new[] {credentialProvider}); } public void RemoveProvider(ICredentialRepository credentialProvider) @@ -28,7 +28,7 @@ namespace mRemoteNG.Credential.Repositories credentialProvider.CredentialsUpdated -= RaiseCredentialsUpdatedEvent; credentialProvider.RepositoryConfigUpdated -= OnRepoConfigChanged; _credentialProviders.Remove(credentialProvider); - RaiseRepositoriesUpdatedEvent(ActionType.Removed, new[] { credentialProvider }); + RaiseRepositoriesUpdatedEvent(ActionType.Removed, new[] {credentialProvider}); } public bool Contains(Guid repositoryId) @@ -43,12 +43,14 @@ namespace mRemoteNG.Credential.Repositories { list.AddRange(repository.CredentialRecords); } + return list; } public ICredentialRecord GetCredentialRecord(Guid id) { - return CredentialProviders.SelectMany(repo => repo.CredentialRecords).FirstOrDefault(record => record.Id.Equals(id)); + return CredentialProviders.SelectMany(repo => repo.CredentialRecords) + .FirstOrDefault(record => record.Id.Equals(id)); } public IEnumerator GetEnumerator() @@ -66,7 +68,8 @@ namespace mRemoteNG.Credential.Repositories private void RaiseRepositoriesUpdatedEvent(ActionType action, IEnumerable changedItems) { - RepositoriesUpdated?.Invoke(this, new CollectionUpdatedEventArgs(action, changedItems)); + RepositoriesUpdated?.Invoke(this, + new CollectionUpdatedEventArgs(action, changedItems)); } private void RaiseCredentialsUpdatedEvent(object sender, CollectionUpdatedEventArgs args) @@ -78,7 +81,7 @@ namespace mRemoteNG.Credential.Repositories { var repo = sender as ICredentialRepository; if (repo == null) return; - RaiseRepositoriesUpdatedEvent(ActionType.Updated, new[] { repo }); + RaiseRepositoriesUpdatedEvent(ActionType.Updated, new[] {repo}); } } } \ No newline at end of file diff --git a/mRemoteV1/Credential/Repositories/XmlCredentialRepository.cs b/mRemoteV1/Credential/Repositories/XmlCredentialRepository.cs index bb0268809..ebb20073b 100644 --- a/mRemoteV1/Credential/Repositories/XmlCredentialRepository.cs +++ b/mRemoteV1/Credential/Repositories/XmlCredentialRepository.cs @@ -17,7 +17,9 @@ namespace mRemoteNG.Credential.Repositories public IList CredentialRecords { get; } public bool IsLoaded { get; private set; } - public XmlCredentialRepository(ICredentialRepositoryConfig config, CredentialRecordSaver credentialRecordSaver, CredentialRecordLoader credentialRecordLoader) + public XmlCredentialRepository(ICredentialRepositoryConfig config, + CredentialRecordSaver credentialRecordSaver, + CredentialRecordLoader credentialRecordLoader) { if (config == null) throw new ArgumentNullException(nameof(config)); @@ -28,7 +30,8 @@ namespace mRemoteNG.Credential.Repositories Config = config; CredentialRecords = new FullyObservableCollection(); - ((FullyObservableCollection) CredentialRecords).CollectionUpdated += RaiseCredentialsUpdatedEvent; + ((FullyObservableCollection)CredentialRecords).CollectionUpdated += + RaiseCredentialsUpdatedEvent; Config.PropertyChanged += (sender, args) => RaiseRepositoryConfigUpdatedEvent(args); _credentialRecordSaver = credentialRecordSaver; _credentialRecordLoader = credentialRecordLoader; @@ -42,6 +45,7 @@ namespace mRemoteNG.Credential.Repositories if (ThisIsADuplicateCredentialRecord(newCredential)) continue; CredentialRecords.Add(newCredential); } + IsLoaded = true; Config.Key = key; } @@ -71,7 +75,8 @@ namespace mRemoteNG.Credential.Repositories RepositoryConfigUpdated?.Invoke(this, args); } - protected virtual void RaiseCredentialsUpdatedEvent(object sender, CollectionUpdatedEventArgs args) + protected virtual void RaiseCredentialsUpdatedEvent(object sender, + CollectionUpdatedEventArgs args) { CredentialsUpdated?.Invoke(this, args); } diff --git a/mRemoteV1/Credential/Repositories/XmlCredentialRepositoryFactory.cs b/mRemoteV1/Credential/Repositories/XmlCredentialRepositoryFactory.cs index 0cebc69db..8ab806b83 100644 --- a/mRemoteV1/Credential/Repositories/XmlCredentialRepositoryFactory.cs +++ b/mRemoteV1/Credential/Repositories/XmlCredentialRepositoryFactory.cs @@ -12,7 +12,8 @@ namespace mRemoteNG.Credential.Repositories private readonly ISecureSerializer, string> _serializer; private readonly ISecureDeserializer> _deserializer; - public XmlCredentialRepositoryFactory(ISecureSerializer, string> serializer, ISecureDeserializer> deserializer) + public XmlCredentialRepositoryFactory(ISecureSerializer, string> serializer, + ISecureDeserializer> deserializer) { if (serializer == null) throw new ArgumentNullException(nameof(serializer)); diff --git a/mRemoteV1/Messages/Message.cs b/mRemoteV1/Messages/Message.cs index 45dc0699b..5888e579d 100644 --- a/mRemoteV1/Messages/Message.cs +++ b/mRemoteV1/Messages/Message.cs @@ -2,12 +2,12 @@ using System; namespace mRemoteNG.Messages { - public class Message : IMessage - { - public MessageClass Class { get; set; } - public string Text { get; set; } - public DateTime Date { get; set; } - public bool OnlyLog { get; set; } + public class Message : IMessage + { + public MessageClass Class { get; set; } + public string Text { get; set; } + public DateTime Date { get; set; } + public bool OnlyLog { get; set; } public Message(MessageClass messageClass, string messageText, bool onlyLog = false) { @@ -16,5 +16,5 @@ namespace mRemoteNG.Messages Date = DateTime.Now; OnlyLog = onlyLog; } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Messages/MessageCollector.cs b/mRemoteV1/Messages/MessageCollector.cs index b156cc12b..9a89be74b 100644 --- a/mRemoteV1/Messages/MessageCollector.cs +++ b/mRemoteV1/Messages/MessageCollector.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Messages @@ -26,7 +27,7 @@ namespace mRemoteNG.Messages public void AddMessage(IMessage message) { - AddMessages(new [] {message}); + AddMessages(new[] {message}); } public void AddMessages(IEnumerable messages) @@ -38,18 +39,27 @@ namespace mRemoteNG.Messages _messageList.Add(message); newMessages.Add(message); } + if (newMessages.Any()) RaiseCollectionChangedEvent(NotifyCollectionChangedAction.Add, newMessages); } - public void AddExceptionMessage(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = true) + public void AddExceptionMessage(string message, + Exception ex, + MessageClass msgClass = MessageClass.ErrorMsg, + bool logOnly = true) { - AddMessage(msgClass, message + Environment.NewLine + Tools.MiscTools.GetExceptionMessageRecursive(ex), logOnly); + AddMessage(msgClass, message + Environment.NewLine + Tools.MiscTools.GetExceptionMessageRecursive(ex), + logOnly); } - public void AddExceptionStackTrace(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = true) + public void AddExceptionStackTrace(string message, + Exception ex, + MessageClass msgClass = MessageClass.ErrorMsg, + bool logOnly = true) { - AddMessage(msgClass, message + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace, logOnly); + AddMessage(msgClass, message + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace, + logOnly); } public void ClearMessages() diff --git a/mRemoteV1/Messages/MessageWriters/NotificationPanelMessageWriter.cs b/mRemoteV1/Messages/MessageWriters/NotificationPanelMessageWriter.cs index 7ec99de38..29cb3d44e 100644 --- a/mRemoteV1/Messages/MessageWriters/NotificationPanelMessageWriter.cs +++ b/mRemoteV1/Messages/MessageWriters/NotificationPanelMessageWriter.cs @@ -26,7 +26,7 @@ namespace mRemoteNG.Messages.MessageWriters private void AddToList(ListViewItem lvItem) { if (_messageWindow.lvErrorCollector.InvokeRequired) - _messageWindow.lvErrorCollector.Invoke((MethodInvoker) (() => AddToList(lvItem))); + _messageWindow.lvErrorCollector.Invoke((MethodInvoker)(() => AddToList(lvItem))); else _messageWindow.lvErrorCollector.Items.Insert(0, lvItem); } diff --git a/mRemoteV1/Messages/MessageWriters/PopupMessageWriter.cs b/mRemoteV1/Messages/MessageWriters/PopupMessageWriter.cs index 93602d504..2e6a0495c 100644 --- a/mRemoteV1/Messages/MessageWriters/PopupMessageWriter.cs +++ b/mRemoteV1/Messages/MessageWriters/PopupMessageWriter.cs @@ -10,16 +10,20 @@ namespace mRemoteNG.Messages.MessageWriters switch (message.Class) { case MessageClass.DebugMsg: - MessageBox.Show(message.Text, string.Format(Language.strTitleInformation, message.Date), MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show(message.Text, string.Format(Language.strTitleInformation, message.Date), + MessageBoxButtons.OK, MessageBoxIcon.Information); break; case MessageClass.InformationMsg: - MessageBox.Show(message.Text, string.Format(Language.strTitleInformation, message.Date), MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show(message.Text, string.Format(Language.strTitleInformation, message.Date), + MessageBoxButtons.OK, MessageBoxIcon.Information); break; case MessageClass.WarningMsg: - MessageBox.Show(message.Text, string.Format(Language.strTitleWarning, message.Date), MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show(message.Text, string.Format(Language.strTitleWarning, message.Date), + MessageBoxButtons.OK, MessageBoxIcon.Warning); break; case MessageClass.ErrorMsg: - MessageBox.Show(message.Text, string.Format(Language.strTitleError, message.Date), MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(message.Text, string.Format(Language.strTitleError, message.Date), + MessageBoxButtons.OK, MessageBoxIcon.Error); break; default: throw new ArgumentOutOfRangeException(); diff --git a/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs b/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs index c9d7d9dc6..a3e30c685 100644 --- a/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs +++ b/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs @@ -15,7 +15,9 @@ namespace mRemoteNG.Messages.WriterDecorators private readonly ErrorAndInfoWindow _messageWindow; private readonly FrmMain _frmMain = FrmMain.Default; - public MessageFocusDecorator(ErrorAndInfoWindow messageWindow, IMessageTypeFilteringOptions filter, IMessageWriter decoratedWriter) + public MessageFocusDecorator(ErrorAndInfoWindow messageWindow, + IMessageTypeFilteringOptions filter, + IMessageWriter decoratedWriter) { _filter = filter ?? throw new ArgumentNullException(nameof(filter)); _messageWindow = messageWindow ?? throw new ArgumentNullException(nameof(messageWindow)); @@ -46,14 +48,15 @@ namespace mRemoteNG.Messages.WriterDecorators if (_filter.AllowErrorMessages) return true; break; } + return false; } private async Task SwitchToMessageAsync() { await Task - .Delay(TimeSpan.FromMilliseconds(300)) - .ContinueWith(task => SwitchToMessage()); + .Delay(TimeSpan.FromMilliseconds(300)) + .ContinueWith(task => SwitchToMessage()); } private void SwitchToMessage() diff --git a/mRemoteV1/Messages/WriterDecorators/MessageTypeFilterDecorator.cs b/mRemoteV1/Messages/WriterDecorators/MessageTypeFilterDecorator.cs index cf92b5774..ed8a4be23 100644 --- a/mRemoteV1/Messages/WriterDecorators/MessageTypeFilterDecorator.cs +++ b/mRemoteV1/Messages/WriterDecorators/MessageTypeFilterDecorator.cs @@ -43,6 +43,7 @@ namespace mRemoteNG.Messages.WriterDecorators if (_filter.AllowDebugMessages) return true; break; } + return false; } } diff --git a/mRemoteV1/Properties/AssemblyInfo.cs b/mRemoteV1/Properties/AssemblyInfo.cs index 08b0f1007..2f15b6a72 100644 --- a/mRemoteV1/Properties/AssemblyInfo.cs +++ b/mRemoteV1/Properties/AssemblyInfo.cs @@ -3,7 +3,6 @@ using System.Resources; using System.Runtime.InteropServices; - // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. diff --git a/mRemoteV1/Properties/Settings.settings b/mRemoteV1/Properties/Settings.settings index 40257a085..630931987 100644 --- a/mRemoteV1/Properties/Settings.settings +++ b/mRemoteV1/Properties/Settings.settings @@ -1,699 +1,701 @@  - - - - - 0, 0 - - - 0, 0 - - - Normal - - - False - - - True - - - - - - True - - - True - - - True - - - False - - - False - - - - - - True - - - True - - - False - - - False - - - True - - - False - - - False - - - noinfo - - - - - - - - - - - - False - - - True - - - False - - - False - - - False - - - - - - 80 - - - False - - - - - - - - - - - - RDP - - - Default Settings - - - False - - - FitToWindow - - - Colors16Bit - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - DoNotPlay - - - 2 - - - False - - - False - - - False - - - 0 - - - False - - - True - - - 0, 0 - - - Bottom - - - True - - - 3, 24 - - - Top - - - False - - - False - - - - - - - - - - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - EncrBasic - - - False - - - - - - - - - False - - - False - - - False - - - True - - - False - - - False - - - AuthVNC - - - ColNormal - - - SmartSAspect - - - False - - - CompNone - - - EncHextile - - - - - - - - - 0 - - - ProxyNone - - - - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - NoAuth - - - False - - - 5500 - - - False - - - - - - IE - - - False - - - - - - False - - - False - - - - - - False - - - - - - False - - - False - - - 14 - - - 1980-01-01 - - - False - - - Never - - - Yes - - - mRemoteNG - - - False - - - False - - - False - - - False - - - False - - - False - - - 5 - - - - - - - - - - - - - - - - - - False - - - False - - - False - - - False - - - 4 - - - - - - - - - mRemoteNG - - - 10 - - - {0}.{1:yyyyMMdd-HHmmssffff}.backup - - - False - - - True - - - False - - - False - - - release - - - - - - True - - - - - - - - - True - - - https://mremoteng.org/ - - - - - - True - - - False - - - False - - - RDP - - - 9/9, 33/8 - - - 9/8, 34/8 - - - False - - - 20 - - - AES - - - GCM - - - 1000 - - - Dynamic - - - False - - - 0 - - - False - - - False - - - False - - - False - - - 00000000-0000-0000-0000-000000000000 - - - - - - False - - - True - - - True - - - True - - - False - - - False - - - True - - - True - - - False - - - False - - - False - - - False - - - True - - - True - - - cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW - - - True - - - - - - - - - - - - General - - - True - - - False - - - False - - - False - - - False - - - 0, 0 - - - - - - False - - - False - - - General - - - False - - - False - - - True - - - False - - + + + + + + 0, 0 + + + 0, 0 + + + Normal + + + False + + + True + + + + + + True + + + True + + + True + + + False + + + False + + + + + + True + + + True + + + False + + + False + + + True + + + False + + + False + + + noinfo + + + + + + + + + + + + False + + + True + + + False + + + False + + + False + + + + + + 80 + + + False + + + + + + + + + + + + RDP + + + Default Settings + + + False + + + FitToWindow + + + Colors16Bit + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + DoNotPlay + + + 2 + + + False + + + False + + + False + + + 0 + + + False + + + True + + + 0, 0 + + + Bottom + + + True + + + 3, 24 + + + Top + + + False + + + False + + + + + + + + + + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + EncrBasic + + + False + + + + + + + + + False + + + False + + + False + + + True + + + False + + + False + + + AuthVNC + + + ColNormal + + + SmartSAspect + + + False + + + CompNone + + + EncHextile + + + + + + + + + 0 + + + ProxyNone + + + + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + NoAuth + + + False + + + 5500 + + + False + + + + + + IE + + + False + + + + + + False + + + False + + + + + + False + + + + + + False + + + False + + + 14 + + + 1980-01-01 + + + False + + + Never + + + Yes + + + mRemoteNG + + + False + + + False + + + False + + + False + + + False + + + False + + + 5 + + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + 4 + + + + + + + + + mRemoteNG + + + 10 + + + {0}.{1:yyyyMMdd-HHmmssffff}.backup + + + False + + + True + + + False + + + False + + + release + + + + + + True + + + + + + + + + True + + + https://mremoteng.org/ + + + + + + True + + + False + + + False + + + RDP + + + 9/9, 33/8 + + + 9/8, 34/8 + + + False + + + 20 + + + AES + + + GCM + + + 1000 + + + Dynamic + + + False + + + 0 + + + False + + + False + + + False + + + False + + + 00000000-0000-0000-0000-000000000000 + + + + + + False + + + True + + + True + + + True + + + False + + + False + + + True + + + True + + + False + + + False + + + False + + + False + + + True + + + True + + + cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW + + + True + + + + + + + + + + + + General + + + True + + + False + + + False + + + False + + + False + + + 0, 0 + + + + + + False + + + False + + + General + + + False + + + False + + + True + + + False + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/Index.htm b/mRemoteV1/Resources/Help/Index.htm index cfa50ca0a..cc9cad1dd 100644 --- a/mRemoteV1/Resources/Help/Index.htm +++ b/mRemoteV1/Resources/Help/Index.htm @@ -1,48 +1,86 @@ - - mRemoteNG Help - + + mRemoteNG Help + -
+
Done from nmat, please remove this div after review. -
-

Welcome to mRemoteNG

-
-

+

+

Welcome to mRemoteNG

+
+

This documentation is written and based on version 1.76 of mRemoteNG. If you find anything to improve or wrong with the documentation then please report it to github. Also note that documentation can be found on github pages that are updated more frequently then information provided here. -

-

Getting Started

-
-

User Interface

- -

Special Topics

-

Connections

- +

+

Getting Started

+ +

User Interface

+ +

Special Topics

+

Connections

+ - + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/Introduction.htm b/mRemoteV1/Resources/Help/Introduction.htm index 114ff60ba..c92c65111 100644 --- a/mRemoteV1/Resources/Help/Introduction.htm +++ b/mRemoteV1/Resources/Help/Introduction.htm @@ -1,26 +1,26 @@ - - Introduction - + + Introduction + -
+
Done from nmat, please remove this div after review. -
-

Introduction

-
-

+

+

Introduction

+
+

mRemoteNG is a multi-protocol remote connections manager.
As of Version 1.00 it supports the RDP, VNC, ICA, SSH, Telnet, RAW, Rlogin and HTTP/S protocols.
The main goal is to minimize window clutter and to provide a easy gui for managing all your remote connections. -

-

Features

-
-
    +

    +

    Features

    +
    +
    • Free and Open Source, released under the GPL
    • Panels and tabs allow to group certain connections together, dock them to any side of the window or completely undock them and move them to another screen for example
    • Multiple supported protocols (RDP, VNC, ICA, SSH, Telnet, RAW, Rlogin and HTTP/S)
    • @@ -41,13 +41,13 @@
    • Fullscreen (Kiosk) mode
    • Assign global credentials to use when no information is provided on connection basis
    • Host Up/Down (Ping) feature shows if the selected host answers to a ping
    • -
    -

    License

    -
    -

    +

+

License

+
+

The application is released under the GPL (V2)
Binary and source code packages are available for download. -

+

- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/Main.css b/mRemoteV1/Resources/Help/Main.css index 48c211da7..a00e6a96c 100644 --- a/mRemoteV1/Resources/Help/Main.css +++ b/mRemoteV1/Resources/Help/Main.css @@ -1,19 +1,16 @@ /* COMMON STUFF */ -body -{ - background-color: #FFFFFF; - margin-left: 10px; - margin-top: 10px; - margin-right: 10px; - margin-bottom: 10px; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - font-size: 0.75em; - color: #333333; +body { + background-color: #FFFFFF; + margin-left: 10px; + margin-top: 10px; + margin-right: 10px; + margin-bottom: 10px; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-size: 0.75em; + color: #333333; } -img { - border: none; -} +img { border: none; } hr { display: block; @@ -25,75 +22,73 @@ hr { } /* HEADINGS */ + h1 { - font-size: 2.0em; - color: #000000; + font-size: 2.0em; + color: #000000; } h2 { - font-size: 1.5em; - color: #000000; + font-size: 1.5em; + color: #000000; } h3 { - font-size: 1.17em; - color: #000000; + font-size: 1.17em; + color: #000000; } h4 { - font-size: 1em; - color: #000000; + font-size: 1em; + color: #000000; } h5 { - font-size: .83em; - color: #000000; + font-size: .83em; + color: #000000; } /* LINKS */ -a:link -{ - color: #5d6b70; - text-decoration: none; + +a:link { + color: #5d6b70; + text-decoration: none; } -a:visited -{ - color: #5d6b70; - text-decoration: none; +a:visited { + color: #5d6b70; + text-decoration: none; } -a:hover -{ - color: Black; - text-decoration: underline; +a:hover { + color: Black; + text-decoration: underline; } /* TABLES */ + table { - font-family: arial, sans-serif; - border-collapse: collapse; + font-family: arial, sans-serif; + border-collapse: collapse; } td, th { - border: 1px solid #dddddd; - text-align: left; - padding: 8px; + border: 1px solid #dddddd; + text-align: left; + padding: 8px; } -tr:nth-child(even) { - background-color: #f2f2f2; -} +tr:nth-child(even) { background-color: #f2f2f2; } /* MISC STYLES */ -.Code -{ - padding-right: 5px; - padding-left: 5px; - color: #000000; - font-family: 'Courier New' , Monospace; - background-color: #C1C1C1; + +.Code { + padding-right: 5px; + padding-left: 5px; + color: #000000; + font-family: 'Courier New', Monospace; + background-color: #C1C1C1; } .monospace { @@ -101,28 +96,29 @@ tr:nth-child(even) { font-family: 'Courier New', monospace; } -.nowrap { - white-space: nowrap -} +.nowrap { white-space: nowrap } .isa_info, .isa_success, .isa_warning, .isa_error { margin: 10px 0px; - padding:12px; - + padding: 12px; } + .isa_info { color: #00529B; background-color: #BDE5F8; } + .isa_success { color: #4F8A10; background-color: #DFF2BF; } + .isa_warning { color: #9F6000; background-color: #FEEFB3; } + .isa_error { color: #D8000C; background-color: #FFD2D2; -} +} \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/gs_command_line_switches.htm b/mRemoteV1/Resources/Help/gs_command_line_switches.htm index 23c5fa119..c120b56da 100644 --- a/mRemoteV1/Resources/Help/gs_command_line_switches.htm +++ b/mRemoteV1/Resources/Help/gs_command_line_switches.htm @@ -1,78 +1,80 @@ - - Command-Line Switches - + + Command-Line Switches + -
+
Complete from nmat updates, please remove this div after review. -
-

+

+

The following is a list of command line switches supported by mRemoteNG. -

-
+

+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandDescription
- /cons:PathToConnectionsFile -

- /c:PathToConnectionsFile -
- Loads the connections file from the given path. -

- This path can be a: -
    -
  • full file path
  • -
  • path relative to the current directory
  • -
  • path relative to the mRemoteNG application directory
  • -
  • path relative to the mRemoteNG default connection file directory
  • -
-
/resetResets window position, panels and toolbars
- /resetpos -

- /rp -
Reset the windows position
- /resetpanels -

- /rpnl -
Resets all panel's positions. Use this if you have troubles with panel layouts
- /resettoolbar -

- /rtbr -
Resets the positions of all toolbars
- /noreconnect -

- /norc -
Temporary disables reconnect to previously opened sessions. Use this if you have problems opening mRemoteNG after you enabled the setting and restarted mRemoteNG
CommandDescription
+ /cons:PathToConnectionsFile +

+ /c:PathToConnectionsFile +
+ Loads the connections file from the given path. +

+ This path can be a: +
    +
  • full file path
  • +
  • path relative to the current directory
  • +
  • path relative to the mRemoteNG application directory
  • +
  • path relative to the mRemoteNG default connection file directory
  • +
+
+ /reset + Resets window position, panels and toolbars
+ /resetpos +

+ /rp +
Reset the windows position
+ /resetpanels +

+ /rpnl +
Resets all panel's positions. Use this if you have troubles with panel layouts
+ /resettoolbar +

+ /rtbr +
Resets the positions of all toolbars
+ /noreconnect +

+ /norc +
Temporary disables reconnect to previously opened sessions. Use this if you have problems opening mRemoteNG after you enabled the setting and restarted mRemoteNG
-
+
- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/gs_installation.htm b/mRemoteV1/Resources/Help/gs_installation.htm index 8526efb9c..9b419bc34 100644 --- a/mRemoteV1/Resources/Help/gs_installation.htm +++ b/mRemoteV1/Resources/Help/gs_installation.htm @@ -1,43 +1,43 @@ - - Installation - + + Installation + -
+
Done from nmat, remove this div after review. -
-

Information

-

+

+

Information

+

Downloads are provided in four different packages, the setup package, binary package, portable package and the source package. They are described below. -

-

Setup Package

-

+

+

Setup Package

+

The setup package is the compiled version of mRemoteNG which comes in an MSI installer.
The common way to get mRemoteNG up and running -

-

Portable Package

-

+

+

Portable Package

+

The portable package consists of the same files as the bin package but contains an modified version of the executable which stores and loads all your settings - from files in the application's directory.
+ from files in the application's directory.
This package can be used to run mRemoteNG from an USB stick an preserve your configuration wherever you go. -

-

Source Package

-

+

+

Source Package

+

The source package is a zip package and contains the source code in form of a Visual Studio solution. -

-

Updating and Uninstalling

-

+

+

Updating and Uninstalling

+

mRemoteNG can be updated without uninstalling it before.
For portable version of mRemoteNG stores all user data in same folder as mRemoteNG.exe file. -

+

- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/gs_prerequisites.htm b/mRemoteV1/Resources/Help/gs_prerequisites.htm index 414384104..ce1a87d29 100644 --- a/mRemoteV1/Resources/Help/gs_prerequisites.htm +++ b/mRemoteV1/Resources/Help/gs_prerequisites.htm @@ -1,115 +1,143 @@ - - Prerequisites - + + Prerequisites + -
+
Done from nmat, remove this div after review -
+
-

Supported Operating Systems:

-
- +

Prerequisites:

+
+
    +
  • + Microsoft .NET Framework 4.0 +
  • +
  • + Microsoft Terminal Services Client 8.0 or later. +
      +
    • Needed if you use RDP. mstscax.dll and/or msrdp.ocx must be registered.
    • +
    • + Included with newer Windows versions. + KB2574819 AND either + KB2592687 or + KB2923545 + is required for Windows 7/Windows Server 2008 R2 +
    • +
    +
  • +
  • + PuTTY +
      +
    • Needed if you use Telnet, SSH, Rlogin or RAW. Included in all packages.
    • +
    • An appropriate and integrated version is included with mRemoteNG.
    • +
    +
  • +
  • + Citrix ICA Client +
      +
    • Needed if you use ICA. wfica.ocx must be registered.
    • +
    +
  • +
- -

Windows™ 7/Windows Server 2008 R2 clients (requirements)

-
+ +

Windows™ 7/Windows Server 2008 R2 clients (requirements)

+
TIP! You can use powershell to fetch if the hotfixes are installed. Try using example:

Get-HotFix | where {$_.HotFixID -eq "KB2574819" -and $_.HotFixID -eq "KB2592687"} -
-

+

+

The following updates must be present on any Windows 7 or Server 2008 client that will be running mRemoteNG. (They must have been installed in the order provided below): -

- + - + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/gs_running_mremoteng.htm b/mRemoteV1/Resources/Help/gs_running_mremoteng.htm index abf39373f..b82e102d8 100644 --- a/mRemoteV1/Resources/Help/gs_running_mremoteng.htm +++ b/mRemoteV1/Resources/Help/gs_running_mremoteng.htm @@ -1,177 +1,179 @@ - + Running mRemoteNG - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
-

First Run

-
-

- Here is a quick reference of the interface: -

- -

- The screenshot above explains the most basic of the interface. To understand it all - we are creating a small tutorial here. -

+

First Run

+
+

+ Here is a quick reference of the interface: +

+ +

+ The screenshot above explains the most basic of the interface. To understand it all + we are creating a small tutorial here. +

-

Creating a connection

-

- Right click on the root item (the little blue globe named "Connections") in - the Connections panel and select "New Connection". Or use the keybinding - Ctrl+N if the Connections are selected. -

- -

- A new item shows up under the root item. You can give it a name now - (or rename it later). Here we just name it "Test". -

- -

- Now lets look at the Config panel in the bottom left, just under the - Connections panel. -

- -

- As you may notice this is where you configure all the properties of connections - and folders.
- There are a lot of values that can be set but for our first connection we will - keep things simple. -

-

- The most important things right now are that we tell the application which host - we want to connect to and which protocol we want to use.
- In this example we will use a Windows 2012 R2 server that has RDP (Remote Desktop - Protocol) enabled.
- As RDP is the default protocol whenever you create a new connection we don't have - to change anything there. -

-

- The next thing we will do is to fill in the Hostname/IP field with the hostname - we want to connect to. Lets also fill in a username and password so that we login - automatically to the server. -

- -

- Lets now try to connect to the server. -

-
- TIP! You can see an indicator in the properties window that is glowing green. - -

- This icon does a ICMP ping on to check response from the server. If it glows green - it indicates a connection response can be made using ping to the host. - However this is turned off on windows by default. You have to enable ICMP and allow - the firewall access for it. -
-

Opening and Closing Connections

-

- There are multiple ways to open a connection in mRemoteNG, but the easiest - way is to double click the connection in the Connections panel. -

-

- If you double click the connection you will notice that the connection is going - to try and open in a new panel called  General  and under a tab - called  Test . -

- -
- NOTE! If the connection fails you will find out what the problem was - in the dialog notifications panel. -
-

- If all goes well you should see the remote desktop without any problems. -

-

- To close the connection you can do any of the following: -

    +

    Creating a connection

    +

    + Right click on the root item (the little blue globe named "Connections") in + the Connections panel and select "New Connection". Or use the keybinding + Ctrl+N if the Connections are selected. +

    + +

    + A new item shows up under the root item. You can give it a name now + (or rename it later). Here we just name it "Test". +

    + +

    + Now lets look at the Config panel in the bottom left, just under the + Connections panel. +

    + +

    + As you may notice this is where you configure all the properties of connections + and folders.
    + There are a lot of values that can be set but for our first connection we will + keep things simple. +

    +

    + The most important things right now are that we tell the application which host + we want to connect to and which protocol we want to use.
    + In this example we will use a Windows 2012 R2 server that has RDP (Remote Desktop + Protocol) enabled.
    + As RDP is the default protocol whenever you create a new connection we don't have + to change anything there. +

    +

    + The next thing we will do is to fill in the Hostname/IP field with the hostname + we want to connect to. Lets also fill in a username and password so that we login + automatically to the server. +

    + +

    + Lets now try to connect to the server. +

    +
    + TIP! You can see an indicator in the properties window that is glowing green. + +

    + This icon does a ICMP ping on to check response from the server. If it glows green + it indicates a connection response can be made using ping to the host. + However this is turned off on windows by default. You have to enable ICMP and allow + the firewall access for it. +
    +

    Opening and Closing Connections

    +

    + There are multiple ways to open a connection in mRemoteNG, but the easiest + way is to double click the connection in the Connections panel. +

    +

    + If you double click the connection you will notice that the connection is going + to try and open in a new panel called  General  and under a tab + called  Test . +

    + +
    + NOTE! If the connection fails you will find out what the problem was + in the dialog notifications panel. +
    +

    + If all goes well you should see the remote desktop without any problems. +

    +

    + To close the connection you can do any of the following: +

    • Log off in the start menu - Closes the connection and logs you out completely from RDP
    • Close the panel with the - Which leaves your session active on server but closes connection in mRemoteNG
    • Close the connection tab with - Also keeps your login active on server but closes RDP connection in mRemoteNG
    • Double click the connection tab - Same as above where the connection is active on server but closes RDP connection in mRemoteNG
    • -
    -

    -

    Folders and Inheritance

    -

    - Folders on mRemoteNG cannot only be used to categorize connections but also to - apply properties to the underlying connections. -

    -

    Example

    -

    - You have 10 Remote Desktop enabled servers in one domain and 15 in another domain. -

    -

    - Normally you would spend a lot of time creating all those connections and setting - the individual properties like username, password, etc. In mRemoteNG there is an - easier way. You just create two folders, one for domain A and one for domain B - and set all properties there. -

    -

    - Then create the Connections and let them inherit every property. The only - properties left to fill on Connection basis are the Connections name and hostname. - Everything else will be inherited from the parent folder. -

    -

    - Here is how you do this: -

    -

    1. Add the folder

    -

    - This can be done with: -

      +
    +

    +

    Folders and Inheritance

    +

    + Folders on mRemoteNG cannot only be used to categorize connections but also to + apply properties to the underlying connections. +

    +

    Example

    +

    + You have 10 Remote Desktop enabled servers in one domain and 15 in another domain. +

    +

    + Normally you would spend a lot of time creating all those connections and setting + the individual properties like username, password, etc. In mRemoteNG there is an + easier way. You just create two folders, one for domain A and one for domain B + and set all properties there. +

    +

    + Then create the Connections and let them inherit every property. The only + properties left to fill on Connection basis are the Connections name and hostname. + Everything else will be inherited from the parent folder. +

    +

    + Here is how you do this: +

    +

    1. Add the folder

    +

    + This can be done with: +

    • Right click on connections and click on New Folder
    • -
    • File > New Folder
    • +
    • + File > New Folder +
    • Or with keybinding: Ctrl+Shift+N
    • -
    -

    - -

    - Then give it a name and fill all the properties you need (like you did with - the test connection) -

    -
    - -

    - When you have filled in the settings and values you can either just drag the test - Connection inside the folder or create a new one. -

    - -

    - Right now nothing has changed and nothing will be inherited.
    - To enable inheritance switch to the inheritance view by clicking the - dedicated button. (Marked with a red arrow below) -

    - -

    - The properties that show up now are almost the same as before, but you - only select yes or no to enable or disable a inheritance. -

    - -

    - When no is selected the property will not be inherited, yes indicates - an inherited property. -

    -

    - For this test set Inherit Everything to Yes. -

    -

    - Now if you switch back to the properties view (the button left - of the inheritance button) you should see that not much is left of all - those properties. -

    - -

    - Only the Name and Hostname/IP properties are left over, everything else will be - inherited from the parent folder. -

    -

    - Of course you can also only let some of the properties be inherited. Just play - around with this a bit and you'll get the hang of it. -

    - - +
+

+ +

+ Then give it a name and fill all the properties you need (like you did with + the test connection) +

+
+ +

+ When you have filled in the settings and values you can either just drag the test + Connection inside the folder or create a new one. +

+ +

+ Right now nothing has changed and nothing will be inherited.
+ To enable inheritance switch to the inheritance view by clicking the + dedicated button. (Marked with a red arrow below) +

+ +

+ The properties that show up now are almost the same as before, but you + only select yes or no to enable or disable a inheritance. +

+ +

+ When no is selected the property will not be inherited, yes indicates + an inherited property. +

+

+ For this test set Inherit Everything to Yes. +

+

+ Now if you switch back to the properties view (the button left + of the inheritance button) you should see that not much is left of all + those properties. +

+ +

+ Only the Name and Hostname/IP properties are left over, everything else will be + inherited from the parent folder. +

+

+ Of course you can also only let some of the properties be inherited. Just play + around with this a bit and you'll get the hang of it. +

+ + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/st_common_problems_rdp.htm b/mRemoteV1/Resources/Help/st_common_problems_rdp.htm index 6a418d772..ef0a32b2f 100644 --- a/mRemoteV1/Resources/Help/st_common_problems_rdp.htm +++ b/mRemoteV1/Resources/Help/st_common_problems_rdp.htm @@ -1,66 +1,73 @@ - + Common Problems (RDP) - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
-

Introduction

-

- Its hard to make a document on all problems that can occur with connections - but here at least we are trying to list some of the most common problems for RDP - that has been noticed. -

+

Introduction

+

+ Its hard to make a document on all problems that can occur with connections + but here at least we are trying to list some of the most common problems for RDP + that has been noticed. +

- -

Quick Reference

- - + +

Quick Reference

+ + - -

CredSSP - CVE-2018-0886 - Authentication error

-

- mRemoteNG uses the Microsoft Terminal Services Client (MSTSC) libraries in order - to make Remote Desktop connections. mRemoteNG has no control over the functionality - changes implemented by Microsoft. -

-

- Relevant line of code that shows our - "RDP Client" connection "object": - - private MsRdpClient8NotSafeForScripting _rdpClient; -

-

- Relevant MS documentation for this .NET class: - MsRdpClient8NotSafeForScripting class -

-

- Please refer to - Microsoft's documentation - for full details regarding this problem. -

-

- Patched clients attempting to connect to Unpatched servers will fail with the following error: -

- -

- The same error will occur with MSTSC directly on a - patched client attempting to connect to an unpatched server. -

-

Per the MS documentation, the only ways around this are to:

-
    -
  • Patch the servers
  • -
  • set the "Encryption Oracle Remediation" policy to "Vulnerable" - refer to the MS documentation above for details:
    -
  • -
  • Uninstall KB4103727
  • -
- - - + +

CredSSP - CVE-2018-0886 - Authentication error

+

+ mRemoteNG uses the Microsoft Terminal Services Client (MSTSC) libraries in order + to make Remote Desktop connections. mRemoteNG has no control over the functionality + changes implemented by Microsoft. +

+

+ Relevant line of code that shows our + "RDP Client" connection "object": + + private MsRdpClient8NotSafeForScripting _rdpClient; + +

+

+ Relevant MS documentation for this .NET class: + MsRdpClient8NotSafeForScripting class +

+

+ Please refer to + Microsoft's documentation + for full details regarding this problem. +

+

+ Patched clients attempting to connect to Unpatched servers will fail with the following error: +

+ +

+ The same error will occur with MSTSC directly on a + patched client attempting to connect to an unpatched server. +

+

Per the MS documentation, the only ways around this are to:

+
    +
  • Patch the servers
  • +
  • + set the "Encryption Oracle Remediation" policy to "Vulnerable" - refer to the MS documentation above for details:
    + +
  • +
  • Uninstall KB4103727
  • +
+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_config.htm b/mRemoteV1/Resources/Help/ui_config.htm index aed8bc99b..3be5e0b0c 100644 --- a/mRemoteV1/Resources/Help/ui_config.htm +++ b/mRemoteV1/Resources/Help/ui_config.htm @@ -1,67 +1,71 @@ - + Config - - -
- Complete from nmat updates, please remove this div after review. Need information in properties and inheritance. -
+ + +
+ Complete from nmat updates, please remove this div after review. Need information in properties and inheritance. +
- -

Introduction

-
- -

- Config dialog to setup the connection specific properties. - This includes inheritance from other items before the item and more. Details below is about - how to work with this dialog to get the most out of connections and configuration. -

-

Quick Reference

-
    -
  • Top Bar - Main top bar information.
  • -
- + +

Introduction

+
+ +

+ Config dialog to setup the connection specific properties. + This includes inheritance from other items before the item and more. Details below is about + how to work with this dialog to get the most out of connections and configuration. +

+

Quick Reference

+ + - -

Top Bar

-
-

- -

+ +

Top Bar

+
+

+ +

Red - Sort values Categories or Alphabetical.
Green - Show Properties, Inheritance values
Blue - Connection icon
Yellow - Host status (based on ICMP ping) -

-

Sort Values

-

- Sorts the values in properties either by Categories or Alphabetically. -

+

+

Sort Values

+

+ Sorts the values in properties either by Categories or Alphabetically. +

Categories sort - Shows values in categories with expanding options.
Alphabetical sort - Expands everything and shows values in alphabetical order instead -

-

Properties and Inheritance

-

- -

-

Icon

-

- The icon indicates the visual identifier for the connection. Clicking the icon will let you set a different icon - for the connection. -

-
- NOTE! Don't forget that mRemoteNG will save the change on exit auto unless you have unchecked this setting in options. -
-

Status

-

Is a indicator that will glow red or green depending on the status of the host. The status is based on ICMP ping to the host.

-
- IMPORTANT! In order for this to work you have to open up ICMP. On windows servers this is also disabled in windows firewall. -
- - - +

+

Properties and Inheritance

+

+ +

+

Icon

+

+ The icon indicates the visual identifier for the connection. Clicking the icon will let you set a different icon + for the connection. +

+
+ NOTE! Don't forget that mRemoteNG will save the change on exit auto unless you have unchecked this setting in options. +
+

Status

+

Is a indicator that will glow red or green depending on the status of the host. The status is based on ICMP ping to the host.

+
+ IMPORTANT! In order for this to work you have to open up ICMP. On windows servers this is also disabled in windows firewall. +
+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_connections.htm b/mRemoteV1/Resources/Help/ui_connections.htm index c67afec6d..b5d5e4c27 100644 --- a/mRemoteV1/Resources/Help/ui_connections.htm +++ b/mRemoteV1/Resources/Help/ui_connections.htm @@ -1,86 +1,98 @@ - + Connections - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
-

Introduction

-
-

- The connections dialog is the main collection of all connections that is added to mRemoteNG. This document will - explain the details of the connections dialog. -

+

Introduction

+
+

+ The connections dialog is the main collection of all connections that is added to mRemoteNG. This document will + explain the details of the connections dialog. +

- -

Top Menu Bar

-
-

- -

+ +

Top Menu Bar

+
+

+ +

Red - New Connection
Green - New Folder
Blue - View (Expand/Collapse all folders)
Yellow - Ascending sort -

-

Quick Reference

- - +

+

Quick Reference

+ + - -

New Connection

-
-

- Creates a new connection item in the connections dialog after where cursor is present. -

-
- TIP! You can also duplicate an already created connection if you want to follow - some sort of template of a connection. Just right click on folder or connection to - duplicate the item. The information is then carried over for editing. This can save a lot - of time when the connection list is large. -
- + +

New Connection

+
+

+ Creates a new connection item in the connections dialog after where cursor is present. +

+
+ TIP! You can also duplicate an already created connection if you want to follow + some sort of template of a connection. Just right click on folder or connection to + duplicate the item. The information is then carried over for editing. This can save a lot + of time when the connection list is large. +
+ - -

New Folder

-
-

- Creates a new folder in connections dialog after where cursor is present. -

-
- TIP! Folders can help to make adding connections easier. By setting a folder with - some values that can be inheritaded down to the connections. Read more about this in - Configuration -
- + +

New Folder

+
+

+ Creates a new folder in connections dialog after where cursor is present. +

+
+ TIP! Folders can help to make adding connections easier. By setting a folder with + some values that can be inheritaded down to the connections. Read more about this in + Configuration +
+ - -

View

-
-

- Collapses or expands all directories in the connection dialog. Useful when working with - a lot of connections sorted in different directories. -

- + +

View

+
+

+ Collapses or expands all directories in the connection dialog. Useful when working with + a lot of connections sorted in different directories. +

+ - -

Ascending

-
-

- Works like a sort or a refresh to get connection in ascending order. (Descending order is - note supported yet) When you have been moving around in the tree of connections, just click - this item to refresh the list and get everything in ascending ordering. -

- - - + +

Ascending

+
+

+ Works like a sort or a refresh to get connection in ascending order. (Descending order is + note supported yet) When you have been moving around in the tree of connections, just click + this item to refresh the list and get everything in ascending ordering. +

+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_external_tools.htm b/mRemoteV1/Resources/Help/ui_external_tools.htm index eafa63ba2..d554bcfac 100644 --- a/mRemoteV1/Resources/Help/ui_external_tools.htm +++ b/mRemoteV1/Resources/Help/ui_external_tools.htm @@ -1,44 +1,44 @@ - - External Tools - + + External Tools + -
+
Complete from nmat updates, please remove this div after review. -
- -

Introduction to External Tools

-

+

+ +

Introduction to External Tools

+

External Tools can help you get things done that can't be done in mRemoteNG.
You can for example start a command prompt or launch your favorite FTP tool from within mRemoteNG.
This wouldn't make much sense by itself because you can already launch your applications by using the Windows Start Menu, Quick Launch or whatever you prefer to use to start your apps. -

-

+

+

But there's more! -

-

+

+

In mRemoteNG, you can launch applications and tell them what to do with the use of arguments (parameters) and variables of the currently selected Connection. You can, for example, select your home router's SSH Connection entry and do a traceroute (tracert) on that host. This is much quicker and more powerful than opening the console and typing "tracert yourhost". -

-

+

+

The external tools configuration is stored in %APPDATA%\mRemoteNG\extApps.xml -

-

Variables

-

+

+

Variables

+

Variables and arguments can be used to tell the external tool what to do. -

-

+

+

This is the list of variables supported by mRemoteNG: -

-
    +

    +
    • %NAME%
    • %HOSTNAME%
    • %PORT%
    • @@ -48,183 +48,185 @@
    • %DESCRIPTION%
    • %MACADDRESS%
    • %USERFIELD%
    • -
    -

    +

+

Variables always refer to the currently selected connection. Variable names are case-insensitive. Variables can be used in both the Filename and Arguments fields. -

-

+

+

mRemoteNG will also expand environment variables such as %PATH% and %USERPROFILE%. If you need to use an environment variable with the same name as an mRemoteNG variable, use \% instead of %. The most common use of this is for the USERNAME environment variable. %USERNAME% will be expanded to the username set in the currently selected connection. \%USERNAME\% will be expanded to the value set in the USERNAME environment variable. -

-

+

+

If you need to send a variable name to a program without mRemoteNG expanding it, use ^% instead of %. mRemoteNG will remove the caret (^) and leave the rest unchanged. For example, ^%USERNAME^% will be sent to the program as %USERNAME% and will not be expanded. -

-

Special Character Escaping

-

+

+

Special Character Escaping

+

Expanded variables will be escaped using the rules below. There are two levels of escaping that are done. The first is escaping for standard argument splitting (C/C++ argv, CommandLineToArgvW, etc). The second is escaping shell metacharacters for ShellExecute. -

-

Argument splitting escaping:

-
    +

    +

    Argument splitting escaping:

    +
    • Each quotation mark will be escaped by a backslash.
    • -
    • One or more backslashes (\) followed by a quotation mark ("): -
        -
      • Each backslash will be escaped by another backslash.
      • -
      • The quotation mark will be escaped by a backslash.
      • -      If the connection's user field contains - "This" is a \"test\".
        -      Then %USERFIELD% is replaced with - \"This\" is a \\\"test\\\". -
      +
    • + One or more backslashes (\) followed by a quotation mark ("): +
        +
      • Each backslash will be escaped by another backslash.
      • +
      • The quotation mark will be escaped by a backslash.
      • +      If the connection's user field contains + "This" is a \"test\".
        +      Then %USERFIELD% is replaced with + \"This\" is a \\\"test\\\". +
    • -
    • A variable name followed by a quotation mark (for example, %USERFIELD%") with - a value ending in one or more backslashes: -
        -
      • Each backslash will be escaped by another backslash.
      • -
      • Example:
      • -      If the connection's user field contains c:\Example\
        -      Then "%USERFIELD%" is replaced with "c:\Example\\" -
      +
    • + A variable name followed by a quotation mark (for example, %USERFIELD%") with + a value ending in one or more backslashes: +
        +
      • Each backslash will be escaped by another backslash.
      • +
      • Example:
      • +      If the connection's user field contains c:\Example\
        +      Then "%USERFIELD%" is replaced with "c:\Example\\" +
    • -
    -

    +

+

To disable argument splitting escaping for a variable, precede its name with a minus (-) sign. For example, %-USERFIELD%. -

-

Shell metacharacter escaping:

-
    +

    +

    Shell metacharacter escaping:

    +
    • The shell metacharacters are ( ) % ! ^ " < > & |
    • Each shell metacharacter will be escaped by a caret (^).
    • -
    -

    +

+

To disable both argument splitting and shell metacharacter escaping for a variable, precede its name with an exclamation point (!). For example, %!USERFIELD%. This is not recommended and may cause unexpected results. -

-

+

+

Only variables that have been expanded will be escaped. It is up to you to escape the rest of the arguments. -

+

-

Variable Examples

- +

Variable Examples

+
- - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + -
ArgumentsUser FieldResultArgumentsUser FieldResult
%USERFIELD%"Example" Text\^"Example\^" Text%USERFIELD%"Example" Text\^"Example\^" Text
%-USERFIELD%"Example" Text^"Example^" Text%-USERFIELD%"Example" Text^"Example^" Text
%!USERFIELD%"Example" Text"Example" Text%!USERFIELD%"Example" Text"Example" Text
^%USERFIELD^%"Example" Text%USERFIELD%^%USERFIELD^%"Example" Text%USERFIELD%
^^%USERFIELD^^%"Example" Text^%USERFIELD^%^^%USERFIELD^^%"Example" Text^%USERFIELD^%
-d "%USERFIELD%"c:\Example\-d "c:\Example\\"-d "%USERFIELD%"c:\Example\-d "c:\Example\\"
-d "%-USERFIELD%"c:\Example\-d "c:\Example\"-d "%-USERFIELD%"c:\Example\-d "c:\Example\"
-d "%USERFIELD%"Left & Right-d "Left ^& Right"-d "%USERFIELD%"Left & Right-d "Left ^& Right"
-d "%!USERFIELD%"Left & Right-d "Left & Right"-d "%!USERFIELD%"Left & Right-d "Left & Right"
%WINDIR%N/Ac:\Windows\%WINDIR%N/Ac:\Windows\
\%WINDIR\%N/Ac:\Windows\\%WINDIR\%N/Ac:\Windows\
\^%WINDIR\^%N/A\%WINDIR\%\^%WINDIR\^%N/A\%WINDIR\%
\\%WINDIR\\%N/A\\%WINDIR\\%\\%WINDIR\\%N/A\\%WINDIR\\%
-

Example

-

+ +

Example

+

First of all, start the external tools editor. To do this, click Tools in the main menu and select External Tools.
You will see a screen like on the following screenshot. -

-

- -

-

+

+

+ +

+

The fields below the list are greyed out because you haven't created an external tool entry yet.
To create one, right click the blank area in the list and select Add, as in the screenshot below. -

-

- -

-

+

+

+ +

+

This is what you'll get: -

-

- -

-

+

+

+ +

+

So the three fields are now available and need to be filled.
The Display Name is simply the name you will see when you want to launch that tool, so give it a descriptive name.
I named mine Traceroute as I will create a external tool that will start the tracert command in the console. -

-

- -

-

+

+

+ +

+

Ok, the next thing we'll need is a filename. This is the program that we want to be executed.
I simply type in cmd for a Windows cmd console. -

-

- -

-

+

+

+ +

+

Now the fun part comes in—the arguments.
The Windows cmd has a command line argument that tells the console to launch the command followed by that argument and stay open.
@@ -234,23 +236,23 @@ completes.
After that, I just type tracert %HostName%. This tells the console to do a traceroute on the hostname of the currently selected Connection. -

-

- -

-

+

+

+ +

+

Alright! That's all we'll need.
Now right click one of you connections, click Tools, External Tools and select Traceroute. -

-

- -

-

+

+

+ +

+

Voilà! A console window will popup and execute your tracert command. -

-

- -

+

+

+ +

- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_file_transfer.htm b/mRemoteV1/Resources/Help/ui_file_transfer.htm index 33adffbe7..e37703ded 100644 --- a/mRemoteV1/Resources/Help/ui_file_transfer.htm +++ b/mRemoteV1/Resources/Help/ui_file_transfer.htm @@ -1,79 +1,80 @@ - - SSH File Transfer - + + SSH File Transfer + -
+
Complete from nmat updates, please remove this div after review. -
+
- -

Introduction

-
-

+ +

Introduction

+
+

SSH File Transfer functionality allows you to securely transfer files to a remote host over an encrypted tunnel using either SFTP or SCP. -

- +

+ - -

Use Cases

-
-

The primary use case is to upload individual files, such as configuration files, to a remote host.

- + +

Use Cases

+
+

The primary use case is to upload individual files, such as configuration files, to a remote host.

+ - -

Prerequisites

-
-
    + +

    Prerequisites

    +
    +
    • SSH File Transfer requires an SSH service to listen on an available network port (default 22) on a remote host.
    • A username and password must be supplied to connect with the remote host.
    • The remote host must have a writeable folder on its filesystem to place the transferred files.
    • -
    - +
+ - -

Configuration Options

-
-
    + +

    Configuration Options

    +
    +
    • Host - The remote host you connect to. Can be DNS name or IP address.
    • Port - Remote network port listening for SSH/SFTP/SCP traffic.
    • User - Username for account to log on to remote host.
    • Password - Password for account to log on to remote host.
    • Protocol - Choice of SCP or SFTP protocol used for communication.
    • Local File - Path of file to transfer from local host.
    • -
    • Remote File - Path where file will be transferred on remote host. -
        -
      • Example: /home/John/Documents
      • -
      +
    • + Remote File - Path where file will be transferred on remote host. +
        +
      • Example: /home/John/Documents
      • +
    • -
    - +
+ -

Using SSH File Transfer

-
-

+

Using SSH File Transfer

+
+

To begin, select Tools and then SSH File Transfer. The tool will fill the window and allow you to input the configuration options. Each piece of information is needed for a successful transfer. -

+

-

+

To populate the Local File option, select the Browse button and navigate to the desired file on the local filesystem. To populate the Remote File option, manually type desired filesystem path, including the desired file name. -

+

-

+

Once all options are populated, select Transfer and the progress bar at the bottom of the window will show the progress. -

+

-

Troubleshooting SSH File Transfer

-
-

+

Troubleshooting SSH File Transfer

+
+

To troubleshoot issues with SSH File Transfer, consult the log under %AppData%\mRemoteNG\mRemoteNG.log. This log provides verbose information about successful and failed connections.

Common Issues

@@ -91,6 +92,6 @@ [14] ERROR- SSH background transfer failed!
This issue was likely encountered due to a permissions issue. Ensure you have appropriate access to write to the specified Remote File. -

+

- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_import_and_export.htm b/mRemoteV1/Resources/Help/ui_import_and_export.htm index 659c2b339..e42d287ad 100644 --- a/mRemoteV1/Resources/Help/ui_import_and_export.htm +++ b/mRemoteV1/Resources/Help/ui_import_and_export.htm @@ -1,48 +1,48 @@ - + Import/Export - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
- -

Introduction

-
-

- Import/Export is for importing or exporting your configuration of connections. -

- + +

Introduction

+
+

+ Import/Export is for importing or exporting your configuration of connections. +

+ - -

Import

-
-

Import from File...

-

- Opens a normal file load dialog to open a exported xml or csv file for mRemoteNG. - See Export to file... further down this page for information on - exporting your connections. -

-

Import from Active Directory

-

- If you have servers that is located in a domain. Then this option can be used to fetch - those servers to easily import them to mRemoteNG. -

-

Import from Port Scan

- + +

Import

+
+

Import from File...

+

+ Opens a normal file load dialog to open a exported xml or csv file for mRemoteNG. + See Export to file... further down this page for information on + exporting your connections. +

+

Import from Active Directory

+

+ If you have servers that is located in a domain. Then this option can be used to fetch + those servers to easily import them to mRemoteNG. +

+

Import from Port Scan

+ - -

Export to file...

-
-

- Here you can export your settings to a file to share or backup. The dialog shown below - is the dialog of which you chose the options to export. -

- - - - + +

Export to file...

+
+

+ Here you can export your settings to a file to share or backup. The dialog shown below + is the dialog of which you chose the options to export. +

+ + + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_keyboardshortcuts.htm b/mRemoteV1/Resources/Help/ui_keyboardshortcuts.htm index bbe18af21..4de806adc 100644 --- a/mRemoteV1/Resources/Help/ui_keyboardshortcuts.htm +++ b/mRemoteV1/Resources/Help/ui_keyboardshortcuts.htm @@ -1,106 +1,136 @@  - + Keyboardshortcuts - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
-

Keybindings

-

File

- - +

Keybindings

+

File

+
+ - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - -
Keybinding Action
Ctrl+N
+ Ctrl+N + New Connection
Ctrl+Shift+N
+ Ctrl+Shift+N + New Folder
Ctrl+O
+ Ctrl+O + Open Connection File...
Ctrl+S
+ Ctrl+S + Save Connection File
Ctrl+Shift+S
+ Ctrl+Shift+S + Save Connection File As...
+ + -

View

- - +

View

+
+ - - - + + + - - - + + + - - - + + + - -
Keybinding Action
Ctrl+Alt+C
+ Ctrl+Alt+C + Jump to (Connections and Config)
Ctrl+Alt+E
+ Ctrl+Alt+E + Jump to (Notifications)
F11
+ F11 + Fullscreen
+ + -

Connections

- - +

Connections

+
+ - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - -
Keybinding Action
Ctrl+Shift+C
+ Ctrl+Shift+C + Connect
Ctrl+D
+ Ctrl+D + Duplicate
F2
+ F2 + Rename
Del
+ Del + Delete...
Ctrl+Up
+ Ctrl+Up + Move Up
Ctrl+Down
+ Ctrl+Down + Move Down
+ + -

Help

- - +

Help

+
+ - - - + + + - -
Keybinding Action
F1
+ F1 + mRemoteNG Help
- - + + + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_menus.htm b/mRemoteV1/Resources/Help/ui_menus.htm index df4d7c8f4..85334e941 100644 --- a/mRemoteV1/Resources/Help/ui_menus.htm +++ b/mRemoteV1/Resources/Help/ui_menus.htm @@ -1,224 +1,240 @@ - - Menus - + + Menus + -
+
Complete from nmat updates, please remove this div after review. -
+
- -

Introduction

-
- -

+ +

Introduction

+
+ +

In this section we are going to explain the menus located in mRemoteNG. The above screenshot shows the main menu with colors. Short color explanation:

- Red - Anchor to move menu around the interface
- Green - The menu items + Red - Anchor to move menu around the interface
+ Green - The menu items

-

-

Quick Reference

-
    -
  • File Menu - Contains standard commands for the application
  • -
  • View Menu - Menu for additional dialogs for mRemoteNG
  • -
  • Tools Menu - Additional tools that can be used and triggered in mRemoteNG
  • -
  • Help Menu - Get more information for the application
  • -
- +

+

Quick Reference

+ + - -

File Menu

-
- + +

File Menu

+
+
- - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + -
ItemDescriptionItemDescription
New ConnectionWill add a new connection to the Connections dialog after where the cursor is positioned.New ConnectionWill add a new connection to the Connections dialog after where the cursor is positioned.
New FolderAdd a new folder in the Connections dialog tree where the cursor is positioned.New FolderAdd a new folder in the Connections dialog tree where the cursor is positioned.
New Connection FileCreate a new connection file. Dialog will come up asking about: filename and where to place the new connection file.New Connection FileCreate a new connection file. Dialog will come up asking about: filename and where to place the new connection file.
Open Connection File - Open a connection file. Dialog comes up asking about which file to open. For security reasons, this also shows a dialog - to ask if you want to save the current file before continuing. - Open Connection File + Open a connection file. Dialog comes up asking about which file to open. For security reasons, this also shows a dialog + to ask if you want to save the current file before continuing. +
Save Connection FileSaves the currently opened connection file. If you are using a SQL server connection instead it will send a save to the SQL server.Save Connection FileSaves the currently opened connection file. If you are using a SQL server connection instead it will send a save to the SQL server.
Save Connection File As...Saves the current connection file to a specific location on disk.Save Connection File As...Saves the current connection file to a specific location on disk.
Delete...Delete currently selected item in connections dialog.Delete...Delete currently selected item in connections dialog.
RenameRename current selected item in connections dialog.RenameRename current selected item in connections dialog.
DuplicateDuplicate current selected item in connections dialog.DuplicateDuplicate current selected item in connections dialog.
Reconnect All Open ConnectionsSends a reconnect to all the open connections in mRemoteNG.Reconnect All Open ConnectionsSends a reconnect to all the open connections in mRemoteNG.
ExitExit mRemoteNG applicationExitExit mRemoteNG application
- + + - -

View Menu

-
- + +

View Menu

+
+
- - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + -
ItemDescriptionItemDescription
Add Connection PanelCreate a new and empty panel.Add Connection PanelCreate a new and empty panel.
Connection PanelsJump to panel.Connection PanelsJump to panel.
ConnectionsShow connections dialogConnectionsShow connections dialog
ConfigShow config dialogConfigShow config dialog
NotificationsShow notifications dialogNotificationsShow notifications dialog
ScreenshotsOpen Screenshots panel (See: ScreenshotManager for more information)ScreenshotsOpen Screenshots panel (See: ScreenshotManager for more information)
Jump ToPlace focus on "Connections and Config" or "Notifications" panel based on selection.Jump ToPlace focus on "Connections and Config" or "Notifications" panel based on selection.
Reset layoutResets the layout of panels and dialogs. Warning will come up about the action before continuing.Reset layoutResets the layout of panels and dialogs. Warning will come up about the action before continuing.
Lock toolbar positionsLocks the toolbars at the top of the application so you do not move around items by mistake.Lock toolbar positionsLocks the toolbars at the top of the application so you do not move around items by mistake.
Quick Connect ToolbarShow quick connect toolbarQuick Connect ToolbarShow quick connect toolbar
External Tools ToolbarShow external tools toolbarExternal Tools ToolbarShow external tools toolbar
Multi SSH ToolbarShow multi ssh toolbarMulti SSH ToolbarShow multi ssh toolbar
FullscreenFullscreen mRemoteNG (will not fullscreen connection window but only the mRemoteNG application)FullscreenFullscreen mRemoteNG (will not fullscreen connection window but only the mRemoteNG application)
- + + - -

Tools Menu

-
- + +

Tools Menu

+
+
- - + + - - + + - - + + - - + + - - + + - - + + -
ItemDescriptionItemDescription
SSH File TransferShow SSH file transer panel (See: SSH File Transfer for more details)SSH File TransferShow SSH file transer panel (See: SSH File Transfer for more details)
External ToolsShow external tools dialog (See: External Tools for more details)External ToolsShow external tools dialog (See: External Tools for more details)
Port ScanShow port scan dialog (See: Port Scan for more details)Port ScanShow port scan dialog (See: Port Scan for more details)
Components CheckShow installed components requirements testComponents CheckShow installed components requirements test
OptionsOpens mRemoteNG global settings and options dialogOptionsOpens mRemoteNG global settings and options dialog
- + + - -

Help Menu

-
- + +

Help Menu

+
+
- - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + -
ItemDescriptionItemDescription
mRemoteNG HelpShow help panel (this panel)mRemoteNG HelpShow help panel (this panel)
WebsiteGo to mRemoteNG websiteWebsiteGo to mRemoteNG website
DonateGo to mRemoteNG donation page. (Please help keep mRemoteNG awesome!)DonateGo to mRemoteNG donation page. (Please help keep mRemoteNG awesome!)
Support ForumGo to mRemoteNG suport forum (Best place is still chat for fast answers)Support ForumGo to mRemoteNG suport forum (Best place is still chat for fast answers)
Report a BugGo to github page to report a bug foundReport a BugGo to github page to report a bug found
Check for UpdatesOpens dialog to check for any updates of mRemoteNGCheck for UpdatesOpens dialog to check for any updates of mRemoteNG
AboutOpen about dialog for mRemoteNG (Shows contributors, changelog and more)AboutOpen about dialog for mRemoteNG (Shows contributors, changelog and more)
- + + - + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_navigation.htm b/mRemoteV1/Resources/Help/ui_navigation.htm index 141adffb5..ddeb38763 100644 --- a/mRemoteV1/Resources/Help/ui_navigation.htm +++ b/mRemoteV1/Resources/Help/ui_navigation.htm @@ -1,134 +1,140 @@ - + Navigation - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
-

Introduction

-

-

-

Quick Reference

- +

Introduction

+

+

+

Quick Reference

+ - -

-

- mRemoteNG is using panels and tabs to stay organized but also to create a better - view of all multitasking that is being done inside the application. Because - of that it can be good to know some more information on how to work with panels - and tabs to get the most out of those features. -

-

Panels

-

- Panels are used to organize tabbed connections. This might seem - a bit confusing but its a great way to stay organized. Below is a few examples - of how to use panels to give you a hands on better view of them. -

-
    -
  • + +

    +

    + mRemoteNG is using panels and tabs to stay organized but also to create a better + view of all multitasking that is being done inside the application. Because + of that it can be good to know some more information on how to work with panels + and tabs to get the most out of those features. +

    +

    Panels

    +

    + Panels are used to organize tabbed connections. This might seem + a bit confusing but its a great way to stay organized. Below is a few examples + of how to use panels to give you a hands on better view of them. +

    +
      +
    • Test and Production - You can add 2 panels where you have the test servers are located and the other where production servers are running. -
    • -
    • +
    • +
    • Datacenters - Maybe you divide them into datacenters. -
    • -
    • +
    • +
    • Temp project - To see all servers you work on for a temporary project. -
    • -
    • +
    • +
    • Home vs Work - Maybe you are sneaky at work and want to login at home to check you machine at home for something while keeping work in its own panel. -
    • -
    • +
    • +
    • ...and many more -
    • -
    -

    - For this tutorial we will keep it simple with Domain A and Domain B. Where both - have their own panels. -

    - -

    Creating panels

    -

    - Usually panels are created using connections and folders to stay organized - automatic when making connections. However you can also create panels manually. - See below: -

    - -

    - Creating manual panels will make you able to organize tabs manually in mRemoteNG. - To then open a connection to the new panel then Right click on connection and use - "Connect (with options)" > Choose panel before connecting -

    -

    - The other option in the menu named "Connection Panels" will list all panels - in open in the current running mRemoteNG window. -

    -

    More options

    -

    - Right click menu for panels will give you a few more options for the panels: -

    - -
      -
    • Rename - Rename the panel
    • -
    • +
    • +
    +

    + For this tutorial we will keep it simple with Domain A and Domain B. Where both + have their own panels. +

    + +

    Creating panels

    +

    + Usually panels are created using connections and folders to stay organized + automatic when making connections. However you can also create panels manually. + See below: +

    + +

    + Creating manual panels will make you able to organize tabs manually in mRemoteNG. + To then open a connection to the new panel then Right click on connection and use + "Connect (with options)" > Choose panel before connecting +

    +

    + The other option in the menu named "Connection Panels" will list all panels + in open in the current running mRemoteNG window. +

    +

    More options

    +

    + Right click menu for panels will give you a few more options for the panels: +

    + +
      +
    • Rename - Rename the panel
    • +
    • Send To... - Send the whole panel to monitor/screen [number]. Note this is not a real window but a detachable panel. So if you double click the title the panel will go back to mRemoteNG and not fullscreen the window. -
    • -
    -

    Tabs

    -

    - Speaking plain the tabs are also the connections that is open in mRemoteNG. - There are few tips and tricks regarding tabs and we will try to list them here. - In the below examples we will give you examples of RDP and SSH connections. -

    -

    Right click conext menu

    -

    - The right click context menu allows you to trigger som additional actions on - tabs for example: Rename Tab, Duplicate Tab, Reconnect, Disconnect etc. Below - are the two context menus from RDP and SSH. -

    -
    -

    RDP context menu

    - -
    -
    -

    SSH context menu

    - -
    -

    - If you check the difference between the menus you can see that there are some - actions that differ depending on the connection. This is intentional since its - specific for the type of connection. -

    -

    - The default and always available menu items are: -

      + +
    +

    Tabs

    +

    + Speaking plain the tabs are also the connections that is open in mRemoteNG. + There are few tips and tricks regarding tabs and we will try to list them here. + In the below examples we will give you examples of RDP and SSH connections. +

    +

    Right click conext menu

    +

    + The right click context menu allows you to trigger som additional actions on + tabs for example: Rename Tab, Duplicate Tab, Reconnect, Disconnect etc. Below + are the two context menus from RDP and SSH. +

    +
    +

    RDP context menu

    + +
    +
    +

    SSH context menu

    + +
    +

    + If you check the difference between the menus you can see that there are some + actions that differ depending on the connection. This is intentional since its + specific for the type of connection. +

    +

    + The default and always available menu items are: +

    • Screenshot - Create a screenshot to Screenshot Manager
    • External Tools - Run external tool script/action
    • Rename Tab - Rename current tab
    • Duplicate Tab - Duplicate tab connection
    • Reconnect - Reconnect the current tab
    • - Disconnect - Disconnect the current tab (Double clicking the tab - will also disconnect the current tab. If you want to change this action then - go to Tools > Options > Tabs & Panels and uncheck - "Double click on tab closes it") + Disconnect - Disconnect the current tab (Double clicking the tab + will also disconnect the current tab. If you want to change this action then + go to Tools > Options > Tabs & Panels and uncheck + "Double click on tab closes it")
    • -
    - Click around and try it out. You will get the hang of it. -

    - - - +
+ Click around and try it out. You will get the hang of it. +

+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_notifications.htm b/mRemoteV1/Resources/Help/ui_notifications.htm index 34aa16196..13a24511d 100644 --- a/mRemoteV1/Resources/Help/ui_notifications.htm +++ b/mRemoteV1/Resources/Help/ui_notifications.htm @@ -1,82 +1,82 @@ - + Notifications - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
- -

Introduction

-
-

- Notifications panel contains information for any errors or informational messages that - mRemoteNG triggers. Some example errors can be if there is a problem to connect, information - on lost connection and so much more. -

-

Settings for notifications

-
-

- Notification settings can be found in (Tools > Options > Notifications) below we will explain what - can be set and how they do affect for various troubleshooting. -

- + +

Introduction

+
+

+ Notifications panel contains information for any errors or informational messages that + mRemoteNG triggers. Some example errors can be if there is a problem to connect, information + on lost connection and so much more. +

+

Settings for notifications

+
+

+ Notification settings can be found in (Tools > Options > Notifications) below we will explain what + can be set and how they do affect for various troubleshooting. +

+ - -

Notifications general settings

- notification warning -

- This will tell mRemoteNG what type of messages and the level of messages to send to the panel. - It does not the level for the log that mRemoteNG has but only for panel output. -

-

There is also 2 different options mentioned below:

-
    -
  • + +

    Notifications general settings

    +notification warning +

    + This will tell mRemoteNG what type of messages and the level of messages to send to the panel. + It does not the level for the log that mRemoteNG has but only for panel output. +

    +

    There is also 2 different options mentioned below:

    +
      +
    • Show these message types - Level of messages to show in panel. (default: Warnings and Errors) -
    • -
    • +
    • +
    • Switch to Notifications panel on - If interface should switch to the panel when a level of message occurs (default: all enabled)
      - TIP! If you dont want the panel to show at all. Then unmark all options in - Switch to Notification panel on. Then the panel will not come up automatic. + TIP! If you dont want the panel to show at all. Then unmark all options in + Switch to Notification panel on. Then the panel will not come up automatic.
      -
    • -
    - +
  • +
+ - -

Logging settings

-

- Here you define the logging of messages. That is a continues log which can be used to backtrack - any error that has occurred. Good when for example reporting issues about mRemoteNG or to check - more details about problems. -

-
    -
  • + +

    Logging settings

    +

    + Here you define the logging of messages. That is a continues log which can be used to backtrack + any error that has occurred. Good when for example reporting issues about mRemoteNG or to check + more details about problems. +

    +
      +
    • Log path - Choose where the log should recide (default: Log to application directory) -
    • -
    • +
    • +
    • Log these message types - Level of logging to logfile (default: Informations, Warnings, Errors) -
    • -
    - +
  • +
+ - -

Popups settings

- popup warning -

- When items are selected here you will recieve a popup on the error that occurrs based on level - chosen in settings here. This can be useful if you do not want to use the notification area and only - get a popup if error occurs. (default: all off) -

- - - + +

Popups settings

+popup warning +

+ When items are selected here you will recieve a popup on the error that occurrs based on level + chosen in settings here. This can be useful if you do not want to use the notification area and only + get a popup if error occurs. (default: all off) +

+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_options.htm b/mRemoteV1/Resources/Help/ui_options.htm index c4e6b78e3..7fe7be77d 100644 --- a/mRemoteV1/Resources/Help/ui_options.htm +++ b/mRemoteV1/Resources/Help/ui_options.htm @@ -1,456 +1,512 @@ - + Options - - -
- Complete from nmat updates, please remove this div after review. Need help with missing information here. -
+ + +
+ Complete from nmat updates, please remove this div after review. Need help with missing information here. +
- -

Introduction

-
-

- Options window which can also be named settings is the window where you can personalize - your options for all of mRemoteNG. This includes how to set logging, credentials and so on. - Continue reading for the details of the different options here. -

-

Quick Reference

- - + +

Introduction

+
+

+ Options window which can also be named settings is the window where you can personalize + your options for all of mRemoteNG. This includes how to set logging, credentials and so on. + Continue reading for the details of the different options here. +

+

Quick Reference

+ + - -

Startup/Exit

-

- Options below are for the various settings for Startup/Exit of mRemoteNG. -

- - - - - - - + +

Startup/Exit

+

+ Options below are for the various settings for Startup/Exit of mRemoteNG. +

+
OptionDefaultDescription
+ + + + + + - - + + - - + This option will allow you to open the connection from which + you where connected to after last exit of application. + + + - - + + - -
+ Option + + Default + + Description +
Save connection on exit On Save to connection file/database on exit of mRemoteNG.
Reconnect to previously opened sessions on startup Off - This option will allow you to open the connection from which - you where connected to after last exit of application. -
Allow only a single instance of the application (mRemoteNG restart required) Off - Enforces and makes sure only a single instance of mRemoteNG is running on the - computer. + Enforces and makes sure only a single instance of mRemoteNG is running on the + computer.
Check proper installation of components at startup Off Opens the panel for Components Check on every startup.
- + + + - -

Appearance

-

- Various options for mRemoteNG appearance. -

- - - - - - - + +

Appearance

+

+ Various options for mRemoteNG appearance. +

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - - + + - - + + - -
+ Option + + Default + + Description +
Language (Automatically Detect) Which language to use for the interface of mRemoteNG.
Show description tooltips in connection tree Off - Holding mouse over a item in connection tree will show a popout from mouse - with information. + Holding mouse over a item in connection tree will show a popout from mouse + with information.
Show full connections file path in window title Off - Adds the complete path to the title of mRemoteNG to where the connection file is - located. + Adds the complete path to the title of mRemoteNG to where the connection file is + located.
Always show notification area icon Off - Adds mRemoteNG to the taskbar in the OS. + Adds mRemoteNG to the taskbar in the OS.
Minimize to notification area Off - Will place mRemoteNG in taskbar on minimize. + Will place mRemoteNG in taskbar on minimize.
- + + + - -

Tabs & Panels

-

- Various settings for how tabs & panels should work in mRemoteNG. -

- - - - - - - + +

Tabs & Panels

+

+ Various settings for how tabs & panels should work in mRemoteNG. +

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - -
+ Option + + Default + + Description +
Always show panel tabs Off Will always show the tabs & panels in mRemoteNG
Open new tab to the right of the currently selected tab On - When active then open next tab on the right of the active selection in mRemoteNG. Turn - this off and next tab will open the next connection at the end of all tabs. + When active then open next tab on the right of the active selection in mRemoteNG. Turn + this off and next tab will open the next connection at the end of all tabs.
Show logon information on tab names Off Show your login in the connection tab.
Show protocols on tab names Off When active then in the tab show what protocol is used for the connection.
Identify quick connect tabs by adding the prefix "Quick:" Off - When active shows Quick: before the connection name in the tab connection to easier - identify what is a quick connection and what is a non quick connection. + When active shows Quick: before the connection name in the tab connection to easier + identify what is a quick connection and what is a non quick connection.
Double click on tab closes it On - When double clicking a tab it will close the connection but does not log you - out from the server. The connection in this case is active on the destination - server. + When double clicking a tab it will close the connection but does not log you + out from the server. The connection in this case is active on the destination + server.
Always show panel selection dialog when opening connections Off - Option to allow you to always select what panel to place the connection on. - If this is off it will create a General panel where the connection is placed - or use the connections set panel from the connection options. + Option to allow you to always select what panel to place the connection on. + If this is off it will create a General panel where the connection is placed + or use the connections set panel from the connection options.
Create a empty panel when mRemoteNG starts Off - On startup if this is active mRemoteNG will create a panel mentioned under - Panel Name: + On startup if this is active mRemoteNG will create a panel mentioned under + Panel Name:
- + + + - -

Notifications

- - + +

Notifications

+ + - -

Connections

-

-

- - - - - - - + +

Connections

+

+

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - - + + - - + + - - + + - - - + + - - - + + - - - + + - -
+ Option + + Default + + Description +
Single click on connections opens it Off - In connection tree when this is active will try to connect on single click. By default - this is turned off to use double click to open connection. + In connection tree when this is active will try to connect on single click. By default + this is turned off to use double click to open connection.
Single click on opened connection in Connection Tree switches to the opened Connection Tab Off - Allows you to single click on a active connection in the connection tree to go to that - open connection in the tabs faster. + Allows you to single click on a active connection in the connection tree to go to that + open connection in the tabs faster.
Set hostname like display name when creating or renaming connections Off - Will make mRemoteNG try to use the remote host hostname to set the title of the tab - in mRemoteNG. + Will make mRemoteNG try to use the remote host hostname to set the title of the tab + in mRemoteNG.
Save connections after every exit On - When active mRemoteNG will save the connection tree to the active config - after every exit. If inactive then you have to save using - File > Save Connection File or keyboard shortcut - Ctrl+S + When active mRemoteNG will save the connection tree to the active config + after every exit. If inactive then you have to save using + File > Save Connection File or keyboard shortcut + Ctrl+S
Filter search matches in connection tree Off - Allows you to filter out the connections to which does not match - your filter search in the connection tree. If not active the search - will only select the filter to which you do search. + Allows you to filter out the connections to which does not match + your filter search in the connection tree. If not active the search + will only select the filter to which you do search.
RDP Reconnect count 5Value in seconds
+
+ Value in seconds
RDP Connection Timeout 20Value in seconds
+
+ Value in seconds
Auto save time in minutes (0 means disabled) 0Value in minutes
+
+ Value in minutes
When closing connections Warn me when closing connections - Various options of how mRemoteNG should act when you close connections. - The different options are listed below: -
    -
  • Warn me when closing connections
  • -
  • Warn me only when closing multiple connections
  • -
  • Warn me only when exiting mRemoteNG
  • -
  • Do not warn me when closing connections
  • -
- By default a warning will come up on closing a connection. Change this value - based on your prefered settings. + Various options of how mRemoteNG should act when you close connections. + The different options are listed below: +
    +
  • Warn me when closing connections
  • +
  • Warn me only when closing multiple connections
  • +
  • Warn me only when exiting mRemoteNG
  • +
  • Do not warn me when closing connections
  • +
+ By default a warning will come up on closing a connection. Change this value + based on your prefered settings.
- + + + - -

Credentials

-

- Options for credentials in mRemoteNG. The main purpose here - is that when you have empty username, password or domain field - then use below information. -

- - - - - - - + +

Credentials

+

+ Options for credentials in mRemoteNG. The main purpose here + is that when you have empty username, password or domain field + then use below information. +

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - -
+ Option + + Default + + Description +
None On Use no specific settings on login
My Current credentials (Windows logon information) Off - This option will use the logon information for the OS. This is useful if you - are in a domain that uses specific credentials and want to login to servers - with those credentials. + This option will use the logon information for the OS. This is useful if you + are in a domain that uses specific credentials and want to login to servers + with those credentials.
The following: Off - Use one or two of the options below for the empty login or all of them. - For example if you have a different domain that you login to the servers with. + Use one or two of the options below for the empty login or all of them. + For example if you have a different domain that you login to the servers with.
- + + + - - -

SQL Server

-
- NOTE! To understand more about SQL Server connection please - See here -
- - - - - - - + + +

SQL Server

+
+ NOTE! To understand more about SQL Server connection please + + See here + +
+
OptionDefaultDescription
+ + + + + + - -
+ Option + + Default + + Description +
Use SQL Server to load & save connections Off Enable to fetch connections from a database.
- + + + - -

Updates

-

- Options for how mRemoteNG should check for updates from the website. -

- - - - - - - + +

Updates

+

+ Options for how mRemoteNG should check for updates from the website. +

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - -
+ Option + + Default + + Description +
Check for updates at startup On (Every 14 days) - Here you can choose how often mRemoteNG checks for updates. - Standard is every 14 days + Here you can choose how often mRemoteNG checks for updates. + Standard is every 14 days
Release Channel: Stable - The main channel to use for mRemoteNG. Note that the channels are described under - the selection. Stable is suggested for normal usage but its always good to get - feedback on upcoming releases. + The main channel to use for mRemoteNG. Note that the channels are described under + the selection. Stable is suggested for normal usage but its always good to get + feedback on upcoming releases.
Use a proxy server to connect Off - Proxy to connect through to check for updates. This is not a proxy connection - for when you connect to a server but more to check for updates. + Proxy to connect through to check for updates. This is not a proxy connection + for when you connect to a server but more to check for updates.
- + + + - - -

Theme

-

- UI themes. This is not enabled by default but can be used - inside mRemoteNG. To enable themes you have to first - enable it in the checkbox at the bottom of the options. - Then restart mRemoteNG in order for it to work. -

-

- Default theme is: vs2015light -

-
- NOTE! To know more about themes and how to - create your own See Here -
- + + +

Theme

+

+ UI themes. This is not enabled by default but can be used + inside mRemoteNG. To enable themes you have to first + enable it in the checkbox at the bottom of the options. + Then restart mRemoteNG in order for it to work. +

+

+ Default theme is: vs2015light +

+
+ NOTE! To know more about themes and how to + create your own + + See Here + +
+ - - -

Security

- + + +

Security

+ - - -

Advanced

- - - - - - - + + +

Advanced

+
OptionDefaultDescription
+ + + + + + - - + + - - + + - - + + - - + + - - + + - -
+ Option + + Default + + Description +
Automatically get session information Off
Automatically try to reconnect when disconnected from server (RDP & ICA only) Off
Use UTF8 encoding for RDP "Load Balance info" property Off
Use custom PuTTY path: Off
To configure PuTTY sessions click this button: Launch PuTTY Will launch the putty agent so you can edit the sessions.
Maximum PuTTY and integrated external tools wait time: 2 seconds
- - - + + + + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_port_scan.htm b/mRemoteV1/Resources/Help/ui_port_scan.htm index a11203707..bd77b6d58 100644 --- a/mRemoteV1/Resources/Help/ui_port_scan.htm +++ b/mRemoteV1/Resources/Help/ui_port_scan.htm @@ -1,57 +1,58 @@ - + Port Scan - - -
- Complete from nmat updates, please remove this div after review. -
+ + +
+ Complete from nmat updates, please remove this div after review. +
- -

Introduction

-
-

- The Port Scan feature (under Tools > Port Scan) is similar to a nmap port scan. - It will scan a range of IP addresses and to determine if specific mRemoteNG supported - protocols are active. Hosts can then be bulk imported into mRemoteNG. -

- + +

Introduction

+
+

+ The Port Scan feature (under Tools > Port Scan) is similar to a nmap port scan. + It will scan a range of IP addresses and to determine if specific mRemoteNG supported + protocols are active. Hosts can then be bulk imported into mRemoteNG. +

+ - -

Use Case

-
-

- You've just inherited a new network with little to no documentation. - Inputting a range of IP addresses and scanning your entire network - should give you a good idea of what is currently online. - Importing those devices will then give you a quick - (relatively, scanning a large subnet will take a while) way to get into those devices. -

- + +

Use Case

+
+

+ You've just inherited a new network with little to no documentation. + Inputting a range of IP addresses and scanning your entire network + should give you a good idea of what is currently online. + Importing those devices will then give you a quick + (relatively, scanning a large subnet will take a while) way to get into those devices. +

+ - -

How to use

-
-
    -
  1. Start the Port Scan feature by clicking Tools > Port Scan in the menu bar.
  2. -
  3. Input your Start IP and End IP of the range you'd like to scan.
  4. -
  5. Enter the Start Port and End Port that mRemoteNG should test for. + +

    How to use

    +
    +
      +
    1. Start the Port Scan feature by clicking Tools > Port Scan in the menu bar.
    2. +
    3. Input your Start IP and End IP of the range you'd like to scan.
    4. +
    5. + Enter the Start Port and End Port that mRemoteNG should test for.
      - TIP! If you leave this at the default of 0 & 0, - the test will be for the default protocol ports that mRemoteNG supports. + TIP! If you leave this at the default of 0 & 0, + the test will be for the default protocol ports that mRemoteNG supports.
      -
    6. -
    7. Click Scan
    8. -
    9. Wait. Possibly a long time.
    10. -
    11. +
    12. +
    13. Click Scan
    14. +
    15. Wait. Possibly a long time.
    16. +
    17. The table will populate, and eventually you'll get a notification that the scan has completed. Alternatively, you can press Stop to end the scan at any time. -
    18. -
    19. Change the dropdown to the protocol you'd like to import and click Import.
    20. -
    - - - +
  6. +
  7. Change the dropdown to the protocol you'd like to import and click Import.
  8. +
+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_quick_connect.htm b/mRemoteV1/Resources/Help/ui_quick_connect.htm index 1123f6057..a60e75c49 100644 --- a/mRemoteV1/Resources/Help/ui_quick_connect.htm +++ b/mRemoteV1/Resources/Help/ui_quick_connect.htm @@ -1,54 +1,54 @@ - - Quick Connect - + + Quick Connect + -
+
Complete from nmat updates, please remove this div after review. -
- -

+

+ +

The Quick Connect functionality of mRemoteNG allows you to quickly connect to a remote host using a variety of network protocols. -

-

Use Cases

-

+

+

Use Cases

+

The primary use case for Quick Connect is to connect to remote hosts when you already remember the DNS hostname/IP address and the appropriate protocol for the connection.

An additional use case is to connect to remote hosts saved as a connection quickly. -

+

-

Prerequisites

-
    +

    Prerequisites

    +
    • Knowledge of a DNS host name or IP address
    • Knowledge of an appropriate protocol to communicate with remote host
    • -
    -

    OR

    -
      +
    +

    OR

    +
    • A predefined mRemoteNG connection
    • -
    +
-

Using QuickConnect

+

Using QuickConnect

-

+

To use Quick Connect, ensure the Quick Connect toolbar is enabled by selecting View and then Quick Connect Toolbar.
Next, input a DNS host name or IP address into the box labeled "Connect". This box will also save previous entries during your session.
- Quick Connect Toolbar + Quick Connect Toolbar

- Quick Connect Toolbar + Quick Connect Toolbar

Select the appropriate network protocol by clicking the arrow next to the Connect box.
- Quick Connect Toolbar + Quick Connect Toolbar

If you wish to use an existing connection, select the globe icon next to the protocol button and select the appropriate connection. -

+

- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_screenshot_manager.htm b/mRemoteV1/Resources/Help/ui_screenshot_manager.htm index 7d1db7cd7..783c3e011 100644 --- a/mRemoteV1/Resources/Help/ui_screenshot_manager.htm +++ b/mRemoteV1/Resources/Help/ui_screenshot_manager.htm @@ -1,62 +1,62 @@ - + Screenshot Manager - - - -
- Complete from nmat updates, please remove this div after review. -
+ + + +
+ Complete from nmat updates, please remove this div after review. +
-

Introduction

-

- The screenshot manager is a panel and tool that can be used to organize - and take screenshots inside mRemoteNG. -

+

Introduction

+

+ The screenshot manager is a panel and tool that can be used to organize + and take screenshots inside mRemoteNG. +

- -

Take a screenshot

-

- To take a screenshot of a instance its as easy as to right click on the - connection tab and press Screenshot and it will open the screenshot - manager. -

- - -

- On the left image you will see the right click menu for the connection tab. Clicking the - screenshot there will allow mRemoteNG to create a screenshot. -

-

- The right image is where the screenshots are stored in mRemoteNG. Here you can store - and then decide what to do with the images after you are done taking screenshots. -

- + +

Take a screenshot

+

+ To take a screenshot of a instance its as easy as to right click on the + connection tab and press Screenshot and it will open the screenshot + manager. +

+ + +

+ On the left image you will see the right click menu for the connection tab. Clicking the + screenshot there will allow mRemoteNG to create a screenshot. +

+

+ The right image is where the screenshots are stored in mRemoteNG. Here you can store + and then decide what to do with the images after you are done taking screenshots. +

+ - -

Editing

-

- The manager is a simple tool for saving and deleting screenshots. If you need to do - more with the screenshots then the suggestion is to open them in a third party app. - Here is what the manager allows you to do: -

    + +

    Editing

    +

    + The manager is a simple tool for saving and deleting screenshots. If you need to do + more with the screenshots then the suggestion is to open them in a third party app. + Here is what the manager allows you to do: +

    • Save
    • Save All
    • Delete
    • Delete All
    • -
    -

    -

    - Once you press save, a window to save the files will come up where you want to save - the screenshots. -

    -

    - Short summary of screenshot manager is that you can sit and create screenshots without - having to open a different manager all the time and instead let mRemoteNG create the - main screenshot which can be edited later on. -

    - - - +
+

+

+ Once you press save, a window to save the files will come up where you want to save + the screenshots. +

+

+ Short summary of screenshot manager is that you can sit and create screenshots without + having to open a different manager all the time and instead let mRemoteNG create the + main screenshot which can be edited later on. +

+ + + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/ui_sql_configuration.htm b/mRemoteV1/Resources/Help/ui_sql_configuration.htm index 1c652c95b..1d0803e31 100644 --- a/mRemoteV1/Resources/Help/ui_sql_configuration.htm +++ b/mRemoteV1/Resources/Help/ui_sql_configuration.htm @@ -1,39 +1,39 @@ - - SQL Configuration - + + SQL Configuration + -
+
Complete from nmat updates, please remove this div after review. -
+
-

Warning!

-
+

Warning!

+
The SQL feature is in an early beta stage and not intended for use in an productive environment! I recommend you to do a full backup of your connections and settings before switching to SQL Server. -
-

Databases Supported

-
-

+

+

Databases Supported

+
+

The list below are databases which have been tested on for support. Note that other databases may be supported in the future. -

-
    +

    +
    • Microsoft™ SQL Server
    • -
    -

    Steps to configure your SQL Server

    -
    -
      +
+

Steps to configure your SQL Server

+
+
  1. Create a new Database called "mRemoteNG" on your SQL Server.
  2. Run the SQL Script for your DB type listed below in topic (SQL Table creation Scripts) on the newly created Database.
  3. Give the users that you want to grant access to the mRemoteNG Connections Database Read/Write permissions on the Database.
  4. -
-

Steps to configure mRemoteNG for SQL

-
-
    +
+

Steps to configure mRemoteNG for SQL

+
+
  1. Start mRemoteNG if it's not already running.
  2. Go to Tools - Options - SQL Server
  3. Check the box that says "Use SQL Server to load & save connections".
  4. @@ -42,24 +42,26 @@
  5. Click OK to apply the changes. The main window title should now change to "mRemoteNG | SQL Server".
  6. Now click on File - Save to update the tables on your SQL Server with the data from the loaded connections xml file. (Do not click File - New, this doesn't work yet)
  7. You should now be able to do everything you were able to do with the XML storage plus see the changes live on another mRemoteNG instance that is connected to the same Database.
  8. -
-

SQL Table creation Scripts

-
-
+ +

SQL Table creation Scripts

+
+
- - - - - - - - - + + + + + + + + +
Script (click on script below for your db type)Description
Microsoft™ SQL scriptMicrosoft™ SQL Server
Script (click on script below for your db type)Description
+ Microsoft™ SQL script + Microsoft™ SQL Server
-
+
- + \ No newline at end of file diff --git a/mRemoteV1/Resources/Tiles/mRemoteNG.VisualElementsManifest.xml b/mRemoteV1/Resources/Tiles/mRemoteNG.VisualElementsManifest.xml index 1976da8a7..21d61de8c 100644 --- a/mRemoteV1/Resources/Tiles/mRemoteNG.VisualElementsManifest.xml +++ b/mRemoteV1/Resources/Tiles/mRemoteNG.VisualElementsManifest.xml @@ -1,8 +1,8 @@ - - + + \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_confcons_v2_5.xsd b/mRemoteV1/Schemas/mremoteng_confcons_v2_5.xsd index eea55c968..2364b621e 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_5.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_5.xsd @@ -1,135 +1,135 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd b/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd index e9df6b67e..f472fec32 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd @@ -1,147 +1,147 @@  + + targetNamespace="http://mremoteng.org" + xmlns="http://mremoteng.org" + xmlns:mrng="http://mremoteng.org" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + elementFormDefault="unqualified"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd b/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd index cb5905b1e..b2195ebe6 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd @@ -1,153 +1,153 @@  + + targetNamespace="http://mremoteng.org" + elementFormDefault="unqualified" + xmlns="http://mremoteng.org" + xmlns:mrng="http://mremoteng.org" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_credrepo_list_v1_0.xsd b/mRemoteV1/Schemas/mremoteng_credrepo_list_v1_0.xsd index 4f498b76b..76a4750a4 100644 --- a/mRemoteV1/Schemas/mremoteng_credrepo_list_v1_0.xsd +++ b/mRemoteV1/Schemas/mremoteng_credrepo_list_v1_0.xsd @@ -1,26 +1,26 @@  + + targetNamespace="http://mremoteng.org" + elementFormDefault="qualified" + xmlns="http://mremoteng.org" + xmlns:mrng="http://mremoteng.org" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + version="1.0"> - - - - - - + + + + + + + + + + + + + + - - - - - - - - \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_creds_v1_0.xsd b/mRemoteV1/Schemas/mremoteng_creds_v1_0.xsd index 8ad81340f..13e176f2c 100644 --- a/mRemoteV1/Schemas/mremoteng_creds_v1_0.xsd +++ b/mRemoteV1/Schemas/mremoteng_creds_v1_0.xsd @@ -1,32 +1,32 @@  + + targetNamespace="http://mremoteng.org" + elementFormDefault="qualified" + xmlns="http://mremoteng.org" + xmlns:mrng="http://mremoteng.org" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + version="1.0"> - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - \ No newline at end of file diff --git a/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs b/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs index 83bf82a6d..8c105cd71 100644 --- a/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs +++ b/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs @@ -14,7 +14,9 @@ namespace mRemoteNG.Security.Authentication public int MaxAttempts { get; set; } = 3; public SecureString LastAuthenticatedPassword { get; private set; } - public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText, Func> authenticationRequestor) + public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, + string cipherText, + Func> authenticationRequestor) { _cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider)); _cipherText = cipherText.ThrowIfNullOrEmpty(nameof(cipherText)); @@ -42,8 +44,10 @@ namespace mRemoteNG.Security.Authentication password = providedPassword.First(); if (password == null || password.Length == 0) break; } + attempts++; } + return authenticated; } } diff --git a/mRemoteV1/Security/BlockCipherEngines.cs b/mRemoteV1/Security/BlockCipherEngines.cs index 88932b87b..45f89d013 100644 --- a/mRemoteV1/Security/BlockCipherEngines.cs +++ b/mRemoteV1/Security/BlockCipherEngines.cs @@ -1,5 +1,5 @@ - -// ReSharper disable InconsistentNaming +// ReSharper disable InconsistentNaming + namespace mRemoteNG.Security { public enum BlockCipherEngines diff --git a/mRemoteV1/Security/BlockCipherModes.cs b/mRemoteV1/Security/BlockCipherModes.cs index 11d2e932b..cb1cfd27d 100644 --- a/mRemoteV1/Security/BlockCipherModes.cs +++ b/mRemoteV1/Security/BlockCipherModes.cs @@ -1,5 +1,5 @@ - -// ReSharper disable InconsistentNaming +// ReSharper disable InconsistentNaming + namespace mRemoteNG.Security { public enum BlockCipherModes diff --git a/mRemoteV1/Security/EncryptedSecureString.cs b/mRemoteV1/Security/EncryptedSecureString.cs index 9b66713df..848de5d46 100644 --- a/mRemoteV1/Security/EncryptedSecureString.cs +++ b/mRemoteV1/Security/EncryptedSecureString.cs @@ -1,6 +1,7 @@ using System.Security; using mRemoteNG.Security.SymmetricEncryption; using Org.BouncyCastle.Security; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Security @@ -51,7 +52,7 @@ namespace mRemoteNG.Security { machineKeyString += (char)random.Next(33, 126); } - + return machineKeyString.ConvertToSecureString(); } } diff --git a/mRemoteV1/Security/Factories/CryptoProviderFactoryFromSettings.cs b/mRemoteV1/Security/Factories/CryptoProviderFactoryFromSettings.cs index 16052ed81..7873e9927 100644 --- a/mRemoteV1/Security/Factories/CryptoProviderFactoryFromSettings.cs +++ b/mRemoteV1/Security/Factories/CryptoProviderFactoryFromSettings.cs @@ -4,7 +4,9 @@ { public ICryptographyProvider Build() { - var provider = new CryptoProviderFactory(Settings.Default.EncryptionEngine, Settings.Default.EncryptionBlockCipherMode).Build(); + var provider = + new CryptoProviderFactory(Settings.Default.EncryptionEngine, Settings.Default.EncryptionBlockCipherMode) + .Build(); provider.KeyDerivationIterations = Settings.Default.EncryptionKeyDerivationIterations; return provider; } diff --git a/mRemoteV1/Security/Factories/CryptoProviderFactoryFromXml.cs b/mRemoteV1/Security/Factories/CryptoProviderFactoryFromXml.cs index 69da8ff4e..6d4d5d559 100644 --- a/mRemoteV1/Security/Factories/CryptoProviderFactoryFromXml.cs +++ b/mRemoteV1/Security/Factories/CryptoProviderFactoryFromXml.cs @@ -21,8 +21,10 @@ namespace mRemoteNG.Security.Factories ICryptographyProvider cryptoProvider; try { - var engine = (BlockCipherEngines)Enum.Parse(typeof(BlockCipherEngines), _element?.Attribute("EncryptionEngine")?.Value ?? ""); - var mode = (BlockCipherModes)Enum.Parse(typeof(BlockCipherModes), _element?.Attribute("BlockCipherMode")?.Value ?? ""); + var engine = (BlockCipherEngines)Enum.Parse(typeof(BlockCipherEngines), + _element?.Attribute("EncryptionEngine")?.Value ?? ""); + var mode = (BlockCipherModes)Enum.Parse(typeof(BlockCipherModes), + _element?.Attribute("BlockCipherMode")?.Value ?? ""); cryptoProvider = new CryptoProviderFactory(engine, mode).Build(); var keyDerivationIterations = int.Parse(_element?.Attribute("KdfIterations")?.Value ?? ""); diff --git a/mRemoteV1/Security/KeyDerivation/IKeyDerivationFunction.cs b/mRemoteV1/Security/KeyDerivation/IKeyDerivationFunction.cs index 5b081e932..ee3c77705 100644 --- a/mRemoteV1/Security/KeyDerivation/IKeyDerivationFunction.cs +++ b/mRemoteV1/Security/KeyDerivation/IKeyDerivationFunction.cs @@ -1,5 +1,4 @@ - -namespace mRemoteNG.Security.KeyDerivation +namespace mRemoteNG.Security.KeyDerivation { public interface IKeyDerivationFunction { diff --git a/mRemoteV1/Security/KeyDerivation/Pkcs5S2KeyGenerator.cs b/mRemoteV1/Security/KeyDerivation/Pkcs5S2KeyGenerator.cs index 8d01c88b8..c34bfc3e5 100644 --- a/mRemoteV1/Security/KeyDerivation/Pkcs5S2KeyGenerator.cs +++ b/mRemoteV1/Security/KeyDerivation/Pkcs5S2KeyGenerator.cs @@ -28,7 +28,7 @@ namespace mRemoteNG.Security.KeyDerivation var keyGenerator = new Pkcs5S2ParametersGenerator(); keyGenerator.Init(passwordInBytes, salt, _iterations); - var keyParameter = (KeyParameter) keyGenerator.GenerateDerivedMacParameters(_keyBitSize); + var keyParameter = (KeyParameter)keyGenerator.GenerateDerivedMacParameters(_keyBitSize); var keyBytes = keyParameter.GetKey(); return keyBytes; } diff --git a/mRemoteV1/Security/PasswordCreation/PasswordIncludesSpecialCharactersConstraint.cs b/mRemoteV1/Security/PasswordCreation/PasswordIncludesSpecialCharactersConstraint.cs index 46bf16167..86ba562a6 100644 --- a/mRemoteV1/Security/PasswordCreation/PasswordIncludesSpecialCharactersConstraint.cs +++ b/mRemoteV1/Security/PasswordCreation/PasswordIncludesSpecialCharactersConstraint.cs @@ -10,7 +10,7 @@ namespace mRemoteNG.Security.PasswordCreation { private readonly int _minimumCount; - public IEnumerable SpecialCharacters { get; } = new []{'!','@','#','$','%','^','&','*'}; + public IEnumerable SpecialCharacters { get; } = new[] {'!', '@', '#', '$', '%', '^', '&', '*'}; public string ConstraintHint { get; } @@ -22,14 +22,15 @@ namespace mRemoteNG.Security.PasswordCreation _minimumCount = minimumCount; } - public PasswordIncludesSpecialCharactersConstraint(IEnumerable specialCharacters, int minimumCount = 1) + public PasswordIncludesSpecialCharactersConstraint(IEnumerable specialCharacters, int minimumCount = 1) : this(minimumCount) { if (specialCharacters == null) throw new ArgumentNullException(nameof(specialCharacters)); SpecialCharacters = specialCharacters; - ConstraintHint = string.Format(Language.strPasswordConstainsSpecialCharactersConstraintHint, _minimumCount, string.Concat(SpecialCharacters)); + ConstraintHint = string.Format(Language.strPasswordConstainsSpecialCharactersConstraintHint, _minimumCount, + string.Concat(SpecialCharacters)); } public bool Validate(SecureString password) diff --git a/mRemoteV1/Security/PasswordCreation/PasswordLengthConstraint.cs b/mRemoteV1/Security/PasswordCreation/PasswordLengthConstraint.cs index 0c6758143..adbdb17bb 100644 --- a/mRemoteV1/Security/PasswordCreation/PasswordLengthConstraint.cs +++ b/mRemoteV1/Security/PasswordCreation/PasswordLengthConstraint.cs @@ -18,7 +18,8 @@ namespace mRemoteNG.Security.PasswordCreation if (maxLength <= 0) throw new ArgumentException($"{nameof(maxLength)} must be a positive, non-zero value."); if (maxLength < minimumLength) - throw new ArgumentException($"{nameof(maxLength)} must be greater than or equal to {nameof(minimumLength)}."); + throw new ArgumentException( + $"{nameof(maxLength)} must be greater than or equal to {nameof(minimumLength)}."); _minLength = minimumLength; _maxLength = maxLength; diff --git a/mRemoteV1/Security/RandomGenerator.cs b/mRemoteV1/Security/RandomGenerator.cs index 286caddfa..7687080a8 100644 --- a/mRemoteV1/Security/RandomGenerator.cs +++ b/mRemoteV1/Security/RandomGenerator.cs @@ -13,12 +13,14 @@ namespace mRemoteNG.Security var randomGen = new SecureRandom(); var stringBuilder = new StringBuilder(); - const string availableChars = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+|[]{};:',./<>?"; + const string availableChars = + @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+|[]{};:',./<>?"; for (var x = 0; x < length; x++) { var randomIndex = randomGen.Next(availableChars.Length - 1); stringBuilder.Append(availableChars[randomIndex]); } + return stringBuilder.ToString(); } } diff --git a/mRemoteV1/Security/SaveFilter.cs b/mRemoteV1/Security/SaveFilter.cs index 7216e82d9..db3a086fa 100644 --- a/mRemoteV1/Security/SaveFilter.cs +++ b/mRemoteV1/Security/SaveFilter.cs @@ -1,26 +1,25 @@ - namespace mRemoteNG.Security { - public class SaveFilter - { - public SaveFilter(bool disableEverything = false) - { - if (disableEverything) return; - SaveUsername = true; - SavePassword = true; - SaveDomain = true; - SaveCredentialId = true; + public class SaveFilter + { + public SaveFilter(bool disableEverything = false) + { + if (disableEverything) return; + SaveUsername = true; + SavePassword = true; + SaveDomain = true; + SaveCredentialId = true; SaveInheritance = true; - } + } - public bool SaveUsername { get; set; } + public bool SaveUsername { get; set; } - public bool SavePassword { get; set; } + public bool SavePassword { get; set; } - public bool SaveDomain { get; set; } + public bool SaveDomain { get; set; } public bool SaveCredentialId { get; set; } - public bool SaveInheritance { get; set; } - } + public bool SaveInheritance { get; set; } + } } \ No newline at end of file diff --git a/mRemoteV1/Security/SymmetricEncryption/AeadCryptographyProvider.cs b/mRemoteV1/Security/SymmetricEncryption/AeadCryptographyProvider.cs index 850da78d4..c8e0635c7 100644 --- a/mRemoteV1/Security/SymmetricEncryption/AeadCryptographyProvider.cs +++ b/mRemoteV1/Security/SymmetricEncryption/AeadCryptographyProvider.cs @@ -16,6 +16,7 @@ using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Security.SymmetricEncryption @@ -115,7 +116,8 @@ namespace mRemoteNG.Security.SymmetricEncryption //User Error Checks if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength) - throw new ArgumentException($"Must have a password of at least {MinPasswordLength} characters!", nameof(password)); + throw new ArgumentException($"Must have a password of at least {MinPasswordLength} characters!", + nameof(password)); if (secretMessage == null || secretMessage.Length == 0) throw new ArgumentException(@"Secret Message Required!", nameof(secretMessage)); @@ -170,6 +172,7 @@ namespace mRemoteNG.Security.SymmetricEncryption //Write Cipher Text binaryWriter.Write(cipherText); } + return combinedStream.ToArray(); } @@ -180,21 +183,27 @@ namespace mRemoteNG.Security.SymmetricEncryption return decryptedText; } - private string SimpleDecryptWithPassword(string encryptedMessage, SecureString decryptionKey, int nonSecretPayloadLength = 0) + private string SimpleDecryptWithPassword(string encryptedMessage, + SecureString decryptionKey, + int nonSecretPayloadLength = 0) { if (string.IsNullOrWhiteSpace(encryptedMessage)) return ""; //throw new ArgumentException(@"Encrypted Message Required!", nameof(encryptedMessage)); var cipherText = Convert.FromBase64String(encryptedMessage); - var plainText = SimpleDecryptWithPassword(cipherText, decryptionKey.ConvertToUnsecureString(), nonSecretPayloadLength); + var plainText = SimpleDecryptWithPassword(cipherText, decryptionKey.ConvertToUnsecureString(), + nonSecretPayloadLength); return plainText == null ? null : _encoding.GetString(plainText); } - private byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, string password, int nonSecretPayloadLength = 0) + private byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, + string password, + int nonSecretPayloadLength = 0) { //User Error Checks if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength) - throw new ArgumentException($"Must have a password of at least {MinPasswordLength} characters!", nameof(password)); + throw new ArgumentException($"Must have a password of at least {MinPasswordLength} characters!", + nameof(password)); if (encryptedMessage == null || encryptedMessage.Length == 0) throw new ArgumentException(@"Encrypted Message Required!", nameof(encryptedMessage)); @@ -227,13 +236,14 @@ namespace mRemoteNG.Security.SymmetricEncryption //Grab Nonce var nonce = cipherReader.ReadBytes(NonceBitSize / 8); - + var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload); _aeadBlockCipher.Init(false, parameters); //Decrypt Cipher Text - var cipherText = cipherReader.ReadBytes(encryptedMessage.Length - nonSecretPayloadLength - nonce.Length); - var plainText = new byte[_aeadBlockCipher.GetOutputSize(cipherText.Length)]; + var cipherText = + cipherReader.ReadBytes(encryptedMessage.Length - nonSecretPayloadLength - nonce.Length); + var plainText = new byte[_aeadBlockCipher.GetOutputSize(cipherText.Length)]; try { diff --git a/mRemoteV1/Security/SymmetricEncryption/LegacyRijndaelCryptographyProvider.cs b/mRemoteV1/Security/SymmetricEncryption/LegacyRijndaelCryptographyProvider.cs index 5ebd0eb3e..5cfa17ef1 100644 --- a/mRemoteV1/Security/SymmetricEncryption/LegacyRijndaelCryptographyProvider.cs +++ b/mRemoteV1/Security/SymmetricEncryption/LegacyRijndaelCryptographyProvider.cs @@ -9,69 +9,70 @@ using mRemoteNG.Messages; namespace mRemoteNG.Security.SymmetricEncryption { - public class LegacyRijndaelCryptographyProvider : ICryptographyProvider - { + public class LegacyRijndaelCryptographyProvider : ICryptographyProvider + { public int BlockSizeInBytes { get; } public BlockCipherEngines CipherEngine { get; } public BlockCipherModes CipherMode { get; } - public int KeyDerivationIterations { get; set; } + public int KeyDerivationIterations { get; set; } - public LegacyRijndaelCryptographyProvider() - { - BlockSizeInBytes = 16; - } + public LegacyRijndaelCryptographyProvider() + { + BlockSizeInBytes = 16; + } public string Encrypt(string strToEncrypt, SecureString strSecret) - { - if (strToEncrypt == "" || strSecret.Length == 0) - return strToEncrypt; - - try - { - var rd = new RijndaelManaged(); + { + if (strToEncrypt == "" || strSecret.Length == 0) + return strToEncrypt; + + try + { + var rd = new RijndaelManaged(); var md5 = new MD5CryptoServiceProvider(); var key = md5.ComputeHash(Encoding.UTF8.GetBytes(strSecret.ConvertToUnsecureString())); - - md5.Clear(); - rd.Key = key; - rd.GenerateIV(); + + md5.Clear(); + rd.Key = key; + rd.GenerateIV(); var iv = rd.IV; var ms = new MemoryStream(); - - ms.Write(iv, 0, iv.Length); + + ms.Write(iv, 0, iv.Length); var cs = new CryptoStream(ms, rd.CreateEncryptor(), CryptoStreamMode.Write); var data = Encoding.UTF8.GetBytes(strToEncrypt); - - cs.Write(data, 0, data.Length); - cs.FlushFinalBlock(); + + cs.Write(data, 0, data.Length); + cs.FlushFinalBlock(); var encdata = ms.ToArray(); - cs.Close(); - rd.Clear(); - - return Convert.ToBase64String(encdata); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorEncryptionFailed, ex.Message)); - } - - return strToEncrypt; - } - - public string Decrypt(string ciphertextBase64, SecureString password) - { - if (string.IsNullOrEmpty(ciphertextBase64) || password.Length == 0) - return ciphertextBase64; - - try - { + cs.Close(); + rd.Clear(); + + return Convert.ToBase64String(encdata); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + string.Format(Language.strErrorEncryptionFailed, ex.Message)); + } + + return strToEncrypt; + } + + public string Decrypt(string ciphertextBase64, SecureString password) + { + if (string.IsNullOrEmpty(ciphertextBase64) || password.Length == 0) + return ciphertextBase64; + + try + { var plaintext = ""; using (var rijndaelManaged = new RijndaelManaged()) @@ -89,7 +90,8 @@ namespace mRemoteNG.Security.SymmetricEncryption memoryStream.Read(iv, 0, iv.Length); rijndaelManaged.IV = iv; - var cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Read); + var cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), + CryptoStreamMode.Read); using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8, true)) { plaintext = streamReader.ReadToEnd(); @@ -99,11 +101,11 @@ namespace mRemoteNG.Security.SymmetricEncryption return plaintext; } - catch (Exception ex) - { - //Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorDecryptionFailed, ex.Message)); + catch (Exception ex) + { + //Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorDecryptionFailed, ex.Message)); throw new EncryptionException(Language.strErrorDecryptionFailed, ex); - } - } - } + } + } + } } \ No newline at end of file diff --git a/mRemoteV1/Settings.cs b/mRemoteV1/Settings.cs index 53c713966..60a552075 100644 --- a/mRemoteV1/Settings.cs +++ b/mRemoteV1/Settings.cs @@ -2,17 +2,16 @@ namespace mRemoteNG { - - // This class allows you to handle specific events on the settings class: // The SettingChanging event is raised before a setting's value is changed. // The PropertyChanged event is raised after a setting's value is changed. // The SettingsLoaded event is raised after the setting values are loaded. // The SettingsSaving event is raised before the setting values are saved. [global::System.Configuration.SettingsProviderAttribute(typeof(mRemoteNG.Config.Settings.Providers.ChooseProvider))] - internal sealed partial class Settings { - - public Settings() { + internal sealed partial class Settings + { + public Settings() + { // // To add event handlers for saving and changing settings, uncomment the lines below: // // this.SettingChanging += this.SettingChangingEventHandler; @@ -21,12 +20,14 @@ namespace mRemoteNG // } - private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { + private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) + { // Add code to handle the SettingChangingEvent event here. } - - private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { + + private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) + { // Add code to handle the SettingsSaving event here. } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Themes/ExtendedColorPalette.cs b/mRemoteV1/Themes/ExtendedColorPalette.cs index 2aae9691e..f8bbe1d70 100644 --- a/mRemoteV1/Themes/ExtendedColorPalette.cs +++ b/mRemoteV1/Themes/ExtendedColorPalette.cs @@ -3,7 +3,6 @@ using System.Drawing; namespace mRemoteNG.Themes { - /// /// Class used for the UI to display the color tables,as the Dictionary value keys cannot be directly replaced /// @@ -14,6 +13,7 @@ namespace mRemoteNG.Themes Key = _key; Value = _value; } + public string Key { get; set; } public Color Value { get; set; } @@ -26,25 +26,30 @@ namespace mRemoteNG.Themes public class ExtendedColorPalette { #region Private Variables + //Collection for color values that are not loaded by dock panels (list, buttons,panel content, etc) #endregion #region Constructors + public ExtendedColorPalette() { ExtColorPalette = new Dictionary(); - DefaultColorPalette = new Dictionary(); // If this is the default palette, it will not have a default-default palette - + DefaultColorPalette = + new Dictionary(); // If this is the default palette, it will not have a default-default palette } + #endregion #region Public Methods + // Set the default theme, that theme should contain all color values used by the application public void setDefault(ExtendedColorPalette inPalettte) { DefaultColorPalette = inPalettte.ExtColorPalette; } + #endregion /// @@ -52,23 +57,24 @@ namespace mRemoteNG.Themes /// /// /// - public Color getColor(string colorKey) + public Color getColor(string colorKey) { - var retColor = ExtColorPalette.ContainsKey(colorKey) ? ExtColorPalette[colorKey]:Color.Empty; + var retColor = ExtColorPalette.ContainsKey(colorKey) ? ExtColorPalette[colorKey] : Color.Empty; //Invisible colors are not good, might indicate missing color from the palette as is represented by 00000000 if (retColor != Color.Empty && retColor.A != 0) return retColor; - if(DefaultColorPalette != null) + if (DefaultColorPalette != null) { retColor = DefaultColorPalette.ContainsKey(colorKey) ? DefaultColorPalette[colorKey] : Color.Empty; } + //why are we here?, just avoid a crash - if(retColor == Color.Empty) + if (retColor == Color.Empty) { //Fail to pink , because why not retColor = Color.Pink; } - return retColor; + return retColor; } /// @@ -76,7 +82,7 @@ namespace mRemoteNG.Themes /// /// /// - public void addColor(string colorKey,Color inColor) + public void addColor(string colorKey, Color inColor) { ExtColorPalette.Add(colorKey, inColor); } @@ -89,7 +95,7 @@ namespace mRemoteNG.Themes /// public void replaceColor(string colorKey, Color inColor) { - ExtColorPalette[colorKey]= inColor; + ExtColorPalette[colorKey] = inColor; } public Dictionary DefaultColorPalette { get; set; } @@ -97,7 +103,4 @@ namespace mRemoteNG.Themes public Dictionary ExtColorPalette { get; set; } } -} - - - \ No newline at end of file +} \ No newline at end of file diff --git a/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs b/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs index 2ee357cb6..e62b89130 100644 --- a/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs +++ b/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs @@ -4,24 +4,22 @@ using System.Globalization; using System.IO; using System.Xml; -namespace mRemoteNG.Themes +namespace mRemoteNG.Themes { //Class to extract the rest of the required theme colors for MremoteNG from the vstheme file - public class MremoteNGPaletteManipulator + public class MremoteNGPaletteManipulator { private XmlDocument _xml; - private ExtendedColorPalette _defaultPalette; + private ExtendedColorPalette _defaultPalette; - //warning, defaultpalette should always contain all the values, because when is loaded there is no default palette (parameter is null - public MremoteNGPaletteManipulator(byte[] file, ExtendedColorPalette defaultPalette = null ) + public MremoteNGPaletteManipulator(byte[] file, ExtendedColorPalette defaultPalette = null) { _xml = new XmlDocument(); - _xml.LoadXml(new StreamReader(new MemoryStream(file)).ReadToEnd()); + _xml.LoadXml(new StreamReader(new MemoryStream(file)).ReadToEnd()); _defaultPalette = defaultPalette ?? new ExtendedColorPalette(); } - //Load the colors for the mRemoteNG own components as Dockpanel only have a menus and docks palette @@ -33,19 +31,19 @@ namespace mRemoteNG.Themes // foreach (DictionaryEntry entry in resourceSet) { - var colorName = entry.Key.ToString(); + var colorName = entry.Key.ToString(); var xmlQueryPath = entry.Value.ToString(); if (_xml.DocumentElement == null) continue; var colorNodeList = _xml.DocumentElement.FirstChild.SelectNodes(xmlQueryPath); var color = colorNodeList != null && colorNodeList.Count > 0 ? colorNodeList[0].Value : null; - if (color != null ) + if (color != null) { - newPalette.addColor(colorName , ColorTranslator.FromHtml($"#{color}")); + newPalette.addColor(colorName, ColorTranslator.FromHtml($"#{color}")); } - } + } return newPalette; - } + } /// @@ -53,10 +51,10 @@ namespace mRemoteNG.Themes /// /// /// - public byte[] mergePalette(ExtendedColorPalette colorPalette) + public byte[] mergePalette(ExtendedColorPalette colorPalette) { var resourceSet = ColorMapTheme.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true); - + foreach (DictionaryEntry entry in resourceSet) { var colorName = entry.Key.ToString(); @@ -66,12 +64,12 @@ namespace mRemoteNG.Themes var paletteColor = colorPalette.getColor(colorName); colorNodeList[0].Value = $"FF{paletteColor.R:X2}{paletteColor.G:X2}{paletteColor.B:X2}"; } + var ms = new MemoryStream(); _xml.Save(ms); var bytes = ms.ToArray(); return bytes; } - } -} +} \ No newline at end of file diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index 2cadca511..bebbf3258 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -21,7 +21,7 @@ } } - public class MremoteDockPaneStripFactory : DockPanelExtender.IDockPaneStripFactory + public class MremoteDockPaneStripFactory : DockPanelExtender.IDockPaneStripFactory { public DockPaneStripBase CreateDockPaneStrip(DockPane pane) { @@ -42,5 +42,5 @@ { return new FloatWindowNG(dockPanel, pane); } - } + } } \ No newline at end of file diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index 8440eca65..eb0f2445e 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -6,24 +6,29 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Themes { - /// /// /// Container class for all the color and style elements to define a theme /// - public class ThemeInfo : ICloneable + public class ThemeInfo : ICloneable { #region Private Variables + private string _name; private ThemeBase _theme; - private string _URI; + private string _URI; private VisualStudioToolStripExtender.VsVersion _version; private ExtendedColorPalette _extendedPalette; #endregion #region Constructors - public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion, ExtendedColorPalette inExtendedPalette) + + public ThemeInfo(string themeName, + ThemeBase inTheme, + string inURI, + VisualStudioToolStripExtender.VsVersion inVersion, + ExtendedColorPalette inExtendedPalette) { _name = themeName; _theme = inTheme; @@ -33,13 +38,16 @@ namespace mRemoteNG.Themes IsThemeBase = false; IsExtendable = false; - if(_extendedPalette != null) + if (_extendedPalette != null) IsExtended = true; setCustomExtenders(); } - public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion) + public ThemeInfo(string themeName, + ThemeBase inTheme, + string inURI, + VisualStudioToolStripExtender.VsVersion inVersion) { _name = themeName; _theme = inTheme; @@ -49,11 +57,12 @@ namespace mRemoteNG.Themes IsExtendable = false; IsExtended = false; setCustomExtenders(); - } + #endregion #region Public Methods + public object Clone() { var extPalette = new ExtendedColorPalette @@ -75,19 +84,21 @@ namespace mRemoteNG.Themes #region Properties + [Browsable(false)] public string Name - { - get => _name; + { + get => _name; set - { - if (string.Equals(_name, value, StringComparison.InvariantCulture)) - { - return; - } - _name = value; - } - } + { + if (string.Equals(_name, value, StringComparison.InvariantCulture)) + { + return; + } + + _name = value; + } + } public ThemeBase Theme { @@ -98,12 +109,13 @@ namespace mRemoteNG.Themes { return; } + _theme = value; setCustomExtenders(); } } - public string URI + public string URI { get => _URI; set @@ -112,6 +124,7 @@ namespace mRemoteNG.Themes { return; } + _URI = value; } } @@ -125,6 +138,7 @@ namespace mRemoteNG.Themes { return; } + _version = value; } } @@ -138,6 +152,7 @@ namespace mRemoteNG.Themes { return; } + _extendedPalette = value; } } diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 4890b6dfe..53a6fbb8f 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -19,14 +19,16 @@ namespace mRemoteNG.Themes { #region Private Variables - private ThemeInfo _activeTheme; - private Hashtable themes; + private ThemeInfo _activeTheme; + private Hashtable themes; private bool _themeActive; private static ThemeManager themeInstance; private readonly string themePath = App.Info.SettingsFileInfo.ThemeFolder; + #endregion #region Constructors + private ThemeManager() { LoadThemes(); @@ -41,7 +43,7 @@ namespace mRemoteNG.Themes else { ActiveTheme = DefaultTheme; - if(string.IsNullOrEmpty(Settings.Default.ThemeName)) return; + if (string.IsNullOrEmpty(Settings.Default.ThemeName)) return; //too early for logging to be enabled... Debug.WriteLine("Detected invalid Theme in settings file. Resetting to default."); @@ -54,6 +56,7 @@ namespace mRemoteNG.Themes #endregion #region Public Methods + public static ThemeManager getInstance() { return themeInstance ?? (themeInstance = new ThemeManager()); @@ -62,7 +65,7 @@ namespace mRemoteNG.Themes public ThemeInfo getTheme(string themeName) { - if(themes[themeName] != null) + if (themes[themeName] != null) return (ThemeInfo)themes[themeName]; return null; } @@ -77,14 +80,12 @@ namespace mRemoteNG.Themes if (!Directory.Exists(themePath)) { Directory.CreateDirectory(themePath); - } var orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder); var files = orig.GetFiles(); foreach (var file in files) { - if (!File.Exists(Path.Combine(themePath, file.Name))) file.CopyTo(Path.Combine(themePath, file.Name), true); } @@ -109,9 +110,9 @@ namespace mRemoteNG.Themes if (!File.Exists($"{themePath}\\vs2015light.vstheme")) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Could not find default theme file.", true); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Could not find default theme file.", + true); return null; - } //First we load the default base theme, its vs2015lightNG @@ -131,7 +132,7 @@ namespace mRemoteNG.Themes } //The manager precharges all the themes at once - public List LoadThemes() + public List LoadThemes() { if (themes != null) return themes.Values.OfType().ToList(); themes = new Hashtable(); @@ -166,44 +167,65 @@ namespace mRemoteNG.Themes //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme // 2003 - var vs2003 = new ThemeInfo("vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); + var vs2003 = new ThemeInfo("vs2003", new VS2003Theme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2003, + ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2003.Name, vs2003); // 2005 - var vs2005 = new ThemeInfo("vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); + var vs2005 = new ThemeInfo("vs2005", new VS2005Theme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2005, + ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2005.Name, vs2005); // 2012 - var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); + var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2012, + ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2012Light.Name, vs2012Light); - var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); + var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2012, + ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2012Dark.Name, vs2012Dark); - var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); + var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2012, + ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2012Blue.Name, vs2012Blue); // 2013 - var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); + var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2013, + ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2013Light.Name, vs2013Light); - var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); + var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2013, + ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2013Dark.Name, vs2013Dark); - var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); + var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2013, + ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2013Blue.Name, vs2013Blue); // 2015 - var vs2015Light = new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); + var vs2015Light = new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2015, + ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2015Light.Name, vs2015Light); - var vs2015Dark = new ThemeInfo("vs2015Dark", new VS2015DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); + var vs2015Dark = new ThemeInfo("vs2015Dark", new VS2015DarkTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2015, + ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2015Dark.Name, vs2015Dark); - var vs2015Blue = new ThemeInfo("vs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); + var vs2015Blue = new ThemeInfo("vs2015Blue", new VS2015BlueTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2015, + ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2015Blue.Name, vs2015Blue); - - } } - catch(Exception ex) + catch (Exception ex) { Runtime.MessageCollector.AddExceptionStackTrace("Error loading themes", ex); } + return themes.Values.OfType().ToList(); } @@ -220,8 +242,8 @@ namespace mRemoteNG.Themes modifiedTheme.Name = newThemeName; modifiedTheme.IsExtendable = true; modifiedTheme.IsThemeBase = false; - ThemeSerializer.SaveToXmlFile(modifiedTheme,baseTheme); - themes.Add(newThemeName,modifiedTheme); + ThemeSerializer.SaveToXmlFile(modifiedTheme, baseTheme); + themes.Add(newThemeName, modifiedTheme); return modifiedTheme; } @@ -229,7 +251,7 @@ namespace mRemoteNG.Themes public void deleteTheme(ThemeInfo themeToDelete) { if (!themes.Contains(themeToDelete.Name)) return; - if(ActiveTheme == themeToDelete) + if (ActiveTheme == themeToDelete) ActiveTheme = DefaultTheme; themes.Remove(themeToDelete.Name); ThemeSerializer.DeleteFile(themeToDelete); @@ -256,32 +278,36 @@ namespace mRemoteNG.Themes return name.IndexOfAny(badChars) == -1; } - #endregion #region Events + public delegate void ThemeChangedEventHandler(); + private ThemeChangedEventHandler ThemeChangedEvent; - public event ThemeChangedEventHandler ThemeChanged + public event ThemeChangedEventHandler ThemeChanged { add => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Combine(ThemeChangedEvent, value); remove => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Remove(ThemeChangedEvent, value); } // ReSharper disable once UnusedParameter.Local - private void NotifyThemeChanged(object sender, PropertyChangedEventArgs e) + private void NotifyThemeChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Name") { return; } + ThemeChangedEvent?.Invoke(); } + #endregion #region Properties - public bool ThemingActive + + public bool ThemingActive { get => _themeActive; set @@ -293,14 +319,18 @@ namespace mRemoteNG.Themes } } - public ThemeInfo DefaultTheme => themes != null && ThemesCount > 0 ? (ThemeInfo)themes["vs2015Light"] : new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015); + public ThemeInfo DefaultTheme => + themes != null && ThemesCount > 0 + ? (ThemeInfo)themes["vs2015Light"] + : new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", + VisualStudioToolStripExtender.VsVersion.Vs2015); public ThemeInfo ActiveTheme - { + { // default if themes are not enabled get => ThemingActive == false ? DefaultTheme : _activeTheme; set - { + { // You can only enable theming if there are themes loaded // Default accordingly... if (value == null) @@ -310,7 +340,7 @@ namespace mRemoteNG.Themes Settings.Default.ThemeName = DefaultTheme.Name; _activeTheme = DefaultTheme; - if(changed) + if (changed) NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); Settings.Default.Save(); @@ -318,10 +348,10 @@ namespace mRemoteNG.Themes } _activeTheme = value; - Settings.Default.ThemeName = value.Name; - NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); - } - } + Settings.Default.ThemeName = value.Name; + NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); + } + } public bool ActiveAndExtended => ThemingActive && ActiveTheme.IsExtended; @@ -329,4 +359,4 @@ namespace mRemoteNG.Themes #endregion } -} \ No newline at end of file +} \ No newline at end of file diff --git a/mRemoteV1/Themes/ThemeSerializer.cs b/mRemoteV1/Themes/ThemeSerializer.cs index 2b0fc449c..345407086 100644 --- a/mRemoteV1/Themes/ThemeSerializer.cs +++ b/mRemoteV1/Themes/ThemeSerializer.cs @@ -4,22 +4,22 @@ using System.Linq; namespace mRemoteNG.Themes { - public static class ThemeSerializer - { - /// - /// Save the theme to file, name property is used as filename - /// The baseTheme is used as a template, by copy that file and rewrite the extpalette values - /// - /// - /// - public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme) - { + public static class ThemeSerializer + { + /// + /// Save the theme to file, name property is used as filename + /// The baseTheme is used as a template, by copy that file and rewrite the extpalette values + /// + /// + /// + public static void SaveToXmlFile(ThemeInfo themeToSave, ThemeInfo baseTheme) + { var oldURI = baseTheme.URI; var directoryName = Path.GetDirectoryName(oldURI); - var toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme"; + var toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme"; File.Copy(baseTheme.URI, toSaveURI); themeToSave.URI = toSaveURI; - } + } public static void DeleteFile(ThemeInfo themeToDelete) { @@ -44,22 +44,27 @@ namespace mRemoteNG.Themes /// /// /// - public static ThemeInfo LoadFromXmlFile(string filename, ThemeInfo defaultTheme=null) - { + public static ThemeInfo LoadFromXmlFile(string filename, ThemeInfo defaultTheme = null) + { var bytes = File.ReadAllBytes(filename); //Load the dockpanel part var themeBaseLoad = new MremoteNGThemeBase(bytes); //Load the mremote part - //Cause we cannot default the theme for the default theme + //Cause we cannot default the theme for the default theme var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette); - var loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors()); - if(new[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }.Contains(Path.GetFileNameWithoutExtension(filename))) + var loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, + VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors()); + if (new[] {"darcula", "vs2015blue", "vs2015dark", "vs2015light"}.Contains( + Path + .GetFileNameWithoutExtension(filename)) + ) { loadedTheme.IsThemeBase = true; } + loadedTheme.IsExtendable = true; return loadedTheme; - } + } /* private static string EncodeColorName(Color color) @@ -74,6 +79,5 @@ namespace mRemoteNG.Themes return regex.Match(name).Success ? Color.FromArgb(Convert.ToInt32(name, 16)) : Color.FromName(name); } */ - } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/Authenticode.cs b/mRemoteV1/Tools/Authenticode.cs index 213015c6b..0a29a56fb 100644 --- a/mRemoteV1/Tools/Authenticode.cs +++ b/mRemoteV1/Tools/Authenticode.cs @@ -78,7 +78,8 @@ namespace mRemoteNG.Tools var windowHandle = DisplayParentForm?.Handle ?? IntPtr.Zero; - _trustProviderErrorCode = NativeMethods.WinVerifyTrust(windowHandle, NativeMethods.WINTRUST_ACTION_GENERIC_VERIFY_V2, trustDataPointer); + _trustProviderErrorCode = + NativeMethods.WinVerifyTrust(windowHandle, NativeMethods.WINTRUST_ACTION_GENERIC_VERIFY_V2, trustDataPointer); // ReSharper disable once SwitchStatementMissingSomeCases switch (_trustProviderErrorCode) { @@ -103,7 +104,8 @@ namespace mRemoteNG.Tools if (ex is CryptographicException) { - var hResultProperty = ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance); + var hResultProperty = + ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance); if (hResultProperty != null) { var hResult = Convert.ToInt32(hResultProperty.GetValue(ex, null)); @@ -270,7 +272,8 @@ namespace mRemoteNG.Tools public const int TRUST_E_SUBJECT_NOT_TRUSTED = unchecked ((int) 0x800B0004); public const int TRUST_E_NOSIGNATURE = unchecked ((int) 0x800B0100); - public static readonly Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}"); + public static readonly Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = + new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}"); public const uint WTD_CHOICE_FILE = 1; public const uint WTD_DISABLE_MD2_MD4 = 0x2000; diff --git a/mRemoteV1/Tools/Cmdline/CmdArgumentsInterpreter.cs b/mRemoteV1/Tools/Cmdline/CmdArgumentsInterpreter.cs index 20f23b51e..c66e47f5e 100644 --- a/mRemoteV1/Tools/Cmdline/CmdArgumentsInterpreter.cs +++ b/mRemoteV1/Tools/Cmdline/CmdArgumentsInterpreter.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Text.RegularExpressions; using mRemoteNG.App; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Tools.Cmdline @@ -55,8 +56,10 @@ namespace mRemoteNG.Tools.Cmdline Parts[0] = remover.Replace(Parts[0], "$1"); _parameters.Add(parameter, Parts[0]); } + parameter = null; } + // else Error: no parameter waiting for a value (skipped) break; case 2: @@ -69,6 +72,7 @@ namespace mRemoteNG.Tools.Cmdline _parameters.Add(parameter, "true"); } } + parameter = Parts[1]; break; case 3: @@ -81,6 +85,7 @@ namespace mRemoteNG.Tools.Cmdline _parameters.Add(parameter, "true"); } } + parameter = Parts[1]; // Remove possible enclosing characters (",') if (!_parameters.ContainsKey(parameter)) @@ -88,10 +93,12 @@ namespace mRemoteNG.Tools.Cmdline Parts[2] = remover.Replace(Parts[2], "$1"); _parameters.Add(parameter, Parts[2]); } + parameter = null; break; } } + // In case a parameter is still waiting if (parameter == null) return; if (!_parameters.ContainsKey(parameter)) diff --git a/mRemoteV1/Tools/Cmdline/CommandLineArguments.cs b/mRemoteV1/Tools/Cmdline/CommandLineArguments.cs index 198d745ad..43d5589e4 100644 --- a/mRemoteV1/Tools/Cmdline/CommandLineArguments.cs +++ b/mRemoteV1/Tools/Cmdline/CommandLineArguments.cs @@ -4,125 +4,131 @@ using System.Text.RegularExpressions; namespace mRemoteNG.Tools.Cmdline { - // Adapted from http://qntm.org/cmd - public class CommandLineArguments - { - protected List Arguments = new List(); - - public bool EscapeForShell {get; set;} - - #region Public Methods - public void Add(string argument, bool forceQuotes = false) - { - Arguments.Add(new Argument(argument, false, forceQuotes)); - } - - public void Add(params string[] argumentArray) - { - foreach (var argument in argumentArray) - { - Add(argument); - } - } - - public void AddFileName(string fileName, bool forceQuotes = false) - { - Arguments.Add(new Argument(fileName, true, forceQuotes)); - } - - public override string ToString() - { - var argList = Arguments.Select(argument => ProcessArgument(argument, EscapeForShell)); - return string.Join(" ", argList.ToArray()); - } - - public static string PrefixFileName(string argument) - { - if (string.IsNullOrEmpty(argument)) - return argument; - - if (argument.StartsWith("-")) - argument = ".\\" + argument; - - return argument; - } - - public static string EscapeBackslashes(string argument) - { - if (string.IsNullOrEmpty(argument)) - { - return argument; - } - - // Sequence of backslashes followed by a double quote: - // double up all the backslashes and escape the double quote - return Regex.Replace(argument, "(\\\\*)\"", "$1$1\\\""); - } - - public static string EscapeBackslashesForTrailingQuote(string argument) - { - if (string.IsNullOrEmpty(argument)) - { - return argument; - } - - // Sequence of backslashes followed by the end of the string - // (which will become a double quote): - // double up all the backslashes - return Regex.Replace(argument, "(\\\\*)$", "$1$1"); - } - - public static string QuoteArgument(string argument, bool forceQuotes = false) - { - if (!forceQuotes && !string.IsNullOrEmpty(argument) && !argument.Contains(" ")) - { - return argument; - } - - return "\"" + EscapeBackslashesForTrailingQuote(argument) + "\""; - } - - public static string EscapeShellMetacharacters(string argument) - { - return string.IsNullOrEmpty(argument) ? argument : Regex.Replace(argument, "([()%!^\"<>&|])", "^$1"); - } + // Adapted from http://qntm.org/cmd + public class CommandLineArguments + { + protected List Arguments = new List(); + + public bool EscapeForShell { get; set; } + + #region Public Methods + + public void Add(string argument, bool forceQuotes = false) + { + Arguments.Add(new Argument(argument, false, forceQuotes)); + } + + public void Add(params string[] argumentArray) + { + foreach (var argument in argumentArray) + { + Add(argument); + } + } + + public void AddFileName(string fileName, bool forceQuotes = false) + { + Arguments.Add(new Argument(fileName, true, forceQuotes)); + } + + public override string ToString() + { + var argList = Arguments.Select(argument => ProcessArgument(argument, EscapeForShell)); + return string.Join(" ", argList.ToArray()); + } + + public static string PrefixFileName(string argument) + { + if (string.IsNullOrEmpty(argument)) + return argument; + + if (argument.StartsWith("-")) + argument = ".\\" + argument; + + return argument; + } + + public static string EscapeBackslashes(string argument) + { + if (string.IsNullOrEmpty(argument)) + { + return argument; + } + + // Sequence of backslashes followed by a double quote: + // double up all the backslashes and escape the double quote + return Regex.Replace(argument, "(\\\\*)\"", "$1$1\\\""); + } + + public static string EscapeBackslashesForTrailingQuote(string argument) + { + if (string.IsNullOrEmpty(argument)) + { + return argument; + } + + // Sequence of backslashes followed by the end of the string + // (which will become a double quote): + // double up all the backslashes + return Regex.Replace(argument, "(\\\\*)$", "$1$1"); + } + + public static string QuoteArgument(string argument, bool forceQuotes = false) + { + if (!forceQuotes && !string.IsNullOrEmpty(argument) && !argument.Contains(" ")) + { + return argument; + } + + return "\"" + EscapeBackslashesForTrailingQuote(argument) + "\""; + } + + public static string EscapeShellMetacharacters(string argument) + { + return string.IsNullOrEmpty(argument) ? argument : Regex.Replace(argument, "([()%!^\"<>&|])", "^$1"); + } + + #endregion - #endregion - #region Protected Methods - protected static string ProcessArgument(Argument argument, bool escapeForShell = false) - { - var text = argument.Text; - - if (argument.IsFileName) - { - text = PrefixFileName(text); - } - text = EscapeBackslashes(text); - text = QuoteArgument(text, argument.ForceQuotes); - if (escapeForShell) - { - text = EscapeShellMetacharacters(text); - } - - return text; - } + + protected static string ProcessArgument(Argument argument, bool escapeForShell = false) + { + var text = argument.Text; + + if (argument.IsFileName) + { + text = PrefixFileName(text); + } + + text = EscapeBackslashes(text); + text = QuoteArgument(text, argument.ForceQuotes); + if (escapeForShell) + { + text = EscapeShellMetacharacters(text); + } + + return text; + } + #endregion - + #region Protected Classes - protected class Argument - { - public Argument(string text, bool isFileName = false, bool forceQuotes = false) - { - Text = text; - IsFileName = isFileName; - ForceQuotes = forceQuotes; - } - - public string Text {get; set;} - public bool IsFileName {get; set;} - public bool ForceQuotes {get; set;} - } + + protected class Argument + { + public Argument(string text, bool isFileName = false, bool forceQuotes = false) + { + Text = text; + IsFileName = isFileName; + ForceQuotes = forceQuotes; + } + + public string Text { get; set; } + public bool IsFileName { get; set; } + public bool ForceQuotes { get; set; } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/Cmdline/StartupArgumentsInterpreter.cs b/mRemoteV1/Tools/Cmdline/StartupArgumentsInterpreter.cs index b3f37ae2d..b1cd36e7b 100644 --- a/mRemoteV1/Tools/Cmdline/StartupArgumentsInterpreter.cs +++ b/mRemoteV1/Tools/Cmdline/StartupArgumentsInterpreter.cs @@ -9,7 +9,7 @@ using mRemoteNG.Messages; namespace mRemoteNG.Tools.Cmdline { - public class StartupArgumentsInterpreter + public class StartupArgumentsInterpreter { private readonly MessageCollector _messageCollector; @@ -46,15 +46,15 @@ namespace mRemoteNG.Tools.Cmdline { if (args["resetpos"] == null && args["rp"] == null && args["reset"] == null) return; _messageCollector.AddMessage(MessageClass.DebugMsg, "Cmdline arg: Resetting window positions."); - Settings.Default.MainFormKiosk = false; - var newWidth = 900; - var newHeight = 600; - var newX = Screen.PrimaryScreen.WorkingArea.Width / 2 - newWidth / 2; - var newY = Screen.PrimaryScreen.WorkingArea.Height / 2 - newHeight / 2; - Settings.Default.MainFormLocation = new Point(newX, newY); - Settings.Default.MainFormSize = new Size(newWidth, newHeight); - Settings.Default.MainFormState = FormWindowState.Normal; - } + Settings.Default.MainFormKiosk = false; + var newWidth = 900; + var newHeight = 600; + var newX = Screen.PrimaryScreen.WorkingArea.Width / 2 - newWidth / 2; + var newY = Screen.PrimaryScreen.WorkingArea.Height / 2 - newHeight / 2; + Settings.Default.MainFormLocation = new Point(newX, newY); + Settings.Default.MainFormSize = new Size(newWidth, newHeight); + Settings.Default.MainFormState = FormWindowState.Normal; + } private void ParseResetPanelsArg(CmdArgumentsInterpreter args) { @@ -73,7 +73,8 @@ namespace mRemoteNG.Tools.Cmdline private void ParseNoReconnectArg(CmdArgumentsInterpreter args) { if (args["noreconnect"] == null && args["norc"] == null) return; - _messageCollector.AddMessage(MessageClass.DebugMsg, "Cmdline arg: Disabling reconnection to previously connected hosts"); + _messageCollector.AddMessage(MessageClass.DebugMsg, + "Cmdline arg: Disabling reconnection to previously connected hosts"); Settings.Default.NoReconnect = true; } @@ -95,9 +96,11 @@ namespace mRemoteNG.Tools.Cmdline Settings.Default.CustomConsPath = Path.Combine(GeneralAppInfo.HomePath, args[consParam]); return; } + if (!File.Exists(Path.Combine(ConnectionsFileInfo.DefaultConnectionsPath, args[consParam]))) return; Settings.Default.LoadConsFromCustomLocation = true; - Settings.Default.CustomConsPath = Path.Combine(ConnectionsFileInfo.DefaultConnectionsPath, args[consParam]); + Settings.Default.CustomConsPath = + Path.Combine(ConnectionsFileInfo.DefaultConnectionsPath, args[consParam]); } else { diff --git a/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs b/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs index bf6cfa005..6bcbf357a 100644 --- a/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs +++ b/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs @@ -10,7 +10,7 @@ using mRemoteNG.Tree; namespace mRemoteNG.Tools { - public class ConnectionsTreeToMenuItemsConverter + public class ConnectionsTreeToMenuItemsConverter { public MouseEventHandler MouseUpEventHandler { get; set; } @@ -32,6 +32,7 @@ namespace mRemoteNG.Tools { Runtime.MessageCollector.AddExceptionMessage("frmMain.AddNodeToMenu() failed", ex); } + return dropDownList; } @@ -69,7 +70,7 @@ namespace mRemoteNG.Tools menuItem.Image = node.OpenConnections.Count > 0 ? Resources.Play : Resources.Pause; menuItem.Tag = node; } - + menuItem.MouseUp += MouseUpEventHandler; return menuItem; } diff --git a/mRemoteV1/Tools/CustomCollections/FullyObservableCollection.cs b/mRemoteV1/Tools/CustomCollections/FullyObservableCollection.cs index b51564268..3094e6aa5 100644 --- a/mRemoteV1/Tools/CustomCollections/FullyObservableCollection.cs +++ b/mRemoteV1/Tools/CustomCollections/FullyObservableCollection.cs @@ -6,14 +6,14 @@ using System.Linq; namespace mRemoteNG.Tools.CustomCollections { - public class FullyObservableCollection : IFullyNotifiableList + public class FullyObservableCollection : IFullyNotifiableList where T : INotifyPropertyChanged - { - private readonly IList _list = new List(); - private bool _eventsAllowed; + { + private readonly IList _list = new List(); + private bool _eventsAllowed; public int Count => _list.Count; - public bool IsReadOnly => _list.IsReadOnly; + public bool IsReadOnly => _list.IsReadOnly; public T this[int index] { @@ -21,22 +21,22 @@ namespace mRemoteNG.Tools.CustomCollections set { _list[index] = value; } } - public FullyObservableCollection() - { - } + public FullyObservableCollection() + { + } - public FullyObservableCollection(IEnumerable items) - { + public FullyObservableCollection(IEnumerable items) + { AddRange(items); } - public void Add(T item) - { - _list.Add(item); - SubscribeToChildEvents(item); + public void Add(T item) + { + _list.Add(item); + SubscribeToChildEvents(item); if (_eventsAllowed) RaiseCollectionChangedEvent(ActionType.Added, new[] {item}); - } + } /// /// Adds a range of items to the collection. @@ -44,41 +44,41 @@ namespace mRemoteNG.Tools.CustomCollections /// after all new items are added. /// /// - public void AddRange(IEnumerable items) + public void AddRange(IEnumerable items) { var itemsAsList = items.ToList(); - _eventsAllowed = false; + _eventsAllowed = false; foreach (var item in itemsAsList) Add(item); - _eventsAllowed = true; + _eventsAllowed = true; RaiseCollectionChangedEvent(ActionType.Added, itemsAsList); - } + } public void Insert(int index, T item) { _list.Insert(index, item); SubscribeToChildEvents(item); - RaiseCollectionChangedEvent(ActionType.Added, new[] { item }); + RaiseCollectionChangedEvent(ActionType.Added, new[] {item}); } - public bool Remove(T item) - { - var worked = _list.Remove(item); - if (!worked) return worked; - UnsubscribeFromChildEvents(item); + public bool Remove(T item) + { + var worked = _list.Remove(item); + if (!worked) return worked; + UnsubscribeFromChildEvents(item); RaiseCollectionChangedEvent(ActionType.Removed, new[] {item}); - return worked; - } + return worked; + } - public void RemoveAt(int index) - { - var item = _list[index]; - _list.RemoveAt(index); - UnsubscribeFromChildEvents(item); - RaiseCollectionChangedEvent(ActionType.Removed, new[] { item }); - } + public void RemoveAt(int index) + { + var item = _list[index]; + _list.RemoveAt(index); + UnsubscribeFromChildEvents(item); + RaiseCollectionChangedEvent(ActionType.Removed, new[] {item}); + } public void Clear() { @@ -90,9 +90,9 @@ namespace mRemoteNG.Tools.CustomCollections } private void SubscribeToChildEvents(INotifyPropertyChanged item) - { - item.PropertyChanged += ItemOnPropertyChanged; - } + { + item.PropertyChanged += ItemOnPropertyChanged; + } private void UnsubscribeFromChildEvents(INotifyPropertyChanged item) { @@ -100,12 +100,12 @@ namespace mRemoteNG.Tools.CustomCollections } private void ItemOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) - { + { if (sender is T) - RaiseCollectionChangedEvent(ActionType.Updated, new []{ (T)sender }); - } + RaiseCollectionChangedEvent(ActionType.Updated, new[] {(T)sender}); + } - public event EventHandler> CollectionUpdated; + public event EventHandler> CollectionUpdated; private void RaiseCollectionChangedEvent(ActionType action, IEnumerable changedItems) { @@ -113,11 +113,13 @@ namespace mRemoteNG.Tools.CustomCollections } #region Forwarded method calls + public int IndexOf(T item) => _list.IndexOf(item); public IEnumerator GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); public bool Contains(T item) => _list.Contains(item); public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex); + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Tools/DisposableOptional.cs b/mRemoteV1/Tools/DisposableOptional.cs index ecc6bff64..371c83b76 100644 --- a/mRemoteV1/Tools/DisposableOptional.cs +++ b/mRemoteV1/Tools/DisposableOptional.cs @@ -25,4 +25,4 @@ namespace mRemoteNG.Tools this.First().Dispose(); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/EnumWindows.cs b/mRemoteV1/Tools/EnumWindows.cs index f60ae8ee2..d550fe130 100644 --- a/mRemoteV1/Tools/EnumWindows.cs +++ b/mRemoteV1/Tools/EnumWindows.cs @@ -4,49 +4,52 @@ using System.Runtime.InteropServices; namespace mRemoteNG.Tools { - public class EnumWindows - { - public List EnumWindows_Renamed() - { - var handleList = new List(); - - HandleLists.Add(handleList); - var handleIndex = (IntPtr)HandleLists.IndexOf(handleList); - NativeMethods.EnumWindows(EnumCallback, handleIndex); - HandleLists.Remove(handleList); - - return handleList; - } - - public List EnumChildWindows(IntPtr hWndParent) - { - var handleList = new List(); - - HandleLists.Add(handleList); + public class EnumWindows + { + public List EnumWindows_Renamed() + { + var handleList = new List(); + + HandleLists.Add(handleList); var handleIndex = (IntPtr)HandleLists.IndexOf(handleList); - NativeMethods.EnumChildWindows(hWndParent, EnumCallback, handleIndex); - HandleLists.Remove(handleList); - - return handleList; - } - - private readonly List> HandleLists = new List>(); - - private bool EnumCallback(int hwnd, int lParam) - { - HandleLists[lParam].Add((IntPtr)hwnd); - return true; - } - - // ReSharper disable ClassNeverInstantiated.Local - private class NativeMethods - { - // ReSharper restore ClassNeverInstantiated.Local - public delegate bool EnumWindowsProc(int hwnd, int lParam); - [DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)] - public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); - [DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)] - public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - } - } -} + NativeMethods.EnumWindows(EnumCallback, handleIndex); + HandleLists.Remove(handleList); + + return handleList; + } + + public List EnumChildWindows(IntPtr hWndParent) + { + var handleList = new List(); + + HandleLists.Add(handleList); + var handleIndex = (IntPtr)HandleLists.IndexOf(handleList); + NativeMethods.EnumChildWindows(hWndParent, EnumCallback, handleIndex); + HandleLists.Remove(handleList); + + return handleList; + } + + private readonly List> HandleLists = new List>(); + + private bool EnumCallback(int hwnd, int lParam) + { + HandleLists[lParam].Add((IntPtr)hwnd); + return true; + } + + // ReSharper disable ClassNeverInstantiated.Local + private class NativeMethods + { + // ReSharper restore ClassNeverInstantiated.Local + + public delegate bool EnumWindowsProc(int hwnd, int lParam); + + [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] + public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); + + [DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] + public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/Extensions.cs b/mRemoteV1/Tools/Extensions.cs index ad4eb66b2..8f13b29ab 100644 --- a/mRemoteV1/Tools/Extensions.cs +++ b/mRemoteV1/Tools/Extensions.cs @@ -1,28 +1,27 @@ - -using System; +using System; using System.Collections.Generic; using System.Linq; namespace mRemoteNG.Tools { public static class Extensions - { - public static Optional Maybe(this T value) - { - return new Optional(value); - } + { + public static Optional Maybe(this T value) + { + return new Optional(value); + } - public static Optional MaybeParse(this T value, Func parseFunc) - { - try - { - return new Optional(parseFunc(value)); - } - catch - { - return new Optional(); - } - } + public static Optional MaybeParse(this T value, Func parseFunc) + { + try + { + return new Optional(parseFunc(value)); + } + catch + { + return new Optional(); + } + } /// /// Throws an if the given value is @@ -33,12 +32,12 @@ namespace mRemoteNG.Tools /// /// The name of the argument /// - public static T ThrowIfNull(this T value, string argName) - { + public static T ThrowIfNull(this T value, string argName) + { if (value == null) throw new ArgumentNullException(argName); - return value; - } + return value; + } /// /// Throws an if the value @@ -46,12 +45,12 @@ namespace mRemoteNG.Tools /// /// /// - public static string ThrowIfNullOrEmpty(this string value, string argName) - { + public static string ThrowIfNullOrEmpty(this string value, string argName) + { if (string.IsNullOrEmpty(value)) throw new ArgumentException("Value cannot be null or empty", argName); - return value; - } + return value; + } /// /// Perform an action for each item in the given collection. The item @@ -61,14 +60,14 @@ namespace mRemoteNG.Tools /// /// /// - public static IEnumerable ForEach(this IEnumerable collection, Action action) + public static IEnumerable ForEach(this IEnumerable collection, Action action) { collection = collection.ToList(); foreach (var item in collection) - action(item); + action(item); - return collection; - } - } -} + return collection; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/ExternalTool.cs b/mRemoteV1/Tools/ExternalTool.cs index 5942b508f..b0ab89f86 100644 --- a/mRemoteV1/Tools/ExternalTool.cs +++ b/mRemoteV1/Tools/ExternalTool.cs @@ -8,129 +8,135 @@ using mRemoteNG.App; using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Messages; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Tools { - public class ExternalTool : INotifyPropertyChanged - { + public class ExternalTool : INotifyPropertyChanged + { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - private string _displayName; - private string _fileName; - private bool _waitForExit; - private string _arguments; - private string _workingDir; - private bool _tryIntegrate; - private bool _showOnToolbar = true; - private bool _runElevated; + private string _displayName; + private string _fileName; + private bool _waitForExit; + private string _arguments; + private string _workingDir; + private bool _tryIntegrate; + private bool _showOnToolbar = true; + private bool _runElevated; - #region Public Properties + #region Public Properties - public string DisplayName - { - get { return _displayName; } - set { SetField(ref _displayName, value, nameof(DisplayName)); } - } + public string DisplayName + { + get { return _displayName; } + set { SetField(ref _displayName, value, nameof(DisplayName)); } + } - public string FileName - { - get { return _fileName; } - set { SetField(ref _fileName, value, nameof(FileName)); } - } + public string FileName + { + get { return _fileName; } + set { SetField(ref _fileName, value, nameof(FileName)); } + } - public bool WaitForExit - { - get { return _waitForExit; } - set - { - // WaitForExit cannot be turned on when TryIntegrate is true + public bool WaitForExit + { + get { return _waitForExit; } + set + { + // WaitForExit cannot be turned on when TryIntegrate is true if (TryIntegrate) return; SetField(ref _waitForExit, value, nameof(WaitForExit)); - } - } + } + } - public string Arguments - { - get { return _arguments; } - set { SetField(ref _arguments, value, nameof(Arguments)); } - } + public string Arguments + { + get { return _arguments; } + set { SetField(ref _arguments, value, nameof(Arguments)); } + } - public string WorkingDir - { - get { return _workingDir; } - set { SetField(ref _workingDir, value, nameof(WorkingDir)); } - } + public string WorkingDir + { + get { return _workingDir; } + set { SetField(ref _workingDir, value, nameof(WorkingDir)); } + } - public bool TryIntegrate - { - get { return _tryIntegrate; } - set - { + public bool TryIntegrate + { + get { return _tryIntegrate; } + set + { // WaitForExit cannot be turned on when TryIntegrate is true - if (value) - WaitForExit = false; - SetField(ref _tryIntegrate, value, nameof(TryIntegrate)); - } - } + if (value) + WaitForExit = false; + SetField(ref _tryIntegrate, value, nameof(TryIntegrate)); + } + } - public bool ShowOnToolbar - { - get { return _showOnToolbar; } - set { SetField(ref _showOnToolbar, value, nameof(ShowOnToolbar)); } - } + public bool ShowOnToolbar + { + get { return _showOnToolbar; } + set { SetField(ref _showOnToolbar, value, nameof(ShowOnToolbar)); } + } - public bool RunElevated - { - get { return _runElevated; } - set { SetField(ref _runElevated, value, nameof(RunElevated)); } - } + public bool RunElevated + { + get { return _runElevated; } + set { SetField(ref _runElevated, value, nameof(RunElevated)); } + } + + public ConnectionInfo ConnectionInfo { get; set; } - public ConnectionInfo ConnectionInfo { get; set; } - public Icon Icon { get { return File.Exists(FileName) ? MiscTools.GetIconFromFile(FileName) : Resources.mRemoteNG_Icon; } } - public Image Image - { - get { return Icon?.ToBitmap() ?? Resources.mRemoteNG_Icon.ToBitmap(); } - } + public Image Image + { + get { return Icon?.ToBitmap() ?? Resources.mRemoteNG_Icon.ToBitmap(); } + } - #endregion - - public ExternalTool(string displayName = "", string fileName = "", string arguments = "", string workingDir = "", bool runElevated = false) - { - DisplayName = displayName; - FileName = fileName; - Arguments = arguments; + #endregion + + public ExternalTool(string displayName = "", + string fileName = "", + string arguments = "", + string workingDir = "", + bool runElevated = false) + { + DisplayName = displayName; + FileName = fileName; + Arguments = arguments; WorkingDir = workingDir; RunElevated = runElevated; - } + } public void Start(ConnectionInfo startConnectionInfo = null) - { - try - { - if (string.IsNullOrEmpty(FileName)) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ExternalApp.Start() failed: FileName cannot be blank."); - return; - } - - ConnectionInfo = startConnectionInfo; - - if (TryIntegrate) - StartIntegrated(); + { + try + { + if (string.IsNullOrEmpty(FileName)) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "ExternalApp.Start() failed: FileName cannot be blank."); + return; + } + + ConnectionInfo = startConnectionInfo; + + if (TryIntegrate) + StartIntegrated(); else StartExternalProcess(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("ExternalApp.Start() failed.", ex); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("ExternalApp.Start() failed.", ex); + } + } private void StartExternalProcess() { @@ -155,17 +161,17 @@ namespace mRemoteNG.Tools } private void StartIntegrated() - { - try - { + { + try + { var newConnectionInfo = BuildConnectionInfoForIntegratedApp(); _connectionInitiator.OpenConnection(newConnectionInfo); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("ExternalApp.StartIntegrated() failed.", ex); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("ExternalApp.StartIntegrated() failed.", ex); + } + } private ConnectionInfo BuildConnectionInfoForIntegratedApp() { @@ -180,7 +186,7 @@ namespace mRemoteNG.Tools return newConnectionInfo; } - private void SetConnectionInfoFields(ConnectionInfo newConnectionInfo) + private void SetConnectionInfoFields(ConnectionInfo newConnectionInfo) { newConnectionInfo.Protocol = ProtocolType.IntApp; newConnectionInfo.ExtApp = DisplayName; @@ -188,19 +194,19 @@ namespace mRemoteNG.Tools newConnectionInfo.Panel = Language.strMenuExternalTools; } - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler PropertyChanged; - protected virtual void RaisePropertyChangedEvent(object sender, string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } + protected virtual void RaisePropertyChangedEvent(object sender, string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } - protected bool SetField(ref T field, T value, string propertyName) - { - if (EqualityComparer.Default.Equals(field, value)) return false; - field = value; - RaisePropertyChangedEvent(this, propertyName); - return true; - } + protected bool SetField(ref T field, T value, string propertyName) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + RaisePropertyChangedEvent(this, propertyName); + return true; + } } } \ No newline at end of file diff --git a/mRemoteV1/Tools/ExternalToolArgumentParser.cs b/mRemoteV1/Tools/ExternalToolArgumentParser.cs index edbb1d2b3..a5e7b1672 100644 --- a/mRemoteV1/Tools/ExternalToolArgumentParser.cs +++ b/mRemoteV1/Tools/ExternalToolArgumentParser.cs @@ -7,7 +7,7 @@ using mRemoteNG.Tools.Cmdline; namespace mRemoteNG.Tools { - public class ExternalToolArgumentParser + public class ExternalToolArgumentParser { private readonly ConnectionInfo _connectionInfo; @@ -116,7 +116,9 @@ namespace mRemoteNG.Tools if (haveReplacement) { - var trailing = tokenEnd + 2 <= input.Length ? input.Substring(tokenEnd + 1, 1).ToCharArray()[0] : '\0'; + var trailing = tokenEnd + 2 <= input.Length + ? input.Substring(tokenEnd + 1, 1).ToCharArray()[0] + : '\0'; if (escape == EscapeType.All) { @@ -136,6 +138,7 @@ namespace mRemoteNG.Tools index = tokenEnd; } } while (true); + return replacements; } @@ -152,6 +155,7 @@ namespace mRemoteNG.Tools escape = EscapeType.None; break; } + return escape; } @@ -182,8 +186,8 @@ namespace mRemoteNG.Tools replacement = _connectionInfo.Password; if (string.IsNullOrEmpty(replacement) && Settings.Default.EmptyCredentials == "custom") replacement = new LegacyRijndaelCryptographyProvider() - .Decrypt(Convert.ToString(Settings.Default.DefaultPassword), - Runtime.EncryptionKey); + .Decrypt(Convert.ToString(Settings.Default.DefaultPassword), + Runtime.EncryptionKey); break; case "domain": replacement = _connectionInfo.Domain; @@ -205,6 +209,7 @@ namespace mRemoteNG.Tools default: return original; } + return replacement; } @@ -227,6 +232,7 @@ namespace mRemoteNG.Tools result = before + replacement.Value + after; } } + return result; } diff --git a/mRemoteV1/Tools/ExternalToolsService.cs b/mRemoteV1/Tools/ExternalToolsService.cs index a091f6de8..5957da98c 100644 --- a/mRemoteV1/Tools/ExternalToolsService.cs +++ b/mRemoteV1/Tools/ExternalToolsService.cs @@ -5,7 +5,8 @@ namespace mRemoteNG.Tools { public class ExternalToolsService { - public FullyObservableCollection ExternalTools { get; set; } = new FullyObservableCollection(); + public FullyObservableCollection ExternalTools { get; set; } = + new FullyObservableCollection(); public ExternalTool GetExtAppByName(string name) { diff --git a/mRemoteV1/Tools/ExternalToolsTypeConverter.cs b/mRemoteV1/Tools/ExternalToolsTypeConverter.cs index f409c9182..4b1378e8d 100644 --- a/mRemoteV1/Tools/ExternalToolsTypeConverter.cs +++ b/mRemoteV1/Tools/ExternalToolsTypeConverter.cs @@ -38,4 +38,4 @@ namespace mRemoteNG.Tools return true; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/IeBrowserEmulation.cs b/mRemoteV1/Tools/IeBrowserEmulation.cs index ad6c85ca5..c374626b4 100644 --- a/mRemoteV1/Tools/IeBrowserEmulation.cs +++ b/mRemoteV1/Tools/IeBrowserEmulation.cs @@ -8,24 +8,31 @@ using mRemoteNG.App; namespace mRemoteNG.Tools { - public class IeBrowserEmulation + public class IeBrowserEmulation { // found this here: // http://www.neowin.net/forum/topic/1077469-vbnet-webbrowser-control-does-not-load-javascript/#comment-596755046 private static void SetBrowserFeatureControlKey(string feature, string appName, uint value) { - if (Environment.Is64BitOperatingSystem) { - using (var key = Registry.CurrentUser.CreateSubKey(string.Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var key = Registry.CurrentUser.CreateSubKey( + string + .Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", + feature), + RegistryKeyPermissionCheck.ReadWriteSubTree)) { key?.SetValue(appName, value, RegistryValueKind.DWord); } } - using (var key = Registry.CurrentUser.CreateSubKey(string.Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var key = Registry.CurrentUser.CreateSubKey( + string + .Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", + feature), + RegistryKeyPermissionCheck.ReadWriteSubTree)) { key?.SetValue(appName, value, RegistryValueKind.DWord); } @@ -34,10 +41,13 @@ namespace mRemoteNG.Tools #if PORTABLE private static void DeleteBrowserFeatureControlKey(string feature, string appName) { - if (Environment.Is64BitOperatingSystem) { - using (var key = Registry.CurrentUser.OpenSubKey(string.Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var key = Registry.CurrentUser.OpenSubKey( + string + .Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", + feature), + RegistryKeyPermissionCheck.ReadWriteSubTree)) { if (key?.GetValueNames().Contains(appName) ?? false) key.DeleteValue(appName); @@ -45,7 +55,11 @@ namespace mRemoteNG.Tools } - using (var key = Registry.CurrentUser.CreateSubKey(string.Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var key = Registry.CurrentUser.CreateSubKey( + string + .Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", + feature), + RegistryKeyPermissionCheck.ReadWriteSubTree)) { if (key?.GetValueNames().Contains(appName) ?? false) key.DeleteValue(appName); @@ -61,7 +75,8 @@ namespace mRemoteNG.Tools var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName); // make sure the control is not running inside Visual Studio Designer - if (string.Compare(fileName, "devenv.exe", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(fileName, "XDesProc.exe", StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(fileName, "devenv.exe", StringComparison.OrdinalIgnoreCase) == 0 || + string.Compare(fileName, "XDesProc.exe", StringComparison.OrdinalIgnoreCase) == 0) { return; } @@ -102,7 +117,8 @@ namespace mRemoteNG.Tools var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName); // make sure the control is not running inside Visual Studio Designer - if (string.Compare(fileName, "devenv.exe", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(fileName, "XDesProc.exe", StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(fileName, "devenv.exe", StringComparison.OrdinalIgnoreCase) == 0 || + string.Compare(fileName, "XDesProc.exe", StringComparison.OrdinalIgnoreCase) == 0) { return; } @@ -142,7 +158,9 @@ namespace mRemoteNG.Tools var browserVersion = 9; // default to IE9. - using (var ieKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Internet Explorer", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.QueryValues)) + using (var ieKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Internet Explorer", + RegistryKeyPermissionCheck.ReadSubTree, + RegistryRights.QueryValues)) { if (ieKey != null) { @@ -155,6 +173,7 @@ namespace mRemoteNG.Tools throw new ApplicationException("Microsoft Internet Explorer is required!"); } } + int.TryParse(version.ToString().Split('.')[0], out browserVersion); } } diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index fc11aeb63..57d31df91 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -14,85 +14,93 @@ using static System.String; namespace mRemoteNG.Tools { public static class MiscTools - { - public static Icon GetIconFromFile(string FileName) - { - try - { - return File.Exists(FileName) == false ? null : Icon.ExtractAssociatedIcon(FileName); - } - catch (ArgumentException AEx) - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, - "GetIconFromFile failed (Tools.Misc) - using default icon" + Environment.NewLine + AEx.Message, true); + { + public static Icon GetIconFromFile(string FileName) + { + try + { + return File.Exists(FileName) == false ? null : Icon.ExtractAssociatedIcon(FileName); + } + catch (ArgumentException AEx) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "GetIconFromFile failed (Tools.Misc) - using default icon" + + Environment.NewLine + AEx.Message, + true); return Resources.mRemoteNG_Icon; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "GetIconFromFile failed (Tools.Misc)" + Environment.NewLine + + ex.Message, true); + return null; + } + } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "GetIconFromFile failed (Tools.Misc)" + Environment.NewLine + ex.Message, true); - return null; - } - } - - public static Optional PasswordDialog(string passwordName = null, bool verify = true) - { - var passwordForm = new PasswordForm(passwordName, verify); - return passwordForm.GetKey(); - } - + public static Optional PasswordDialog(string passwordName = null, bool verify = true) + { + var passwordForm = new PasswordForm(passwordName, verify); + return passwordForm.GetKey(); + } - public static string CreateConstantID() - { - return Guid.NewGuid().ToString(); - } - - public static string LeadingZero(string Number) - { - if (Convert.ToInt32(Number) < 10) - { - return "0" + Number; - } - return Number; - } + public static string CreateConstantID() + { + return Guid.NewGuid().ToString(); + } + + + public static string LeadingZero(string Number) + { + if (Convert.ToInt32(Number) < 10) + { + return "0" + Number; + } + + return Number; + } public static string DBDate(DateTime Dt) - { - var strDate = Dt.Year + LeadingZero(Convert.ToString(Dt.Month)) + LeadingZero(Convert.ToString(Dt.Day)) + " " + LeadingZero(Convert.ToString(Dt.Hour)) + ":" + LeadingZero(Convert.ToString(Dt.Minute)) + ":" + LeadingZero(Convert.ToString(Dt.Second)); - return strDate; - } + { + var strDate = Dt.Year + LeadingZero(Convert.ToString(Dt.Month)) + LeadingZero(Convert.ToString(Dt.Day)) + + " " + LeadingZero(Convert.ToString(Dt.Hour)) + ":" + + LeadingZero(Convert.ToString(Dt.Minute)) + ":" + LeadingZero(Convert.ToString(Dt.Second)); + return strDate; + } - public static string PrepareValueForDB(string Text) - { - return Text.Replace("\'", "\'\'"); - } + public static string PrepareValueForDB(string Text) + { + return Text.Replace("\'", "\'\'"); + } public static string GetExceptionMessageRecursive(Exception ex) { return GetExceptionMessageRecursive(ex, Environment.NewLine); } - private static string GetExceptionMessageRecursive(Exception ex, string separator) - { - var message = ex.Message; - if (ex.InnerException == null) return message; - var innerMessage = GetExceptionMessageRecursive(ex.InnerException, separator); - message = Join(separator, message, innerMessage); - return message; - } - - public static Image TakeScreenshot(UI.Tabs.ConnectionTab sender) + private static string GetExceptionMessageRecursive(Exception ex, string separator) + { + var message = ex.Message; + if (ex.InnerException == null) return message; + var innerMessage = GetExceptionMessageRecursive(ex.InnerException, separator); + message = Join(separator, message, innerMessage); + return message; + } + + + public static Image TakeScreenshot(UI.Tabs.ConnectionTab sender) { try - { + { if (sender != null) { - var bmp = new Bitmap(sender.Width, sender.Height, PixelFormat.Format32bppRgb); - Graphics g = Graphics.FromImage(bmp); - g.CopyFromScreen(sender.PointToScreen(Point.Empty), Point.Empty , bmp.Size, CopyPixelOperation.SourceCopy); + var bmp = new Bitmap(sender.Width, sender.Height, PixelFormat.Format32bppRgb); + Graphics g = Graphics.FromImage(bmp); + g.CopyFromScreen(sender.PointToScreen(Point.Empty), Point.Empty, bmp.Size, + CopyPixelOperation.SourceCopy); return bmp; } } @@ -103,103 +111,108 @@ namespace mRemoteNG.Tools return null; } - - public class EnumTypeConverter : EnumConverter - { - private readonly Type _enumType; - - public EnumTypeConverter(Type type) : base(type) - { - _enumType = type; - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) - { - return destType == typeof(string); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType) - { - if (value == null) return null; - var fi = _enumType.GetField(Enum.GetName(_enumType, value)); - var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); - - return dna != null ? dna.Description : value.ToString(); - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType) - { - return srcType == typeof(string); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - foreach (var fi in _enumType.GetFields()) - { - var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); - - if (dna != null && (string) value == dna.Description) - { - return Enum.Parse(_enumType, fi.Name); - } - } - return value != null ? Enum.Parse(_enumType, (string) value) : null; - } - } - - public class YesNoTypeConverter : TypeConverter - { - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (!(value is string)) return base.ConvertFrom(context, culture, value); - if (string.Equals(value.ToString(), Language.strYes, StringComparison.CurrentCultureIgnoreCase)) - { - return true; - } - - if (string.Equals(value.ToString(), Language.strNo, StringComparison.CurrentCultureIgnoreCase)) - { - return false; - } - - throw new Exception("Values must be \"Yes\" or \"No\""); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - return Convert.ToBoolean(value) ? Language.strYes : Language.strNo; - } - - return base.ConvertTo(context, culture, value, destinationType); - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) - { - return true; - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) - { - bool[] bools = {true, false}; - - var svc = new StandardValuesCollection(bools); - - return svc; - } - } - } + public class EnumTypeConverter : EnumConverter + { + private readonly Type _enumType; + + public EnumTypeConverter(Type type) : base(type) + { + _enumType = type; + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) + { + return destType == typeof(string); + } + + public override object ConvertTo(ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destType) + { + if (value == null) return null; + var fi = _enumType.GetField(Enum.GetName(_enumType, value)); + var dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); + + return dna != null ? dna.Description : value.ToString(); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType) + { + return srcType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + foreach (var fi in _enumType.GetFields()) + { + var dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); + + if (dna != null && (string)value == dna.Description) + { + return Enum.Parse(_enumType, fi.Name); + } + } + + return value != null ? Enum.Parse(_enumType, (string)value) : null; + } + } + + public class YesNoTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (!(value is string)) return base.ConvertFrom(context, culture, value); + if (string.Equals(value.ToString(), Language.strYes, StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + + if (string.Equals(value.ToString(), Language.strNo, StringComparison.CurrentCultureIgnoreCase)) + { + return false; + } + + throw new Exception("Values must be \"Yes\" or \"No\""); + } + + public override object ConvertTo(ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destinationType) + { + if (destinationType == typeof(string)) + { + return Convert.ToBoolean(value) ? Language.strYes : Language.strNo; + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) + { + bool[] bools = {true, false}; + + var svc = new StandardValuesCollection(bools); + + return svc; + } + } + } } \ No newline at end of file diff --git a/mRemoteV1/Tools/MouseClickSimulator.cs b/mRemoteV1/Tools/MouseClickSimulator.cs index f39dccd92..d0b702269 100644 --- a/mRemoteV1/Tools/MouseClickSimulator.cs +++ b/mRemoteV1/Tools/MouseClickSimulator.cs @@ -13,7 +13,9 @@ namespace mRemoteNG.Tools var clientMousePosition = controlToClick.PointToClient(currentMousePosition); var tempWLow = clientMousePosition.X; var tempWHigh = clientMousePosition.Y; - NativeMethods.SendMessage(controlToClick.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, (IntPtr)NativeMethods.MAKELPARAM(ref tempWLow, ref tempWHigh)); + NativeMethods.SendMessage(controlToClick.Handle, NativeMethods.WM_LBUTTONDOWN, + (IntPtr)NativeMethods.MK_LBUTTON, + (IntPtr)NativeMethods.MAKELPARAM(ref tempWLow, ref tempWHigh)); clientMousePosition.X = tempWLow; clientMousePosition.Y = tempWHigh; controlToClick.Focus(); diff --git a/mRemoteV1/Tools/MultiSSHController.cs b/mRemoteV1/Tools/MultiSSHController.cs index ffc14cdbc..d2dc91b8c 100644 --- a/mRemoteV1/Tools/MultiSSHController.cs +++ b/mRemoteV1/Tools/MultiSSHController.cs @@ -8,7 +8,7 @@ using mRemoteNG.Connection.Protocol; namespace mRemoteNG.Tools { - public class MultiSSHController + public class MultiSSHController { private readonly ArrayList processHandlers = new ArrayList(); private readonly ArrayList quickConnectConnections = new ArrayList(); @@ -60,13 +60,15 @@ namespace mRemoteNG.Tools { return; } + foreach (PuttyBase proc in processHandlers) { NativeMethods.PostMessage(proc.PuttyHandle, keyType, new IntPtr(keyData), new IntPtr(0)); } } -#region Event Processors + #region Event Processors + private void refreshActiveConnections(object sender, EventArgs e) { processHandlers.Clear(); @@ -75,7 +77,8 @@ namespace mRemoteNG.Tools processHandlers.AddRange(ProcessOpenConnections(connection)); } - var connectionTreeConnections = Runtime.ConnectionsService.ConnectionTreeModel.GetRecursiveChildList().Where(item => item.OpenConnections.Count > 0); + var connectionTreeConnections = Runtime.ConnectionsService.ConnectionTreeModel.GetRecursiveChildList() + .Where(item => item.OpenConnections.Count > 0); foreach (var connection in connectionTreeConnections) { @@ -85,7 +88,7 @@ namespace mRemoteNG.Tools private void processKeyPress(object sender, KeyEventArgs e) { - if (!(sender is TextBox txtMultiSSH)) return; + if (!(sender is TextBox txtMultiSSH)) return; if (processHandlers.Count == 0) { @@ -121,6 +124,7 @@ namespace mRemoteNG.Tools { SendAllKeystrokes(NativeMethods.WM_CHAR, Convert.ToByte(chr1)); } + SendAllKeystrokes(NativeMethods.WM_KEYDOWN, 13); // Enter = char13 } @@ -133,6 +137,7 @@ namespace mRemoteNG.Tools { previousCommands.Add(txtMultiSSH.Text.Trim()); } + if (previousCommands.Count >= CommandHistoryLength) { previousCommands.RemoveAt(0); @@ -141,6 +146,7 @@ namespace mRemoteNG.Tools previousCommandIndex = previousCommands.Count - 1; txtMultiSSH.Clear(); } -#endregion + + #endregion } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/NotificationAreaIcon.cs b/mRemoteV1/Tools/NotificationAreaIcon.cs index d9d9b6e90..165ce4aa1 100644 --- a/mRemoteV1/Tools/NotificationAreaIcon.cs +++ b/mRemoteV1/Tools/NotificationAreaIcon.cs @@ -37,7 +37,7 @@ namespace mRemoteNG.Tools _cMen = new ContextMenuStrip { Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, - System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)), + System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)), RenderMode = ToolStripRenderMode.Professional }; _cMen.Items.AddRange(new ToolStripItem[] {_cMenCons, cMenSep1, cMenExit}); @@ -85,7 +85,9 @@ namespace mRemoteNG.Tools }; // ReSharper disable once CoVariantArrayConversion - ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionsService.ConnectionTreeModel).ToArray(); + ToolStripItem[] rootMenuItems = menuItemsConverter + .CreateToolStripDropDownItems(Runtime.ConnectionsService + .ConnectionTreeModel).ToArray(); _cMenCons.DropDownItems.AddRange(rootMenuItems); } @@ -119,7 +121,7 @@ namespace mRemoteNG.Tools if (((ToolStripMenuItem)sender).Tag is ContainerInfo) return; if (FrmMain.Visible == false) ShowForm(); - _connectionInitiator.OpenConnection((ConnectionInfo) ((ToolStripMenuItem) sender).Tag); + _connectionInitiator.OpenConnection((ConnectionInfo)((ToolStripMenuItem)sender).Tag); } private static void cMenExit_Click(object sender, EventArgs e) diff --git a/mRemoteV1/Tools/Optional.cs b/mRemoteV1/Tools/Optional.cs index dc1dc0c18..2d0c83eb6 100644 --- a/mRemoteV1/Tools/Optional.cs +++ b/mRemoteV1/Tools/Optional.cs @@ -12,26 +12,26 @@ namespace mRemoteNG.Tools /// The underlying type that may or may not have a value public class Optional : IEnumerable, IComparable> { - private readonly T[] _optional; + private readonly T[] _optional; /// /// Create a new empty instance of Optional /// - public Optional() - { - _optional = new T[0]; - } + public Optional() + { + _optional = new T[0]; + } /// /// Create a new instance of Optional from the given value. /// If the value is null, the Optional will be empty /// - public Optional(T value) - { - _optional = value != null - ? new[] {value} - : new T[0]; - } + public Optional(T value) + { + _optional = value != null + ? new[] {value} + : new T[0]; + } public override string ToString() { @@ -56,18 +56,21 @@ namespace mRemoteNG.Tools public static Optional Empty => new Optional(); #region IEnumerable - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - public IEnumerator GetEnumerator() - { - return ((IEnumerable)_optional).GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)_optional).GetEnumerator(); + } + #endregion #region IComparable + /// /// Compares this to another instance /// of the same type. For purposes of comparison, empty Optional @@ -95,58 +98,61 @@ namespace mRemoteNG.Tools return ((IComparable)_optional[0]).CompareTo(other.First()); throw new ArgumentException(string.Format( - "Cannot compare objects. Optional type {0} is not comparable to itself", - typeof(T).FullName)); + "Cannot compare objects. Optional type {0} is not comparable to itself", + typeof(T).FullName)); } + #endregion #region Override Equals and GetHashCode public override bool Equals(object obj) - { - if (ReferenceEquals(this, obj)) - return true; + { + if (ReferenceEquals(this, obj)) + return true; - var objAsOptional = obj as Optional; - if (objAsOptional != null) - return Equals(objAsOptional); + var objAsOptional = obj as Optional; + if (objAsOptional != null) + return Equals(objAsOptional); - if (obj is T) - Equals((T)obj); + if (obj is T) + Equals((T)obj); - return false; - } + return false; + } - public bool Equals(Optional other) - { - var otherObj = other.FirstOrDefault(); - var thisObj = _optional.FirstOrDefault(); - if (thisObj == null && otherObj == null) - return true; - if (thisObj == null) - return false; - return thisObj.Equals(otherObj); - } + public bool Equals(Optional other) + { + var otherObj = other.FirstOrDefault(); + var thisObj = _optional.FirstOrDefault(); + if (thisObj == null && otherObj == null) + return true; + if (thisObj == null) + return false; + return thisObj.Equals(otherObj); + } - public override int GetHashCode() - { - return _optional != null - ? _optional.GetHashCode() - : 0; - } - #endregion + public override int GetHashCode() + { + return _optional != null + ? _optional.GetHashCode() + : 0; + } - #region Operators + #endregion - public static bool operator ==(Optional left, Optional right) - { - return Equals(left, right); - } + #region Operators - public static bool operator !=(Optional left, Optional right) - { - return !Equals(left, right); - } - #endregion - } -} + public static bool operator ==(Optional left, Optional right) + { + return Equals(left, right); + } + + public static bool operator !=(Optional left, Optional right) + { + return !Equals(left, right); + } + + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/PortScanner.cs b/mRemoteV1/Tools/PortScanner.cs index 3b213542f..212c426a3 100644 --- a/mRemoteV1/Tools/PortScanner.cs +++ b/mRemoteV1/Tools/PortScanner.cs @@ -11,36 +11,45 @@ using mRemoteNG.Messages; namespace mRemoteNG.Tools { - public class PortScanner - { - private readonly List _ipAddresses = new List(); - private readonly List _ports = new List(); - private Thread _scanThread; - private readonly List _scannedHosts = new List(); - private readonly int _timeoutInMilliseconds; + public class PortScanner + { + private readonly List _ipAddresses = new List(); + private readonly List _ports = new List(); + private Thread _scanThread; + private readonly List _scannedHosts = new List(); + private readonly int _timeoutInMilliseconds; #region Public Methods - public PortScanner(IPAddress ipAddress1, IPAddress ipAddress2, int port1, int port2, int timeoutInMilliseconds = 5000, bool checkDefaultPortsOnly = false) - { + public PortScanner(IPAddress ipAddress1, + IPAddress ipAddress2, + int port1, + int port2, + int timeoutInMilliseconds = 5000, + bool checkDefaultPortsOnly = false) + { var ipAddressStart = IpAddressMin(ipAddress1, ipAddress2); var ipAddressEnd = IpAddressMax(ipAddress1, ipAddress2); var portStart = Math.Min(port1, port2); - var portEnd = Math.Max(port1, port2); + var portEnd = Math.Max(port1, port2); // if only one port was specified, just scan the one port... if (portStart == 0) portStart = portEnd; - if (timeoutInMilliseconds < 0) - throw new ArgumentOutOfRangeException(nameof(timeoutInMilliseconds)); + if (timeoutInMilliseconds < 0) + throw new ArgumentOutOfRangeException(nameof(timeoutInMilliseconds)); - _timeoutInMilliseconds = timeoutInMilliseconds; - _ports.Clear(); + _timeoutInMilliseconds = timeoutInMilliseconds; + _ports.Clear(); if (checkDefaultPortsOnly) - _ports.AddRange(new[] { ScanHost.SshPort, ScanHost.TelnetPort, ScanHost.HttpPort, ScanHost.HttpsPort, ScanHost.RloginPort, ScanHost.RdpPort, ScanHost.VncPort }); + _ports.AddRange(new[] + { + ScanHost.SshPort, ScanHost.TelnetPort, ScanHost.HttpPort, ScanHost.HttpsPort, ScanHost.RloginPort, + ScanHost.RdpPort, ScanHost.VncPort + }); else { for (var port = portStart; port <= portEnd; port++) @@ -54,49 +63,54 @@ namespace mRemoteNG.Tools _scannedHosts.Clear(); } - - public void StartScan() - { - _scanThread = new Thread(ScanAsync); - _scanThread.SetApartmentState(ApartmentState.STA); - _scanThread.IsBackground = true; - _scanThread.Start(); - } - - public void StopScan() - { - foreach(var p in _pings) + + public void StartScan() + { + _scanThread = new Thread(ScanAsync); + _scanThread.SetApartmentState(ApartmentState.STA); + _scanThread.IsBackground = true; + _scanThread.Start(); + } + + public void StopScan() + { + foreach (var p in _pings) { p.SendAsyncCancel(); } - _scanThread.Abort(); + + _scanThread.Abort(); } - - public static bool IsPortOpen(string hostname, string port) - { - try - { - var tcpClient = new TcpClient(hostname, Convert.ToInt32(port)); - tcpClient.Close(); - return true; - } - catch (Exception) - { - return false; - } - } + + public static bool IsPortOpen(string hostname, string port) + { + try + { + var tcpClient = new TcpClient(hostname, Convert.ToInt32(port)); + tcpClient.Close(); + return true; + } + catch (Exception) + { + return false; + } + } + #endregion #region Private Methods private int _hostCount; private readonly List _pings = new List(); + private void ScanAsync() - { - try - { - _hostCount = 0; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Starting scan of {_ipAddresses.Count} hosts...", true); + { + try + { + _hostCount = 0; + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Tools.PortScan: Starting scan of {_ipAddresses.Count} hosts...", + true); foreach (var ipAddress in _ipAddresses) { RaiseBeginHostScanEvent(ipAddress); @@ -111,15 +125,19 @@ namespace mRemoteNG.Tools } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"Tools.PortScan: Ping failed for {ipAddress} {Environment.NewLine} {ex.Message}", true); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + $"Tools.PortScan: Ping failed for {ipAddress} {Environment.NewLine} {ex.Message}", + true); } } } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"StartScanBG failed (Tools.PortScan) {Environment.NewLine} {ex.Message}", true); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + $"StartScanBG failed (Tools.PortScan) {Environment.NewLine} {ex.Message}", + true); + } + } /* Some examples found here: * http://stackoverflow.com/questions/2114266/convert-ping-application-to-multithreaded-version-to-increase-speed-c-sharp @@ -134,12 +152,15 @@ namespace mRemoteNG.Tools var scanHost = new ScanHost(ip); _hostCount++; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Scanning {_hostCount} of {_ipAddresses.Count} hosts: {scanHost.HostIp}", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Tools.PortScan: Scanning {_hostCount} of {_ipAddresses.Count} hosts: {scanHost.HostIp}", + true); + - if (e.Cancelled) { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: CANCELLED host: {scanHost.HostIp}", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Tools.PortScan: CANCELLED host: {scanHost.HostIp}", true); // cleanup p.PingCompleted -= PingSender_PingCompleted; p.Dispose(); @@ -148,7 +169,9 @@ namespace mRemoteNG.Tools if (e.Error != null) { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Ping failed to {e.UserState} {Environment.NewLine} {e.Error.Message}", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Ping failed to {e.UserState} {Environment.NewLine} {e.Error.Message}", + true); scanHost.ClosedPorts.AddRange(_ports); scanHost.SetAllProtocols(false); } @@ -162,8 +185,8 @@ namespace mRemoteNG.Tools catch (Exception dnsex) { Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, - $"Tools.PortScan: Could not resolve {scanHost.HostIp} {Environment.NewLine} {dnsex.Message}", - true); + $"Tools.PortScan: Could not resolve {scanHost.HostIp} {Environment.NewLine} {dnsex.Message}", + true); } if (string.IsNullOrEmpty(scanHost.HostName)) @@ -217,9 +240,10 @@ namespace mRemoteNG.Tools } } } - else if(e.Reply.Status != IPStatus.Success) + else if (e.Reply.Status != IPStatus.Success) { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Ping did not complete to {e.UserState} : {e.Reply.Status}", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Ping did not complete to {e.UserState} : {e.Reply.Status}", true); scanHost.ClosedPorts.AddRange(_ports); scanHost.SetAllProtocols(false); } @@ -229,7 +253,8 @@ namespace mRemoteNG.Tools p.Dispose(); var h = string.IsNullOrEmpty(scanHost.HostName) ? "HostNameNotFound" : scanHost.HostName; - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Scan of {scanHost.HostIp} ({h}) complete.", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Tools.PortScan: Scan of {scanHost.HostIp} ({h}) complete.", true); _scannedHosts.Add(scanHost); RaiseHostScannedEvent(scanHost, _hostCount, _ipAddresses.Count); @@ -237,93 +262,104 @@ namespace mRemoteNG.Tools if (_scannedHosts.Count == _ipAddresses.Count) RaiseScanCompleteEvent(_scannedHosts); } - - private static IEnumerable IpAddressArrayFromRange(IPAddress ipAddress1, IPAddress ipAddress2) - { - var startIpAddress = IpAddressMin(ipAddress1, ipAddress2); - var endIpAddress = IpAddressMax(ipAddress1, ipAddress2); - - var startAddress = IpAddressToInt32(startIpAddress); - var endAddress = IpAddressToInt32(endIpAddress); - var addressCount = endAddress - startAddress; - - var addressArray = new IPAddress[addressCount + 1]; - var index = 0; - for (var address = startAddress; address <= endAddress; address++) - { - addressArray[index] = IpAddressFromInt32(address); - index++; - } - - return addressArray; - } - - private static IPAddress IpAddressMin(IPAddress ipAddress1, IPAddress ipAddress2) - { - return IpAddressCompare(ipAddress1, ipAddress2) < 0 ? ipAddress1 : ipAddress2; - } - private static IPAddress IpAddressMax(IPAddress ipAddress1, IPAddress ipAddress2) - { - return IpAddressCompare(ipAddress1, ipAddress2) > 0 ? ipAddress1 : ipAddress2; - } + private static IEnumerable IpAddressArrayFromRange(IPAddress ipAddress1, IPAddress ipAddress2) + { + var startIpAddress = IpAddressMin(ipAddress1, ipAddress2); + var endIpAddress = IpAddressMax(ipAddress1, ipAddress2); - private static int IpAddressCompare(IPAddress ipAddress1, IPAddress ipAddress2) - { - return IpAddressToInt32(ipAddress1) - IpAddressToInt32(ipAddress2); - } - - private static int IpAddressToInt32(IPAddress ipAddress) - { - if (ipAddress.AddressFamily != AddressFamily.InterNetwork) - { - throw (new ArgumentException("ipAddress")); - } - - var addressBytes = ipAddress.GetAddressBytes(); // in network order (big-endian) - if (BitConverter.IsLittleEndian) - { - Array.Reverse(addressBytes); // to host order (little-endian) - } - Debug.Assert(addressBytes.Length == 4); - - return BitConverter.ToInt32(addressBytes, 0); - } - - private static IPAddress IpAddressFromInt32(int ipAddress) - { - var addressBytes = BitConverter.GetBytes(ipAddress); // in host order - if (BitConverter.IsLittleEndian) - { - Array.Reverse(addressBytes); // to network order (big-endian) - } - Debug.Assert(addressBytes.Length == 4); + var startAddress = IpAddressToInt32(startIpAddress); + var endAddress = IpAddressToInt32(endIpAddress); + var addressCount = endAddress - startAddress; + + var addressArray = new IPAddress[addressCount + 1]; + var index = 0; + for (var address = startAddress; address <= endAddress; address++) + { + addressArray[index] = IpAddressFromInt32(address); + index++; + } + + return addressArray; + } + + private static IPAddress IpAddressMin(IPAddress ipAddress1, IPAddress ipAddress2) + { + return IpAddressCompare(ipAddress1, ipAddress2) < 0 ? ipAddress1 : ipAddress2; + } + + private static IPAddress IpAddressMax(IPAddress ipAddress1, IPAddress ipAddress2) + { + return IpAddressCompare(ipAddress1, ipAddress2) > 0 ? ipAddress1 : ipAddress2; + } + + private static int IpAddressCompare(IPAddress ipAddress1, IPAddress ipAddress2) + { + return IpAddressToInt32(ipAddress1) - IpAddressToInt32(ipAddress2); + } + + private static int IpAddressToInt32(IPAddress ipAddress) + { + if (ipAddress.AddressFamily != AddressFamily.InterNetwork) + { + throw (new ArgumentException("ipAddress")); + } + + var addressBytes = ipAddress.GetAddressBytes(); // in network order (big-endian) + if (BitConverter.IsLittleEndian) + { + Array.Reverse(addressBytes); // to host order (little-endian) + } + + Debug.Assert(addressBytes.Length == 4); + + return BitConverter.ToInt32(addressBytes, 0); + } + + private static IPAddress IpAddressFromInt32(int ipAddress) + { + var addressBytes = BitConverter.GetBytes(ipAddress); // in host order + if (BitConverter.IsLittleEndian) + { + Array.Reverse(addressBytes); // to network order (big-endian) + } + + Debug.Assert(addressBytes.Length == 4); return new IPAddress(addressBytes); - } + } + #endregion - + #region Events - public delegate void BeginHostScanEventHandler(string host); - public event BeginHostScanEventHandler BeginHostScan; + + public delegate void BeginHostScanEventHandler(string host); + + public event BeginHostScanEventHandler BeginHostScan; + private void RaiseBeginHostScanEvent(IPAddress ipAddress) { BeginHostScan?.Invoke(ipAddress.ToString()); } public delegate void HostScannedEventHandler(ScanHost scanHost, int scannedHostCount, int totalHostCount); - public event HostScannedEventHandler HostScanned; - private void RaiseHostScannedEvent(ScanHost scanHost, int scannedHostCount, int totalHostCount) - { + + public event HostScannedEventHandler HostScanned; + + private void RaiseHostScannedEvent(ScanHost scanHost, int scannedHostCount, int totalHostCount) + { HostScanned?.Invoke(scanHost, scannedHostCount, totalHostCount); } - - public delegate void ScanCompleteEventHandler(List hosts); - public event ScanCompleteEventHandler ScanComplete; - private void RaiseScanCompleteEvent(List hosts) - { + + public delegate void ScanCompleteEventHandler(List hosts); + + public event ScanCompleteEventHandler ScanComplete; + + private void RaiseScanCompleteEvent(List hosts) + { ScanComplete?.Invoke(hosts); } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/Tools/ProcessController.cs b/mRemoteV1/Tools/ProcessController.cs index cc8aec596..f0cc16633 100644 --- a/mRemoteV1/Tools/ProcessController.cs +++ b/mRemoteV1/Tools/ProcessController.cs @@ -7,152 +7,161 @@ using mRemoteNG.Tools.Cmdline; namespace mRemoteNG.Tools { - public class ProcessController - { + public class ProcessController + { #region Public Methods - public bool Start(string fileName, CommandLineArguments arguments = null) - { - Process.StartInfo.UseShellExecute = false; - Process.StartInfo.FileName = fileName; - if (arguments != null) - Process.StartInfo.Arguments = arguments.ToString(); - - if (!Process.Start()) - return false; - GetMainWindowHandle(); - - return true; - } - - public bool SetControlVisible(string className, string text, bool visible = true) - { - if (Process == null || Process.HasExited) - return false; - if (Handle == IntPtr.Zero) - return false; - - var controlHandle = GetControlHandle(className, text); - if (controlHandle == IntPtr.Zero) - return false; - var nCmdShow = visible ? NativeMethods.SW_SHOW : NativeMethods.SW_HIDE; + public bool Start(string fileName, CommandLineArguments arguments = null) + { + Process.StartInfo.UseShellExecute = false; + Process.StartInfo.FileName = fileName; + if (arguments != null) + Process.StartInfo.Arguments = arguments.ToString(); + + if (!Process.Start()) + return false; + GetMainWindowHandle(); + + return true; + } + + public bool SetControlVisible(string className, string text, bool visible = true) + { + if (Process == null || Process.HasExited) + return false; + if (Handle == IntPtr.Zero) + return false; + + var controlHandle = GetControlHandle(className, text); + if (controlHandle == IntPtr.Zero) + return false; + + var nCmdShow = visible ? NativeMethods.SW_SHOW : NativeMethods.SW_HIDE; NativeMethods.ShowWindow(controlHandle, (int)nCmdShow); - return true; - } - - public bool SetControlText(string className, string oldText, string newText) - { - if (Process == null || Process.HasExited || Handle == IntPtr.Zero) - return false; + return true; + } - var controlHandle = GetControlHandle(className, oldText); - if (controlHandle == IntPtr.Zero) - return false; - - var result = NativeMethods.SendMessage(controlHandle, NativeMethods.WM_SETTEXT, (IntPtr)0, new StringBuilder(newText)); - return result.ToInt32() == NativeMethods.TRUE; - } - - public bool SelectListBoxItem(string itemText) - { - if (Process == null || Process.HasExited || Handle == IntPtr.Zero) - return false; - - var listBoxHandle = GetControlHandle("ListBox"); - if (listBoxHandle == IntPtr.Zero) - return false; - - var result = NativeMethods.SendMessage(listBoxHandle, NativeMethods.LB_SELECTSTRING, (IntPtr)(-1), new StringBuilder(itemText)); - return result.ToInt32() != NativeMethods.LB_ERR; - } - - public bool ClickButton(string text) - { - if (Process == null || Process.HasExited || Handle == IntPtr.Zero) - return false; - - var buttonHandle = GetControlHandle("Button", text); - if (buttonHandle == IntPtr.Zero) - return false; + public bool SetControlText(string className, string oldText, string newText) + { + if (Process == null || Process.HasExited || Handle == IntPtr.Zero) + return false; + + var controlHandle = GetControlHandle(className, oldText); + if (controlHandle == IntPtr.Zero) + return false; + + var result = NativeMethods.SendMessage(controlHandle, NativeMethods.WM_SETTEXT, (IntPtr)0, + new StringBuilder(newText)); + return result.ToInt32() == NativeMethods.TRUE; + } + + public bool SelectListBoxItem(string itemText) + { + if (Process == null || Process.HasExited || Handle == IntPtr.Zero) + return false; + + var listBoxHandle = GetControlHandle("ListBox"); + if (listBoxHandle == IntPtr.Zero) + return false; + + var result = NativeMethods.SendMessage(listBoxHandle, NativeMethods.LB_SELECTSTRING, (IntPtr)(-1), + new StringBuilder(itemText)); + return result.ToInt32() != NativeMethods.LB_ERR; + } + + public bool ClickButton(string text) + { + if (Process == null || Process.HasExited || Handle == IntPtr.Zero) + return false; + + var buttonHandle = GetControlHandle("Button", text); + if (buttonHandle == IntPtr.Zero) + return false; var buttonControlId = NativeMethods.GetDlgCtrlID(buttonHandle); NativeMethods.SendMessage(Handle, NativeMethods.WM_COMMAND, (IntPtr)buttonControlId, buttonHandle); - - return true; - } - - public void WaitForExit() - { - if (Process == null || Process.HasExited) - return; - Process.WaitForExit(); - } -#endregion - + + return true; + } + + public void WaitForExit() + { + if (Process == null || Process.HasExited) + return; + Process.WaitForExit(); + } + + #endregion + #region Protected Fields - private readonly Process Process = new Process(); + private readonly Process Process = new Process(); private IntPtr Handle = IntPtr.Zero; private List Controls = new List(); + #endregion #region Protected Methods - // ReSharper disable once UnusedMethodReturnValue.Local + + // ReSharper disable once UnusedMethodReturnValue.Local private IntPtr GetMainWindowHandle() - { - if (Process == null || Process.HasExited) - return IntPtr.Zero; - - Process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); - - Handle = IntPtr.Zero; - var startTicks = Environment.TickCount; - while (Handle == IntPtr.Zero && Environment.TickCount < startTicks + (Settings.Default.MaxPuttyWaitTime * 1000)) - { - Process.Refresh(); - Handle = Process.MainWindowHandle; - if (Handle == IntPtr.Zero) - { - System.Threading.Thread.Sleep(0); - } - } - - return Handle; - } + { + if (Process == null || Process.HasExited) + return IntPtr.Zero; + + Process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); + + Handle = IntPtr.Zero; + var startTicks = Environment.TickCount; + while (Handle == IntPtr.Zero && + Environment.TickCount < startTicks + (Settings.Default.MaxPuttyWaitTime * 1000)) + { + Process.Refresh(); + Handle = Process.MainWindowHandle; + if (Handle == IntPtr.Zero) + { + System.Threading.Thread.Sleep(0); + } + } + + return Handle; + } private IntPtr GetControlHandle(string className, string text = "") - { - if (Process == null || Process.HasExited || Handle == IntPtr.Zero) - return IntPtr.Zero; - - if (Controls.Count == 0) - { + { + if (Process == null || Process.HasExited || Handle == IntPtr.Zero) + return IntPtr.Zero; + + if (Controls.Count == 0) + { var windowEnumerator = new EnumWindows(); Controls = windowEnumerator.EnumChildWindows(Handle); - } + } var stringBuilder = new StringBuilder(); - var controlHandle = IntPtr.Zero; - foreach (var control in Controls) - { - NativeMethods.GetClassName(control, stringBuilder, stringBuilder.Capacity); - if (stringBuilder.ToString() != className) continue; - if (string.IsNullOrEmpty(text)) - { - controlHandle = control; - break; - } - else - { - NativeMethods.SendMessage(control, NativeMethods.WM_GETTEXT, new IntPtr(stringBuilder.Capacity), stringBuilder); - if (stringBuilder.ToString() != text) continue; - controlHandle = control; - break; - } - } - - return controlHandle; - } + var controlHandle = IntPtr.Zero; + foreach (var control in Controls) + { + NativeMethods.GetClassName(control, stringBuilder, stringBuilder.Capacity); + if (stringBuilder.ToString() != className) continue; + if (string.IsNullOrEmpty(text)) + { + controlHandle = control; + break; + } + else + { + NativeMethods.SendMessage(control, NativeMethods.WM_GETTEXT, new IntPtr(stringBuilder.Capacity), + stringBuilder); + if (stringBuilder.ToString() != text) continue; + controlHandle = control; + break; + } + } + + return controlHandle; + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/PropertyGridCommandSite.cs b/mRemoteV1/Tools/PropertyGridCommandSite.cs index 828e1ac27..046253a79 100644 --- a/mRemoteV1/Tools/PropertyGridCommandSite.cs +++ b/mRemoteV1/Tools/PropertyGridCommandSite.cs @@ -2,168 +2,171 @@ using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Reflection; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Tools { - public class PropertyGridCommandSite : IMenuCommandService, ISite - { - private readonly object TheObject; - public PropertyGridCommandSite(object @object) - { - TheObject = @object; - } - - public DesignerVerbCollection Verbs - { - get - { - var objectVerbs = new DesignerVerbCollection(); - // ReSharper disable VBPossibleMistakenCallToGetType.2 - var methods = TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); - // ReSharper restore VBPossibleMistakenCallToGetType.2 - foreach (var method in methods) - { - var commandAttributes = method.GetCustomAttributes(typeof(CommandAttribute), true); - if (commandAttributes.Length == 0) - { - continue; - } - - var commandAttribute = (CommandAttribute) commandAttributes[0]; - if (!commandAttribute.Command) - { - continue; - } - - var displayName = method.Name; - var displayNameAttributes = method.GetCustomAttributes(typeof(DisplayNameAttribute), true); - if (displayNameAttributes.Length != 0) - { - var displayNameAttribute = (DisplayNameAttribute) displayNameAttributes[0]; - if (!string.IsNullOrEmpty(displayNameAttribute.DisplayName)) - { - displayName = displayNameAttribute.DisplayName; - } - } - objectVerbs.Add(new DesignerVerb(displayName, new EventHandler(VerbEventHandler))); - } - - return objectVerbs; - } - } - - private void VerbEventHandler(object sender, EventArgs e) - { - var verb = sender as DesignerVerb; - if (verb == null) - { - return; - } - // ReSharper disable VBPossibleMistakenCallToGetType.2 - var methods = TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); - // ReSharper restore VBPossibleMistakenCallToGetType.2 - foreach (var method in methods) - { - var commandAttributes = method.GetCustomAttributes(typeof(CommandAttribute), true); - if (commandAttributes.Length == 0) - { - continue; - } - - var commandAttribute = (CommandAttribute) commandAttributes[0]; - if (!commandAttribute.Command) - { - continue; - } - - var displayName = method.Name; - var displayNameAttributes = method.GetCustomAttributes(typeof(DisplayNameAttribute), true); - if (displayNameAttributes.Length != 0) - { - var displayNameAttribute = (DisplayNameAttribute) displayNameAttributes[0]; - if (!string.IsNullOrEmpty(displayNameAttribute.DisplayName)) - { - displayName = displayNameAttribute.DisplayName; - } - } + public class PropertyGridCommandSite : IMenuCommandService, ISite + { + private readonly object TheObject; + + public PropertyGridCommandSite(object @object) + { + TheObject = @object; + } + + public DesignerVerbCollection Verbs + { + get + { + var objectVerbs = new DesignerVerbCollection(); + // ReSharper disable VBPossibleMistakenCallToGetType.2 + var methods = TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); + // ReSharper restore VBPossibleMistakenCallToGetType.2 + foreach (var method in methods) + { + var commandAttributes = method.GetCustomAttributes(typeof(CommandAttribute), true); + if (commandAttributes.Length == 0) + { + continue; + } + + var commandAttribute = (CommandAttribute)commandAttributes[0]; + if (!commandAttribute.Command) + { + continue; + } + + var displayName = method.Name; + var displayNameAttributes = method.GetCustomAttributes(typeof(DisplayNameAttribute), true); + if (displayNameAttributes.Length != 0) + { + var displayNameAttribute = (DisplayNameAttribute)displayNameAttributes[0]; + if (!string.IsNullOrEmpty(displayNameAttribute.DisplayName)) + { + displayName = displayNameAttribute.DisplayName; + } + } + + objectVerbs.Add(new DesignerVerb(displayName, new EventHandler(VerbEventHandler))); + } + + return objectVerbs; + } + } + + private void VerbEventHandler(object sender, EventArgs e) + { + var verb = sender as DesignerVerb; + if (verb == null) + { + return; + } + + // ReSharper disable VBPossibleMistakenCallToGetType.2 + var methods = TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); + // ReSharper restore VBPossibleMistakenCallToGetType.2 + foreach (var method in methods) + { + var commandAttributes = method.GetCustomAttributes(typeof(CommandAttribute), true); + if (commandAttributes.Length == 0) + { + continue; + } + + var commandAttribute = (CommandAttribute)commandAttributes[0]; + if (!commandAttribute.Command) + { + continue; + } + + var displayName = method.Name; + var displayNameAttributes = method.GetCustomAttributes(typeof(DisplayNameAttribute), true); + if (displayNameAttributes.Length != 0) + { + var displayNameAttribute = (DisplayNameAttribute)displayNameAttributes[0]; + if (!string.IsNullOrEmpty(displayNameAttribute.DisplayName)) + { + displayName = displayNameAttribute.DisplayName; + } + } + + if (verb.Text != displayName) continue; + method.Invoke(TheObject, null); + return; + } + } + + public object GetService(Type serviceType) + { + return serviceType == typeof(IMenuCommandService) ? this : null; + } - if (verb.Text != displayName) continue; - method.Invoke(TheObject, null); - return; - } - } - - public object GetService(Type serviceType) - { - return serviceType == typeof(IMenuCommandService) ? this : null; - } - public IComponent Component - { - get { throw new NotSupportedException(); } - } - + { + get { throw new NotSupportedException(); } + } + public IContainer Container { get { return null; } } - public bool DesignMode - { - get { return true; } - } + public bool DesignMode + { + get { return true; } + } - public string Name - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public void AddCommand(MenuCommand command) - { - throw new NotSupportedException(); - } - - public void AddVerb(DesignerVerb verb) - { - throw new NotSupportedException(); - } - - public MenuCommand FindCommand(CommandID commandId) - { - throw new NotSupportedException(); - } - - public bool GlobalInvoke(CommandID commandId) - { - throw new NotSupportedException(); - } - - public void RemoveCommand(MenuCommand command) - { - throw new NotSupportedException(); - } - - public void RemoveVerb(DesignerVerb verb) - { - throw new NotSupportedException(); - } - - public void ShowContextMenu(CommandID menuId, int x, int y) - { - throw new NotSupportedException(); - } - - } - - public class CommandAttribute : Attribute - { - public bool Command { get; set; } + public string Name + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } - public CommandAttribute(bool isCommand = true) - { - Command = isCommand; - } - } -} + public void AddCommand(MenuCommand command) + { + throw new NotSupportedException(); + } + + public void AddVerb(DesignerVerb verb) + { + throw new NotSupportedException(); + } + + public MenuCommand FindCommand(CommandID commandId) + { + throw new NotSupportedException(); + } + + public bool GlobalInvoke(CommandID commandId) + { + throw new NotSupportedException(); + } + + public void RemoveCommand(MenuCommand command) + { + throw new NotSupportedException(); + } + + public void RemoveVerb(DesignerVerb verb) + { + throw new NotSupportedException(); + } + + public void ShowContextMenu(CommandID menuId, int x, int y) + { + throw new NotSupportedException(); + } + } + + public class CommandAttribute : Attribute + { + public bool Command { get; set; } + + public CommandAttribute(bool isCommand = true) + { + Command = isCommand; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/PuttyProcessController.cs b/mRemoteV1/Tools/PuttyProcessController.cs index c091e96c7..2497b8284 100644 --- a/mRemoteV1/Tools/PuttyProcessController.cs +++ b/mRemoteV1/Tools/PuttyProcessController.cs @@ -2,12 +2,14 @@ using mRemoteNG.Tools.Cmdline; namespace mRemoteNG.Tools { - public class PuttyProcessController : ProcessController - { - public bool Start(CommandLineArguments arguments = null) - { - var filename = Settings.Default.UseCustomPuttyPath ? Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath; - return Start(filename, arguments); - } - } -} + public class PuttyProcessController : ProcessController + { + public bool Start(CommandLineArguments arguments = null) + { + var filename = Settings.Default.UseCustomPuttyPath + ? Settings.Default.CustomPuttyPath + : App.Info.GeneralAppInfo.PuttyPath; + return Start(filename, arguments); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/PuttyTypeDetector.cs b/mRemoteV1/Tools/PuttyTypeDetector.cs index 73e85c3f1..37e173f3c 100644 --- a/mRemoteV1/Tools/PuttyTypeDetector.cs +++ b/mRemoteV1/Tools/PuttyTypeDetector.cs @@ -5,64 +5,84 @@ using System.IO; namespace mRemoteNG.Tools { - public class PuttyTypeDetector - { - public static PuttyType GetPuttyType() - { - return GetPuttyType(PuttyBase.PuttyPath); - } - - public static PuttyType GetPuttyType(string filename) - { - if (IsPuttyNg(filename)) - { - return PuttyType.PuttyNg; - } - if (IsKitty(filename)) - { - return PuttyType.Kitty; - } - if (IsXming(filename)) - { - return PuttyType.Xming; - } - - // Check this last - if (IsPutty(filename)) - { - return PuttyType.Putty; - } - - return PuttyType.Unknown; - } - - private static bool IsPutty(string filename) - { - return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTY")); - } + public class PuttyTypeDetector + { + public static PuttyType GetPuttyType() + { + return GetPuttyType(PuttyBase.PuttyPath); + } - private static bool IsPuttyNg(string filename) - { - return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTYNG")); - } + public static PuttyType GetPuttyType(string filename) + { + if (IsPuttyNg(filename)) + { + return PuttyType.PuttyNg; + } - private static bool IsKitty(string filename) - { - return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTY") && FileVersionInfo.GetVersionInfo(filename).Comments.Contains("KiTTY")); - } + if (IsKitty(filename)) + { + return PuttyType.Kitty; + } - private static bool IsXming(string filename) - { - return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTY") && FileVersionInfo.GetVersionInfo(filename).ProductVersion.Contains("Xming")); - } + if (IsXming(filename)) + { + return PuttyType.Xming; + } - public enum PuttyType - { - Unknown = 0, - Putty, - PuttyNg, - Kitty, - Xming - } - } -} + // Check this last + if (IsPutty(filename)) + { + return PuttyType.Putty; + } + + return PuttyType.Unknown; + } + + private static bool IsPutty(string filename) + { + return !string.IsNullOrEmpty(filename) && File.Exists(filename) && + Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTY")); + } + + private static bool IsPuttyNg(string filename) + { + return !string.IsNullOrEmpty(filename) && File.Exists(filename) && + Convert.ToBoolean(FileVersionInfo.GetVersionInfo(filename).InternalName.Contains("PuTTYNG")); + } + + private static bool IsKitty(string filename) + { + return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean( + FileVersionInfo + .GetVersionInfo(filename) + .InternalName + .Contains("PuTTY") && + FileVersionInfo + .GetVersionInfo(filename) + .Comments + .Contains("KiTTY")); + } + + private static bool IsXming(string filename) + { + return !string.IsNullOrEmpty(filename) && File.Exists(filename) && Convert.ToBoolean( + FileVersionInfo + .GetVersionInfo(filename) + .InternalName + .Contains("PuTTY") && + FileVersionInfo + .GetVersionInfo(filename) + .ProductVersion + .Contains("Xming")); + } + + public enum PuttyType + { + Unknown = 0, + Putty, + PuttyNg, + Kitty, + Xming + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/ReconnectGroup.cs b/mRemoteV1/Tools/ReconnectGroup.cs index d78361e24..6dd8436c6 100644 --- a/mRemoteV1/Tools/ReconnectGroup.cs +++ b/mRemoteV1/Tools/ReconnectGroup.cs @@ -3,127 +3,134 @@ using System.Drawing; namespace mRemoteNG.Tools { - public partial class ReconnectGroup - { - public ReconnectGroup() - { - InitializeComponent(); - } - private bool _ServerReady; + public partial class ReconnectGroup + { + public ReconnectGroup() + { + InitializeComponent(); + } + + private bool _ServerReady; + public bool ServerReady - { - get => _ServerReady; + { + get => _ServerReady; set - { - SetStatusImage(value ? Resources.HostStatus_On : Resources.HostStatus_Off); + { + SetStatusImage(value ? Resources.HostStatus_On : Resources.HostStatus_Off); - _ServerReady = value; - } - } - - private delegate void SetStatusImageCB(Image Img); - private void SetStatusImage(Image Img) - { - if (pbServerStatus.InvokeRequired) - { - var d = new SetStatusImageCB(SetStatusImage); - ParentForm?.Invoke(d, new object[] {Img}); - } - else - { - pbServerStatus.Image = Img; - } - } + _ServerReady = value; + } + } + + private delegate void SetStatusImageCB(Image Img); + + private void SetStatusImage(Image Img) + { + if (pbServerStatus.InvokeRequired) + { + var d = new SetStatusImageCB(SetStatusImage); + ParentForm?.Invoke(d, new object[] {Img}); + } + else + { + pbServerStatus.Image = Img; + } + } + + private void chkReconnectWhenReady_CheckedChanged(object sender, EventArgs e) + { + _ReconnectWhenReady = chkReconnectWhenReady.Checked; + } + + private bool _ReconnectWhenReady; - private void chkReconnectWhenReady_CheckedChanged(object sender, EventArgs e) - { - _ReconnectWhenReady = chkReconnectWhenReady.Checked; - } - - private bool _ReconnectWhenReady; public bool ReconnectWhenReady - { - get => _ReconnectWhenReady; + { + get => _ReconnectWhenReady; set - { - _ReconnectWhenReady = value; - SetCheckbox(value); - } - } - - private delegate void SetCheckboxCB(bool Val); - private void SetCheckbox(bool Val) - { - if (chkReconnectWhenReady.InvokeRequired) - { - var d = new SetCheckboxCB(SetCheckbox); - ParentForm?.Invoke(d, new object[] {Val}); - } - else - { - chkReconnectWhenReady.Checked = Val; - } - } - - public delegate void CloseClickedEventHandler(); - private CloseClickedEventHandler CloseClickedEvent; - - public event CloseClickedEventHandler CloseClicked - { - add => CloseClickedEvent = (CloseClickedEventHandler) Delegate.Combine(CloseClickedEvent, value); - remove => CloseClickedEvent = (CloseClickedEventHandler) Delegate.Remove(CloseClickedEvent, value); + { + _ReconnectWhenReady = value; + SetCheckbox(value); + } + } + + private delegate void SetCheckboxCB(bool Val); + + private void SetCheckbox(bool Val) + { + if (chkReconnectWhenReady.InvokeRequired) + { + var d = new SetCheckboxCB(SetCheckbox); + ParentForm?.Invoke(d, new object[] {Val}); + } + else + { + chkReconnectWhenReady.Checked = Val; + } + } + + public delegate void CloseClickedEventHandler(); + + private CloseClickedEventHandler CloseClickedEvent; + + public event CloseClickedEventHandler CloseClicked + { + add => CloseClickedEvent = (CloseClickedEventHandler)Delegate.Combine(CloseClickedEvent, value); + remove => CloseClickedEvent = (CloseClickedEventHandler)Delegate.Remove(CloseClickedEvent, value); } - private void btnClose_Click(object sender, EventArgs e) - { - CloseClickedEvent?.Invoke(); - } + private void btnClose_Click(object sender, EventArgs e) + { + CloseClickedEvent?.Invoke(); + } - private void tmrAnimation_Tick(object sender, EventArgs e) - { - switch (lblAnimation.Text) - { - case "": - lblAnimation.Text = "»"; - break; - case "»": - lblAnimation.Text = "»»"; - break; - case "»»": - lblAnimation.Text = "»»»"; - break; - case "»»»": - lblAnimation.Text = ""; - break; - } - } - - private delegate void DisposeReconnectGroupCB(); - public void DisposeReconnectGroup() - { - if (InvokeRequired) - { - var d = new DisposeReconnectGroupCB(DisposeReconnectGroup); - ParentForm?.Invoke(d); - } - else - { - Dispose(); - } - } - - public void ReconnectGroup_Load(object sender, EventArgs e) - { - ApplyLanguage(); - } - - private void ApplyLanguage() - { - grpAutomaticReconnect.Text = Language.strGroupboxAutomaticReconnect; - btnClose.Text = Language.strButtonClose; - lblServerStatus.Text = Language.strLabelServerStatus; - chkReconnectWhenReady.Text = Language.strCheckboxReconnectWhenReady; - } - } + private void tmrAnimation_Tick(object sender, EventArgs e) + { + switch (lblAnimation.Text) + { + case "": + lblAnimation.Text = "»"; + break; + case "»": + lblAnimation.Text = "»»"; + break; + case "»»": + lblAnimation.Text = "»»»"; + break; + case "»»»": + lblAnimation.Text = ""; + break; + } + } + + private delegate void DisposeReconnectGroupCB(); + + public void DisposeReconnectGroup() + { + if (InvokeRequired) + { + var d = new DisposeReconnectGroupCB(DisposeReconnectGroup); + ParentForm?.Invoke(d); + } + else + { + Dispose(); + } + } + + public void ReconnectGroup_Load(object sender, EventArgs e) + { + ApplyLanguage(); + } + + private void ApplyLanguage() + { + grpAutomaticReconnect.Text = Language.strGroupboxAutomaticReconnect; + btnClose.Text = Language.strButtonClose; + lblServerStatus.Text = Language.strLabelServerStatus; + chkReconnectWhenReady.Text = Language.strCheckboxReconnectWhenReady; + } + } } \ No newline at end of file diff --git a/mRemoteV1/Tools/ScanHost.cs b/mRemoteV1/Tools/ScanHost.cs index d7c4fa67b..6bf15fde2 100644 --- a/mRemoteV1/Tools/ScanHost.cs +++ b/mRemoteV1/Tools/ScanHost.cs @@ -15,6 +15,7 @@ namespace mRemoteNG.Tools public class ScanHost { #region Properties + public static int SshPort { get; set; } = (int)ProtocolSSH1.Defaults.Port; public static int TelnetPort { get; set; } = (int)ProtocolTelnet.Defaults.Port; public static int HttpPort { get; set; } = (int)ProtocolHTTP.Defaults.Port; @@ -33,6 +34,7 @@ namespace mRemoteNG.Tools public bool Https { get; set; } public string HostIp { get; set; } public string HostName { get; set; } = ""; + public string HostNameWithoutDomain { get @@ -41,12 +43,15 @@ namespace mRemoteNG.Tools { return HostIp; } + return HostName.Split('.')[0]; } } + #endregion #region Methods + public ScanHost(string host) { HostIp = host; @@ -58,14 +63,16 @@ namespace mRemoteNG.Tools { try { - return "SSH: " + Convert.ToString(Ssh) + " Telnet: " + Convert.ToString(Telnet) + " HTTP: " + Convert.ToString(Http) + " HTTPS: " + Convert.ToString(Https) + " Rlogin: " + Convert.ToString(Rlogin) + " RDP: " + Convert.ToString(Rdp) + " VNC: " + Convert.ToString(Vnc); + return "SSH: " + Convert.ToString(Ssh) + " Telnet: " + Convert.ToString(Telnet) + " HTTP: " + + Convert.ToString(Http) + " HTTPS: " + Convert.ToString(Https) + " Rlogin: " + + Convert.ToString(Rlogin) + " RDP: " + Convert.ToString(Rdp) + " VNC: " + Convert.ToString(Vnc); } catch (Exception) { Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "ToString failed (Tools.PortScan)", true); return ""; } - } + } //Adpating to objectlistview instaed of listview public string HostIPorName @@ -78,23 +85,56 @@ namespace mRemoteNG.Tools return HostName; } } - public string RdpName { get { return BoolToYesNo(Rdp); } } - public string VncName { get { return BoolToYesNo(Vnc); } } - public string SshName { get { return BoolToYesNo(Rdp); } } - public string TelnetName { get { return BoolToYesNo(Telnet); } } - public string RloginName { get { return BoolToYesNo(Rlogin); } } - public string HttpName { get { return BoolToYesNo(Http); } } - public string HttpsName { get { return BoolToYesNo(Https); } } - public string OpenPortsName { - get { + + public string RdpName + { + get { return BoolToYesNo(Rdp); } + } + + public string VncName + { + get { return BoolToYesNo(Vnc); } + } + + public string SshName + { + get { return BoolToYesNo(Rdp); } + } + + public string TelnetName + { + get { return BoolToYesNo(Telnet); } + } + + public string RloginName + { + get { return BoolToYesNo(Rlogin); } + } + + public string HttpName + { + get { return BoolToYesNo(Http); } + } + + public string HttpsName + { + get { return BoolToYesNo(Https); } + } + + public string OpenPortsName + { + get + { var strOpen = ""; foreach (int p in OpenPorts) { strOpen += p + ", "; } + return strOpen; } } + public string ClosedPortsName { get @@ -104,12 +144,12 @@ namespace mRemoteNG.Tools { strClosed += p + ", "; } + return strClosed; } } - private static string BoolToYesNo(bool value) { return value ? Language.strYes : Language.strNo; @@ -125,6 +165,7 @@ namespace mRemoteNG.Tools Https = value; Http = value; } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Tools/SecureTransfer.cs b/mRemoteV1/Tools/SecureTransfer.cs index 2615fbf74..eec8a79b1 100644 --- a/mRemoteV1/Tools/SecureTransfer.cs +++ b/mRemoteV1/Tools/SecureTransfer.cs @@ -24,7 +24,6 @@ namespace mRemoteNG.Tools public SecureTransfer() { - } public SecureTransfer(string host, string user, string pass, int port, SSHTransferProtocol protocol) @@ -36,7 +35,13 @@ namespace mRemoteNG.Tools Protocol = protocol; } - public SecureTransfer(string host, string user, string pass, int port, SSHTransferProtocol protocol, string source, string dest) + public SecureTransfer(string host, + string user, + string pass, + int port, + SSHTransferProtocol protocol, + string source, + string dest) { Host = host; User = user; @@ -49,7 +54,7 @@ namespace mRemoteNG.Tools public void Connect() { - if(Protocol == SSHTransferProtocol.SCP) + if (Protocol == SSHTransferProtocol.SCP) { ScpClt = new ScpClient(Host, Port, User, Password); ScpClt.Connect(); @@ -94,7 +99,9 @@ namespace mRemoteNG.Tools { if (!ScpClt.IsConnected) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strSSHTransferFailed + Environment.NewLine + "SCP Not Connected!"); + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strSSHTransferFailed + Environment.NewLine + + "SCP Not Connected!"); return; } @@ -105,10 +112,15 @@ namespace mRemoteNG.Tools { if (!SftpClt.IsConnected) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, Language.strSSHTransferFailed + Environment.NewLine + "SFTP Not Connected!"); + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strSSHTransferFailed + Environment.NewLine + + "SFTP Not Connected!"); return; } - asyncResult = (SftpUploadAsyncResult)SftpClt.BeginUploadFile(new FileStream(SrcFile, Open), $"{DstFile}", asyncCallback); + + asyncResult = + (SftpUploadAsyncResult)SftpClt.BeginUploadFile(new FileStream(SrcFile, Open), $"{DstFile}", + asyncCallback); } } @@ -118,4 +130,4 @@ namespace mRemoteNG.Tools SFTP = 1 } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/Tools.LocalizedAttributes.cs b/mRemoteV1/Tools/Tools.LocalizedAttributes.cs index f2838c9ec..64821b487 100644 --- a/mRemoteV1/Tools/Tools.LocalizedAttributes.cs +++ b/mRemoteV1/Tools/Tools.LocalizedAttributes.cs @@ -1,149 +1,154 @@ using System; using System.ComponentModel; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Tools { - public class LocalizedAttributes - { - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public class LocalizedAttributes + { + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedCategoryAttribute : CategoryAttribute - { - private const int MaxOrder = 10; - private int Order; - - public LocalizedCategoryAttribute(string value, int Order = 1) : base(value) - { - this.Order = Order > MaxOrder ? MaxOrder : Order; - } - - protected override string GetLocalizedString(string value) - { - string OrderPrefix = ""; - for (int x = 0; x <= MaxOrder - Order; x++) - { - OrderPrefix += Convert.ToString("\t"); - } - - return OrderPrefix + Language.ResourceManager.GetString(value); - } - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + { + private const int MaxOrder = 10; + private int Order; + + public LocalizedCategoryAttribute(string value, int Order = 1) : base(value) + { + this.Order = Order > MaxOrder ? MaxOrder : Order; + } + + protected override string GetLocalizedString(string value) + { + string OrderPrefix = ""; + for (int x = 0; x <= MaxOrder - Order; x++) + { + OrderPrefix += Convert.ToString("\t"); + } + + return OrderPrefix + Language.ResourceManager.GetString(value); + } + } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedDisplayNameAttribute : DisplayNameAttribute - { - - private bool Localized; - - public LocalizedDisplayNameAttribute(string value) : base(value) - { - Localized = false; - } - + { + private bool Localized; + + public LocalizedDisplayNameAttribute(string value) : base(value) + { + Localized = false; + } + public override string DisplayName - { - get - { - if (!Localized) - { - Localized = true; - DisplayNameValue = Language.ResourceManager.GetString(DisplayNameValue); - } - - return base.DisplayName; - } - } - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + { + get + { + if (!Localized) + { + Localized = true; + DisplayNameValue = Language.ResourceManager.GetString(DisplayNameValue); + } + + return base.DisplayName; + } + } + } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedDescriptionAttribute : DescriptionAttribute - { - private bool Localized; - public LocalizedDescriptionAttribute(string value) : base(value) - { - Localized = false; - } - + { + private bool Localized; + + public LocalizedDescriptionAttribute(string value) : base(value) + { + Localized = false; + } + public override string Description - { - get - { - if (!Localized) - { - Localized = true; - DescriptionValue = Language.ResourceManager.GetString(DescriptionValue); - } - - return base.Description; - } - } - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + { + get + { + if (!Localized) + { + Localized = true; + DescriptionValue = Language.ResourceManager.GetString(DescriptionValue); + } + + return base.Description; + } + } + } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedDefaultValueAttribute : DefaultValueAttribute - { - public LocalizedDefaultValueAttribute(string name) : base(Language.ResourceManager.GetString(name)) - { - } - - // This allows localized attributes in a derived class to override a matching - // non-localized attribute inherited from its base class + { + public LocalizedDefaultValueAttribute(string name) : base(Language.ResourceManager.GetString(name)) + { + } + + // This allows localized attributes in a derived class to override a matching + // non-localized attribute inherited from its base class public override object TypeId { get { return typeof(DefaultValueAttribute); } } - } - + } + #region Special localization - with String.Format - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedDisplayNameInheritAttribute : DisplayNameAttribute - { - private bool Localized; - public LocalizedDisplayNameInheritAttribute(string value) : base(value) - { - - Localized = false; - } - + { + private bool Localized; + + public LocalizedDisplayNameInheritAttribute(string value) : base(value) + { + Localized = false; + } + public override string DisplayName - { - get - { - if (!Localized) - { - Localized = true; - DisplayNameValue = string.Format(Language.strFormatInherit, Language.ResourceManager.GetString(DisplayNameValue)); - } - - return base.DisplayName; - } - } - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + { + get + { + if (!Localized) + { + Localized = true; + DisplayNameValue = string.Format(Language.strFormatInherit, + Language.ResourceManager.GetString(DisplayNameValue)); + } + + return base.DisplayName; + } + } + } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class LocalizedDescriptionInheritAttribute : DescriptionAttribute - { - private bool Localized; - public LocalizedDescriptionInheritAttribute(string value) : base(value) - { - - Localized = false; - } - + { + private bool Localized; + + public LocalizedDescriptionInheritAttribute(string value) : base(value) + { + Localized = false; + } + public override string Description - { - get - { - if (!Localized) - { - Localized = true; - DescriptionValue = string.Format(Language.strFormatInheritDescription, Language.ResourceManager.GetString(DescriptionValue)); - } - - return base.Description; - } - } - } + { + get + { + if (!Localized) + { + Localized = true; + DescriptionValue = string.Format(Language.strFormatInheritDescription, + Language.ResourceManager.GetString(DescriptionValue)); + } + + return base.Description; + } + } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/Tools.SystemMenu.cs b/mRemoteV1/Tools/Tools.SystemMenu.cs index 227c242a7..13a11ac44 100644 --- a/mRemoteV1/Tools/Tools.SystemMenu.cs +++ b/mRemoteV1/Tools/Tools.SystemMenu.cs @@ -2,58 +2,61 @@ using System; using System.Drawing; using mRemoteNG.App; using Microsoft.Win32.SafeHandles; + // ReSharper disable MemberCanBeMadeStatic.Global namespace mRemoteNG.Tools { - public sealed class SystemMenu : SafeHandleZeroOrMinusOneIsInvalid, IDisposable + public sealed class SystemMenu : SafeHandleZeroOrMinusOneIsInvalid, IDisposable { - [Flags] - public enum Flags - { - MF_STRING = NativeMethods.MF_STRING, - MF_SEPARATOR = NativeMethods.MF_SEPARATOR, - MF_BYCOMMAND = NativeMethods.MF_BYCOMMAND, - MF_BYPOSITION = NativeMethods.MF_BYPOSITION, - MF_POPUP = NativeMethods.MF_POPUP, - WM_SYSCOMMAND = NativeMethods.WM_SYSCOMMAND - } + [Flags] + public enum Flags + { + MF_STRING = NativeMethods.MF_STRING, + MF_SEPARATOR = NativeMethods.MF_SEPARATOR, + MF_BYCOMMAND = NativeMethods.MF_BYCOMMAND, + MF_BYPOSITION = NativeMethods.MF_BYPOSITION, + MF_POPUP = NativeMethods.MF_POPUP, + WM_SYSCOMMAND = NativeMethods.WM_SYSCOMMAND + } private bool disposed; internal IntPtr SystemMenuHandle; private readonly IntPtr FormHandle; - public SystemMenu(IntPtr Handle) :base(true) - { - FormHandle = Handle; + public SystemMenu(IntPtr Handle) : base(true) + { + FormHandle = Handle; SystemMenuHandle = NativeMethods.GetSystemMenu(FormHandle, false); SetHandle(SystemMenuHandle); } - - public void Reset() - { - SystemMenuHandle = NativeMethods.GetSystemMenu(FormHandle, true); - } + + public void Reset() + { + SystemMenuHandle = NativeMethods.GetSystemMenu(FormHandle, true); + } public void AppendMenuItem(IntPtr ParentMenu, Flags Flags, IntPtr ID, string Text) - { - NativeMethods.AppendMenu(ParentMenu, (int)Flags, ID, Text); - } - - public IntPtr CreatePopupMenuItem() - { - return NativeMethods.CreatePopupMenu(); - } - - public bool InsertMenuItem(IntPtr SysMenu, int Position, Flags Flags, IntPtr SubMenu, string Text) - { - return NativeMethods.InsertMenu(SysMenu, Position, (int)Flags, SubMenu, Text); - } - - public IntPtr SetBitmap(IntPtr Menu, int Position, Flags Flags, Bitmap Bitmap) - { - return new IntPtr(Convert.ToInt32(NativeMethods.SetMenuItemBitmaps(Menu, Position, (int)Flags, Bitmap.GetHbitmap(), Bitmap.GetHbitmap()))); - } + { + NativeMethods.AppendMenu(ParentMenu, (int)Flags, ID, Text); + } + + public IntPtr CreatePopupMenuItem() + { + return NativeMethods.CreatePopupMenu(); + } + + public bool InsertMenuItem(IntPtr SysMenu, int Position, Flags Flags, IntPtr SubMenu, string Text) + { + return NativeMethods.InsertMenu(SysMenu, Position, (int)Flags, SubMenu, Text); + } + + public IntPtr SetBitmap(IntPtr Menu, int Position, Flags Flags, Bitmap Bitmap) + { + return new IntPtr(Convert.ToInt32(NativeMethods.SetMenuItemBitmaps(Menu, Position, (int)Flags, + Bitmap.GetHbitmap(), + Bitmap.GetHbitmap()))); + } protected override bool ReleaseHandle() { @@ -72,7 +75,8 @@ namespace mRemoteNG.Tools } */ - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", + "CA2216:DisposableTypesShouldDeclareFinalizer")] public new void Dispose() { Dispose(true); diff --git a/mRemoteV1/Tools/Tools.WindowPlacement.cs b/mRemoteV1/Tools/Tools.WindowPlacement.cs index 60adac28c..b6a34d553 100644 --- a/mRemoteV1/Tools/Tools.WindowPlacement.cs +++ b/mRemoteV1/Tools/Tools.WindowPlacement.cs @@ -5,89 +5,90 @@ using mRemoteNG.App; namespace mRemoteNG.Tools { - public class WindowPlacement - { - private Form _form; - + public class WindowPlacement + { + private Form _form; + + + public WindowPlacement(Form form) + { + _form = form; + } - public WindowPlacement(Form form) - { - _form = form; - } - #region Public Properties + public Form Form - { - get - { - return _form; - } - set - { - _form = value; - } - } - + { + get { return _form; } + set { _form = value; } + } + public bool RestoreToMaximized - { - get - { - NativeMethods.WINDOWPLACEMENT windowPlacement = GetWindowPlacement(); - return Convert.ToBoolean(windowPlacement.flags & NativeMethods.WPF_RESTORETOMAXIMIZED); - } - set - { + { + get + { NativeMethods.WINDOWPLACEMENT windowPlacement = GetWindowPlacement(); - if (value) - { - windowPlacement.flags = windowPlacement.flags | NativeMethods.WPF_RESTORETOMAXIMIZED; - } - else - { - windowPlacement.flags = windowPlacement.flags & ~NativeMethods.WPF_RESTORETOMAXIMIZED; - } - SetWindowPlacement(windowPlacement); - } - } + return Convert.ToBoolean(windowPlacement.flags & NativeMethods.WPF_RESTORETOMAXIMIZED); + } + set + { + NativeMethods.WINDOWPLACEMENT windowPlacement = GetWindowPlacement(); + if (value) + { + windowPlacement.flags = windowPlacement.flags | NativeMethods.WPF_RESTORETOMAXIMIZED; + } + else + { + windowPlacement.flags = windowPlacement.flags & ~NativeMethods.WPF_RESTORETOMAXIMIZED; + } + + SetWindowPlacement(windowPlacement); + } + } + #endregion - + #region Private Functions - private NativeMethods.WINDOWPLACEMENT GetWindowPlacement() - { - if (_form == null) - { - throw (new NullReferenceException("WindowPlacement.Form is not set.")); - } + + private NativeMethods.WINDOWPLACEMENT GetWindowPlacement() + { + if (_form == null) + { + throw (new NullReferenceException("WindowPlacement.Form is not set.")); + } + NativeMethods.WINDOWPLACEMENT windowPlacement = new NativeMethods.WINDOWPLACEMENT(); - windowPlacement.length = (uint)Marshal.SizeOf(windowPlacement); - try - { + windowPlacement.length = (uint)Marshal.SizeOf(windowPlacement); + try + { NativeMethods.GetWindowPlacement(_form.Handle, ref windowPlacement); - return windowPlacement; - } - catch (Exception) - { - throw; - } - } - - private bool SetWindowPlacement(NativeMethods.WINDOWPLACEMENT windowPlacement) - { - if (_form == null) - { - throw (new NullReferenceException("WindowPlacement.Form is not set.")); - } - windowPlacement.length = (uint)Marshal.SizeOf(windowPlacement); - try - { - return NativeMethods.SetWindowPlacement(_form.Handle, ref windowPlacement); - } - catch (Exception) - { - throw; - } - } + return windowPlacement; + } + catch (Exception) + { + throw; + } + } + + private bool SetWindowPlacement(NativeMethods.WINDOWPLACEMENT windowPlacement) + { + if (_form == null) + { + throw (new NullReferenceException("WindowPlacement.Form is not set.")); + } + + windowPlacement.length = (uint)Marshal.SizeOf(windowPlacement); + try + { + return NativeMethods.SetWindowPlacement(_form.Handle, ref windowPlacement); + } + catch (Exception) + { + throw; + } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs b/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs index 56f6cbc01..4663bf273 100644 --- a/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs +++ b/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs @@ -8,4 +8,4 @@ Users, LocalMachine } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs b/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs index aa2919bb3..b17745029 100644 --- a/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs +++ b/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs @@ -51,4 +51,4 @@ namespace mRemoteNG.Tools.WindowsRegistry } } } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tree/AlwaysConfirmYes.cs b/mRemoteV1/Tree/AlwaysConfirmYes.cs index 5eb7b9fe1..ff1f88cd3 100644 --- a/mRemoteV1/Tree/AlwaysConfirmYes.cs +++ b/mRemoteV1/Tree/AlwaysConfirmYes.cs @@ -1,5 +1,4 @@ - -namespace mRemoteNG.Tree +namespace mRemoteNG.Tree { public class AlwaysConfirmYes : IConfirm { diff --git a/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs index 63c2870fa..cff2882f2 100644 --- a/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs +++ b/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs @@ -19,7 +19,8 @@ namespace mRemoteNG.Tree { if (clickedNode == null) throw new ArgumentNullException(nameof(clickedNode)); - if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; + if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && + clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; _connectionInitiator.OpenConnection(clickedNode); } } diff --git a/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs index 75b1e5e50..0f5eb8ffc 100644 --- a/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs +++ b/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs @@ -19,7 +19,8 @@ namespace mRemoteNG.Tree { if (clickedNode == null) throw new ArgumentNullException(nameof(clickedNode)); - if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; + if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && + clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; _connectionInitiator.SwitchToOpenConnection(clickedNode); } } diff --git a/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs index 2e0034cf2..3656301aa 100644 --- a/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs +++ b/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs @@ -7,7 +7,8 @@ namespace mRemoteNG.Tree { public class TreeNodeCompositeClickHandler : ITreeNodeClickHandler { - public IEnumerable> ClickHandlers { get; set; } = new ITreeNodeClickHandler[0]; + public IEnumerable> ClickHandlers { get; set; } = + new ITreeNodeClickHandler[0]; public void Execute(ConnectionInfo clickedNode) { diff --git a/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs b/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs index 21dd3094f..09bbecd54 100644 --- a/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs +++ b/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs @@ -26,7 +26,9 @@ namespace mRemoteNG.Tree e.Handled = true; } - public void DropModel(ConnectionInfo dropSource, ConnectionInfo dropTarget, DropTargetLocation dropTargetLocation) + public void DropModel(ConnectionInfo dropSource, + ConnectionInfo dropTarget, + DropTargetLocation dropTargetLocation) { switch (dropTargetLocation) { @@ -79,7 +81,9 @@ namespace mRemoteNG.Tree e.Handled = true; } - public DragDropEffects CanModelDrop(ConnectionInfo dropSource, ConnectionInfo dropTarget, DropTargetLocation dropTargetLocation) + public DragDropEffects CanModelDrop(ConnectionInfo dropSource, + ConnectionInfo dropTarget, + DropTargetLocation dropTargetLocation) { var dragDropEffect = DragDropEffects.None; if (!NodeIsDraggable(dropSource)) @@ -87,16 +91,18 @@ namespace mRemoteNG.Tree _infoMessage = Language.strNodeNotDraggable; _enableFeedback = false; } - else switch (dropTargetLocation) - { - case DropTargetLocation.Item: - dragDropEffect = HandleCanDropOnItem(dropSource, dropTarget); - break; - case DropTargetLocation.AboveItem: - case DropTargetLocation.BelowItem: - dragDropEffect = HandleCanDropBetweenItems(dropSource, dropTarget); - break; - } + else + switch (dropTargetLocation) + { + case DropTargetLocation.Item: + dragDropEffect = HandleCanDropOnItem(dropSource, dropTarget); + break; + case DropTargetLocation.AboveItem: + case DropTargetLocation.BelowItem: + dragDropEffect = HandleCanDropBetweenItems(dropSource, dropTarget); + break; + } + return dragDropEffect; } @@ -113,6 +119,7 @@ namespace mRemoteNG.Tree { _enableFeedback = false; } + return dragDropEffect; } @@ -128,6 +135,7 @@ namespace mRemoteNG.Tree dragDropEffect = DragDropEffects.Move; _currentFeedbackColor = DropAllowedFeedbackColor; } + return dragDropEffect; } @@ -157,7 +165,8 @@ namespace mRemoteNG.Tree private bool AncestorDraggingOntoChild(ConnectionInfo source, ConnectionInfo target) { - return source is ContainerInfo sourceAsContainer && sourceAsContainer.GetRecursiveChildList().Contains(target); + return source is ContainerInfo sourceAsContainer && + sourceAsContainer.GetRecursiveChildList().Contains(target); } private bool DraggingOntoCurrentParent(ConnectionInfo source, ConnectionInfo target) diff --git a/mRemoteV1/Tree/ConnectionTreeModel.cs b/mRemoteV1/Tree/ConnectionTreeModel.cs index 502cf36ee..3a0fefb59 100644 --- a/mRemoteV1/Tree/ConnectionTreeModel.cs +++ b/mRemoteV1/Tree/ConnectionTreeModel.cs @@ -18,7 +18,9 @@ namespace mRemoteNG.Tree RootNodes.Add(rootNode); rootNode.CollectionChanged += RaiseCollectionChangedEvent; rootNode.PropertyChanged += RaisePropertyChangedEvent; - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, rootNode)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, + rootNode)); } public void RemoveRootNode(ContainerInfo rootNode) @@ -27,7 +29,9 @@ namespace mRemoteNG.Tree rootNode.CollectionChanged -= RaiseCollectionChangedEvent; rootNode.PropertyChanged -= RaisePropertyChangedEvent; RootNodes.Remove(rootNode); - RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, rootNode)); + RaiseCollectionChangedEvent(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, + rootNode)); } public IReadOnlyList GetRecursiveChildList() @@ -37,6 +41,7 @@ namespace mRemoteNG.Tree { list.AddRange(GetRecursiveChildList(rootNode)); } + return list; } @@ -59,11 +64,12 @@ namespace mRemoteNG.Tree { if (connectionInfo is RootNodeInfo) return; - + connectionInfo?.RemoveParent(); } public event NotifyCollectionChangedEventHandler CollectionChanged; + private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) { CollectionChanged?.Invoke(sender, args); diff --git a/mRemoteV1/Tree/NodeSearcher.cs b/mRemoteV1/Tree/NodeSearcher.cs index cb9bd8234..21d839123 100644 --- a/mRemoteV1/Tree/NodeSearcher.cs +++ b/mRemoteV1/Tree/NodeSearcher.cs @@ -5,7 +5,7 @@ using mRemoteNG.Connection; namespace mRemoteNG.Tree { - public class NodeSearcher + public class NodeSearcher { private readonly ConnectionTreeModel _connectionTreeModel; @@ -31,6 +31,7 @@ namespace mRemoteNG.Tree node.Hostname.ToLowerInvariant().Contains(searchTextLower)) Matches.Add(node); } + if (Matches.Count > 0) CurrentMatch = Matches.First(); return Matches; diff --git a/mRemoteV1/Tree/NodeType.cs b/mRemoteV1/Tree/NodeType.cs index 6f39352b9..33ef4705c 100644 --- a/mRemoteV1/Tree/NodeType.cs +++ b/mRemoteV1/Tree/NodeType.cs @@ -9,4 +9,4 @@ PuttyRoot = 4, PuttySession = 5 } -} +} \ No newline at end of file diff --git a/mRemoteV1/Tree/PreviousSessionOpener.cs b/mRemoteV1/Tree/PreviousSessionOpener.cs index 810296b64..bc6cffdda 100644 --- a/mRemoteV1/Tree/PreviousSessionOpener.cs +++ b/mRemoteV1/Tree/PreviousSessionOpener.cs @@ -20,12 +20,13 @@ namespace mRemoteNG.Tree public void Execute(IConnectionTree connectionTree) { - var connectionInfoList = connectionTree.GetRootConnectionNode().GetRecursiveChildList().Where(node => !(node is ContainerInfo)); + var connectionInfoList = connectionTree.GetRootConnectionNode().GetRecursiveChildList() + .Where(node => !(node is ContainerInfo)); var previouslyOpenedConnections = connectionInfoList .Where(item => - item.PleaseConnect && - //ignore items that have already connected - !_connectionInitiator.ActiveConnections.Contains(item.ConstantID)); + item.PleaseConnect && + //ignore items that have already connected + !_connectionInitiator.ActiveConnections.Contains(item.ConstantID)); foreach (var connectionInfo in previouslyOpenedConnections) { diff --git a/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs b/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs index 8b26236f7..2cbd278d8 100644 --- a/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs +++ b/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs @@ -10,7 +10,8 @@ namespace mRemoteNG.Tree public void Execute(IConnectionTree connectionTree) { var rootNode = connectionTree.GetRootConnectionNode(); - var containerList = connectionTree.ConnectionTreeModel.GetRecursiveChildList(rootNode).OfType(); + var containerList = connectionTree.ConnectionTreeModel.GetRecursiveChildList(rootNode) + .OfType(); var previouslyExpandedNodes = containerList.Where(container => container.IsExpanded); connectionTree.ExpandedObjects = previouslyExpandedNodes; connectionTree.InvokeRebuildAll(true); diff --git a/mRemoteV1/Tree/Root/RootNodeInfo.cs b/mRemoteV1/Tree/Root/RootNodeInfo.cs index 47e863a71..c9a0c6c8c 100644 --- a/mRemoteV1/Tree/Root/RootNodeInfo.cs +++ b/mRemoteV1/Tree/Root/RootNodeInfo.cs @@ -7,62 +7,57 @@ using mRemoteNG.Tools; namespace mRemoteNG.Tree.Root { - [DefaultProperty("Name")] + [DefaultProperty("Name")] public class RootNodeInfo : ContainerInfo - { - private string _name; - private string _customPassword = ""; + { + private string _name; + private string _customPassword = ""; - public RootNodeInfo(RootNodeType rootType, string uniqueId) - : base(uniqueId) - { + public RootNodeInfo(RootNodeType rootType, string uniqueId) + : base(uniqueId) + { _name = Language.strConnections; - Type = rootType; - } + Type = rootType; + } + + public RootNodeInfo(RootNodeType rootType) + : this(rootType, Guid.NewGuid().ToString()) + { + } - public RootNodeInfo(RootNodeType rootType) - : this(rootType, Guid.NewGuid().ToString()) - { - } - #region Public Properties - [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - Browsable(true), - LocalizedAttributes.LocalizedDefaultValue("strConnections"), - LocalizedAttributes.LocalizedDisplayName("strPropertyNameName"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")] - public override string Name - { - get { return _name; } + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), + Browsable(true), + LocalizedAttributes.LocalizedDefaultValue("strConnections"), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameName"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")] + public override string Name + { + get { return _name; } set { _name = value; } - } + } - [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - Browsable(true), - LocalizedAttributes.LocalizedDisplayName("strPasswordProtect"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), + Browsable(true), + LocalizedAttributes.LocalizedDisplayName("strPasswordProtect"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public new bool Password { get; set; } - [Browsable(false)] - public string PasswordString - { - get - { - return Password ? _customPassword : DefaultPassword; - } - set - { - _customPassword = value; - Password = !string.IsNullOrEmpty(value) && _customPassword != DefaultPassword; - } - } - [Browsable(false)] - public string DefaultPassword { get; } = "mR3m"; - - [Browsable(false)] - public RootNodeType Type {get; set;} + public string PasswordString + { + get { return Password ? _customPassword : DefaultPassword; } + set + { + _customPassword = value; + Password = !string.IsNullOrEmpty(value) && _customPassword != DefaultPassword; + } + } + + [Browsable(false)] public string DefaultPassword { get; } = "mR3m"; + + [Browsable(false)] public RootNodeType Type { get; set; } public override TreeNodeType GetTreeNodeType() { @@ -70,18 +65,19 @@ namespace mRemoteNG.Tree.Root ? TreeNodeType.Root : TreeNodeType.PuttyRoot; } + #endregion - public override void AddChildAt(ConnectionInfo newChildItem, int index) - { + public override void AddChildAt(ConnectionInfo newChildItem, int index) + { newChildItem.Inheritance.DisableInheritance(); - base.AddChildAt(newChildItem, index); - } + base.AddChildAt(newChildItem, index); + } - public override void RemoveChild(ConnectionInfo removalTarget) - { + public override void RemoveChild(ConnectionInfo removalTarget) + { removalTarget.Inheritance.EnableInheritance(); - base.RemoveChild(removalTarget); - } - } + base.RemoveChild(removalTarget); + } + } } \ No newline at end of file diff --git a/mRemoteV1/Tree/Root/RootPuttySessionsNodeInfo.cs b/mRemoteV1/Tree/Root/RootPuttySessionsNodeInfo.cs index 85c9be9da..2b78cd9a2 100644 --- a/mRemoteV1/Tree/Root/RootPuttySessionsNodeInfo.cs +++ b/mRemoteV1/Tree/Root/RootPuttySessionsNodeInfo.cs @@ -2,7 +2,7 @@ using mRemoteNG.Tools; namespace mRemoteNG.Tree.Root { - public class RootPuttySessionsNodeInfo : RootNodeInfo + public class RootPuttySessionsNodeInfo : RootNodeInfo { private string _name; private string _panel; @@ -15,37 +15,39 @@ namespace mRemoteNG.Tree.Root string.IsNullOrEmpty(Settings.Default.PuttySavedSessionsPanel) ? Language.strGeneral : Settings.Default.PuttySavedSessionsPanel; - } + } #region Public Properties + [LocalizedAttributes.LocalizedDefaultValue("strPuttySavedSessionsRootName")] public override string Name - { - get { return _name; } - set - { - _name = value; + { + get { return _name; } + set + { + _name = value; //Settings.Default.PuttySavedSessionsName = value; - } - } - + } + } + [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), - LocalizedAttributes.LocalizedDisplayName("strPropertyNamePanel"), - LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")] + LocalizedAttributes.LocalizedDisplayName("strPropertyNamePanel"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")] public override string Panel - { - get { return _panel; } - set - { - _panel = value; + { + get { return _panel; } + set + { + _panel = value; Settings.Default.PuttySavedSessionsPanel = value; - } + } } public override TreeNodeType GetTreeNodeType() { return TreeNodeType.PuttyRoot; } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGButton.cs b/mRemoteV1/UI/Controls/Base/NGButton.cs index 0be06fff1..746032dcb 100644 --- a/mRemoteV1/UI/Controls/Base/NGButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGButton.cs @@ -11,7 +11,7 @@ namespace mRemoteNG.UI.Controls.Base //Extended button class, the button onPaint completely repaint the control public class NGButton : Button { - private ThemeManager _themeManager ; + private ThemeManager _themeManager; /// /// Store the mouse state, required for coloring the component according to the mouse state @@ -80,15 +80,15 @@ namespace mRemoteNG.UI.Controls.Base base.OnPaint(e); return; } + Color back; Color fore; Color border; if (Enabled) { - switch (_mice) { - case MouseState.HOVER: + case MouseState.HOVER: back = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Hover_Background"); fore = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Hover_Foreground"); border = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Hover_Border"); @@ -113,7 +113,6 @@ namespace mRemoteNG.UI.Controls.Base } - e.Graphics.FillRectangle(new SolidBrush(back), e.ClipRectangle); e.Graphics.DrawRectangle(new Pen(border, 1), 0, 0, Width - 1, Height - 1); e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; @@ -124,9 +123,12 @@ namespace mRemoteNG.UI.Controls.Base { SizeF stringSize = e.Graphics.MeasureString(Text, Font); - e.Graphics.DrawImageUnscaled(Image, Width / 2 - (int)stringSize.Width / 2 - Image.Width , Height / 2 - Image.Height/2); + e.Graphics.DrawImageUnscaled(Image, Width / 2 - (int)stringSize.Width / 2 - Image.Width, + Height / 2 - Image.Height / 2); } - TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, fore, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); + + TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, fore, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); } private void InitializeComponent() @@ -135,9 +137,9 @@ namespace mRemoteNG.UI.Controls.Base // // NGButton // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs index c7432d603..f5a650b2e 100644 --- a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs @@ -78,6 +78,7 @@ namespace mRemoteNG.UI.Controls.Base base.OnPaint(e); return; } + //Get the colors Color fore; Color glyph; @@ -104,7 +105,6 @@ namespace mRemoteNG.UI.Controls.Base } else { - fore = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Text_Disabled"); glyph = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Glyph_Disabled"); checkBorder = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Border_Disabled"); @@ -126,7 +126,8 @@ namespace mRemoteNG.UI.Controls.Base } var textRect = new Rectangle(_textXCoord, 0, Width - 16, Height); - TextRenderer.DrawText(e.Graphics, Text, Font, textRect, fore, Parent.BackColor, TextFormatFlags.PathEllipsis); + TextRenderer.DrawText(e.Graphics, Text, Font, textRect, fore, Parent.BackColor, + TextFormatFlags.PathEllipsis); } private void InitializeComponent() @@ -137,8 +138,6 @@ namespace mRemoteNG.UI.Controls.Base // Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); ResumeLayout(false); - } } -} - +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGComboBox.cs b/mRemoteV1/UI/Controls/Base/NGComboBox.cs index 0740926e1..86c8d3276 100644 --- a/mRemoteV1/UI/Controls/Base/NGComboBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGComboBox.cs @@ -9,12 +9,14 @@ namespace mRemoteNG.UI.Controls.Base internal class NGComboBox : ComboBox { private ThemeManager _themeManager; + public enum MouseState { HOVER, DOWN, OUT } + public MouseState _mice { get; set; } public NGComboBox() @@ -66,23 +68,35 @@ namespace mRemoteNG.UI.Controls.Base if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { - itemBrush = new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Selected_Foreground")); - e.Graphics.FillRectangle(new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Selected_Background")), e.Bounds); + itemBrush = new SolidBrush( + _themeManager + .ActiveTheme.ExtendedPalette.getColor("List_Item_Selected_Foreground")); + e.Graphics.FillRectangle( + new SolidBrush(_themeManager + .ActiveTheme.ExtendedPalette + .getColor("List_Item_Selected_Background")), + e.Bounds); } else - e.Graphics.FillRectangle(new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background")), e.Bounds); + e.Graphics.FillRectangle( + new SolidBrush(_themeManager + .ActiveTheme.ExtendedPalette.getColor("ComboBox_Background")), + e.Bounds); if (Items.Count > 0) { if (string.IsNullOrEmpty(DisplayMember)) - e.Graphics.DrawString(Items[index].ToString(), e.Font, itemBrush, e.Bounds, StringFormat.GenericDefault); + e.Graphics.DrawString(Items[index].ToString(), e.Font, itemBrush, e.Bounds, + StringFormat.GenericDefault); else { if (Items[index].GetType().GetProperty(DisplayMember) != null) { e.Graphics.DrawString( - Items[index].GetType().GetProperty(DisplayMember)?.GetValue(Items[index], null).ToString(), - e.Font, itemBrush, e.Bounds, StringFormat.GenericDefault); + Items[index] + .GetType().GetProperty(DisplayMember)?.GetValue(Items[index], null) + .ToString(), + e.Font, itemBrush, e.Bounds, StringFormat.GenericDefault); } } } @@ -92,12 +106,12 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - - if ( !_themeManager.ActiveAndExtended) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; } + //Colors var Border = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Border"); var Back = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background"); @@ -110,7 +124,9 @@ namespace mRemoteNG.UI.Controls.Base Border = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_MouseOver_Border"); ButtBack = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Button_MouseOver_Background"); ButtFore = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Button_MouseOver_Foreground"); - }if (DroppedDown) + } + + if (DroppedDown) { Border = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_MouseOver_Border"); ButtBack = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Button_Pressed_Background"); @@ -118,7 +134,6 @@ namespace mRemoteNG.UI.Controls.Base } - e.Graphics.Clear(Back); //Border @@ -127,6 +142,7 @@ namespace mRemoteNG.UI.Controls.Base var boxRect = new Rectangle(0, 0, Width - 1, Height - 1); e.Graphics.DrawRectangle(p, boxRect); } + //Button using (var b = new SolidBrush(ButtBack)) { @@ -134,11 +150,12 @@ namespace mRemoteNG.UI.Controls.Base } //Arrow - e.Graphics.DrawString("\u25BC", Font, new SolidBrush(ButtFore), Width-17, Height/2 -5); + e.Graphics.DrawString("\u25BC", Font, new SolidBrush(ButtFore), Width - 17, Height / 2 - 5); //Text var textRect = new Rectangle(2, 2, Width - 20, Height - 4); - TextRenderer.DrawText(e.Graphics, Text, Font, textRect, Fore, Back, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); + TextRenderer.DrawText(e.Graphics, Text, Font, textRect, Fore, Back, + TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } private void InitializeComponent() @@ -147,9 +164,9 @@ namespace mRemoteNG.UI.Controls.Base // // NGComboBox // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs index a4266434a..7e50a2717 100644 --- a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs @@ -33,8 +33,9 @@ namespace mRemoteNG.UI.Controls.Base base.OnPaint(e); return; } + //Reusing the textbox colors - var titleColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Foreground"); + var titleColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Foreground"); //var backColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Backgorund"); var lineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Line"); @@ -47,7 +48,8 @@ namespace mRemoteNG.UI.Controls.Base //var state = Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled; - var flags = TextFormatFlags.PreserveGraphicsTranslateTransform | TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.TextBoxControl |TextFormatFlags.WordBreak; + var flags = TextFormatFlags.PreserveGraphicsTranslateTransform | TextFormatFlags.PreserveGraphicsClipping | + TextFormatFlags.TextBoxControl | TextFormatFlags.WordBreak; if (!ShowKeyboardCues) flags |= TextFormatFlags.HidePrefix; @@ -60,7 +62,8 @@ namespace mRemoteNG.UI.Controls.Base var bounds = new Rectangle(0, 0, Width, Height); var rectangle = bounds; rectangle.Width -= 8; - var size = TextRenderer.MeasureText(e.Graphics, Text, Font, new Size(rectangle.Width, rectangle.Height), flags); + var size = TextRenderer.MeasureText(e.Graphics, Text, Font, new Size(rectangle.Width, rectangle.Height), + flags); rectangle.Width = size.Width; rectangle.Height = size.Height; if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right) @@ -75,16 +78,22 @@ namespace mRemoteNG.UI.Controls.Base { var num = bounds.Top + (Font.Height / 2); //Left line - e.Graphics.DrawLine(pen, bounds.Left + Padding.Left , num - Padding.Top, bounds.Left + Padding.Left, bounds.Height - Padding.Bottom); + e.Graphics.DrawLine(pen, bounds.Left + Padding.Left, num - Padding.Top, bounds.Left + Padding.Left, + bounds.Height - Padding.Bottom); //Bottom line - e.Graphics.DrawLine(pen, bounds.Left + Padding.Left, bounds.Height - Padding.Bottom, bounds.Width -Padding.Right, bounds.Height -Padding.Bottom); + e.Graphics.DrawLine(pen, bounds.Left + Padding.Left, bounds.Height - Padding.Bottom, + bounds.Width - Padding.Right, bounds.Height - Padding.Bottom); //Beside text line - e.Graphics.DrawLine(pen, bounds.Left +Padding.Left, num - Padding.Top, rectangle.X - 3, num - Padding.Top); + e.Graphics.DrawLine(pen, bounds.Left + Padding.Left, num - Padding.Top, rectangle.X - 3, + num - Padding.Top); //Top line cutted - e.Graphics.DrawLine(pen, rectangle.X + rectangle.Width + 2, num - Padding.Top, bounds.Width - Padding.Right, num - Padding.Top); + e.Graphics.DrawLine(pen, rectangle.X + rectangle.Width + 2, num - Padding.Top, + bounds.Width - Padding.Right, num - Padding.Top); //Right line - e.Graphics.DrawLine(pen, bounds.Width - Padding.Right, num - Padding.Top, bounds.Width - Padding.Right, bounds.Height - Padding.Bottom); + e.Graphics.DrawLine(pen, bounds.Width - Padding.Right, num - Padding.Top, bounds.Width - Padding.Right, + bounds.Height - Padding.Bottom); } + RaisePaintEvent(this, e); } @@ -94,9 +103,9 @@ namespace mRemoteNG.UI.Controls.Base // // NGGroupBox // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGLabel.cs b/mRemoteV1/UI/Controls/Base/NGLabel.cs index f2c656a2e..28cdd43ab 100644 --- a/mRemoteV1/UI/Controls/Base/NGLabel.cs +++ b/mRemoteV1/UI/Controls/Base/NGLabel.cs @@ -93,7 +93,8 @@ namespace mRemoteNG.UI.Controls.Base } else { - var disabledtextLabel = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Foreground"); + var disabledtextLabel = + _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Foreground"); TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, disabledtextLabel, _textFormatFlags); } } @@ -104,9 +105,9 @@ namespace mRemoteNG.UI.Controls.Base // // NGLabel // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGListView.cs b/mRemoteV1/UI/Controls/Base/NGListView.cs index 642134f5a..b05986efb 100644 --- a/mRemoteV1/UI/Controls/Base/NGListView.cs +++ b/mRemoteV1/UI/Controls/Base/NGListView.cs @@ -10,6 +10,7 @@ namespace mRemoteNG.UI.Controls.Base internal class NGListView : ObjectListView { private CellBorderDecoration deco; + //Control if the gridlines are styled, must be set before the OnCreateControl is fired public bool DecorateLines { get; set; } = true; @@ -43,7 +44,7 @@ namespace mRemoteNG.UI.Controls.Base }; HeaderFormatStyle = headerStylo; //Border style - if(DecorateLines) + if (DecorateLines) { UseCellFormatEvents = true; GridLines = false; @@ -56,6 +57,7 @@ namespace mRemoteNG.UI.Controls.Base }; FormatCell += NGListView_FormatCell; } + if (Items != null && Items.Count != 0) BuildList(); Invalidate(); @@ -79,7 +81,6 @@ namespace mRemoteNG.UI.Controls.Base Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); ((ISupportInitialize)(this)).EndInit(); ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs index 6d4563d09..0ab030875 100644 --- a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs +++ b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Windows.Forms; using mRemoteNG.Themes; + // ReSharper disable LocalizableElement namespace mRemoteNG.UI.Controls.Base @@ -10,7 +11,6 @@ namespace mRemoteNG.UI.Controls.Base //original ones cannot be themed due to protected inheritance internal class NGNumericUpDown : NumericUpDown { - private readonly ThemeManager _themeManager; private NGButton Up; private NGButton Down; @@ -63,7 +63,7 @@ namespace mRemoteNG.UI.Controls.Base Text = "\u25BC", Font = new Font(Font.FontFamily, 5f) }; - Down.SetBounds(Controls.Owner.Width - 17, Controls.Owner.Height /2 + 1, 16, Controls.Owner.Height / 2 - 1); + Down.SetBounds(Controls.Owner.Width - 17, Controls.Owner.Height / 2 + 1, 16, Controls.Owner.Height / 2 - 1); Down.Click += Down_Click; Controls.Add(Up); Controls.Add(Down); @@ -82,7 +82,6 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnEnabledChanged(EventArgs e) { - if (_themeManager.ActiveAndExtended) { if (Enabled) @@ -95,6 +94,7 @@ namespace mRemoteNG.UI.Controls.Base BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); } } + base.OnEnabledChanged(e); Invalidate(); } @@ -107,7 +107,10 @@ namespace mRemoteNG.UI.Controls.Base if (!_themeManager.ActiveAndExtended) return; //Fix Border if (BorderStyle != BorderStyle.None) - e.Graphics.DrawRectangle(new Pen(_themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Border"), 1), 0, 0, Width - 1, Height - 1); + e.Graphics.DrawRectangle( + new Pen(_themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Border"), + 1), 0, 0, Width - 1, + Height - 1); } private void InitializeComponent() @@ -117,10 +120,10 @@ namespace mRemoteNG.UI.Controls.Base // // NGNumericUpDown // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); ((System.ComponentModel.ISupportInitialize)(this)).EndInit(); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs index 7600a4d4d..8b34aef54 100644 --- a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs @@ -30,4 +30,4 @@ namespace mRemoteNG.UI.Controls.Base Invalidate(); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs index a6b065a45..2b098da34 100644 --- a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs +++ b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs @@ -4,7 +4,6 @@ using System.Windows.Forms; namespace mRemoteNG.UI.Controls.Base { - // Repaint of a ProgressBar on a flat style internal class NGProgressBar : ProgressBar { @@ -33,11 +32,13 @@ namespace mRemoteNG.UI.Controls.Base base.OnPaint(e); return; } + var progressFill = _themeManager.ActiveTheme.ExtendedPalette.getColor("ProgressBar_Fill"); var back = _themeManager.ActiveTheme.ExtendedPalette.getColor("ProgressBar_Background"); var doneProgress = (int)(e.ClipRectangle.Width * ((double)Value / Maximum)); e.Graphics.FillRectangle(new SolidBrush(progressFill), 0, 0, doneProgress, e.ClipRectangle.Height); - e.Graphics.FillRectangle(new SolidBrush(back), doneProgress, 0, e.ClipRectangle.Width, e.ClipRectangle.Height); + e.Graphics.FillRectangle(new SolidBrush(back), doneProgress, 0, e.ClipRectangle.Width, + e.ClipRectangle.Height); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs index 1de9e7efe..e80a7b1e7 100644 --- a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs @@ -19,10 +19,12 @@ namespace mRemoteNG.UI.Controls.Base { var display = new DisplayProperties(); - _circleSmall = new Rectangle(display.ScaleWidth(4), display.ScaleHeight(4), display.ScaleWidth(6), display.ScaleHeight(6)); - _circle = new Rectangle(display.ScaleWidth(1), display.ScaleHeight(1), display.ScaleWidth(12), display.ScaleHeight(12)); + _circleSmall = new Rectangle(display.ScaleWidth(4), display.ScaleHeight(4), display.ScaleWidth(6), + display.ScaleHeight(6)); + _circle = new Rectangle(display.ScaleWidth(1), display.ScaleHeight(1), display.ScaleWidth(12), + display.ScaleHeight(12)); _textXCoord = display.ScaleWidth(16); - ThemeManager.getInstance().ThemeChanged += OnCreateControl; + ThemeManager.getInstance().ThemeChanged += OnCreateControl; } @@ -79,6 +81,7 @@ namespace mRemoteNG.UI.Controls.Base base.OnPaint(e); return; } + // Init var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; @@ -104,7 +107,6 @@ namespace mRemoteNG.UI.Controls.Base outline = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Border_Hover"); } } - } else { @@ -113,7 +115,8 @@ namespace mRemoteNG.UI.Controls.Base } var textRect = new Rectangle(_textXCoord, Padding.Top, Width - 16, Height); - TextRenderer.DrawText(e.Graphics, Text, Font, textRect, fore, Parent.BackColor, TextFormatFlags.PathEllipsis); + TextRenderer.DrawText(e.Graphics, Text, Font, textRect, fore, Parent.BackColor, + TextFormatFlags.PathEllipsis); g.FillEllipse(new SolidBrush(centerBack), _circle); g.FillEllipse(new SolidBrush(center), _circleSmall); @@ -126,9 +129,9 @@ namespace mRemoteNG.UI.Controls.Base // // NGRadioButton // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/Base/NGTextBox.cs b/mRemoteV1/UI/Controls/Base/NGTextBox.cs index 00253193b..e50fd8fac 100644 --- a/mRemoteV1/UI/Controls/Base/NGTextBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGTextBox.cs @@ -11,7 +11,7 @@ namespace mRemoteNG.UI.Controls.Base { private ThemeManager _themeManager; - public NGTextBox() + public NGTextBox() { InitializeComponent(); ThemeManager.getInstance().ThemeChanged += OnCreateControl; @@ -23,7 +23,9 @@ namespace mRemoteNG.UI.Controls.Base _themeManager = ThemeManager.getInstance(); if (!_themeManager.ActiveAndExtended) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor(ReadOnly ? "TextBox_Disabled_Background" : "TextBox_Background"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor(ReadOnly + ? "TextBox_Disabled_Background" + : "TextBox_Background"); Invalidate(); } @@ -43,6 +45,7 @@ namespace mRemoteNG.UI.Controls.Base BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); } } + base.OnEnabledChanged(e); Invalidate(); } @@ -55,7 +58,6 @@ namespace mRemoteNG.UI.Controls.Base // Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionContextMenu.cs b/mRemoteV1/UI/Controls/ConnectionContextMenu.cs index c2469c866..019dc7e83 100644 --- a/mRemoteV1/UI/Controls/ConnectionContextMenu.cs +++ b/mRemoteV1/UI/Controls/ConnectionContextMenu.cs @@ -9,6 +9,7 @@ using mRemoteNG.Container; using mRemoteNG.Tools; using mRemoteNG.Tree; using mRemoteNG.Tree.Root; + // ReSharper disable UnusedParameter.Local @@ -56,7 +57,7 @@ namespace mRemoteNG.UI.Controls _connectionTree = connectionTree; _connectionInitiator = new ConnectionInitiator(); InitializeComponent(); - ApplyLanguage(); + ApplyLanguage(); EnableShortcutKeys(); Opening += (sender, args) => { @@ -66,6 +67,7 @@ namespace mRemoteNG.UI.Controls args.Cancel = true; return; } + ShowHideMenuItems(); }; } @@ -108,8 +110,10 @@ namespace mRemoteNG.UI.Controls // // cMenTree // - Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); - Items.AddRange(new ToolStripItem[] { + Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, 0); + Items.AddRange(new ToolStripItem[] + { _cMenTreeConnect, _cMenTreeConnectWithOptions, _cMenTreeDisconnect, @@ -146,7 +150,8 @@ namespace mRemoteNG.UI.Controls // // cMenTreeConnectWithOptions // - _cMenTreeConnectWithOptions.DropDownItems.AddRange(new ToolStripItem[] { + _cMenTreeConnectWithOptions.DropDownItems.AddRange(new ToolStripItem[] + { _cMenTreeConnectWithOptionsConnectToConsoleSession, _cMenTreeConnectWithOptionsDontConnectToConsoleSession, _cMenTreeConnectWithOptionsConnectInFullscreen, @@ -160,7 +165,8 @@ namespace mRemoteNG.UI.Controls // cMenTreeConnectWithOptionsConnectToConsoleSession // _cMenTreeConnectWithOptionsConnectToConsoleSession.Image = Resources.monitor_go; - _cMenTreeConnectWithOptionsConnectToConsoleSession.Name = "_cMenTreeConnectWithOptionsConnectToConsoleSession"; + _cMenTreeConnectWithOptionsConnectToConsoleSession.Name = + "_cMenTreeConnectWithOptionsConnectToConsoleSession"; _cMenTreeConnectWithOptionsConnectToConsoleSession.Size = new System.Drawing.Size(245, 22); _cMenTreeConnectWithOptionsConnectToConsoleSession.Text = "Connect to console session"; _cMenTreeConnectWithOptionsConnectToConsoleSession.Click += OnConnectToConsoleSessionClicked; @@ -168,7 +174,8 @@ namespace mRemoteNG.UI.Controls // cMenTreeConnectWithOptionsDontConnectToConsoleSession // _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Image = Resources.monitor_delete; - _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Name = "_cMenTreeConnectWithOptionsDontConnectToConsoleSession"; + _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Name = + "_cMenTreeConnectWithOptionsDontConnectToConsoleSession"; _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Size = new System.Drawing.Size(245, 22); _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Text = "Don\'t connect to console session"; _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Visible = false; @@ -193,7 +200,8 @@ namespace mRemoteNG.UI.Controls // cMenTreeConnectWithOptionsChoosePanelBeforeConnecting // _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Image = Resources.Panels; - _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Name = "_cMenTreeConnectWithOptionsChoosePanelBeforeConnecting"; + _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Name = + "_cMenTreeConnectWithOptionsChoosePanelBeforeConnecting"; _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Size = new System.Drawing.Size(245, 22); _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Text = "Choose panel before connecting"; _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Click += OnChoosePanelBeforeConnectingClicked; @@ -269,7 +277,8 @@ namespace mRemoteNG.UI.Controls // // cMenTreeImport // - _cMenTreeImport.DropDownItems.AddRange(new ToolStripItem[] { + _cMenTreeImport.DropDownItems.AddRange(new ToolStripItem[] + { _cMenTreeImportFile, _cMenTreeImportActiveDirectory, _cMenTreeImportPortScan @@ -334,7 +343,8 @@ namespace mRemoteNG.UI.Controls // // cMenTreeToolsSort // - _cMenTreeToolsSort.DropDownItems.AddRange(new ToolStripItem[] { + _cMenTreeToolsSort.DropDownItems.AddRange(new ToolStripItem[] + { _cMenTreeToolsSortAscending, _cMenTreeToolsSortDescending }); @@ -380,7 +390,8 @@ namespace mRemoteNG.UI.Controls _cMenTreeConnect.Text = Language.strConnect; _cMenTreeConnectWithOptions.Text = Language.strConnectWithOptions; _cMenTreeConnectWithOptionsConnectToConsoleSession.Text = Language.strConnectToConsoleSession; - _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Text = Language.strDontConnectToConsoleSessionMenuItem; + _cMenTreeConnectWithOptionsDontConnectToConsoleSession.Text = + Language.strDontConnectToConsoleSessionMenuItem; _cMenTreeConnectWithOptionsConnectInFullscreen.Text = Language.strConnectInFullscreen; _cMenTreeConnectWithOptionsNoCredentials.Text = Language.strConnectNoCredentials; _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Text = Language.strChoosePanelBeforeConnecting; @@ -439,7 +450,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("ShowHideMenuItems (UI.Controls.ConnectionContextMenu) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "ShowHideMenuItems (UI.Controls.ConnectionContextMenu) failed", + ex); } } @@ -563,6 +576,7 @@ namespace mRemoteNG.UI.Controls { continue; } + menuItem.Enabled = enable; if (menuItem.HasDropDownItems) { @@ -592,7 +606,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenTreeTools_DropDownOpening failed (UI.Window.ConnectionTreeWindow)", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "cMenTreeTools_DropDownOpening failed (UI.Window.ConnectionTreeWindow)", + ex); } } @@ -606,6 +622,7 @@ namespace mRemoteNG.UI.Controls } #region Click handlers + private void OnConnectClicked(object sender, EventArgs e) { var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; @@ -619,27 +636,37 @@ namespace mRemoteNG.UI.Controls { var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; if (selectedNodeAsContainer != null) - _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(selectedNodeAsContainer, + ConnectionInfo.Force.UseConsoleSession | + ConnectionInfo.Force.DoNotJump); else - _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, + ConnectionInfo.Force.UseConsoleSession | + ConnectionInfo.Force.DoNotJump); } private void OnDontConnectToConsoleSessionClicked(object sender, EventArgs e) { var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; if (selectedNodeAsContainer != null) - _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(selectedNodeAsContainer, + ConnectionInfo.Force.DontUseConsoleSession | + ConnectionInfo.Force.DoNotJump); else - _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, + ConnectionInfo.Force.DontUseConsoleSession | + ConnectionInfo.Force.DoNotJump); } private void OnConnectInFullscreenClicked(object sender, EventArgs e) { var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; if (selectedNodeAsContainer != null) - _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(selectedNodeAsContainer, + ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); else - _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, + ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); } private void OnConnectWithNoCredentialsClick(object sender, EventArgs e) @@ -655,9 +682,13 @@ namespace mRemoteNG.UI.Controls { var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; if (selectedNodeAsContainer != null) - _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(selectedNodeAsContainer, + ConnectionInfo.Force.OverridePanel | + ConnectionInfo.Force.DoNotJump); else - _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, + ConnectionInfo.Force.OverridePanel | + ConnectionInfo.Force.DoNotJump); } private void OnDisconnectClicked(object sender, EventArgs e) @@ -691,7 +722,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("DisconnectConnection (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "DisconnectConnection (UI.Window.ConnectionTreeWindow) failed", + ex); } } @@ -712,7 +745,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("SSHTransferFile (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "SSHTransferFile (UI.Window.ConnectionTreeWindow) failed", + ex); } } @@ -742,7 +777,8 @@ namespace mRemoteNG.UI.Controls if (_connectionTree.SelectedNode == null) selectedNodeAsContainer = Runtime.ConnectionsService.ConnectionTreeModel.RootNodes.First(); else - selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent; + selectedNodeAsContainer = + _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent; Import.ImportFromFile(selectedNodeAsContainer); } @@ -800,14 +836,18 @@ namespace mRemoteNG.UI.Controls { try { - if (_connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.Connection | _connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.PuttySession) + if (_connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.Connection | + _connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.PuttySession) externalTool.Start(_connectionTree.SelectedNode); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenTreeToolsExternalAppsEntry_Click failed (UI.Window.ConnectionTreeWindow)", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "cMenTreeToolsExternalAppsEntry_Click failed (UI.Window.ConnectionTreeWindow)", + ex); } } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs index c24eeeee0..dfd8f21d6 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs @@ -11,6 +11,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Linq; using System.Windows.Forms; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.UI.Controls @@ -19,14 +20,17 @@ namespace mRemoteNG.UI.Controls { private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; - private readonly StatusImageList _statusImageList = new StatusImageList(); - private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = new ConnectionTreeSearchTextFilter(); + private readonly StatusImageList _statusImageList = new StatusImageList(); + + private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = + new ConnectionTreeSearchTextFilter(); + private bool _nodeInEditMode; private bool _allowEdit; private ConnectionContextMenu _contextMenu; private ConnectionTreeModel _connectionTreeModel; - public ConnectionInfo SelectedNode => (ConnectionInfo) SelectedObject; + public ConnectionInfo SelectedNode => (ConnectionInfo)SelectedObject; public NodeSearcher NodeSearcher { get; private set; } @@ -34,9 +38,11 @@ namespace mRemoteNG.UI.Controls public IEnumerable PostSetupActions { get; set; } = new IConnectionTreeDelegate[0]; - public ITreeNodeClickHandler DoubleClickHandler { get; set; } = new TreeNodeCompositeClickHandler(); + public ITreeNodeClickHandler DoubleClickHandler { get; set; } = + new TreeNodeCompositeClickHandler(); - public ITreeNodeClickHandler SingleClickHandler { get; set; } = new TreeNodeCompositeClickHandler(); + public ITreeNodeClickHandler SingleClickHandler { get; set; } = + new TreeNodeCompositeClickHandler(); public ConnectionTreeModel ConnectionTreeModel { @@ -66,11 +72,13 @@ namespace mRemoteNG.UI.Controls components?.Dispose(); _statusImageList?.Dispose(); } + base.Dispose(disposing); } #region ConnectionTree Setup + private void SetupConnectionTreeView() { SmallImageList = _statusImageList.ImageList; @@ -111,14 +119,14 @@ namespace mRemoteNG.UI.Controls { if (!(args.Model is ContainerInfo container)) return; container.IsExpanded = false; - AutoResizeColumn(Columns[0]); - }; + AutoResizeColumn(Columns[0]); + }; Expanded += (sender, args) => { if (!(args.Model is ContainerInfo container)) return; container.IsExpanded = true; - AutoResizeColumn(Columns[0]); - }; + AutoResizeColumn(Columns[0]); + }; SelectionChanged += tvConnections_AfterSelect; MouseDoubleClick += OnMouse_DoubleClick; MouseClick += OnMouse_SingleClick; @@ -129,34 +137,35 @@ namespace mRemoteNG.UI.Controls AfterLabelEdit += OnAfterLabelEdit; } - /// - /// Resizes the given column to ensure that all content is shown - /// - private void AutoResizeColumn(ColumnHeader column) - { - if (InvokeRequired) - { - Invoke((MethodInvoker) (() => AutoResizeColumn(column))); - return; - } + /// + /// Resizes the given column to ensure that all content is shown + /// + private void AutoResizeColumn(ColumnHeader column) + { + if (InvokeRequired) + { + Invoke((MethodInvoker)(() => AutoResizeColumn(column))); + return; + } - var longestIndentationAndTextWidth = int.MinValue; - var horizontalScrollOffset = LowLevelScrollPosition.X; - const int padding = 10; + var longestIndentationAndTextWidth = int.MinValue; + var horizontalScrollOffset = LowLevelScrollPosition.X; + const int padding = 10; - for (var i = 0; i < Items.Count; i++) - { - var rowIndentation = Items[i].Position.X; - var rowTextWidth = TextRenderer.MeasureText(Items[i].Text, Font).Width; + for (var i = 0; i < Items.Count; i++) + { + var rowIndentation = Items[i].Position.X; + var rowTextWidth = TextRenderer.MeasureText(Items[i].Text, Font).Width; - longestIndentationAndTextWidth = Math.Max(rowIndentation + rowTextWidth, longestIndentationAndTextWidth); - } + longestIndentationAndTextWidth = + Math.Max(rowIndentation + rowTextWidth, longestIndentationAndTextWidth); + } - column.Width = longestIndentationAndTextWidth + - SmallImageSize.Width + - horizontalScrollOffset + - padding; - } + column.Width = longestIndentationAndTextWidth + + SmallImageSize.Width + + horizontalScrollOffset + + padding; + } private void PopulateTreeView(ConnectionTreeModel newModel) { @@ -164,8 +173,8 @@ namespace mRemoteNG.UI.Controls RegisterModelUpdateHandlers(newModel); NodeSearcher = new NodeSearcher(newModel); ExecutePostSetupActions(); - AutoResizeColumn(Columns[0]); - } + AutoResizeColumn(Columns[0]); + } private void RegisterModelUpdateHandlers(ConnectionTreeModel newModel) { @@ -196,8 +205,8 @@ namespace mRemoteNG.UI.Controls // Removed "TO DO" from above comment. Per #142 it apperas that this no longer occurs with ObjectListView 2.9.1 var property = propertyChangedEventArgs.PropertyName; if (property != nameof(ConnectionInfo.Name) - && property != nameof(ConnectionInfo.OpenConnections) - && property != nameof(ConnectionInfo.Icon)) + && property != nameof(ConnectionInfo.OpenConnections) + && property != nameof(ConnectionInfo.Icon)) { return; } @@ -206,8 +215,8 @@ namespace mRemoteNG.UI.Controls return; RefreshObject(senderAsConnectionInfo); - AutoResizeColumn(Columns[0]); - } + AutoResizeColumn(Columns[0]); + } private void ExecutePostSetupActions() { @@ -216,9 +225,11 @@ namespace mRemoteNG.UI.Controls action.Execute(this); } } + #endregion #region ConnectionTree Behavior + public RootNodeInfo GetRootConnectionNode() { return (RootNodeInfo)ConnectionTreeModel.RootNodes.First(item => item is RootNodeInfo); @@ -270,7 +281,8 @@ namespace mRemoteNG.UI.Controls private void AddNode(ConnectionInfo newNode) { - if (SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttyRoot || SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttySession) + if (SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttyRoot || + SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttySession) return; // the new node will survive filtering if filtering is active @@ -370,19 +382,19 @@ namespace mRemoteNG.UI.Controls private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { - // disable filtering if necessary. prevents RefreshObjects from - // throwing an exception - var filteringEnabled = IsFiltering; - var filter = ModelFilter; - if (filteringEnabled) - { - ResetColumnFiltering(); - } + // disable filtering if necessary. prevents RefreshObjects from + // throwing an exception + var filteringEnabled = IsFiltering; + var filter = ModelFilter; + if (filteringEnabled) + { + ResetColumnFiltering(); + } - RefreshObject(sender); - AutoResizeColumn(Columns[0]); + RefreshObject(sender); + AutoResizeColumn(Columns[0]); - // turn filtering back on + // turn filtering back on if (!filteringEnabled) return; ModelFilter = filter; UpdateFiltering(); @@ -402,7 +414,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterSelect (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "tvConnections_AfterSelect (UI.Window.ConnectionTreeWindow) failed", + ex); } } @@ -442,7 +456,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_MouseMove (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "tvConnections_MouseMove (UI.Window.ConnectionTreeWindow) failed", + ex); } } @@ -479,9 +495,12 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterLabelEdit (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "tvConnections_AfterLabelEdit (UI.Window.ConnectionTreeWindow) failed", + ex); } } + #endregion } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs index 425c329db..f2d782e6c 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs @@ -30,4 +30,4 @@ namespace mRemoteNG.UI.Controls objectAsConnectionInfo.Description.ToLowerInvariant().Contains(filterTextLower); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs index 77643a1e5..bf063f54b 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs @@ -1,5 +1,4 @@ - -namespace mRemoteNG.UI.Controls +namespace mRemoteNG.UI.Controls { public interface IConnectionTreeDelegate { diff --git a/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs b/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs index ca275a040..848bfa2c7 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs @@ -3,13 +3,13 @@ using mRemoteNG.Connection; namespace mRemoteNG.UI.Controls { - public class NameColumn : OLVColumn + public class NameColumn : OLVColumn { public NameColumn(ImageGetterDelegate imageGetterDelegate) { AspectName = "Name"; FillsFreeSpace = false; - AspectGetter = item => ((ConnectionInfo) item).Name; + AspectGetter = item => ((ConnectionInfo)item).Name; ImageGetter = imageGetterDelegate; AutoCompleteEditor = false; } diff --git a/mRemoteV1/UI/Controls/CredentialRecordListBox.cs b/mRemoteV1/UI/Controls/CredentialRecordListBox.cs index fd0aeb19a..2b863c5a2 100644 --- a/mRemoteV1/UI/Controls/CredentialRecordListBox.cs +++ b/mRemoteV1/UI/Controls/CredentialRecordListBox.cs @@ -8,8 +8,8 @@ namespace mRemoteNG.UI.Controls public partial class CredentialRecordListBox : ListBox { public new ICredentialRecord SelectedItem => (ICredentialRecord)base.SelectedItem; - public ICredentialRecord NoneSelection { get; } = new CredentialRecord { Title = $"--{Language.strNone}--" }; - public ICredentialRecord AddNewSelection { get; } = new CredentialRecord { Title = $"--{Language.strAdd}--" }; + public ICredentialRecord NoneSelection { get; } = new CredentialRecord {Title = $"--{Language.strNone}--"}; + public ICredentialRecord AddNewSelection { get; } = new CredentialRecord {Title = $"--{Language.strAdd}--"}; public CredentialRecordListBox(IEnumerable listOfCredentialRecords) { diff --git a/mRemoteV1/UI/Controls/CredentialRecordListView.cs b/mRemoteV1/UI/Controls/CredentialRecordListView.cs index 42d20d3cc..8507a95f9 100644 --- a/mRemoteV1/UI/Controls/CredentialRecordListView.cs +++ b/mRemoteV1/UI/Controls/CredentialRecordListView.cs @@ -28,11 +28,12 @@ namespace mRemoteNG.UI.Controls } } - public KeyValuePair SelectedObject => CastRowObject(objectListView1.SelectedObject); + public KeyValuePair SelectedObject => + CastRowObject(objectListView1.SelectedObject); - public IEnumerable> SelectedObjects => + public IEnumerable> SelectedObjects => from object item - in objectListView1.SelectedObjects + in objectListView1.SelectedObjects select CastRowObject(item); public bool MultipleObjectsSelected => objectListView1.SelectedObjects.Count > 1; @@ -115,28 +116,35 @@ namespace mRemoteNG.UI.Controls private KeyValuePair CastRowObject(object model) { - if (!(model is KeyValuePair)) return default(KeyValuePair); + if (!(model is KeyValuePair)) + return default(KeyValuePair); var keyValuePair = (KeyValuePair)model; return keyValuePair; } - private void CredentialRepositoryListOnRepositoriesUpdated(object sender, CollectionUpdatedEventArgs arg) + private void CredentialRepositoryListOnRepositoriesUpdated(object sender, + CollectionUpdatedEventArgs + arg) { SetObjectList(); } - private void CredentialRepositoryListOnCredentialsUpdated(object sender, CollectionUpdatedEventArgs collectionUpdatedEventArgs) + private void CredentialRepositoryListOnCredentialsUpdated(object sender, + CollectionUpdatedEventArgs + collectionUpdatedEventArgs) { SetObjectList(); } public event EventHandler SelectionChanged; + private void RaiseSelectionChangedEvent() { SelectionChanged?.Invoke(this, EventArgs.Empty); } public event EventHandler CellClick; + private void RaiseCellClickEvent(object sender, CellClickEventArgs args) { CellClick?.Invoke(sender, args); diff --git a/mRemoteV1/UI/Controls/CredentialRepositoryListView.cs b/mRemoteV1/UI/Controls/CredentialRepositoryListView.cs index 725fbe352..74805d0b4 100644 --- a/mRemoteV1/UI/Controls/CredentialRepositoryListView.cs +++ b/mRemoteV1/UI/Controls/CredentialRepositoryListView.cs @@ -28,7 +28,7 @@ namespace mRemoteNG.UI.Controls public Func RepositoryFilter { get; set; } public ICredentialRepository SelectedRepository => GetSelectedRepository(); - public Func DoubleClickHandler { get; set; } + public Func DoubleClickHandler { get; set; } public CredentialRepositoryListView() { @@ -44,11 +44,11 @@ namespace mRemoteNG.UI.Controls private void SetupObjectListView() { - olvColumnTitle.AspectGetter = rowObject => ((ICredentialRepository) rowObject).Config.Title; - olvColumnProvider.AspectGetter = rowObject => ((ICredentialRepository) rowObject).Config.TypeName; - olvColumnSource.AspectGetter = rowObject => ((ICredentialRepository) rowObject).Config.Source; - olvColumnId.AspectGetter = rowObject => ((ICredentialRepository) rowObject).Config.Id; - olvColumnIsLoaded.AspectGetter = rowObject => ((ICredentialRepository) rowObject).IsLoaded; + olvColumnTitle.AspectGetter = rowObject => ((ICredentialRepository)rowObject).Config.Title; + olvColumnProvider.AspectGetter = rowObject => ((ICredentialRepository)rowObject).Config.TypeName; + olvColumnSource.AspectGetter = rowObject => ((ICredentialRepository)rowObject).Config.Source; + olvColumnId.AspectGetter = rowObject => ((ICredentialRepository)rowObject).Config.Id; + olvColumnIsLoaded.AspectGetter = rowObject => ((ICredentialRepository)rowObject).IsLoaded; SetListObjects(CredentialRepositoryList.CredentialProviders); objectListView1.SelectionChanged += (sender, args) => RaiseSelectionChangedEvent(); objectListView1.MouseDoubleClick += ObjectListView1OnMouseDoubleClick; @@ -61,9 +61,7 @@ namespace mRemoteNG.UI.Controls private void SetListObjects(IEnumerable repositories) { - var filteredRepositories = RepositoryFilter == null ? - repositories : - repositories.Where(RepositoryFilter); + var filteredRepositories = RepositoryFilter == null ? repositories : repositories.Where(RepositoryFilter); objectListView1.SetObjects(filteredRepositories); } @@ -83,6 +81,7 @@ namespace mRemoteNG.UI.Controls } public event EventHandler SelectionChanged; + private void RaiseSelectionChangedEvent() { SelectionChanged?.Invoke(this, EventArgs.Empty); @@ -95,6 +94,7 @@ namespace mRemoteNG.UI.Controls _credentialRepositoryList.RepositoriesUpdated -= OnRepositoriesUpdated; components?.Dispose(); } + base.Dispose(disposing); } } diff --git a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs index cd198e917..91a35a5e9 100644 --- a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs +++ b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs @@ -17,7 +17,8 @@ namespace mRemoteNG.UI.Controls public ExternalToolsToolStrip() { Initialize(); - Runtime.ExternalToolsService.ExternalTools.CollectionUpdated += (sender, args) => AddExternalToolsToToolBar(); + Runtime.ExternalToolsService.ExternalTools.CollectionUpdated += + (sender, args) => AddExternalToolsToToolBar(); } private void Initialize() @@ -53,6 +54,7 @@ namespace mRemoteNG.UI.Controls } #region Ext Apps Toolbar + private void cMenToolbarShowText_Click(object sender, EventArgs e) { SwitchToolBarText(!CMenToolbarShowText.Checked); @@ -75,7 +77,9 @@ namespace mRemoteNG.UI.Controls if (CMenToolbarShowText.Checked) button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; else - button.DisplayStyle = button.Image != null ? ToolStripItemDisplayStyle.Image : ToolStripItemDisplayStyle.ImageAndText; + button.DisplayStyle = button.Image != null + ? ToolStripItemDisplayStyle.Image + : ToolStripItemDisplayStyle.ImageAndText; button.Tag = tool; } @@ -100,7 +104,9 @@ namespace mRemoteNG.UI.Controls extA.Start(selectedTreeNode); else { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "No connection was selected, external tool may return errors.", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + "No connection was selected, external tool may return errors.", + true); extA.Start(); } } @@ -112,15 +118,19 @@ namespace mRemoteNG.UI.Controls if (show) tItem.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; else - tItem.DisplayStyle = tItem.Image != null ? ToolStripItemDisplayStyle.Image : ToolStripItemDisplayStyle.ImageAndText; + tItem.DisplayStyle = tItem.Image != null + ? ToolStripItemDisplayStyle.Image + : ToolStripItemDisplayStyle.ImageAndText; } CMenToolbarShowText.Checked = show; } + #endregion // CodeAyalysis doesn't like null propagation - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "components")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", + MessageId = "components")] protected override void Dispose(bool disposing) { try diff --git a/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs b/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs index 57c745386..32b919cb3 100644 --- a/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs +++ b/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs @@ -12,191 +12,206 @@ namespace mRemoteNG.UI.Controls.FilteredPropertyGrid /// It also allows to hide (or filter) the properties of the SelectedObject displayed by the PropertyGrid. /// public partial class FilteredPropertyGrid : PropertyGrid - { - /// - /// Contain a reference to the collection of properties to show in the parent PropertyGrid. - /// - /// By default, m_PropertyDescriptors contain all the properties of the object. - readonly List _propertyDescriptors = new List(); + { + /// + /// Contain a reference to the collection of properties to show in the parent PropertyGrid. + /// + /// By default, m_PropertyDescriptors contain all the properties of the object. + readonly List _propertyDescriptors = new List(); - /// - /// Contain a reference to the array of properties to display in the PropertyGrid. - /// - private AttributeCollection _hiddenAttributes; - private AttributeCollection _browsableAttributes; + /// + /// Contain a reference to the array of properties to display in the PropertyGrid. + /// + private AttributeCollection _hiddenAttributes; - /// - /// Contain references to the arrays of properties or categories to hide. - /// - private string[] _mBrowsableProperties; - private string[] _mHiddenProperties; - /// - /// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid. - /// - private ObjectWrapper _mWrapper; + private AttributeCollection _browsableAttributes; - /// - /// Public constructor. - /// - public FilteredPropertyGrid() - { - InitializeComponent(); - base.SelectedObject = _mWrapper; - } + /// + /// Contain references to the arrays of properties or categories to hide. + /// + private string[] _mBrowsableProperties; - /// - /// A list of all currently properties being shown by the property grid. - /// - public IEnumerable VisibleProperties => _propertyDescriptors.Select(p => p.Name); + private string[] _mHiddenProperties; - public new AttributeCollection BrowsableAttributes { - get => _browsableAttributes; - set { - if (_browsableAttributes == value) return; - _hiddenAttributes = null; - _browsableAttributes = value; - RefreshProperties(); - } - } + /// + /// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid. + /// + private ObjectWrapper _mWrapper; - /// - /// Get or set the categories to hide. - /// - public AttributeCollection HiddenAttributes { - get => _hiddenAttributes; - set { - if (value == _hiddenAttributes) return; - _hiddenAttributes = value; - _browsableAttributes = null; - RefreshProperties(); - } - } + /// + /// Public constructor. + /// + public FilteredPropertyGrid() + { + InitializeComponent(); + base.SelectedObject = _mWrapper; + } - /// - /// Get or set the properties to show. - /// - /// if one or several properties don't exist. - public string[] BrowsableProperties { - get => _mBrowsableProperties; - set { - if (value == _mBrowsableProperties) return; - _mBrowsableProperties = value; - RefreshProperties(); - } - } + /// + /// A list of all currently properties being shown by the property grid. + /// + public IEnumerable VisibleProperties => _propertyDescriptors.Select(p => p.Name); - /// Get or set the properties to hide. - public string[] HiddenProperties { - get => _mHiddenProperties; - set { - if (value == _mHiddenProperties) return; - _mHiddenProperties = value; - RefreshProperties(); - } - } + public new AttributeCollection BrowsableAttributes + { + get => _browsableAttributes; + set + { + if (_browsableAttributes == value) return; + _hiddenAttributes = null; + _browsableAttributes = value; + RefreshProperties(); + } + } - /// - /// Overwrite the PropertyGrid.SelectedObject property. - /// - /// The object passed to the base PropertyGrid is the wrapper. - public new object SelectedObject { - get => - _mWrapper != null - ? ((ObjectWrapper)base.SelectedObject).SelectedObject + /// + /// Get or set the categories to hide. + /// + public AttributeCollection HiddenAttributes + { + get => _hiddenAttributes; + set + { + if (value == _hiddenAttributes) return; + _hiddenAttributes = value; + _browsableAttributes = null; + RefreshProperties(); + } + } + + /// + /// Get or set the properties to show. + /// + /// if one or several properties don't exist. + public string[] BrowsableProperties + { + get => _mBrowsableProperties; + set + { + if (value == _mBrowsableProperties) return; + _mBrowsableProperties = value; + RefreshProperties(); + } + } + + /// Get or set the properties to hide. + public string[] HiddenProperties + { + get => _mHiddenProperties; + set + { + if (value == _mHiddenProperties) return; + _mHiddenProperties = value; + RefreshProperties(); + } + } + + /// + /// Overwrite the PropertyGrid.SelectedObject property. + /// + /// The object passed to the base PropertyGrid is the wrapper. + public new object SelectedObject + { + get => + _mWrapper != null + ? ((ObjectWrapper)base.SelectedObject).SelectedObject : null; - set { - // Set the new object to the wrapper and create one if necessary. - if(_mWrapper == null) - { - _mWrapper = new ObjectWrapper(value); - RefreshProperties(); - } - else if(_mWrapper.SelectedObject != value) - { - var needrefresh = value.GetType() != _mWrapper.SelectedObject.GetType(); - _mWrapper.SelectedObject = value; - if(needrefresh) - RefreshProperties(); - } - // Set the list of properties to the wrapper. - _mWrapper.PropertyDescriptors = _propertyDescriptors; - // Link the wrapper to the parent PropertyGrid. - base.SelectedObject = _mWrapper; - } - } + set + { + // Set the new object to the wrapper and create one if necessary. + if (_mWrapper == null) + { + _mWrapper = new ObjectWrapper(value); + RefreshProperties(); + } + else if (_mWrapper.SelectedObject != value) + { + var needrefresh = value.GetType() != _mWrapper.SelectedObject.GetType(); + _mWrapper.SelectedObject = value; + if (needrefresh) + RefreshProperties(); + } - /// - /// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties. - /// - private void RefreshProperties() - { - if(_mWrapper == null) - return; + // Set the list of properties to the wrapper. + _mWrapper.PropertyDescriptors = _propertyDescriptors; + // Link the wrapper to the parent PropertyGrid. + base.SelectedObject = _mWrapper; + } + } - // Clear the list of properties to be displayed. - _propertyDescriptors.Clear(); - // Check whether the list is filtered - if(_browsableAttributes != null && _browsableAttributes.Count > 0) - { - // Add to the list the attributes that need to be displayed. - foreach(Attribute attribute in _browsableAttributes) - ShowAttribute(attribute); - } - else - { - // Fill the collection with all the properties. - var originalPropertyDescriptors = TypeDescriptor - .GetProperties(_mWrapper.SelectedObject) - .OfType() - .Where(PropertyDoesntHaveBrowsableFalseAttribute); + /// + /// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties. + /// + private void RefreshProperties() + { + if (_mWrapper == null) + return; - foreach(PropertyDescriptor propertyDescriptor in originalPropertyDescriptors) - _propertyDescriptors.Add(propertyDescriptor); + // Clear the list of properties to be displayed. + _propertyDescriptors.Clear(); + // Check whether the list is filtered + if (_browsableAttributes != null && _browsableAttributes.Count > 0) + { + // Add to the list the attributes that need to be displayed. + foreach (Attribute attribute in _browsableAttributes) + ShowAttribute(attribute); + } + else + { + // Fill the collection with all the properties. + var originalPropertyDescriptors = TypeDescriptor + .GetProperties(_mWrapper.SelectedObject) + .OfType() + .Where(PropertyDoesntHaveBrowsableFalseAttribute); - // Remove from the list the attributes that mustn't be displayed. - if(_hiddenAttributes != null) - foreach (Attribute attribute in _hiddenAttributes) - HideAttribute(attribute); - } + foreach (PropertyDescriptor propertyDescriptor in originalPropertyDescriptors) + _propertyDescriptors.Add(propertyDescriptor); - // Get all the properties of the SelectedObject - var allproperties = TypeDescriptor.GetProperties(_mWrapper.SelectedObject); - - // Hide if necessary, some properties - if(_mHiddenProperties != null && _mHiddenProperties.Length > 0) - { - // Remove from the list the properties that mustn't be displayed. - foreach(var propertyname in _mHiddenProperties) - { - try - { - var property = allproperties[propertyname]; - // Remove from the list the property - HideProperty(property); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Could not hide Property.", ex); + // Remove from the list the attributes that mustn't be displayed. + if (_hiddenAttributes != null) + foreach (Attribute attribute in _hiddenAttributes) + HideAttribute(attribute); + } + + // Get all the properties of the SelectedObject + var allproperties = TypeDescriptor.GetProperties(_mWrapper.SelectedObject); + + // Hide if necessary, some properties + if (_mHiddenProperties != null && _mHiddenProperties.Length > 0) + { + // Remove from the list the properties that mustn't be displayed. + foreach (var propertyname in _mHiddenProperties) + { + try + { + var property = allproperties[propertyname]; + // Remove from the list the property + HideProperty(property); } - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Could not hide Property.", + ex); + } + } + } - // Display if necessary, some properties - if(_mBrowsableProperties != null && _mBrowsableProperties.Length > 0) - { - foreach(var propertyname in _mBrowsableProperties) - { - try - { - ShowProperty(allproperties[propertyname]); - } - catch (Exception ex) - { + // Display if necessary, some properties + if (_mBrowsableProperties != null && _mBrowsableProperties.Length > 0) + { + foreach (var propertyname in _mBrowsableProperties) + { + try + { + ShowProperty(allproperties[propertyname]); + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Property not found", ex); - } - } - } - } + } + } + } + } /// /// Predicate to determine if a property has a Browsable(false) attribute @@ -204,25 +219,26 @@ namespace mRemoteNG.UI.Controls.FilteredPropertyGrid /// /// /// - private bool PropertyDoesntHaveBrowsableFalseAttribute(PropertyDescriptor propertyDescriptor) - { - return !propertyDescriptor.Attributes.Contains(new BrowsableAttribute(false)); - } + private bool PropertyDoesntHaveBrowsableFalseAttribute(PropertyDescriptor propertyDescriptor) + { + return !propertyDescriptor.Attributes.Contains(new BrowsableAttribute(false)); + } - /// + /// /// Allows to hide a set of properties to the parent PropertyGrid. /// /// A set of attributes that filter the original collection of properties. /// For better performance, include the BrowsableAttribute with true value. private void HideAttribute(Attribute attribute) { - var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute }); - if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) - throw new ArgumentException("Attribute not found", attribute.ToString()); + var filteredoriginalpropertydescriptors = + TypeDescriptor.GetProperties(_mWrapper.SelectedObject, new[] {attribute}); + if (filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) + throw new ArgumentException("Attribute not found", attribute.ToString()); - foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) - HideProperty(propertydescriptor); - } + foreach (PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) + HideProperty(propertydescriptor); + } /// /// Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid. @@ -230,23 +246,24 @@ namespace mRemoteNG.UI.Controls.FilteredPropertyGrid /// The attribute to be added. private void ShowAttribute(Attribute attribute) { - var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute }); - if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) - throw new ArgumentException("Attribute not found", attribute.ToString()); + var filteredoriginalpropertydescriptors = + TypeDescriptor.GetProperties(_mWrapper.SelectedObject, new[] {attribute}); + if (filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) + throw new ArgumentException("Attribute not found", attribute.ToString()); - foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) - ShowProperty(propertydescriptor); - } + foreach (PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) + ShowProperty(propertydescriptor); + } - /// - /// Add a property to the list of properties to be displayed in the PropertyGrid. - /// - /// The property to be added. - private void ShowProperty(PropertyDescriptor property) - { - if(!_propertyDescriptors.Contains(property)) - _propertyDescriptors.Add(property); - } + /// + /// Add a property to the list of properties to be displayed in the PropertyGrid. + /// + /// The property to be added. + private void ShowProperty(PropertyDescriptor property) + { + if (!_propertyDescriptors.Contains(property)) + _propertyDescriptors.Add(property); + } /// /// Allows to hide a property to the parent PropertyGrid. @@ -254,8 +271,8 @@ namespace mRemoteNG.UI.Controls.FilteredPropertyGrid /// The name of the property to be hidden. private void HideProperty(PropertyDescriptor property) { - if(_propertyDescriptors.Contains(property)) - _propertyDescriptors.Remove(property); - } - } + if (_propertyDescriptors.Contains(property)) + _propertyDescriptors.Remove(property); + } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs b/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs index a67abef46..221edec33 100644 --- a/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs +++ b/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs @@ -8,115 +8,117 @@ namespace mRemoteNG.UI.Controls.FilteredPropertyGrid /// This class is a wrapper. It contains the object the PropertyGrid has to display. /// internal class ObjectWrapper : ICustomTypeDescriptor - { - /// - /// Creates a new instance of an with the given object to be wrapped. - /// - /// A reference to the selected object that will linked to the parent PropertyGrid. - internal ObjectWrapper(object obj) - { - SelectedObject = obj; - } + { + /// + /// Creates a new instance of an with the given object to be wrapped. + /// + /// A reference to the selected object that will linked to the parent PropertyGrid. + internal ObjectWrapper(object obj) + { + SelectedObject = obj; + } - /// - /// Get or set a reference to the selected objet that will linked to the parent PropertyGrid. - /// - public object SelectedObject { get; set; } + /// + /// Get or set a reference to the selected objet that will linked to the parent PropertyGrid. + /// + public object SelectedObject { get; set; } - /// - /// Get or set a reference to the collection of properties to show in the parent PropertyGrid - /// - public List PropertyDescriptors { get; set; } = new List(); + /// + /// Get or set a reference to the collection of properties to show in the parent PropertyGrid + /// + public List PropertyDescriptors { get; set; } = new List(); - #region ICustomTypeDescriptor Members - public PropertyDescriptorCollection GetProperties(Attribute[] attributes) - { - return GetProperties(); - } + #region ICustomTypeDescriptor Members - public PropertyDescriptorCollection GetProperties() - { - return new PropertyDescriptorCollection(PropertyDescriptors.ToArray(), true); - } + public PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { + return GetProperties(); + } - /// - /// GetAttributes - /// - /// AttributeCollection - public AttributeCollection GetAttributes() - { - return TypeDescriptor.GetAttributes(SelectedObject, true); - } + public PropertyDescriptorCollection GetProperties() + { + return new PropertyDescriptorCollection(PropertyDescriptors.ToArray(), true); + } - /// - /// Get Class Name - /// - /// String - public string GetClassName() - { - return TypeDescriptor.GetClassName(SelectedObject, true); - } + /// + /// GetAttributes + /// + /// AttributeCollection + public AttributeCollection GetAttributes() + { + return TypeDescriptor.GetAttributes(SelectedObject, true); + } - /// - /// GetComponentName - /// - /// String - public string GetComponentName() - { - return TypeDescriptor.GetComponentName(SelectedObject, true); - } + /// + /// Get Class Name + /// + /// String + public string GetClassName() + { + return TypeDescriptor.GetClassName(SelectedObject, true); + } - /// - /// GetConverter - /// - /// TypeConverter - public TypeConverter GetConverter() - { - return TypeDescriptor.GetConverter(SelectedObject, true); - } + /// + /// GetComponentName + /// + /// String + public string GetComponentName() + { + return TypeDescriptor.GetComponentName(SelectedObject, true); + } - /// - /// GetDefaultEvent - /// - /// EventDescriptor - public EventDescriptor GetDefaultEvent() - { - return TypeDescriptor.GetDefaultEvent(SelectedObject, true); - } + /// + /// GetConverter + /// + /// TypeConverter + public TypeConverter GetConverter() + { + return TypeDescriptor.GetConverter(SelectedObject, true); + } - /// - /// GetDefaultProperty - /// - /// PropertyDescriptor - public PropertyDescriptor GetDefaultProperty() - { - return TypeDescriptor.GetDefaultProperty(SelectedObject, true); - } + /// + /// GetDefaultEvent + /// + /// EventDescriptor + public EventDescriptor GetDefaultEvent() + { + return TypeDescriptor.GetDefaultEvent(SelectedObject, true); + } - /// - /// GetEditor - /// - /// editorBaseType - /// object - public object GetEditor(Type editorBaseType) - { - return TypeDescriptor.GetEditor(this,editorBaseType, true); - } + /// + /// GetDefaultProperty + /// + /// PropertyDescriptor + public PropertyDescriptor GetDefaultProperty() + { + return TypeDescriptor.GetDefaultProperty(SelectedObject, true); + } - public EventDescriptorCollection GetEvents(Attribute[] attributes) - { - return TypeDescriptor.GetEvents(SelectedObject, attributes, true); - } + /// + /// GetEditor + /// + /// editorBaseType + /// object + public object GetEditor(Type editorBaseType) + { + return TypeDescriptor.GetEditor(this, editorBaseType, true); + } - public EventDescriptorCollection GetEvents() - { - return TypeDescriptor.GetEvents(SelectedObject, true); - } + public EventDescriptorCollection GetEvents(Attribute[] attributes) + { + return TypeDescriptor.GetEvents(SelectedObject, attributes, true); + } - public object GetPropertyOwner(PropertyDescriptor pd) - { - return SelectedObject; - } - #endregion - } -} + public EventDescriptorCollection GetEvents() + { + return TypeDescriptor.GetEvents(SelectedObject, true); + } + + public object GetPropertyOwner(PropertyDescriptor pd) + { + return SelectedObject; + } + + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/HeadlessTabControl.cs b/mRemoteV1/UI/Controls/HeadlessTabControl.cs index d9c821bae..07b06960c 100644 --- a/mRemoteV1/UI/Controls/HeadlessTabControl.cs +++ b/mRemoteV1/UI/Controls/HeadlessTabControl.cs @@ -21,9 +21,9 @@ namespace mRemoteNG.UI.Controls // // HeadlessTabControl // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/IPTextBox.cs b/mRemoteV1/UI/Controls/IPTextBox.cs index 055a61aa9..b3f31ad7a 100644 --- a/mRemoteV1/UI/Controls/IPTextBox.cs +++ b/mRemoteV1/UI/Controls/IPTextBox.cs @@ -2,73 +2,74 @@ * http://www.codeproject.com/Articles/11576/IP-TextBox * Original Author: mawnkay */ + using System; using System.Windows.Forms; using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls { - /* class IPTextBox - * An IP Address Box - * A TextBox that only allows entry of a valid ip address - */ - public class IPTextBox: UserControl - { - private Panel panel1; - public Base.NGTextBox Octet1; - public Base.NGTextBox Octet2; - public Base.NGTextBox Octet3; - public Base.NGTextBox Octet4; + /* class IPTextBox + * An IP Address Box + * A TextBox that only allows entry of a valid ip address + */ + public class IPTextBox : UserControl + { + private Panel panel1; + public Base.NGTextBox Octet1; + public Base.NGTextBox Octet2; + public Base.NGTextBox Octet3; + public Base.NGTextBox Octet4; private Base.NGLabel label1; private Base.NGLabel label2; - private Base.NGLabel label3; - private ToolTip toolTip1; - private System.ComponentModel.IContainer components; + private Base.NGLabel label3; + private ToolTip toolTip1; + private System.ComponentModel.IContainer components; - /* Sets and Gets the tooltiptext on toolTip1 */ - public string ToolTipText - { - get => toolTip1.GetToolTip(Octet1); - set - { - toolTip1.SetToolTip(Octet1,value); - toolTip1.SetToolTip(Octet2,value); - toolTip1.SetToolTip(Octet3,value); - toolTip1.SetToolTip(Octet4,value); - toolTip1.SetToolTip(label1,value); - toolTip1.SetToolTip(label2,value); - toolTip1.SetToolTip(label3,value); - } - } + /* Sets and Gets the tooltiptext on toolTip1 */ + public string ToolTipText + { + get => toolTip1.GetToolTip(Octet1); + set + { + toolTip1.SetToolTip(Octet1, value); + toolTip1.SetToolTip(Octet2, value); + toolTip1.SetToolTip(Octet3, value); + toolTip1.SetToolTip(Octet4, value); + toolTip1.SetToolTip(label1, value); + toolTip1.SetToolTip(label2, value); + toolTip1.SetToolTip(label3, value); + } + } - /* Set or Get the string that represents the value in the box */ - public override string Text - { - get => Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text; - set - { - if (!string.IsNullOrEmpty(value)) - { - var pieces = value.Split(@".".ToCharArray(),4); - Octet1.Text = pieces[0]; - Octet2.Text = pieces[1]; - Octet3.Text = pieces[2]; - Octet4.Text = pieces[3]; - } - else - { - Octet1.Text = ""; - Octet2.Text = ""; - Octet3.Text = ""; - Octet4.Text = ""; - } - } - } + /* Set or Get the string that represents the value in the box */ + public override string Text + { + get => Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text; + set + { + if (!string.IsNullOrEmpty(value)) + { + var pieces = value.Split(@".".ToCharArray(), 4); + Octet1.Text = pieces[0]; + Octet2.Text = pieces[1]; + Octet3.Text = pieces[2]; + Octet4.Text = pieces[3]; + } + else + { + Octet1.Text = ""; + Octet2.Text = ""; + Octet3.Text = ""; + Octet4.Text = ""; + } + } + } - public IPTextBox() - { - // This call is required by the Windows.Forms Form Designer. - InitializeComponent(); + public IPTextBox() + { + // This call is required by the Windows.Forms Form Designer. + InitializeComponent(); } protected override void OnLoad(EventArgs e) @@ -83,23 +84,25 @@ namespace mRemoteNG.UI.Controls if (!ThemeManager.getInstance().ActiveAndExtended) return; panel1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } - protected override void Dispose( bool disposing ) - { - if( disposing ) - { - // ReSharper disable once UseNullPropagation - if(components != null) - components.Dispose(); - } - base.Dispose( disposing ); - } - #region Component Designer generated code - - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - private void InitializeComponent() - { + protected override void Dispose(bool disposing) + { + if (disposing) + { + // ReSharper disable once UseNullPropagation + if (components != null) + components.Dispose(); + } + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + private void InitializeComponent() + { this.components = new System.ComponentModel.Container(); this.panel1 = new System.Windows.Forms.Panel(); this.Octet4 = new mRemoteNG.UI.Controls.Base.NGTextBox(); @@ -178,7 +181,8 @@ namespace mRemoteNG.UI.Controls // this.Octet1.BackColor = System.Drawing.SystemColors.Menu; this.Octet1.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.Octet1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Octet1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Octet1.Location = new System.Drawing.Point(1, 1); this.Octet1.MaxLength = 3; this.Octet1.Name = "Octet1"; @@ -215,14 +219,15 @@ namespace mRemoteNG.UI.Controls // IPTextBox // this.Controls.Add(this.panel1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "IPTextBox"; this.Size = new System.Drawing.Size(124, 18); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); this.ResumeLayout(false); + } - } #endregion /* IsValid(string inString) @@ -232,185 +237,186 @@ namespace mRemoteNG.UI.Controls * endif */ private static bool IsValid(string inString) - { - try - { - var theValue = int.Parse(inString); - if(theValue >=0 && theValue <= 255) - return true; + { + try + { + var theValue = int.Parse(inString); + if (theValue >= 0 && theValue <= 255) + return true; - MessageBox.Show(Language.strIPRange,Language.strOutOfRange); - return false; - } - catch - { - return false; - } - } + MessageBox.Show(Language.strIPRange, Language.strOutOfRange); + return false; + } + catch + { + return false; + } + } - /* Performs KeyPress analysis and handling to ensure a valid ip octet is - * being entered in Box1. + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box1. */ - private void Box1_KeyPress(object sender, KeyPressEventArgs e) - { - //Only Accept a '.', a numeral, or backspace - if(e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) - { - //If the key pressed is a '.' - if(e.KeyChar.ToString() == ".") - { - //If the Text is a valid ip octet move to the next box - if(Octet1.Text != "" && Octet1.Text.Length != Octet1.SelectionLength) - { - if(IsValid(Octet1.Text)) - Octet2.Focus(); - else - Octet1.SelectAll(); - } - e.Handled = true; - } + private void Box1_KeyPress(object sender, KeyPressEventArgs e) + { + //Only Accept a '.', a numeral, or backspace + if (e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) + { + //If the key pressed is a '.' + if (e.KeyChar.ToString() == ".") + { + //If the Text is a valid ip octet move to the next box + if (Octet1.Text != "" && Octet1.Text.Length != Octet1.SelectionLength) + { + if (IsValid(Octet1.Text)) + Octet2.Focus(); + else + Octet1.SelectAll(); + } - //If we are not overwriting the whole text - else if(Octet1.SelectionLength != Octet1.Text.Length) - { - //Check that the new Text value will be a valid - // ip octet then move on to next box - if (Octet1.Text.Length != 2) return; - if(!IsValid(Octet1.Text + e.KeyChar)) - { - Octet1.SelectAll(); - e.Handled = true; - } - else - { - Octet2.Focus(); - } - } - } - //Do nothing if the keypress is not numeral, backspace, or '.' - else - e.Handled = true; - } + e.Handled = true; + } - /* Performs KeyPress analysis and handling to ensure a valid ip octet is - * being entered in Box2. - */ - private void Box2_KeyPress(object sender, KeyPressEventArgs e) - { - //Similar to Box1_KeyPress but in special case for backspace moves cursor - //to the previous box (Box1) - if(e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) - { - if(e.KeyChar.ToString() == ".") - { - if(Octet2.Text != "" && Octet2.Text.Length != Octet2.SelectionLength) - { - if(IsValid(Octet1.Text)) - Octet3.Focus(); - else - Octet2.SelectAll(); - } - e.Handled = true; - } - else if(Octet2.SelectionLength != Octet2.Text.Length) - { - if (Octet2.Text.Length != 2) return; - if(!IsValid(Octet2.Text + e.KeyChar)) - { - Octet2.SelectAll(); - e.Handled = true; - } - else - { - Octet3.Focus(); - } - } - else if(Octet2.Text.Length == 0 && e.KeyChar == 8) - { - Octet1.Focus(); - Octet1.SelectionStart = Octet1.Text.Length; - } - } - else - e.Handled = true; + //If we are not overwriting the whole text + else if (Octet1.SelectionLength != Octet1.Text.Length) + { + //Check that the new Text value will be a valid + // ip octet then move on to next box + if (Octet1.Text.Length != 2) return; + if (!IsValid(Octet1.Text + e.KeyChar)) + { + Octet1.SelectAll(); + e.Handled = true; + } + else + { + Octet2.Focus(); + } + } + } + //Do nothing if the keypress is not numeral, backspace, or '.' + else + e.Handled = true; + } - } + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box2. + */ + private void Box2_KeyPress(object sender, KeyPressEventArgs e) + { + //Similar to Box1_KeyPress but in special case for backspace moves cursor + //to the previous box (Box1) + if (e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) + { + if (e.KeyChar.ToString() == ".") + { + if (Octet2.Text != "" && Octet2.Text.Length != Octet2.SelectionLength) + { + if (IsValid(Octet1.Text)) + Octet3.Focus(); + else + Octet2.SelectAll(); + } - /* Performs KeyPress analysis and handling to ensure a valid ip octet is - * being entered in Box3. - */ - private void Box3_KeyPress(object sender, KeyPressEventArgs e) - { - //Identical to Box2_KeyPress except that previous box is Box2 and - //next box is Box3 - if(e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) - { - if(e.KeyChar.ToString() == ".") - { - if(Octet3.Text != "" && Octet3.SelectionLength != Octet3.Text.Length) - { - if(IsValid(Octet1.Text)) - Octet4.Focus(); - else - Octet3.SelectAll(); - } - e.Handled = true; - } - else if(Octet3.SelectionLength != Octet3.Text.Length) - { - if (Octet3.Text.Length != 2) return; - if(!IsValid(Octet3.Text + e.KeyChar)) - { - Octet3.SelectAll(); - e.Handled = true; - } - else - { - Octet4.Focus(); - } - } - else if(Octet3.Text.Length == 0 && e.KeyChar == 8) - { - Octet2.Focus(); - Octet2.SelectionStart = Octet2.Text.Length; - } - } - else - e.Handled = true; - } + e.Handled = true; + } + else if (Octet2.SelectionLength != Octet2.Text.Length) + { + if (Octet2.Text.Length != 2) return; + if (!IsValid(Octet2.Text + e.KeyChar)) + { + Octet2.SelectAll(); + e.Handled = true; + } + else + { + Octet3.Focus(); + } + } + else if (Octet2.Text.Length == 0 && e.KeyChar == 8) + { + Octet1.Focus(); + Octet1.SelectionStart = Octet1.Text.Length; + } + } + else + e.Handled = true; + } - /* Performs KeyPress analysis and handling to ensure a valid ip octet is - * being entered in Box4. - */ - private void Box4_KeyPress(object sender, KeyPressEventArgs e) - { - //Similar to Box3 but ignores the '.' character and does not advance - //to the next box. Also Box3 is previous box for backspace case. - if(char.IsDigit(e.KeyChar) || e.KeyChar == 8) - { - if(Octet4.SelectionLength != Octet4.Text.Length) - { - if (Octet4.Text.Length != 2) return; - if (IsValid(Octet4.Text + e.KeyChar)) return; - Octet4.SelectAll(); - e.Handled = true; - } - else if(Octet4.Text.Length == 0 && e.KeyChar == 8) - { - Octet3.Focus(); - Octet3.SelectionStart = Octet3.Text.Length; - } - } - else - e.Handled = true; - } + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box3. + */ + private void Box3_KeyPress(object sender, KeyPressEventArgs e) + { + //Identical to Box2_KeyPress except that previous box is Box2 and + //next box is Box3 + if (e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) + { + if (e.KeyChar.ToString() == ".") + { + if (Octet3.Text != "" && Octet3.SelectionLength != Octet3.Text.Length) + { + if (IsValid(Octet1.Text)) + Octet4.Focus(); + else + Octet3.SelectAll(); + } - // Selects All text in a box for overwriting upon entering the box - private void Box_Enter(object sender, EventArgs e) - { - var tb = (TextBox) sender; - tb.SelectAll(); - } + e.Handled = true; + } + else if (Octet3.SelectionLength != Octet3.Text.Length) + { + if (Octet3.Text.Length != 2) return; + if (!IsValid(Octet3.Text + e.KeyChar)) + { + Octet3.SelectAll(); + e.Handled = true; + } + else + { + Octet4.Focus(); + } + } + else if (Octet3.Text.Length == 0 && e.KeyChar == 8) + { + Octet2.Focus(); + Octet2.SelectionStart = Octet2.Text.Length; + } + } + else + e.Handled = true; + } + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box4. + */ + private void Box4_KeyPress(object sender, KeyPressEventArgs e) + { + //Similar to Box3 but ignores the '.' character and does not advance + //to the next box. Also Box3 is previous box for backspace case. + if (char.IsDigit(e.KeyChar) || e.KeyChar == 8) + { + if (Octet4.SelectionLength != Octet4.Text.Length) + { + if (Octet4.Text.Length != 2) return; + if (IsValid(Octet4.Text + e.KeyChar)) return; + Octet4.SelectAll(); + e.Handled = true; + } + else if (Octet4.Text.Length == 0 && e.KeyChar == 8) + { + Octet3.Focus(); + Octet3.SelectionStart = Octet3.Text.Length; + } + } + else + e.Handled = true; + } + + // Selects All text in a box for overwriting upon entering the box + private void Box_Enter(object sender, EventArgs e) + { + var tb = (TextBox)sender; + tb.SelectAll(); + } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs index bb431a1b8..96ade99ce 100644 --- a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs +++ b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs @@ -5,64 +5,68 @@ using mRemoteNG.Tools; namespace mRemoteNG.UI.Controls { - public class MultiSshToolStrip : ToolStrip - { - private IContainer components; - private ToolStripLabel _lblMultiSsh; - private ToolStripTextBox _txtMultiSsh; + public class MultiSshToolStrip : ToolStrip + { + private IContainer components; + private ToolStripLabel _lblMultiSsh; + private ToolStripTextBox _txtMultiSsh; + // ReSharper disable once NotAccessedField.Local private MultiSSHController _multiSshController; - private readonly ThemeManager _themeManager; + private readonly ThemeManager _themeManager; public MultiSshToolStrip() - { - InitializeComponent(); - _themeManager = ThemeManager.getInstance(); - _themeManager.ThemeChanged += ApplyTheme; - ApplyTheme(); + { + InitializeComponent(); + _themeManager = ThemeManager.getInstance(); + _themeManager.ThemeChanged += ApplyTheme; + ApplyTheme(); _multiSshController = new MultiSSHController(_txtMultiSsh); - } + } - private void InitializeComponent() - { - components = new System.ComponentModel.Container(); - _lblMultiSsh = new ToolStripLabel(); - _txtMultiSsh = new ToolStripTextBox(); - SuspendLayout(); - // - // lblMultiSSH - // - _lblMultiSsh.Name = "_lblMultiSsh"; - _lblMultiSsh.Size = new System.Drawing.Size(77, 22); - _lblMultiSsh.Text = "Multi SSH:"; - // - // txtMultiSSH - // - _txtMultiSsh.Name = "_txtMultiSsh"; - _txtMultiSsh.Size = new System.Drawing.Size(new DisplayProperties().ScaleWidth(300), 25); - _txtMultiSsh.ToolTipText = "Press ENTER to send. Ctrl+C is sent immediately."; + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + _lblMultiSsh = new ToolStripLabel(); + _txtMultiSsh = new ToolStripTextBox(); + SuspendLayout(); + // + // lblMultiSSH + // + _lblMultiSsh.Name = "_lblMultiSsh"; + _lblMultiSsh.Size = new System.Drawing.Size(77, 22); + _lblMultiSsh.Text = "Multi SSH:"; + // + // txtMultiSSH + // + _txtMultiSsh.Name = "_txtMultiSsh"; + _txtMultiSsh.Size = new System.Drawing.Size(new DisplayProperties().ScaleWidth(300), 25); + _txtMultiSsh.ToolTipText = "Press ENTER to send. Ctrl+C is sent immediately."; - Items.AddRange(new ToolStripItem[] { - _lblMultiSsh, - _txtMultiSsh}); - ResumeLayout(true); - } + Items.AddRange(new ToolStripItem[] + { + _lblMultiSsh, + _txtMultiSsh + }); + ResumeLayout(true); + } - private void ApplyTheme() - { - if (!_themeManager.ActiveAndExtended) return; + private void ApplyTheme() + { + if (!_themeManager.ActiveAndExtended) return; _txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - _txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - } + _txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + } protected override void Dispose(bool disposing) - { - if (disposing) - { - components?.Dispose(); - } - base.Dispose(disposing); - } - } -} + { + if (disposing) + { + components?.Dispose(); + } + + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/NewPasswordWithVerification.cs b/mRemoteV1/UI/Controls/NewPasswordWithVerification.cs index 16b5faa82..419481b1e 100644 --- a/mRemoteV1/UI/Controls/NewPasswordWithVerification.cs +++ b/mRemoteV1/UI/Controls/NewPasswordWithVerification.cs @@ -13,11 +13,9 @@ namespace mRemoteNG.UI.Controls private char _passwordChar; - [Browsable(false)] - public SecureString SecureString { get; private set; } + [Browsable(false)] public SecureString SecureString { get; private set; } - [Browsable(false)] - public bool PasswordsMatch { get; private set; } + [Browsable(false)] public bool PasswordsMatch { get; private set; } [Browsable(true)] public char PasswordChar @@ -93,6 +91,7 @@ namespace mRemoteNG.UI.Controls PasswordsMatch = false; SecureString = null; } + TogglePasswordMatchIndicator(PasswordsMatch); } diff --git a/mRemoteV1/UI/Controls/PageSequence/PageSequence.cs b/mRemoteV1/UI/Controls/PageSequence/PageSequence.cs index 2384518ec..fe11dc3ee 100644 --- a/mRemoteV1/UI/Controls/PageSequence/PageSequence.cs +++ b/mRemoteV1/UI/Controls/PageSequence/PageSequence.cs @@ -13,7 +13,8 @@ namespace mRemoteNG.UI.Controls.PageSequence public IEnumerable Pages => _pages; public int CurrentPageIndex { get; private set; } - public PageSequence(Control pageContainer, IEnumerable pages) : this(pageContainer, pages.ToArray()) + public PageSequence(Control pageContainer, IEnumerable pages) : this(pageContainer, + pages.ToArray()) { } @@ -59,6 +60,7 @@ namespace mRemoteNG.UI.Controls.PageSequence indexModifier++; break; } + var pageIndexToReplace = CurrentPageIndex + indexModifier; UnsubscribeFromPageEvents(_pages[pageIndexToReplace]); SubscribeToPageEvents(newPage); diff --git a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs index ef6b4075a..4e4f4681f 100644 --- a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs +++ b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs @@ -44,10 +44,10 @@ namespace mRemoteNG.UI.Controls.PageSequence // // SequencedControl // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "SequencedControl"; this.ResumeLayout(false); - } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/QuickConnectComboBox.cs b/mRemoteV1/UI/Controls/QuickConnectComboBox.cs index 2161a1e67..2773849bd 100644 --- a/mRemoteV1/UI/Controls/QuickConnectComboBox.cs +++ b/mRemoteV1/UI/Controls/QuickConnectComboBox.cs @@ -7,235 +7,240 @@ using mRemoteNG.Connection.Protocol; namespace mRemoteNG.UI.Controls { - public class QuickConnectComboBox : ToolStripComboBox - { - private readonly ComboBox _comboBox; - private bool _ignoreEnter; - - public QuickConnectComboBox() - { - _comboBox = ComboBox; - if (_comboBox == null) return; - _comboBox.PreviewKeyDown += ComboBox_PreviewKeyDown; - _comboBox.SelectedIndexChanged += ComboBox_SelectedIndexChanged; - _comboBox.DrawItem += ComboBox_DrawItem; - _comboBox.DrawMode = DrawMode.OwnerDrawFixed; - - // This makes it so that _ignoreEnter works correctly before any items are added to the combo box - _comboBox.Items.Clear(); - } - - private void ComboBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) - { - if (e.KeyCode == Keys.Enter & _comboBox.DroppedDown) - { - _ignoreEnter = true; - } - } - - protected override void OnKeyDown(KeyEventArgs e) - { - base.OnKeyDown(e); - if (e.KeyCode == Keys.Enter) - { - // Only connect if Enter was not pressed while the combo box was dropped down - if (!_ignoreEnter) - { - OnConnectRequested(new ConnectRequestedEventArgs(_comboBox.Text)); - } - _ignoreEnter = false; - e.Handled = true; - } - else if (e.KeyCode == Keys.Delete & _comboBox.DroppedDown) - { - if (_comboBox.SelectedIndex != -1) - { - // Items can't be removed from the ComboBox while it is dropped down without possibly causing - // an exception so we must close it, delete the item, and then drop it down again. When we - // close it programmatically, the SelectedItem may revert to Nothing, so we must save it first. - var item = _comboBox.SelectedItem; - _comboBox.DroppedDown = false; - _comboBox.Items.Remove(item); - _comboBox.SelectedIndex = -1; - if (_comboBox.Items.Count != 0) - { - _comboBox.DroppedDown = true; - } - } - e.Handled = true; - } - } - - private void ComboBox_SelectedIndexChanged(object sender, EventArgs e) - { - if (!(_comboBox.SelectedItem is HistoryItem)) - { - return; - } - var historyItem = (HistoryItem) _comboBox.SelectedItem; - OnProtocolChanged(new ProtocolChangedEventArgs(historyItem.ConnectionInfo.Protocol)); - } - - private static void ComboBox_DrawItem(object sender, DrawItemEventArgs e) - { - var comboBox = sender as ComboBox; - if (comboBox == null) - { - return; - } - var drawItem = comboBox.Items[e.Index]; - - string drawString; - if (drawItem is HistoryItem) - { - var historyItem = (HistoryItem) drawItem; - drawString = historyItem.ToString(true); - } - else - { - drawString = drawItem.ToString(); - } - - e.DrawBackground(); - e.Graphics.DrawString(drawString, e.Font, new SolidBrush(e.ForeColor), new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)); - e.DrawFocusRectangle(); - } - - private struct HistoryItem : IEquatable - { - - public ConnectionInfo ConnectionInfo {get; set;} - - public bool Equals(HistoryItem other) - { - if (ConnectionInfo.Hostname != other.ConnectionInfo.Hostname) - { - return false; - } - if (ConnectionInfo.Port != other.ConnectionInfo.Port) - { - return false; - } + public class QuickConnectComboBox : ToolStripComboBox + { + private readonly ComboBox _comboBox; + private bool _ignoreEnter; - return ConnectionInfo.Protocol == other.ConnectionInfo.Protocol; - } - - public override string ToString() - { - return ToString(false); - } - - public string ToString(bool includeProtocol) - { - var port = string.Empty; - if (ConnectionInfo.Port != ConnectionInfo.GetDefaultPort()) - { - port = $":{ConnectionInfo.Port}"; - } + public QuickConnectComboBox() + { + _comboBox = ComboBox; + if (_comboBox == null) return; + _comboBox.PreviewKeyDown += ComboBox_PreviewKeyDown; + _comboBox.SelectedIndexChanged += ComboBox_SelectedIndexChanged; + _comboBox.DrawItem += ComboBox_DrawItem; + _comboBox.DrawMode = DrawMode.OwnerDrawFixed; + + // This makes it so that _ignoreEnter works correctly before any items are added to the combo box + _comboBox.Items.Clear(); + } + + private void ComboBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + if (e.KeyCode == Keys.Enter & _comboBox.DroppedDown) + { + _ignoreEnter = true; + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.KeyCode == Keys.Enter) + { + // Only connect if Enter was not pressed while the combo box was dropped down + if (!_ignoreEnter) + { + OnConnectRequested(new ConnectRequestedEventArgs(_comboBox.Text)); + } + + _ignoreEnter = false; + e.Handled = true; + } + else if (e.KeyCode == Keys.Delete & _comboBox.DroppedDown) + { + if (_comboBox.SelectedIndex != -1) + { + // Items can't be removed from the ComboBox while it is dropped down without possibly causing + // an exception so we must close it, delete the item, and then drop it down again. When we + // close it programmatically, the SelectedItem may revert to Nothing, so we must save it first. + var item = _comboBox.SelectedItem; + _comboBox.DroppedDown = false; + _comboBox.Items.Remove(item); + _comboBox.SelectedIndex = -1; + if (_comboBox.Items.Count != 0) + { + _comboBox.DroppedDown = true; + } + } + + e.Handled = true; + } + } + + private void ComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (!(_comboBox.SelectedItem is HistoryItem)) + { + return; + } + + var historyItem = (HistoryItem)_comboBox.SelectedItem; + OnProtocolChanged(new ProtocolChangedEventArgs(historyItem.ConnectionInfo.Protocol)); + } + + private static void ComboBox_DrawItem(object sender, DrawItemEventArgs e) + { + var comboBox = sender as ComboBox; + if (comboBox == null) + { + return; + } + + var drawItem = comboBox.Items[e.Index]; + + string drawString; + if (drawItem is HistoryItem) + { + var historyItem = (HistoryItem)drawItem; + drawString = historyItem.ToString(true); + } + else + { + drawString = drawItem.ToString(); + } + + e.DrawBackground(); + e.Graphics.DrawString(drawString, e.Font, new SolidBrush(e.ForeColor), + new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)); + e.DrawFocusRectangle(); + } + + private struct HistoryItem : IEquatable + { + public ConnectionInfo ConnectionInfo { get; set; } + + public bool Equals(HistoryItem other) + { + if (ConnectionInfo.Hostname != other.ConnectionInfo.Hostname) + { + return false; + } + + if (ConnectionInfo.Port != other.ConnectionInfo.Port) + { + return false; + } + + return ConnectionInfo.Protocol == other.ConnectionInfo.Protocol; + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool includeProtocol) + { + var port = string.Empty; + if (ConnectionInfo.Port != ConnectionInfo.GetDefaultPort()) + { + port = $":{ConnectionInfo.Port}"; + } + + return includeProtocol + ? $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})" + : $"{ConnectionInfo.Hostname}{port}"; + } + } + + private bool Exists(HistoryItem searchItem) + { + foreach (var item in _comboBox.Items) + { + if (!(item is HistoryItem)) + { + continue; + } + + var historyItem = (HistoryItem)item; + if (historyItem.Equals(searchItem)) + { + return true; + } + } + + return false; + } + + public void Add(ConnectionInfo connectionInfo) + { + try + { + var historyItem = new HistoryItem {ConnectionInfo = connectionInfo}; + if (!Exists(historyItem)) + { + _comboBox.Items.Insert(0, historyItem); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex); + } + } - return includeProtocol ? $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})" : $"{ConnectionInfo.Hostname}{port}"; - } - } - - private bool Exists(HistoryItem searchItem) - { - foreach (var item in _comboBox.Items) - { - if (!(item is HistoryItem)) - { - continue; - } - var historyItem = (HistoryItem) item; - if (historyItem.Equals(searchItem)) - { - return true; - } - } - return false; - } - - public void Add(ConnectionInfo connectionInfo) - { - try - { - var historyItem = new HistoryItem {ConnectionInfo = connectionInfo}; - if (!Exists(historyItem)) - { - _comboBox.Items.Insert(0, historyItem); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex); - } - } - #region Events - public class ConnectRequestedEventArgs : EventArgs - { - - public ConnectRequestedEventArgs(string connectionString) - { - ConnectionString = connectionString; - } - public string ConnectionString { get; } - } - - public delegate void ConnectRequestedEventHandler(object sender, ConnectRequestedEventArgs e); - private ConnectRequestedEventHandler ConnectRequestedEvent; - - public event ConnectRequestedEventHandler ConnectRequested - { - add - { - ConnectRequestedEvent = (ConnectRequestedEventHandler) Delegate.Combine(ConnectRequestedEvent, value); - } - remove - { - ConnectRequestedEvent = (ConnectRequestedEventHandler) Delegate.Remove(ConnectRequestedEvent, value); - } - } + public class ConnectRequestedEventArgs : EventArgs + { + public ConnectRequestedEventArgs(string connectionString) + { + ConnectionString = connectionString; + } + + public string ConnectionString { get; } + } + + public delegate void ConnectRequestedEventHandler(object sender, ConnectRequestedEventArgs e); + + private ConnectRequestedEventHandler ConnectRequestedEvent; + + public event ConnectRequestedEventHandler ConnectRequested + { + add + { + ConnectRequestedEvent = (ConnectRequestedEventHandler)Delegate.Combine(ConnectRequestedEvent, value); + } + remove + { + ConnectRequestedEvent = (ConnectRequestedEventHandler)Delegate.Remove(ConnectRequestedEvent, value); + } + } - private void OnConnectRequested(ConnectRequestedEventArgs e) - { + private void OnConnectRequested(ConnectRequestedEventArgs e) + { // TODO: Any reason to not jsut pass "e"? ConnectRequestedEvent?.Invoke(this, new ConnectRequestedEventArgs(e.ConnectionString)); - } - - public class ProtocolChangedEventArgs : EventArgs - { - - public ProtocolChangedEventArgs(ProtocolType protocol) - { - Protocol = protocol; - } + } - public ProtocolType Protocol { get; } - } - - public delegate void ProtocolChangedEventHandler(object sender, ProtocolChangedEventArgs e); - private ProtocolChangedEventHandler ProtocolChangedEvent; - - public event ProtocolChangedEventHandler ProtocolChanged - { - add - { - ProtocolChangedEvent = (ProtocolChangedEventHandler) Delegate.Combine(ProtocolChangedEvent, value); - } - remove - { - ProtocolChangedEvent = (ProtocolChangedEventHandler) Delegate.Remove(ProtocolChangedEvent, value); - } - } + public class ProtocolChangedEventArgs : EventArgs + { + public ProtocolChangedEventArgs(ProtocolType protocol) + { + Protocol = protocol; + } + + public ProtocolType Protocol { get; } + } + + public delegate void ProtocolChangedEventHandler(object sender, ProtocolChangedEventArgs e); + + private ProtocolChangedEventHandler ProtocolChangedEvent; + + public event ProtocolChangedEventHandler ProtocolChanged + { + add { ProtocolChangedEvent = (ProtocolChangedEventHandler)Delegate.Combine(ProtocolChangedEvent, value); } + remove { ProtocolChangedEvent = (ProtocolChangedEventHandler)Delegate.Remove(ProtocolChangedEvent, value); } + } - private void OnProtocolChanged(ProtocolChangedEventArgs e) - { + private void OnProtocolChanged(ProtocolChangedEventArgs e) + { // TODO: Any reason to not jsut pass "e"? - ProtocolChangedEvent?.Invoke(this, new ProtocolChangedEventArgs(e.Protocol)); - } + ProtocolChangedEvent?.Invoke(this, new ProtocolChangedEventArgs(e.Protocol)); + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index 4707f770a..7b4eadd7c 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -82,11 +82,13 @@ namespace mRemoteNG.UI.Controls // tsQuickConnect // Dock = DockStyle.None; - Items.AddRange(new ToolStripItem[] { - _lblQuickConnect, - _cmbQuickConnect, - _btnQuickConnect, - _btnConnections}); + Items.AddRange(new ToolStripItem[] + { + _lblQuickConnect, + _cmbQuickConnect, + _btnQuickConnect, + _btnConnections + }); Location = new Point(3, 24); Name = "tsQuickConnect"; Size = new Size(_display.ScaleWidth(387), 25); @@ -136,8 +138,10 @@ namespace mRemoteNG.UI.Controls private void ApplyTheme() { if (!_themeManager.ThemingActive) return; - vsToolStripExtender.SetStyle(_mnuQuickConnectProtocol, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_mnuConnections, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_mnuQuickConnectProtocol, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_mnuConnections, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); if (!_themeManager.ActiveAndExtended) return; _cmbQuickConnect.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); @@ -145,6 +149,7 @@ namespace mRemoteNG.UI.Controls } #region Quick Connect + private void PopulateQuickConnectProtocolMenu() { try @@ -159,6 +164,7 @@ namespace mRemoteNG.UI.Controls menuItem.Checked = true; _btnQuickConnect.Text = Settings.Default.QuickConnectProtocol; } + _mnuQuickConnectProtocol.Items.Add(menuItem); } } @@ -182,12 +188,16 @@ namespace mRemoteNG.UI.Controls { try { - var connectionInfo = Runtime.ConnectionsService.CreateQuickConnect(_cmbQuickConnect.Text.Trim(), Converter.StringToProtocol(Settings.Default.QuickConnectProtocol)); + var connectionInfo = Runtime.ConnectionsService.CreateQuickConnect(_cmbQuickConnect.Text.Trim(), + Converter.StringToProtocol(Settings + .Default + .QuickConnectProtocol)); if (connectionInfo == null) { _cmbQuickConnect.Focus(); return; } + _cmbQuickConnect.Add(connectionInfo); ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); } @@ -220,9 +230,11 @@ namespace mRemoteNG.UI.Controls menuItem.Checked = menuItem.Text.Equals(protocol); } } + #endregion #region Connections DropDown + private void btnConnections_DropDownOpening(object sender, EventArgs e) { _btnConnections.DropDownItems.Clear(); @@ -232,15 +244,16 @@ namespace mRemoteNG.UI.Controls }; // ReSharper disable once CoVariantArrayConversion - ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionsService.ConnectionTreeModel).ToArray(); + ToolStripItem[] rootMenuItems = menuItemsConverter + .CreateToolStripDropDownItems(Runtime.ConnectionsService + .ConnectionTreeModel).ToArray(); _btnConnections.DropDownItems.AddRange(rootMenuItems); - } private void ConnectionsMenuItem_MouseUp(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; - var menuItem = (ToolStripMenuItem) sender; + var menuItem = (ToolStripMenuItem)sender; switch (menuItem.Tag) { @@ -254,10 +267,12 @@ namespace mRemoteNG.UI.Controls break; } } + #endregion // CodeAyalysis doesn't like null propagation - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "components")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", + MessageId = "components")] protected override void Dispose(bool disposing) { try diff --git a/mRemoteV1/UI/Controls/SecureTextBox.cs b/mRemoteV1/UI/Controls/SecureTextBox.cs index d07e2ef4d..7026c9316 100644 --- a/mRemoteV1/UI/Controls/SecureTextBox.cs +++ b/mRemoteV1/UI/Controls/SecureTextBox.cs @@ -18,7 +18,5 @@ namespace mRemoteNG.UI.Controls { SecString = Text.ConvertToSecureString(); } - - } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/StatusImageList.cs b/mRemoteV1/UI/Controls/StatusImageList.cs index 6211d581b..419b8e63d 100644 --- a/mRemoteV1/UI/Controls/StatusImageList.cs +++ b/mRemoteV1/UI/Controls/StatusImageList.cs @@ -21,8 +21,8 @@ namespace mRemoteNG.UI.Controls { ColorDepth = ColorDepth.Depth32Bit, ImageSize = new Size( - (int)Math.Round(16 * display.ResolutionScalingFactor.Width), - (int)Math.Round(16 * display.ResolutionScalingFactor.Height)), + (int)Math.Round(16 * display.ResolutionScalingFactor.Width), + (int)Math.Round(16 * display.ResolutionScalingFactor.Height)), TransparentColor = Color.Transparent }; @@ -48,7 +48,7 @@ namespace mRemoteNG.UI.Controls if (connectionInfo is RootPuttySessionsNodeInfo) return "PuttySessions"; if (connectionInfo is RootNodeInfo) return "Root"; if (connectionInfo is ContainerInfo) return "Folder"; - + return GetConnectionIcon(connectionInfo); } @@ -77,7 +77,8 @@ namespace mRemoteNG.UI.Controls } ImageList.Images.Add(BuildConnectionIconName(connection.Icon, false), image); - ImageList.Images.Add(BuildConnectionIconName(connection.Icon, true), Overlay(image, Resources.ConnectedOverlay)); + ImageList.Images.Add(BuildConnectionIconName(connection.Icon, true), + Overlay(image, Resources.ConnectedOverlay)); return name; } @@ -88,6 +89,7 @@ namespace mRemoteNG.UI.Controls { gr.DrawImage(foreground, new Rectangle(0, 0, foreground.Width, foreground.Height)); } + return result; } @@ -101,7 +103,9 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace($"Unable to fill the image list of type {nameof(StatusImageList)}", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + $"Unable to fill the image list of type {nameof(StatusImageList)}", + ex); } } diff --git a/mRemoteV1/UI/Controls/TextBoxExtensions.cs b/mRemoteV1/UI/Controls/TextBoxExtensions.cs index 8c951b494..81bb0ddda 100644 --- a/mRemoteV1/UI/Controls/TextBoxExtensions.cs +++ b/mRemoteV1/UI/Controls/TextBoxExtensions.cs @@ -10,14 +10,16 @@ namespace mRemoteNG.UI.Controls public static bool SetCueBannerText(this TextBox textBox, string cueText, bool showCueWhenFocused = false) { if (!textBox.IsHandleCreated || cueText == null) return false; - var result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_SETCUEBANNER, (IntPtr) Convert.ToInt32(showCueWhenFocused), cueText); + var result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_SETCUEBANNER, + (IntPtr)Convert.ToInt32(showCueWhenFocused), cueText); return result.ToInt64() == NativeMethods.TRUE; } public static string GetCueBannerText(this TextBox textBox) { var cueBannerText = new StringBuilder(256); - var result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_GETCUEBANNER, cueBannerText, new IntPtr(cueBannerText.Capacity)); + var result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_GETCUEBANNER, cueBannerText, + new IntPtr(cueBannerText.Capacity)); return result.ToInt64() != 0 ? cueBannerText.ToString() : null; } } diff --git a/mRemoteV1/UI/Controls/ToolStripSplitButton.cs b/mRemoteV1/UI/Controls/ToolStripSplitButton.cs index ed7090851..1386136fa 100644 --- a/mRemoteV1/UI/Controls/ToolStripSplitButton.cs +++ b/mRemoteV1/UI/Controls/ToolStripSplitButton.cs @@ -3,56 +3,57 @@ using System.Windows.Forms; namespace mRemoteNG.UI.Controls { - public class ToolStripSplitButton : System.Windows.Forms.ToolStripSplitButton - { + public class ToolStripSplitButton : System.Windows.Forms.ToolStripSplitButton + { public new ToolStripDropDown DropDown - { - get { return base.DropDown; } - set - { - if (base.DropDown != value) - { - base.DropDown = value; - base.DropDown.Closing += DropDown_Closing; - } - } - } - - private void DropDown_Closing(object sender, ToolStripDropDownClosingEventArgs e) - { - if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked) - { - return; - } - - Rectangle dropDownButtonBoundsClient = DropDownButtonBounds; // Relative to the ToolStripSplitButton - dropDownButtonBoundsClient.Offset(Bounds.Location); // Relative to the parent of the ToolStripSplitButton - Rectangle dropDownButtonBoundsScreen = GetCurrentParent().RectangleToScreen(dropDownButtonBoundsClient); // Relative to the screen - - if (dropDownButtonBoundsScreen.Contains(Control.MousePosition)) - { - e.Cancel = true; - } - } - - protected override void OnMouseDown(MouseEventArgs e) - { - _dropDownVisibleOnMouseDown = DropDown.Visible; - base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseEventArgs e) - { - if (_dropDownVisibleOnMouseDown) - { - DropDown.Close(); - } - else - { - base.OnMouseUp(e); - } - } - - private bool _dropDownVisibleOnMouseDown; - } -} + { + get { return base.DropDown; } + set + { + if (base.DropDown != value) + { + base.DropDown = value; + base.DropDown.Closing += DropDown_Closing; + } + } + } + + private void DropDown_Closing(object sender, ToolStripDropDownClosingEventArgs e) + { + if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked) + { + return; + } + + Rectangle dropDownButtonBoundsClient = DropDownButtonBounds; // Relative to the ToolStripSplitButton + dropDownButtonBoundsClient.Offset(Bounds.Location); // Relative to the parent of the ToolStripSplitButton + Rectangle dropDownButtonBoundsScreen = + GetCurrentParent().RectangleToScreen(dropDownButtonBoundsClient); // Relative to the screen + + if (dropDownButtonBoundsScreen.Contains(Control.MousePosition)) + { + e.Cancel = true; + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + _dropDownVisibleOnMouseDown = DropDown.Visible; + base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + if (_dropDownVisibleOnMouseDown) + { + DropDown.Close(); + } + else + { + base.OnMouseUp(e); + } + } + + private bool _dropDownVisibleOnMouseDown; + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/DialogFactory.cs b/mRemoteV1/UI/DialogFactory.cs index 6ffbf1adc..f5eae4d88 100644 --- a/mRemoteV1/UI/DialogFactory.cs +++ b/mRemoteV1/UI/DialogFactory.cs @@ -28,7 +28,9 @@ namespace mRemoteNG.UI /// /// /// - public static void ShowLoadConnectionsFailedDialog(string connectionFileName, string messageText, bool showCancelButton) + public static void ShowLoadConnectionsFailedDialog(string connectionFileName, + string messageText, + bool showCancelButton) { var commandButtons = new List { @@ -46,13 +48,13 @@ namespace mRemoteNG.UI try { CTaskDialog.ShowTaskDialogBox( - GeneralAppInfo.ProductName, - messageText, - "", "", "", "", "", - string.Join(" | ", commandButtons), - ETaskDialogButtons.None, - ESysIcons.Question, - ESysIcons.Question); + GeneralAppInfo.ProductName, + messageText, + "", "", "", "", "", + string.Join(" | ", commandButtons), + ETaskDialogButtons.None, + ESysIcons.Question, + ESysIcons.Question); switch (CTaskDialog.CommandButtonResult) { @@ -78,9 +80,11 @@ namespace mRemoteNG.UI catch (Exception exception) { Runtime.MessageCollector.AddExceptionMessage( - string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), - exception, - MessageClass.WarningMsg); + string + .Format(Language.strConnectionsFileCouldNotBeLoadedNew, + connectionFileName), + exception, + MessageClass.WarningMsg); } } } diff --git a/mRemoteV1/UI/DisplayProperties.cs b/mRemoteV1/UI/DisplayProperties.cs index dae5ee068..2cf4ff15e 100644 --- a/mRemoteV1/UI/DisplayProperties.cs +++ b/mRemoteV1/UI/DisplayProperties.cs @@ -17,7 +17,7 @@ namespace mRemoteNG.UI /// Creates a new instance with the default /// of type /// - public DisplayProperties() + public DisplayProperties() : this(new GdiPlusGraphicsProvider()) { } @@ -116,4 +116,4 @@ namespace mRemoteNG.UI return (int)Math.Round(value * scalingValue); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/FontOverrider.cs b/mRemoteV1/UI/FontOverrider.cs index 693cda276..a1267c696 100644 --- a/mRemoteV1/UI/FontOverrider.cs +++ b/mRemoteV1/UI/FontOverrider.cs @@ -11,7 +11,8 @@ namespace mRemoteNG.UI foreach (Control tempLoopVarCtlChild in ctlParent.Controls) { var ctlChild = tempLoopVarCtlChild; - ctlChild.Font = new Font(SystemFonts.MessageBoxFont.Name, ctlChild.Font.Size, ctlChild.Font.Style, ctlChild.Font.Unit, ctlChild.Font.GdiCharSet); + ctlChild.Font = new Font(SystemFonts.MessageBoxFont.Name, ctlChild.Font.Size, ctlChild.Font.Style, + ctlChild.Font.Unit, ctlChild.Font.GdiCharSet); if (ctlChild.Controls.Count > 0) { FontOverride(ctlChild); diff --git a/mRemoteV1/UI/FormExtensions.cs b/mRemoteV1/UI/FormExtensions.cs index cf60601a1..a3fcb6c56 100644 --- a/mRemoteV1/UI/FormExtensions.cs +++ b/mRemoteV1/UI/FormExtensions.cs @@ -8,11 +8,11 @@ namespace mRemoteNG.UI { public static void CenterOnTarget(this Form formToMove, Form formToCenterOn) { - var targetFormCenterX = formToCenterOn.Location.X + formToCenterOn.Width/2; - var targetFormCenterY = formToCenterOn.Location.Y + formToCenterOn.Height/2; + var targetFormCenterX = formToCenterOn.Location.X + formToCenterOn.Width / 2; + var targetFormCenterY = formToCenterOn.Location.Y + formToCenterOn.Height / 2; - var thisFormCenterX = formToMove.Location.X + formToMove.Width/2; - var thisFormCenterY = formToMove.Location.Y + formToMove.Height/2; + var thisFormCenterX = formToMove.Location.X + formToMove.Width / 2; + var thisFormCenterY = formToMove.Location.Y + formToMove.Height / 2; formToMove.Location = new Point(targetFormCenterX - thisFormCenterX, targetFormCenterY - thisFormCenterY); } diff --git a/mRemoteV1/UI/Forms/ExportForm.cs b/mRemoteV1/UI/Forms/ExportForm.cs index ef67d708d..b5198609c 100644 --- a/mRemoteV1/UI/Forms/ExportForm.cs +++ b/mRemoteV1/UI/Forms/ExportForm.cs @@ -14,97 +14,100 @@ namespace mRemoteNG.UI.Forms private ThemeManager _themeManager; #region Public Properties + public string FileName - { - get => txtFileName.Text; + { + get => txtFileName.Text; set => txtFileName.Text = value; } public SaveFormat SaveFormat - { - get - { - var exportFormat = cboFileFormat.SelectedItem as ExportFormat; - return exportFormat?.Format ?? SaveFormat.mRXML; - } + { + get + { + var exportFormat = cboFileFormat.SelectedItem as ExportFormat; + return exportFormat?.Format ?? SaveFormat.mRXML; + } set - { - foreach (var item in cboFileFormat.Items) - { - var exportFormat = item as ExportFormat; - if (exportFormat?.Format != value) continue; - cboFileFormat.SelectedItem = item; - break; - } - } - } + { + foreach (var item in cboFileFormat.Items) + { + var exportFormat = item as ExportFormat; + if (exportFormat?.Format != value) continue; + cboFileFormat.SelectedItem = item; + break; + } + } + } public ExportScope Scope - { - get - { - if (rdoExportSelectedFolder.Checked) - return ExportScope.SelectedFolder; - if (rdoExportSelectedConnection.Checked) - return ExportScope.SelectedConnection; - return ExportScope.Everything; - } + { + get + { + if (rdoExportSelectedFolder.Checked) + return ExportScope.SelectedFolder; + if (rdoExportSelectedConnection.Checked) + return ExportScope.SelectedConnection; + return ExportScope.Everything; + } set - { - switch (value) - { - case ExportScope.Everything: - rdoExportEverything.Checked = true; - break; - case ExportScope.SelectedFolder: - rdoExportSelectedFolder.Checked = true; - break; - case ExportScope.SelectedConnection: - rdoExportSelectedConnection.Checked = true; - break; - } - } - } + { + switch (value) + { + case ExportScope.Everything: + rdoExportEverything.Checked = true; + break; + case ExportScope.SelectedFolder: + rdoExportSelectedFolder.Checked = true; + break; + case ExportScope.SelectedConnection: + rdoExportSelectedConnection.Checked = true; + break; + } + } + } + + private ContainerInfo _selectedFolder; - private ContainerInfo _selectedFolder; public ContainerInfo SelectedFolder - { - get => _selectedFolder; + { + get => _selectedFolder; set - { - _selectedFolder = value; - lblSelectedFolder.Text = value?.Name; - rdoExportSelectedFolder.Enabled = value != null; - } - } + { + _selectedFolder = value; + lblSelectedFolder.Text = value?.Name; + rdoExportSelectedFolder.Enabled = value != null; + } + } + + private ConnectionInfo _selectedConnection; - private ConnectionInfo _selectedConnection; public ConnectionInfo SelectedConnection - { - get => _selectedConnection; + { + get => _selectedConnection; set - { - _selectedConnection = value; - lblSelectedConnection.Text = value?.Name; - rdoExportSelectedConnection.Enabled = value != null; - } - } + { + _selectedConnection = value; + lblSelectedConnection.Text = value?.Name; + rdoExportSelectedConnection.Enabled = value != null; + } + } public bool IncludeUsername - { - get => chkUsername.Checked; + { + get => chkUsername.Checked; set => chkUsername.Checked = value; } public bool IncludePassword - { - get => chkPassword.Checked; + { + get => chkPassword.Checked; set => chkPassword.Checked = value; } public bool IncludeDomain - { - get => chkDomain.Checked; + { + get => chkDomain.Checked; set => chkDomain.Checked = value; } @@ -115,63 +118,68 @@ namespace mRemoteNG.UI.Forms } public bool IncludeInheritance - { - get => chkInheritance.Checked; + { + get => chkInheritance.Checked; set => chkInheritance.Checked = value; } + #endregion #region Constructors - public ExportForm() - { - InitializeComponent(); + + public ExportForm() + { + InitializeComponent(); FontOverrider.FontOverride(this); - SelectedFolder = null; - SelectedConnection = null; - btnOK.Enabled = false; - } + SelectedFolder = null; + SelectedConnection = null; + btnOK.Enabled = false; + } + #endregion #region Private Methods + #region Event Handlers + private void ExportForm_Load(object sender, EventArgs e) - { - cboFileFormat.Items.Clear(); + { + cboFileFormat.Items.Clear(); cboFileFormat.Items.Add(new ExportFormat(SaveFormat.mRXML)); cboFileFormat.Items.Add(new ExportFormat(SaveFormat.mRCSV)); - cboFileFormat.SelectedIndex = 0; + cboFileFormat.SelectedIndex = 0; ApplyTheme(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); - } + } private void txtFileName_TextChanged(object sender, EventArgs e) - { - btnOK.Enabled = !string.IsNullOrEmpty(txtFileName.Text); - } + { + btnOK.Enabled = !string.IsNullOrEmpty(txtFileName.Text); + } private void btnBrowse_Click(object sender, EventArgs e) - { - using (var saveFileDialog = new SaveFileDialog()) - { - saveFileDialog.CheckPathExists = true; - saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal); - saveFileDialog.OverwritePrompt = true; + { + using (var saveFileDialog = new SaveFileDialog()) + { + saveFileDialog.CheckPathExists = true; + saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + saveFileDialog.OverwritePrompt = true; - var fileTypes = new List(); - fileTypes.AddRange(new[] {Language.strFiltermRemoteXML, "*.xml"}); - fileTypes.AddRange(new[] {Language.strFiltermRemoteCSV, "*.csv"}); - fileTypes.AddRange(new[] {Language.strFilterAll, "*.*"}); + var fileTypes = new List(); + fileTypes.AddRange(new[] {Language.strFiltermRemoteXML, "*.xml"}); + fileTypes.AddRange(new[] {Language.strFiltermRemoteCSV, "*.csv"}); + fileTypes.AddRange(new[] {Language.strFilterAll, "*.*"}); - saveFileDialog.Filter = string.Join("|", fileTypes.ToArray()); - SelectFileTypeBasedOnSaveFormat(saveFileDialog); + saveFileDialog.Filter = string.Join("|", fileTypes.ToArray()); + SelectFileTypeBasedOnSaveFormat(saveFileDialog); if (saveFileDialog.ShowDialog(this) != DialogResult.OK) - return; + return; - txtFileName.Text = saveFileDialog.FileName; + txtFileName.Text = saveFileDialog.FileName; } - } + } private void SelectFileTypeBasedOnSaveFormat(FileDialog saveFileDialog) { @@ -179,14 +187,14 @@ namespace mRemoteNG.UI.Forms } private void btnOK_Click(object sender, EventArgs e) - { - DialogResult = DialogResult.OK; - } + { + DialogResult = DialogResult.OK; + } private void btnCancel_Click(object sender, EventArgs e) - { - DialogResult = DialogResult.Cancel; - } + { + DialogResult = DialogResult.Cancel; + } private void cboFileformat_SelectedIndexChanged(object sender, EventArgs e) { @@ -206,6 +214,7 @@ namespace mRemoteNG.UI.Forms // chkAssignedCredential.Enabled = false; //} } + #endregion private void ApplyTheme() @@ -218,73 +227,82 @@ namespace mRemoteNG.UI.Forms private void ApplyLanguage() - { - Text = Language.strExport; + { + Text = Language.strExport; - grpFile.Text = Language.strExportFile; - lblFileName.Text = Language.strLabelFilename; - btnBrowse.Text = Language.strButtonBrowse; - lblFileFormat.Text = Language.strFileFormatLabel; + grpFile.Text = Language.strExportFile; + lblFileName.Text = Language.strLabelFilename; + btnBrowse.Text = Language.strButtonBrowse; + lblFileFormat.Text = Language.strFileFormatLabel; - grpItems.Text = Language.strExportItems; - rdoExportEverything.Text = Language.strExportEverything; - rdoExportSelectedFolder.Text = Language.strExportSelectedFolder; - rdoExportSelectedConnection.Text = Language.strExportSelectedConnection; + grpItems.Text = Language.strExportItems; + rdoExportEverything.Text = Language.strExportEverything; + rdoExportSelectedFolder.Text = Language.strExportSelectedFolder; + rdoExportSelectedConnection.Text = Language.strExportSelectedConnection; - grpProperties.Text = Language.strExportProperties; - chkUsername.Text = Language.strCheckboxUsername; - chkPassword.Text = Language.strCheckboxPassword; - chkDomain.Text = Language.strCheckboxDomain; - chkAssignedCredential.Text = Language.strAssignedCredential; - chkInheritance.Text = Language.strCheckboxInheritance; - lblUncheckProperties.Text = Language.strUncheckProperties; + grpProperties.Text = Language.strExportProperties; + chkUsername.Text = Language.strCheckboxUsername; + chkPassword.Text = Language.strCheckboxPassword; + chkDomain.Text = Language.strCheckboxDomain; + chkAssignedCredential.Text = Language.strAssignedCredential; + chkInheritance.Text = Language.strCheckboxInheritance; + lblUncheckProperties.Text = Language.strUncheckProperties; + + btnOK.Text = Language.strButtonOK; + btnCancel.Text = Language.strButtonCancel; + } - btnOK.Text = Language.strButtonOK; - btnCancel.Text = Language.strButtonCancel; - } #endregion #region Public Enumerations - public enum ExportScope - { - Everything, - SelectedFolder, - SelectedConnection - } + + public enum ExportScope + { + Everything, + SelectedFolder, + SelectedConnection + } + #endregion #region Private Classes - [ImmutableObject(true)] + + [ImmutableObject(true)] private class ExportFormat - { + { #region Public Properties - public SaveFormat Format { get; } + public SaveFormat Format { get; } - #endregion + #endregion #region Constructors - public ExportFormat(SaveFormat format) - { - Format = format; - } + + public ExportFormat(SaveFormat format) + { + Format = format; + } + #endregion #region Public Methods - public override string ToString() - { - switch (Format) - { - case SaveFormat.mRXML: - return Language.strMremoteNgXml; + + public override string ToString() + { + switch (Format) + { + case SaveFormat.mRXML: + return Language.strMremoteNgXml; case SaveFormat.mRCSV: - return Language.strMremoteNgCsv; - default: - return Format.ToString(); - } - } + return Language.strMremoteNgCsv; + default: + return Format.ToString(); + } + } + #endregion - } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/FrmSplashScreen.cs b/mRemoteV1/UI/Forms/FrmSplashScreen.cs index bf28eaca3..f8882e8de 100644 --- a/mRemoteV1/UI/Forms/FrmSplashScreen.cs +++ b/mRemoteV1/UI/Forms/FrmSplashScreen.cs @@ -26,4 +26,4 @@ namespace mRemoteNG.UI.Forms } } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/FullscreenHandler.cs b/mRemoteV1/UI/Forms/FullscreenHandler.cs index b601a8e27..55086a11d 100644 --- a/mRemoteV1/UI/Forms/FullscreenHandler.cs +++ b/mRemoteV1/UI/Forms/FullscreenHandler.cs @@ -41,8 +41,10 @@ namespace mRemoteNG.UI.Forms { _handledForm.WindowState = FormWindowState.Normal; } + _handledForm.WindowState = FormWindowState.Maximized; } + private void ExitFullscreen() { _handledForm.FormBorderStyle = _savedBorderStyle; diff --git a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs index 1e099e2fb..e55b51e55 100644 --- a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs +++ b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs @@ -45,4 +45,4 @@ namespace mRemoteNG.UI.Forms.Input Close(); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs index 4ccb54d16..2d5908856 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs @@ -22,6 +22,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages } #region Public Methods + public override string PageName { get => Language.strTabAdvanced; @@ -70,19 +71,23 @@ namespace mRemoteNG.UI.Forms.OptionsPages puttyPathChanged = true; Settings.Default.CustomPuttyPath = txtCustomPuttyPath.Text; } + if (Settings.Default.UseCustomPuttyPath != chkUseCustomPuttyPath.Checked) { puttyPathChanged = true; Settings.Default.UseCustomPuttyPath = chkUseCustomPuttyPath.Checked; } + if (puttyPathChanged) { - PuttyBase.PuttyPath = Settings.Default.UseCustomPuttyPath ? Settings.Default.CustomPuttyPath : GeneralAppInfo.PuttyPath; + PuttyBase.PuttyPath = Settings.Default.UseCustomPuttyPath + ? Settings.Default.CustomPuttyPath + : GeneralAppInfo.PuttyPath; PuttySessionsManager.Instance.AddSessions(); } - Settings.Default.MaxPuttyWaitTime = (int) numPuttyWaitTime.Value; - Settings.Default.UVNCSCPort = (int) numUVNCSCPort.Value; + Settings.Default.MaxPuttyWaitTime = (int)numPuttyWaitTime.Value; + Settings.Default.UVNCSCPort = (int)numUVNCSCPort.Value; } #endregion @@ -155,7 +160,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages lblConfigurePuttySessions.Enabled = exists; btnLaunchPutty.Enabled = exists; - } #endregion diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs index 3c29be533..ad9f61017 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs @@ -25,7 +25,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages base.ApplyLanguage(); lblLanguage.Text = Language.strLanguage; - lblLanguageRestartRequired.Text = string.Format(Language.strLanguageRestartRequired, Application.ProductName); + lblLanguageRestartRequired.Text = + string.Format(Language.strLanguageRestartRequired, Application.ProductName); chkShowDescriptionTooltipsInTree.Text = Language.strShowDescriptionTooltips; chkShowFullConnectionsFilePathInTitle.Text = Language.strShowFullConsFilePath; chkShowSystemTrayIcon.Text = Language.strAlwaysShowSysTrayIcon; @@ -41,11 +42,13 @@ namespace mRemoteNG.UI.Forms.OptionsPages { cboLanguage.Items.Add(nativeName); } + if (!string.IsNullOrEmpty(Settings.Default.OverrideUICulture) && SupportedCultures.IsNameSupported(Settings.Default.OverrideUICulture)) { cboLanguage.SelectedItem = SupportedCultures.get_CultureNativeName(Settings.Default.OverrideUICulture); } + if (cboLanguage.SelectedIndex == -1) { cboLanguage.SelectedIndex = 0; @@ -59,7 +62,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void SaveSettings() { - if (cboLanguage.SelectedIndex > 0 && SupportedCultures.IsNativeNameSupported(Convert.ToString(cboLanguage.SelectedItem))) { diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs index d026d8ce6..785a40236 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs @@ -59,13 +59,13 @@ namespace mRemoteNG.UI.Forms.OptionsPages switch (Settings.Default.ConfirmCloseConnection) { - case (int) ConfirmCloseEnum.Never: + case (int)ConfirmCloseEnum.Never: radCloseWarnNever.Checked = true; break; - case (int) ConfirmCloseEnum.Exit: + case (int)ConfirmCloseEnum.Exit: radCloseWarnExit.Checked = true; break; - case (int) ConfirmCloseEnum.Multiple: + case (int)ConfirmCloseEnum.Multiple: radCloseWarnMultiple.Checked = true; break; default: @@ -84,12 +84,12 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.UseFilterSearch = chkUseFilterSearch.Checked; Settings.Default.PlaceSearchBarAboveConnectionTree = chkPlaceSearchBarAboveConnectionTree.Checked; - Settings.Default.RdpReconnectionCount = (int) numRdpReconnectionCount.Value; - Settings.Default.ConRDPOverallConnectionTimeout = (int) numRDPConTimeout.Value; - Settings.Default.AutoSaveEveryMinutes = (int) numAutoSave.Value; + Settings.Default.RdpReconnectionCount = (int)numRdpReconnectionCount.Value; + Settings.Default.ConRDPOverallConnectionTimeout = (int)numRDPConTimeout.Value; + Settings.Default.AutoSaveEveryMinutes = (int)numAutoSave.Value; if (Settings.Default.AutoSaveEveryMinutes > 0) { - _frmMain.tmrAutoSave.Interval = Settings.Default.AutoSaveEveryMinutes*60000; + _frmMain.tmrAutoSave.Interval = Settings.Default.AutoSaveEveryMinutes * 60000; _frmMain.tmrAutoSave.Enabled = true; } else @@ -99,19 +99,22 @@ namespace mRemoteNG.UI.Forms.OptionsPages if (radCloseWarnAll.Checked) { - Settings.Default.ConfirmCloseConnection = (int) ConfirmCloseEnum.All; + Settings.Default.ConfirmCloseConnection = (int)ConfirmCloseEnum.All; } + if (radCloseWarnMultiple.Checked) { - Settings.Default.ConfirmCloseConnection = (int) ConfirmCloseEnum.Multiple; + Settings.Default.ConfirmCloseConnection = (int)ConfirmCloseEnum.Multiple; } + if (radCloseWarnExit.Checked) { - Settings.Default.ConfirmCloseConnection = (int) ConfirmCloseEnum.Exit; + Settings.Default.ConfirmCloseConnection = (int)ConfirmCloseEnum.Exit; } + if (radCloseWarnNever.Checked) { - Settings.Default.ConfirmCloseConnection = (int) ConfirmCloseEnum.Never; + Settings.Default.ConfirmCloseConnection = (int)ConfirmCloseEnum.Never; } } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs index 0ed23bdb4..8d2417552 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs @@ -4,7 +4,7 @@ using mRemoteNG.Security.SymmetricEncryption; namespace mRemoteNG.UI.Forms.OptionsPages { - public sealed partial class CredentialsPage : OptionsPage + public sealed partial class CredentialsPage : OptionsPage { public CredentialsPage() { @@ -13,7 +13,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages PageIcon = Resources.Key_Icon; } - public override string PageName { + public override string PageName + { get => Language.Credentials; set { } } @@ -48,7 +49,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages txtCredentialsUsername.Text = Settings.Default.DefaultUsername; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - txtCredentialsPassword.Text = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); + txtCredentialsPassword.Text = + cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); txtCredentialsDomain.Text = Settings.Default.DefaultDomain; } @@ -69,7 +71,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.DefaultUsername = txtCredentialsUsername.Text; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - Settings.Default.DefaultPassword = cryptographyProvider.Encrypt(txtCredentialsPassword.Text, Runtime.EncryptionKey); + Settings.Default.DefaultPassword = + cryptographyProvider.Encrypt(txtCredentialsPassword.Text, Runtime.EncryptionKey); Settings.Default.DefaultDomain = txtCredentialsDomain.Text; } diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs index 692c8c568..e00b844eb 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs @@ -110,7 +110,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.SwitchToMCOnInformation = chkSwitchToMCInformation.Checked; Settings.Default.SwitchToMCOnWarning = chkSwitchToMCWarnings.Checked; Settings.Default.SwitchToMCOnError = chkSwitchToMCErrors.Checked; - } private void SaveLoggingSettings() diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index 143073d63..550ccf3e9 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -5,46 +5,45 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Forms.OptionsPages { - public class OptionsPage : UserControl - { - protected OptionsPage() - { + public class OptionsPage : UserControl + { + protected OptionsPage() + { InitializeComponent(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; } #region Public Properties - // ReSharper disable once UnusedAutoPropertyAccessor.Global - [Browsable(false)]public virtual string PageName {get; set;} - public virtual Icon PageIcon {get; protected set;} + // ReSharper disable once UnusedAutoPropertyAccessor.Global + [Browsable(false)] public virtual string PageName { get; set; } + + public virtual Icon PageIcon { get; protected set; } public virtual Image IconImage => PageIcon?.ToBitmap(); - #endregion - - #region Public Methods - public virtual void ApplyLanguage() - { - - } - - public virtual void LoadSettings() - { - - } - - public virtual void SaveSettings() - { - - } - - public virtual void RevertSettings() - { - - } #endregion - protected virtual void ApplyTheme() + #region Public Methods + + public virtual void ApplyLanguage() + { + } + + public virtual void LoadSettings() + { + } + + public virtual void SaveSettings() + { + } + + public virtual void RevertSettings() + { + } + + #endregion + + protected virtual void ApplyTheme() { if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); @@ -63,7 +62,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); Name = "OptionsPage"; ResumeLayout(false); - } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs index 278084b29..2aca2c0ca 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs @@ -36,21 +36,21 @@ namespace mRemoteNG.UI.Forms.OptionsPages { chkEncryptCompleteFile.Checked = Settings.Default.EncryptCompleteConnectionsFile; comboBoxEncryptionEngine.Text = Enum.GetName(typeof(BlockCipherEngines), Settings.Default.EncryptionEngine); - comboBoxBlockCipher.Text = Enum.GetName(typeof(BlockCipherModes), Settings.Default.EncryptionBlockCipherMode); + comboBoxBlockCipher.Text = + Enum.GetName(typeof(BlockCipherModes), Settings.Default.EncryptionBlockCipherMode); numberBoxKdfIterations.Value = Settings.Default.EncryptionKeyDerivationIterations; } public override void SaveSettings() { Settings.Default.EncryptCompleteConnectionsFile = chkEncryptCompleteFile.Checked; - Settings.Default.EncryptionEngine = (BlockCipherEngines) comboBoxEncryptionEngine.SelectedItem; - Settings.Default.EncryptionBlockCipherMode = (BlockCipherModes) comboBoxBlockCipher.SelectedItem; + Settings.Default.EncryptionEngine = (BlockCipherEngines)comboBoxEncryptionEngine.SelectedItem; + Settings.Default.EncryptionBlockCipherMode = (BlockCipherModes)comboBoxBlockCipher.SelectedItem; Settings.Default.EncryptionKeyDerivationIterations = (int)numberBoxKdfIterations.Value; } public override void RevertSettings() { - } private void PopulateEncryptionEngineDropDown() diff --git a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs index e3571f9d0..86502532f 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs @@ -7,7 +7,7 @@ using mRemoteNG.Security.SymmetricEncryption; namespace mRemoteNG.UI.Forms.OptionsPages { - public sealed partial class SqlServerPage + public sealed partial class SqlServerPage { private readonly SqlDatabaseConnectionTester _databaseConnectionTester; @@ -50,7 +50,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); txtSQLPassword.Text = cryptographyProvider.Decrypt(Settings.Default.SQLPass, Runtime.EncryptionKey); chkSQLReadOnly.Checked = Settings.Default.SQLReadOnly; - lblTestConnectionResults.Text = ""; + lblTestConnectionResults.Text = ""; } public override void SaveSettings() @@ -75,7 +75,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages private static void ReinitializeSqlUpdater() { Runtime.ConnectionsService.RemoteConnectionsSyncronizer?.Dispose(); - Runtime.ConnectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker()); + Runtime.ConnectionsService.RemoteConnectionsSyncronizer = + new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker()); Runtime.ConnectionsService.LoadConnections(true, false, ""); } @@ -117,7 +118,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages imgConnectionStatus.Image = Resources.loading_spinner; btnTestConnection.Enabled = false; - var connectionTestResult = await _databaseConnectionTester.TestConnectivity(server, database, username, password); + var connectionTestResult = + await _databaseConnectionTester.TestConnectivity(server, database, username, password); btnTestConnection.Enabled = true; @@ -129,15 +131,18 @@ namespace mRemoteNG.UI.Forms.OptionsPages break; case ConnectionTestResult.ServerNotAccessible: UpdateConnectionImage(false); - lblTestConnectionResults.Text = BuildTestFailedMessage(string.Format(Language.ServerNotAccessible, server)); + lblTestConnectionResults.Text = + BuildTestFailedMessage(string.Format(Language.ServerNotAccessible, server)); break; case ConnectionTestResult.CredentialsRejected: UpdateConnectionImage(false); - lblTestConnectionResults.Text = BuildTestFailedMessage(string.Format(Language.LoginFailedForUser, username)); + lblTestConnectionResults.Text = + BuildTestFailedMessage(string.Format(Language.LoginFailedForUser, username)); break; case ConnectionTestResult.UnknownDatabase: UpdateConnectionImage(false); - lblTestConnectionResults.Text = BuildTestFailedMessage(string.Format(Language.DatabaseNotAvailable, database)); + lblTestConnectionResults.Text = + BuildTestFailedMessage(string.Format(Language.DatabaseNotAvailable, database)); break; case ConnectionTestResult.UnknownError: UpdateConnectionImage(false); diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs index 55ee9ad24..07802f78a 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs @@ -20,8 +20,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages base.ApplyLanguage(); chkAlwaysShowPanelTabs.Text = Language.strAlwaysShowPanelTabs; - chkAlwaysShowConnectionTabs.Text = Language.strAlwaysShowConnectionTabs; - chkOpenNewTabRightOfSelected.Text = Language.strOpenNewTabRight; + chkAlwaysShowConnectionTabs.Text = Language.strAlwaysShowConnectionTabs; + chkOpenNewTabRightOfSelected.Text = Language.strOpenNewTabRight; chkShowLogonInfoOnTabs.Text = Language.strShowLogonInfoOnTabs; chkShowProtocolOnTabs.Text = Language.strShowProtocolOnTabs; chkIdentifyQuickConnectTabs.Text = Language.strIdentifyQuickConnectTabs; @@ -34,8 +34,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { chkAlwaysShowPanelTabs.Checked = Settings.Default.AlwaysShowPanelTabs; - chkAlwaysShowConnectionTabs.Checked = Settings.Default.AlwaysShowConnectionTabs; - chkOpenNewTabRightOfSelected.Checked = Settings.Default.OpenTabsRightOfSelected; + chkAlwaysShowConnectionTabs.Checked = Settings.Default.AlwaysShowConnectionTabs; + chkOpenNewTabRightOfSelected.Checked = Settings.Default.OpenTabsRightOfSelected; chkShowLogonInfoOnTabs.Checked = Settings.Default.ShowLogonInfoOnTabs; chkShowProtocolOnTabs.Checked = Settings.Default.ShowProtocolOnTabs; chkIdentifyQuickConnectTabs.Checked = Settings.Default.IdentifyQuickConnectTabs; @@ -51,8 +51,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages base.SaveSettings(); Settings.Default.AlwaysShowPanelTabs = chkAlwaysShowPanelTabs.Checked; - Settings.Default.AlwaysShowConnectionTabs = chkAlwaysShowConnectionTabs.Checked; - FrmMain.Default.ShowHidePanelTabs(); + Settings.Default.AlwaysShowConnectionTabs = chkAlwaysShowConnectionTabs.Checked; + FrmMain.Default.ShowHidePanelTabs(); Settings.Default.OpenTabsRightOfSelected = chkOpenNewTabRightOfSelected.Checked; Settings.Default.ShowLogonInfoOnTabs = chkShowLogonInfoOnTabs.Checked; diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index f0a1e73b0..77d47e188 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -11,11 +11,12 @@ namespace mRemoteNG.UI.Forms.OptionsPages { public sealed partial class ThemePage { - #region Private Fields + private readonly ThemeManager _themeManager; private readonly bool _oriActiveTheming; private readonly List modifiedThemes = new List(); + #endregion public ThemePage() @@ -83,18 +84,20 @@ namespace mRemoteNG.UI.Forms.OptionsPages // Save the theme settings form close so we don't run into unexpected results while modifying... // Prompt the user that a restart is required to apply the new theme... - if (cboTheme.SelectedItem != null) // LoadSettings calls SaveSettings, so these might be null the first time around + if (cboTheme.SelectedItem != null + ) // LoadSettings calls SaveSettings, so these might be null the first time around { - if (!Settings.Default.ThemeName.Equals(((ThemeInfo) cboTheme.SelectedItem).Name)) + if (!Settings.Default.ThemeName.Equals(((ThemeInfo)cboTheme.SelectedItem).Name)) { - Settings.Default.ThemeName = ((ThemeInfo) cboTheme.SelectedItem).Name; + Settings.Default.ThemeName = ((ThemeInfo)cboTheme.SelectedItem).Name; - CTaskDialog.MessageBox("Theme Changed", "Restart Required.","Please restart mRemoteNG to apply the selected theme.", - ETaskDialogButtons.Ok, ESysIcons.Information); + CTaskDialog.MessageBox("Theme Changed", "Restart Required.", + "Please restart mRemoteNG to apply the selected theme.", + ETaskDialogButtons.Ok, ESysIcons.Information); } } - foreach(var updatedTheme in modifiedThemes) + foreach (var updatedTheme in modifiedThemes) { _themeManager.updateTheme(updatedTheme); } @@ -105,9 +108,11 @@ namespace mRemoteNG.UI.Forms.OptionsPages base.RevertSettings(); _themeManager.ThemingActive = _oriActiveTheming; } + #region Private Methods #region Event Handlers + private void cboTheme_SelectionChangeCommitted(object sender, EventArgs e) { btnThemeNew.Enabled = false; @@ -147,7 +152,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages /// private void ListPalette_CellClick(object sender, CellClickEventArgs e) { - var colorElem = (PseudoKeyColor)e.Model; var colorDlg = new ColorDialog @@ -165,7 +169,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages colorElem.Value = colorDlg.Color; listPalette.RefreshObject(e.Model); _themeManager.refreshUI(); - } private void ColorMeList(ThemeInfo ti) @@ -176,7 +179,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void btnThemeNew_Click(object sender, EventArgs e) { - using (var frmInputBox = new FrmInputBox(Language.strOptionsThemeNewThemeCaption, Language.strOptionsThemeNewThemeText, _themeManager.ActiveTheme.Name)) + using (var frmInputBox = new FrmInputBox(Language.strOptionsThemeNewThemeCaption, + Language.strOptionsThemeNewThemeText, + _themeManager.ActiveTheme.Name)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK) return; @@ -188,14 +193,19 @@ namespace mRemoteNG.UI.Forms.OptionsPages } else { - CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, ESysIcons.Information, 0); + CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", + "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, + ESysIcons.Information, 0); } } } private void btnThemeDelete_Click(object sender, EventArgs e) { - var res = CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Information, 0); + var res = CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings, + Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", + ETaskDialogButtons.YesNo, + ESysIcons.Question, ESysIcons.Information, 0); if (res != DialogResult.Yes) return; if (modifiedThemes.Contains(_themeManager.ActiveTheme)) @@ -203,6 +213,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages _themeManager.deleteTheme(_themeManager.ActiveTheme); LoadSettings(); } + #endregion #endregion diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs index 65a013c33..e1bdfd5e4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs @@ -26,6 +26,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages } #region Public Methods + public override string PageName { get => Language.strTabUpdates; @@ -36,7 +37,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { base.ApplyLanguage(); - lblUpdatesExplanation.Text = Language.strUpdateCheck; + lblUpdatesExplanation.Text = Language.strUpdateCheck; chkCheckForUpdatesOnStartup.Text = Language.strCheckForUpdatesOnStartup; btnUpdateCheckNow.Text = Language.strCheckNow; @@ -65,24 +66,26 @@ namespace mRemoteNG.UI.Forms.OptionsPages chkCheckForUpdatesOnStartup.Checked = false; cboUpdateCheckFrequency.SelectedIndex = nDaily; } // Daily - else switch (Settings.Default.CheckForUpdatesFrequencyDays) - { - case 1: - cboUpdateCheckFrequency.SelectedIndex = nDaily; - break; - case 7: - cboUpdateCheckFrequency.SelectedIndex = nWeekly; - break; - case 31: - cboUpdateCheckFrequency.SelectedIndex = nMonthly; - break; - default: - var nCustom = - cboUpdateCheckFrequency.Items.Add(string.Format(Language.strUpdateFrequencyCustom, - Settings.Default.CheckForUpdatesFrequencyDays)); - cboUpdateCheckFrequency.SelectedIndex = nCustom; - break; - } + else + switch (Settings.Default.CheckForUpdatesFrequencyDays) + { + case 1: + cboUpdateCheckFrequency.SelectedIndex = nDaily; + break; + case 7: + cboUpdateCheckFrequency.SelectedIndex = nWeekly; + break; + case 31: + cboUpdateCheckFrequency.SelectedIndex = nMonthly; + break; + default: + var nCustom = + cboUpdateCheckFrequency.Items.Add(string.Format(Language.strUpdateFrequencyCustom, + Settings + .Default.CheckForUpdatesFrequencyDays)); + cboUpdateCheckFrequency.SelectedIndex = nCustom; + break; + } var stable = cboReleaseChannel.Items.Add(UpdateChannelInfo.STABLE); var beta = cboReleaseChannel.Items.Add(UpdateChannelInfo.BETA); @@ -112,7 +115,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages pnlProxyAuthentication.Enabled = Settings.Default.UpdateProxyUseAuthentication; txtProxyUsername.Text = Settings.Default.UpdateProxyAuthUser; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - txtProxyPassword.Text = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey); + txtProxyPassword.Text = + cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey); btnTestProxy.Enabled = Settings.Default.UpdateUseProxy; } @@ -139,12 +143,13 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.UpdateUseProxy = chkUseProxyForAutomaticUpdates.Checked; Settings.Default.UpdateProxyAddress = txtProxyAddress.Text; - Settings.Default.UpdateProxyPort = (int) numProxyPort.Value; + Settings.Default.UpdateProxyPort = (int)numProxyPort.Value; Settings.Default.UpdateProxyUseAuthentication = chkUseProxyAuthentication.Checked; Settings.Default.UpdateProxyAuthUser = txtProxyUsername.Text; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - Settings.Default.UpdateProxyAuthPass = cryptographyProvider.Encrypt(txtProxyPassword.Text, Runtime.EncryptionKey); + Settings.Default.UpdateProxyAuthPass = + cryptographyProvider.Encrypt(txtProxyPassword.Text, Runtime.EncryptionKey); } #endregion @@ -197,8 +202,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages _appUpdate = new AppUpdater(); //_appUpdate.Load += _appUpdate.Update_Load; _appUpdate.SetProxySettings(chkUseProxyForAutomaticUpdates.Checked, txtProxyAddress.Text, - (int) numProxyPort.Value, chkUseProxyAuthentication.Checked, txtProxyUsername.Text, - txtProxyPassword.Text); + (int)numProxyPort.Value, chkUseProxyAuthentication.Checked, + txtProxyUsername.Text, + txtProxyPassword.Text); btnTestProxy.Enabled = false; btnTestProxy.Text = Language.strOptionsProxyTesting; @@ -238,18 +244,22 @@ namespace mRemoteNG.UI.Forms.OptionsPages { return; } + if (e.Error != null) { throw e.Error; } - CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.strProxyTestSucceeded, "", Language.strButtonOK, false); + CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.strProxyTestSucceeded, "", + Language.strButtonOK, false); } catch (Exception ex) { CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.strProxyTestFailed, - MiscTools.GetExceptionMessageRecursive(ex), "", "", "", Language.strButtonOK, false, ESysIcons.Error, - 0); + MiscTools.GetExceptionMessageRecursive(ex), "", "", "", Language.strButtonOK, + false, + ESysIcons.Error, + 0); } } diff --git a/mRemoteV1/UI/Forms/PasswordForm.cs b/mRemoteV1/UI/Forms/PasswordForm.cs index 33b05d270..e9246f466 100644 --- a/mRemoteV1/UI/Forms/PasswordForm.cs +++ b/mRemoteV1/UI/Forms/PasswordForm.cs @@ -7,7 +7,7 @@ using mRemoteNG.Tools; namespace mRemoteNG.UI.Forms { public partial class PasswordForm : IKeyProvider - { + { private readonly string _passwordName; private SecureString _password = new SecureString(); @@ -16,7 +16,7 @@ namespace mRemoteNG.UI.Forms /// password box is shown which must match the first password /// to continue. /// - private bool NewPasswordMode { get; } + private bool NewPasswordMode { get; } /// /// Creates a new password form for entering or setting a password. @@ -27,12 +27,12 @@ namespace mRemoteNG.UI.Forms /// password box is shown which must match the first password /// to continue. /// - public PasswordForm(string passwordName = null, bool newPasswordMode = true) - { - InitializeComponent(); - _passwordName = passwordName; - NewPasswordMode = newPasswordMode; - } + public PasswordForm(string passwordName = null, bool newPasswordMode = true) + { + InitializeComponent(); + _passwordName = passwordName; + NewPasswordMode = newPasswordMode; + } /// /// Dispaly a dialog box requesting that the user @@ -48,17 +48,18 @@ namespace mRemoteNG.UI.Forms } #region Event Handlers + private void frmPassword_Load(object sender, EventArgs e) - { - ApplyLanguage(); + { + ApplyLanguage(); var display = new DisplayProperties(); - pbLock.Image = display.ScaleImage(pbLock.Image); - Height = tableLayoutPanel1.Height; + pbLock.Image = display.ScaleImage(pbLock.Image); + Height = tableLayoutPanel1.Height; if (NewPasswordMode) return; lblVerify.Visible = false; - txtVerify.Visible = false; - } + txtVerify.Visible = false; + } private void PasswordForm_FormClosed(object sender, FormClosedEventArgs e) { @@ -68,60 +69,66 @@ namespace mRemoteNG.UI.Forms } private void btnCancel_Click(object sender, EventArgs e) - { - DialogResult = DialogResult.Cancel; + { + DialogResult = DialogResult.Cancel; Close(); - } + } - private void btnOK_Click(object sender, EventArgs e) - { + private void btnOK_Click(object sender, EventArgs e) + { if (NewPasswordMode) - VerifyNewPassword(); + VerifyNewPassword(); - DialogResult = DialogResult.OK; - } + DialogResult = DialogResult.OK; + } + + private void txtPassword_TextChanged(object sender, EventArgs e) + { + HideStatus(); + } - private void txtPassword_TextChanged(object sender, EventArgs e) - { - HideStatus(); - } #endregion - + #region Private Methods - private void ApplyLanguage() - { - Text = string.IsNullOrEmpty(_passwordName) ? Language.strTitlePassword : string.Format(Language.strTitlePasswordWithName, _passwordName); - - lblPassword.Text = Language.strLabelPassword; - lblVerify.Text = Language.strLabelVerify; - btnCancel.Text = Language.strButtonCancel; - btnOK.Text = Language.strButtonOK; - } - + + private void ApplyLanguage() + { + Text = string.IsNullOrEmpty(_passwordName) + ? Language.strTitlePassword + : string.Format(Language.strTitlePasswordWithName, _passwordName); + + lblPassword.Text = Language.strLabelPassword; + lblVerify.Text = Language.strLabelVerify; + btnCancel.Text = Language.strButtonCancel; + btnOK.Text = Language.strButtonOK; + } + // ReSharper disable once UnusedMethodReturnValue.Local private bool VerifyNewPassword() - { - if (txtPassword.Text.Length >= 3) - { - if (txtPassword.Text == txtVerify.Text) - return true; - ShowStatus(Language.strPasswordStatusMustMatch); - return false; - } - ShowStatus(Language.strPasswordStatusTooShort); - return false; - } - - private void ShowStatus(string status) - { - lblStatus.Visible = true; - lblStatus.Text = status; - } - - private void HideStatus() - { - lblStatus.Visible = false; - } + { + if (txtPassword.Text.Length >= 3) + { + if (txtPassword.Text == txtVerify.Text) + return true; + ShowStatus(Language.strPasswordStatusMustMatch); + return false; + } + + ShowStatus(Language.strPasswordStatusTooShort); + return false; + } + + private void ShowStatus(string status) + { + lblStatus.Visible = true; + lblStatus.Text = status; + } + + private void HideStatus() + { + lblStatus.Visible = false; + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/TextBox.cs b/mRemoteV1/UI/Forms/TextBox.cs index 38b238d64..1b7329faa 100644 --- a/mRemoteV1/UI/Forms/TextBox.cs +++ b/mRemoteV1/UI/Forms/TextBox.cs @@ -6,50 +6,59 @@ using System.Windows.Forms; namespace mRemoteNG.UI.Forms { - public class TextBox : Controls.Base.NGTextBox - { + public class TextBox : Controls.Base.NGTextBox + { #region Public Properties - [Category("Behavior"), - DefaultValue(false)]private bool _SelectAllOnFocus; + + [Category("Behavior"), + DefaultValue(false)] + private bool _SelectAllOnFocus; + public bool SelectAllOnFocus - { - get => _SelectAllOnFocus; + { + get => _SelectAllOnFocus; set => _SelectAllOnFocus = value; } + #endregion - + #region Protected Methods - protected override void OnEnter(EventArgs e) - { - base.OnEnter(e); + + protected override void OnEnter(EventArgs e) + { + base.OnEnter(e); if (MouseButtons != MouseButtons.None) return; SelectAll(); _focusHandled = true; } - - protected override void OnLeave(EventArgs e) - { - base.OnLeave(e); - - _focusHandled = false; - } - - protected override void OnMouseUp(MouseEventArgs e) - { - base.OnMouseUp(e); + + protected override void OnLeave(EventArgs e) + { + base.OnLeave(e); + + _focusHandled = false; + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); if (_focusHandled) return; if (SelectionLength == 0) { SelectAll(); } + _focusHandled = true; } + #endregion - + #region Private Fields - private bool _focusHandled; + + private bool _focusHandled; + #endregion private void InitializeComponent() @@ -58,9 +67,9 @@ namespace mRemoteNG.UI.Forms // // TextBox // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ResumeLayout(false); - } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/UnhandledExceptionWindow.cs b/mRemoteV1/UI/Forms/UnhandledExceptionWindow.cs index 6147851ba..a06cffad0 100644 --- a/mRemoteV1/UI/Forms/UnhandledExceptionWindow.cs +++ b/mRemoteV1/UI/Forms/UnhandledExceptionWindow.cs @@ -32,27 +32,27 @@ namespace mRemoteNG.UI.Forms Text = Language.mRemoteNGUnhandledException; labelExceptionCaught.Text = Language.UnhandledExceptionOccured; - labelExceptionIsFatalHeader.Text = _isFatal - ? Language.ExceptionForcesmRemoteNGToClose + labelExceptionIsFatalHeader.Text = _isFatal + ? Language.ExceptionForcesmRemoteNGToClose : string.Empty; labelExceptionMessageHeader.Text = Language.ExceptionMessage; labelStackTraceHeader.Text = Language.StackTrace; buttonCopyAll.Text = Language.strMenuNotificationsCopyAll; buttonClose.Text = _isFatal - ? Language.strMenuExit + ? Language.strMenuExit : Language.strButtonClose; } private void buttonCopyAll_Click(object sender, EventArgs e) { var text = new StringBuilder() - .AppendLine(labelExceptionMessageHeader.Text) - .AppendLine("\"" + textBoxExceptionMessage.Text + "\"") - .AppendLine() - .AppendLine(labelStackTraceHeader.Text) - .AppendLine(textBoxStackTrace.Text) - .ToString(); + .AppendLine(labelExceptionMessageHeader.Text) + .AppendLine("\"" + textBoxExceptionMessage.Text + "\"") + .AppendLine() + .AppendLine(labelStackTraceHeader.Text) + .AppendLine(textBoxStackTrace.Text) + .ToString(); Clipboard.SetText(text); } @@ -65,4 +65,4 @@ namespace mRemoteNG.UI.Forms Close(); } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.cs b/mRemoteV1/UI/Forms/frmChoosePanel.cs index 12d765461..e038e761a 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.cs @@ -6,70 +6,74 @@ using mRemoteNG.UI.Panels; namespace mRemoteNG.UI.Forms { - public partial class FrmChoosePanel - { - private readonly PanelAdder _panelAdder; + public partial class FrmChoosePanel + { + private readonly PanelAdder _panelAdder; - public FrmChoosePanel() - { - InitializeComponent(); + public FrmChoosePanel() + { + InitializeComponent(); _panelAdder = new PanelAdder(); - } + } + public string Panel - { - get => cbPanels.SelectedItem.ToString(); + { + get => cbPanels.SelectedItem.ToString(); set => cbPanels.SelectedItem = value; } - private void frmChoosePanel_Load(object sender, System.EventArgs e) - { - ApplyLanguage(); - ApplyTheme(); - AddAvailablePanels(); - } + private void frmChoosePanel_Load(object sender, System.EventArgs e) + { + ApplyLanguage(); + ApplyTheme(); + AddAvailablePanels(); + } - private void ApplyLanguage() - { - btnOK.Text = Language.strButtonOK; - lblDescription.Text = Language.strLabelSelectPanel; - btnNew.Text = Language.strButtonNew; - Text = Language.strTitleSelectPanel; - } + private void ApplyLanguage() + { + btnOK.Text = Language.strButtonOK; + lblDescription.Text = Language.strLabelSelectPanel; + btnNew.Text = Language.strButtonNew; + Text = Language.strTitleSelectPanel; + } - private void ApplyTheme() - { + private void ApplyTheme() + { if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - lblDescription.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - lblDescription.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + lblDescription.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + lblDescription.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void AddAvailablePanels() - { - cbPanels.Items.Clear(); + { + cbPanels.Items.Clear(); - for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) - { + for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) + { cbPanels.Items.Add(Runtime.WindowList[i].Text.Replace("&&", "&")); - } + } - if (cbPanels.Items.Count > 0) - { - cbPanels.SelectedItem = cbPanels.Items[0]; - cbPanels.Enabled = true; - btnOK.Enabled = true; - } - else - { - cbPanels.Enabled = false; - btnOK.Enabled = false; - } - } + if (cbPanels.Items.Count > 0) + { + cbPanels.SelectedItem = cbPanels.Items[0]; + cbPanels.Enabled = true; + btnOK.Enabled = true; + } + else + { + cbPanels.Enabled = false; + btnOK.Enabled = false; + } + } - private void btnNew_Click(object sender, System.EventArgs e) - { - using (var frmInputBox = new FrmInputBox(Language.strNewPanel, Language.strPanelName + ":", Language.strNewPanel)) + private void btnNew_Click(object sender, System.EventArgs e) + { + using (var frmInputBox = + new FrmInputBox(Language.strNewPanel, Language.strPanelName + ":", Language.strNewPanel)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK || string.IsNullOrEmpty(frmInputBox.returnValue)) return; @@ -78,11 +82,11 @@ namespace mRemoteNG.UI.Forms cbPanels.SelectedItem = frmInputBox.returnValue; cbPanels.Focus(); } - } + } - private void btnOK_Click(object sender, System.EventArgs e) - { + private void btnOK_Click(object sender, System.EventArgs e) + { DialogResult = DialogResult.OK; - } - } -} + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 5f7393ef5..b21e6fd27 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -56,9 +56,9 @@ namespace mRemoteNG.UI.Forms private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); private FrmMain() - { - _showFullPathInTitle = Settings.Default.ShowCompleteConsPathInTitle; - InitializeComponent(); + { + _showFullPathInTitle = Settings.Default.ShowCompleteConsPathInTitle; + InitializeComponent(); Fullscreen = new FullscreenHandler(this); //Theming support @@ -70,68 +70,75 @@ namespace mRemoteNG.UI.Forms } #region Properties + public FormWindowState PreviousWindowState { get; set; } - public bool IsClosing { get; private set; } + public bool IsClosing { get; private set; } public bool AreWeUsingSqlServerForSavingConnections - { - get => _usingSqlServer; + { + get => _usingSqlServer; set - { - if (_usingSqlServer == value) - { - return; - } - _usingSqlServer = value; - UpdateWindowTitle(); - } - } + { + if (_usingSqlServer == value) + { + return; + } + + _usingSqlServer = value; + UpdateWindowTitle(); + } + } public string ConnectionsFileName - { - get => _connectionsFileName; + { + get => _connectionsFileName; set - { - if (_connectionsFileName == value) - { - return; - } - _connectionsFileName = value; - UpdateWindowTitle(); - } - } + { + if (_connectionsFileName == value) + { + return; + } + + _connectionsFileName = value; + UpdateWindowTitle(); + } + } public bool ShowFullPathInTitle - { - get => _showFullPathInTitle; + { + get => _showFullPathInTitle; set - { - if (_showFullPathInTitle == value) - { - return; - } - _showFullPathInTitle = value; - UpdateWindowTitle(); - } - } + { + if (_showFullPathInTitle == value) + { + return; + } + + _showFullPathInTitle = value; + UpdateWindowTitle(); + } + } public ConnectionInfo SelectedConnection - { - get => _selectedConnection; + { + get => _selectedConnection; set - { - if (_selectedConnection == value) - { - return; - } - _selectedConnection = value; - UpdateWindowTitle(); - } - } + { + if (_selectedConnection == value) + { + return; + } + + _selectedConnection = value; + UpdateWindowTitle(); + } + } + #endregion #region Startup & Shutdown + private void frmMain_Load(object sender, EventArgs e) { var messageCollector = Runtime.MessageCollector; @@ -141,7 +148,8 @@ namespace mRemoteNG.UI.Forms Startup.Instance.InitializeProgram(messageCollector); msMain.Location = Point.Empty; - var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip, _externalToolsToolStrip, _multiSshToolStrip, msMain); + var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip, + _externalToolsToolStrip, _multiSshToolStrip, msMain); settingsLoader.LoadSettings(); SetMenuDependencies(); @@ -149,12 +157,12 @@ namespace mRemoteNG.UI.Forms var uiLoader = new DockPanelLayoutLoader(this, messageCollector); uiLoader.LoadPanelsFromXml(); - LockToolbarPositions(Settings.Default.LockToolbars); - Settings.Default.PropertyChanged += OnApplicationSettingChanged; + LockToolbarPositions(Settings.Default.LockToolbars); + Settings.Default.PropertyChanged += OnApplicationSettingChanged; - _themeManager.ThemeChanged += ApplyTheme; + _themeManager.ThemeChanged += ApplyTheme; - _fpChainedWindowHandle = NativeMethods.SetClipboardViewer(Handle); + _fpChainedWindowHandle = NativeMethods.SetClipboardViewer(Handle); Runtime.WindowList = new WindowList(); @@ -169,13 +177,13 @@ namespace mRemoteNG.UI.Forms Windows.TreeForm.Focus(); PuttySessionsManager.Instance.StartWatcher(); - if (Settings.Default.StartupComponentsCheck) + if (Settings.Default.StartupComponentsCheck) Windows.Show(WindowType.ComponentsCheck); Startup.Instance.CreateConnectionsProvider(messageCollector); _screenSystemMenu.BuildScreenList(); - SystemEvents.DisplaySettingsChanged += _screenSystemMenu.OnDisplayChanged; + SystemEvents.DisplaySettingsChanged += _screenSystemMenu.OnDisplayChanged; ApplyLanguage(); Opacity = 1; @@ -204,35 +212,39 @@ namespace mRemoteNG.UI.Forms } private void OnApplicationSettingChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) - { - if (propertyChangedEventArgs.PropertyName != nameof(Settings.LockToolbars)) - return; + { + if (propertyChangedEventArgs.PropertyName != nameof(Settings.LockToolbars)) + return; - LockToolbarPositions(Settings.Default.LockToolbars); - } + LockToolbarPositions(Settings.Default.LockToolbars); + } - private void LockToolbarPositions(bool shouldBeLocked) - { - var toolbars = new ToolStrip[] { _quickConnectToolStrip, _multiSshToolStrip, _externalToolsToolStrip, msMain }; - foreach (var toolbar in toolbars) - { - toolbar.GripStyle = shouldBeLocked - ? ToolStripGripStyle.Hidden - : ToolStripGripStyle.Visible; - } - } + private void LockToolbarPositions(bool shouldBeLocked) + { + var toolbars = new ToolStrip[] + {_quickConnectToolStrip, _multiSshToolStrip, _externalToolsToolStrip, msMain}; + foreach (var toolbar in toolbars) + { + toolbar.GripStyle = shouldBeLocked + ? ToolStripGripStyle.Hidden + : ToolStripGripStyle.Visible; + } + } - private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) + private void ConnectionsServiceOnConnectionsLoaded(object sender, + ConnectionsLoadedEventArgs connectionsLoadedEventArgs) { UpdateWindowTitle(); } - private void ConnectionsServiceOnConnectionsSaved(object sender, ConnectionsSavedEventArgs connectionsSavedEventArgs) + private void ConnectionsServiceOnConnectionsSaved(object sender, + ConnectionsSavedEventArgs connectionsSavedEventArgs) { if (connectionsSavedEventArgs.UsingDatabase) return; - _backupPruner.PruneBackupFiles(connectionsSavedEventArgs.ConnectionFileName, Settings.Default.BackupFileKeepCount); + _backupPruner.PruneBackupFiles(connectionsSavedEventArgs.ConnectionFileName, + Settings.Default.BackupFileKeepCount); } private void SetMenuDependencies() @@ -243,7 +255,7 @@ namespace mRemoteNG.UI.Forms viewMenu.TsExternalTools = _externalToolsToolStrip; viewMenu.TsQuickConnect = _quickConnectToolStrip; - viewMenu.TsMultiSsh = _multiSshToolStrip; + viewMenu.TsMultiSsh = _multiSshToolStrip; viewMenu.FullscreenHandler = Fullscreen; viewMenu.MainForm = this; @@ -255,41 +267,46 @@ namespace mRemoteNG.UI.Forms //Theming support private void ApplyTheme() - { + { if (!_themeManager.ThemingActive) { pnlDock.Theme = _themeManager.DefaultTheme.Theme; return; } - try - { + try + { // this will always throw when turning themes on from // the options menu. - pnlDock.Theme = _themeManager.ActiveTheme.Theme; - } - catch (Exception) - { - // intentionally ignore exception - } + pnlDock.Theme = _themeManager.ActiveTheme.Theme; + } + catch (Exception) + { + // intentionally ignore exception + } - // Persist settings when rebuilding UI - try - { - vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_quickConnectToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + // Persist settings when rebuilding UI + try + { + vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_quickConnectToolStrip, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); if (!_themeManager.ActiveAndExtended) return; - tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - } - catch (Exception ex) - { + tsContainer.TopToolStripPanel.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionStackTrace("Error applying theme", ex, MessageClass.WarningMsg); - } + } } private void frmMain_Shown(object sender, EventArgs e) @@ -308,8 +325,11 @@ namespace mRemoteNG.UI.Forms Language.strAskUpdatesCommandAskLater }; - CTaskDialog.ShowTaskDialogBox(this, GeneralAppInfo.ProductName, Language.strAskUpdatesMainInstruction, string.Format(Language.strAskUpdatesContent, GeneralAppInfo.ProductName), - "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question); + CTaskDialog.ShowTaskDialogBox(this, GeneralAppInfo.ProductName, Language.strAskUpdatesMainInstruction, + string.Format(Language.strAskUpdatesContent, GeneralAppInfo.ProductName), + "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, + ESysIcons.Question, + ESysIcons.Question); if (CTaskDialog.CommandButtonResult == 0 | CTaskDialog.CommandButtonResult == 1) { @@ -329,20 +349,25 @@ namespace mRemoteNG.UI.Forms if (!Settings.Default.CheckForUpdatesOnStartup) return; var nextUpdateCheck = Convert.ToDateTime( - Settings.Default.CheckForUpdatesLastCheck.Add( - TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays)))); + Settings.Default.CheckForUpdatesLastCheck.Add( + TimeSpan + .FromDays(Convert + .ToDouble(Settings + .Default + .CheckForUpdatesFrequencyDays)))); if (!Settings.Default.UpdatePending && DateTime.UtcNow <= nextUpdateCheck) return; - if (!IsHandleCreated) CreateHandle(); // Make sure the handle is created so that InvokeRequired returns the correct result + if (!IsHandleCreated) + CreateHandle(); // Make sure the handle is created so that InvokeRequired returns the correct result Startup.Instance.CheckForUpdate(); } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) - { + { if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0)) - { - var openConnections = 0; + { + var openConnections = 0; if (pnlDock.Contents.Count > 0) { foreach (var dc in pnlDock.Contents) @@ -355,180 +380,198 @@ namespace mRemoteNG.UI.Forms } } - if (openConnections > 0 && (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All | (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & openConnections > 1) || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Exit)) - { - var result = CTaskDialog.MessageBox(this, Application.ProductName, Language.strConfirmExitMainInstruction, "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) - { + if (openConnections > 0 && + (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All | + (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & + openConnections > 1) || Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Exit)) + { + var result = CTaskDialog.MessageBox(this, Application.ProductName, + Language.strConfirmExitMainInstruction, "", "", "", + Language.strCheckboxDoNotShowThisMessageAgain, + ETaskDialogButtons.YesNo, ESysIcons.Question, + ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - e.Cancel = true; - return; - } - } - } + } + + if (result == DialogResult.No) + { + e.Cancel = true; + return; + } + } + } Shutdown.Cleanup(_quickConnectToolStrip, _externalToolsToolStrip, _multiSshToolStrip, this); - IsClosing = true; + IsClosing = true; if (Runtime.WindowList != null) - { + { foreach (BaseWindow window in Runtime.WindowList) - { - window.Close(); - } - } + { + window.Close(); + } + } Shutdown.StartUpdate(); - Debug.Print("[END] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); - } + Debug.Print("[END] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); + } + #endregion #region Timer - private void tmrAutoSave_Tick(object sender, EventArgs e) - { + + private void tmrAutoSave_Tick(object sender, EventArgs e) + { Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Doing AutoSave"); - Runtime.ConnectionsService.SaveConnectionsAsync(); - } + Runtime.ConnectionsService.SaveConnectionsAsync(); + } + #endregion #region Window Overrides and DockPanel Stuff + private void frmMain_ResizeBegin(object sender, EventArgs e) - { - _inSizeMove = true; - } + { + _inSizeMove = true; + } private void frmMain_Resize(object sender, EventArgs e) - { - if (WindowState == FormWindowState.Minimized) - { - if (!Settings.Default.MinimizeToTray) return; - if (Runtime.NotificationAreaIcon == null) - { - Runtime.NotificationAreaIcon = new NotificationAreaIcon(); - } - Hide(); - } - else - { - PreviousWindowState = WindowState; - } - } + { + if (WindowState == FormWindowState.Minimized) + { + if (!Settings.Default.MinimizeToTray) return; + if (Runtime.NotificationAreaIcon == null) + { + Runtime.NotificationAreaIcon = new NotificationAreaIcon(); + } + + Hide(); + } + else + { + PreviousWindowState = WindowState; + } + } private void frmMain_ResizeEnd(object sender, EventArgs e) - { - _inSizeMove = false; - // This handles activations from clicks that started a size/move operation - ActivateConnection(); - } + { + _inSizeMove = false; + // This handles activations from clicks that started a size/move operation + ActivateConnection(); + } - protected override void WndProc(ref System.Windows.Forms.Message m) - { + protected override void WndProc(ref System.Windows.Forms.Message m) + { // Listen for and handle operating system messages - try - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (m.Msg) - { - case NativeMethods.WM_MOUSEACTIVATE: - _inMouseActivate = true; - break; - case NativeMethods.WM_ACTIVATEAPP: + try + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (m.Msg) + { + case NativeMethods.WM_MOUSEACTIVATE: + _inMouseActivate = true; + break; + case NativeMethods.WM_ACTIVATEAPP: var candidateTabToFocus = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) - ?? GetChildAtPoint(MousePosition); + ?? GetChildAtPoint(MousePosition); - if(candidateTabToFocus is InterfaceControl) + if (candidateTabToFocus is InterfaceControl) { candidateTabToFocus.Parent.Focus(); } - _inMouseActivate = false; - break; - case NativeMethods.WM_ACTIVATE: - // Only handle this msg if it was triggered by a click - if (NativeMethods.LOWORD(m.WParam) == NativeMethods.WA_CLICKACTIVE) - { - var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) - ?? GetChildAtPoint(MousePosition); - if (controlThatWasClicked != null) - { - if (controlThatWasClicked is TreeView || - controlThatWasClicked is ComboBox || - controlThatWasClicked is TextBox || + + _inMouseActivate = false; + break; + case NativeMethods.WM_ACTIVATE: + // Only handle this msg if it was triggered by a click + if (NativeMethods.LOWORD(m.WParam) == NativeMethods.WA_CLICKACTIVE) + { + var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) + ?? GetChildAtPoint(MousePosition); + if (controlThatWasClicked != null) + { + if (controlThatWasClicked is TreeView || + controlThatWasClicked is ComboBox || + controlThatWasClicked is TextBox || controlThatWasClicked is FrmMain) - { - controlThatWasClicked.Focus(); - } - else if (controlThatWasClicked.CanSelect || - controlThatWasClicked is MenuStrip || - controlThatWasClicked is ToolStrip ) - { + { + controlThatWasClicked.Focus(); + } + else if (controlThatWasClicked.CanSelect || + controlThatWasClicked is MenuStrip || + controlThatWasClicked is ToolStrip) + { // Simulate a mouse event since one wasn't generated by Windows SimulateClick(controlThatWasClicked); controlThatWasClicked.Focus(); } else if (controlThatWasClicked is AutoHideStripBase) - { + { // only focus the autohide toolstrip controlThatWasClicked.Focus(); - } - else - { - // This handles activations from clicks that did not start a size/move operation - ActivateConnection(); - } - } - } - break; - case NativeMethods.WM_WINDOWPOSCHANGED: - // Ignore this message if the window wasn't activated - var windowPos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS)); - if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0) - { - if (!_inMouseActivate && !_inSizeMove) - ActivateConnection(); - } - break; - case NativeMethods.WM_SYSCOMMAND: - var screen = _screenSystemMenu.GetScreenById(m.WParam.ToInt32()); + } + else + { + // This handles activations from clicks that did not start a size/move operation + ActivateConnection(); + } + } + } + + break; + case NativeMethods.WM_WINDOWPOSCHANGED: + // Ignore this message if the window wasn't activated + var windowPos = + (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS)); + if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0) + { + if (!_inMouseActivate && !_inSizeMove) + ActivateConnection(); + } + + break; + case NativeMethods.WM_SYSCOMMAND: + var screen = _screenSystemMenu.GetScreenById(m.WParam.ToInt32()); if (screen != null) Screens.SendFormToScreen(screen); - break; - case NativeMethods.WM_DRAWCLIPBOARD: - NativeMethods.SendMessage(_fpChainedWindowHandle, m.Msg, m.LParam, m.WParam); - _clipboardChangedEvent?.Invoke(); - break; - case NativeMethods.WM_CHANGECBCHAIN: - //Send to the next window - NativeMethods.SendMessage(_fpChainedWindowHandle, m.Msg, m.LParam, m.WParam); - _fpChainedWindowHandle = m.LParam; - break; - } - } - catch (Exception ex) - { + break; + case NativeMethods.WM_DRAWCLIPBOARD: + NativeMethods.SendMessage(_fpChainedWindowHandle, m.Msg, m.LParam, m.WParam); + _clipboardChangedEvent?.Invoke(); + break; + case NativeMethods.WM_CHANGECBCHAIN: + //Send to the next window + NativeMethods.SendMessage(_fpChainedWindowHandle, m.Msg, m.LParam, m.WParam); + _fpChainedWindowHandle = m.LParam; + break; + } + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionStackTrace("frmMain WndProc failed", ex); } - base.WndProc(ref m); - } + base.WndProc(ref m); + } private void SimulateClick(Control control) { var clientMousePosition = control.PointToClient(MousePosition); var temp_wLow = clientMousePosition.X; var temp_wHigh = clientMousePosition.Y; - NativeMethods.SendMessage(control.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, (IntPtr)NativeMethods.MAKELPARAM(ref temp_wLow, ref temp_wHigh)); + NativeMethods.SendMessage(control.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, + (IntPtr)NativeMethods.MAKELPARAM(ref temp_wLow, ref temp_wHigh)); clientMousePosition.X = temp_wLow; clientMousePosition.Y = temp_wHigh; } - private void ActivateConnection() - { - var cw = pnlDock.ActiveDocument as ConnectionWindow; + private void ActivateConnection() + { + var cw = pnlDock.ActiveDocument as ConnectionWindow; var dp = cw?.ActiveControl as DockPane; if (!(dp?.ActiveContent is ConnectionTab tab)) return; @@ -541,74 +584,76 @@ namespace mRemoteNG.UI.Forms } private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) - { - ActivateConnection(); - } + { + ActivateConnection(); + } - internal void UpdateWindowTitle() - { - if (InvokeRequired) - { - Invoke(new MethodInvoker(UpdateWindowTitle)); - return; - } + internal void UpdateWindowTitle() + { + if (InvokeRequired) + { + Invoke(new MethodInvoker(UpdateWindowTitle)); + return; + } - var titleBuilder = new StringBuilder(Application.ProductName); - const string separator = " - "; + var titleBuilder = new StringBuilder(Application.ProductName); + const string separator = " - "; - if (Runtime.ConnectionsService.IsConnectionsFileLoaded) - { - if (Runtime.ConnectionsService.UsingDatabase) - { - titleBuilder.Append(separator); - titleBuilder.Append(Language.strSQLServer.TrimEnd(':')); - } - else - { - if (!string.IsNullOrEmpty(Runtime.ConnectionsService.ConnectionFileName)) - { - titleBuilder.Append(separator); - titleBuilder.Append(Settings.Default.ShowCompleteConsPathInTitle - ? Runtime.ConnectionsService.ConnectionFileName - : Path.GetFileName(Runtime.ConnectionsService.ConnectionFileName)); - } - } - } + if (Runtime.ConnectionsService.IsConnectionsFileLoaded) + { + if (Runtime.ConnectionsService.UsingDatabase) + { + titleBuilder.Append(separator); + titleBuilder.Append(Language.strSQLServer.TrimEnd(':')); + } + else + { + if (!string.IsNullOrEmpty(Runtime.ConnectionsService.ConnectionFileName)) + { + titleBuilder.Append(separator); + titleBuilder.Append(Settings.Default.ShowCompleteConsPathInTitle + ? Runtime.ConnectionsService.ConnectionFileName + : Path.GetFileName(Runtime.ConnectionsService.ConnectionFileName)); + } + } + } - if (!string.IsNullOrEmpty(SelectedConnection?.Name)) - { - titleBuilder.Append(separator); - titleBuilder.Append(SelectedConnection.Name); + if (!string.IsNullOrEmpty(SelectedConnection?.Name)) + { + titleBuilder.Append(separator); + titleBuilder.Append(SelectedConnection.Name); if (Settings.Default.TrackActiveConnectionInConnectionTree) Windows.TreeForm.JumpToNode(SelectedConnection); - } + } Text = titleBuilder.ToString(); - } + } - public void ShowHidePanelTabs(DockContent closingDocument = null) - { - DocumentStyle newDocumentStyle; + public void ShowHidePanelTabs(DockContent closingDocument = null) + { + DocumentStyle newDocumentStyle; - if (Settings.Default.AlwaysShowPanelTabs) - { - newDocumentStyle = DocumentStyle.DockingWindow; // Show the panel tabs - } - else - { - var nonConnectionPanelCount = 0; - foreach (var dockContent in pnlDock.Documents) - { - var document = (DockContent) dockContent; - if ((closingDocument == null || document != closingDocument) && !(document is ConnectionWindow)) - { - nonConnectionPanelCount++; - } - } + if (Settings.Default.AlwaysShowPanelTabs) + { + newDocumentStyle = DocumentStyle.DockingWindow; // Show the panel tabs + } + else + { + var nonConnectionPanelCount = 0; + foreach (var dockContent in pnlDock.Documents) + { + var document = (DockContent)dockContent; + if ((closingDocument == null || document != closingDocument) && !(document is ConnectionWindow)) + { + nonConnectionPanelCount++; + } + } - newDocumentStyle = nonConnectionPanelCount == 0 ? DocumentStyle.DockingSdi : DocumentStyle.DockingWindow; - } + newDocumentStyle = nonConnectionPanelCount == 0 + ? DocumentStyle.DockingSdi + : DocumentStyle.DockingWindow; + } // TODO: See if we can get this to work with DPS #if false @@ -630,13 +675,15 @@ namespace mRemoteNG.UI.Forms } #endif - if (pnlDock.DocumentStyle == newDocumentStyle) return; - pnlDock.DocumentStyle = newDocumentStyle; - pnlDock.Size = new Size(1, 1); - } -#endregion + if (pnlDock.DocumentStyle == newDocumentStyle) return; + pnlDock.DocumentStyle = newDocumentStyle; + pnlDock.Size = new Size(1, 1); + } + + #endregion + + #region Screen Stuff -#region Screen Stuff public void SetDefaultLayout() { pnlDock.Visible = false; @@ -646,27 +693,38 @@ namespace mRemoteNG.UI.Forms pnlDock.DockTopPortion = pnlDock.Height * 0.25; pnlDock.DockBottomPortion = pnlDock.Height * 0.25; - Windows.TreeForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; + Windows.TreeForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | + DockAreas.DockTop | DockAreas.Float; Windows.TreeForm.Show(pnlDock, DockState.DockLeft); - Windows.ConfigForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; + Windows.ConfigForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | + DockAreas.DockTop | DockAreas.Float; Windows.ConfigForm.Show(pnlDock); Windows.ConfigForm.DockTo(Windows.TreeForm.Pane, DockStyle.Bottom, -1); - Windows.ErrorsForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; - Windows.ErrorsForm.Show( pnlDock, DockState.DockBottomAutoHide ); + Windows.ErrorsForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | + DockAreas.DockTop | DockAreas.Float; + Windows.ErrorsForm.Show(pnlDock, DockState.DockBottomAutoHide); Windows.ScreenshotForm.Hide(); pnlDock.Visible = true; } -#endregion -#region Events + #endregion + + #region Events + public delegate void ClipboardchangeEventHandler(); + public static event ClipboardchangeEventHandler ClipboardChanged { - add => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Combine(_clipboardChangedEvent, value); - remove => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Remove(_clipboardChangedEvent, value); + add => + _clipboardChangedEvent = + (ClipboardchangeEventHandler)Delegate.Combine(_clipboardChangedEvent, value); + remove => + _clipboardChangedEvent = + (ClipboardchangeEventHandler)Delegate.Remove(_clipboardChangedEvent, value); } -#endregion + + #endregion private void ViewMenu_Opening(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index 390ffd3a6..158a1e412 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -14,7 +14,7 @@ namespace mRemoteNG.UI.Forms private readonly string _pageName; private readonly DisplayProperties _display = new DisplayProperties(); - public FrmOptions(): this(Language.strStartupExit) + public FrmOptions() : this(Language.strStartupExit) { } @@ -108,7 +108,7 @@ namespace mRemoteNG.UI.Forms break; } - if(!isSet) + if (!isSet) lstOptionPages.Items[0].Selected = true; } @@ -124,6 +124,7 @@ namespace mRemoteNG.UI.Forms Debug.WriteLine(page.PageName); page.SaveSettings(); } + Debug.WriteLine(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); Settings.Default.Save(); } @@ -145,6 +146,7 @@ namespace mRemoteNG.UI.Forms Debug.WriteLine(page.PageName); page.RevertSettings(); } + Debug.WriteLine(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); } } diff --git a/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs index 26fd63ce6..074093c0e 100644 --- a/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs +++ b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs @@ -11,16 +11,16 @@ namespace mRemoteNG.UI.GraphicsUtilities // Dpi of a 'normal' definition screen private const int BaselineDpi = 96; - + public SizeF GetResolutionScalingFactor() { //This method could be optimized, as it is called for every control / subcontrol //and causes overhead for 100s in the options page using (var f = new Form()) - { + { var g = f.CreateGraphics(); - return new SizeF(g.DpiX / BaselineDpi, g.DpiY / BaselineDpi); - } + return new SizeF(g.DpiX / BaselineDpi, g.DpiY / BaselineDpi); + } } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs b/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs index 918a5b7e4..ac9451a3c 100644 --- a/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs +++ b/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs @@ -6,4 +6,4 @@ namespace mRemoteNG.UI.GraphicsUtilities { SizeF GetResolutionScalingFactor(); } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/HelpMenu.cs b/mRemoteV1/UI/Menu/HelpMenu.cs index 74db6e2f5..ec4eb70b3 100644 --- a/mRemoteV1/UI/Menu/HelpMenu.cs +++ b/mRemoteV1/UI/Menu/HelpMenu.cs @@ -40,17 +40,19 @@ namespace mRemoteNG.UI.Menu // // mMenInfo // - DropDownItems.AddRange(new ToolStripItem[] { - _mMenInfoHelp, - _mMenInfoSep1, - _mMenInfoWebsite, - _mMenInfoDonate, - _mMenInfoForum, - _mMenInfoBugReport, - _toolStripSeparator2, - _mMenToolsUpdate, - _mMenInfoSep2, - _mMenInfoAbout}); + DropDownItems.AddRange(new ToolStripItem[] + { + _mMenInfoHelp, + _mMenInfoSep1, + _mMenInfoWebsite, + _mMenInfoDonate, + _mMenInfoForum, + _mMenInfoBugReport, + _toolStripSeparator2, + _mMenToolsUpdate, + _mMenInfoSep2, + _mMenInfoAbout + }); Name = "mMenInfo"; Size = new System.Drawing.Size(44, 20); Text = Language.strMenuHelp; @@ -142,6 +144,7 @@ namespace mRemoteNG.UI.Menu } #region Info + private void mMenToolsUpdate_Click(object sender, EventArgs e) => Windows.Show(WindowType.Update); private void mMenInfoHelp_Click(object sender, EventArgs e) => Windows.Show(WindowType.Help); @@ -155,6 +158,7 @@ namespace mRemoteNG.UI.Menu private void mMenInfoDonate_Click(object sender, EventArgs e) => Process.Start(GeneralAppInfo.UrlDonate); private void mMenInfoAbout_Click(object sender, EventArgs e) => Windows.Show(WindowType.About); + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/MainFileMenu.cs b/mRemoteV1/UI/Menu/MainFileMenu.cs index 31ee707d2..49ac393f1 100644 --- a/mRemoteV1/UI/Menu/MainFileMenu.cs +++ b/mRemoteV1/UI/Menu/MainFileMenu.cs @@ -70,7 +70,8 @@ namespace mRemoteNG.UI.Menu // // mMenFile // - DropDownItems.AddRange(new ToolStripItem[] { + DropDownItems.AddRange(new ToolStripItem[] + { _mMenFileNewConnection, _mMenFileNewFolder, _mMenFileSep1, @@ -110,7 +111,7 @@ namespace mRemoteNG.UI.Menu _mMenFileNewFolder.Image = Resources.Folder_Add; _mMenFileNewFolder.Name = "mMenFileNewFolder"; _mMenFileNewFolder.ShortcutKeys = (Keys.Control | Keys.Shift) - | Keys.N; + | Keys.N; _mMenFileNewFolder.Size = new System.Drawing.Size(281, 22); _mMenFileNewFolder.Text = Language.strNewFolder; _mMenFileNewFolder.Click += mMenFileNewFolder_Click; @@ -151,7 +152,7 @@ namespace mRemoteNG.UI.Menu _mMenFileSaveAs.Image = Resources.Connections_SaveAs; _mMenFileSaveAs.Name = "mMenFileSaveAs"; _mMenFileSaveAs.ShortcutKeys = (Keys.Control | Keys.Shift) - | Keys.S; + | Keys.S; _mMenFileSaveAs.Size = new System.Drawing.Size(281, 22); _mMenFileSaveAs.Text = Language.strMenuSaveConnectionFileAs; _mMenFileSaveAs.Click += mMenFileSaveAs_Click; @@ -205,10 +206,12 @@ namespace mRemoteNG.UI.Menu // // mMenFileImport // - _mMenFileImport.DropDownItems.AddRange(new ToolStripItem[] { - _mMenFileImportFromFile, - _mMenFileImportFromActiveDirectory, - _mMenFileImportFromPortScan}); + _mMenFileImport.DropDownItems.AddRange(new ToolStripItem[] + { + _mMenFileImportFromFile, + _mMenFileImportFromActiveDirectory, + _mMenFileImportFromPortScan + }); _mMenFileImport.Name = "mMenFileImport"; _mMenFileImport.Size = new System.Drawing.Size(281, 22); _mMenFileImport.Text = Language.strImportMenuItem; @@ -274,6 +277,7 @@ namespace mRemoteNG.UI.Menu } #region File + internal void mMenFile_DropDownOpening(object sender, EventArgs e) { var selectedNodeType = TreeWindow.SelectedNode?.GetTreeNodeType(); @@ -381,7 +385,8 @@ namespace mRemoteNG.UI.Menu { if (Runtime.ConnectionsService.IsConnectionsFileLoaded) { - var msgBoxResult = MessageBox.Show(Language.strSaveConnectionsFileBeforeOpeningAnother, Language.strSave, MessageBoxButtons.YesNoCancel); + var msgBoxResult = MessageBox.Show(Language.strSaveConnectionsFileBeforeOpeningAnother, + Language.strSave, MessageBoxButtons.YesNoCancel); // ReSharper disable once SwitchStatementMissingSomeCases switch (msgBoxResult) { @@ -410,7 +415,8 @@ namespace mRemoteNG.UI.Menu var newFileName = saveFileDialog.FileName; - Runtime.ConnectionsService.SaveConnections(Runtime.ConnectionsService.ConnectionTreeModel, false, new SaveFilter(), newFileName); + Runtime.ConnectionsService.SaveConnections(Runtime.ConnectionsService.ConnectionTreeModel, false, + new SaveFilter(), newFileName); if (newFileName == Runtime.ConnectionsService.GetDefaultStartupConnectionFileName()) { @@ -481,6 +487,7 @@ namespace mRemoteNG.UI.Menu { Shutdown.Quit(); } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/ScreenSelectionSystemMenu.cs b/mRemoteV1/UI/Menu/ScreenSelectionSystemMenu.cs index 749961f8c..9aaa455f1 100644 --- a/mRemoteV1/UI/Menu/ScreenSelectionSystemMenu.cs +++ b/mRemoteV1/UI/Menu/ScreenSelectionSystemMenu.cs @@ -22,6 +22,7 @@ namespace mRemoteNG.UI.Menu if (_sysMenSubItems[i] != id) continue; return Screen.AllScreens[i]; } + return null; } @@ -43,11 +44,16 @@ namespace mRemoteNG.UI.Menu for (var i = 0; i <= Screen.AllScreens.Length - 1; i++) { _sysMenSubItems[i] = 200 + i; - _systemMenu.AppendMenuItem(popMen, SystemMenu.Flags.MF_STRING, new IntPtr(_sysMenSubItems[i]), Language.strScreen + " " + Convert.ToString(i + 1)); + _systemMenu.AppendMenuItem(popMen, SystemMenu.Flags.MF_STRING, new IntPtr(_sysMenSubItems[i]), + Language.strScreen + " " + Convert.ToString(i + 1)); } - _systemMenu.InsertMenuItem(_systemMenu.SystemMenuHandle, 0, SystemMenu.Flags.MF_POPUP | SystemMenu.Flags.MF_BYPOSITION, popMen, Language.strSendTo); - _systemMenu.InsertMenuItem(_systemMenu.SystemMenuHandle, 1, SystemMenu.Flags.MF_BYPOSITION | SystemMenu.Flags.MF_SEPARATOR, IntPtr.Zero, null); + _systemMenu.InsertMenuItem(_systemMenu.SystemMenuHandle, 0, + SystemMenu.Flags.MF_POPUP | SystemMenu.Flags.MF_BYPOSITION, popMen, + Language.strSendTo); + _systemMenu.InsertMenuItem(_systemMenu.SystemMenuHandle, 1, + SystemMenu.Flags.MF_BYPOSITION | SystemMenu.Flags.MF_SEPARATOR, IntPtr.Zero, + null); } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/ToolsMenu.cs b/mRemoteV1/UI/Menu/ToolsMenu.cs index fb02d0fec..e8ba44867 100644 --- a/mRemoteV1/UI/Menu/ToolsMenu.cs +++ b/mRemoteV1/UI/Menu/ToolsMenu.cs @@ -5,7 +5,7 @@ using mRemoteNG.Credential; namespace mRemoteNG.UI.Menu { - public class ToolsMenu : ToolStripMenuItem + public class ToolsMenu : ToolStripMenuItem { private ToolStripSeparator _mMenToolsSep1; private ToolStripMenuItem _mMenToolsOptions; @@ -37,15 +37,17 @@ namespace mRemoteNG.UI.Menu // // mMenTools // - DropDownItems.AddRange(new ToolStripItem[] { - _mMenToolsSshTransfer, - _mMenToolsUvncsc, - _mMenToolsExternalApps, - _mMenToolsPortScan, - _mMenViewScreenshotManager, - _mMenToolsSep1, - _mMenToolsComponentsCheck, - _mMenToolsOptions}); + DropDownItems.AddRange(new ToolStripItem[] + { + _mMenToolsSshTransfer, + _mMenToolsUvncsc, + _mMenToolsExternalApps, + _mMenToolsPortScan, + _mMenViewScreenshotManager, + _mMenToolsSep1, + _mMenToolsComponentsCheck, + _mMenToolsOptions + }); Name = "mMenTools"; Size = new System.Drawing.Size(48, 20); Text = Language.strMenuTools; @@ -125,6 +127,7 @@ namespace mRemoteNG.UI.Menu } #region Tools + private void mMenToolsSSHTransfer_Click(object sender, EventArgs e) { Windows.Show(WindowType.SSHTransfer); @@ -159,6 +162,7 @@ namespace mRemoteNG.UI.Menu { Windows.Show(WindowType.Options); } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/ViewMenu.cs b/mRemoteV1/UI/Menu/ViewMenu.cs index 38b294d7b..e9cb01d56 100644 --- a/mRemoteV1/UI/Menu/ViewMenu.cs +++ b/mRemoteV1/UI/Menu/ViewMenu.cs @@ -7,7 +7,7 @@ using mRemoteNG.UI.Window; namespace mRemoteNG.UI.Menu { - public class ViewMenu : ToolStripMenuItem + public class ViewMenu : ToolStripMenuItem { private ToolStripMenuItem _mMenViewConnectionPanels; private ToolStripSeparator _mMenViewSep1; @@ -28,11 +28,11 @@ namespace mRemoteNG.UI.Menu private ToolStripMenuItem _mMenViewLockToolbars; private ToolStripSeparator _toolStripSeparator1; private readonly PanelAdder _panelAdder; - - public ToolStrip TsExternalTools { get; set; } + + public ToolStrip TsExternalTools { get; set; } public ToolStrip TsQuickConnect { get; set; } - public ToolStrip TsMultiSsh { get; set; } + public ToolStrip TsMultiSsh { get; set; } public FullscreenHandler FullscreenHandler { get; set; } public FrmMain MainForm { get; set; } @@ -41,7 +41,7 @@ namespace mRemoteNG.UI.Menu { Initialize(); _panelAdder = new PanelAdder(); - } + } private void Initialize() { @@ -55,35 +55,37 @@ namespace mRemoteNG.UI.Menu _mMenViewJumpToConnectionsConfig = new ToolStripMenuItem(); _mMenViewJumpToErrorsInfos = new ToolStripMenuItem(); _mMenViewResetLayout = new ToolStripMenuItem(); - _mMenViewLockToolbars = new ToolStripMenuItem(); + _mMenViewLockToolbars = new ToolStripMenuItem(); _mMenViewSep2 = new ToolStripSeparator(); _mMenViewQuickConnectToolbar = new ToolStripMenuItem(); _mMenViewExtAppsToolbar = new ToolStripMenuItem(); - _mMenViewMultiSshToolbar = new ToolStripMenuItem(); - _mMenViewSep3 = new ToolStripSeparator(); + _mMenViewMultiSshToolbar = new ToolStripMenuItem(); + _mMenViewSep3 = new ToolStripSeparator(); _mMenViewFullscreen = new ToolStripMenuItem(); _toolStripSeparator1 = new ToolStripSeparator(); // // mMenView // - DropDownItems.AddRange(new ToolStripItem[] { - _mMenViewAddConnectionPanel, - _mMenViewConnectionPanels, - _mMenViewSep1, - _mMenViewConnections, - _mMenViewConfig, - _mMenViewErrorsAndInfos, - _toolStripSeparator1, - _mMenViewJumpTo, - _mMenViewResetLayout, - _mMenViewLockToolbars, - _mMenViewSep2, - _mMenViewQuickConnectToolbar, - _mMenViewExtAppsToolbar, - _mMenViewMultiSshToolbar, - _mMenViewSep3, - _mMenViewFullscreen}); + DropDownItems.AddRange(new ToolStripItem[] + { + _mMenViewAddConnectionPanel, + _mMenViewConnectionPanels, + _mMenViewSep1, + _mMenViewConnections, + _mMenViewConfig, + _mMenViewErrorsAndInfos, + _toolStripSeparator1, + _mMenViewJumpTo, + _mMenViewResetLayout, + _mMenViewLockToolbars, + _mMenViewSep2, + _mMenViewQuickConnectToolbar, + _mMenViewExtAppsToolbar, + _mMenViewMultiSshToolbar, + _mMenViewSep3, + _mMenViewFullscreen + }); Name = "mMenView"; Size = new System.Drawing.Size(44, 20); Text = Language.strMenuView; @@ -146,9 +148,11 @@ namespace mRemoteNG.UI.Menu // // mMenViewJumpTo // - _mMenViewJumpTo.DropDownItems.AddRange(new ToolStripItem[] { - _mMenViewJumpToConnectionsConfig, - _mMenViewJumpToErrorsInfos}); + _mMenViewJumpTo.DropDownItems.AddRange(new ToolStripItem[] + { + _mMenViewJumpToConnectionsConfig, + _mMenViewJumpToErrorsInfos + }); _mMenViewJumpTo.Image = Resources.JumpTo; _mMenViewJumpTo.Name = "mMenViewJumpTo"; _mMenViewJumpTo.Size = new System.Drawing.Size(228, 22); @@ -179,18 +183,18 @@ namespace mRemoteNG.UI.Menu _mMenViewResetLayout.Size = new System.Drawing.Size(228, 22); _mMenViewResetLayout.Text = Language.strMenuResetLayout; _mMenViewResetLayout.Click += mMenViewResetLayout_Click; - // - // mMenViewLockToolbars - // - _mMenViewLockToolbars.Image = Resources.application_side_tree; - _mMenViewLockToolbars.Name = "mMenViewLockToolbars"; - _mMenViewLockToolbars.Size = new System.Drawing.Size(228, 22); - _mMenViewLockToolbars.Text = Language.strMenuLockToolbars; + // + // mMenViewLockToolbars + // + _mMenViewLockToolbars.Image = Resources.application_side_tree; + _mMenViewLockToolbars.Name = "mMenViewLockToolbars"; + _mMenViewLockToolbars.Size = new System.Drawing.Size(228, 22); + _mMenViewLockToolbars.Text = Language.strMenuLockToolbars; _mMenViewLockToolbars.Click += mMenViewLockToolbars_Click; - // - // mMenViewSep2 - // - _mMenViewSep2.Name = "mMenViewSep2"; + // + // mMenViewSep2 + // + _mMenViewSep2.Name = "mMenViewSep2"; _mMenViewSep2.Size = new System.Drawing.Size(225, 6); // // mMenViewQuickConnectToolbar @@ -208,18 +212,18 @@ namespace mRemoteNG.UI.Menu _mMenViewExtAppsToolbar.Size = new System.Drawing.Size(228, 22); _mMenViewExtAppsToolbar.Text = Language.strMenuExternalToolsToolbar; _mMenViewExtAppsToolbar.Click += mMenViewExtAppsToolbar_Click; - // - // mMenViewMultiSSHToolbar - // - _mMenViewMultiSshToolbar.Image = Resources.Panels; - _mMenViewMultiSshToolbar.Name = "mMenViewMultiSSHToolbar"; - _mMenViewMultiSshToolbar.Size = new System.Drawing.Size(279, 26); - _mMenViewMultiSshToolbar.Text = Language.strMenuMultiSshToolbar; + // + // mMenViewMultiSSHToolbar + // + _mMenViewMultiSshToolbar.Image = Resources.Panels; + _mMenViewMultiSshToolbar.Name = "mMenViewMultiSSHToolbar"; + _mMenViewMultiSshToolbar.Size = new System.Drawing.Size(279, 26); + _mMenViewMultiSshToolbar.Text = Language.strMenuMultiSshToolbar; _mMenViewMultiSshToolbar.Click += mMenViewMultiSSHToolbar_Click; - // - // mMenViewSep3 - // - _mMenViewSep3.Name = "mMenViewSep3"; + // + // mMenViewSep3 + // + _mMenViewSep3.Name = "mMenViewSep3"; _mMenViewSep3.Size = new System.Drawing.Size(225, 6); // // mMenViewFullscreen @@ -233,9 +237,8 @@ namespace mRemoteNG.UI.Menu _mMenViewFullscreen.Click += mMenViewFullscreen_Click; } - - public void ApplyLanguage() + public void ApplyLanguage() { Text = Language.strMenuView; _mMenViewAddConnectionPanel.Text = Language.strMenuAddConnectionPanel; @@ -255,24 +258,25 @@ namespace mRemoteNG.UI.Menu } #region View + internal void mMenView_DropDownOpening(object sender, EventArgs e) { _mMenViewConnections.Checked = !Windows.TreeForm.IsHidden; _mMenViewConfig.Checked = !Windows.ConfigForm.IsHidden; _mMenViewErrorsAndInfos.Checked = !Windows.ErrorsForm.IsHidden; - _mMenViewLockToolbars.Checked = Settings.Default.LockToolbars; + _mMenViewLockToolbars.Checked = Settings.Default.LockToolbars; _mMenViewExtAppsToolbar.Checked = TsExternalTools.Visible; _mMenViewQuickConnectToolbar.Checked = TsQuickConnect.Visible; - _mMenViewMultiSshToolbar.Checked = TsMultiSsh.Visible; + _mMenViewMultiSshToolbar.Checked = TsMultiSsh.Visible; - _mMenViewConnectionPanels.DropDownItems.Clear(); + _mMenViewConnectionPanels.DropDownItems.Clear(); for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) { var tItem = new ToolStripMenuItem(Runtime.WindowList[i].Text, - Runtime.WindowList[i].Icon.ToBitmap(), ConnectionPanelMenuItem_Click) - { Tag = Runtime.WindowList[i] }; + Runtime.WindowList[i].Icon.ToBitmap(), ConnectionPanelMenuItem_Click) + {Tag = Runtime.WindowList[i]}; _mMenViewConnectionPanels.DropDownItems.Add(tItem); } @@ -347,28 +351,28 @@ namespace mRemoteNG.UI.Menu private void mMenViewResetLayout_Click(object sender, EventArgs e) { var msgBoxResult = MessageBox.Show(Language.strConfirmResetLayout, string.Empty, MessageBoxButtons.YesNo, - MessageBoxIcon.Question); + MessageBoxIcon.Question); if (msgBoxResult == DialogResult.Yes) { MainForm.SetDefaultLayout(); } } - private void mMenViewLockToolbars_Click(object sender, EventArgs eventArgs) - { - if (Settings.Default.LockToolbars) - { - Settings.Default.LockToolbars = false; - _mMenViewLockToolbars.Checked = false; - } - else - { - Settings.Default.LockToolbars = true; - _mMenViewLockToolbars.Checked = true; - } - } + private void mMenViewLockToolbars_Click(object sender, EventArgs eventArgs) + { + if (Settings.Default.LockToolbars) + { + Settings.Default.LockToolbars = false; + _mMenViewLockToolbars.Checked = false; + } + else + { + Settings.Default.LockToolbars = true; + _mMenViewLockToolbars.Checked = true; + } + } - private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e) + private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e) { _panelAdder.AddPanel(); } @@ -401,25 +405,26 @@ namespace mRemoteNG.UI.Menu } } - private void mMenViewMultiSSHToolbar_Click(object sender, EventArgs e) - { - if (_mMenViewMultiSshToolbar.Checked == false) - { - TsMultiSsh.Visible = true; - _mMenViewMultiSshToolbar.Checked = true; - } - else - { - TsMultiSsh.Visible = false; - _mMenViewMultiSshToolbar.Checked = false; - } - } + private void mMenViewMultiSSHToolbar_Click(object sender, EventArgs e) + { + if (_mMenViewMultiSshToolbar.Checked == false) + { + TsMultiSsh.Visible = true; + _mMenViewMultiSshToolbar.Checked = true; + } + else + { + TsMultiSsh.Visible = false; + _mMenViewMultiSshToolbar.Checked = false; + } + } - private void mMenViewFullscreen_Click(object sender, EventArgs e) + private void mMenViewFullscreen_Click(object sender, EventArgs e) { FullscreenHandler.Value = !FullscreenHandler.Value; _mMenViewFullscreen.Checked = FullscreenHandler.Value; } + #endregion } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index 795babf3e..438ffbff3 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -26,7 +26,8 @@ namespace mRemoteNG.UI.Panels } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Couldn\'t add panel" + Environment.NewLine + ex.Message); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "Couldn\'t add panel" + Environment.NewLine + ex.Message); return null; } } @@ -59,7 +60,7 @@ namespace mRemoteNG.UI.Panels var cMen = new ContextMenuStrip(); var cMenRen = CreateRenameMenuItem(pnlcForm); var cMenScreens = CreateScreensMenuItem(pnlcForm); - cMen.Items.AddRange(new ToolStripItem[] { cMenRen, cMenScreens }); + cMen.Items.AddRange(new ToolStripItem[] {cMenRen, cMenScreens}); pnlcForm.TabPageContextMenuStrip = cMen; } @@ -100,7 +101,8 @@ namespace mRemoteNG.UI.Panels } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenConnectionPanelRename_Click: Caught Exception: ", ex); + Runtime.MessageCollector.AddExceptionStackTrace("cMenConnectionPanelRename_Click: Caught Exception: ", + ex); } } @@ -126,7 +128,9 @@ namespace mRemoteNG.UI.Panels } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenConnectionPanelScreens_DropDownOpening: Caught Exception: ", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "cMenConnectionPanelScreens_DropDownOpening: Caught Exception: ", + ex); } } @@ -149,11 +153,13 @@ namespace mRemoteNG.UI.Panels panel = (DockContent)obj; } } + Screens.SendPanelToScreen(panel, screen); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenConnectionPanelScreen_Click: Caught Exception: ", ex); + Runtime.MessageCollector.AddExceptionStackTrace("cMenConnectionPanelScreen_Click: Caught Exception: ", + ex); } } } diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 203c453ee..b3be1ceff 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -17,6 +17,7 @@ namespace mRemoteNG.UI.Tabs ///Silent close ignores the popup asking for confirmation /// public bool silentClose { get; set; } + /// /// Protocol close ignores the interface controller cleanup and the user confirmation dialog /// @@ -35,17 +36,24 @@ namespace mRemoteNG.UI.Tabs protected override void OnFormClosing(FormClosingEventArgs e) { - if(!protocolClose) + if (!protocolClose) { if (!silentClose) { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, + string + .Format(Language.strConfirmCloseConnectionPanelMainInstruction, + TabText), "", "", "", + Language.strCheckboxDoNotShowThisMessageAgain, + ETaskDialogButtons.YesNo, ESysIcons.Question, + ESysIcons.Question); if (CTaskDialog.VerificationChecked) { Settings.Default.ConfirmCloseConnection--; } + if (result == DialogResult.No) { e.Cancel = true; @@ -66,11 +74,13 @@ namespace mRemoteNG.UI.Tabs ((InterfaceControl)Tag)?.Protocol.Close(); } } + base.OnFormClosing(e); } #region HelperFunctions + public void RefreshInterfaceController() { try @@ -84,6 +94,7 @@ namespace mRemoteNG.UI.Tabs Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); } } + #endregion } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 437e2cce0..af5fcd30f 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -60,7 +60,7 @@ namespace mRemoteNG.UI.Tabs private const int _ToolWindowStripGapLeft = 0; private const int _ToolWindowStripGapRight = 0; private const int _ToolWindowImageHeight = 16; - private const int _ToolWindowImageWidth = 0;//16; + private const int _ToolWindowImageWidth = 0; //16; private const int _ToolWindowImageGapTop = 3; private const int _ToolWindowImageGapBottom = 1; private const int _ToolWindowImageGapLeft = 2; @@ -76,10 +76,10 @@ namespace mRemoteNG.UI.Tabs private const int _DocumentButtonGapBottom = 3; private const int _DocumentButtonGapBetween = 0; private const int _DocumentButtonGapRight = 3; - private const int _DocumentTabGapTop = 0;//3; - private const int _DocumentTabGapLeft = 0;//3; - private const int _DocumentTabGapRight = 0;//3; - private const int _DocumentIconGapBottom = 2;//2; + private const int _DocumentTabGapTop = 0; //3; + private const int _DocumentTabGapLeft = 0; //3; + private const int _DocumentTabGapRight = 0; //3; + private const int _DocumentIconGapBottom = 2; //2; private const int _DocumentIconGapLeft = 8; private const int _DocumentIconGapRight = 0; private const int _DocumentIconHeight = 16; @@ -99,18 +99,23 @@ namespace mRemoteNG.UI.Tabs private bool m_documentTabsOverflow; private static string m_toolTipSelect; private bool m_suspendDrag; + #endregion #region Properties - private Rectangle TabStripRectangle => Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; + private Rectangle TabStripRectangle => + Appearance == DockPane.AppearanceStyle.Document + ? TabStripRectangle_Document + : TabStripRectangle_ToolWindow; private Rectangle TabStripRectangle_ToolWindow { get { var rect = ClientRectangle; - return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); + return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, + rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); } } @@ -119,7 +124,8 @@ namespace mRemoteNG.UI.Tabs get { var rect = ClientRectangle; - return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height + DocumentStripGapTop - DocumentStripGapBottom); + return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, + rect.Height + DocumentStripGapTop - DocumentStripGapBottom); } } @@ -138,11 +144,11 @@ namespace mRemoteNG.UI.Tabs x += DocumentTabGapLeft; width -= DocumentTabGapLeft + - DocumentTabGapRight + - DocumentButtonGapRight + - ButtonOverflow.Width + - ButtonWindowList.Width + - 2 * DocumentButtonGapBetween; + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonOverflow.Width + + ButtonWindowList.Width + + 2 * DocumentButtonGapBetween; return new Rectangle(x, y, width, height); } @@ -158,9 +164,9 @@ namespace mRemoteNG.UI.Tabs { if (m_buttonOverflow != null) return m_buttonOverflow; m_buttonOverflow = new InertButton( - DockPane.DockPanel.Theme.ImageService.DockPaneHover_OptionOverflow, - DockPane.DockPanel.Theme.ImageService.DockPane_OptionOverflow, - DockPane.DockPanel.Theme.ImageService.DockPanePress_OptionOverflow); + DockPane.DockPanel.Theme.ImageService.DockPaneHover_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPane_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPanePress_OptionOverflow); m_buttonOverflow.Click += WindowList_Click; Controls.Add(m_buttonOverflow); @@ -174,9 +180,9 @@ namespace mRemoteNG.UI.Tabs { if (m_buttonWindowList != null) return m_buttonWindowList; m_buttonWindowList = new InertButton( - DockPane.DockPanel.Theme.ImageService.DockPaneHover_List, - DockPane.DockPanel.Theme.ImageService.DockPane_List, - DockPane.DockPanel.Theme.ImageService.DockPanePress_List); + DockPane.DockPanel.Theme.ImageService.DockPaneHover_List, + DockPane.DockPanel.Theme.ImageService.DockPane_List, + DockPane.DockPanel.Theme.ImageService.DockPanePress_List); m_buttonWindowList.Click += WindowList_Click; Controls.Add(m_buttonWindowList); @@ -337,9 +343,9 @@ namespace mRemoteNG.UI.Tabs : base(pane) { SetStyle(ControlStyles.ResizeRedraw | - ControlStyles.UserPaint | - ControlStyles.AllPaintingInWmPaint | - ControlStyles.OptimizedDoubleBuffer, true); + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); SuspendLayout(); @@ -362,6 +368,7 @@ namespace mRemoteNG.UI.Tabs m_boldFont = null; } } + base.Dispose(disposing); } @@ -378,17 +385,20 @@ namespace mRemoteNG.UI.Tabs return 0; var height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), - ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) - + ToolWindowStripGapTop + ToolWindowStripGapBottom; + ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + + ToolWindowStripGapTop + ToolWindowStripGapBottom; return height; } private int MeasureHeight_Document() { - var height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), - ButtonOverflow.Height + DocumentButtonGapTop + DocumentButtonGapBottom) - + DocumentStripGapBottom + DocumentStripGapTop; + var height = + Math.Max( + TextFont.Height + DocumentTabGapTop + + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + ButtonOverflow.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + + DocumentStripGapBottom + DocumentStripGapTop; return height; } @@ -414,7 +424,9 @@ namespace mRemoteNG.UI.Tabs public override GraphicsPath GetOutline(int index) { - return Appearance == DockPane.AppearanceStyle.Document ? GetOutline_Document(index) : GetOutline_ToolWindow(index); + return Appearance == DockPane.AppearanceStyle.Document + ? GetOutline_Document(index) + : GetOutline_ToolWindow(index); } private GraphicsPath GetOutline_Document(int index) @@ -447,8 +459,8 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom); path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); } - return path; + return path; } private GraphicsPath GetOutline_ToolWindow(int index) @@ -469,7 +481,6 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); return path; - } private void CalculateTabs() @@ -491,7 +502,7 @@ namespace mRemoteNG.UI.Tabs var countTabs = Tabs.Count; foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); tab.Flag = false; } @@ -507,7 +518,7 @@ namespace mRemoteNG.UI.Tabs anyWidthWithinAverage = false; foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; if (tab.Flag) continue; @@ -518,6 +529,7 @@ namespace mRemoteNG.UI.Tabs anyWidthWithinAverage = true; remainedTabs--; } + if (remainedTabs != 0) averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; } @@ -528,7 +540,7 @@ namespace mRemoteNG.UI.Tabs var roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; if (tab.Flag) continue; @@ -547,7 +559,7 @@ namespace mRemoteNG.UI.Tabs var x = rectTabStrip.X + ToolWindowStripGapLeft; foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; tab.TabX = x; x += tab.TabWidth; } @@ -639,7 +651,7 @@ namespace mRemoteNG.UI.Tabs x = rectTabStrip.X; foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; tab.TabX = x; x += tab.TabWidth; } @@ -685,7 +697,7 @@ namespace mRemoteNG.UI.Tabs var content = Tabs[index].Content; var sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft - + ToolWindowImageGapRight + ToolWindowTextGapRight; + + ToolWindowImageGapRight + ToolWindowTextGapRight; } private const int TAB_CLOSE_BUTTON_WIDTH = 30; @@ -694,11 +706,13 @@ namespace mRemoteNG.UI.Tabs { var content = Tabs[index].Content; var height = GetTabRectangle_Document(index).Height; - var sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + var sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, + new Size(DocumentTabMaxWidth, height), DocumentTextFormat); int width; if (DockPane.DockPanel.ShowDocumentIcon) - width = sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; + width = sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + + DocumentTextGapRight; else width = sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; @@ -710,7 +724,10 @@ namespace mRemoteNG.UI.Tabs { // IMPORTANT: fill background. var rectTabStrip = TabStripRectangle; - g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background), rectTabStrip); + g.FillRectangle( + DockPane.DockPanel.Theme.PaintingService.GetBrush(DockPane.DockPanel.Theme.ColorPalette + .MainWindowActive + .Background), rectTabStrip); if (Appearance == DockPane.AppearanceStyle.Document) DrawTabStrip_Document(g); @@ -758,7 +775,8 @@ namespace mRemoteNG.UI.Tabs else tabUnderLineColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background; - g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(tabUnderLineColor, 4), rectTabStrip.Left, rectTabStrip.Bottom, rectTabStrip.Right, rectTabStrip.Bottom); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(tabUnderLineColor, 4), rectTabStrip.Left, + rectTabStrip.Bottom, rectTabStrip.Right, rectTabStrip.Bottom); } g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); @@ -776,7 +794,7 @@ namespace mRemoteNG.UI.Tabs var borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, - rect.Right, rect.Top); + rect.Right, rect.Top); for (var i = 0; i < Tabs.Count; i++) { @@ -788,7 +806,9 @@ namespace mRemoteNG.UI.Tabs private Rectangle GetTabRectangle(int index) { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabRectangle_ToolWindow(index) : GetTabRectangle_Document(index); + return Appearance == DockPane.AppearanceStyle.ToolWindow + ? GetTabRectangle_ToolWindow(index) + : GetTabRectangle_Document(index); } private Rectangle GetTabRectangle_ToolWindow(int index) @@ -827,7 +847,9 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabOutline_ToolWindow(tab, rtlTransform, toScreen) : GetTabOutline_Document(tab, rtlTransform, toScreen, false); + return Appearance == DockPane.AppearanceStyle.ToolWindow + ? GetTabOutline_ToolWindow(tab, rtlTransform, toScreen) + : GetTabOutline_Document(tab, rtlTransform, toScreen, false); } private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) @@ -865,14 +887,14 @@ namespace mRemoteNG.UI.Tabs if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; var rectIcon = new Rectangle( - rect.X + ToolWindowImageGapLeft, - rect.Y + rect.Height - ToolWindowImageGapBottom - ToolWindowImageHeight, - ToolWindowImageWidth, ToolWindowImageHeight); + rect.X + ToolWindowImageGapLeft, + rect.Y + rect.Height - ToolWindowImageGapBottom - ToolWindowImageHeight, + ToolWindowImageWidth, ToolWindowImageHeight); var rectText = PatchController.EnableHighDpi == true ? new Rectangle( - rect.X + ToolWindowImageGapLeft, - rect.Y + rect.Height - ToolWindowImageGapBottom - TextFont.Height, - ToolWindowImageWidth, TextFont.Height) + rect.X + ToolWindowImageGapLeft, + rect.Y + rect.Height - ToolWindowImageGapBottom - TextFont.Height, + ToolWindowImageWidth, TextFont.Height) : rectIcon; rectText.X += rectIcon.Width + ToolWindowImageGapRight; rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - @@ -901,12 +923,13 @@ namespace mRemoteNG.UI.Tabs g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(backgroundColor), rect); g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, - rect.Left, rect.Bottom); + rect.Left, rect.Bottom); g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Bottom - 1, - rect.Right, rect.Bottom - 1); + rect.Right, rect.Bottom - 1); g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Right - 1, rect.Top, - rect.Right - 1, rect.Bottom); - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + rect.Right - 1, rect.Bottom); + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, + ToolWindowTextFormat); } else { @@ -925,8 +948,9 @@ namespace mRemoteNG.UI.Tabs g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(backgroundColor), rect); g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, - rect.Right, rect.Top); - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); + rect.Right, rect.Top); + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, + ToolWindowTextFormat); } if (rectTab.Contains(rectIcon)) @@ -942,20 +966,21 @@ namespace mRemoteNG.UI.Tabs var rectCloseButton = GetCloseButtonRect(rect); var rectIcon = new Rectangle( - rect.X + DocumentIconGapLeft, - rect.Y + rect.Height - DocumentIconGapBottom - DocumentIconHeight, - DocumentIconWidth, DocumentIconHeight); + rect.X + DocumentIconGapLeft, + rect.Y + rect.Height - DocumentIconGapBottom - DocumentIconHeight, + DocumentIconWidth, DocumentIconHeight); var rectText = PatchController.EnableHighDpi == true ? new Rectangle( - rect.X + DocumentIconGapLeft, - rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, - DocumentIconWidth, TextFont.Height) + rect.X + DocumentIconGapLeft, + rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, + DocumentIconWidth, TextFont.Height) : rectIcon; if (DockPane.DockPanel.ShowDocumentIcon) { rectText.X += rectIcon.Width + DocumentIconGapRight; rectText.Y = rect.Y; - rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - DocumentIconGapRight - DocumentTextGapRight - rectCloseButton.Width; + rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - DocumentIconGapRight - + DocumentTextGapRight - rectCloseButton.Width; rectText.Height = rect.Height; } else @@ -1035,6 +1060,7 @@ namespace mRemoteNG.UI.Tabs } private bool m_isMouseDown; + protected bool IsMouseDown { get => m_isMouseDown; @@ -1096,8 +1122,8 @@ namespace mRemoteNG.UI.Tabs var closeButtonRect = GetCloseButtonRect(tabRect); var mouseRect = new Rectangle(mousePos, new Size(1, 1)); buttonUpdate = SetActiveClose(closeButtonRect.IntersectsWith(mouseRect) - ? closeButtonRect - : Rectangle.Empty); + ? closeButtonRect + : Rectangle.Empty); } } } @@ -1144,7 +1170,8 @@ namespace mRemoteNG.UI.Tabs const int gap = 3; var imageSize = PatchController.EnableHighDpi == true ? rectTab.Height - gap * 2 : 15; - return new Rectangle(rectTab.X + rectTab.Width - imageSize - gap - 1, rectTab.Y + gap, imageSize, imageSize); + return new Rectangle(rectTab.X + rectTab.Width - imageSize - gap - 1, rectTab.Y + gap, imageSize, + imageSize); } private void WindowList_Click(object sender, EventArgs e) @@ -1152,16 +1179,23 @@ namespace mRemoteNG.UI.Tabs SelectMenu.Items.Clear(); foreach (var tab1 in Tabs) { - var tab = (MremoteNGTab) tab1; + var tab = (MremoteNGTab)tab1; var content = tab.Content; var item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); item.Tag = tab.Content; item.Click += ContextMenuItem_Click; } - var workingArea = Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, ButtonWindowList.Height / 2))); - var menu = new Rectangle(ButtonWindowList.PointToScreen(new Point(0, ButtonWindowList.Location.Y + ButtonWindowList.Height)), SelectMenu.Size); - var menuMargined = new Rectangle(menu.X - SelectMenuMargin, menu.Y - SelectMenuMargin, menu.Width + SelectMenuMargin, menu.Height + SelectMenuMargin); + var workingArea = + Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, + ButtonWindowList.Height / 2))); + var menu = new Rectangle( + ButtonWindowList.PointToScreen(new Point(0, + ButtonWindowList.Location.Y + + ButtonWindowList.Height)), + SelectMenu.Size); + var menuMargined = new Rectangle(menu.X - SelectMenuMargin, menu.Y - SelectMenuMargin, + menu.Width + SelectMenuMargin, menu.Height + SelectMenuMargin); if (workingArea.Contains(menuMargined)) { SelectMenu.Show(menu.Location); @@ -1169,8 +1203,10 @@ namespace mRemoteNG.UI.Tabs else { var newPoint = menu.Location; - newPoint.X = DrawHelper.Balance(SelectMenu.Width, SelectMenuMargin, newPoint.X, workingArea.Left, workingArea.Right); - newPoint.Y = DrawHelper.Balance(SelectMenu.Size.Height, SelectMenuMargin, newPoint.Y, workingArea.Top, workingArea.Bottom); + newPoint.X = DrawHelper.Balance(SelectMenu.Width, SelectMenuMargin, newPoint.X, workingArea.Left, + workingArea.Right); + newPoint.Y = DrawHelper.Balance(SelectMenu.Size.Height, SelectMenuMargin, newPoint.Y, workingArea.Top, + workingArea.Bottom); var button = ButtonWindowList.PointToScreen(new Point(0, ButtonWindowList.Height)); if (newPoint.Y < button.Y) { @@ -1236,10 +1272,11 @@ namespace mRemoteNG.UI.Tabs buttonWidth = buttonWidth * height / buttonHeight; buttonHeight = height; } + var buttonSize = new Size(buttonWidth, buttonHeight); var x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft - - DocumentButtonGapRight - buttonWidth; + - DocumentButtonGapRight - buttonWidth; var y = rectTabStrip.Y + DocumentButtonGapTop; var point = new Point(x, y); ButtonOverflow.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); @@ -1282,6 +1319,7 @@ namespace mRemoteNG.UI.Tabs // don't activate if mouse is down on active close button result = !ActiveCloseHitTest(e.Location); } + return result; } @@ -1342,6 +1380,7 @@ namespace mRemoteNG.UI.Tabs } #region Native Methods + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { diff --git a/mRemoteV1/UI/Tabs/Enums.cs b/mRemoteV1/UI/Tabs/Enums.cs index 46afbc369..601f30d14 100644 --- a/mRemoteV1/UI/Tabs/Enums.cs +++ b/mRemoteV1/UI/Tabs/Enums.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; namespace mRemoteNG.UI.Tabs { - [Flags] internal enum FlagsSetWindowPos : uint { diff --git a/mRemoteV1/UI/Tabs/FloatWindowNG.cs b/mRemoteV1/UI/Tabs/FloatWindowNG.cs index ce15434a4..770474da4 100644 --- a/mRemoteV1/UI/Tabs/FloatWindowNG.cs +++ b/mRemoteV1/UI/Tabs/FloatWindowNG.cs @@ -10,16 +10,14 @@ namespace mRemoteNG.UI.Tabs { class FloatWindowNG : FloatWindow { - public FloatWindowNG(DockPanel dockPanel, DockPane pane) - : base(dockPanel, pane) - { + : base(dockPanel, pane) + { } public FloatWindowNG(DockPanel dockPanel, DockPane pane, Rectangle bounds) : base(dockPanel, pane, bounds) - { - + { } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs index 265b88915..38088ad37 100644 --- a/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs +++ b/mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs @@ -33,9 +33,11 @@ namespace mRemoteNG.UI.Tabs private const int _TabGapBetween = 10; #region Customizable Properties + public Font TextFont => DockPanel.Theme.Skin.AutoHideStripSkin.TextFont; private static StringFormat _stringFormatTabHorizontal; + private StringFormat StringFormatTabHorizontal { get @@ -61,6 +63,7 @@ namespace mRemoteNG.UI.Tabs } private static StringFormat _stringFormatTabVertical; + private StringFormat StringFormatTabVertical { get @@ -70,9 +73,11 @@ namespace mRemoteNG.UI.Tabs _stringFormatTabVertical = new StringFormat(); _stringFormatTabVertical.Alignment = StringAlignment.Near; _stringFormatTabVertical.LineAlignment = StringAlignment.Center; - _stringFormatTabVertical.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical; + _stringFormatTabVertical.FormatFlags = + StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical; _stringFormatTabVertical.Trimming = StringTrimming.None; } + if (RightToLeft == RightToLeft.Yes) _stringFormatTabVertical.FormatFlags |= StringFormatFlags.DirectionRightToLeft; else @@ -111,6 +116,7 @@ namespace mRemoteNG.UI.Tabs private static Matrix MatrixIdentity { get; } = new Matrix(); private static DockState[] _dockStates; + private static DockState[] DockStates { get @@ -123,11 +129,13 @@ namespace mRemoteNG.UI.Tabs _dockStates[2] = DockState.DockTopAutoHide; _dockStates[3] = DockState.DockBottomAutoHide; } + return _dockStates; } } private static GraphicsPath _graphicsPath; + internal static GraphicsPath GraphicsPath { get @@ -143,9 +151,9 @@ namespace mRemoteNG.UI.Tabs : base(panel) { SetStyle(ControlStyles.ResizeRedraw | - ControlStyles.UserPaint | - ControlStyles.AllPaintingInWmPaint | - ControlStyles.OptimizedDoubleBuffer, true); + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); BackColor = SystemColors.ControlLight; } @@ -191,7 +199,7 @@ namespace mRemoteNG.UI.Tabs { var matrixRotated = new Matrix(); matrixRotated.RotateAt(90, new PointF(rectTabStrip.X + (float)rectTabStrip.Height / 2, - rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + rectTabStrip.Y + (float)rectTabStrip.Height / 2)); g.Transform = matrixRotated; } @@ -200,6 +208,7 @@ namespace mRemoteNG.UI.Tabs foreach (TabNG tab in pane.AutoHideTabs) DrawTab(g, tab); } + g.Transform = matrixIdentity; } @@ -226,8 +235,8 @@ namespace mRemoteNG.UI.Tabs foreach (TabNG tab in pane.AutoHideTabs) { var width = imageWidth + ImageGapLeft + ImageGapRight + - TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + - TextGapLeft + TextGapRight; + TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + + TextGapLeft + TextGapRight; tab.TabX = x; tab.TabWidth = width; x += width; @@ -298,11 +307,11 @@ namespace mRemoteNG.UI.Tabs // The DockState is DockLeftAutoHide or DockRightAutoHide, so rotate the image 90 degrees to the right. var rectTransform = RtlTransform(rectImage, dockState); Point[] rotationPoints = - { - new Point(rectTransform.X + rectTransform.Width, rectTransform.Y), - new Point(rectTransform.X + rectTransform.Width, rectTransform.Y + rectTransform.Height), - new Point(rectTransform.X, rectTransform.Y) - }; + { + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y), + new Point(rectTransform.X + rectTransform.Width, rectTransform.Y + rectTransform.Height), + new Point(rectTransform.X, rectTransform.Y) + }; using (var rotatedIcon = new Icon(((Form)content).Icon, 16, 16)) { @@ -324,9 +333,11 @@ namespace mRemoteNG.UI.Tabs var textColor = DockPanel.Theme.Skin.AutoHideStripSkin.TabGradient.TextColor; if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) - g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical); + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, + StringFormatTabVertical); else - g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabHorizontal); + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, + StringFormatTabHorizontal); // Set rotate back g.Transform = matrixRotate; @@ -406,8 +417,9 @@ namespace mRemoteNG.UI.Tabs var x = tab.TabX; var y = rectTabStrip.Y + - (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ? - 0 : TabGapTop); + (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide + ? 0 + : TabGapTop); var width = tab.TabWidth; var height = rectTabStrip.Height - TabGapTop; @@ -435,8 +447,8 @@ namespace mRemoteNG.UI.Tabs } return new Rectangle((int)(pts[0].X - (float)rect.Height / 2 + .5F), - (int)(pts[0].Y - (float)rect.Width / 2 + .5F), - rect.Height, rect.Width); + (int)(pts[0].Y - (float)rect.Width / 2 + .5F), + rect.Height, rect.Width); } protected override IDockContent HitTest(Point point) @@ -468,11 +480,11 @@ namespace mRemoteNG.UI.Tabs return new Rectangle((int)bounds.Left, (int)bounds.Top, (int)bounds.Width, (int)bounds.Height); } - protected override int MeasureHeight() + protected override int MeasureHeight() { return Math.Max(ImageGapBottom + - ImageGapTop + ImageHeight, - TextFont.Height) + TabGapTop; + ImageGapTop + ImageHeight, + TextFont.Height) + TabGapTop; } protected override void OnRefreshChanges() @@ -484,6 +496,6 @@ namespace mRemoteNG.UI.Tabs protected override Tab CreateTab(IDockContent content) { return new TabNG(content); - } + } } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/TabHelper.cs b/mRemoteV1/UI/Tabs/TabHelper.cs index 912d7fc1a..62e102d86 100644 --- a/mRemoteV1/UI/Tabs/TabHelper.cs +++ b/mRemoteV1/UI/Tabs/TabHelper.cs @@ -6,15 +6,16 @@ namespace mRemoteNG.UI.Tabs { class TabHelper { - private static readonly Lazy lazyHelper= new Lazy(() => new TabHelper()); + private static readonly Lazy lazyHelper = new Lazy(() => new TabHelper()); public static TabHelper Instance => lazyHelper.Value; private TabHelper() { - } + private ConnectionTab currentTab; + public ConnectionTab CurrentTab { get => currentTab; @@ -22,29 +23,34 @@ namespace mRemoteNG.UI.Tabs { currentTab = value; findCurrentPanel(); - Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Tab got focused: " + currentTab.TabText); + Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, + "Tab got focused: " + currentTab.TabText); } } + private void findCurrentPanel() { var currentForm = currentTab.Parent; - while (currentForm != null && ! (currentForm is ConnectionWindow)) + while (currentForm != null && !(currentForm is ConnectionWindow)) { currentForm = currentForm.Parent; } + if (currentForm != null) CurrentPanel = (ConnectionWindow)currentForm; } + private ConnectionWindow currentPanel; + public ConnectionWindow CurrentPanel { get => currentPanel; set { currentPanel = value; - Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Panel got focused: " + currentPanel.TabText); + Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, + "Panel got focused: " + currentPanel.TabText); } } - } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/TaskDialog/CommandButton.cs b/mRemoteV1/UI/TaskDialog/CommandButton.cs index dfc7fe1a7..1cd0cea68 100644 --- a/mRemoteV1/UI/TaskDialog/CommandButton.cs +++ b/mRemoteV1/UI/TaskDialog/CommandButton.cs @@ -10,7 +10,9 @@ namespace mRemoteNG.UI.TaskDialog public sealed partial class CommandButton : Button { //-------------------------------------------------------------------------------- + #region PRIVATE MEMBERS + //-------------------------------------------------------------------------------- private Image imgArrow1; private Image imgArrow2; @@ -19,13 +21,21 @@ namespace mRemoteNG.UI.TaskDialog private const int TOP_MARGIN = 10; private const int ARROW_WIDTH = 19; - enum eButtonState { Normal, MouseOver, Down } + enum eButtonState + { + Normal, + MouseOver, + Down + } + eButtonState m_State = eButtonState.Normal; #endregion //-------------------------------------------------------------------------------- + #region PUBLIC PROPERTIES + //-------------------------------------------------------------------------------- // Override this to make sure the control is invalidated (repainted) when 'Text' is changed public override string Text @@ -45,15 +55,26 @@ namespace mRemoteNG.UI.TaskDialog // AutoHeight determines whether the button automatically resizes itself to fit the Text bool m_autoHeight = true; + [Browsable(true)] [Category("Behavior")] [DefaultValue(true)] - public bool AutoHeight { get { return m_autoHeight; } set { m_autoHeight = value; if (m_autoHeight) Invalidate(); } } + public bool AutoHeight + { + get { return m_autoHeight; } + set + { + m_autoHeight = value; + if (m_autoHeight) Invalidate(); + } + } #endregion //-------------------------------------------------------------------------------- + #region CONSTRUCTOR + //-------------------------------------------------------------------------------- public CommandButton() { @@ -66,16 +87,21 @@ namespace mRemoteNG.UI.TaskDialog #endregion //-------------------------------------------------------------------------------- + #region PUBLIC ROUTINES + //-------------------------------------------------------------------------------- public int GetBestHeight() { return (TOP_MARGIN * 2) + (int)GetSmallTextSizeF().Height + (int)GetLargeTextSizeF().Height; } + #endregion //-------------------------------------------------------------------------------- + #region PRIVATE ROUTINES + //-------------------------------------------------------------------------------- string GetLargeText() { @@ -99,7 +125,7 @@ namespace mRemoteNG.UI.TaskDialog SizeF GetLargeTextSizeF() { var x = LEFT_MARGIN + ARROW_WIDTH + 5; - var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN + var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN var g = Graphics.FromHwnd(Handle); var textSize = g.MeasureString(GetLargeText(), Font, mzSize); return textSize; @@ -110,15 +136,18 @@ namespace mRemoteNG.UI.TaskDialog var s = GetSmallText(); if (s == "") return new SizeF(0, 0); var x = LEFT_MARGIN + ARROW_WIDTH + 8; // <- indent small text slightly more - var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN + var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN var g = Graphics.FromHwnd(Handle); var textSize = g.MeasureString(s, SmallFont, mzSize); return textSize; } + #endregion //-------------------------------------------------------------------------------- + #region OVERRIDES + //-------------------------------------------------------------------------------- protected override void OnCreateControl() { @@ -135,12 +164,14 @@ namespace mRemoteNG.UI.TaskDialog base.OnPaint(e); return; } + e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; const LinearGradientMode mode = LinearGradientMode.Vertical; - var newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1); + var newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, + ClientRectangle.Height - 1); var img = imgArrow1; @@ -150,7 +181,6 @@ namespace mRemoteNG.UI.TaskDialog Color border; if (Enabled) { - switch (m_State) { case eButtonState.MouseOver: @@ -194,12 +224,18 @@ namespace mRemoteNG.UI.TaskDialog var szL = GetLargeTextSizeF(); //e.Graphics.DrawString(largetext, base.Font, new SolidBrush(text_color), new RectangleF(new PointF(LEFT_MARGIN + imgArrow1.Width + 5, TOP_MARGIN), szL)); - TextRenderer.DrawText(e.Graphics, largetext, Font, new Rectangle(LEFT_MARGIN + imgArrow1.Width + 5, TOP_MARGIN, (int)szL.Width, (int)szL.Height), fore, TextFormatFlags.Default); + TextRenderer.DrawText(e.Graphics, largetext, Font, + new Rectangle(LEFT_MARGIN + imgArrow1.Width + 5, TOP_MARGIN, (int)szL.Width, + (int)szL.Height), fore, + TextFormatFlags.Default); if (smalltext != "") { var szS = GetSmallTextSizeF(); - e.Graphics.DrawString(smalltext, SmallFont, new SolidBrush(fore), new RectangleF(new PointF(LEFT_MARGIN + imgArrow1.Width + 8, TOP_MARGIN + (int)szL.Height), szS)); + e.Graphics.DrawString(smalltext, SmallFont, new SolidBrush(fore), + new + RectangleF(new PointF(LEFT_MARGIN + imgArrow1.Width + 8, TOP_MARGIN + (int)szL.Height), + szS)); } e.Graphics.DrawImage(img, new Point(LEFT_MARGIN, TOP_MARGIN + (int)(szL.Height / 2) - img.Height / 2)); @@ -249,10 +285,12 @@ namespace mRemoteNG.UI.TaskDialog return; } } + base.OnSizeChanged(e); } + #endregion //-------------------------------------------------------------------------------- } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/TaskDialog/cTaskDialog.cs b/mRemoteV1/UI/TaskDialog/cTaskDialog.cs index ef3f70d76..241430889 100644 --- a/mRemoteV1/UI/TaskDialog/cTaskDialog.cs +++ b/mRemoteV1/UI/TaskDialog/cTaskDialog.cs @@ -51,18 +51,18 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- public static DialogResult ShowTaskDialogBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - string commandButtons, - ETaskDialogButtons buttons, - ESysIcons mainIcon, - ESysIcons footerIcon, - int defaultIndex) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + string commandButtons, + ETaskDialogButtons buttons, + ESysIcons mainIcon, + ESysIcons footerIcon, + int defaultIndex) { DialogResult result; @@ -100,36 +100,36 @@ namespace mRemoteNG.UI.TaskDialog // Overloaded versions... //-------------------------------------------------------------------------------- public static DialogResult ShowTaskDialogBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - string commandButtons, - ETaskDialogButtons buttons, - ESysIcons mainIcon, - ESysIcons footerIcon) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + string commandButtons, + ETaskDialogButtons buttons, + ESysIcons mainIcon, + ESysIcons footerIcon) { return ShowTaskDialogBox(owner, title, mainInstruction, content, expandedInfo, footer, verificationText, - radioButtons, commandButtons, buttons, mainIcon, footerIcon, 0); + radioButtons, commandButtons, buttons, mainIcon, footerIcon, 0); } public static DialogResult ShowTaskDialogBox(string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - string commandButtons, - ETaskDialogButtons buttons, - ESysIcons mainIcon, - ESysIcons footerIcon) + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + string commandButtons, + ETaskDialogButtons buttons, + ESysIcons mainIcon, + ESysIcons footerIcon) { return ShowTaskDialogBox(null, title, mainInstruction, content, expandedInfo, footer, verificationText, - radioButtons, commandButtons, buttons, mainIcon, footerIcon, 0); + radioButtons, commandButtons, buttons, mainIcon, footerIcon, 0); } #endregion @@ -140,56 +140,56 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- public static DialogResult MessageBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - ETaskDialogButtons buttons, - ESysIcons mainIcon, - ESysIcons footerIcon) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + ETaskDialogButtons buttons, + ESysIcons mainIcon, + ESysIcons footerIcon) { return ShowTaskDialogBox(owner, title, mainInstruction, content, expandedInfo, footer, verificationText, "", - "", buttons, mainIcon, footerIcon); + "", buttons, mainIcon, footerIcon); } //-------------------------------------------------------------------------------- // Overloaded versions... //-------------------------------------------------------------------------------- public static DialogResult MessageBox(string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - ETaskDialogButtons buttons, - ESysIcons mainIcon, - ESysIcons footerIcon) + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + ETaskDialogButtons buttons, + ESysIcons mainIcon, + ESysIcons footerIcon) { return ShowTaskDialogBox(null, title, mainInstruction, content, expandedInfo, footer, verificationText, "", - "", buttons, mainIcon, footerIcon); + "", buttons, mainIcon, footerIcon); } public static DialogResult MessageBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - ETaskDialogButtons buttons, - ESysIcons mainIcon) + string title, + string mainInstruction, + string content, + ETaskDialogButtons buttons, + ESysIcons mainIcon) { return MessageBox(owner, title, mainInstruction, content, "", "", "", buttons, mainIcon, - ESysIcons.Information); + ESysIcons.Information); } public static DialogResult MessageBox(string title, - string mainInstruction, - string content, - ETaskDialogButtons buttons, - ESysIcons mainIcon) + string mainInstruction, + string content, + ETaskDialogButtons buttons, + ESysIcons mainIcon) { return MessageBox(null, title, mainInstruction, content, "", "", "", buttons, mainIcon, - ESysIcons.Information); + ESysIcons.Information); } //-------------------------------------------------------------------------------- @@ -202,19 +202,20 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- public static int ShowRadioBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - ESysIcons mainIcon, - ESysIcons footerIcon, - int defaultIndex) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + ESysIcons mainIcon, + ESysIcons footerIcon, + int defaultIndex) { var res = ShowTaskDialogBox(owner, title, mainInstruction, content, expandedInfo, footer, verificationText, - radioButtons, "", ETaskDialogButtons.OkCancel, mainIcon, footerIcon, defaultIndex); + radioButtons, "", ETaskDialogButtons.OkCancel, mainIcon, footerIcon, + defaultIndex); if (res == DialogResult.OK) return RadioButtonResult; return -1; @@ -224,66 +225,67 @@ namespace mRemoteNG.UI.TaskDialog // Overloaded versions... //-------------------------------------------------------------------------------- public static int ShowRadioBox(string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - ESysIcons mainIcon, - ESysIcons footerIcon, - int defaultIndex) + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + ESysIcons mainIcon, + ESysIcons footerIcon, + int defaultIndex) { var res = ShowTaskDialogBox(null, title, mainInstruction, content, expandedInfo, footer, verificationText, - radioButtons, "", ETaskDialogButtons.OkCancel, mainIcon, footerIcon, defaultIndex); + radioButtons, "", ETaskDialogButtons.OkCancel, mainIcon, footerIcon, + defaultIndex); if (res == DialogResult.OK) return RadioButtonResult; return -1; } public static int ShowRadioBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string radioButtons, - ESysIcons mainIcon, - ESysIcons footerIcon) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string radioButtons, + ESysIcons mainIcon, + ESysIcons footerIcon) { return ShowRadioBox(owner, title, mainInstruction, content, expandedInfo, footer, verificationText, - radioButtons, ESysIcons.Question, ESysIcons.Information, 0); + radioButtons, ESysIcons.Question, ESysIcons.Information, 0); } public static int ShowRadioBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string radioButtons, - int defaultIndex) + string title, + string mainInstruction, + string content, + string radioButtons, + int defaultIndex) { return ShowRadioBox(owner, title, mainInstruction, content, "", "", "", radioButtons, ESysIcons.Question, - ESysIcons.Information, defaultIndex); + ESysIcons.Information, defaultIndex); } public static int ShowRadioBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string radioButtons) + string title, + string mainInstruction, + string content, + string radioButtons) { return ShowRadioBox(owner, title, mainInstruction, content, "", "", "", radioButtons, ESysIcons.Question, - ESysIcons.Information, 0); + ESysIcons.Information, 0); } public static int ShowRadioBox(string title, - string mainInstruction, - string content, - string radioButtons) + string mainInstruction, + string content, + string radioButtons) { return ShowRadioBox(null, title, mainInstruction, content, "", "", "", radioButtons, ESysIcons.Question, - ESysIcons.Information, 0); + ESysIcons.Information, 0); } #endregion @@ -294,20 +296,21 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- public static int ShowCommandBox(IWin32Window owner, - string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string commandButtons, - bool showCancelButton, - ESysIcons mainIcon, - ESysIcons footerIcon) + string title, + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string commandButtons, + bool showCancelButton, + ESysIcons mainIcon, + ESysIcons footerIcon) { var res = ShowTaskDialogBox(owner, title, mainInstruction, content, expandedInfo, footer, verificationText, - "", commandButtons, showCancelButton ? ETaskDialogButtons.Cancel : ETaskDialogButtons.None, - mainIcon, footerIcon); + "", commandButtons, + showCancelButton ? ETaskDialogButtons.Cancel : ETaskDialogButtons.None, + mainIcon, footerIcon); if (res == DialogResult.OK) return CommandButtonResult; return -1; @@ -317,36 +320,44 @@ namespace mRemoteNG.UI.TaskDialog // Overloaded versions... //-------------------------------------------------------------------------------- public static int ShowCommandBox(string title, - string mainInstruction, - string content, - string expandedInfo, - string footer, - string verificationText, - string commandButtons, - bool showCancelButton, - ESysIcons mainIcon, - ESysIcons footerIcon) + string mainInstruction, + string content, + string expandedInfo, + string footer, + string verificationText, + string commandButtons, + bool showCancelButton, + ESysIcons mainIcon, + ESysIcons footerIcon) { var res = ShowTaskDialogBox(null, title, mainInstruction, content, expandedInfo, footer, verificationText, - "", commandButtons, showCancelButton ? ETaskDialogButtons.Cancel : ETaskDialogButtons.None, - mainIcon, footerIcon); + "", commandButtons, + showCancelButton ? ETaskDialogButtons.Cancel : ETaskDialogButtons.None, + mainIcon, footerIcon); if (res == DialogResult.OK) return CommandButtonResult; return -1; } - public static int ShowCommandBox(IWin32Window owner, string title, string mainInstruction, string content, - string commandButtons, bool showCancelButton) + public static int ShowCommandBox(IWin32Window owner, + string title, + string mainInstruction, + string content, + string commandButtons, + bool showCancelButton) { return ShowCommandBox(owner, title, mainInstruction, content, "", "", "", commandButtons, showCancelButton, - ESysIcons.Question, ESysIcons.Information); + ESysIcons.Question, ESysIcons.Information); } - public static int ShowCommandBox(string title, string mainInstruction, string content, string commandButtons, - bool showCancelButton) + public static int ShowCommandBox(string title, + string mainInstruction, + string content, + string commandButtons, + bool showCancelButton) { return ShowCommandBox(null, title, mainInstruction, content, "", "", "", commandButtons, showCancelButton, - ESysIcons.Question, ESysIcons.Information); + ESysIcons.Question, ESysIcons.Information); } #endregion diff --git a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs index 222ffa30f..6e91dd767 100644 --- a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs +++ b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs @@ -10,11 +10,15 @@ namespace mRemoteNG.UI.TaskDialog public partial class frmTaskDialog : Form { //-------------------------------------------------------------------------------- + #region PRIVATE members + //-------------------------------------------------------------------------------- private string _mainInstruction = "Main Instruction Text"; - private readonly Font _mainInstructionFont = new Font("Segoe UI", 11.75F, FontStyle.Regular, GraphicsUnit.Point, 0); + + private readonly Font _mainInstructionFont = + new Font("Segoe UI", 11.75F, FontStyle.Regular, GraphicsUnit.Point, 0); private readonly List _radioButtonCtrls = new List(); private readonly DisplayProperties _display = new DisplayProperties(); @@ -24,28 +28,51 @@ namespace mRemoteNG.UI.TaskDialog private int _mainInstructionLeftMargin; private int _mainInstructionRightMargin; + #endregion //-------------------------------------------------------------------------------- + #region PROPERTIES + //-------------------------------------------------------------------------------- public ESysIcons MainIcon { get; set; } = ESysIcons.Question; public ESysIcons FooterIcon { get; set; } = ESysIcons.Warning; - public string Title { get => Text; + public string Title + { + get => Text; set => Text = value; } - public string MainInstruction { get => _mainInstruction; - set { _mainInstruction = value; Invalidate(); } } - public string Content { get => lbContent.Text; + + public string MainInstruction + { + get => _mainInstruction; + set + { + _mainInstruction = value; + Invalidate(); + } + } + + public string Content + { + get => lbContent.Text; set => lbContent.Text = value; } - public string ExpandedInfo { get => lbExpandedInfo.Text; + + public string ExpandedInfo + { + get => lbExpandedInfo.Text; set => lbExpandedInfo.Text = value; } - public string Footer { get => lbFooter.Text; + + public string Footer + { + get => lbFooter.Text; set => lbFooter.Text = value; } + public int DefaultButtonIndex { get; set; } public string RadioButtons { get; set; } = ""; @@ -66,10 +93,15 @@ namespace mRemoteNG.UI.TaskDialog public ETaskDialogButtons Buttons { get; set; } = ETaskDialogButtons.YesNoCancel; - public string VerificationText { get => cbVerify.Text; + public string VerificationText + { + get => cbVerify.Text; set => cbVerify.Text = value; } - public bool VerificationCheckBoxChecked { get => cbVerify.Checked; + + public bool VerificationCheckBoxChecked + { + get => cbVerify.Checked; set => cbVerify.Checked = value; } @@ -78,7 +110,9 @@ namespace mRemoteNG.UI.TaskDialog #endregion //-------------------------------------------------------------------------------- + #region CONSTRUCTOR + //-------------------------------------------------------------------------------- public frmTaskDialog() { @@ -94,13 +128,17 @@ namespace mRemoteNG.UI.TaskDialog Footer = ""; VerificationText = ""; } + #endregion //-------------------------------------------------------------------------------- + #region BuildForm + // This is the main routine that should be called before .ShowDialog() //-------------------------------------------------------------------------------- private bool _formBuilt; + public void BuildForm() { var formHeight = 0; @@ -185,6 +223,7 @@ namespace mRemoteNG.UI.TaskDialog pnlHeight += rb.Height; _radioButtonCtrls.Add(rb); } + pnlRadioButtons.Height = pnlHeight; formHeight += pnlRadioButtons.Height; } @@ -202,7 +241,7 @@ namespace mRemoteNG.UI.TaskDialog { Parent = pnlCommandButtons, Location = new Point(_display.ScaleWidth(50), t) }; - if (_isVista) // <- tweak font if vista + if (_isVista) // <- tweak font if vista btn.Font = new Font(btn.Font, FontStyle.Regular); btn.Text = arr[i]; btn.Size = new Size(Width - btn.Left - _display.ScaleWidth(15), btn.GetBestHeight()); @@ -213,6 +252,7 @@ namespace mRemoteNG.UI.TaskDialog if (i == DefaultButtonIndex) _focusControl = btn; } + pnlCommandButtons.Height = pnlHeight; formHeight += pnlCommandButtons.Height; } @@ -311,6 +351,7 @@ namespace mRemoteNG.UI.TaskDialog default: throw new ArgumentOutOfRangeException(); } + formHeight += pnlFooter.Height; } @@ -335,16 +376,24 @@ namespace mRemoteNG.UI.TaskDialog panel5.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); panel3.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); panel3.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlCommandButtons.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCommandButtons.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlMainInstruction.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlMainInstruction.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCommandButtons.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCommandButtons.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlMainInstruction.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlMainInstruction.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); pnlContent.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); pnlContent.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlExpandedInfo.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlExpandedInfo.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlRadioButtons.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlRadioButtons.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlExpandedInfo.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlExpandedInfo.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlRadioButtons.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlRadioButtons.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } //-------------------------------------------------------------------------------- @@ -364,6 +413,7 @@ namespace mRemoteNG.UI.TaskDialog g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.DrawImage(srcImg, 0, 0, w, h); } + return b; } @@ -381,10 +431,13 @@ namespace mRemoteNG.UI.TaskDialog lb.Height = (int)stringSize.Height + 4; } } + #endregion //-------------------------------------------------------------------------------- + #region EVENTS + //-------------------------------------------------------------------------------- private void CommandButton_Click(object sender, EventArgs e) { @@ -444,14 +497,23 @@ namespace mRemoteNG.UI.TaskDialog { switch (MainIcon) { - case ESysIcons.Error: System.Media.SystemSounds.Hand.Play(); break; - case ESysIcons.Information: System.Media.SystemSounds.Asterisk.Play(); break; - case ESysIcons.Question: System.Media.SystemSounds.Asterisk.Play(); break; - case ESysIcons.Warning: System.Media.SystemSounds.Exclamation.Play(); break; + case ESysIcons.Error: + System.Media.SystemSounds.Hand.Play(); + break; + case ESysIcons.Information: + System.Media.SystemSounds.Asterisk.Play(); + break; + case ESysIcons.Question: + System.Media.SystemSounds.Asterisk.Play(); + break; + case ESysIcons.Warning: + System.Media.SystemSounds.Exclamation.Play(); + break; default: throw new ArgumentOutOfRangeException(); } } + _focusControl?.Focus(); } @@ -459,4 +521,4 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- } -} +} \ No newline at end of file diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index d2c49b5d2..e00289e11 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -9,25 +9,26 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Window { - public class AboutWindow : BaseWindow - { + public class AboutWindow : BaseWindow + { #region Form Init - internal Controls.Base.NGLabel lblCopyright; - internal Controls.Base.NGLabel lblTitle; - internal Controls.Base.NGLabel lblVersion; - internal Controls.Base.NGLabel lblLicense; - internal Controls.Base.NGTextBox txtChangeLog; - internal Controls.Base.NGLabel lblChangeLog; - internal Panel pnlBottom; - internal PictureBox pbLogo; + internal Controls.Base.NGLabel lblCopyright; + internal Controls.Base.NGLabel lblTitle; + internal Controls.Base.NGLabel lblVersion; + internal Controls.Base.NGLabel lblLicense; + internal Controls.Base.NGTextBox txtChangeLog; + internal Controls.Base.NGLabel lblChangeLog; + internal Panel pnlBottom; + internal PictureBox pbLogo; internal Controls.Base.NGLabel lblCredits; internal Controls.Base.NGTextBox txtCredits; internal Panel pnlTop; private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutWindow)); + { + System.ComponentModel.ComponentResourceManager resources = + new System.ComponentModel.ComponentResourceManager(typeof(AboutWindow)); this.pnlTop = new System.Windows.Forms.Panel(); this.pbLogo = new System.Windows.Forms.PictureBox(); this.pnlBottom = new System.Windows.Forms.Panel(); @@ -46,7 +47,8 @@ namespace mRemoteNG.UI.Window // // pnlTop // - this.pnlTop.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(52)))), ((int)(((byte)(58)))), ((int)(((byte)(64))))); + this.pnlTop.BackColor = + System.Drawing.Color.FromArgb(((int)(((byte)(52)))), ((int)(((byte)(58)))), ((int)(((byte)(64))))); this.pnlTop.Controls.Add(this.pbLogo); this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top; this.pnlTop.ForeColor = System.Drawing.Color.White; @@ -97,12 +99,15 @@ namespace mRemoteNG.UI.Window // // txtCredits // - this.txtCredits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.txtCredits.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.txtCredits.BackColor = System.Drawing.SystemColors.Control; this.txtCredits.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCredits.Cursor = System.Windows.Forms.Cursors.Default; - this.txtCredits.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtCredits.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtCredits.ForeColor = System.Drawing.SystemColors.ControlText; this.txtCredits.Location = new System.Drawing.Point(8, 156); this.txtCredits.MinimumSize = new System.Drawing.Size(370, 260); @@ -116,13 +121,16 @@ namespace mRemoteNG.UI.Window // // txtChangeLog // - this.txtChangeLog.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.txtChangeLog.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.txtChangeLog.BackColor = System.Drawing.SystemColors.Control; this.txtChangeLog.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtChangeLog.Cursor = System.Windows.Forms.Cursors.Default; - this.txtChangeLog.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtChangeLog.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtChangeLog.ForeColor = System.Drawing.SystemColors.ControlText; this.txtChangeLog.Location = new System.Drawing.Point(414, 156); this.txtChangeLog.MinimumSize = new System.Drawing.Size(370, 260); @@ -137,7 +145,8 @@ namespace mRemoteNG.UI.Window // lblTitle // this.lblTitle.AutoSize = true; - this.lblTitle.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblTitle.ForeColor = System.Drawing.SystemColors.ControlText; this.lblTitle.Location = new System.Drawing.Point(3, 3); this.lblTitle.Name = "lblTitle"; @@ -202,7 +211,8 @@ namespace mRemoteNG.UI.Window this.ClientSize = new System.Drawing.Size(1117, 705); this.Controls.Add(this.pnlBottom); this.Controls.Add(this.pnlTop); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ForeColor = System.Drawing.SystemColors.ControlText; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximumSize = new System.Drawing.Size(20000, 10000); @@ -216,30 +226,33 @@ namespace mRemoteNG.UI.Window this.pnlBottom.ResumeLayout(false); this.pnlBottom.PerformLayout(); this.ResumeLayout(false); + } - } #endregion #region Public Methods - public AboutWindow() - { - WindowType = WindowType.About; - DockPnl = new DockContent(); - InitializeComponent(); + + public AboutWindow() + { + WindowType = WindowType.About; + DockPnl = new DockContent(); + InitializeComponent(); FontOverrider.FontOverride(this); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); } + #endregion #region Private Methods - private void ApplyLanguage() - { - lblLicense.Text = Language.strLabelReleasedUnderGPL; - lblChangeLog.Text = Language.strLabelChangeLog; - TabText = Language.strAbout; - Text = Language.strAbout; - } + + private void ApplyLanguage() + { + lblLicense.Text = Language.strLabelReleasedUnderGPL; + lblChangeLog.Text = Language.strLabelChangeLog; + TabText = Language.strAbout; + Text = Language.strAbout; + } private new void ApplyTheme() { @@ -255,13 +268,13 @@ namespace mRemoteNG.UI.Window } private void ApplyEditions() - { - #if PORTABLE - lblTitle.Text += " " + Language.strLabelPortableEdition; - #endif - } + { +#if PORTABLE + lblTitle.Text += " " + Language.strLabelPortableEdition; +#endif + } - #if false +#if false private void FillLinkLabel(LinkLabel llbl, string txt, string URL) { llbl.Links.Clear(); @@ -282,21 +295,22 @@ namespace mRemoteNG.UI.Window llbl.Text = txt; } - #endif +#endif + #endregion -#region Form Stuff + #region Form Stuff - private void About_Load(object sender, EventArgs e) - { + private void About_Load(object sender, EventArgs e) + { ApplyTheme(); - ApplyEditions(); + ApplyEditions(); - try - { - lblCopyright.Text = GeneralAppInfo.Copyright; + try + { + lblCopyright.Text = GeneralAppInfo.Copyright; - lblVersion.Text = $@"Version {GeneralAppInfo.ApplicationVersion}"; + lblVersion.Text = $@"Version {GeneralAppInfo.ApplicationVersion}"; // AppVeyor seems to pull text files in UNIX format... This messes up the display on the about screen... // @@ -310,8 +324,9 @@ namespace mRemoteNG.UI.Window // The Changelog is a bit long anyways... Limit the number of lines to something reasonable. if (File.Exists(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) - { - using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT", Encoding.Default, true)) + { + using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT", Encoding.Default, + true)) { string line; var i = 0; @@ -329,8 +344,8 @@ namespace mRemoteNG.UI.Window } } - if (File.Exists(GeneralAppInfo.HomePath + "\\CREDITS.TXT")) - { + if (File.Exists(GeneralAppInfo.HomePath + "\\CREDITS.TXT")) + { using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CREDITS.TXT", Encoding.Default, true)) { string line; @@ -338,13 +353,13 @@ namespace mRemoteNG.UI.Window txtCredits.Text += line + Environment.NewLine; } } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - "Loading About failed" + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "Loading About failed" + Environment.NewLine + ex.Message, true); + } + } #if false private void llblFAMFAMFAM_LinkClicked(Object sender, LinkLabelLinkClickedEventArgs e) @@ -362,6 +377,7 @@ namespace mRemoteNG.UI.Window Runtime.GoToURL(Language.strWeifenLuoAttributionURL); } #endif -#endregion - } -} + + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index ea30adcc9..07e0d9fea 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -35,7 +35,6 @@ namespace mRemoteNG.UI.Window #region Private Methods - #region Event Handlers private void ADImport_Load(object sender, EventArgs e) diff --git a/mRemoteV1/UI/Window/BaseWindow.cs b/mRemoteV1/UI/Window/BaseWindow.cs index 8bbaf300f..993c2c0c5 100644 --- a/mRemoteV1/UI/Window/BaseWindow.cs +++ b/mRemoteV1/UI/Window/BaseWindow.cs @@ -1,16 +1,19 @@ using mRemoteNG.Themes; using WeifenLuo.WinFormsUI.Docking; + // ReSharper disable UnusedAutoPropertyAccessor.Global namespace mRemoteNG.UI.Window { - public class BaseWindow : DockContent + public class BaseWindow : DockContent { #region Private Variables + //private WindowType _WindowType; //private DockContent _DockPnl; private ThemeManager _themeManager; + #endregion #region Public Properties @@ -20,17 +23,19 @@ namespace mRemoteNG.UI.Window protected DockContent DockPnl { get; set; } #endregion - + #region Public Methods - public void SetFormText(string t) - { - Text = t; - TabText = t; - } + + public void SetFormText(string t) + { + Text = t; + TabText = t; + } + #endregion internal void ApplyTheme() - { + { _themeManager = ThemeManager.getInstance(); if (!_themeManager.ActiveAndExtended) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); @@ -39,6 +44,7 @@ namespace mRemoteNG.UI.Window #region Private Methods + /* private void Base_Load(object sender, EventArgs e) { @@ -52,6 +58,7 @@ namespace mRemoteNG.UI.Window FrmMain.Default.ShowHidePanelTabs(this); } */ + #endregion private void InitializeComponent() @@ -61,10 +68,10 @@ namespace mRemoteNG.UI.Window // BaseWindow // this.ClientSize = new System.Drawing.Size(284, 261); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "BaseWindow"; this.ResumeLayout(false); - } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs index ad8f45edb..9b978864e 100644 --- a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs +++ b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs @@ -15,12 +15,13 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { - public class ComponentsCheckWindow : BaseWindow - { - private readonly Image _successImage; - private readonly Image _failureImage; + public class ComponentsCheckWindow : BaseWindow + { + private readonly Image _successImage; + private readonly Image _failureImage; #region Form Stuff + private System.Windows.Forms.PictureBox pbCheck1; private Controls.Base.NGLabel lblCheck1; private System.Windows.Forms.Panel pnlCheck2; @@ -85,8 +86,10 @@ namespace mRemoteNG.UI.Window // // pnlCheck1 // - this.pnlCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.pnlCheck1.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck1.Controls.Add(this.txtCheck1); this.pnlCheck1.Controls.Add(this.lblCheck1); this.pnlCheck1.Controls.Add(this.pbCheck1); @@ -98,9 +101,11 @@ namespace mRemoteNG.UI.Window // // txtCheck1 // - this.txtCheck1.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.txtCheck1.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.txtCheck1.BackColor = System.Drawing.SystemColors.Control; this.txtCheck1.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCheck1.Location = new System.Drawing.Point(129, 29); @@ -112,9 +117,12 @@ namespace mRemoteNG.UI.Window // // lblCheck1 // - this.lblCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.lblCheck1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCheck1.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblCheck1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck1.ForeColor = System.Drawing.SystemColors.ControlText; this.lblCheck1.Location = new System.Drawing.Point(108, 3); this.lblCheck1.Name = "lblCheck1"; @@ -124,8 +132,10 @@ namespace mRemoteNG.UI.Window // // pbCheck1 // - this.pbCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.pbCheck1.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck1.Location = new System.Drawing.Point(3, 3); this.pbCheck1.Name = "pbCheck1"; this.pbCheck1.Size = new System.Drawing.Size(72, 123); @@ -134,8 +144,10 @@ namespace mRemoteNG.UI.Window // // pnlCheck2 // - this.pnlCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.pnlCheck2.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck2.Controls.Add(this.txtCheck2); this.pnlCheck2.Controls.Add(this.lblCheck2); this.pnlCheck2.Controls.Add(this.pbCheck2); @@ -147,9 +159,11 @@ namespace mRemoteNG.UI.Window // // txtCheck2 // - this.txtCheck2.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.txtCheck2.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.txtCheck2.BackColor = System.Drawing.SystemColors.Control; this.txtCheck2.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCheck2.Location = new System.Drawing.Point(129, 29); @@ -161,9 +175,12 @@ namespace mRemoteNG.UI.Window // // lblCheck2 // - this.lblCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.lblCheck2.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCheck2.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblCheck2.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck2.Location = new System.Drawing.Point(112, 3); this.lblCheck2.Name = "lblCheck2"; this.lblCheck2.Size = new System.Drawing.Size(447, 23); @@ -172,8 +189,10 @@ namespace mRemoteNG.UI.Window // // pbCheck2 // - this.pbCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.pbCheck2.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck2.Location = new System.Drawing.Point(3, 3); this.pbCheck2.Name = "pbCheck2"; this.pbCheck2.Size = new System.Drawing.Size(72, 123); @@ -182,8 +201,10 @@ namespace mRemoteNG.UI.Window // // pnlCheck3 // - this.pnlCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.pnlCheck3.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck3.Controls.Add(this.txtCheck3); this.pnlCheck3.Controls.Add(this.lblCheck3); this.pnlCheck3.Controls.Add(this.pbCheck3); @@ -195,9 +216,11 @@ namespace mRemoteNG.UI.Window // // txtCheck3 // - this.txtCheck3.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.txtCheck3.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.txtCheck3.BackColor = System.Drawing.SystemColors.Control; this.txtCheck3.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCheck3.Location = new System.Drawing.Point(129, 29); @@ -209,9 +232,12 @@ namespace mRemoteNG.UI.Window // // lblCheck3 // - this.lblCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.lblCheck3.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCheck3.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblCheck3.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck3.Location = new System.Drawing.Point(112, 3); this.lblCheck3.Name = "lblCheck3"; this.lblCheck3.Size = new System.Drawing.Size(447, 23); @@ -220,8 +246,10 @@ namespace mRemoteNG.UI.Window // // pbCheck3 // - this.pbCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.pbCheck3.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck3.Location = new System.Drawing.Point(3, 3); this.pbCheck3.Name = "pbCheck3"; this.pbCheck3.Size = new System.Drawing.Size(72, 123); @@ -230,8 +258,10 @@ namespace mRemoteNG.UI.Window // // pnlCheck4 // - this.pnlCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.pnlCheck4.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck4.Controls.Add(this.txtCheck4); this.pnlCheck4.Controls.Add(this.lblCheck4); this.pnlCheck4.Controls.Add(this.pbCheck4); @@ -243,9 +273,11 @@ namespace mRemoteNG.UI.Window // // txtCheck4 // - this.txtCheck4.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.txtCheck4.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.txtCheck4.BackColor = System.Drawing.SystemColors.Control; this.txtCheck4.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCheck4.Location = new System.Drawing.Point(129, 30); @@ -257,9 +289,12 @@ namespace mRemoteNG.UI.Window // // lblCheck4 // - this.lblCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.lblCheck4.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCheck4.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblCheck4.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck4.Location = new System.Drawing.Point(112, 3); this.lblCheck4.Name = "lblCheck4"; this.lblCheck4.Size = new System.Drawing.Size(447, 23); @@ -268,8 +303,10 @@ namespace mRemoteNG.UI.Window // // pbCheck4 // - this.pbCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.pbCheck4.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck4.Location = new System.Drawing.Point(3, 3); this.pbCheck4.Name = "pbCheck4"; this.pbCheck4.Size = new System.Drawing.Size(72, 123); @@ -278,8 +315,10 @@ namespace mRemoteNG.UI.Window // // pnlCheck5 // - this.pnlCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.pnlCheck5.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck5.Controls.Add(this.txtCheck5); this.pnlCheck5.Controls.Add(this.lblCheck5); this.pnlCheck5.Controls.Add(this.pbCheck5); @@ -291,9 +330,11 @@ namespace mRemoteNG.UI.Window // // txtCheck5 // - this.txtCheck5.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.txtCheck5.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.txtCheck5.BackColor = System.Drawing.SystemColors.Control; this.txtCheck5.BorderStyle = System.Windows.Forms.BorderStyle.None; this.txtCheck5.Location = new System.Drawing.Point(129, 29); @@ -305,9 +346,12 @@ namespace mRemoteNG.UI.Window // // lblCheck5 // - this.lblCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.lblCheck5.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCheck5.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblCheck5.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck5.Location = new System.Drawing.Point(112, 3); this.lblCheck5.Name = "lblCheck5"; this.lblCheck5.Size = new System.Drawing.Size(447, 23); @@ -316,8 +360,10 @@ namespace mRemoteNG.UI.Window // // pbCheck5 // - this.pbCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); + this.pbCheck5.Anchor = + ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck5.Location = new System.Drawing.Point(3, 3); this.pbCheck5.Name = "pbCheck5"; this.pbCheck5.Size = new System.Drawing.Size(72, 123); @@ -327,7 +373,9 @@ namespace mRemoteNG.UI.Window // btnCheckAgain // this.btnCheckAgain._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; - this.btnCheckAgain.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCheckAgain.Anchor = + ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Right))); this.btnCheckAgain.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnCheckAgain.Location = new System.Drawing.Point(476, 810); this.btnCheckAgain.Name = "btnCheckAgain"; @@ -340,7 +388,9 @@ namespace mRemoteNG.UI.Window // chkAlwaysShow // this.chkAlwaysShow._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; - this.chkAlwaysShow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkAlwaysShow.Anchor = + ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left))); this.chkAlwaysShow.AutoSize = true; this.chkAlwaysShow.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.chkAlwaysShow.Location = new System.Drawing.Point(12, 814); @@ -353,9 +403,11 @@ namespace mRemoteNG.UI.Window // // pnlChecks // - this.pnlChecks.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.pnlChecks.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.pnlChecks.AutoScroll = true; this.pnlChecks.Controls.Add(this.pnlCheck1); this.pnlChecks.Controls.Add(this.pnlCheck2); @@ -375,7 +427,8 @@ namespace mRemoteNG.UI.Window this.Controls.Add(this.pnlChecks); this.Controls.Add(this.chkAlwaysShow); this.Controls.Add(this.btnCheckAgain); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = global::mRemoteNG.Resources.ComponentsCheck_Icon; this.Name = "ComponentsCheckWindow"; this.TabText = "Components Check"; @@ -399,11 +452,12 @@ namespace mRemoteNG.UI.Window this.pnlChecks.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); - } + #endregion #region Public Methods + public ComponentsCheckWindow() { WindowType = WindowType.ComponentsCheck; @@ -415,9 +469,11 @@ namespace mRemoteNG.UI.Window FontOverrider.FontOverride(this); ThemeManager.getInstance().ThemeChanged += ApplyTheme; } + #endregion #region Form Stuff + private void ComponentsCheck_Load(object sender, EventArgs e) { ApplyLanguage(); @@ -468,7 +524,8 @@ namespace mRemoteNG.UI.Window { try { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to show the components window", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to show the components window", + true); base.Show(panel); } catch (Exception ex) @@ -476,6 +533,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddExceptionMessage("Failed to properly show the ComponentsWindow", ex); } } + #endregion private void CheckComponents() @@ -508,7 +566,7 @@ namespace mRemoteNG.UI.Window if (!(new Version(rdpClient.Version) >= RdpProtocol.Versions.RDC80)) { throw new Exception( - $"Found RDC Client version {rdpClient.Version} but version {RdpProtocol.Versions.RDC80} or higher is required."); + $"Found RDC Client version {rdpClient.Version} but version {RdpProtocol.Versions.RDC80} or higher is required."); } pbCheck1.Image = _successImage; @@ -526,7 +584,7 @@ namespace mRemoteNG.UI.Window txtCheck1.Text = string.Format(Language.strCcRDPFailed, GeneralAppInfo.UrlForum); Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, - "RDP " + Language.strCcNotInstalledProperly, true); + "RDP " + Language.strCcNotInstalledProperly, true); Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, ex.Message, true); } } @@ -562,7 +620,7 @@ namespace mRemoteNG.UI.Window txtCheck2.Text = string.Format(Language.strCcVNCFailed, GeneralAppInfo.UrlForum); Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, - "VNC " + Language.strCcNotInstalledProperly, true); + "VNC " + Language.strCcNotInstalledProperly, true); } } @@ -598,9 +656,9 @@ namespace mRemoteNG.UI.Window txtCheck3.Text = Language.strCcPuttyFailed; Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, - "PuTTY " + Language.strCcNotInstalledProperly, true); + "PuTTY " + Language.strCcNotInstalledProperly, true); Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "File " + pPath + " does not exist.", - true); + true); } } @@ -628,7 +686,8 @@ namespace mRemoteNG.UI.Window lblCheck4.Text = @"ICA (Citrix ICA) " + Language.strCcCheckFailed; txtCheck4.Text = string.Format(Language.strCcICAFailed, GeneralAppInfo.UrlForum); - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "ICA " + Language.strCcNotInstalledProperly, true); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "ICA " + Language.strCcNotInstalledProperly, true); Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, ex.Message, true); } } @@ -672,9 +731,9 @@ namespace mRemoteNG.UI.Window txtCheck5.Text = string.Format(Language.strCcGeckoFailed, GeneralAppInfo.UrlForum); Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, - "Gecko " + Language.strCcNotInstalledProperly, true); + "Gecko " + Language.strCcNotInstalledProperly, true); Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, - "GeckoFx was not found in " + geckoFxPath, true); + "GeckoFx was not found in " + geckoFxPath, true); } } } diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 9c79b119e..a2eb7e45b 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -25,7 +25,7 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { public class ConfigWindow : BaseWindow - { + { private bool _originalPropertyGridToolStripItemCountValid; private int _originalPropertyGridToolStripItemCount; private System.ComponentModel.Container _components; @@ -44,6 +44,7 @@ namespace mRemoteNG.UI.Window private ThemeManager _themeManager; private AbstractConnectionRecord _selectedTreeNode; + public AbstractConnectionRecord SelectedTreeNode { get => _selectedTreeNode; @@ -55,7 +56,7 @@ namespace mRemoteNG.UI.Window } private void InitializeComponent() - { + { _components = new System.ComponentModel.Container(); Load += Config_Load; SystemColorsChanged += Config_SystemColorsChanged; @@ -89,8 +90,8 @@ namespace mRemoteNG.UI.Window //pGrid // _pGrid.Anchor = ((AnchorStyles.Top | AnchorStyles.Bottom) - | AnchorStyles.Left) - | AnchorStyles.Right; + | AnchorStyles.Left) + | AnchorStyles.Right; _pGrid.BrowsableProperties = null; _pGrid.ContextMenuStrip = PropertyGridContextMenu; _pGrid.Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, Convert.ToByte(0)); @@ -105,7 +106,10 @@ namespace mRemoteNG.UI.Window // //propertyGridContextMenu // - PropertyGridContextMenu.Items.AddRange(new ToolStripItem[] { _propertyGridContextMenuReset, _toolStripSeparator1, _propertyGridContextMenuShowHelpText }); + PropertyGridContextMenu.Items.AddRange(new ToolStripItem[] + { + _propertyGridContextMenuReset, _toolStripSeparator1, _propertyGridContextMenuShowHelpText + }); PropertyGridContextMenu.Name = "PropertyGridContextMenu"; PropertyGridContextMenu.Size = new Size(157, 76); // @@ -201,66 +205,67 @@ namespace mRemoteNG.UI.Window Text = @"Config"; PropertyGridContextMenu.ResumeLayout(false); ResumeLayout(false); - - } + } #region Public Properties + public bool PropertiesVisible - { - get => _btnShowProperties.Checked; + { + get => _btnShowProperties.Checked; set - { + { _btnShowProperties.Checked = value; - if (!value) return; - _btnShowInheritance.Checked = false; - _btnShowDefaultInheritance.Checked = false; - _btnShowDefaultProperties.Checked = false; - } - } + if (!value) return; + _btnShowInheritance.Checked = false; + _btnShowDefaultInheritance.Checked = false; + _btnShowDefaultProperties.Checked = false; + } + } public bool InheritanceVisible - { - get => _btnShowInheritance.Checked; + { + get => _btnShowInheritance.Checked; set - { + { _btnShowInheritance.Checked = value; - if (!value) return; - _btnShowProperties.Checked = false; - _btnShowDefaultInheritance.Checked = false; - _btnShowDefaultProperties.Checked = false; - } - } + if (!value) return; + _btnShowProperties.Checked = false; + _btnShowDefaultInheritance.Checked = false; + _btnShowDefaultProperties.Checked = false; + } + } public bool DefaultPropertiesVisible - { - get => _btnShowDefaultProperties.Checked; + { + get => _btnShowDefaultProperties.Checked; set - { + { _btnShowDefaultProperties.Checked = value; - if (!value) return; - _btnShowProperties.Checked = false; - _btnShowDefaultInheritance.Checked = false; - _btnShowInheritance.Checked = false; - } - } + if (!value) return; + _btnShowProperties.Checked = false; + _btnShowDefaultInheritance.Checked = false; + _btnShowInheritance.Checked = false; + } + } public bool DefaultInheritanceVisible - { - get => _btnShowDefaultInheritance.Checked; + { + get => _btnShowDefaultInheritance.Checked; set - { + { _btnShowDefaultInheritance.Checked = value; - if (!value) return; - _btnShowProperties.Checked = false; - _btnShowDefaultProperties.Checked = false; - _btnShowInheritance.Checked = false; - } - } + if (!value) return; + _btnShowProperties.Checked = false; + _btnShowDefaultProperties.Checked = false; + _btnShowInheritance.Checked = false; + } + } /// /// A list of properties being shown for the current object. /// - public IEnumerable VisibleObjectProperties => _pGrid.VisibleProperties; + public IEnumerable VisibleObjectProperties => _pGrid.VisibleProperties; + #endregion #region Constructors @@ -276,144 +281,145 @@ namespace mRemoteNG.UI.Window InitializeComponent(); ApplyLanguage(); } + #endregion #region Public Methods - protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData) - { - // Main form handle command key events + protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData) + { + // Main form handle command key events // Adapted from http://kiwigis.blogspot.com/2009/05/adding-tab-key-support-to-propertygrid.html - if ((keyData & Keys.KeyCode) != Keys.Tab) return base.ProcessCmdKey(ref msg, keyData); - var selectedItem = _pGrid.SelectedGridItem; - var gridRoot = selectedItem; - while (gridRoot.GridItemType != GridItemType.Root) - { - gridRoot = gridRoot.Parent; - } + if ((keyData & Keys.KeyCode) != Keys.Tab) return base.ProcessCmdKey(ref msg, keyData); + var selectedItem = _pGrid.SelectedGridItem; + var gridRoot = selectedItem; + while (gridRoot.GridItemType != GridItemType.Root) + { + gridRoot = gridRoot.Parent; + } - var gridItems = new List(); - FindChildGridItems(gridRoot, ref gridItems); + var gridItems = new List(); + FindChildGridItems(gridRoot, ref gridItems); - if (!ContainsGridItemProperty(gridItems)) - return true; + if (!ContainsGridItemProperty(gridItems)) + return true; - var newItem = selectedItem; + var newItem = selectedItem; - // ReSharper disable once SwitchStatementMissingSomeCases - switch (keyData) - { - case (Keys.Tab | Keys.Shift): - newItem = FindPreviousGridItemProperty(gridItems, selectedItem); - break; - case Keys.Tab: - newItem = FindNextGridItemProperty(gridItems, selectedItem); - break; - } + // ReSharper disable once SwitchStatementMissingSomeCases + switch (keyData) + { + case (Keys.Tab | Keys.Shift): + newItem = FindPreviousGridItemProperty(gridItems, selectedItem); + break; + case Keys.Tab: + newItem = FindNextGridItemProperty(gridItems, selectedItem); + break; + } - _pGrid.SelectedGridItem = newItem; + _pGrid.SelectedGridItem = newItem; - return true; // Handled - } + return true; // Handled + } - private void FindChildGridItems(GridItem item, ref List gridItems) - { - gridItems.Add(item); + private void FindChildGridItems(GridItem item, ref List gridItems) + { + gridItems.Add(item); - if (item.Expandable && !item.Expanded) return; - foreach (GridItem child in item.GridItems) - { - FindChildGridItems(child, ref gridItems); - } - } + if (item.Expandable && !item.Expanded) return; + foreach (GridItem child in item.GridItems) + { + FindChildGridItems(child, ref gridItems); + } + } - private bool ContainsGridItemProperty(IEnumerable gridItems) - { - return gridItems.Any(item => item.GridItemType == GridItemType.Property); - } + private bool ContainsGridItemProperty(IEnumerable gridItems) + { + return gridItems.Any(item => item.GridItemType == GridItemType.Property); + } private GridItem FindPreviousGridItemProperty(IList gridItems, GridItem startItem) - { - if (gridItems.Count == 0 || startItem == null) - return null; + { + if (gridItems.Count == 0 || startItem == null) + return null; - var startIndex = gridItems.IndexOf(startItem); - if (startItem.GridItemType == GridItemType.Property) - { - startIndex--; - if (startIndex < 0) - { - startIndex = gridItems.Count - 1; - } - } + var startIndex = gridItems.IndexOf(startItem); + if (startItem.GridItemType == GridItemType.Property) + { + startIndex--; + if (startIndex < 0) + { + startIndex = gridItems.Count - 1; + } + } - var previousIndex = 0; - var previousIndexValid = false; - for (var index = startIndex; index >= 0; index--) - { - if (gridItems[index].GridItemType != GridItemType.Property) continue; - previousIndex = index; - previousIndexValid = true; - break; - } + var previousIndex = 0; + var previousIndexValid = false; + for (var index = startIndex; index >= 0; index--) + { + if (gridItems[index].GridItemType != GridItemType.Property) continue; + previousIndex = index; + previousIndexValid = true; + break; + } - if (previousIndexValid) - return gridItems[previousIndex]; + if (previousIndexValid) + return gridItems[previousIndex]; - for (var index = gridItems.Count - 1; index >= startIndex + 1; index--) - { - if (gridItems[index].GridItemType != GridItemType.Property) continue; - previousIndex = index; - previousIndexValid = true; - break; - } + for (var index = gridItems.Count - 1; index >= startIndex + 1; index--) + { + if (gridItems[index].GridItemType != GridItemType.Property) continue; + previousIndex = index; + previousIndexValid = true; + break; + } - return !previousIndexValid ? null : gridItems[previousIndex]; - } + return !previousIndexValid ? null : gridItems[previousIndex]; + } - private GridItem FindNextGridItemProperty(IList gridItems, GridItem startItem) - { - if (gridItems.Count == 0 || startItem == null) - return null; + private GridItem FindNextGridItemProperty(IList gridItems, GridItem startItem) + { + if (gridItems.Count == 0 || startItem == null) + return null; - var startIndex = gridItems.IndexOf(startItem); - if (startItem.GridItemType == GridItemType.Property) - { - startIndex++; - if (startIndex >= gridItems.Count) - { - startIndex = 0; - } - } + var startIndex = gridItems.IndexOf(startItem); + if (startItem.GridItemType == GridItemType.Property) + { + startIndex++; + if (startIndex >= gridItems.Count) + { + startIndex = 0; + } + } - var nextIndex = 0; - var nextIndexValid = false; - for (var index = startIndex; index <= gridItems.Count - 1; index++) - { - if (gridItems[index].GridItemType != GridItemType.Property) continue; - nextIndex = index; - nextIndexValid = true; - break; - } + var nextIndex = 0; + var nextIndexValid = false; + for (var index = startIndex; index <= gridItems.Count - 1; index++) + { + if (gridItems[index].GridItemType != GridItemType.Property) continue; + nextIndex = index; + nextIndexValid = true; + break; + } - if (nextIndexValid) - return gridItems[nextIndex]; + if (nextIndexValid) + return gridItems[nextIndex]; - for (var index = 0; index <= startIndex - 1; index++) - { - if (gridItems[index].GridItemType != GridItemType.Property) continue; - nextIndex = index; - nextIndexValid = true; - break; - } + for (var index = 0; index <= startIndex - 1; index++) + { + if (gridItems[index].GridItemType != GridItemType.Property) continue; + nextIndex = index; + nextIndexValid = true; + break; + } - return !nextIndexValid ? null : gridItems[nextIndex]; - } + return !nextIndexValid ? null : gridItems[nextIndex]; + } - private void SetPropertyGridObject(object propertyGridObject) - { - try - { + private void SetPropertyGridObject(object propertyGridObject) + { + try + { _btnShowProperties.Enabled = false; _btnShowInheritance.Enabled = false; _btnShowDefaultProperties.Enabled = false; @@ -424,56 +430,56 @@ namespace mRemoteNG.UI.Window _btnIcon.Image = null; if (propertyGridObject is ConnectionInfo gridObjectAsConnectionInfo) //CONNECTION INFO - { + { if (propertyGridObject is ContainerInfo gridObjectAsContainerInfo) //CONTAINER { if (propertyGridObject is RootNodeInfo gridObjectAsRootNodeInfo) // ROOT - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (gridObjectAsRootNodeInfo.Type) - { - case RootNodeType.Connection: - PropertiesVisible = true; - DefaultPropertiesVisible = false; - _btnShowProperties.Enabled = true; - _btnShowInheritance.Enabled = false; - _btnShowDefaultProperties.Enabled = true; - _btnShowDefaultInheritance.Enabled = true; - _btnIcon.Enabled = false; - _btnHostStatus.Enabled = false; - break; - case RootNodeType.PuttySessions: - PropertiesVisible = true; - DefaultPropertiesVisible = false; - _btnShowProperties.Enabled = true; - _btnShowInheritance.Enabled = false; - _btnShowDefaultProperties.Enabled = false; - _btnShowDefaultInheritance.Enabled = false; - _btnIcon.Enabled = false; - _btnHostStatus.Enabled = false; - break; - } - - _pGrid.SelectedObject = propertyGridObject; - } - else { - _pGrid.SelectedObject = propertyGridObject; + // ReSharper disable once SwitchStatementMissingSomeCases + switch (gridObjectAsRootNodeInfo.Type) + { + case RootNodeType.Connection: + PropertiesVisible = true; + DefaultPropertiesVisible = false; + _btnShowProperties.Enabled = true; + _btnShowInheritance.Enabled = false; + _btnShowDefaultProperties.Enabled = true; + _btnShowDefaultInheritance.Enabled = true; + _btnIcon.Enabled = false; + _btnHostStatus.Enabled = false; + break; + case RootNodeType.PuttySessions: + PropertiesVisible = true; + DefaultPropertiesVisible = false; + _btnShowProperties.Enabled = true; + _btnShowInheritance.Enabled = false; + _btnShowDefaultProperties.Enabled = false; + _btnShowDefaultInheritance.Enabled = false; + _btnIcon.Enabled = false; + _btnHostStatus.Enabled = false; + break; + } - _btnShowProperties.Enabled = true; - _btnShowInheritance.Enabled = + _pGrid.SelectedObject = propertyGridObject; + } + else + { + _pGrid.SelectedObject = propertyGridObject; + + _btnShowProperties.Enabled = true; + _btnShowInheritance.Enabled = gridObjectAsContainerInfo.Parent != null && !(gridObjectAsContainerInfo.Parent is RootNodeInfo); - _btnShowDefaultProperties.Enabled = false; - _btnShowDefaultInheritance.Enabled = false; - _btnIcon.Enabled = true; - _btnHostStatus.Enabled = false; + _btnShowDefaultProperties.Enabled = false; + _btnShowDefaultInheritance.Enabled = false; + _btnIcon.Enabled = true; + _btnHostStatus.Enabled = false; - PropertiesVisible = true; - } + PropertiesVisible = true; + } } else //NO CONTAINER - { + { if (PropertiesVisible) //Properties selected { _pGrid.SelectedObject = propertyGridObject; @@ -540,33 +546,38 @@ namespace mRemoteNG.UI.Window } var conIcon = ConnectionIcon.FromString(Convert.ToString(gridObjectAsConnectionInfo.Icon)); - if (conIcon != null) - { + if (conIcon != null) + { _btnIcon.Image = conIcon.ToBitmap(); - } - } - else if (propertyGridObject is ConnectionInfoInheritance) //INHERITANCE - { + } + } + else if (propertyGridObject is ConnectionInfoInheritance) //INHERITANCE + { _pGrid.SelectedObject = propertyGridObject; - if (InheritanceVisible) - { + if (InheritanceVisible) + { InheritanceVisible = true; _btnShowProperties.Enabled = true; _btnShowInheritance.Enabled = true; _btnShowDefaultProperties.Enabled = false; _btnShowDefaultInheritance.Enabled = false; _btnIcon.Enabled = true; - _btnHostStatus.Enabled = !((ConnectionInfo)((ConnectionInfoInheritance)propertyGridObject).Parent).IsContainer; + _btnHostStatus.Enabled = + !((ConnectionInfo)((ConnectionInfoInheritance)propertyGridObject).Parent).IsContainer; InheritanceVisible = true; - var conIcon = ConnectionIcon.FromString(Convert.ToString(((ConnectionInfo)((ConnectionInfoInheritance)propertyGridObject).Parent).Icon)); - if (conIcon != null) - { + var conIcon = ConnectionIcon.FromString(Convert.ToString( + ((ConnectionInfo) + ((ConnectionInfoInheritance) + propertyGridObject).Parent) + .Icon)); + if (conIcon != null) + { _btnIcon.Image = conIcon.ToBitmap(); - } - } - else if (DefaultInheritanceVisible) - { + } + } + else if (DefaultInheritanceVisible) + { _btnShowProperties.Enabled = true; _btnShowInheritance.Enabled = false; _btnShowDefaultProperties.Enabled = true; @@ -575,36 +586,39 @@ namespace mRemoteNG.UI.Window _btnHostStatus.Enabled = false; DefaultInheritanceVisible = true; - } - - } + } + } ShowHideGridItems(); SetHostStatus(propertyGridObject); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridObjectFailed + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridObjectFailed + Environment.NewLine + + ex.Message, true); + } + } + #endregion #region Private Methods - private void ApplyLanguage() - { - _btnShowInheritance.Text = Language.strButtonInheritance; - _btnShowDefaultInheritance.Text = Language.strButtonDefaultInheritance; - _btnShowProperties.Text = Language.strButtonProperties; - _btnShowDefaultProperties.Text = Language.strButtonDefaultProperties; - _btnIcon.Text = Language.strButtonIcon; - _btnHostStatus.Text = Language.strStatus; - Text = Language.strMenuConfig; - TabText = Language.strMenuConfig; - _propertyGridContextMenuShowHelpText.Text = Language.strMenuShowHelpText; - } - private new void ApplyTheme() - { + private void ApplyLanguage() + { + _btnShowInheritance.Text = Language.strButtonInheritance; + _btnShowDefaultInheritance.Text = Language.strButtonDefaultInheritance; + _btnShowProperties.Text = Language.strButtonProperties; + _btnShowDefaultProperties.Text = Language.strButtonDefaultProperties; + _btnIcon.Text = Language.strButtonIcon; + _btnHostStatus.Text = Language.strStatus; + Text = Language.strMenuConfig; + TabText = Language.strMenuConfig; + _propertyGridContextMenuShowHelpText.Text = Language.strMenuShowHelpText; + } + + private new void ApplyTheme() + { if (!ThemeManager.getInstance().ActiveAndExtended) return; _pGrid.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _pGrid.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); @@ -614,79 +628,86 @@ namespace mRemoteNG.UI.Window _pGrid.HelpBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _pGrid.HelpForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); _pGrid.CategoryForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); - _pGrid.CommandsDisabledLinkColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); - _pGrid.CommandsBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); - _pGrid.CommandsForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); + _pGrid.CommandsDisabledLinkColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); + _pGrid.CommandsBackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); + _pGrid.CommandsForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); } private void AddToolStripItems() - { - try - { - var customToolStrip = new ToolStrip(); - customToolStrip.Items.Add(_btnShowProperties); - customToolStrip.Items.Add(_btnShowInheritance); - customToolStrip.Items.Add(_btnShowDefaultProperties); - customToolStrip.Items.Add(_btnShowDefaultInheritance); - customToolStrip.Items.Add(_btnHostStatus); - customToolStrip.Items.Add(_btnIcon); - customToolStrip.Show(); + { + try + { + var customToolStrip = new ToolStrip(); + customToolStrip.Items.Add(_btnShowProperties); + customToolStrip.Items.Add(_btnShowInheritance); + customToolStrip.Items.Add(_btnShowDefaultProperties); + customToolStrip.Items.Add(_btnShowDefaultInheritance); + customToolStrip.Items.Add(_btnHostStatus); + customToolStrip.Items.Add(_btnIcon); + customToolStrip.Show(); - var propertyGridToolStrip = new ToolStrip(); + var propertyGridToolStrip = new ToolStrip(); - ToolStrip toolStrip = null; - foreach (Control control in _pGrid.Controls) - { + ToolStrip toolStrip = null; + foreach (Control control in _pGrid.Controls) + { toolStrip = control as ToolStrip; - if (toolStrip == null) continue; - propertyGridToolStrip = toolStrip; - break; - } + if (toolStrip == null) continue; + propertyGridToolStrip = toolStrip; + break; + } - if (toolStrip == null) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strCouldNotFindToolStripInFilteredPropertyGrid, true); - return; - } + if (toolStrip == null) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strCouldNotFindToolStripInFilteredPropertyGrid, true); + return; + } - if (!_originalPropertyGridToolStripItemCountValid) - { - _originalPropertyGridToolStripItemCount = propertyGridToolStrip.Items.Count; - _originalPropertyGridToolStripItemCountValid = true; - } - Debug.Assert(_originalPropertyGridToolStripItemCount == 5); + if (!_originalPropertyGridToolStripItemCountValid) + { + _originalPropertyGridToolStripItemCount = propertyGridToolStrip.Items.Count; + _originalPropertyGridToolStripItemCountValid = true; + } - // Hide the "Property Pages" button - propertyGridToolStrip.Items[_originalPropertyGridToolStripItemCount - 1].Visible = false; + Debug.Assert(_originalPropertyGridToolStripItemCount == 5); - var expectedToolStripItemCount = _originalPropertyGridToolStripItemCount + customToolStrip.Items.Count; - if (propertyGridToolStrip.Items.Count == expectedToolStripItemCount) return; - propertyGridToolStrip.AllowMerge = true; - ToolStripManager.Merge(customToolStrip, propertyGridToolStrip); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigUiLoadFailed + Environment.NewLine + ex.Message, true); - } - } + // Hide the "Property Pages" button + propertyGridToolStrip.Items[_originalPropertyGridToolStripItemCount - 1].Visible = false; - private void Config_Load(object sender, EventArgs e) - { + var expectedToolStripItemCount = _originalPropertyGridToolStripItemCount + customToolStrip.Items.Count; + if (propertyGridToolStrip.Items.Count == expectedToolStripItemCount) return; + propertyGridToolStrip.AllowMerge = true; + ToolStripManager.Merge(customToolStrip, propertyGridToolStrip); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigUiLoadFailed + Environment.NewLine + ex.Message, + true); + } + } + + private void Config_Load(object sender, EventArgs e) + { _themeManager = ThemeManager.getInstance(); _themeManager.ThemeChanged += ApplyTheme; ApplyTheme(); - AddToolStripItems(); - _pGrid.HelpVisible = Settings.Default.ShowConfigHelpText; - } + AddToolStripItems(); + _pGrid.HelpVisible = Settings.Default.ShowConfigHelpText; + } - private void Config_SystemColorsChanged(object sender, EventArgs e) - { - AddToolStripItems(); - } + private void Config_SystemColorsChanged(object sender, EventArgs e) + { + AddToolStripItems(); + } - private void pGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) - { - try + private void pGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) + { + try { UpdateConnectionInfoNode(e); UpdateRootInfoNode(e); @@ -694,10 +715,12 @@ namespace mRemoteNG.UI.Window ShowHideGridItems(); } catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridValueFailed + Environment.NewLine + ex.Message, true); - } - } + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridValueFailed + Environment.NewLine + + ex.Message, true); + } + } private void UpdateConnectionInfoNode(PropertyValueChangedEventArgs e) { @@ -728,7 +751,7 @@ namespace mRemoteNG.UI.Window } if (selectedGridObject is DefaultConnectionInfo) - DefaultConnectionInfo.Instance.SaveTo(Settings.Default, a=>"ConDefault"+a); + DefaultConnectionInfo.Instance.SaveTo(Settings.Default, a => "ConDefault" + a); } private void UpdateRootInfoNode(PropertyValueChangedEventArgs e) @@ -765,19 +788,19 @@ namespace mRemoteNG.UI.Window private void UpdateInheritanceNode() { if (!(_pGrid.SelectedObject is DefaultConnectionInheritance)) return; - DefaultConnectionInheritance.Instance.SaveTo(Settings.Default, a=>"InhDefault"+a); + DefaultConnectionInheritance.Instance.SaveTo(Settings.Default, a => "InhDefault" + a); } private void pGrid_PropertySortChanged(object sender, EventArgs e) - { - if (_pGrid.PropertySort == PropertySort.CategorizedAlphabetical) - _pGrid.PropertySort = PropertySort.Categorized; - } + { + if (_pGrid.PropertySort == PropertySort.CategorizedAlphabetical) + _pGrid.PropertySort = PropertySort.Categorized; + } - private void ShowHideGridItems() - { - try - { + private void ShowHideGridItems() + { + try + { var strHide = new List(); if (_pGrid.SelectedObject is RootNodeInfo o) { @@ -786,6 +809,7 @@ namespace mRemoteNG.UI.Window { strHide.Add("Password"); } + strHide.Add("CacheBitmaps"); strHide.Add("Colors"); strHide.Add("DisplayThemes"); @@ -868,6 +892,7 @@ namespace mRemoteNG.UI.Window { strHide.Add("RDPAlertIdleTimeout"); } + if (conI.RDGatewayUsageMethod == RdpProtocol.RDGatewayUsageMethod.Never) { strHide.Add("RDGatewayDomain"); @@ -876,20 +901,25 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); } - else if (conI.RDGatewayUseConnectionCredentials == RdpProtocol.RDGatewayUseConnectionCredentials.Yes) + else if (conI.RDGatewayUseConnectionCredentials == + RdpProtocol.RDGatewayUseConnectionCredentials.Yes) { strHide.Add("RDGatewayDomain"); strHide.Add("RDGatewayPassword"); strHide.Add("RDGatewayUsername"); } - if (!(conI.Resolution == RdpProtocol.RDPResolutions.FitToWindow || conI.Resolution == RdpProtocol.RDPResolutions.Fullscreen)) + + if (!(conI.Resolution == RdpProtocol.RDPResolutions.FitToWindow || + conI.Resolution == RdpProtocol.RDPResolutions.Fullscreen)) { strHide.Add("AutomaticResize"); } + if (conI.RedirectSound != RdpProtocol.RDPSounds.BringToThisComputer) { strHide.Add("SoundQuality"); } + break; case ProtocolType.VNC: strHide.Add("CacheBitmaps"); @@ -928,6 +958,7 @@ namespace mRemoteNG.UI.Window strHide.Add("Username"); strHide.Add("Domain"); } + if (conI.VNCProxyType == ProtocolVNC.ProxyType.ProxyNone) { strHide.Add("VNCProxyIP"); @@ -935,6 +966,7 @@ namespace mRemoteNG.UI.Window strHide.Add("VNCProxyPort"); strHide.Add("VNCProxyUsername"); } + strHide.Add("SoundQuality"); break; case ProtocolType.SSH1: @@ -1429,248 +1461,276 @@ namespace mRemoteNG.UI.Window _pGrid.HiddenProperties = strHide.ToArray(); _pGrid.Refresh(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridHideItemsFailed + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridHideItemsFailed + + Environment.NewLine + ex.Message, true); + } + } - private void btnShowProperties_Click(object sender, EventArgs e) - { + private void btnShowProperties_Click(object sender, EventArgs e) + { if (_pGrid.SelectedObject is ConnectionInfoInheritance o) - { - if (_pGrid.SelectedObject is DefaultConnectionInheritance) - { + { + if (_pGrid.SelectedObject is DefaultConnectionInheritance) + { PropertiesVisible = true; InheritanceVisible = false; DefaultPropertiesVisible = false; DefaultInheritanceVisible = false; SetPropertyGridObject((RootNodeInfo)_selectedTreeNode); - } - else - { + } + else + { PropertiesVisible = true; InheritanceVisible = false; DefaultPropertiesVisible = false; DefaultInheritanceVisible = false; SetPropertyGridObject(o.Parent); - } - } - else if (_pGrid.SelectedObject is ConnectionInfo) - { - if (!((ConnectionInfo) _pGrid.SelectedObject).IsDefault) return; - PropertiesVisible = true; - InheritanceVisible = false; - DefaultPropertiesVisible = false; - DefaultInheritanceVisible = false; - SetPropertyGridObject((RootNodeInfo)_selectedTreeNode); - } - } + } + } + else if (_pGrid.SelectedObject is ConnectionInfo) + { + if (!((ConnectionInfo)_pGrid.SelectedObject).IsDefault) return; + PropertiesVisible = true; + InheritanceVisible = false; + DefaultPropertiesVisible = false; + DefaultInheritanceVisible = false; + SetPropertyGridObject((RootNodeInfo)_selectedTreeNode); + } + } - private void btnShowDefaultProperties_Click(object sender, EventArgs e) - { - if (!(_pGrid.SelectedObject is RootNodeInfo) && !(_pGrid.SelectedObject is ConnectionInfoInheritance)) return; - PropertiesVisible = false; - InheritanceVisible = false; - DefaultPropertiesVisible = true; - DefaultInheritanceVisible = false; - SetPropertyGridObject(DefaultConnectionInfo.Instance); - } + private void btnShowDefaultProperties_Click(object sender, EventArgs e) + { + if (!(_pGrid.SelectedObject is RootNodeInfo) && + !(_pGrid.SelectedObject is ConnectionInfoInheritance)) return; + PropertiesVisible = false; + InheritanceVisible = false; + DefaultPropertiesVisible = true; + DefaultInheritanceVisible = false; + SetPropertyGridObject(DefaultConnectionInfo.Instance); + } - private void btnShowInheritance_Click(object sender, EventArgs e) - { - if (!(_pGrid.SelectedObject is ConnectionInfo)) return; - PropertiesVisible = false; - InheritanceVisible = true; - DefaultPropertiesVisible = false; - DefaultInheritanceVisible = false; - SetPropertyGridObject(((ConnectionInfo)_pGrid.SelectedObject).Inheritance); - } + private void btnShowInheritance_Click(object sender, EventArgs e) + { + if (!(_pGrid.SelectedObject is ConnectionInfo)) return; + PropertiesVisible = false; + InheritanceVisible = true; + DefaultPropertiesVisible = false; + DefaultInheritanceVisible = false; + SetPropertyGridObject(((ConnectionInfo)_pGrid.SelectedObject).Inheritance); + } - private void btnShowDefaultInheritance_Click(object sender, EventArgs e) - { - if (!(_pGrid.SelectedObject is RootNodeInfo) && !(_pGrid.SelectedObject is ConnectionInfo)) return; - PropertiesVisible = false; - InheritanceVisible = false; - DefaultPropertiesVisible = false; - DefaultInheritanceVisible = true; - SetPropertyGridObject(DefaultConnectionInheritance.Instance); - } + private void btnShowDefaultInheritance_Click(object sender, EventArgs e) + { + if (!(_pGrid.SelectedObject is RootNodeInfo) && !(_pGrid.SelectedObject is ConnectionInfo)) return; + PropertiesVisible = false; + InheritanceVisible = false; + DefaultPropertiesVisible = false; + DefaultInheritanceVisible = true; + SetPropertyGridObject(DefaultConnectionInheritance.Instance); + } - private void btnHostStatus_Click(object sender, EventArgs e) - { - SetHostStatus(_pGrid.SelectedObject); - } + private void btnHostStatus_Click(object sender, EventArgs e) + { + SetHostStatus(_pGrid.SelectedObject); + } - private void btnIcon_Click(object sender, MouseEventArgs e) - { - try - { - if (!(_pGrid.SelectedObject is ConnectionInfo) || _pGrid.SelectedObject is PuttySessionInfo) return; - CMenIcons.Items.Clear(); + private void btnIcon_Click(object sender, MouseEventArgs e) + { + try + { + if (!(_pGrid.SelectedObject is ConnectionInfo) || _pGrid.SelectedObject is PuttySessionInfo) return; + CMenIcons.Items.Clear(); - foreach (var iStr in ConnectionIcon.Icons) - { - var tI = new ToolStripMenuItem - { - Text = iStr, - Image = ConnectionIcon.FromString(iStr).ToBitmap() - }; - tI.Click += IconMenu_Click; + foreach (var iStr in ConnectionIcon.Icons) + { + var tI = new ToolStripMenuItem + { + Text = iStr, + Image = ConnectionIcon.FromString(iStr).ToBitmap() + }; + tI.Click += IconMenu_Click; - CMenIcons.Items.Add(tI); - } - var mPos = new Point(new Size(PointToScreen(new Point(e.Location.X + _pGrid.Width - 100, e.Location.Y)))); - CMenIcons.Show(mPos); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridButtonIconClickFailed + Environment.NewLine + ex.Message, true); - } - } + CMenIcons.Items.Add(tI); + } - private void IconMenu_Click(object sender, EventArgs e) - { - try - { - var connectionInfo = (ConnectionInfo)_pGrid.SelectedObject; - if (connectionInfo == null) return; + var mPos = new Point( + new Size(PointToScreen(new Point(e.Location.X + _pGrid.Width - 100, + e.Location.Y)))); + CMenIcons.Show(mPos); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridButtonIconClickFailed + + Environment.NewLine + ex.Message, true); + } + } - var selectedMenuItem = (ToolStripMenuItem)sender; + private void IconMenu_Click(object sender, EventArgs e) + { + try + { + var connectionInfo = (ConnectionInfo)_pGrid.SelectedObject; + if (connectionInfo == null) return; - var iconName = selectedMenuItem?.Text; - if (string.IsNullOrEmpty(iconName)) return; + var selectedMenuItem = (ToolStripMenuItem)sender; - var connectionIcon = ConnectionIcon.FromString(iconName); - if (connectionIcon == null) return; + var iconName = selectedMenuItem?.Text; + if (string.IsNullOrEmpty(iconName)) return; - _btnIcon.Image = connectionIcon.ToBitmap(); + var connectionIcon = ConnectionIcon.FromString(iconName); + if (connectionIcon == null) return; - connectionInfo.Icon = iconName; - _pGrid.Refresh(); + _btnIcon.Image = connectionIcon.ToBitmap(); + + connectionInfo.Icon = iconName; + _pGrid.Refresh(); + + Runtime.ConnectionsService.SaveConnectionsAsync(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridMenuClickFailed + + Environment.NewLine + ex.Message, true); + } + } - Runtime.ConnectionsService.SaveConnectionsAsync(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridMenuClickFailed + Environment.NewLine + ex.Message, true); - } - } #endregion #region Host Status (Ping) - private Thread _pThread; - private void CheckHostAlive(object hostName) - { - if (string.IsNullOrEmpty(hostName as string)) - { - ShowStatusImage(Resources.HostStatus_Off); + private Thread _pThread; + + private void CheckHostAlive(object hostName) + { + if (string.IsNullOrEmpty(hostName as string)) + { + ShowStatusImage(Resources.HostStatus_Off); return; - } + } - var pingSender = new Ping(); + var pingSender = new Ping(); - try - { - var pReply = pingSender.Send((string)hostName); - if (pReply?.Status == IPStatus.Success) - { - if ((string)_btnHostStatus.Tag == "checking") - ShowStatusImage(Resources.HostStatus_On); - } - else - { - if ((string)_btnHostStatus.Tag == "checking") - ShowStatusImage(Resources.HostStatus_Off); - } - } - catch (Exception) - { - if ((string)_btnHostStatus.Tag == "checking") - ShowStatusImage(Resources.HostStatus_Off); - } - } + try + { + var pReply = pingSender.Send((string)hostName); + if (pReply?.Status == IPStatus.Success) + { + if ((string)_btnHostStatus.Tag == "checking") + ShowStatusImage(Resources.HostStatus_On); + } + else + { + if ((string)_btnHostStatus.Tag == "checking") + ShowStatusImage(Resources.HostStatus_Off); + } + } + catch (Exception) + { + if ((string)_btnHostStatus.Tag == "checking") + ShowStatusImage(Resources.HostStatus_Off); + } + } private delegate void ShowStatusImageCb(Image image); - private void ShowStatusImage(Image image) - { - if (_pGrid.InvokeRequired) - { - ShowStatusImageCb d = ShowStatusImage; + + private void ShowStatusImage(Image image) + { + if (_pGrid.InvokeRequired) + { + ShowStatusImageCb d = ShowStatusImage; _pGrid.Invoke(d, image); - } - else - { + } + else + { _btnHostStatus.Image = image; _btnHostStatus.Tag = "checkfinished"; - } - } + } + } - private void SetHostStatus(object connectionInfo) - { - try - { + private void SetHostStatus(object connectionInfo) + { + try + { _btnHostStatus.Image = Resources.HostStatus_Check; - // To check status, ConnectionInfo must be an mRemoteNG.Connection.Info that is not a container + // To check status, ConnectionInfo must be an mRemoteNG.Connection.Info that is not a container if (!(connectionInfo is ConnectionInfo info)) return; if (info.IsContainer) return; _btnHostStatus.Tag = "checking"; - _pThread = new Thread(CheckHostAlive); - _pThread.SetApartmentState(ApartmentState.STA); - _pThread.IsBackground = true; - _pThread.Start(((ConnectionInfo)connectionInfo).Hostname); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridSetHostStatusFailed + Environment.NewLine + ex.Message, true); - } - } + _pThread = new Thread(CheckHostAlive); + _pThread.SetApartmentState(ApartmentState.STA); + _pThread.IsBackground = true; + _pThread.Start(((ConnectionInfo)connectionInfo).Hostname); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + Language.strConfigPropertyGridSetHostStatusFailed + + Environment.NewLine + ex.Message, true); + } + } + #endregion #region Event Handlers + private void propertyGridContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e) - { - try - { - _propertyGridContextMenuShowHelpText.Checked = Settings.Default.ShowConfigHelpText; - var gridItem = _pGrid.SelectedGridItem; - _propertyGridContextMenuReset.Enabled = Convert.ToBoolean(_pGrid.SelectedObject != null && gridItem?.PropertyDescriptor != null && gridItem.PropertyDescriptor.CanResetValue(_pGrid.SelectedObject)); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenu_Opening() failed.", ex); - } - } - - private void propertyGridContextMenuReset_Click(object sender, EventArgs e) - { - try - { - var gridItem = _pGrid.SelectedGridItem; - if (_pGrid.SelectedObject != null && gridItem?.PropertyDescriptor != null && gridItem.PropertyDescriptor.CanResetValue(_pGrid.SelectedObject)) - { - _pGrid.ResetSelectedProperty(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenuReset_Click() failed.", ex); - } - } - - private void propertyGridContextMenuShowHelpText_Click(object sender, EventArgs e) - { - _propertyGridContextMenuShowHelpText.Checked = !_propertyGridContextMenuShowHelpText.Checked; - } - - private void propertyGridContextMenuShowHelpText_CheckedChanged(object sender, EventArgs e) - { - Settings.Default.ShowConfigHelpText = _propertyGridContextMenuShowHelpText.Checked; - _pGrid.HelpVisible = _propertyGridContextMenuShowHelpText.Checked; + { + try + { + _propertyGridContextMenuShowHelpText.Checked = Settings.Default.ShowConfigHelpText; + var gridItem = _pGrid.SelectedGridItem; + _propertyGridContextMenuReset.Enabled = Convert.ToBoolean( + _pGrid.SelectedObject != null && + gridItem?.PropertyDescriptor != null && + gridItem.PropertyDescriptor + .CanResetValue(_pGrid + .SelectedObject)); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + "UI.Window.Config.propertyGridContextMenu_Opening() failed.", + ex); + } } + + private void propertyGridContextMenuReset_Click(object sender, EventArgs e) + { + try + { + var gridItem = _pGrid.SelectedGridItem; + if (_pGrid.SelectedObject != null && gridItem?.PropertyDescriptor != null && + gridItem.PropertyDescriptor.CanResetValue(_pGrid.SelectedObject)) + { + _pGrid.ResetSelectedProperty(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + "UI.Window.Config.propertyGridContextMenuReset_Click() failed.", + ex); + } + } + + private void propertyGridContextMenuShowHelpText_Click(object sender, EventArgs e) + { + _propertyGridContextMenuShowHelpText.Checked = !_propertyGridContextMenuShowHelpText.Checked; + } + + private void propertyGridContextMenuShowHelpText_CheckedChanged(object sender, EventArgs e) + { + Settings.Default.ShowConfigHelpText = _propertyGridContextMenuShowHelpText.Checked; + _pGrid.HelpVisible = _propertyGridContextMenuShowHelpText.Checked; + } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 5598c07f6..76595a9dd 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -13,49 +13,50 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.UI.Window { public partial class ConnectionTreeWindow - { + { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - private ThemeManager _themeManager; + private ThemeManager _themeManager; - public ConnectionInfo SelectedNode => olvConnections.SelectedNode; + public ConnectionInfo SelectedNode => olvConnections.SelectedNode; - public ConnectionTree ConnectionTree - { - get { return olvConnections; } + public ConnectionTree ConnectionTree + { + get { return olvConnections; } set { olvConnections = value; } - } - - public ConnectionTreeWindow() : this(new DockContent()) - { - } - - public ConnectionTreeWindow(DockContent panel) - { - WindowType = WindowType.Tree; - DockPnl = panel; - InitializeComponent(); - SetMenuEventHandlers(); - SetConnectionTreeEventHandlers(); - Settings.Default.PropertyChanged += OnAppSettingsChanged; - ApplyLanguage(); } - private void OnAppSettingsChanged(object o, PropertyChangedEventArgs propertyChangedEventArgs) - { - if (propertyChangedEventArgs.PropertyName == nameof(Settings.UseFilterSearch)) - { - ConnectionTree.UseFiltering = Settings.Default.UseFilterSearch; - ApplyFiltering(); + public ConnectionTreeWindow() : this(new DockContent()) + { + } + + public ConnectionTreeWindow(DockContent panel) + { + WindowType = WindowType.Tree; + DockPnl = panel; + InitializeComponent(); + SetMenuEventHandlers(); + SetConnectionTreeEventHandlers(); + Settings.Default.PropertyChanged += OnAppSettingsChanged; + ApplyLanguage(); + } + + private void OnAppSettingsChanged(object o, PropertyChangedEventArgs propertyChangedEventArgs) + { + if (propertyChangedEventArgs.PropertyName == nameof(Settings.UseFilterSearch)) + { + ConnectionTree.UseFiltering = Settings.Default.UseFilterSearch; + ApplyFiltering(); } PlaceSearchBar(Settings.Default.PlaceSearchBarAboveConnectionTree); - SetConnectionTreeClickHandlers(); - } + SetConnectionTreeClickHandlers(); + } private void PlaceSearchBar(bool placeSearchBarAboveConnectionTree) { @@ -63,7 +64,8 @@ namespace mRemoteNG.UI.Window } - #region Form Stuff + #region Form Stuff + private void Tree_Load(object sender, EventArgs e) { //work on the theme change @@ -95,83 +97,100 @@ namespace mRemoteNG.UI.Window { if (!_themeManager.ThemingActive) return; vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(olvConnections.ContextMenuStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(olvConnections.ContextMenuStrip, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); if (!_themeManager.ActiveAndExtended) return; //Treelistview need to be manually themed olvConnections.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Background"); olvConnections.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Foreground"); - olvConnections.SelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Background"); - olvConnections.SelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Foreground"); - olvConnections.UnfocusedSelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Background"); - olvConnections.UnfocusedSelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Foreground"); + olvConnections.SelectedBackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Background"); + olvConnections.SelectedForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Foreground"); + olvConnections.UnfocusedSelectedBackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Background"); + olvConnections.UnfocusedSelectedForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Foreground"); //There is a border around txtSearch that dont theme well txtSearch.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); txtSearch.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } + #endregion #region ConnectionTree - private void SetConnectionTreeEventHandlers() - { - olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(prompt => - CTaskDialog.MessageBox(Application.ProductName, prompt, "", ETaskDialogButtons.YesNo, ESysIcons.Question)); + + private void SetConnectionTreeEventHandlers() + { + olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(prompt => + CTaskDialog + .MessageBox(Application.ProductName, + prompt, + "", + ETaskDialogButtons + .YesNo, + ESysIcons + .Question)); olvConnections.KeyDown += tvConnections_KeyDown; olvConnections.KeyPress += tvConnections_KeyPress; SetTreePostSetupActions(); SetConnectionTreeClickHandlers(); - Runtime.ConnectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded; + Runtime.ConnectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded; } - private void SetTreePostSetupActions() - { - var actions = new List - { - new PreviouslyOpenedFolderExpander(), - new RootNodeExpander() - }; + private void SetTreePostSetupActions() + { + var actions = new List + { + new PreviouslyOpenedFolderExpander(), + new RootNodeExpander() + }; - if (Settings.Default.OpenConsFromLastSession && !Settings.Default.NoReconnect) + if (Settings.Default.OpenConsFromLastSession && !Settings.Default.NoReconnect) actions.Add(new PreviousSessionOpener(_connectionInitiator)); - olvConnections.PostSetupActions = actions; - } - - private void SetConnectionTreeClickHandlers() - { - var singleClickHandlers = new List>(); - var doubleClickHandlers = new List> - { - new ExpandNodeClickHandler(olvConnections) - }; - - if (Settings.Default.SingleClickOnConnectionOpensIt) - singleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); - else - doubleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); - - if (Settings.Default.SingleClickSwitchesToOpenConnection) - singleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); - - olvConnections.SingleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = singleClickHandlers }; - olvConnections.DoubleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = doubleClickHandlers }; + olvConnections.PostSetupActions = actions; } - private void ConnectionsServiceOnConnectionsLoaded(object o, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) - { - if (olvConnections.InvokeRequired) - { - olvConnections.Invoke(() => ConnectionsServiceOnConnectionsLoaded(o, connectionsLoadedEventArgs)); - return; - } + private void SetConnectionTreeClickHandlers() + { + var singleClickHandlers = new List>(); + var doubleClickHandlers = new List> + { + new ExpandNodeClickHandler(olvConnections) + }; + + if (Settings.Default.SingleClickOnConnectionOpensIt) + singleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); + else + doubleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); + + if (Settings.Default.SingleClickSwitchesToOpenConnection) + singleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); + + olvConnections.SingleClickHandler = new TreeNodeCompositeClickHandler {ClickHandlers = singleClickHandlers}; + olvConnections.DoubleClickHandler = new TreeNodeCompositeClickHandler {ClickHandlers = doubleClickHandlers}; + } + + private void ConnectionsServiceOnConnectionsLoaded(object o, + ConnectionsLoadedEventArgs connectionsLoadedEventArgs) + { + if (olvConnections.InvokeRequired) + { + olvConnections.Invoke(() => ConnectionsServiceOnConnectionsLoaded(o, connectionsLoadedEventArgs)); + return; + } + + olvConnections.ConnectionTreeModel = connectionsLoadedEventArgs.NewConnectionTreeModel; + olvConnections.SelectedObject = connectionsLoadedEventArgs.NewConnectionTreeModel.RootNodes + .OfType().FirstOrDefault(); + } - olvConnections.ConnectionTreeModel = connectionsLoadedEventArgs.NewConnectionTreeModel; - olvConnections.SelectedObject = connectionsLoadedEventArgs.NewConnectionTreeModel.RootNodes - .OfType().FirstOrDefault(); - } #endregion #region Top Menu + private void SetMenuEventHandlers() { mMenViewExpandAllFolders.Click += (sender, args) => olvConnections.ExpandAll(); @@ -180,38 +199,43 @@ namespace mRemoteNG.UI.Window olvConnections.CollapseAll(); olvConnections.Expand(olvConnections.GetRootConnectionNode()); }; - mMenSortAscending.Click += (sender, args) => olvConnections.SortRecursive(olvConnections.GetRootConnectionNode(), ListSortDirection.Ascending); + mMenSortAscending.Click += (sender, args) => + olvConnections.SortRecursive(olvConnections.GetRootConnectionNode(), ListSortDirection.Ascending); } + #endregion #region Tree Context Menu + private void cMenTreeAddConnection_Click(object sender, EventArgs e) - { - olvConnections.AddConnection(); - } + { + olvConnections.AddConnection(); + } private void cMenTreeAddFolder_Click(object sender, EventArgs e) - { + { olvConnections.AddFolder(); - } + } + #endregion #region Search + private void txtSearch_GotFocus(object sender, EventArgs e) - { - if (txtSearch.Text == Language.strSearchPrompt) - txtSearch.Text = ""; - } + { + if (txtSearch.Text == Language.strSearchPrompt) + txtSearch.Text = ""; + } private void txtSearch_LostFocus(object sender, EventArgs e) - { + { if (txtSearch.Text != "") return; txtSearch.Text = Language.strSearchPrompt; - } + } private void txtSearch_KeyDown(object sender, KeyEventArgs e) - { - try + { + try { switch (e.KeyCode) { @@ -238,94 +262,103 @@ namespace mRemoteNG.UI.Window break; } } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("txtSearch_KeyDown (UI.Window.ConnectionTreeWindow) failed", ex); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace( + "txtSearch_KeyDown (UI.Window.ConnectionTreeWindow) failed", + ex); + } + } private void txtSearch_TextChanged(object sender, EventArgs e) { ApplyFiltering(); } - private void ApplyFiltering() - { - if (Settings.Default.UseFilterSearch) - { - if (txtSearch.Text == "" || txtSearch.Text == Language.strSearchPrompt) - { - olvConnections.RemoveFilter(); - return; - } - olvConnections.ApplyFilter(txtSearch.Text); - } - else - { - if (txtSearch.Text == "") return; - olvConnections.NodeSearcher?.SearchByName(txtSearch.Text); - JumpToNode(olvConnections.NodeSearcher?.CurrentMatch); - } + private void ApplyFiltering() + { + if (Settings.Default.UseFilterSearch) + { + if (txtSearch.Text == "" || txtSearch.Text == Language.strSearchPrompt) + { + olvConnections.RemoveFilter(); + return; + } + + olvConnections.ApplyFilter(txtSearch.Text); + } + else + { + if (txtSearch.Text == "") return; + olvConnections.NodeSearcher?.SearchByName(txtSearch.Text); + JumpToNode(olvConnections.NodeSearcher?.CurrentMatch); + } } - public void JumpToNode(ConnectionInfo connectionInfo) - { - if (connectionInfo == null) - { - olvConnections.SelectedObject = null; + public void JumpToNode(ConnectionInfo connectionInfo) + { + if (connectionInfo == null) + { + olvConnections.SelectedObject = null; return; - } - ExpandParentsRecursive(connectionInfo); + } + + ExpandParentsRecursive(connectionInfo); olvConnections.SelectObject(connectionInfo); olvConnections.EnsureModelVisible(connectionInfo); } - private void ExpandParentsRecursive(ConnectionInfo connectionInfo) - { - while (true) - { - if (connectionInfo?.Parent == null) return; - olvConnections.Expand(connectionInfo.Parent); - connectionInfo = connectionInfo.Parent; - } - } + private void ExpandParentsRecursive(ConnectionInfo connectionInfo) + { + while (true) + { + if (connectionInfo?.Parent == null) return; + olvConnections.Expand(connectionInfo.Parent); + connectionInfo = connectionInfo.Parent; + } + } - private void tvConnections_KeyPress(object sender, KeyPressEventArgs e) - { - try - { - if (!char.IsLetterOrDigit(e.KeyChar)) return; - txtSearch.Text = e.KeyChar.ToString(); - txtSearch.Focus(); - txtSearch.SelectionStart = txtSearch.TextLength; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_KeyPress (UI.Window.ConnectionTreeWindow) failed", ex); - } - } + private void tvConnections_KeyPress(object sender, KeyPressEventArgs e) + { + try + { + if (!char.IsLetterOrDigit(e.KeyChar)) return; + txtSearch.Text = e.KeyChar.ToString(); + txtSearch.Focus(); + txtSearch.SelectionStart = txtSearch.TextLength; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace( + "tvConnections_KeyPress (UI.Window.ConnectionTreeWindow) failed", + ex); + } + } private void tvConnections_KeyDown(object sender, KeyEventArgs e) - { - try - { - if (e.KeyCode == Keys.Enter) - { - e.Handled = true; + { + try + { + if (e.KeyCode == Keys.Enter) + { + e.Handled = true; _connectionInitiator.OpenConnection(SelectedNode); - } - else if (e.Control && e.KeyCode == Keys.F) - { - txtSearch.Focus(); + } + else if (e.Control && e.KeyCode == Keys.F) + { + txtSearch.Focus(); txtSearch.SelectAll(); - e.Handled = true; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_KeyDown (UI.Window.ConnectionTreeWindow) failed", ex); - } - } + e.Handled = true; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace( + "tvConnections_KeyDown (UI.Window.ConnectionTreeWindow) failed", + ex); + } + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 1a19f6aa4..c0d91e8c9 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -21,13 +21,14 @@ using mRemoteNG.UI.Tabs; namespace mRemoteNG.UI.Window { - public partial class ConnectionWindow : BaseWindow + public partial class ConnectionWindow : BaseWindow { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private VisualStudioToolStripExtender vsToolStripExtender; private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); #region Public Methods + public ConnectionWindow(DockContent panel, string formText = "") { if (formText == "") @@ -79,7 +80,8 @@ namespace mRemoteNG.UI.Window cmenTabStartChat.Click += (sender, args) => StartChat(); cmenTabTransferFile.Click += (sender, args) => TransferFile(); cmenTabRefreshScreen.Click += (sender, args) => RefreshScreen(); - cmenTabSendSpecialKeysCtrlAltDel.Click += (sender, args) => SendSpecialKeys(ProtocolVNC.SpecialKeys.CtrlAltDel); + cmenTabSendSpecialKeysCtrlAltDel.Click += + (sender, args) => SendSpecialKeys(ProtocolVNC.SpecialKeys.CtrlAltDel); cmenTabSendSpecialKeysCtrlEsc.Click += (sender, args) => SendSpecialKeys(ProtocolVNC.SpecialKeys.CtrlEsc); cmenTabRenameTab.Click += (sender, args) => RenameTab(); cmenTabDuplicateTab.Click += (sender, args) => DuplicateTab(); @@ -136,23 +138,25 @@ namespace mRemoteNG.UI.Window TabPageContextMenuStrip = cmenTab }; - //if (Settings.Default.AlwaysShowConnectionTabs == false) - // TODO: See if we can make this work with DPS... - //TabController.HideTabsMode = TabControl.HideTabsModes.HideAlways; + //if (Settings.Default.AlwaysShowConnectionTabs == false) + // TODO: See if we can make this work with DPS... + //TabController.HideTabsMode = TabControl.HideTabsModes.HideAlways; //Show the tab - conTab.Show(connDock,DockState.Document); + conTab.Show(connDock, DockState.Document); conTab.Focus(); return conTab; } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("AddConnectionTab (UI.Window.ConnectionWindow) failed", ex); + Runtime.MessageCollector.AddExceptionMessage("AddConnectionTab (UI.Window.ConnectionWindow) failed", + ex); } return null; } + #endregion public void reconnectAll(IConnectionInitiator initiator) @@ -171,9 +175,8 @@ namespace mRemoteNG.UI.Window iControl.Protocol.Close(); initiator.OpenConnection(iControl.Info, ConnectionInfo.Force.DoNotJump); } - } - catch(Exception ex) + catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("reconnectAll (UI.Window.ConnectionWindow) failed", ex); } @@ -183,6 +186,7 @@ namespace mRemoteNG.UI.Window } #region Form + private void Connection_Load(object sender, EventArgs e) { ApplyTheme(); @@ -197,6 +201,7 @@ namespace mRemoteNG.UI.Window connDock.Theme = ThemeManager.getInstance().DefaultTheme.Theme; return; } + base.ApplyTheme(); try { @@ -211,14 +216,17 @@ namespace mRemoteNG.UI.Window { DefaultRenderer = _toolStripProfessionalRenderer }; - vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, + ThemeManager.getInstance().ActiveTheme.Theme); if (!ThemeManager.getInstance().ActiveAndExtended) return; - connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); + connDock.DockBackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } private bool _documentHandlersAdded; private bool _floatHandlersAdded; + private void Connection_DockStateChanged(object sender, EventArgs e) { switch (DockState) @@ -231,6 +239,7 @@ namespace mRemoteNG.UI.Window FrmMain.Default.ResizeEnd -= Connection_ResizeEnd; _documentHandlersAdded = false; } + DockHandler.FloatPane.FloatWindow.ResizeBegin += Connection_ResizeBegin; DockHandler.FloatPane.FloatWindow.ResizeEnd += Connection_ResizeEnd; _floatHandlersAdded = true; @@ -244,6 +253,7 @@ namespace mRemoteNG.UI.Window DockHandler.FloatPane.FloatWindow.ResizeEnd -= Connection_ResizeEnd; _floatHandlersAdded = false; } + FrmMain.Default.ResizeBegin += Connection_ResizeBegin; FrmMain.Default.ResizeEnd += Connection_ResizeEnd; _documentHandlersAdded = true; @@ -276,15 +286,23 @@ namespace mRemoteNG.UI.Window private void Connection_FormClosing(object sender, FormClosingEventArgs e) { - if (!FrmMain.Default.IsClosing && + if (!FrmMain.Default.IsClosing && (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & connDock.Documents.Any() || - Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & connDock.Documents.Count() > 1)) + Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & + connDock.Documents.Count() > 1)) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, Text), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, + string + .Format(Language.strConfirmCloseConnectionPanelMainInstruction, + Text), "", "", "", + Language.strCheckboxDoNotShowThisMessageAgain, + ETaskDialogButtons.YesNo, ESysIcons.Question, + ESysIcons.Question); if (CTaskDialog.VerificationChecked) { Settings.Default.ConfirmCloseConnection--; } + if (result == DialogResult.No) { e.Cancel = true; @@ -296,7 +314,7 @@ namespace mRemoteNG.UI.Window { foreach (var dockContent in connDock.Documents.ToArray()) { - var tabP = (ConnectionTab) dockContent; + var tabP = (ConnectionTab)dockContent; if (tabP.Tag == null) continue; tabP.silentClose = true; tabP.Close(); @@ -304,33 +322,40 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.Connection_FormClosing() failed", ex); + Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.Connection_FormClosing() failed", + ex); } } public new event EventHandler ResizeBegin; + private void Connection_ResizeBegin(object sender, EventArgs e) { ResizeBegin?.Invoke(this, e); } public new event EventHandler ResizeEnd; + private void Connection_ResizeEnd(object sender, EventArgs e) { ResizeEnd?.Invoke(sender, e); } + #endregion #region Events + private void ConnDockOnActiveContentChanged(object sender, EventArgs e) { var ic = GetInterfaceControl(); if (ic?.Info == null) return; FrmMain.Default.SelectedConnection = ic.Info; } + #endregion #region Tab Menu + private void ShowHideMenuButtons(object sender, CancelEventArgs e) { try @@ -373,7 +398,8 @@ namespace mRemoteNG.UI.Window cmenTabTransferFile.Visible = false; } - if (interfaceControl.Info.Protocol == ProtocolType.SSH1 | interfaceControl.Info.Protocol == ProtocolType.SSH2) + if (interfaceControl.Info.Protocol == ProtocolType.SSH1 | + interfaceControl.Info.Protocol == ProtocolType.SSH2) { cmenTabTransferFile.Visible = true; } @@ -384,12 +410,15 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("ShowHideMenuButtons (UI.Window.ConnectionWindow) failed", ex); + Runtime.MessageCollector.AddExceptionMessage("ShowHideMenuButtons (UI.Window.ConnectionWindow) failed", + ex); } } + #endregion #region Tab Actions + private void ToggleSmartSize() { try @@ -419,7 +448,8 @@ namespace mRemoteNG.UI.Window var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; - if (interfaceControl.Info.Protocol == ProtocolType.SSH1 | interfaceControl.Info.Protocol == ProtocolType.SSH2) + if (interfaceControl.Info.Protocol == ProtocolType.SSH1 | + interfaceControl.Info.Protocol == ProtocolType.SSH2) SshTransferFile(); else if (interfaceControl.Info.Protocol == ProtocolType.VNC) VncTransferFile(); @@ -532,7 +562,8 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("ToggleFullscreen (UI.Window.ConnectionWindow) failed", ex); + Runtime.MessageCollector.AddExceptionMessage("ToggleFullscreen (UI.Window.ConnectionWindow) failed", + ex); } } @@ -546,7 +577,9 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed", ex); + Runtime.MessageCollector.AddExceptionMessage( + "ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed", + ex); } } @@ -581,7 +614,9 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("cMenTreeTools_DropDownOpening failed (UI.Window.ConnectionWindow)", ex); + Runtime.MessageCollector.AddExceptionStackTrace( + "cMenTreeTools_DropDownOpening failed (UI.Window.ConnectionWindow)", + ex); } } @@ -594,7 +629,9 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)", ex); + Runtime.MessageCollector.AddExceptionMessage( + "cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)", + ex); } } @@ -620,11 +657,17 @@ namespace mRemoteNG.UI.Window if (selectedTab == null) return; if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionOthersInstruction, selectedTab.TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, + string.Format(Language.strConfirmCloseConnectionOthersInstruction, + selectedTab.TabText), "", "", "", + Language.strCheckboxDoNotShowThisMessageAgain, + ETaskDialogButtons.YesNo, ESysIcons.Question, + ESysIcons.Question); if (CTaskDialog.VerificationChecked) { Settings.Default.ConfirmCloseConnection--; } + if (result == DialogResult.No) { return; @@ -633,7 +676,7 @@ namespace mRemoteNG.UI.Window foreach (var dockContent in connDock.DocumentsToArray()) { - var tab = (ConnectionTab) dockContent; + var tab = (ConnectionTab)dockContent; if (selectedTab != tab) { tab.Close(); @@ -643,24 +686,24 @@ namespace mRemoteNG.UI.Window private void CloseOtherTabsToTheRight() { - try { var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; if (selectedTab == null) return; var dockPane = selectedTab.Pane; - var pastTabToKeepAlive= false; + var pastTabToKeepAlive = false; var connectionsToClose = new List(); - foreach (var dockContent in dockPane.Contents ) + foreach (var dockContent in dockPane.Contents) { - var tab = (ConnectionTab) dockContent; + var tab = (ConnectionTab)dockContent; if (pastTabToKeepAlive) connectionsToClose.Add(tab); if (selectedTab == tab) pastTabToKeepAlive = true; } + foreach (var tab in connectionsToClose) { tab.Close(); @@ -670,7 +713,7 @@ namespace mRemoteNG.UI.Window { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); } - } + } private void DuplicateTab() { @@ -693,9 +736,11 @@ namespace mRemoteNG.UI.Window var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Reconnect (UI.Window.ConnectionWindow) failed. Could not find InterfaceControl."); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "Reconnect (UI.Window.ConnectionWindow) failed. Could not find InterfaceControl."); return; } + Invoke(new Action(() => Prot_Event_Closed(interfaceControl.Protocol))); _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); } @@ -711,11 +756,12 @@ namespace mRemoteNG.UI.Window { var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; - using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ((ConnectionTab)interfaceControl.Parent).TabText)) + using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, + ((ConnectionTab)interfaceControl.Parent).TabText)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK) return; - if(!string.IsNullOrEmpty(frmInputBox.returnValue)) + if (!string.IsNullOrEmpty(frmInputBox.returnValue)) ((ConnectionTab)interfaceControl.Parent).TabText = frmInputBox.returnValue.Replace("&", "&&"); } } @@ -733,9 +779,11 @@ namespace mRemoteNG.UI.Window if (TabHelper.Instance.CurrentTab == null) return; Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(TabHelper.Instance.CurrentTab)); } + #endregion #region Protocols + public void Prot_Event_Closed(object sender) { var protocolBase = sender as ProtocolBase; @@ -743,8 +791,8 @@ namespace mRemoteNG.UI.Window if (tabPage.Disposing) return; tabPage.protocolClose = true; Invoke(new Action(() => tabPage.Close())); - } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs index 90e317c20..0e7ec2160 100644 --- a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs +++ b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs @@ -13,17 +13,17 @@ using Message = mRemoteNG.Messages.Message; namespace mRemoteNG.UI.Window { - public partial class ErrorAndInfoWindow : BaseWindow - { + public partial class ErrorAndInfoWindow : BaseWindow + { private ControlLayout _layout = ControlLayout.Vertical; private readonly ThemeManager _themeManager; - private readonly DisplayProperties _display; + private readonly DisplayProperties _display; public DockContent PreviousActiveForm { get; set; } - public ErrorAndInfoWindow() : this(new DockContent()) - { - } + public ErrorAndInfoWindow() : this(new DockContent()) + { + } public ErrorAndInfoWindow(DockContent panel) { @@ -41,22 +41,25 @@ namespace mRemoteNG.UI.Window } #region Form Stuff - private void ErrorsAndInfos_Load(object sender, EventArgs e) - { - } - private void ApplyLanguage() - { - clmMessage.Text = Language.strColumnMessage; - cMenMCCopy.Text = Language.strMenuNotificationsCopyAll; - cMenMCDelete.Text = Language.strMenuNotificationsDeleteAll; - TabText = Language.strMenuNotifications; - Text = Language.strMenuNotifications; - } + private void ErrorsAndInfos_Load(object sender, EventArgs e) + { + } + + private void ApplyLanguage() + { + clmMessage.Text = Language.strColumnMessage; + cMenMCCopy.Text = Language.strMenuNotificationsCopyAll; + cMenMCDelete.Text = Language.strMenuNotificationsDeleteAll; + TabText = Language.strMenuNotifications; + Text = Language.strMenuNotifications; + } + #endregion #region Private Methods - private new void ApplyTheme() + + private new void ApplyTheme() { if (!_themeManager.ActiveAndExtended) return; lvErrorCollector.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); @@ -74,297 +77,335 @@ namespace mRemoteNG.UI.Window { imgListMC.ImageSize = _display.ScaleSize(imgListMC.ImageSize); imgListMC.Images.Add(_display.ScaleImage(Resources.brick)); - imgListMC.Images.Add(_display.ScaleImage(Resources.InformationSmall)); - imgListMC.Images.Add(_display.ScaleImage(Resources.WarningSmall)); - imgListMC.Images.Add(_display.ScaleImage(Resources.ErrorSmall)); - } + imgListMC.Images.Add(_display.ScaleImage(Resources.InformationSmall)); + imgListMC.Images.Add(_display.ScaleImage(Resources.WarningSmall)); + imgListMC.Images.Add(_display.ScaleImage(Resources.ErrorSmall)); + } - private void LayoutVertical() - { - try - { - pnlErrorMsg.Location = new Point(0, Height - _display.ScaleHeight(200)); - pnlErrorMsg.Size = new Size(Width, Height - pnlErrorMsg.Top); - pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - txtMsgText.Size = new Size( - pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), - pnlErrorMsg.Height - _display.ScaleHeight(20)); - lvErrorCollector.Location = new Point(0, 0); - lvErrorCollector.Size = new Size(Width, Height - pnlErrorMsg.Height - _display.ScaleHeight(5)); - lvErrorCollector.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; + private void LayoutVertical() + { + try + { + pnlErrorMsg.Location = new Point(0, Height - _display.ScaleHeight(200)); + pnlErrorMsg.Size = new Size(Width, Height - pnlErrorMsg.Top); + pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + txtMsgText.Size = new Size( + pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), + pnlErrorMsg.Height - _display.ScaleHeight(20)); + lvErrorCollector.Location = new Point(0, 0); + lvErrorCollector.Size = new Size(Width, Height - pnlErrorMsg.Height - _display.ScaleHeight(5)); + lvErrorCollector.Anchor = + AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; - _layout = ControlLayout.Vertical; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "LayoutVertical (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + _layout = ControlLayout.Vertical; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "LayoutVertical (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + ex.Message, true); + } + } - private void LayoutHorizontal() - { - try - { - pnlErrorMsg.Location = new Point(0, 0); - pnlErrorMsg.Size = new Size(_display.ScaleWidth(200), Height); - pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top; + private void LayoutHorizontal() + { + try + { + pnlErrorMsg.Location = new Point(0, 0); + pnlErrorMsg.Size = new Size(_display.ScaleWidth(200), Height); + pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top; txtMsgText.Size = new Size( - pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), - pnlErrorMsg.Height - _display.ScaleHeight(20)); - lvErrorCollector.Location = new Point(pnlErrorMsg.Width + _display.ScaleWidth(5), 0); - lvErrorCollector.Size = new Size(Width - pnlErrorMsg.Width - _display.ScaleWidth(5), Height); - lvErrorCollector.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; + pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), + pnlErrorMsg.Height - _display.ScaleHeight(20)); + lvErrorCollector.Location = new Point(pnlErrorMsg.Width + _display.ScaleWidth(5), 0); + lvErrorCollector.Size = new Size(Width - pnlErrorMsg.Width - _display.ScaleWidth(5), Height); + lvErrorCollector.Anchor = + AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; - _layout = ControlLayout.Horizontal; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "LayoutHorizontal (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + _layout = ControlLayout.Horizontal; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "LayoutHorizontal (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + ex.Message, true); + } + } - private void ErrorsAndInfos_Resize(object sender, EventArgs e) - { - try - { - if (Width > Height) - { - if (_layout == ControlLayout.Vertical) - LayoutHorizontal(); - } - else - { - if (_layout == ControlLayout.Horizontal) - LayoutVertical(); - } + private void ErrorsAndInfos_Resize(object sender, EventArgs e) + { + try + { + if (Width > Height) + { + if (_layout == ControlLayout.Vertical) + LayoutHorizontal(); + } + else + { + if (_layout == ControlLayout.Horizontal) + LayoutVertical(); + } - lvErrorCollector.Columns[0].Width = lvErrorCollector.Width - 20; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ErrorsAndInfos_Resize (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + lvErrorCollector.Columns[0].Width = lvErrorCollector.Width - 20; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "ErrorsAndInfos_Resize (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + ex.Message, true); + } + } - private void SetStyleWhenNoMessageSelected() - { - try - { - pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + private void SetStyleWhenNoMessageSelected() + { + try + { + pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); pbError.Image = null; - txtMsgText.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + txtMsgText.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); txtMsgText.Text = ""; lblMsgDate.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); lblMsgDate.Text = ""; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "pnlErrorMsg_ResetDefaultStyle (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "pnlErrorMsg_ResetDefaultStyle (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + + ex.Message, true); + } + } - private void MC_KeyDown(object sender, KeyEventArgs e) - { - try - { - if (e.KeyCode != Keys.Escape) return; - try - { - if (PreviousActiveForm != null) - PreviousActiveForm.Show(FrmMain.Default.pnlDock); - else - Windows.TreeForm.Show(FrmMain.Default.pnlDock); - } - catch (Exception) - { - // ignored - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "MC_KeyDown (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + private void MC_KeyDown(object sender, KeyEventArgs e) + { + try + { + if (e.KeyCode != Keys.Escape) return; + try + { + if (PreviousActiveForm != null) + PreviousActiveForm.Show(FrmMain.Default.pnlDock); + else + Windows.TreeForm.Show(FrmMain.Default.pnlDock); + } + catch (Exception) + { + // ignored + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "MC_KeyDown (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + ex.Message, true); + } + } - private void lvErrorCollector_SelectedIndexChanged(object sender, EventArgs e) - { - try - { - if (lvErrorCollector.SelectedItems.Count == 0 | lvErrorCollector.SelectedItems.Count > 1) - { - SetStyleWhenNoMessageSelected(); - return; - } + private void lvErrorCollector_SelectedIndexChanged(object sender, EventArgs e) + { + try + { + if (lvErrorCollector.SelectedItems.Count == 0 | lvErrorCollector.SelectedItems.Count > 1) + { + SetStyleWhenNoMessageSelected(); + return; + } - var sItem = lvErrorCollector.SelectedItems[0]; + var sItem = lvErrorCollector.SelectedItems[0]; var eMsg = (Message)sItem.Tag; - switch (eMsg.Class) - { + switch (eMsg.Class) + { case MessageClass.DebugMsg: - pbError.Image = _display.ScaleImage(Resources.brick); - if(_themeManager.ThemingActive) + pbError.Image = _display.ScaleImage(Resources.brick); + if (_themeManager.ThemingActive) { pnlErrorMsg.BackColor = Color.LightSteelBlue; txtMsgText.BackColor = Color.LightSteelBlue; lblMsgDate.BackColor = Color.LightSteelBlue; } + break; - case MessageClass.InformationMsg: - pbError.Image = _display.ScaleImage(Resources.Information); + case MessageClass.InformationMsg: + pbError.Image = _display.ScaleImage(Resources.Information); if (_themeManager.ThemingActive) { pnlErrorMsg.BackColor = Color.LightSteelBlue; - txtMsgText.BackColor = Color.LightSteelBlue; + txtMsgText.BackColor = Color.LightSteelBlue; lblMsgDate.BackColor = Color.LightSteelBlue; } + break; - case MessageClass.WarningMsg: - pbError.Image = _display.ScaleImage(Resources.Warning); + case MessageClass.WarningMsg: + pbError.Image = _display.ScaleImage(Resources.Warning); if (_themeManager.ActiveAndExtended) { //Inverse colors for dramatic effect - pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); - pnlErrorMsg.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor ("WarningText_Background"); - txtMsgText.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); - txtMsgText.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Background"); - lblMsgDate.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); - lblMsgDate.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Background"); + pnlErrorMsg.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); + pnlErrorMsg.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Background"); + txtMsgText.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); + txtMsgText.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Background"); + lblMsgDate.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); + lblMsgDate.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Background"); } + break; - case MessageClass.ErrorMsg: - pbError.Image = _display.ScaleImage(Resources._Error); + case MessageClass.ErrorMsg: + pbError.Image = _display.ScaleImage(Resources._Error); if (_themeManager.ActiveAndExtended) { - pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); - pnlErrorMsg.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); - txtMsgText.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); - txtMsgText.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); - lblMsgDate.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); - lblMsgDate.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); + pnlErrorMsg.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); + pnlErrorMsg.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); + txtMsgText.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); + txtMsgText.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); + lblMsgDate.BackColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); + lblMsgDate.ForeColor = + _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); } + break; - } + } - lblMsgDate.Text = eMsg.Date.ToString(CultureInfo.InvariantCulture); - txtMsgText.Text = eMsg.Text; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "lvErrorCollector_SelectedIndexChanged (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); - } - } + lblMsgDate.Text = eMsg.Date.ToString(CultureInfo.InvariantCulture); + txtMsgText.Text = eMsg.Text; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "lvErrorCollector_SelectedIndexChanged (UI.Window.ErrorsAndInfos) failed" + + Environment.NewLine + + ex.Message, true); + } + } - private void cMenMC_Opening(object sender, System.ComponentModel.CancelEventArgs e) - { - if (lvErrorCollector.Items.Count > 0) - { - cMenMCCopy.Enabled = true; - cMenMCDelete.Enabled = true; - } - else - { - cMenMCCopy.Enabled = false; - cMenMCDelete.Enabled = false; - } + private void cMenMC_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + if (lvErrorCollector.Items.Count > 0) + { + cMenMCCopy.Enabled = true; + cMenMCDelete.Enabled = true; + } + else + { + cMenMCCopy.Enabled = false; + cMenMCDelete.Enabled = false; + } - if (lvErrorCollector.SelectedItems.Count > 0) - { - cMenMCCopy.Text = Language.strMenuCopy; - cMenMCDelete.Text = Language.strMenuNotificationsDelete; - } - else - { - cMenMCCopy.Text = Language.strMenuNotificationsCopyAll; - cMenMCDelete.Text = Language.strMenuNotificationsDeleteAll; - } - } + if (lvErrorCollector.SelectedItems.Count > 0) + { + cMenMCCopy.Text = Language.strMenuCopy; + cMenMCDelete.Text = Language.strMenuNotificationsDelete; + } + else + { + cMenMCCopy.Text = Language.strMenuNotificationsCopyAll; + cMenMCDelete.Text = Language.strMenuNotificationsDeleteAll; + } + } - private void cMenMCCopy_Click(object sender, EventArgs e) - { - CopyMessagesToClipboard(); - } + private void cMenMCCopy_Click(object sender, EventArgs e) + { + CopyMessagesToClipboard(); + } - private void CopyMessagesToClipboard() - { - try - { - IEnumerable items; - if (lvErrorCollector.SelectedItems.Count > 0) - { - items = lvErrorCollector.SelectedItems; - } - else - { - items = lvErrorCollector.Items; - } + private void CopyMessagesToClipboard() + { + try + { + IEnumerable items; + if (lvErrorCollector.SelectedItems.Count > 0) + { + items = lvErrorCollector.SelectedItems; + } + else + { + items = lvErrorCollector.Items; + } - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("----------"); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("----------"); - lvErrorCollector.BeginUpdate(); + lvErrorCollector.BeginUpdate(); - foreach (ListViewItem item in items) - { + foreach (ListViewItem item in items) + { if (!(item.Tag is Message message)) - { - continue; - } + { + continue; + } - stringBuilder.AppendLine(message.Class.ToString()); - stringBuilder.AppendLine(message.Date.ToString(CultureInfo.InvariantCulture)); - stringBuilder.AppendLine(message.Text); - stringBuilder.AppendLine("----------"); - } + stringBuilder.AppendLine(message.Class.ToString()); + stringBuilder.AppendLine(message.Date.ToString(CultureInfo.InvariantCulture)); + stringBuilder.AppendLine(message.Text); + stringBuilder.AppendLine("----------"); + } - Clipboard.SetText(stringBuilder.ToString()); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "UI.Window.ErrorsAndInfos.CopyMessagesToClipboard() failed." + Environment.NewLine + ex.Message, true); - } - finally - { - lvErrorCollector.EndUpdate(); - } - } + Clipboard.SetText(stringBuilder.ToString()); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "UI.Window.ErrorsAndInfos.CopyMessagesToClipboard() failed." + + Environment.NewLine + ex.Message, + true); + } + finally + { + lvErrorCollector.EndUpdate(); + } + } - private void cMenMCDelete_Click(object sender, EventArgs e) - { - DeleteMessages(); - } + private void cMenMCDelete_Click(object sender, EventArgs e) + { + DeleteMessages(); + } - private void DeleteMessages() - { - try - { - lvErrorCollector.BeginUpdate(); + private void DeleteMessages() + { + try + { + lvErrorCollector.BeginUpdate(); + + if (lvErrorCollector.SelectedItems.Count > 0) + { + foreach (ListViewItem item in lvErrorCollector.SelectedItems) + item.Remove(); + } + else + { + lvErrorCollector.Items.Clear(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, + "UI.Window.ErrorsAndInfos.DeleteMessages() failed" + + Environment.NewLine + ex.Message, true); + } + finally + { + lvErrorCollector.EndUpdate(); + } + } - if (lvErrorCollector.SelectedItems.Count > 0) - { - foreach (ListViewItem item in lvErrorCollector.SelectedItems) - item.Remove(); - } - else - { - lvErrorCollector.Items.Clear(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "UI.Window.ErrorsAndInfos.DeleteMessages() failed" + Environment.NewLine + ex.Message, true); - } - finally - { - lvErrorCollector.EndUpdate(); - } - } #endregion - private enum ControlLayout - { - Vertical = 0, - Horizontal = 1 - } - } -} + private enum ControlLayout + { + Vertical = 0, + Horizontal = 1 + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ExternalToolsWindow.cs b/mRemoteV1/UI/Window/ExternalToolsWindow.cs index 07a1e176e..efd967571 100644 --- a/mRemoteV1/UI/Window/ExternalToolsWindow.cs +++ b/mRemoteV1/UI/Window/ExternalToolsWindow.cs @@ -12,47 +12,48 @@ using mRemoteNG.Tools.CustomCollections; namespace mRemoteNG.UI.Window { - public partial class ExternalToolsWindow - { + public partial class ExternalToolsWindow + { private readonly ExternalAppsSaver _externalAppsSaver; private readonly ThemeManager _themeManager; - private readonly FullyObservableCollection _currentlySelectedExternalTools; + private readonly FullyObservableCollection _currentlySelectedExternalTools; public ExternalToolsWindow() - { - InitializeComponent(); - WindowType = WindowType.ExternalApps; - DockPnl = new DockContent(); + { + InitializeComponent(); + WindowType = WindowType.ExternalApps; + DockPnl = new DockContent(); _themeManager = ThemeManager.getInstance(); _themeManager.ThemeChanged += ApplyTheme; _externalAppsSaver = new ExternalAppsSaver(); _currentlySelectedExternalTools = new FullyObservableCollection(); _currentlySelectedExternalTools.CollectionUpdated += CurrentlySelectedExternalToolsOnCollectionUpdated; - BrowseButton.Height = FilenameTextBox.Height; - BrowseWorkingDir.Height = WorkingDirTextBox.Height; - } + BrowseButton.Height = FilenameTextBox.Height; + BrowseWorkingDir.Height = WorkingDirTextBox.Height; + } - #region Private Methods - private void ExternalTools_Load(object sender, EventArgs e) - { - ApplyLanguage(); - ApplyTheme(); - UpdateToolsListObjView(); - } + #region Private Methods + + private void ExternalTools_Load(object sender, EventArgs e) + { + ApplyLanguage(); + ApplyTheme(); + UpdateToolsListObjView(); + } private void ApplyLanguage() - { - Text = Language.strMenuExternalTools; - TabText = Language.strMenuExternalTools; + { + Text = Language.strMenuExternalTools; + TabText = Language.strMenuExternalTools; - NewToolToolstripButton.Text = Language.strButtonNew; - DeleteToolToolstripButton.Text = Language.strOptionsThemeButtonDelete; - LaunchToolToolstripButton.Text = Language.strButtonLaunch; + NewToolToolstripButton.Text = Language.strButtonNew; + DeleteToolToolstripButton.Text = Language.strOptionsThemeButtonDelete; + LaunchToolToolstripButton.Text = Language.strButtonLaunch; - DisplayNameColumnHeader.Text = Language.strColumnDisplayName; - FilenameColumnHeader.Text = Language.strColumnFilename; - ArgumentsColumnHeader.Text = Language.strColumnArguments; + DisplayNameColumnHeader.Text = Language.strColumnDisplayName; + FilenameColumnHeader.Text = Language.strColumnFilename; + ArgumentsColumnHeader.Text = Language.strColumnArguments; WorkingDirColumnHeader.Text = Language.strWorkingDirColumnHeader; WaitForExitColumnHeader.Text = Language.strColumnWaitForExit; TryToIntegrateColumnHeader.Text = Language.strTryToIntegrateColumnHeader; @@ -60,71 +61,75 @@ namespace mRemoteNG.UI.Window ShowOnToolbarColumnHeader.Text = Language.strShowOnToolbarColumnHeader; TryToIntegrateCheckBox.Text = Language.strTryIntegrate; - ShowOnToolbarCheckBox.Text = Language.strShowOnToolbar; + ShowOnToolbarCheckBox.Text = Language.strShowOnToolbar; RunElevatedCheckBox.Text = Language.strRunElevated; PropertiesGroupBox.Text = Language.strGroupboxExternalToolProperties; - DisplayNameLabel.Text = Language.strLabelDisplayName; - FilenameLabel.Text = Language.strLabelFilename; - ArgumentsLabel.Text = Language.strLabelArguments; + DisplayNameLabel.Text = Language.strLabelDisplayName; + FilenameLabel.Text = Language.strLabelFilename; + ArgumentsLabel.Text = Language.strLabelArguments; WorkingDirLabel.Text = Language.srtWorkingDirectory; OptionsLabel.Text = Language.strLabelOptions; - WaitForExitCheckBox.Text = Language.strCheckboxWaitForExit; - BrowseButton.Text = Language.strButtonBrowse; + WaitForExitCheckBox.Text = Language.strCheckboxWaitForExit; + BrowseButton.Text = Language.strButtonBrowse; BrowseWorkingDir.Text = Language.strButtonBrowse; NewToolMenuItem.Text = Language.strMenuNewExternalTool; - DeleteToolMenuItem.Text = Language.strMenuDeleteExternalTool; - LaunchToolMenuItem.Text = Language.strMenuLaunchExternalTool; - } + DeleteToolMenuItem.Text = Language.strMenuDeleteExternalTool; + LaunchToolMenuItem.Text = Language.strMenuLaunchExternalTool; + } - private new void ApplyTheme() - { - if (!_themeManager.ThemingActive) return; - vsToolStripExtender.SetStyle(ToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(ToolsContextMenuStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - //Apply the extended palette + private new void ApplyTheme() + { + if (!_themeManager.ThemingActive) return; + vsToolStripExtender.SetStyle(ToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(ToolsContextMenuStrip, _themeManager.ActiveTheme.Version, + _themeManager.ActiveTheme.Theme); + //Apply the extended palette - ToolStripContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Background; - ToolStripContainer.TopToolStripPanel.ForeColor = _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Text; - PropertiesGroupBox.BackColor = _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Background; - PropertiesGroupBox.ForeColor = _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Text; - } + ToolStripContainer.TopToolStripPanel.BackColor = + _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Background; + ToolStripContainer.TopToolStripPanel.ForeColor = + _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Text; + PropertiesGroupBox.BackColor = + _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Background; + PropertiesGroupBox.ForeColor = _themeManager.ActiveTheme.Theme.ColorPalette.CommandBarMenuDefault.Text; + } - private void UpdateToolsListObjView() - { - try - { - ToolsListObjView.BeginUpdate(); - ToolsListObjView.SetObjects(Runtime.ExternalToolsService.ExternalTools, true); - ToolsListObjView.AutoResizeColumns(); - ToolsListObjView.EndUpdate(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.PopulateToolsListObjView()", ex); - } - } + private void UpdateToolsListObjView() + { + try + { + ToolsListObjView.BeginUpdate(); + ToolsListObjView.SetObjects(Runtime.ExternalToolsService.ExternalTools, true); + ToolsListObjView.AutoResizeColumns(); + ToolsListObjView.EndUpdate(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.PopulateToolsListObjView()", ex); + } + } - private void LaunchTool() - { - try - { - foreach (var externalTool in _currentlySelectedExternalTools) - { - externalTool.Start(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.LaunchTool() failed.", ex); - } - } + private void LaunchTool() + { + try + { + foreach (var externalTool in _currentlySelectedExternalTools) + { + externalTool.Start(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.LaunchTool() failed.", ex); + } + } - private void UpdateEditorControls() - { - var selectedTool = _currentlySelectedExternalTools.FirstOrDefault(); + private void UpdateEditorControls() + { + var selectedTool = _currentlySelectedExternalTools.FirstOrDefault(); DisplayNameTextBox.Text = selectedTool?.DisplayName; FilenameTextBox.Text = selectedTool?.FileName; @@ -134,122 +139,132 @@ namespace mRemoteNG.UI.Window TryToIntegrateCheckBox.Checked = selectedTool?.TryIntegrate ?? false; ShowOnToolbarCheckBox.Checked = selectedTool?.ShowOnToolbar ?? false; RunElevatedCheckBox.Checked = selectedTool?.RunElevated ?? false; - WaitForExitCheckBox.Enabled = !TryToIntegrateCheckBox.Checked; + WaitForExitCheckBox.Enabled = !TryToIntegrateCheckBox.Checked; } - private void UpdateToolstipControls() - { - _currentlySelectedExternalTools.Clear(); - _currentlySelectedExternalTools.AddRange(ToolsListObjView.SelectedObjects.OfType()); - PropertiesGroupBox.Enabled = _currentlySelectedExternalTools.Count == 1; + private void UpdateToolstipControls() + { + _currentlySelectedExternalTools.Clear(); + _currentlySelectedExternalTools.AddRange(ToolsListObjView.SelectedObjects.OfType()); + PropertiesGroupBox.Enabled = _currentlySelectedExternalTools.Count == 1; - var atleastOneToolSelected = _currentlySelectedExternalTools.Count > 0; - DeleteToolMenuItem.Enabled = atleastOneToolSelected; - DeleteToolToolstripButton.Enabled = atleastOneToolSelected; - LaunchToolMenuItem.Enabled = atleastOneToolSelected; - LaunchToolToolstripButton.Enabled = atleastOneToolSelected; + var atleastOneToolSelected = _currentlySelectedExternalTools.Count > 0; + DeleteToolMenuItem.Enabled = atleastOneToolSelected; + DeleteToolToolstripButton.Enabled = atleastOneToolSelected; + LaunchToolMenuItem.Enabled = atleastOneToolSelected; + LaunchToolToolstripButton.Enabled = atleastOneToolSelected; } - #endregion + + #endregion #region Event Handlers - private void CurrentlySelectedExternalToolsOnCollectionUpdated(object sender, CollectionUpdatedEventArgs collectionUpdatedEventArgs) - { - UpdateEditorControls(); - } + + private void CurrentlySelectedExternalToolsOnCollectionUpdated(object sender, + CollectionUpdatedEventArgs + collectionUpdatedEventArgs) + { + UpdateEditorControls(); + } private void ExternalTools_FormClosed(object sender, FormClosedEventArgs e) - { + { _externalAppsSaver.Save(Runtime.ExternalToolsService.ExternalTools); - _themeManager.ThemeChanged -= ApplyTheme; - _currentlySelectedExternalTools.CollectionUpdated -= CurrentlySelectedExternalToolsOnCollectionUpdated; + _themeManager.ThemeChanged -= ApplyTheme; + _currentlySelectedExternalTools.CollectionUpdated -= CurrentlySelectedExternalToolsOnCollectionUpdated; } private void NewTool_Click(object sender, EventArgs e) - { - try - { - var externalTool = new ExternalTool(Language.strExternalToolDefaultName); - Runtime.ExternalToolsService.ExternalTools.Add(externalTool); - UpdateToolsListObjView(); - ToolsListObjView.SelectedObject = externalTool; - DisplayNameTextBox.Focus(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.NewTool_Click() failed.", ex); - } - } + { + try + { + var externalTool = new ExternalTool(Language.strExternalToolDefaultName); + Runtime.ExternalToolsService.ExternalTools.Add(externalTool); + UpdateToolsListObjView(); + ToolsListObjView.SelectedObject = externalTool; + DisplayNameTextBox.Focus(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.NewTool_Click() failed.", ex); + } + } private void DeleteTool_Click(object sender, EventArgs e) - { - try - { - string message; - if (_currentlySelectedExternalTools.Count == 1) - message = string.Format(Language.strConfirmDeleteExternalTool, _currentlySelectedExternalTools[0].DisplayName); - else if (_currentlySelectedExternalTools.Count > 1) - message = string.Format(Language.strConfirmDeleteExternalToolMultiple, _currentlySelectedExternalTools.Count); - else - return; + { + try + { + string message; + if (_currentlySelectedExternalTools.Count == 1) + message = string.Format(Language.strConfirmDeleteExternalTool, + _currentlySelectedExternalTools[0].DisplayName); + else if (_currentlySelectedExternalTools.Count > 1) + message = string.Format(Language.strConfirmDeleteExternalToolMultiple, + _currentlySelectedExternalTools.Count); + else + return; - if (MessageBox.Show(FrmMain.Default, message, "Question?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) - return; + if (MessageBox.Show(FrmMain.Default, message, "Question?", MessageBoxButtons.YesNo, + MessageBoxIcon.Question) != DialogResult.Yes) + return; - foreach (var externalTool in _currentlySelectedExternalTools) - { - Runtime.ExternalToolsService.ExternalTools.Remove(externalTool); - } - var firstDeletedNode = _currentlySelectedExternalTools.FirstOrDefault(); - var oldSelectedIndex = ToolsListObjView.IndexOf(firstDeletedNode); + foreach (var externalTool in _currentlySelectedExternalTools) + { + Runtime.ExternalToolsService.ExternalTools.Remove(externalTool); + } + + var firstDeletedNode = _currentlySelectedExternalTools.FirstOrDefault(); + var oldSelectedIndex = ToolsListObjView.IndexOf(firstDeletedNode); _currentlySelectedExternalTools.Clear(); UpdateToolsListObjView(); var maxIndex = ToolsListObjView.GetItemCount() - 1; - ToolsListObjView.SelectedIndex = oldSelectedIndex <= maxIndex - ? oldSelectedIndex - : maxIndex; + ToolsListObjView.SelectedIndex = oldSelectedIndex <= maxIndex + ? oldSelectedIndex + : maxIndex; - UpdateToolstipControls(); + UpdateToolstipControls(); } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.DeleteTool_Click() failed.", ex); - } - } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.DeleteTool_Click() failed.", ex); + } + } private void LaunchTool_Click(object sender, EventArgs e) - { - LaunchTool(); - } + { + LaunchTool(); + } private void ToolsListObjView_SelectedIndexChanged(object sender, EventArgs e) - { - try - { - UpdateToolstipControls(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.ToolsListObjView_SelectedIndexChanged() failed.", ex); - } - } + { + try + { + UpdateToolstipControls(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + "UI.Window.ExternalTools.ToolsListObjView_SelectedIndexChanged() failed.", + ex); + } + } private void ToolsListObjView_DoubleClick(object sender, EventArgs e) - { - if (ToolsListObjView.SelectedItems.Count > 0) - { - LaunchTool(); - } - } + { + if (ToolsListObjView.SelectedItems.Count > 0) + { + LaunchTool(); + } + } private void PropertyControl_ChangedOrLostFocus(object sender, EventArgs e) - { - var selectedTool = _currentlySelectedExternalTools.FirstOrDefault(); + { + var selectedTool = _currentlySelectedExternalTools.FirstOrDefault(); if (selectedTool == null) - return; + return; - try - { + try + { selectedTool.DisplayName = DisplayNameTextBox.Text; selectedTool.FileName = FilenameTextBox.Text; selectedTool.Arguments = ArgumentsCheckBox.Text; @@ -260,32 +275,36 @@ namespace mRemoteNG.UI.Window selectedTool.RunElevated = RunElevatedCheckBox.Checked; UpdateToolsListObjView(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.PropertyControl_ChangedOrLostFocus() failed.", ex); - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + "UI.Window.ExternalTools.PropertyControl_ChangedOrLostFocus() failed.", + ex); + } + } private void BrowseButton_Click(object sender, EventArgs e) - { - try - { - using (var browseDialog = new OpenFileDialog()) - { - browseDialog.Filter = string.Join("|", Language.strFilterApplication, "*.exe", Language.strFilterAll, "*.*"); - if (browseDialog.ShowDialog() != DialogResult.OK) + { + try + { + using (var browseDialog = new OpenFileDialog()) + { + browseDialog.Filter = string.Join("|", Language.strFilterApplication, "*.exe", + Language.strFilterAll, "*.*"); + if (browseDialog.ShowDialog() != DialogResult.OK) return; - var selectedItem = _currentlySelectedExternalTools.FirstOrDefault(); - if (selectedItem == null) - return; - selectedItem.FileName = browseDialog.FileName; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.BrowseButton_Click() failed.", ex); - } + var selectedItem = _currentlySelectedExternalTools.FirstOrDefault(); + if (selectedItem == null) + return; + selectedItem.FileName = browseDialog.FileName; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.BrowseButton_Click() failed.", + ex); + } } private void BrowseWorkingDir_Click(object sender, EventArgs e) @@ -301,11 +320,11 @@ namespace mRemoteNG.UI.Window return; selectedItem.WorkingDir = browseDialog.SelectedPath; } - } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.BrowseButton_Click() failed.", ex); + Runtime.MessageCollector.AddExceptionMessage("UI.Window.ExternalTools.BrowseButton_Click() failed.", + ex); } } @@ -317,8 +336,10 @@ namespace mRemoteNG.UI.Window if (!(e.Model is ExternalTool rowItemAsExternalTool) || !rowItemAsExternalTool.TryIntegrate) return; - e.Text = $"'{Language.strCheckboxWaitForExit}' cannot be enabled if '{Language.strTryIntegrate}' is enabled"; + e.Text = + $"'{Language.strCheckboxWaitForExit}' cannot be enabled if '{Language.strTryIntegrate}' is enabled"; } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/HelpWindow.cs b/mRemoteV1/UI/Window/HelpWindow.cs index 6396330b2..ef93ccb71 100644 --- a/mRemoteV1/UI/Window/HelpWindow.cs +++ b/mRemoteV1/UI/Window/HelpWindow.cs @@ -7,28 +7,27 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { public class HelpWindow : BaseWindow - { - + { #region Form Init - private TreeView tvIndex; + private TreeView tvIndex; private ImageList imgListHelp; - private System.ComponentModel.Container components; - private SplitContainer pnlSplitter; - private Label lblDocName; - private WebBrowser wbHelp; - - private void InitializeComponent() - { - components = new System.ComponentModel.Container(); - Load += Help_Load; - Shown += Help_Shown; + private System.ComponentModel.Container components; + private SplitContainer pnlSplitter; + private Label lblDocName; + private WebBrowser wbHelp; + + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + Load += Help_Load; + Shown += Help_Shown; var TreeNode1 = new TreeNode("Introduction"); var TreeNode2 = new TreeNode("Prerequisites"); var TreeNode3 = new TreeNode("Installation/Update"); var TreeNode4 = new TreeNode("Running mRemoteNG"); var TreeNode5 = new TreeNode("Command-Line Switches"); - var TreeNode6 = new TreeNode("Getting Started", new[] { TreeNode2, TreeNode3, TreeNode4, TreeNode5 }); + var TreeNode6 = new TreeNode("Getting Started", new[] {TreeNode2, TreeNode3, TreeNode4, TreeNode5}); var TreeNode7 = new TreeNode("Menus"); var TreeNode8 = new TreeNode("Connections"); var TreeNode9 = new TreeNode("Config"); @@ -43,58 +42,60 @@ namespace mRemoteNG.UI.Window var TreeNode18 = new TreeNode("External Tools"); var TreeNode19 = new TreeNode("Import/Export"); var TreeNode20 = new TreeNode("Keyboard Shortcuts"); - var TreeNode21 = new TreeNode("User Interface", new[] { + var TreeNode21 = new TreeNode("User Interface", new[] + { TreeNode7, TreeNode8, TreeNode9, TreeNode10, TreeNode11, TreeNode12, TreeNode13, TreeNode14, TreeNode15, TreeNode16, TreeNode17, TreeNode18, TreeNode19, TreeNode20 }); var TreeNode22 = new TreeNode("Common Problems (RDP)"); - var TreeNode23 = new TreeNode("Special Topics", new[] { + var TreeNode23 = new TreeNode("Special Topics", new[] + { TreeNode22 }); - var TreeNode99 = new TreeNode("Help", new[] { TreeNode1, TreeNode6, TreeNode21, TreeNode23 }); + var TreeNode99 = new TreeNode("Help", new[] {TreeNode1, TreeNode6, TreeNode21, TreeNode23}); wbHelp = new WebBrowser(); - wbHelp.DocumentTitleChanged += wbHelp_DocumentTitleChanged; - tvIndex = new TreeView(); - tvIndex.NodeMouseClick += tvIndex_NodeMouseClick; - tvIndex.AfterSelect += tvIndex_AfterSelect; - imgListHelp = new ImageList(components); - pnlSplitter = new SplitContainer(); - lblDocName = new Label(); - pnlSplitter.Panel1.SuspendLayout(); - pnlSplitter.Panel2.SuspendLayout(); - pnlSplitter.SuspendLayout(); - SuspendLayout(); - // - //wbHelp - // - wbHelp.Anchor = AnchorStyles.Top | AnchorStyles.Bottom - | AnchorStyles.Left - | AnchorStyles.Right; - wbHelp.Location = new System.Drawing.Point(1, 36); - wbHelp.MinimumSize = new System.Drawing.Size(20, 20); - wbHelp.Name = "wbHelp"; - wbHelp.ScriptErrorsSuppressed = true; - wbHelp.Size = new System.Drawing.Size(327, 286); - wbHelp.TabIndex = 1; - // - //tvIndex - // - tvIndex.Anchor = AnchorStyles.Top | AnchorStyles.Bottom - | AnchorStyles.Left - | AnchorStyles.Right; - tvIndex.BorderStyle = BorderStyle.None; - tvIndex.HideSelection = false; - tvIndex.Location = new System.Drawing.Point(1, 1); + wbHelp.DocumentTitleChanged += wbHelp_DocumentTitleChanged; + tvIndex = new TreeView(); + tvIndex.NodeMouseClick += tvIndex_NodeMouseClick; + tvIndex.AfterSelect += tvIndex_AfterSelect; + imgListHelp = new ImageList(components); + pnlSplitter = new SplitContainer(); + lblDocName = new Label(); + pnlSplitter.Panel1.SuspendLayout(); + pnlSplitter.Panel2.SuspendLayout(); + pnlSplitter.SuspendLayout(); + SuspendLayout(); + // + //wbHelp + // + wbHelp.Anchor = AnchorStyles.Top | AnchorStyles.Bottom + | AnchorStyles.Left + | AnchorStyles.Right; + wbHelp.Location = new System.Drawing.Point(1, 36); + wbHelp.MinimumSize = new System.Drawing.Size(20, 20); + wbHelp.Name = "wbHelp"; + wbHelp.ScriptErrorsSuppressed = true; + wbHelp.Size = new System.Drawing.Size(327, 286); + wbHelp.TabIndex = 1; + // + //tvIndex + // + tvIndex.Anchor = AnchorStyles.Top | AnchorStyles.Bottom + | AnchorStyles.Left + | AnchorStyles.Right; + tvIndex.BorderStyle = BorderStyle.None; + tvIndex.HideSelection = false; + tvIndex.Location = new System.Drawing.Point(1, 1); tvIndex.Name = "tvIndex"; - TreeNode1.Tag = "Introduction"; - TreeNode2.Tag = "gs_prerequisites"; - TreeNode3.Tag = "gs_installation"; + TreeNode1.Tag = "Introduction"; + TreeNode2.Tag = "gs_prerequisites"; + TreeNode3.Tag = "gs_installation"; TreeNode4.Tag = "gs_running_mremoteng"; TreeNode5.Tag = "gs_command_line_switches"; TreeNode7.Tag = "ui_menus"; - TreeNode8.Tag = "ui_connections"; - TreeNode9.Tag = "ui_config"; - TreeNode10.Tag = "ui_options"; + TreeNode8.Tag = "ui_connections"; + TreeNode9.Tag = "ui_config"; + TreeNode10.Tag = "ui_options"; TreeNode11.Tag = "ui_navigation"; TreeNode12.Tag = "ui_notifications"; TreeNode13.Tag = "ui_sql_configuration"; @@ -109,135 +110,140 @@ namespace mRemoteNG.UI.Window TreeNode99.Tag = "Index"; tvIndex.Nodes.AddRange(new[] {TreeNode99}); tvIndex.ShowRootLines = false; - tvIndex.Size = new System.Drawing.Size(207, 321); - tvIndex.TabIndex = 0; - // - //imgListHelp - // - imgListHelp.ColorDepth = ColorDepth.Depth32Bit; - imgListHelp.ImageSize = new System.Drawing.Size(16, 16); - imgListHelp.TransparentColor = System.Drawing.Color.Transparent; - // - //pnlSplitter - // - pnlSplitter.Anchor = AnchorStyles.Top | AnchorStyles.Bottom - | AnchorStyles.Left - | AnchorStyles.Right; - pnlSplitter.FixedPanel = FixedPanel.Panel1; - pnlSplitter.Location = new System.Drawing.Point(0, 0); - pnlSplitter.Name = "pnlSplitter"; - // - //pnlSplitter.Panel1 - // - pnlSplitter.Panel1.Controls.Add(tvIndex); - // - //pnlSplitter.Panel2 - // - pnlSplitter.Panel2.Controls.Add(lblDocName); - pnlSplitter.Panel2.Controls.Add(wbHelp); - pnlSplitter.Size = new System.Drawing.Size(542, 323); - pnlSplitter.SplitterDistance = 209; - pnlSplitter.TabIndex = 2; - // - //lblDocName - // - lblDocName.Anchor = AnchorStyles.Top | AnchorStyles.Left - | AnchorStyles.Right; - lblDocName.BackColor = System.Drawing.Color.DimGray; - lblDocName.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)); - lblDocName.ForeColor = System.Drawing.Color.White; - lblDocName.Location = new System.Drawing.Point(1, 1); - lblDocName.Name = "lblDocName"; - lblDocName.Size = new System.Drawing.Size(327, 35); - lblDocName.TabIndex = 2; - lblDocName.Text = @"Introduction"; - lblDocName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; - // - //Help - // - ClientSize = new System.Drawing.Size(542, 323); - Controls.Add(pnlSplitter); - Icon = Resources.Help_Icon; - TabText = @"Help"; - Text = @"Help"; - pnlSplitter.Panel1.ResumeLayout(false); - pnlSplitter.Panel2.ResumeLayout(false); - pnlSplitter.ResumeLayout(false); - ResumeLayout(false); - - } + tvIndex.Size = new System.Drawing.Size(207, 321); + tvIndex.TabIndex = 0; + // + //imgListHelp + // + imgListHelp.ColorDepth = ColorDepth.Depth32Bit; + imgListHelp.ImageSize = new System.Drawing.Size(16, 16); + imgListHelp.TransparentColor = System.Drawing.Color.Transparent; + // + //pnlSplitter + // + pnlSplitter.Anchor = AnchorStyles.Top | AnchorStyles.Bottom + | AnchorStyles.Left + | AnchorStyles.Right; + pnlSplitter.FixedPanel = FixedPanel.Panel1; + pnlSplitter.Location = new System.Drawing.Point(0, 0); + pnlSplitter.Name = "pnlSplitter"; + // + //pnlSplitter.Panel1 + // + pnlSplitter.Panel1.Controls.Add(tvIndex); + // + //pnlSplitter.Panel2 + // + pnlSplitter.Panel2.Controls.Add(lblDocName); + pnlSplitter.Panel2.Controls.Add(wbHelp); + pnlSplitter.Size = new System.Drawing.Size(542, 323); + pnlSplitter.SplitterDistance = 209; + pnlSplitter.TabIndex = 2; + // + //lblDocName + // + lblDocName.Anchor = AnchorStyles.Top | AnchorStyles.Left + | AnchorStyles.Right; + lblDocName.BackColor = System.Drawing.Color.DimGray; + lblDocName.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, + System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)); + lblDocName.ForeColor = System.Drawing.Color.White; + lblDocName.Location = new System.Drawing.Point(1, 1); + lblDocName.Name = "lblDocName"; + lblDocName.Size = new System.Drawing.Size(327, 35); + lblDocName.TabIndex = 2; + lblDocName.Text = @"Introduction"; + lblDocName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + //Help + // + ClientSize = new System.Drawing.Size(542, 323); + Controls.Add(pnlSplitter); + Icon = Resources.Help_Icon; + TabText = @"Help"; + Text = @"Help"; + pnlSplitter.Panel1.ResumeLayout(false); + pnlSplitter.Panel2.ResumeLayout(false); + pnlSplitter.ResumeLayout(false); + ResumeLayout(false); + } + #endregion - + #region Public Methods - public HelpWindow() - { - WindowType = WindowType.Help; - DockPnl = new DockContent(); - InitializeComponent(); - - FillImageList(); - tvIndex.ImageList = imgListHelp; - SetImages(tvIndex.Nodes[0]); - } + + public HelpWindow() + { + WindowType = WindowType.Help; + DockPnl = new DockContent(); + InitializeComponent(); + + FillImageList(); + tvIndex.ImageList = imgListHelp; + SetImages(tvIndex.Nodes[0]); + } + #endregion - + #region Private Methods - private void Help_Load(object sender, EventArgs e) - { - tvIndex.Nodes[0].ExpandAll(); - tvIndex.SelectedNode = tvIndex.Nodes[0].Nodes[0]; - } - - private void Help_Shown(object sender, EventArgs e) - { - // This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise. - wbHelp.AllowWebBrowserDrop = false; - } - - private void tvIndex_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) - { - tvIndex.SelectedNode = e.Node; - } - - private void tvIndex_AfterSelect(object sender, TreeViewEventArgs e) - { - if (!string.IsNullOrEmpty((string)e.Node.Tag)) - { - wbHelp.Navigate(GeneralAppInfo.HomePath + "\\Help\\" + Convert.ToString(e.Node.Tag) +".htm"); - } - } - - private void wbHelp_DocumentTitleChanged(object sender, EventArgs e) - { - lblDocName.Text = wbHelp.DocumentTitle; - } - - private void FillImageList() - { - imgListHelp.Images.Add("File", Resources.Page); - imgListHelp.Images.Add("Folder", Resources.Folder); - imgListHelp.Images.Add("Help", Resources.Help); - } - - private static void SetImages(TreeNode node) - { - node.ImageIndex = 2; - node.SelectedImageIndex = 2; - - foreach (TreeNode n in node.Nodes) - { - if (n.Nodes.Count > 0) - { - n.ImageIndex = 1; - n.SelectedImageIndex = 1; - } - else - { - n.ImageIndex = 0; - n.SelectedImageIndex = 0; - } - } - } + + private void Help_Load(object sender, EventArgs e) + { + tvIndex.Nodes[0].ExpandAll(); + tvIndex.SelectedNode = tvIndex.Nodes[0].Nodes[0]; + } + + private void Help_Shown(object sender, EventArgs e) + { + // This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise. + wbHelp.AllowWebBrowserDrop = false; + } + + private void tvIndex_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + tvIndex.SelectedNode = e.Node; + } + + private void tvIndex_AfterSelect(object sender, TreeViewEventArgs e) + { + if (!string.IsNullOrEmpty((string)e.Node.Tag)) + { + wbHelp.Navigate(GeneralAppInfo.HomePath + "\\Help\\" + Convert.ToString(e.Node.Tag) + ".htm"); + } + } + + private void wbHelp_DocumentTitleChanged(object sender, EventArgs e) + { + lblDocName.Text = wbHelp.DocumentTitle; + } + + private void FillImageList() + { + imgListHelp.Images.Add("File", Resources.Page); + imgListHelp.Images.Add("Folder", Resources.Folder); + imgListHelp.Images.Add("Help", Resources.Help); + } + + private static void SetImages(TreeNode node) + { + node.ImageIndex = 2; + node.SelectedImageIndex = 2; + + foreach (TreeNode n in node.Nodes) + { + if (n.Nodes.Count > 0) + { + n.ImageIndex = 1; + n.SelectedImageIndex = 1; + } + else + { + n.ImageIndex = 0; + n.SelectedImageIndex = 0; + } + } + } + #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Window/PortScanWindow.cs b/mRemoteV1/UI/Window/PortScanWindow.cs index 615755baa..190cb0fb6 100644 --- a/mRemoteV1/UI/Window/PortScanWindow.cs +++ b/mRemoteV1/UI/Window/PortScanWindow.cs @@ -15,238 +15,263 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { public partial class PortScanWindow - { + { #region Constructors - public PortScanWindow() - { - InitializeComponent(); - - WindowType = WindowType.PortScan; - DockPnl = new DockContent(); + + public PortScanWindow() + { + InitializeComponent(); + + WindowType = WindowType.PortScan; + DockPnl = new DockContent(); ApplyTheme(); var display = new DisplayProperties(); - btnScan.Image = display.ScaleImage(btnScan.Image); - } + btnScan.Image = display.ScaleImage(btnScan.Image); + } + #endregion - private new void ApplyTheme() + private new void ApplyTheme() { - base.ApplyTheme(); + base.ApplyTheme(); } #region Private Properties + private bool IpsValid - { - get - { - if (string.IsNullOrEmpty(ipStart.Octet1.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipStart.Octet2.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipStart.Octet3.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipStart.Octet4.Text)) - { - return false; - } - - if (string.IsNullOrEmpty(ipEnd.Octet1.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipEnd.Octet2.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipEnd.Octet3.Text)) - { - return false; - } - if (string.IsNullOrEmpty(ipEnd.Octet4.Text)) - { - return false; - } - - return true; - } - } + { + get + { + if (string.IsNullOrEmpty(ipStart.Octet1.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipStart.Octet2.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipStart.Octet3.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipStart.Octet4.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipEnd.Octet1.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipEnd.Octet2.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipEnd.Octet3.Text)) + { + return false; + } + + if (string.IsNullOrEmpty(ipEnd.Octet4.Text)) + { + return false; + } + + return true; + } + } + #endregion - + #region Private Fields - private PortScanner _portScanner; - private bool _scanning; + + private PortScanner _portScanner; + private bool _scanning; + #endregion - + #region Private Methods + #region Event Handlers - private void PortScan_Load(object sender, EventArgs e) - { - ApplyLanguage(); + private void PortScan_Load(object sender, EventArgs e) + { + ApplyLanguage(); - try - { - olvHosts.Columns.AddRange(new ColumnHeader[]{clmHost, clmSSH, clmTelnet, clmHTTP, clmHTTPS, clmRlogin, clmRDP, clmVNC, clmOpenPorts, clmClosedPorts}); - ShowImportControls(true); - cbProtocol.SelectedIndex = 0; - numericSelectorTimeout.Value = 5; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(Language.strPortScanCouldNotLoadPanel, ex); - } - } + try + { + olvHosts.Columns.AddRange(new ColumnHeader[] + { + clmHost, clmSSH, clmTelnet, clmHTTP, clmHTTPS, clmRlogin, clmRDP, clmVNC, clmOpenPorts, + clmClosedPorts + }); + ShowImportControls(true); + cbProtocol.SelectedIndex = 0; + numericSelectorTimeout.Value = 5; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strPortScanCouldNotLoadPanel, ex); + } + } - private void portStart_Enter(object sender, EventArgs e) - { - portStart.Select(0, portStart.Text.Length); - } + private void portStart_Enter(object sender, EventArgs e) + { + portStart.Select(0, portStart.Text.Length); + } - private void portEnd_Enter(object sender, EventArgs e) - { - portEnd.Select(0, portEnd.Text.Length); - } + private void portEnd_Enter(object sender, EventArgs e) + { + portEnd.Select(0, portEnd.Text.Length); + } - private void btnScan_Click(object sender, EventArgs e) - { - if (_scanning) - { - StopScan(); - } - else - { - if (IpsValid) - { - StartScan(); - } - else - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, Language.strCannotStartPortScan); + private void btnScan_Click(object sender, EventArgs e) + { + if (_scanning) + { + StopScan(); + } + else + { + if (IpsValid) + { + StartScan(); } - } - } + else + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, Language.strCannotStartPortScan); + } + } + } + + private void btnImport_Click(object sender, EventArgs e) + { + var protocol = + (ProtocolType)Enum.Parse(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem), true); + importSelectedHosts(protocol); + } - private void btnImport_Click(object sender, EventArgs e) - { - var protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem), true); - importSelectedHosts(protocol); - } #endregion - - private void ApplyLanguage() - { - lblStartIP.Text = Language.strStartIP; - lblEndIP.Text = Language.strEndIP; - btnScan.Text = Language.strButtonScan; - btnImport.Text = Language.strButtonImport; - lblOnlyImport.Text = Language.strProtocolToImport; - clmHost.Text = Language.strColumnHostnameIP; - clmOpenPorts.Text = Language.strOpenPorts; - clmClosedPorts.Text = Language.strClosedPorts; + + private void ApplyLanguage() + { + lblStartIP.Text = Language.strStartIP; + lblEndIP.Text = Language.strEndIP; + btnScan.Text = Language.strButtonScan; + btnImport.Text = Language.strButtonImport; + lblOnlyImport.Text = Language.strProtocolToImport; + clmHost.Text = Language.strColumnHostnameIP; + clmOpenPorts.Text = Language.strOpenPorts; + clmClosedPorts.Text = Language.strClosedPorts; ngCheckFirstPort.Text = Language.strStartPort; ngCheckLastPort.Text = Language.strEndPort; - lblTimeout.Text = Language.strTimeoutInSeconds; - TabText = Language.strMenuPortScan; - Text = Language.strMenuPortScan; - } - - private void ShowImportControls(bool controlsVisible) - { - pnlImport.Visible = controlsVisible; - if (controlsVisible) - olvHosts.Height = pnlImport.Top - olvHosts.Top; - else - olvHosts.Height = pnlImport.Bottom - olvHosts.Top; - } - - private void StartScan() - { - try - { - _scanning = true; - SwitchButtonText(); - olvHosts.Items.Clear(); - - var ipAddressStart = IPAddress.Parse(ipStart.Text); - var ipAddressEnd = IPAddress.Parse(ipEnd.Text); + lblTimeout.Text = Language.strTimeoutInSeconds; + TabText = Language.strMenuPortScan; + Text = Language.strMenuPortScan; + } + + private void ShowImportControls(bool controlsVisible) + { + pnlImport.Visible = controlsVisible; + if (controlsVisible) + olvHosts.Height = pnlImport.Top - olvHosts.Top; + else + olvHosts.Height = pnlImport.Bottom - olvHosts.Top; + } + + private void StartScan() + { + try + { + _scanning = true; + SwitchButtonText(); + olvHosts.Items.Clear(); + + var ipAddressStart = IPAddress.Parse(ipStart.Text); + var ipAddressEnd = IPAddress.Parse(ipEnd.Text); if (!ngCheckFirstPort.Checked && !ngCheckLastPort.Checked) - _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int)portStart.Value, (int)portEnd.Value, (int)numericSelectorTimeout.Value * 1000, true); + _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int)portStart.Value, + (int)portEnd.Value, (int)numericSelectorTimeout.Value * 1000, true); else - _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int)portStart.Value, (int)portEnd.Value, (int)numericSelectorTimeout.Value*1000); - - _portScanner.BeginHostScan += PortScanner_BeginHostScan; - _portScanner.HostScanned += PortScanner_HostScanned; - _portScanner.ScanComplete += PortScanner_ScanComplete; - - _portScanner.StartScan(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage("StartScan failed (UI.Window.PortScan)", ex); - } - } - - private void StopScan() + _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int)portStart.Value, + (int)portEnd.Value, (int)numericSelectorTimeout.Value * 1000); + + _portScanner.BeginHostScan += PortScanner_BeginHostScan; + _portScanner.HostScanned += PortScanner_HostScanned; + _portScanner.ScanComplete += PortScanner_ScanComplete; + + _portScanner.StartScan(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("StartScan failed (UI.Window.PortScan)", ex); + } + } + + private void StopScan() { _portScanner.BeginHostScan -= PortScanner_BeginHostScan; _portScanner.HostScanned -= PortScanner_HostScanned; _portScanner.ScanComplete -= PortScanner_ScanComplete; _portScanner?.StopScan(); - _scanning = false; - SwitchButtonText(); - } - - private void SwitchButtonText() - { - btnScan.Text = _scanning ? Language.strButtonStop : Language.strButtonScan; - - prgBar.Maximum = 100; - prgBar.Value = 0; - } - - private static void PortScanner_BeginHostScan(string host) - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Scanning " + host, true); - } - - private delegate void PortScannerHostScannedDelegate(ScanHost host, int scannedCount, int totalCount); - private void PortScanner_HostScanned(ScanHost host, int scannedCount, int totalCount) - { - if (InvokeRequired) - { - Invoke(new PortScannerHostScannedDelegate(PortScanner_HostScanned), new object[] {host, scannedCount, totalCount}); - return; - } - - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Host scanned " + host.HostIp, true); + _scanning = false; + SwitchButtonText(); + } + + private void SwitchButtonText() + { + btnScan.Text = _scanning ? Language.strButtonStop : Language.strButtonScan; + + prgBar.Maximum = 100; + prgBar.Value = 0; + } + + private static void PortScanner_BeginHostScan(string host) + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Scanning " + host, true); + } + + private delegate void PortScannerHostScannedDelegate(ScanHost host, int scannedCount, int totalCount); + + private void PortScanner_HostScanned(ScanHost host, int scannedCount, int totalCount) + { + if (InvokeRequired) + { + Invoke(new PortScannerHostScannedDelegate(PortScanner_HostScanned), + new object[] {host, scannedCount, totalCount}); + return; + } + + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Host scanned " + host.HostIp, true); olvHosts.AddObject(host); prgBar.Maximum = totalCount; - prgBar.Value = scannedCount; - } - - private delegate void PortScannerScanComplete(List hosts); - private void PortScanner_ScanComplete(List hosts) - { - if (InvokeRequired) - { - Invoke(new PortScannerScanComplete(PortScanner_ScanComplete), new object[] {hosts}); - return; - } - - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPortScanComplete); - - _scanning = false; - SwitchButtonText(); - } + prgBar.Value = scannedCount; + } + + private delegate void PortScannerScanComplete(List hosts); + + private void PortScanner_ScanComplete(List hosts) + { + if (InvokeRequired) + { + Invoke(new PortScannerScanComplete(PortScanner_ScanComplete), new object[] {hosts}); + return; + } + + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPortScanComplete); + + _scanning = false; + SwitchButtonText(); + } + #endregion private void importSelectedHosts(ProtocolType protocol) @@ -254,12 +279,13 @@ namespace mRemoteNG.UI.Window var hosts = new List(); foreach (ScanHost host in olvHosts.SelectedObjects) { - hosts.Add(host); + hosts.Add(host); } if (hosts.Count < 1) { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Could not import host(s) from port scan context menu"); + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, + "Could not import host(s) from port scan context menu"); return; } @@ -271,20 +297,22 @@ namespace mRemoteNG.UI.Window /// Determines where the imported hosts will be placed /// in the connection tree. /// - private ContainerInfo GetDestinationContainerForImportedHosts() - { - var selectedNode = Windows.TreeForm.SelectedNode - ?? Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType().First(); + private ContainerInfo GetDestinationContainerForImportedHosts() + { + var selectedNode = Windows.TreeForm.SelectedNode + ?? Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType() + .First(); // if a putty node is selected, place imported connections in the root connection node if (selectedNode is RootPuttySessionsNodeInfo || selectedNode is PuttySessionInfo) - selectedNode = Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType().First(); + selectedNode = Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType() + .First(); // if the selected node is a connection, use its parent container var selectedTreeNodeAsContainer = selectedNode as ContainerInfo ?? selectedNode.Parent; - return selectedTreeNodeAsContainer; - } + return selectedTreeNodeAsContainer; + } private void importVNCToolStripMenuItem_Click(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Window/SSHTransferWindow.cs b/mRemoteV1/UI/Window/SSHTransferWindow.cs index 3fa51bcf4..9a1d24528 100644 --- a/mRemoteV1/UI/Window/SSHTransferWindow.cs +++ b/mRemoteV1/UI/Window/SSHTransferWindow.cs @@ -1,8 +1,8 @@ using mRemoteNG.App; using System; using System.IO; -using System.Threading; -using mRemoteNG.Tools; +using System.Threading; +using mRemoteNG.Tools; using WeifenLuo.WinFormsUI.Docking; using System.Windows.Forms; using mRemoteNG.Messages; @@ -13,6 +13,7 @@ namespace mRemoteNG.UI.Window public class SSHTransferWindow : BaseWindow { #region Form Init + private Controls.Base.NGProgressBar pbStatus; private Controls.Base.NGButton btnTransfer; private Controls.Base.NGTextBox txtUser; @@ -36,7 +37,8 @@ namespace mRemoteNG.UI.Window private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SSHTransferWindow)); + System.ComponentModel.ComponentResourceManager resources = + new System.ComponentModel.ComponentResourceManager(typeof(SSHTransferWindow)); this.grpFiles = new mRemoteNG.UI.Controls.Base.NGGroupBox(); this.lblLocalFile = new mRemoteNG.UI.Controls.Base.NGLabel(); this.txtLocalFile = new mRemoteNG.UI.Controls.Base.NGTextBox(); @@ -89,7 +91,8 @@ namespace mRemoteNG.UI.Window // txtLocalFile // this.txtLocalFile.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtLocalFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtLocalFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtLocalFile.Location = new System.Drawing.Point(105, 28); this.txtLocalFile.Name = "txtLocalFile"; this.txtLocalFile.Size = new System.Drawing.Size(455, 22); @@ -112,7 +115,8 @@ namespace mRemoteNG.UI.Window // txtRemoteFile // this.txtRemoteFile.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtRemoteFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtRemoteFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtRemoteFile.Location = new System.Drawing.Point(105, 60); this.txtRemoteFile.Name = "txtRemoteFile"; this.txtRemoteFile.Size = new System.Drawing.Size(542, 22); @@ -232,7 +236,8 @@ namespace mRemoteNG.UI.Window // txtPort // this.txtPort.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtPort.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtPort.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtPort.Location = new System.Drawing.Point(271, 110); this.txtPort.Name = "txtPort"; this.txtPort.Size = new System.Drawing.Size(30, 22); @@ -243,7 +248,8 @@ namespace mRemoteNG.UI.Window // txtHost // this.txtHost.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtHost.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtHost.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtHost.Location = new System.Drawing.Point(105, 19); this.txtHost.Name = "txtHost"; this.txtHost.Size = new System.Drawing.Size(471, 22); @@ -252,7 +258,8 @@ namespace mRemoteNG.UI.Window // txtPassword // this.txtPassword.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtPassword.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtPassword.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtPassword.Location = new System.Drawing.Point(105, 81); this.txtPassword.Name = "txtPassword"; this.txtPassword.Size = new System.Drawing.Size(471, 22); @@ -262,7 +269,8 @@ namespace mRemoteNG.UI.Window // txtUser // this.txtUser.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtUser.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtUser.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtUser.Location = new System.Drawing.Point(105, 51); this.txtUser.Name = "txtUser"; this.txtUser.Size = new System.Drawing.Size(471, 22); @@ -284,7 +292,8 @@ namespace mRemoteNG.UI.Window this.Controls.Add(this.grpFiles); this.Controls.Add(this.grpConnection); this.Controls.Add(this.pbStatus); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "SSHTransferWindow"; this.TabText = "SSH File Transfer"; @@ -295,15 +304,18 @@ namespace mRemoteNG.UI.Window this.grpConnection.ResumeLayout(false); this.grpConnection.PerformLayout(); this.ResumeLayout(false); - } + #endregion #region Private Properties + private readonly OpenFileDialog oDlg; + #endregion #region Public Properties + public string Hostname { get => txtHost.Text; @@ -327,12 +339,14 @@ namespace mRemoteNG.UI.Window get => txtPassword.Text; set => txtPassword.Text = value; } + #endregion #region Form Stuff + private void SSHTransfer_Load(object sender, EventArgs e) { - ApplyTheme(); + ApplyTheme(); ApplyLanguage(); var display = new DisplayProperties(); btnTransfer.Image = display.ScaleImage(btnTransfer.Image); @@ -354,10 +368,13 @@ namespace mRemoteNG.UI.Window TabText = Language.strMenuSSHFileTransfer; Text = Language.strMenuSSHFileTransfer; } + #endregion #region Private Methods + private SecureTransfer st; + private void StartTransfer(SecureTransfer.SSHTransferProtocol Protocol) { if (AllFieldsSet() == false) @@ -374,7 +391,8 @@ namespace mRemoteNG.UI.Window try { - st = new SecureTransfer(txtHost.Text, txtUser.Text, txtPassword.Text, int.Parse(txtPort.Text), Protocol, txtLocalFile.Text, txtRemoteFile.Text); + st = new SecureTransfer(txtHost.Text, txtUser.Text, txtPassword.Text, int.Parse(txtPort.Text), Protocol, + txtLocalFile.Text, txtRemoteFile.Text); // Connect creates the protocol objects and makes the initial connection. st.Connect(); @@ -423,7 +441,8 @@ namespace mRemoteNG.UI.Window try { DisableButtons(); - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Transfer of {Path.GetFileName(st.SrcFile)} started.", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Transfer of {Path.GetFileName(st.SrcFile)} started.", true); st.Upload(); // SftpClient is Asynchronous, so we need to wait here after the upload and handle the status directly since no status events are raised. @@ -432,22 +451,28 @@ namespace mRemoteNG.UI.Window var fi = new FileInfo(st.SrcFile); while (!st.asyncResult.IsCompleted) { - var max = fi.Length > int.MaxValue ? Convert.ToInt32(fi.Length / 1024) : Convert.ToInt32(fi.Length); + var max = fi.Length > int.MaxValue + ? Convert.ToInt32(fi.Length / 1024) + : Convert.ToInt32(fi.Length); - var cur = fi.Length > int.MaxValue ? Convert.ToInt32(st.asyncResult.UploadedBytes / 1024) : Convert.ToInt32(st.asyncResult.UploadedBytes); + var cur = fi.Length > int.MaxValue + ? Convert.ToInt32(st.asyncResult.UploadedBytes / 1024) + : Convert.ToInt32(st.asyncResult.UploadedBytes); SshTransfer_Progress(cur, max); Thread.Sleep(50); } } - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Transfer of {Path.GetFileName(st.SrcFile)} completed.", true); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Transfer of {Path.GetFileName(st.SrcFile)} completed.", true); st.Disconnect(); st.Dispose(); EnableButtons(); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strSSHStartTransferBG, ex, MessageClass.ErrorMsg, false); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strSSHStartTransferBG, ex, + MessageClass.ErrorMsg, false); st?.Disconnect(); st?.Dispose(); } @@ -455,11 +480,13 @@ namespace mRemoteNG.UI.Window private bool AllFieldsSet() { - if (txtHost.Text != "" && txtPort.Text != "" && txtUser.Text != "" && txtLocalFile.Text != "" && txtRemoteFile.Text != "") + if (txtHost.Text != "" && txtPort.Text != "" && txtUser.Text != "" && txtLocalFile.Text != "" && + txtRemoteFile.Text != "") { if (txtPassword.Text == "") { - if (MessageBox.Show(FrmMain.Default, Language.strEmptyPasswordContinue, @"Question?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) + if (MessageBox.Show(FrmMain.Default, Language.strEmptyPasswordContinue, @"Question?", + MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) { return false; } @@ -467,7 +494,8 @@ namespace mRemoteNG.UI.Window if (txtRemoteFile.Text.EndsWith("/") || txtRemoteFile.Text.EndsWith("\\")) { - txtRemoteFile.Text += txtLocalFile.Text.Substring(txtLocalFile.Text.LastIndexOf("\\", StringComparison.Ordinal) + 1); + txtRemoteFile.Text += + txtLocalFile.Text.Substring(txtLocalFile.Text.LastIndexOf("\\", StringComparison.Ordinal) + 1); } return true; @@ -483,6 +511,7 @@ namespace mRemoteNG.UI.Window private int curVal; private delegate void SetStatusCB(); + private void SetStatus() { if (pbStatus.InvokeRequired) @@ -498,6 +527,7 @@ namespace mRemoteNG.UI.Window } private delegate void EnableButtonsCB(); + private void EnableButtons() { if (btnTransfer.InvokeRequired) @@ -512,6 +542,7 @@ namespace mRemoteNG.UI.Window } private delegate void DisableButtonsCB(); + private void DisableButtons() { if (btnTransfer.InvokeRequired) @@ -536,6 +567,7 @@ namespace mRemoteNG.UI.Window #endregion #region Public Methods + public SSHTransferWindow() { WindowType = WindowType.SSHTransfer; @@ -548,9 +580,11 @@ namespace mRemoteNG.UI.Window CheckFileExists = true }; } + #endregion #region Form Stuff + private void btnBrowse_Click(object sender, EventArgs e) { if (oDlg.ShowDialog() != DialogResult.OK) return; @@ -571,6 +605,7 @@ namespace mRemoteNG.UI.Window StartTransfer(SecureTransfer.SSHTransferProtocol.SFTP); } } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs b/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs index d38a6c778..173125266 100644 --- a/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs +++ b/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs @@ -9,26 +9,27 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Window { - public class ScreenshotManagerWindow : BaseWindow - { + public class ScreenshotManagerWindow : BaseWindow + { #region Form Init - internal MenuStrip msMain; - private ToolStripMenuItem mMenFile; - private ToolStripMenuItem mMenFileSaveAll; - private ToolStripMenuItem mMenFileRemoveAll; - internal ContextMenuStrip cMenScreenshot; + + internal MenuStrip msMain; + private ToolStripMenuItem mMenFile; + private ToolStripMenuItem mMenFileSaveAll; + private ToolStripMenuItem mMenFileRemoveAll; + internal ContextMenuStrip cMenScreenshot; private System.ComponentModel.IContainer components; private ToolStripMenuItem cMenScreenshotCopy; - private ToolStripMenuItem cMenScreenshotSave; - internal SaveFileDialog dlgSaveSingleImage; - internal FolderBrowserDialog dlgSaveAllImages; + private ToolStripMenuItem cMenScreenshotSave; + internal SaveFileDialog dlgSaveSingleImage; + internal FolderBrowserDialog dlgSaveAllImages; private FlowLayoutPanel flpScreenshots; private VisualStudioToolStripExtender vsToolStripExtender; private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); private void InitializeComponent() - { + { components = new System.ComponentModel.Container(); flpScreenshots = new FlowLayoutPanel(); msMain = new MenuStrip(); @@ -46,8 +47,8 @@ namespace mRemoteNG.UI.Window // // flpScreenshots // - flpScreenshots.Anchor = AnchorStyles.Top | AnchorStyles.Bottom - | AnchorStyles.Left + flpScreenshots.Anchor = AnchorStyles.Top | AnchorStyles.Bottom + | AnchorStyles.Left | AnchorStyles.Right; flpScreenshots.AutoScroll = true; flpScreenshots.Location = new Point(0, 26); @@ -58,8 +59,10 @@ namespace mRemoteNG.UI.Window // msMain // msMain.Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); - msMain.Items.AddRange(new ToolStripItem[] { - mMenFile}); + msMain.Items.AddRange(new ToolStripItem[] + { + mMenFile + }); msMain.Location = new Point(0, 0); msMain.Name = "msMain"; msMain.RenderMode = ToolStripRenderMode.Professional; @@ -69,9 +72,11 @@ namespace mRemoteNG.UI.Window // // mMenFile // - mMenFile.DropDownItems.AddRange(new ToolStripItem[] { - mMenFileSaveAll, - mMenFileRemoveAll}); + mMenFile.DropDownItems.AddRange(new ToolStripItem[] + { + mMenFileSaveAll, + mMenFileRemoveAll + }); mMenFile.Image = Resources.File; mMenFile.Name = "mMenFile"; mMenFile.Size = new Size(53, 20); @@ -96,9 +101,11 @@ namespace mRemoteNG.UI.Window // // cMenScreenshot // - cMenScreenshot.Items.AddRange(new ToolStripItem[] { - cMenScreenshotCopy, - cMenScreenshotSave}); + cMenScreenshot.Items.AddRange(new ToolStripItem[] + { + cMenScreenshotCopy, + cMenScreenshotSave + }); cMenScreenshot.Name = "cMenScreenshot"; cMenScreenshot.Size = new Size(103, 48); // @@ -120,9 +127,10 @@ namespace mRemoteNG.UI.Window // // dlgSaveSingleImage // - dlgSaveSingleImage.Filter = "Graphics Interchange Format File (.gif)|*.gif|Joint Photographic Experts Group Fi" + - "le (.jpeg)|*.jpeg|Joint Photographic Experts Group File (.jpg)|*.jpg|Portable Ne" + - "twork Graphics File (.png)|*.png"; + dlgSaveSingleImage.Filter = + "Graphics Interchange Format File (.gif)|*.gif|Joint Photographic Experts Group Fi" + + "le (.jpeg)|*.jpeg|Joint Photographic Experts Group File (.jpg)|*.jpg|Portable Ne" + + "twork Graphics File (.png)|*.png"; dlgSaveSingleImage.FilterIndex = 4; // // ScreenshotManagerWindow @@ -145,17 +153,18 @@ namespace mRemoteNG.UI.Window cMenScreenshot.ResumeLayout(false); ResumeLayout(false); PerformLayout(); + } - } #endregion - + #region Form Stuff - private void ScreenshotManager_Load(object sender, EventArgs e) - { + + private void ScreenshotManager_Load(object sender, EventArgs e) + { ApplyTheme(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); - } + } private new void ApplyTheme() { @@ -165,253 +174,284 @@ namespace mRemoteNG.UI.Window { DefaultRenderer = _toolStripProfessionalRenderer }; - vsToolStripExtender.SetStyle(cMenScreenshot, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + vsToolStripExtender.SetStyle(cMenScreenshot, ThemeManager.getInstance().ActiveTheme.Version, + ThemeManager.getInstance().ActiveTheme.Theme); } + private void ApplyLanguage() - { - mMenFile.Text = Language.strMenuFile; - mMenFileSaveAll.Text = Language.strSaveAll; - mMenFileRemoveAll.Text = Language.strRemoveAll; - cMenScreenshotCopy.Text = Language.strMenuCopy; - cMenScreenshotSave.Text = Language.strSave; - dlgSaveSingleImage.Filter = Language.strSaveImageFilter; - TabText = Language.strScreenshots; - Text = Language.strScreenshots; - } + { + mMenFile.Text = Language.strMenuFile; + mMenFileSaveAll.Text = Language.strSaveAll; + mMenFileRemoveAll.Text = Language.strRemoveAll; + cMenScreenshotCopy.Text = Language.strMenuCopy; + cMenScreenshotSave.Text = Language.strSave; + dlgSaveSingleImage.Filter = Language.strSaveImageFilter; + TabText = Language.strScreenshots; + Text = Language.strScreenshots; + } + #endregion - + #region Public Methods - public ScreenshotManagerWindow() : this(new DockContent()) - { - } + public ScreenshotManagerWindow() : this(new DockContent()) + { + } + + internal ScreenshotManagerWindow(DockContent panel) + { + WindowType = WindowType.ScreenshotManager; + DockPnl = panel; + InitializeComponent(); + } + + public void AddScreenshot(Image Screenshot) + { + try + { + var nPB = new PictureBox(); + nPB.MouseDown += pbScreenshot_MouseDown; + + nPB.Parent = flpScreenshots; + nPB.SizeMode = PictureBoxSizeMode.StretchImage; + nPB.BorderStyle = BorderStyle.FixedSingle; + nPB.ContextMenuStrip = cMenScreenshot; + nPB.Image = Screenshot; + nPB.Size = new Size(100, 100); //New Size((Screenshot.Width / 100) * 20, (Screenshot.Height / 100) * 20) + nPB.Show(); + + var nBtn = new Button(); + nBtn.Click += btnCloseScreenshot_Click; + + nBtn.Parent = nPB; + nBtn.FlatStyle = FlatStyle.Flat; + nBtn.Text = "×"; + nBtn.Size = new Size(22, 22); + nBtn.Location = new Point(nPB.Width - nBtn.Width, -1); + nBtn.Show(); + + Show(FrmMain.Default.pnlDock); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "AddScreenshot (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, true); + } + } - internal ScreenshotManagerWindow(DockContent panel) - { - WindowType = WindowType.ScreenshotManager; - DockPnl = panel; - InitializeComponent(); - } - - public void AddScreenshot(Image Screenshot) - { - try - { - var nPB = new PictureBox(); - nPB.MouseDown += pbScreenshot_MouseDown; - - nPB.Parent = flpScreenshots; - nPB.SizeMode = PictureBoxSizeMode.StretchImage; - nPB.BorderStyle = BorderStyle.FixedSingle; - nPB.ContextMenuStrip = cMenScreenshot; - nPB.Image = Screenshot; - nPB.Size = new Size(100, 100); //New Size((Screenshot.Width / 100) * 20, (Screenshot.Height / 100) * 20) - nPB.Show(); - - var nBtn = new Button(); - nBtn.Click += btnCloseScreenshot_Click; - - nBtn.Parent = nPB; - nBtn.FlatStyle = FlatStyle.Flat; - nBtn.Text = "×"; - nBtn.Size = new Size(22, 22); - nBtn.Location = new Point(nPB.Width - nBtn.Width, -1); - nBtn.Show(); - - Show(FrmMain.Default.pnlDock); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "AddScreenshot (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } #endregion - + #region Private Methods - private void pbScreenshot_MouseDown(object sender, MouseEventArgs e) - { - cMenScreenshot.Tag = sender; - - if (e.Button == MouseButtons.Left) - { - OpenScreenshot((PictureBox)sender); - } - } - - private void pbScreenshotOpen_MouseDown(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - CloseOpenedScreenshot((Form)((PictureBox)sender).Parent); - } - } - - private void CloseOpenedScreenshot(Form form) - { - form.Close(); - } - - private void OpenScreenshot(PictureBox sender) - { - try - { - var mImage = sender.Image; - var nForm = new Form - { - StartPosition = FormStartPosition.CenterParent, - ShowInTaskbar = false, - ShowIcon = false, - MaximizeBox = false, - MinimizeBox = false, - Width = mImage.Width + 2, - Height = mImage.Height + 2, - FormBorderStyle = FormBorderStyle.None - }; + private void pbScreenshot_MouseDown(object sender, MouseEventArgs e) + { + cMenScreenshot.Tag = sender; - var nPB = new PictureBox - { - Parent = nForm, - BorderStyle = BorderStyle.FixedSingle, - Location = new Point(0, 0), - SizeMode = PictureBoxSizeMode.AutoSize, - Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Top, - Image = mImage, - ContextMenuStrip = cMenScreenshot - }; - nPB.Show(); - - nPB.MouseDown += pbScreenshotOpen_MouseDown; - - nForm.ShowDialog(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "OpenScreenshot (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } - - private void btnCloseScreenshot_Click(object sender, EventArgs e) - { - try - { - ((PictureBox)((Button)sender).Parent).Dispose(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "btnCloseScreenshot_Click (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } - - private void mMenFileRemoveAll_Click(object sender, EventArgs e) - { - RemoveAllImages(); - } - - private void RemoveAllImages() - { - flpScreenshots.Controls.Clear(); - } - - private void mMenFileSaveAll_Click(object sender, EventArgs e) - { - SaveAllImages(); - } - - private void SaveAllImages() - { - try - { - var pCount = 1; + if (e.Button == MouseButtons.Left) + { + OpenScreenshot((PictureBox)sender); + } + } + + private void pbScreenshotOpen_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + CloseOpenedScreenshot((Form)((PictureBox)sender).Parent); + } + } + + private void CloseOpenedScreenshot(Form form) + { + form.Close(); + } + + private void OpenScreenshot(PictureBox sender) + { + try + { + var mImage = sender.Image; + + var nForm = new Form + { + StartPosition = FormStartPosition.CenterParent, + ShowInTaskbar = false, + ShowIcon = false, + MaximizeBox = false, + MinimizeBox = false, + Width = mImage.Width + 2, + Height = mImage.Height + 2, + FormBorderStyle = FormBorderStyle.None + }; + + var nPB = new PictureBox + { + Parent = nForm, + BorderStyle = BorderStyle.FixedSingle, + Location = new Point(0, 0), + SizeMode = PictureBoxSizeMode.AutoSize, + Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Top, + Image = mImage, + ContextMenuStrip = cMenScreenshot + }; + nPB.Show(); + + nPB.MouseDown += pbScreenshotOpen_MouseDown; + + nForm.ShowDialog(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "OpenScreenshot (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, true); + } + } + + private void btnCloseScreenshot_Click(object sender, EventArgs e) + { + try + { + ((PictureBox)((Button)sender).Parent).Dispose(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "btnCloseScreenshot_Click (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, + true); + } + } + + private void mMenFileRemoveAll_Click(object sender, EventArgs e) + { + RemoveAllImages(); + } + + private void RemoveAllImages() + { + flpScreenshots.Controls.Clear(); + } + + private void mMenFileSaveAll_Click(object sender, EventArgs e) + { + SaveAllImages(); + } + + private void SaveAllImages() + { + try + { + var pCount = 1; + + if (dlgSaveAllImages.ShowDialog() != DialogResult.OK) return; + foreach (var fPath in Directory.GetFiles(dlgSaveAllImages.SelectedPath, "Screenshot_*", + SearchOption.TopDirectoryOnly)) + { + var f = new FileInfo(fPath); + + var fCount = f.Name; + fCount = fCount.Replace(f.Extension, ""); + fCount = fCount.Replace("Screenshot_", ""); + + pCount = (int)(double.Parse(fCount) + 1); + } + + foreach (Control ctrl in flpScreenshots.Controls) + { + if (!(ctrl is PictureBox)) continue; + (ctrl as PictureBox).Image.Save( + dlgSaveAllImages.SelectedPath + "\\Screenshot_" + + Tools.MiscTools.LeadingZero(Convert.ToString(pCount)) + ".png", + System.Drawing.Imaging.ImageFormat.Png); + pCount++; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "SaveAllImages (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, true); + } + } + + private void cMenScreenshotCopy_Click(object sender, EventArgs e) + { + CopyImageToClipboard(); + } + + private void CopyImageToClipboard() + { + try + { + Clipboard.SetImage(((PictureBox)cMenScreenshot.Tag).Image); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "CopyImageToClipboard (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, + true); + } + } + + private void cMenScreenshotSave_Click(object sender, EventArgs e) + { + SaveSingleImage(); + } + + private void SaveSingleImage() + { + try + { + if (dlgSaveSingleImage.ShowDialog() != DialogResult.OK) return; + // ReSharper disable once SwitchStatementMissingSomeCases + switch (dlgSaveSingleImage.FileName + .Substring(dlgSaveSingleImage + .FileName.LastIndexOf(".", StringComparison.Ordinal) + 1) + .ToLower()) + { + case "gif": + ((PictureBox)cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, + System.Drawing.Imaging.ImageFormat.Gif); + break; + case "jpeg": + ((PictureBox)cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, + System.Drawing.Imaging.ImageFormat.Jpeg); + break; + case "jpg": + ((PictureBox)cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, + System.Drawing.Imaging.ImageFormat.Jpeg); + break; + case "png": + ((PictureBox)cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, + System.Drawing.Imaging.ImageFormat.Png); + break; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "SaveSingleImage (UI.Window.ScreenshotManager) failed" + + Environment.NewLine + ex.Message, true); + } + } + + private void mMenFile_DropDownOpening(object sender, EventArgs e) + { + if (flpScreenshots.Controls.Count < 1) + { + mMenFileSaveAll.Enabled = false; + mMenFileRemoveAll.Enabled = false; + } + else + { + mMenFileSaveAll.Enabled = true; + mMenFileRemoveAll.Enabled = true; + } + } - if (dlgSaveAllImages.ShowDialog() != DialogResult.OK) return; - foreach (var fPath in Directory.GetFiles(dlgSaveAllImages.SelectedPath, "Screenshot_*", SearchOption.TopDirectoryOnly)) - { - var f = new FileInfo(fPath); - - var fCount = f.Name; - fCount = fCount.Replace(f.Extension, ""); - fCount = fCount.Replace("Screenshot_", ""); - - pCount = (int) (double.Parse(fCount) + 1); - } - - foreach (Control ctrl in flpScreenshots.Controls) - { - if (!(ctrl is PictureBox)) continue; - (ctrl as PictureBox).Image.Save(dlgSaveAllImages.SelectedPath + "\\Screenshot_" + Tools.MiscTools.LeadingZero(Convert.ToString(pCount)) +".png", System.Drawing.Imaging.ImageFormat.Png); - pCount++; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "SaveAllImages (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } - - private void cMenScreenshotCopy_Click(object sender, EventArgs e) - { - CopyImageToClipboard(); - } - - private void CopyImageToClipboard() - { - try - { - Clipboard.SetImage(((PictureBox) cMenScreenshot.Tag).Image); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "CopyImageToClipboard (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } - - private void cMenScreenshotSave_Click(object sender, EventArgs e) - { - SaveSingleImage(); - } - - private void SaveSingleImage() - { - try - { - if (dlgSaveSingleImage.ShowDialog() != DialogResult.OK) return; - // ReSharper disable once SwitchStatementMissingSomeCases - switch (dlgSaveSingleImage.FileName.Substring(dlgSaveSingleImage.FileName.LastIndexOf(".", StringComparison.Ordinal) + 1).ToLower()) - { - case "gif": - ((PictureBox) cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, System.Drawing.Imaging.ImageFormat.Gif); - break; - case "jpeg": - ((PictureBox) cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, System.Drawing.Imaging.ImageFormat.Jpeg); - break; - case "jpg": - ((PictureBox) cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, System.Drawing.Imaging.ImageFormat.Jpeg); - break; - case "png": - ((PictureBox) cMenScreenshot.Tag).Image.Save(dlgSaveSingleImage.FileName, System.Drawing.Imaging.ImageFormat.Png); - break; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "SaveSingleImage (UI.Window.ScreenshotManager) failed" + Environment.NewLine + ex.Message, true); - } - } - - private void mMenFile_DropDownOpening(object sender, EventArgs e) - { - if (flpScreenshots.Controls.Count < 1) - { - mMenFileSaveAll.Enabled = false; - mMenFileRemoveAll.Enabled = false; - } - else - { - mMenFileSaveAll.Enabled = true; - mMenFileRemoveAll.Enabled = true; - } - } #endregion - } -} + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Window/UltraVNCWindow.cs b/mRemoteV1/UI/Window/UltraVNCWindow.cs index 571cdb8ff..0b69042cc 100644 --- a/mRemoteV1/UI/Window/UltraVNCWindow.cs +++ b/mRemoteV1/UI/Window/UltraVNCWindow.cs @@ -5,16 +5,18 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { - public class UltraVNCWindow : BaseWindow - { + public class UltraVNCWindow : BaseWindow + { #region Form Init - internal System.Windows.Forms.ToolStrip tsMain; - internal System.Windows.Forms.Panel pnlContainer; - internal System.Windows.Forms.ToolStripButton btnDisconnect; - - private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UltraVNCWindow)); + + internal System.Windows.Forms.ToolStrip tsMain; + internal System.Windows.Forms.Panel pnlContainer; + internal System.Windows.Forms.ToolStripButton btnDisconnect; + + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = + new System.ComponentModel.ComponentResourceManager(typeof(UltraVNCWindow)); this.tsMain = new System.Windows.Forms.ToolStrip(); this.btnDisconnect = new System.Windows.Forms.ToolStripButton(); this.pnlContainer = new System.Windows.Forms.Panel(); @@ -24,8 +26,10 @@ namespace mRemoteNG.UI.Window // tsMain // this.tsMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; - this.tsMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.btnDisconnect}); + this.tsMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] + { + this.btnDisconnect + }); this.tsMain.Location = new System.Drawing.Point(0, 0); this.tsMain.Name = "tsMain"; this.tsMain.Size = new System.Drawing.Size(446, 25); @@ -44,9 +48,11 @@ namespace mRemoteNG.UI.Window // // pnlContainer // - this.pnlContainer.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.pnlContainer.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.pnlContainer.Location = new System.Drawing.Point(0, 27); this.pnlContainer.Name = "pnlContainer"; this.pnlContainer.Size = new System.Drawing.Size(446, 335); @@ -59,7 +65,8 @@ namespace mRemoteNG.UI.Window this.ClientSize = new System.Drawing.Size(446, 362); this.Controls.Add(this.pnlContainer); this.Controls.Add(this.tsMain); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = global::mRemoteNG.Resources.UVNC_SC_Icon; this.Name = "UltraVNCWindow"; this.TabText = "UltraVNC SC"; @@ -69,63 +76,70 @@ namespace mRemoteNG.UI.Window this.tsMain.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); + } - } #endregion - + #region Declarations - //Private WithEvents vnc As AxCSC_ViewerXControl + + //Private WithEvents vnc As AxCSC_ViewerXControl + #endregion - + #region Public Methods - public UltraVNCWindow() - { - this.WindowType = WindowType.UltraVNCSC; - this.DockPnl = new DockContent(); - this.InitializeComponent(); - } + + public UltraVNCWindow() + { + this.WindowType = WindowType.UltraVNCSC; + this.DockPnl = new DockContent(); + this.InitializeComponent(); + } + #endregion - + #region Private Methods - private void UltraVNCSC_Load(object sender, System.EventArgs e) - { - ApplyLanguage(); - - StartListening(); - } - - private void ApplyLanguage() - { - btnDisconnect.Text = Language.strButtonDisconnect; - } - - private void StartListening() - { - try - { - //If vnc IsNot Nothing Then - // vnc.Dispose() - // vnc = Nothing - //End If - - //vnc = New AxCSC_ViewerXControl() - //SetupLicense() - - //vnc.Parent = pnlContainer - //vnc.Dock = DockStyle.Fill - //vnc.Show() - - //vnc.StretchMode = ViewerX.ScreenStretchMode.SSM_ASPECT - //vnc.ListeningText = Language.strInheritListeningForIncomingVNCConnections & " " & Settings.UVNCSCPort - - //vnc.ListenEx(Settings.UVNCSCPort) - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "StartListening (UI.Window.UltraVNCSC) failed" + Environment.NewLine + ex.Message); - Close(); - } - } + + private void UltraVNCSC_Load(object sender, System.EventArgs e) + { + ApplyLanguage(); + + StartListening(); + } + + private void ApplyLanguage() + { + btnDisconnect.Text = Language.strButtonDisconnect; + } + + private void StartListening() + { + try + { + //If vnc IsNot Nothing Then + // vnc.Dispose() + // vnc = Nothing + //End If + + //vnc = New AxCSC_ViewerXControl() + //SetupLicense() + + //vnc.Parent = pnlContainer + //vnc.Dock = DockStyle.Fill + //vnc.Show() + + //vnc.StretchMode = ViewerX.ScreenStretchMode.SSM_ASPECT + //vnc.ListeningText = Language.strInheritListeningForIncomingVNCConnections & " " & Settings.UVNCSCPort + + //vnc.ListenEx(Settings.UVNCSCPort) + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + "StartListening (UI.Window.UltraVNCSC) failed" + + Environment.NewLine + ex.Message); + Close(); + } + } #if false private void SetupLicense() @@ -142,21 +156,22 @@ namespace mRemoteNG.UI.Window } } #endif - - //Private Sub vnc_ConnectionAccepted(ByVal sender As Object, ByVal e As AxViewerX._ISmartCodeVNCViewerEvents_ConnectionAcceptedEvent) Handles vnc.ConnectionAccepted - // mC.AddMessage(Messages.MessageClass.InformationMsg, e.bstrServerAddress & " is now connected to your UltraVNC SingleClick panel!") - //End Sub - - //Private Sub vnc_Disconnected(ByVal sender As Object, ByVal e As System.EventArgs) Handles vnc.Disconnected - // StartListening() - //End Sub - - private void btnDisconnect_Click(object sender, EventArgs e) - { - //vnc.Dispose() - Dispose(); - Windows.Show(WindowType.UltraVNCSC); - } -#endregion - } + + //Private Sub vnc_ConnectionAccepted(ByVal sender As Object, ByVal e As AxViewerX._ISmartCodeVNCViewerEvents_ConnectionAcceptedEvent) Handles vnc.ConnectionAccepted + // mC.AddMessage(Messages.MessageClass.InformationMsg, e.bstrServerAddress & " is now connected to your UltraVNC SingleClick panel!") + //End Sub + + //Private Sub vnc_Disconnected(ByVal sender As Object, ByVal e As System.EventArgs) Handles vnc.Disconnected + // StartListening() + //End Sub + + private void btnDisconnect_Click(object sender, EventArgs e) + { + //vnc.Dispose() + Dispose(); + Windows.Show(WindowType.UltraVNCSC); + } + + #endregion + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Window/UpdateWindow.cs b/mRemoteV1/UI/Window/UpdateWindow.cs index 060e93b38..dc64f8264 100644 --- a/mRemoteV1/UI/Window/UpdateWindow.cs +++ b/mRemoteV1/UI/Window/UpdateWindow.cs @@ -13,278 +13,293 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window { - public partial class UpdateWindow : BaseWindow - { + public partial class UpdateWindow : BaseWindow + { private AppUpdater _appUpdate; private bool _isUpdateDownloadHandlerDeclared; #region Public Methods - public UpdateWindow() : this(new DockContent()) - { - } - public UpdateWindow(DockContent panel) - { - WindowType = WindowType.Update; - DockPnl = panel; - InitializeComponent(); + public UpdateWindow() : this(new DockContent()) + { + } + + public UpdateWindow(DockContent panel) + { + WindowType = WindowType.Update; + DockPnl = panel; + InitializeComponent(); FontOverrider.FontOverride(this); - } + } + #endregion #region Form Stuff - private void Update_Load(object sender, EventArgs e) - { + private void Update_Load(object sender, EventArgs e) + { ApplyTheme(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); - CheckForUpdate(); - } + CheckForUpdate(); + } private new void ApplyTheme() { - if (!ThemeManager.getInstance().ActiveAndExtended) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; base.ApplyTheme(); - txtChangeLog.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - txtChangeLog.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + txtChangeLog.BackColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + txtChangeLog.ForeColor = + ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void ApplyLanguage() - { - Text = Language.strMenuCheckForUpdates; - TabText = Language.strMenuCheckForUpdates; - btnCheckForUpdate.Text = Language.strCheckForUpdate; - btnDownload.Text = Runtime.IsPortableEdition ? Language.strDownloadPortable : Language.strDownloadAndInstall; + { + Text = Language.strMenuCheckForUpdates; + TabText = Language.strMenuCheckForUpdates; + btnCheckForUpdate.Text = Language.strCheckForUpdate; + btnDownload.Text = Runtime.IsPortableEdition + ? Language.strDownloadPortable + : Language.strDownloadAndInstall; lblChangeLogLabel.Text = Language.strLabelChangeLog; - lblInstalledVersion.Text = Language.strVersion; - lblInstalledVersionLabel.Text = $"{Language.strCurrentVersion}:"; - lblLatestVersion.Text = Language.strVersion; - lblLatestVersionLabel.Text = $"{Language.strAvailableVersion}:"; - } + lblInstalledVersion.Text = Language.strVersion; + lblInstalledVersionLabel.Text = $"{Language.strCurrentVersion}:"; + lblLatestVersion.Text = Language.strVersion; + lblLatestVersionLabel.Text = $"{Language.strAvailableVersion}:"; + } - private void btnCheckForUpdate_Click(object sender, EventArgs e) - { - CheckForUpdate(); - } + private void btnCheckForUpdate_Click(object sender, EventArgs e) + { + CheckForUpdate(); + } private void btnDownload_Click(object sender, EventArgs e) - { - DownloadUpdate(); - } + { + DownloadUpdate(); + } private void pbUpdateImage_Click(object sender, EventArgs e) - { - var linkUri = pbUpdateImage.Tag as Uri; - if (linkUri == null || linkUri.IsFile || linkUri.IsUnc || linkUri.IsLoopback) - { - return; - } - Process.Start(linkUri.ToString()); - } + { + var linkUri = pbUpdateImage.Tag as Uri; + if (linkUri == null || linkUri.IsFile || linkUri.IsUnc || linkUri.IsLoopback) + { + return; + } + + Process.Start(linkUri.ToString()); + } + #endregion #region Private Methods - private void CheckForUpdate() - { - if (_appUpdate == null) - { - _appUpdate = new AppUpdater(); - //_appUpdate.Load += _appUpdate.Update_Load; - } - else if (_appUpdate.IsGetUpdateInfoRunning) - { - return; - } - lblStatus.Text = Language.strUpdateCheckingLabel; - lblStatus.ForeColor = SystemColors.WindowText; - lblLatestVersionLabel.Visible = false; - lblInstalledVersion.Visible = false; - lblInstalledVersionLabel.Visible = false; - lblLatestVersion.Visible = false; - btnCheckForUpdate.Visible = false; + private void CheckForUpdate() + { + if (_appUpdate == null) + { + _appUpdate = new AppUpdater(); + //_appUpdate.Load += _appUpdate.Update_Load; + } + else if (_appUpdate.IsGetUpdateInfoRunning) + { + return; + } - SetVisibilityOfUpdateControls(false); + lblStatus.Text = Language.strUpdateCheckingLabel; + lblStatus.ForeColor = SystemColors.WindowText; + lblLatestVersionLabel.Visible = false; + lblInstalledVersion.Visible = false; + lblInstalledVersionLabel.Visible = false; + lblLatestVersion.Visible = false; + btnCheckForUpdate.Visible = false; - _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; + SetVisibilityOfUpdateControls(false); - _appUpdate.GetUpdateInfoAsync(); - } + _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; - private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) - { - if (InvokeRequired) - { - var myDelegate = new AsyncCompletedEventHandler(GetUpdateInfoCompleted); - Invoke(myDelegate, sender, e); - return; - } - - try - { - _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; - - lblInstalledVersion.Text = Application.ProductVersion; - lblInstalledVersion.Visible = true; - lblInstalledVersionLabel.Visible = true; - btnCheckForUpdate.Visible = true; - - if (e.Cancelled) - { - return; - } - if (e.Error != null) - { - throw e.Error; - } - - if (_appUpdate.IsUpdateAvailable()) - { - lblStatus.Text = Language.strUpdateAvailable; - lblStatus.ForeColor = Color.OrangeRed; - SetVisibilityOfUpdateControls(true); - - var updateInfo = _appUpdate.CurrentUpdateInfo; - lblLatestVersion.Text = updateInfo.Version.ToString(); - lblLatestVersionLabel.Visible = true; - lblLatestVersion.Visible = true; - - if (updateInfo.ImageAddress == null || string.IsNullOrEmpty(updateInfo.ImageAddress.ToString())) - { - pbUpdateImage.Visible = false; - } - else - { - pbUpdateImage.ImageLocation = updateInfo.ImageAddress.ToString(); - pbUpdateImage.Tag = updateInfo.ImageLinkAddress; - pbUpdateImage.Visible = true; - } - - _appUpdate.GetChangeLogCompletedEvent += GetChangeLogCompleted; - _appUpdate.GetChangeLogAsync(); - - btnDownload.Focus(); - } - else - { - lblStatus.Text = Language.strNoUpdateAvailable; - lblStatus.ForeColor = Color.ForestGreen; - - if (_appUpdate.CurrentUpdateInfo == null) return; - var updateInfo = _appUpdate.CurrentUpdateInfo; - if (!updateInfo.IsValid || updateInfo.Version == null) return; - lblLatestVersion.Text = updateInfo.Version.ToString(); - lblLatestVersionLabel.Visible = true; - lblLatestVersion.Visible = true; - } - } - catch (Exception ex) - { - lblStatus.Text = Language.strUpdateCheckFailedLabel; - lblStatus.ForeColor = Color.OrangeRed; - - Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateCheckCompleteFailed, ex); - } - } - - private void SetVisibilityOfUpdateControls(bool visible) - { - lblChangeLogLabel.Visible = visible; - txtChangeLog.Visible = visible; - btnDownload.Visible = visible; - prgbDownload.Visible = visible; + _appUpdate.GetUpdateInfoAsync(); } - private void GetChangeLogCompleted(object sender, AsyncCompletedEventArgs e) - { - if (InvokeRequired) - { - var myDelegate = new AsyncCompletedEventHandler(GetChangeLogCompleted); - Invoke(myDelegate, sender, e); - return; - } - - try - { - _appUpdate.GetChangeLogCompletedEvent -= GetChangeLogCompleted; - - if (e.Cancelled) - return; - if (e.Error != null) - throw e.Error; - - txtChangeLog.Text = _appUpdate.ChangeLog.Replace("\n", Environment.NewLine); + private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) + { + if (InvokeRequired) + { + var myDelegate = new AsyncCompletedEventHandler(GetUpdateInfoCompleted); + Invoke(myDelegate, sender, e); + return; } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateGetChangeLogFailed, ex); - } - } - private void DownloadUpdate() - { - try - { - btnDownload.Enabled = false; - prgbDownload.Visible = true; - prgbDownload.Value = 0; + try + { + _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; - if (_isUpdateDownloadHandlerDeclared == false) - { - _appUpdate.DownloadUpdateProgressChangedEvent += DownloadUpdateProgressChanged; - _appUpdate.DownloadUpdateCompletedEvent += DownloadUpdateCompleted; - _isUpdateDownloadHandlerDeclared = true; - } + lblInstalledVersion.Text = Application.ProductVersion; + lblInstalledVersion.Visible = true; + lblInstalledVersionLabel.Visible = true; + btnCheckForUpdate.Visible = true; + + if (e.Cancelled) + { + return; + } + + if (e.Error != null) + { + throw e.Error; + } + + if (_appUpdate.IsUpdateAvailable()) + { + lblStatus.Text = Language.strUpdateAvailable; + lblStatus.ForeColor = Color.OrangeRed; + SetVisibilityOfUpdateControls(true); + + var updateInfo = _appUpdate.CurrentUpdateInfo; + lblLatestVersion.Text = updateInfo.Version.ToString(); + lblLatestVersionLabel.Visible = true; + lblLatestVersion.Visible = true; + + if (updateInfo.ImageAddress == null || string.IsNullOrEmpty(updateInfo.ImageAddress.ToString())) + { + pbUpdateImage.Visible = false; + } + else + { + pbUpdateImage.ImageLocation = updateInfo.ImageAddress.ToString(); + pbUpdateImage.Tag = updateInfo.ImageLinkAddress; + pbUpdateImage.Visible = true; + } + + _appUpdate.GetChangeLogCompletedEvent += GetChangeLogCompleted; + _appUpdate.GetChangeLogAsync(); + + btnDownload.Focus(); + } + else + { + lblStatus.Text = Language.strNoUpdateAvailable; + lblStatus.ForeColor = Color.ForestGreen; + + if (_appUpdate.CurrentUpdateInfo == null) return; + var updateInfo = _appUpdate.CurrentUpdateInfo; + if (!updateInfo.IsValid || updateInfo.Version == null) return; + lblLatestVersion.Text = updateInfo.Version.ToString(); + lblLatestVersionLabel.Visible = true; + lblLatestVersion.Visible = true; + } + } + catch (Exception ex) + { + lblStatus.Text = Language.strUpdateCheckFailedLabel; + lblStatus.ForeColor = Color.OrangeRed; + + Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateCheckCompleteFailed, ex); + } + } + + private void SetVisibilityOfUpdateControls(bool visible) + { + lblChangeLogLabel.Visible = visible; + txtChangeLog.Visible = visible; + btnDownload.Visible = visible; + prgbDownload.Visible = visible; + } + + private void GetChangeLogCompleted(object sender, AsyncCompletedEventArgs e) + { + if (InvokeRequired) + { + var myDelegate = new AsyncCompletedEventHandler(GetChangeLogCompleted); + Invoke(myDelegate, sender, e); + return; + } + + try + { + _appUpdate.GetChangeLogCompletedEvent -= GetChangeLogCompleted; + + if (e.Cancelled) + return; + if (e.Error != null) + throw e.Error; + + txtChangeLog.Text = _appUpdate.ChangeLog.Replace("\n", Environment.NewLine); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateGetChangeLogFailed, ex); + } + } + + private void DownloadUpdate() + { + try + { + btnDownload.Enabled = false; + prgbDownload.Visible = true; + prgbDownload.Value = 0; + + if (_isUpdateDownloadHandlerDeclared == false) + { + _appUpdate.DownloadUpdateProgressChangedEvent += DownloadUpdateProgressChanged; + _appUpdate.DownloadUpdateCompletedEvent += DownloadUpdateCompleted; + _isUpdateDownloadHandlerDeclared = true; + } + + _appUpdate.DownloadUpdateAsync(); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateDownloadFailed, ex); + } + } - _appUpdate.DownloadUpdateAsync(); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateDownloadFailed, ex); - } - } #endregion #region Events - private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - prgbDownload.Value = e.ProgressPercentage; - } - private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) - { - try - { - btnDownload.Enabled = true; - prgbDownload.Visible = false; + private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { + prgbDownload.Value = e.ProgressPercentage; + } - if (e.Cancelled) + private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) + { + try + { + btnDownload.Enabled = true; + prgbDownload.Visible = false; + + if (e.Cancelled) return; - if (e.Error != null) - throw e.Error; + if (e.Error != null) + throw e.Error; - if (Runtime.IsPortableEdition) - MessageBox.Show(Language.strUpdatePortableDownloadComplete, Language.strMenuCheckForUpdates, MessageBoxButtons.OK, MessageBoxIcon.Information); - else - { - if (MessageBox.Show(Language.strUpdateDownloadComplete, Language.strMenuCheckForUpdates, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) - { - Shutdown.Quit(_appUpdate.CurrentUpdateInfo.UpdateFilePath); - } - else - { - File.Delete(_appUpdate.CurrentUpdateInfo.UpdateFilePath); - } - } - } - catch (Exception ex) - { + if (Runtime.IsPortableEdition) + MessageBox.Show(Language.strUpdatePortableDownloadComplete, Language.strMenuCheckForUpdates, + MessageBoxButtons.OK, MessageBoxIcon.Information); + else + { + if (MessageBox.Show(Language.strUpdateDownloadComplete, Language.strMenuCheckForUpdates, + MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) + { + Shutdown.Quit(_appUpdate.CurrentUpdateInfo.UpdateFilePath); + } + else + { + File.Delete(_appUpdate.CurrentUpdateInfo.UpdateFilePath); + } + } + } + catch (Exception ex) + { Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateDownloadCompleteFailed, ex); Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, ex.Message); } - } + } + #endregion - } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/WindowList.cs b/mRemoteV1/UI/WindowList.cs index 7f36cc1b1..bf254c6ba 100644 --- a/mRemoteV1/UI/WindowList.cs +++ b/mRemoteV1/UI/WindowList.cs @@ -4,85 +4,90 @@ using mRemoteNG.UI.Window; namespace mRemoteNG.UI { - public class WindowList : CollectionBase - { + public class WindowList : CollectionBase + { #region Public Properties + public BaseWindow this[object Index] - { - get - { - CleanUp(); - if (Index is BaseWindow) + { + get + { + CleanUp(); + if (Index is BaseWindow) return IndexByObject(Index); - if (Index is int) - return IndexByNumber(Convert.ToInt32(Index)); + if (Index is int) + return IndexByNumber(Convert.ToInt32(Index)); return null; - } - } - - public new int Count - { - get - { - CleanUp(); - return List.Count; - } - } - #endregion - - #region Public Methods - public void Add(BaseWindow uiWindow) - { - List.Add(uiWindow); - //AddHandler uiWindow.FormClosing, AddressOf uiFormClosing - } - - public void AddRange(BaseWindow[] uiWindow) - { - foreach (var uW in uiWindow) - { - List.Add(uW); - } - } - - public void Remove(BaseWindow uiWindow) - { - List.Remove(uiWindow); - } - - public BaseWindow FromString(string uiWindow) - { - CleanUp(); - for (var i = 0; i < List.Count; i++) - { - if (this[i].Text == uiWindow.Replace("&", "&&")) - { - return this[i]; - } - } - - return null; - } - #endregion - + } + } - private void CleanUp() - { - for (var i = 0; i <= List.Count - 1; i++) - { - if (i > List.Count - 1) - { - CleanUp(); - return; - } - var baseWindow = List[i] as BaseWindow; - if (baseWindow != null && !baseWindow.IsDisposed) continue; - List.RemoveAt(i); - CleanUp(); - return; - } - } + public new int Count + { + get + { + CleanUp(); + return List.Count; + } + } + + #endregion + + #region Public Methods + + public void Add(BaseWindow uiWindow) + { + List.Add(uiWindow); + //AddHandler uiWindow.FormClosing, AddressOf uiFormClosing + } + + public void AddRange(BaseWindow[] uiWindow) + { + foreach (var uW in uiWindow) + { + List.Add(uW); + } + } + + public void Remove(BaseWindow uiWindow) + { + List.Remove(uiWindow); + } + + public BaseWindow FromString(string uiWindow) + { + CleanUp(); + for (var i = 0; i < List.Count; i++) + { + if (this[i].Text == uiWindow.Replace("&", "&&")) + { + return this[i]; + } + } + + return null; + } + + #endregion + + + private void CleanUp() + { + for (var i = 0; i <= List.Count - 1; i++) + { + if (i > List.Count - 1) + { + CleanUp(); + return; + } + + var baseWindow = List[i] as BaseWindow; + if (baseWindow != null && !baseWindow.IsDisposed) continue; + List.RemoveAt(i); + CleanUp(); + return; + } + } private BaseWindow IndexByObject(object Index) { @@ -108,12 +113,12 @@ namespace mRemoteNG.UI throw new ArgumentOutOfRangeException(e.ParamName, e.ActualValue, "Index was out of bounds"); } } - + /* private void uiFormClosing(object sender, FormClosingEventArgs e) { List.Remove(sender); } */ - } + } } \ No newline at end of file diff --git a/mRemoteV1/UI/WindowType.cs b/mRemoteV1/UI/WindowType.cs index 3b320aaa3..4921365d7 100644 --- a/mRemoteV1/UI/WindowType.cs +++ b/mRemoteV1/UI/WindowType.cs @@ -1,21 +1,21 @@ namespace mRemoteNG.UI { - public enum WindowType - { - Tree = 0, - Connection = 1, - Config = 2, - ErrorsAndInfos = 4, - ScreenshotManager = 5, - Options = 6, - About = 8, - Update = 9, - SSHTransfer = 10, - ActiveDirectoryImport = 11, - Help = 12, - ExternalApps = 13, - PortScan = 14, - UltraVNCSC = 16, - ComponentsCheck = 17, - } + public enum WindowType + { + Tree = 0, + Connection = 1, + Config = 2, + ErrorsAndInfos = 4, + ScreenshotManager = 5, + Options = 6, + About = 8, + Update = 9, + SSHTransfer = 10, + ActiveDirectoryImport = 11, + Help = 12, + ExternalApps = 13, + PortScan = 14, + UltraVNCSC = 16, + ComponentsCheck = 17, + } } \ No newline at end of file diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index c9d603bde..2299a9ca9 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -1,746 +1,759 @@ - + + - -
- -
- - -
-
- - - - - - - - - - + +
+ +
+ + +
+
+ + - - - - + + + + + + + - - - - - - - - - - - - + + + + - - - - 0, 0 - - - 0, 0 - - - Normal - - - False - - - True - - - - - - True - - - True - - - True - - - False - - - False - - - - - - True - - - True - - - False - - - False - - - True - - - False - - - False - - - noinfo - - - - - - - - - - - - False - - - True - - - False - - - False - - - False - - - - - - 80 - - - False - - - - - - - - - - - - RDP - - - Default Settings - - - False - - - FitToWindow - - - Colors16Bit - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - DoNotPlay - - - 2 - - - False - - - False - - - False - - - 0 - - - False - - - True - - - 0, 0 - - - Bottom - - - True - - - 3, 24 - - - Top - - - False - - - False - - - - - - - - - - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - EncrBasic - - - False - - - - - - - - - False - - - False - - - False - - - True - - - False - - - False - - - AuthVNC - - - ColNormal - - - SmartSAspect - - - False - - - CompNone - - - EncHextile - - - - - - - - - 0 - - - ProxyNone - - - - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - NoAuth - - - False - - - 5500 - - - False - - - - - - IE - - - False - - - - - - False - - - False - - - - - - False - - - - - - False - - - False - - - 14 - - - 1980-01-01 - - - False - - - Never - - - Yes - - - mRemoteNG - - - False - - - False - - - False - - - False - - - False - - - False - - - 5 - - - - - - - - - - - - - - - - - - False - - - False - - - False - - - False - - - 4 - - - mRemoteNG - - - 10 - - - {0}.{1:yyyyMMdd-HHmmssffff}.backup - - - False - - - True - - - False - - - False - - - release - - - - - - True - - - - - - - - - True - - - - - - True - - - False - - - False - - - RDP - - - 9/9, 33/8 - - - 9/8, 34/8 - - - False - - - 20 - - - AES - - - GCM - - - 1000 - - - Dynamic - - - False - - - 0 - - - False - - - False - - - False - - - False - - - 00000000-0000-0000-0000-000000000000 - - - - - - False - - - True - - - True - - - True - - - False - - - False - - - True - - - True - - - False - - - False - - - False - - - False - - - True - - - True - - - True - - - - - - - - - - - - General - - - True - - - False - - - False - - - False - - - False - - - 0, 0 - - - - - - False - - - False - - - General - - - False - - - False - - - True - - - False - - - - - - - https://mremoteng.org/ - - - cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + 0, 0 + + + 0, 0 + + + Normal + + + False + + + True + + + + + + True + + + True + + + True + + + False + + + False + + + + + + True + + + True + + + False + + + False + + + True + + + False + + + False + + + noinfo + + + + + + + + + + + + False + + + True + + + False + + + False + + + False + + + + + + 80 + + + False + + + + + + + + + + + + RDP + + + Default Settings + + + False + + + FitToWindow + + + Colors16Bit + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + DoNotPlay + + + 2 + + + False + + + False + + + False + + + 0 + + + False + + + True + + + 0, 0 + + + Bottom + + + True + + + 3, 24 + + + Top + + + False + + + False + + + + + + + + + + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + EncrBasic + + + False + + + + + + + + + False + + + False + + + False + + + True + + + False + + + False + + + AuthVNC + + + ColNormal + + + SmartSAspect + + + False + + + CompNone + + + EncHextile + + + + + + + + + 0 + + + ProxyNone + + + + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + False + + + NoAuth + + + False + + + 5500 + + + False + + + + + + IE + + + False + + + + + + False + + + False + + + + + + False + + + + + + False + + + False + + + 14 + + + 1980-01-01 + + + False + + + Never + + + Yes + + + mRemoteNG + + + False + + + False + + + False + + + False + + + False + + + False + + + 5 + + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + 4 + + + mRemoteNG + + + 10 + + + {0}.{1:yyyyMMdd-HHmmssffff}.backup + + + False + + + True + + + False + + + False + + + release + + + + + + True + + + + + + + + + True + + + + + + True + + + False + + + False + + + RDP + + + 9/9, 33/8 + + + 9/8, 34/8 + + + False + + + 20 + + + AES + + + GCM + + + 1000 + + + Dynamic + + + False + + + 0 + + + False + + + False + + + False + + + False + + + 00000000-0000-0000-0000-000000000000 + + + + + + False + + + True + + + True + + + True + + + False + + + False + + + True + + + True + + + False + + + False + + + False + + + False + + + True + + + True + + + True + + + + + + + + + + + + General + + + True + + + False + + + False + + + False + + + False + + + 0, 0 + + + + + + False + + + False + + + General + + + False + + + False + + + True + + + False + + + + + + + https://mremoteng.org/ + + + cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mRemoteV1/packages.config b/mRemoteV1/packages.config index f64e2f546..0ad6b1a66 100644 --- a/mRemoteV1/packages.config +++ b/mRemoteV1/packages.config @@ -1,13 +1,14 @@  + - - - - - - - - - - + + + + + + + + + + \ No newline at end of file
/// Required designer variable. diff --git a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs index a0f1c6c63..7fb91b4e5 100644 --- a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs +++ b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs @@ -3,12 +3,11 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Forms.Input { - public partial class FrmInputBox : Form + public sealed partial class FrmInputBox : Form { - private readonly DisplayProperties _display = new DisplayProperties(); internal string returnValue; - public FrmInputBox(string title, string promptText, ref string value) + public FrmInputBox(string title, string promptText, string value) { InitializeComponent(); diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index e07feffca..96ca5a163 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -173,8 +173,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void btnThemeNew_Click(object sender, EventArgs e) { - var name = _themeManager.ActiveTheme.Name; - using (var frmInputBox = new FrmInputBox(Language.strOptionsThemeNewThemeCaption, Language.strOptionsThemeNewThemeText, ref name)) + using (var frmInputBox = new FrmInputBox(Language.strOptionsThemeNewThemeCaption, Language.strOptionsThemeNewThemeText, _themeManager.ActiveTheme.Name)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK) return; diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.cs b/mRemoteV1/UI/Forms/frmChoosePanel.cs index 0f7f38a06..edc760c81 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.cs @@ -68,8 +68,7 @@ namespace mRemoteNG.UI.Forms private void btnNew_Click(object sender, System.EventArgs e) { - var pnlName = Language.strNewPanel; - using (var frmInputBox = new FrmInputBox(Language.strNewPanel, Language.strPanelName + ":", ref pnlName)) + using (var frmInputBox = new FrmInputBox(Language.strNewPanel, Language.strPanelName + ":", Language.strNewPanel)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK || string.IsNullOrEmpty(frmInputBox.returnValue)) return; diff --git a/mRemoteV1/UI/Menu/MainFileMenu.cs b/mRemoteV1/UI/Menu/MainFileMenu.cs index 300dcdb3e..31ee707d2 100644 --- a/mRemoteV1/UI/Menu/MainFileMenu.cs +++ b/mRemoteV1/UI/Menu/MainFileMenu.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using mRemoteNG.App; diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index 042de3769..4c5e41a51 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -13,7 +13,7 @@ namespace mRemoteNG.UI.Panels { public class PanelAdder { - public Form AddPanel(string title = "", bool noTabber = false) + public Form AddPanel(string title = "") { try { @@ -21,7 +21,7 @@ namespace mRemoteNG.UI.Panels BuildConnectionWindowContextMenu(connectionForm); SetConnectionWindowTitle(title, connectionForm); ShowConnectionWindow(connectionForm); - PrepareTabControllerSupport(noTabber, connectionForm); + PrepareTabSupport(connectionForm); return connectionForm; } catch (Exception ex) @@ -42,7 +42,7 @@ namespace mRemoteNG.UI.Panels connectionForm.Show(FrmMain.Default.pnlDock, DockState.Document); } - private static void PrepareTabControllerSupport(bool noTabber, ConnectionWindow connectionForm) + private static void PrepareTabSupport(ConnectionWindow connectionForm) { Runtime.WindowList.Add(connectionForm); } @@ -94,13 +94,9 @@ namespace mRemoteNG.UI.Panels { var conW = (ConnectionWindow)((ToolStripMenuItem)sender).Tag; - var nTitle = ""; - new FrmInputBox(Language.strNewTitle, Language.strNewTitle + ":", ref nTitle); - - if (!string.IsNullOrEmpty(nTitle)) - { - conW.SetFormText(nTitle.Replace("&", "&&")); - } + using (var newTitle = new FrmInputBox(Language.strNewTitle, Language.strNewTitle + ":", "")) + if (newTitle.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(newTitle.returnValue)) + conW.SetFormText(newTitle.returnValue.Replace("&", "&&")); } catch (Exception ex) { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 361def12a..5444f0212 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -676,8 +676,7 @@ namespace mRemoteNG.UI.Window { var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) return; - var newTitle = ((ConnectionTab)interfaceControl.Parent).TabText; - using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ref newTitle)) + using (var frmInputBox = new FrmInputBox(Language.strNewTitle, Language.strNewTitle, ((ConnectionTab)interfaceControl.Parent).TabText)) { var dr = frmInputBox.ShowDialog(); if (dr != DialogResult.OK) return; From 6fed9375d30fc106baa7a65329adc56ea870ed30 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 10:52:00 -0500 Subject: [PATCH 054/157] minor theming fix --- mRemoteV1/UI/Controls/Base/NGTextBox.cs | 16 +++++++++------- mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs | 1 - mRemoteV1/UI/Window/AboutWindow.cs | 1 - 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mRemoteV1/UI/Controls/Base/NGTextBox.cs b/mRemoteV1/UI/Controls/Base/NGTextBox.cs index 0356bf1de..4664d14bf 100644 --- a/mRemoteV1/UI/Controls/Base/NGTextBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGTextBox.cs @@ -1,6 +1,7 @@ -using mRemoteNG.Themes; -using System; +using System; +using System.Drawing; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls.Base { @@ -11,7 +12,8 @@ namespace mRemoteNG.UI.Controls.Base private ThemeManager _themeManager; public NGTextBox() - { + { + InitializeComponent(); ThemeManager.getInstance().ThemeChanged += OnCreateControl; } @@ -21,7 +23,7 @@ namespace mRemoteNG.UI.Controls.Base _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor(ReadOnly ? "TextBox_Disabled_Background" : "TextBox_Background"); Invalidate(); } @@ -52,12 +54,12 @@ namespace mRemoteNG.UI.Controls.Base private void InitializeComponent() { - this.SuspendLayout(); + SuspendLayout(); // // NGTextBox // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ResumeLayout(false); + Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); + ResumeLayout(false); } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs index ad2f3d61b..d7af7c9be 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using System.Drawing; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.App.Info; diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index 9f381e96c..3b1a92d21 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -3,7 +3,6 @@ using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; using System.IO; using System.Text; -using System.Text.RegularExpressions; using mRemoteNG.App; using mRemoteNG.App.Info; From 3ea8a75b3ff734d4b60055bf53229c2be1de84cd Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 11:46:14 -0500 Subject: [PATCH 055/157] minor fixes/cleanup --- mRemoteV1/Themes/ThemeManager.cs | 5 +-- mRemoteV1/UI/Forms/frmMain.cs | 2 +- mRemoteV1/UI/Tabs/ConnectionTab.cs | 2 +- mRemoteV1/UI/Window/ConnectionWindow.cs | 55 ++++++++++++++----------- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 28922869e..d1b0b6683 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -4,7 +4,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; using System.IO; using System.Linq; using WeifenLuo.WinFormsUI.Docking; @@ -63,12 +62,12 @@ namespace mRemoteNG.Themes if (themes != null) return themes.Values.OfType().ToList(); themes = new Hashtable(); - //Load the files in theme folder first, to incluide vstheme light as default + //Load the files in theme folder first, to include vstheme light as default var themePath = App.Info.SettingsFileInfo.ThemeFolder; if (themePath == null) return themes.Values.OfType().ToList(); try { - //In install mode first time is necesary to copy the themes folder + //In install mode first time is necessary to copy the themes folder if (!Directory.Exists(themePath)) { Directory.CreateDirectory(themePath); diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 343c9c956..9d31602de 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -195,7 +195,7 @@ namespace mRemoteNG.UI.Forms panelAdder.AddPanel(panelName); }*/ - FrmSplashScreen frmSplashScreen = FrmSplashScreen.getInstance(); + var frmSplashScreen = FrmSplashScreen.getInstance(); frmSplashScreen.Close(); } diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 7579faadb..aa237238e 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -13,7 +13,7 @@ namespace mRemoteNG.UI.Tabs { public partial class ConnectionTab : DockContent { - public bool silentClose { get; set; } = false; + public bool silentClose { get; set; } public ConnectionTab() { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 5444f0212..781819d68 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -16,7 +16,7 @@ using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.TaskDialog; using WeifenLuo.WinFormsUI.Docking; -using ConnectionTab = mRemoteNG.UI.Tabs.ConnectionTab; +using mRemoteNG.UI.Tabs; namespace mRemoteNG.UI.Window { @@ -90,7 +90,13 @@ namespace mRemoteNG.UI.Window { try { - var conTab = new ConnectionTab {Tag = connectionInfo}; + var conTab = new ConnectionTab + { + Tag = connectionInfo, + DockAreas = DockAreas.Document | DockAreas.Float, + ShowIcon = true, + Icon = ConnectionIcon.FromString(connectionInfo.Icon) + }; //Set the connection text based on name and preferences string titleText; @@ -122,11 +128,7 @@ namespace mRemoteNG.UI.Window conTab.TabText = titleText; conTab.TabPageContextMenuStrip = cmenTab; - //Fix MagicRemove, i dont see no icons -.- - conTab.Icon = ConnectionIcon.FromString(connectionInfo.Icon); - //Show the tab - conTab.DockAreas = DockAreas.Document | DockAreas.Float; conTab.Show(connDock,DockState.Document); conTab.Focus(); return conTab; @@ -204,29 +206,34 @@ namespace mRemoteNG.UI.Window private bool _floatHandlersAdded; private void Connection_DockStateChanged(object sender, EventArgs e) { - if (DockState == DockState.Float) + switch (DockState) { - if (_documentHandlersAdded) + case DockState.Float: { - FrmMain.Default.ResizeBegin -= Connection_ResizeBegin; - FrmMain.Default.ResizeEnd -= Connection_ResizeEnd; - _documentHandlersAdded = false; + if (_documentHandlersAdded) + { + FrmMain.Default.ResizeBegin -= Connection_ResizeBegin; + FrmMain.Default.ResizeEnd -= Connection_ResizeEnd; + _documentHandlersAdded = false; + } + DockHandler.FloatPane.FloatWindow.ResizeBegin += Connection_ResizeBegin; + DockHandler.FloatPane.FloatWindow.ResizeEnd += Connection_ResizeEnd; + _floatHandlersAdded = true; + break; } - DockHandler.FloatPane.FloatWindow.ResizeBegin += Connection_ResizeBegin; - DockHandler.FloatPane.FloatWindow.ResizeEnd += Connection_ResizeEnd; - _floatHandlersAdded = true; - } - else if (DockState == DockState.Document) - { - if (_floatHandlersAdded) + case DockState.Document: { - DockHandler.FloatPane.FloatWindow.ResizeBegin -= Connection_ResizeBegin; - DockHandler.FloatPane.FloatWindow.ResizeEnd -= Connection_ResizeEnd; - _floatHandlersAdded = false; + if (_floatHandlersAdded) + { + DockHandler.FloatPane.FloatWindow.ResizeBegin -= Connection_ResizeBegin; + DockHandler.FloatPane.FloatWindow.ResizeEnd -= Connection_ResizeEnd; + _floatHandlersAdded = false; + } + FrmMain.Default.ResizeBegin += Connection_ResizeBegin; + FrmMain.Default.ResizeEnd += Connection_ResizeEnd; + _documentHandlersAdded = true; + break; } - FrmMain.Default.ResizeBegin += Connection_ResizeBegin; - FrmMain.Default.ResizeEnd += Connection_ResizeEnd; - _documentHandlersAdded = true; } } From e626b65f5df1688c4e345d5fd9cc83f870a18b54 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 14:03:38 -0500 Subject: [PATCH 056/157] speed up Options Page load --- mRemoteV1/UI/Controls/Base/NGCheckBox.cs | 10 ++--- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 42 +++++++++++++------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs index 3b1c81dee..6550d2157 100644 --- a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs @@ -1,6 +1,6 @@ -using mRemoteNG.Themes; -using System.Drawing; +using System.Drawing; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls.Base { @@ -131,12 +131,12 @@ namespace mRemoteNG.UI.Controls.Base private void InitializeComponent() { - this.SuspendLayout(); + SuspendLayout(); // // NGCheckBox // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ResumeLayout(false); + Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); + ResumeLayout(false); } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 96ca5a163..9e4f90857 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -94,6 +94,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void SaveSettings() { + // Save the theme on exit so we don't run into unexpected results while modifying... + _themeManager.ActiveTheme = (ThemeInfo)cboTheme.SelectedItem; + base.SaveSettings(); foreach(var updatedTheme in modifiedThemes) { @@ -119,19 +122,31 @@ namespace mRemoteNG.UI.Forms.OptionsPages { btnThemeNew.Enabled = false; btnThemeDelete.Enabled = false; - if (!_themeManager.ThemingActive) return; - _themeManager.ActiveTheme = (ThemeInfo)cboTheme.SelectedItem; - listPalette.ClearObjects(); - if (!_themeManager.ActiveTheme.IsExtendable || !_themeManager.ThemingActive) return; - btnThemeNew.Enabled = true; - listPalette.ClearObjects(); - listPalette.Enabled = false; + + // don't display listPalette if it's not an Extendable theme... listPalette.CellClick -= ListPalette_CellClick; - ColorMeList(); - if (_themeManager.ActiveTheme.IsThemeBase) return; - listPalette.Enabled = true; + listPalette.Enabled = false; + listPalette.Visible = false; + + if (!_themeManager.ThemingActive) return; + + btnThemeNew.Enabled = true; + + var selectedTheme = (ThemeInfo)cboTheme.SelectedItem; + + if (selectedTheme.IsExtendable) + { + // it's Extendable, so now we can do this more expensive operations... + listPalette.ClearObjects(); + ColorMeList(selectedTheme); + listPalette.Enabled = true; + listPalette.Visible = true; + listPalette.CellClick += ListPalette_CellClick; + } + + if (selectedTheme.IsThemeBase) return; + btnThemeDelete.Enabled = true; - listPalette.CellClick += ListPalette_CellClick; } @@ -165,9 +180,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages } - private void ColorMeList() + private void ColorMeList(ThemeInfo ti) { - foreach (var colorElem in _themeManager.ActiveTheme.ExtendedPalette.ExtColorPalette) + foreach (var colorElem in ti.ExtendedPalette.ExtColorPalette) listPalette.AddObject(new PseudoKeyColor(colorElem.Key, colorElem.Value)); } @@ -210,7 +225,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages { if (themeEnableChk.Checked) { - if(_themeManager.ThemesCount > 0) { _themeManager.ThemingActive = true; From df36523d6c2c3c271d194ae4e5b12851338bea9f Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 14:27:24 -0500 Subject: [PATCH 057/157] minor cleanup --- .../UI/Forms/OptionsPages/OptionsPage.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index bb5c7855f..0a1552aa2 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Drawing; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Forms.OptionsPages { @@ -8,8 +9,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages { protected OptionsPage() { - //InitializeComponent(); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + InitializeComponent(); + ThemeManager.getInstance().ThemeChanged += ApplyTheme; } #region Public Properties @@ -59,23 +60,23 @@ namespace mRemoteNG.UI.Forms.OptionsPages protected virtual void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + if (!ThemeManager.getInstance().ThemingActive) return; + BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); Invalidate(); } private void InitializeComponent() { - this.SuspendLayout(); + SuspendLayout(); // // OptionsPage // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "OptionsPage"; - this.ResumeLayout(false); + AutoScaleDimensions = new SizeF(96F, 96F); + AutoScaleMode = AutoScaleMode.Dpi; + Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); + Name = "OptionsPage"; + ResumeLayout(false); } } From 1340bc9902a34b4568379cef2ce95811a39116da Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 14:50:06 -0500 Subject: [PATCH 058/157] apply themes after restart --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 9e4f90857..2f0153ec8 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Collections.Generic; using BrightIdeasSoftware; using mRemoteNG.UI.Forms.Input; +using mRemoteNG.UI.TaskDialog; namespace mRemoteNG.UI.Forms.OptionsPages { @@ -94,8 +95,16 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void SaveSettings() { - // Save the theme on exit so we don't run into unexpected results while modifying... - _themeManager.ActiveTheme = (ThemeInfo)cboTheme.SelectedItem; + // Save the theme settings form close so we don't run into unexpected results while modifying... + // Prompt the user that a restart is required to apply the new theme... + if (!Settings.Default.ThemeName.Equals(((ThemeInfo)cboTheme.SelectedItem).Name)) + { + Settings.Default.ThemeName = ((ThemeInfo)cboTheme.SelectedItem).Name; + Settings.Default.Save(); + + CTaskDialog.MessageBox("Theme Changed", "Restart Required.", "Please restart mRemoteNG to apply the selected theme.", + ETaskDialogButtons.Ok, ESysIcons.Information); + } base.SaveSettings(); foreach(var updatedTheme in modifiedThemes) From b18ffc350f9580ae1b1e00f3f61415d46297dfd1 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 14:53:24 -0500 Subject: [PATCH 059/157] clean up --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 2f0153ec8..e68d07c0d 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -209,7 +209,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages } else { - TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.Ok, TaskDialog.ESysIcons.Error, TaskDialog.ESysIcons.Information, 0); + CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, ESysIcons.Information, 0); } } } @@ -217,7 +217,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void btnThemeDelete_Click(object sender, EventArgs e) { - var res = TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.YesNo, TaskDialog.ESysIcons.Question, TaskDialog.ESysIcons.Information, 0); + var res = CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Information, 0); if (res != DialogResult.Yes) return; if (modifiedThemes.Contains(_themeManager.ActiveTheme)) @@ -241,7 +241,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages } else { - TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeErrorNoThemes, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.Ok, TaskDialog.ESysIcons.Error, TaskDialog.ESysIcons.Information, 0); + CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeErrorNoThemes, "", "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, ESysIcons.Information, 0); themeEnableChk.Checked = false; _themeManager.ThemingActive = false; cboTheme.Enabled = false; From 8a63200ab99c2d9958ce50f59c717aa675d98734 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 15:28:20 -0500 Subject: [PATCH 060/157] handle events only when theming is active --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index e68d07c0d..c3345c5b8 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -68,12 +68,12 @@ namespace mRemoteNG.UI.Forms.OptionsPages cboTheme.SelectedItem = _themeManager.ActiveTheme; cboTheme_SelectionChangeCommitted(this, new EventArgs()); cboTheme.DisplayMember = "Name"; - //Color cell formatter - listPalette.FormatCell += ListPalette_FormatCell; + //Load theming active property and disable controls if (_themeManager.ThemingActive) { themeEnableChk.Checked = true; + listPalette.FormatCell += ListPalette_FormatCell; //Color cell formatter } else { @@ -246,12 +246,15 @@ namespace mRemoteNG.UI.Forms.OptionsPages _themeManager.ThemingActive = false; cboTheme.Enabled = false; } + + listPalette.FormatCell += ListPalette_FormatCell; } else { _themeManager.ThemingActive = false; themeEnableChk.Checked = false; cboTheme.Enabled = false; + listPalette.FormatCell -= ListPalette_FormatCell; } LoadSettings(); } From 9eb15a25a5b25dcfbc05e21c819273f6dce7bce6 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 15:29:19 -0500 Subject: [PATCH 061/157] designer generated change --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs index ae4816e83..ce80421a7 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs @@ -207,7 +207,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.Controls.Add(this.tlpMain); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "ThemePage"; this.Size = new System.Drawing.Size(610, 490); ((System.ComponentModel.ISupportInitialize)(this.listPalette)).EndInit(); From e254d6978e32b1b108df5a10be53278f1cc05245 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 15:33:14 -0500 Subject: [PATCH 062/157] ActiveTheme is only saved in setting and applied on restart --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index c3345c5b8..853211d6c 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -116,7 +116,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void RevertSettings() { base.RevertSettings(); - _themeManager.ActiveTheme = _oriTheme; _themeManager.ThemingActive = _oriActiveTheming; } From 52bdf64cdb56e241f2f776b96a5ec04556cfebb2 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 16:24:16 -0500 Subject: [PATCH 063/157] removed unused variable --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 853211d6c..e30db4377 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -14,7 +14,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages #region Private Fields private readonly ThemeManager _themeManager; - private readonly ThemeInfo _oriTheme; private readonly bool _oriActiveTheming; private readonly List modifiedThemes = new List(); #endregion @@ -27,7 +26,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages if (!_themeManager.ThemingActive) return; _themeManager = ThemeManager.getInstance(); _themeManager.ThemeChanged += ApplyTheme; - _oriTheme = _themeManager.ActiveTheme; _oriActiveTheming = _themeManager.ThemingActive; } @@ -118,14 +116,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages base.RevertSettings(); _themeManager.ThemingActive = _oriActiveTheming; } - - #region Private Methods #region Event Handlers - - - private void cboTheme_SelectionChangeCommitted(object sender, EventArgs e) { btnThemeNew.Enabled = false; @@ -157,8 +150,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages btnThemeDelete.Enabled = true; } - - /// /// Edit an object, since KeyValuePair value cannot be set without creating a new object, a parallel object model exist in the list /// besides the one in the active theme, so any modification must be done to the two models @@ -224,11 +215,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages _themeManager.deleteTheme(_themeManager.ActiveTheme); LoadSettings(); } - #endregion #endregion - private void ThemeEnableChkCheckedChanged(object sender, EventArgs e) { if (themeEnableChk.Checked) From 8487dde0260d12a50a523087f0ba8562a74bf293 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 16:35:02 -0500 Subject: [PATCH 064/157] move connectiontab.designer to proper location in project also make sure it has proper DPI settings --- mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs | 13 ++- mRemoteV1/UI/Tabs/ConnectionTab.resx | 120 ++++++++++++++++++++ mRemoteV1/mRemoteV1.csproj | 7 +- 3 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 mRemoteV1/UI/Tabs/ConnectionTab.resx diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs index f1262d7d1..52f077020 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.Designer.cs @@ -28,9 +28,18 @@ /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.SuspendLayout(); + // + // ConnectionTab + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(284, 261); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Name = "ConnectionTab"; this.Text = "ConnectionTab"; + this.ResumeLayout(false); + } #endregion diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.resx b/mRemoteV1/UI/Tabs/ConnectionTab.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/mRemoteV1/UI/Tabs/ConnectionTab.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 9abcba0c8..a1251c710 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -686,7 +686,9 @@ Form - + + ConnectionTab.cs + Component @@ -979,6 +981,9 @@ UnhandledExceptionWindow.cs + + ConnectionTab.cs + CommandButton.cs From 4ac51a7e582d1d4e437b6548b89a02e18716ce6d Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 17:01:41 -0500 Subject: [PATCH 065/157] Tab ICONS!!!! --- mRemoteV1/UI/Window/ConnectionWindow.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 781819d68..4df04dab8 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -42,6 +42,7 @@ namespace mRemoteNG.UI.Window Text = formText; TabText = formText; connDock.DocumentStyle = DocumentStyle.DockingWindow; + connDock.ShowDocumentIcon = true; } private InterfaceControl GetInterfaceControl() @@ -90,14 +91,6 @@ namespace mRemoteNG.UI.Window { try { - var conTab = new ConnectionTab - { - Tag = connectionInfo, - DockAreas = DockAreas.Document | DockAreas.Float, - ShowIcon = true, - Icon = ConnectionIcon.FromString(connectionInfo.Icon) - }; - //Set the connection text based on name and preferences string titleText; if (Settings.Default.ShowProtocolOnTabs) @@ -125,8 +118,14 @@ namespace mRemoteNG.UI.Window titleText = titleText.Replace("&", "&&"); - conTab.TabText = titleText; - conTab.TabPageContextMenuStrip = cmenTab; + var conTab = new ConnectionTab + { + Tag = connectionInfo, + DockAreas = DockAreas.Document | DockAreas.Float, + Icon = ConnectionIcon.FromString(connectionInfo.Icon), + TabText = titleText, + TabPageContextMenuStrip = cmenTab + }; //Show the tab conTab.Show(connDock,DockState.Document); From 9fef6dd2d3400091bcc3720816935f766bbbf666 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Mon, 7 Jan 2019 17:34:44 -0500 Subject: [PATCH 066/157] minor clean up --- mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs | 2 -- mRemoteV1/UI/Forms/frmOptions.cs | 9 +++++++-- 10 files changed, 7 insertions(+), 12 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs index 466a83787..218432eea 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using System.IO; using System.Windows.Forms; using mRemoteNG.App; diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs index d9da8cd25..8cae1d2ed 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.Tools; diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs index a2af48da2..ec872aee5 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using mRemoteNG.Config; namespace mRemoteNG.UI.Forms.OptionsPages diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs index 25b7e1f3b..b108111b4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using mRemoteNG.App; using mRemoteNG.Security.SymmetricEncryption; diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs index 01319c629..a8ab93351 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Drawing; using System.IO; using System.Windows.Forms; using mRemoteNG.App; diff --git a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs index 417a68d3c..cdb184b4b 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using System.Drawing; using mRemoteNG.Security; namespace mRemoteNG.UI.Forms.OptionsPages diff --git a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs index 7f15ca529..e7705d167 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using mRemoteNG.App; using mRemoteNG.Config.Connections; using mRemoteNG.Config.Connections.Multiuser; diff --git a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs index 22b9cc587..a8b4db3ff 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; namespace mRemoteNG.UI.Forms.OptionsPages { diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs index 2a8508bab..32474bd4b 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs @@ -1,5 +1,3 @@ -using System.Drawing; - namespace mRemoteNG.UI.Forms.OptionsPages { public sealed partial class TabsPanelsPage diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index 25c2522f8..22f5a4d28 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -32,7 +32,10 @@ namespace mRemoteNG.UI.Forms FontOverrider.FontOverride(this); AddOptionsPagesToListView(); SetInitiallyActivatedPage(); - ApplyLanguage(); + // ApplyLanguage(); + // Handle the main page here and the individual pages in + // AddOptionsPagesToListView() -- one less foreach loop.... + Text = Language.strOptionsPageTitle; ApplyTheme(); Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; lstOptionPages.SelectedIndexChanged += LstOptionPages_SelectedIndexChanged; @@ -46,6 +49,7 @@ namespace mRemoteNG.UI.Forms ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } +#if false private void ApplyLanguage() { Text = Language.strOptionsPageTitle; @@ -54,7 +58,7 @@ namespace mRemoteNG.UI.Forms optionPage.ApplyLanguage(); } } - +#endif private void CompileListOfOptionsPages() { _pages = new Dictionary @@ -80,6 +84,7 @@ namespace mRemoteNG.UI.Forms foreach (var page in _pages.Select(keyValuePair => keyValuePair.Value)) { + page.ApplyLanguage(); page.LoadSettings(); lstOptionPages.AddObject(page); } From 174dfbe95ee3c340ddc344fb7a732720312a6562 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 7 Jan 2019 19:07:53 -0500 Subject: [PATCH 067/157] Double click to close tab initial implementation With the setting DoubleClickOnTabClosesIt it will close the tab, otherwise it will undock it. Missing do nothing implementation --- mRemoteV1/Themes/MremoteNGThemeBase.cs | 2 -- mRemoteV1/Themes/ThemeManager.cs | 4 +++- mRemoteV1/UI/Tabs/ConnectionTab.cs | 27 +------------------------- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 26 +++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index 69ef11d98..3cc6d44ad 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -17,8 +17,6 @@ Measures.AutoHideSplitterSize = 3; Measures.DockPadding = 2; ShowAutoHideContentOnHover = false; - - Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); } } diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index d1b0b6683..0ae482987 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -35,9 +35,11 @@ namespace mRemoteNG.Themes private void SetActive() { if (themes[Settings.Default.ThemeName] != null) - ActiveTheme = (ThemeInfo) themes[Settings.Default.ThemeName]; + ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else ActiveTheme = DefaultTheme; + + ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); } #endregion diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index aa237238e..5d28b759c 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -48,32 +48,7 @@ namespace mRemoteNG.UI.Tabs } base.OnFormClosing(e); } - - /* [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override void WndProc(ref Message m) - { - if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) - { - base.WndProc(ref m); - - int index = HitTest(); - if (DockPane.DockPanel.AllowEndUserDocking && index != -1) - { - IDockContent content = Tabs[index].Content; - if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) - content.DockHandler.IsFloat = !content.DockHandler.IsFloat; - } - - return; - } - - base.WndProc(ref m); - return; - } - */ - - - + #region HelperFunctions public void RefreshInterfaceController() diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 2bdbb6b55..cd24d7e0b 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; +using System.Security.Permissions; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; @@ -1337,5 +1338,30 @@ namespace mRemoteNG.UI.Tabs base.OnRightToLeftChanged(e); PerformLayout(); } + + #region Native Methods + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) + { + if (Settings.Default.DoubleClickOnTabClosesIt) + { + DockPane.CloseActiveContent(); + if (PatchController.EnableMemoryLeakFix == true) + { + ContentClosed(); + } + return; + } + + } + + base.WndProc(ref m); + return; + } + + #endregion } } From 7e4003968de1b3fefe95b701d868c63558050a4f Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 7 Jan 2019 19:28:03 -0500 Subject: [PATCH 068/157] Fix broken test Try #1 -.- --- mRemoteV1/Themes/ThemeManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 0ae482987..917b56969 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -38,8 +38,8 @@ namespace mRemoteNG.Themes ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else ActiveTheme = DefaultTheme; - - ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + if(ActiveTheme != null && ActiveTheme.Theme != null) + ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); } #endregion From 190204a47f32d31964313cdcb103020bdfd97461 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 7 Jan 2019 20:01:21 -0500 Subject: [PATCH 069/157] Reverted the double click Reverted the double click as it brokes the tab looks with themes --- mRemoteV1/Themes/ThemeManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 917b56969..b21a59a4b 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -38,8 +38,8 @@ namespace mRemoteNG.Themes ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else ActiveTheme = DefaultTheme; - if(ActiveTheme != null && ActiveTheme.Theme != null) - ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + /* if(ActiveTheme != null && ActiveTheme.Theme != null) + ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory();*/ } #endregion From 27a06f6cfa73cf5153ce4e56c03d566a055a6b1b Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 7 Jan 2019 21:03:08 -0500 Subject: [PATCH 070/157] Partial fix of double clic Missing behavior on no theme scenario. Themes including default tested. --- mRemoteV1/Themes/ThemeManager.cs | 14 +- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 1249 +++++++++++++++----------- 2 files changed, 724 insertions(+), 539 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index b21a59a4b..f4d2b422e 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -37,9 +37,7 @@ namespace mRemoteNG.Themes if (themes[Settings.Default.ThemeName] != null) ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else - ActiveTheme = DefaultTheme; - /* if(ActiveTheme != null && ActiveTheme.Theme != null) - ActiveTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory();*/ + ActiveTheme = DefaultTheme; } #endregion @@ -90,7 +88,7 @@ namespace mRemoteNG.Themes var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0]; //First we load the default theme, its vs2015light - var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); + var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); themes.Add(defaultTheme.Name, defaultTheme); //Then the rest foreach (var themeFile in themeFiles) @@ -126,6 +124,14 @@ namespace mRemoteNG.Themes themes.Add(vs2015Dark.Name, vs2015Dark); var vs2015Blue = new ThemeInfo("DPSvs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); themes.Add(vs2015Blue.Name, vs2015Blue); + + //Override all the themes pane strip for custom event handling + foreach(ThemeInfo overrideTheme in themes) + { + overrideTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + } + + } } catch(Exception ex) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index cd24d7e0b..6529abc4e 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -11,8 +11,9 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Tabs { /// - /// This class is lifted from VS2005DockPaneStrip from DockPanelSuite and customized for MremoteNG + /// This class is lifted from VS2013DockPaneStrip from DockPanelSuite and customized for MremoteNG /// + [ToolboxItem(false)] internal class DockPaneStripNG : DockPaneStripBase { private class MremoteNGTab : Tab @@ -22,64 +23,77 @@ namespace mRemoteNG.UI.Tabs { } - public int TabX { get; set; } + private int m_tabX; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } - public int TabWidth { get; set; } + private int m_tabWidth; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } - public int MaxWidth { get; set; } + private int m_maxWidth; + public int MaxWidth + { + get { return m_maxWidth; } + set { m_maxWidth = value; } + } - protected internal bool Flag { get; set; } - - //private Rectangle? _rect; - - + private bool m_flag; + protected internal bool Flag + { + get { return m_flag; } + set { m_flag = value; } + } } - protected override Tab CreateTab(IDockContent content) { return new MremoteNGTab(content); } + [ToolboxItem(false)] private sealed class InertButton : InertButtonBase { - private Bitmap m_image0, m_image1; + private Bitmap _hovered, _normal, _pressed; - public InertButton(Bitmap image0, Bitmap image1) + public InertButton(Bitmap hovered, Bitmap normal, Bitmap pressed) + : base() { - m_image0 = image0; - m_image1 = image1; + _hovered = hovered; + _normal = normal; + _pressed = pressed; } - private int m_imageCategory; - public int ImageCategory + public override Bitmap Image { - get => m_imageCategory; - set - { - if (m_imageCategory == value) - return; - - m_imageCategory = value; - Invalidate(); - } + get { return _normal; } } - public override Bitmap Image => ImageCategory == 0 ? m_image0 : m_image1; + public override Bitmap HoverImage + { + get { return _hovered; } + } - public override Bitmap HoverImage => null; - - public override Bitmap PressImage => null; + public override Bitmap PressImage + { + get { return _pressed; } + } } #region Constants private const int _ToolWindowStripGapTop = 0; - private const int _ToolWindowStripGapBottom = 1; + private const int _ToolWindowStripGapBottom = 0; private const int _ToolWindowStripGapLeft = 0; private const int _ToolWindowStripGapRight = 0; private const int _ToolWindowImageHeight = 16; - private const int _ToolWindowImageWidth = 16; + private const int _ToolWindowImageWidth = 0;//16; private const int _ToolWindowImageGapTop = 3; private const int _ToolWindowImageGapBottom = 1; private const int _ToolWindowImageGapLeft = 2; @@ -91,49 +105,59 @@ namespace mRemoteNG.UI.Tabs private const int _DocumentStripGapTop = 0; private const int _DocumentStripGapBottom = 1; private const int _DocumentTabMaxWidth = 200; - private const int _DocumentButtonGapTop = 4; - private const int _DocumentButtonGapBottom = 4; + private const int _DocumentButtonGapTop = 3; + private const int _DocumentButtonGapBottom = 3; private const int _DocumentButtonGapBetween = 0; private const int _DocumentButtonGapRight = 3; - private const int _DocumentTabGapTop = 3; - private const int _DocumentTabGapLeft = 3; - private const int _DocumentTabGapRight = 3; - private const int _DocumentIconGapBottom = 2; + private const int _DocumentTabGapTop = 0;//3; + private const int _DocumentTabGapLeft = 0;//3; + private const int _DocumentTabGapRight = 0;//3; + private const int _DocumentIconGapBottom = 2;//2; private const int _DocumentIconGapLeft = 8; private const int _DocumentIconGapRight = 0; private const int _DocumentIconHeight = 16; private const int _DocumentIconWidth = 16; - private const int _DocumentTextGapRight = 3; + private const int _DocumentTextGapRight = 6; #endregion #region Members - private static Bitmap m_imageButtonClose; - private InertButton m_buttonClose; - private static Bitmap m_imageButtonWindowList; - private static Bitmap m_imageButtonWindowListOverflow; + private ContextMenuStrip m_selectMenu; + private InertButton m_buttonOverflow; private InertButton m_buttonWindowList; - private readonly ToolTip m_toolTip; + private IContainer m_components; + private ToolTip m_toolTip; private Font m_font; private Font m_boldFont; - private int m_startDisplayingTab; - private bool m_documentTabsOverflow; + private int m_startDisplayingTab = 0; + private int m_endDisplayingTab = 0; + private int m_firstDisplayingTab = 0; + private bool m_documentTabsOverflow = false; private static string m_toolTipSelect; - private static string m_toolTipClose; - private bool m_closeButtonVisible; - + private Rectangle _activeClose; + private int _selectMenuMargin = 5; + private bool m_suspendDrag = false; #endregion #region Properties - private Rectangle TabStripRectangle => Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; + private Rectangle TabStripRectangle + { + get + { + if (Appearance == DockPane.AppearanceStyle.Document) + return TabStripRectangle_Document; + else + return TabStripRectangle_ToolWindow; + } + } private Rectangle TabStripRectangle_ToolWindow { get { - var rect = ClientRectangle; + Rectangle rect = ClientRectangle; return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); } } @@ -142,8 +166,8 @@ namespace mRemoteNG.UI.Tabs { get { - var rect = ClientRectangle; - return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height - DocumentStripGapTop - ToolWindowStripGapBottom); + Rectangle rect = ClientRectangle; + return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height + DocumentStripGapTop - DocumentStripGapBottom); } } @@ -154,17 +178,17 @@ namespace mRemoteNG.UI.Tabs if (Appearance == DockPane.AppearanceStyle.ToolWindow) return TabStripRectangle; - var rectWindow = TabStripRectangle; - var x = rectWindow.X; - var y = rectWindow.Y; - var width = rectWindow.Width; - var height = rectWindow.Height; + Rectangle rectWindow = TabStripRectangle; + int x = rectWindow.X; + int y = rectWindow.Y; + int width = rectWindow.Width; + int height = rectWindow.Height; x += DocumentTabGapLeft; width -= DocumentTabGapLeft + DocumentTabGapRight + DocumentButtonGapRight + - ButtonClose.Width + + ButtonOverflow.Width + ButtonWindowList.Width + 2 * DocumentButtonGapBetween; @@ -172,49 +196,67 @@ namespace mRemoteNG.UI.Tabs } } - private ContextMenuStrip SelectMenu { get; } + private ContextMenuStrip SelectMenu + { + get { return m_selectMenu; } + } - public int SelectMenuMargin { get; set; } = 5; + public int SelectMenuMargin + { + get { return _selectMenuMargin; } + set { _selectMenuMargin = value; } + } - private static Bitmap ImageButtonClose => m_imageButtonClose ?? (m_imageButtonClose = Resources.TabExit); - - private InertButton ButtonClose + private InertButton ButtonOverflow { get { - if (m_buttonClose != null) return m_buttonClose; - m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); - m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); - m_buttonClose.Click += Close_Click; - Controls.Add(m_buttonClose); + if (m_buttonOverflow == null) + { + m_buttonOverflow = new InertButton( + DockPane.DockPanel.Theme.ImageService.DockPaneHover_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPane_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPanePress_OptionOverflow); + m_buttonOverflow.Click += new EventHandler(WindowList_Click); + Controls.Add(m_buttonOverflow); + } - return m_buttonClose; + return m_buttonOverflow; } } - private static Bitmap ImageButtonWindowList => m_imageButtonWindowList ?? (m_imageButtonWindowList = Resources.TabOption); - - private static Bitmap ImageButtonWindowListOverflow => m_imageButtonWindowListOverflow ?? (m_imageButtonWindowListOverflow = Resources.TabOverflow); - private InertButton ButtonWindowList { get { - if (m_buttonWindowList != null) return m_buttonWindowList; - m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); - m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); - m_buttonWindowList.Click += WindowList_Click; - Controls.Add(m_buttonWindowList); + if (m_buttonWindowList == null) + { + m_buttonWindowList = new InertButton( + DockPane.DockPanel.Theme.ImageService.DockPaneHover_List, + DockPane.DockPanel.Theme.ImageService.DockPane_List, + DockPane.DockPanel.Theme.ImageService.DockPanePress_List); + m_buttonWindowList.Click += new EventHandler(WindowList_Click); + Controls.Add(m_buttonWindowList); + } return m_buttonWindowList; } } - private static GraphicsPath GraphicsPath => MremoteNGAutoHideStrip.GraphicsPath; + private static GraphicsPath GraphicsPath + { + get { return MremoteNGAutoHideStrip.GraphicsPath; } + } - private IContainer Components { get; } + private IContainer Components + { + get { return m_components; } + } - private Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; + public Font TextFont + { + get { return DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; } + } private Font BoldFont { @@ -228,7 +270,7 @@ namespace mRemoteNG.UI.Tabs m_font = TextFont; m_boldFont = new Font(TextFont, FontStyle.Bold); } - else if (!Equals(m_font, TextFont)) + else if (m_font != TextFont) { m_boldFont.Dispose(); m_font = TextFont; @@ -241,7 +283,7 @@ namespace mRemoteNG.UI.Tabs private int StartDisplayingTab { - get => m_startDisplayingTab; + get { return m_startDisplayingTab; } set { m_startDisplayingTab = value; @@ -249,9 +291,17 @@ namespace mRemoteNG.UI.Tabs } } - private int EndDisplayingTab { get; set; } + private int EndDisplayingTab + { + get { return m_endDisplayingTab; } + set { m_endDisplayingTab = value; } + } - private int FirstDisplayingTab { get; set; } + private int FirstDisplayingTab + { + get { return m_firstDisplayingTab; } + set { m_firstDisplayingTab = value; } + } private bool DocumentTabsOverflow { @@ -261,105 +311,196 @@ namespace mRemoteNG.UI.Tabs return; m_documentTabsOverflow = value; - ButtonWindowList.ImageCategory = value ? 1 : 0; + SetInertButtons(); } } #region Customizable Properties - private static int ToolWindowStripGapTop => _ToolWindowStripGapTop; + private static int ToolWindowStripGapTop + { + get { return _ToolWindowStripGapTop; } + } - private static int ToolWindowStripGapBottom => _ToolWindowStripGapBottom; + private static int ToolWindowStripGapBottom + { + get { return _ToolWindowStripGapBottom; } + } - private static int ToolWindowStripGapLeft => _ToolWindowStripGapLeft; + private static int ToolWindowStripGapLeft + { + get { return _ToolWindowStripGapLeft; } + } - private static int ToolWindowStripGapRight => _ToolWindowStripGapRight; + private static int ToolWindowStripGapRight + { + get { return _ToolWindowStripGapRight; } + } - private static int ToolWindowImageHeight => _ToolWindowImageHeight; + private static int ToolWindowImageHeight + { + get { return _ToolWindowImageHeight; } + } - private static int ToolWindowImageWidth => _ToolWindowImageWidth; + private static int ToolWindowImageWidth + { + get { return _ToolWindowImageWidth; } + } - private static int ToolWindowImageGapTop => _ToolWindowImageGapTop; + private static int ToolWindowImageGapTop + { + get { return _ToolWindowImageGapTop; } + } - private static int ToolWindowImageGapBottom => _ToolWindowImageGapBottom; + private static int ToolWindowImageGapBottom + { + get { return _ToolWindowImageGapBottom; } + } - private static int ToolWindowImageGapLeft => _ToolWindowImageGapLeft; + private static int ToolWindowImageGapLeft + { + get { return _ToolWindowImageGapLeft; } + } - private static int ToolWindowImageGapRight => _ToolWindowImageGapRight; + private static int ToolWindowImageGapRight + { + get { return _ToolWindowImageGapRight; } + } - private static int ToolWindowTextGapRight => _ToolWindowTextGapRight; + private static int ToolWindowTextGapRight + { + get { return _ToolWindowTextGapRight; } + } - private static int ToolWindowTabSeperatorGapTop => _ToolWindowTabSeperatorGapTop; + private static int ToolWindowTabSeperatorGapTop + { + get { return _ToolWindowTabSeperatorGapTop; } + } - private static int ToolWindowTabSeperatorGapBottom => _ToolWindowTabSeperatorGapBottom; + private static int ToolWindowTabSeperatorGapBottom + { + get { return _ToolWindowTabSeperatorGapBottom; } + } - private static string ToolTipClose => m_toolTipClose ?? (m_toolTipClose = Language.strRadioCloseWarnExit); - - private static string ToolTipSelect => m_toolTipSelect ?? (m_toolTipSelect = Language.strTabsAndPanels); + private static string ToolTipSelect + { + get + { + if (m_toolTipSelect == null) + m_toolTipSelect = Language.strTabsAndPanels; + return m_toolTipSelect; + } + } private TextFormatFlags ToolWindowTextFormat { get { - const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.HorizontalCenter | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter; - return RightToLeft == RightToLeft.Yes - ? textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right - : textFormat; + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + else + return textFormat; } } - private static int DocumentStripGapTop => _DocumentStripGapTop; + private static int DocumentStripGapTop + { + get { return _DocumentStripGapTop; } + } - private static int DocumentStripGapBottom => _DocumentStripGapBottom; + private static int DocumentStripGapBottom + { + get { return _DocumentStripGapBottom; } + } private TextFormatFlags DocumentTextFormat { get { - const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter | - TextFormatFlags.HorizontalCenter; - return RightToLeft == RightToLeft.Yes ? textFormat | TextFormatFlags.RightToLeft : textFormat; + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft; + else + return textFormat; } } - private static int DocumentTabMaxWidth => _DocumentTabMaxWidth; + private static int DocumentTabMaxWidth + { + get { return _DocumentTabMaxWidth; } + } - private static int DocumentButtonGapTop => _DocumentButtonGapTop; + private static int DocumentButtonGapTop + { + get { return _DocumentButtonGapTop; } + } - private static int DocumentButtonGapBottom => _DocumentButtonGapBottom; + private static int DocumentButtonGapBottom + { + get { return _DocumentButtonGapBottom; } + } - private static int DocumentButtonGapBetween => _DocumentButtonGapBetween; + private static int DocumentButtonGapBetween + { + get { return _DocumentButtonGapBetween; } + } - private static int DocumentButtonGapRight => _DocumentButtonGapRight; + private static int DocumentButtonGapRight + { + get { return _DocumentButtonGapRight; } + } - private static int DocumentTabGapTop => _DocumentTabGapTop; + private static int DocumentTabGapTop + { + get { return _DocumentTabGapTop; } + } - private static int DocumentTabGapLeft => _DocumentTabGapLeft; + private static int DocumentTabGapLeft + { + get { return _DocumentTabGapLeft; } + } - private static int DocumentTabGapRight => _DocumentTabGapRight; + private static int DocumentTabGapRight + { + get { return _DocumentTabGapRight; } + } - private static int DocumentIconGapBottom => _DocumentIconGapBottom; + private static int DocumentIconGapBottom + { + get { return _DocumentIconGapBottom; } + } - private static int DocumentIconGapLeft => _DocumentIconGapLeft; + private static int DocumentIconGapLeft + { + get { return _DocumentIconGapLeft; } + } - private static int DocumentIconGapRight => _DocumentIconGapRight; + private static int DocumentIconGapRight + { + get { return _DocumentIconGapRight; } + } - private static int DocumentIconWidth => _DocumentIconWidth; + private static int DocumentIconWidth + { + get { return _DocumentIconWidth; } + } - private static int DocumentIconHeight => _DocumentIconHeight; + private static int DocumentIconHeight + { + get { return _DocumentIconHeight; } + } - private static int DocumentTextGapRight => _DocumentTextGapRight; - - private static Pen PenToolWindowTabBorder => SystemPens.GrayText; - - private static Pen PenDocumentTabActiveBorder => SystemPens.ControlDarkDark; - - private static Pen PenDocumentTabInactiveBorder => SystemPens.GrayText; + private static int DocumentTextGapRight + { + get { return _DocumentTextGapRight; } + } #endregion @@ -375,14 +516,14 @@ namespace mRemoteNG.UI.Tabs SuspendLayout(); - Components = new System.ComponentModel.Container(); + m_components = new System.ComponentModel.Container(); m_toolTip = new ToolTip(Components); - SelectMenu = new ContextMenuStrip(Components); - pane.DockPanel.Theme.ApplyTo(SelectMenu); + m_selectMenu = new ContextMenuStrip(Components); + pane.DockPanel.Theme.ApplyTo(m_selectMenu); ResumeLayout(); - } - + } + protected override void Dispose(bool disposing) { if (disposing) @@ -399,7 +540,10 @@ namespace mRemoteNG.UI.Tabs protected override int MeasureHeight() { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? MeasureHeight_ToolWindow() : MeasureHeight_Document(); + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return MeasureHeight_ToolWindow(); + else + return MeasureHeight_Document(); } private int MeasureHeight_ToolWindow() @@ -407,7 +551,7 @@ namespace mRemoteNG.UI.Tabs if (DockPane.IsAutoHide || Tabs.Count <= 1) return 0; - var height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + int height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + ToolWindowStripGapTop + ToolWindowStripGapBottom; @@ -416,8 +560,8 @@ namespace mRemoteNG.UI.Tabs private int MeasureHeight_Document() { - var height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), - ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + int height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + ButtonOverflow.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + DocumentStripGapBottom + DocumentStripGapTop; return height; @@ -425,33 +569,6 @@ namespace mRemoteNG.UI.Tabs protected override void OnPaint(PaintEventArgs e) { - var rect = TabsRectangle; - var gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient; - if (Appearance == DockPane.AppearanceStyle.Document) - { - rect.X -= DocumentTabGapLeft; - - // Add these values back in so that the DockStrip color is drawn - // beneath the close button and window list button. - // It is possible depending on the DockPanel DocumentStyle to have - // a Document without a DockStrip. - rect.Width += DocumentTabGapLeft + - DocumentTabGapRight + - DocumentButtonGapRight + - ButtonClose.Width + - ButtonWindowList.Width; - } - else - { - gradient = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient; - } - //Fix MagicRemove , missing gradient implementation in themes - //Also coloring in tabs in not correct in some themes - var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); - var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Background"); - var gradientMode = gradient.LinearGradientMode; - - rect.SafelyDrawLinearGradient(startColor, endColor, gradientMode, e.Graphics); base.OnPaint(e); CalculateTabs(); if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null) @@ -471,21 +588,22 @@ namespace mRemoteNG.UI.Tabs public override GraphicsPath GetOutline(int index) { - return Appearance == DockPane.AppearanceStyle.Document ? GetOutline_Document(index) : GetOutline_ToolWindow(index); + if (Appearance == DockPane.AppearanceStyle.Document) + return GetOutline_Document(index); + else + return GetOutline_ToolWindow(index); } private GraphicsPath GetOutline_Document(int index) { - var rectangle = Tabs[index].Rectangle; - if (rectangle == null) return null; - var rectTab = rectangle.Value; + Rectangle rectTab = Tabs[index].Rectangle.Value; rectTab.X -= rectTab.Height / 2; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - var path = new GraphicsPath(); - var pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); path.AddPath(pathTab, true); if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) @@ -505,20 +623,17 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); } return path; - } private GraphicsPath GetOutline_ToolWindow(int index) { - var rectangle = Tabs[index].Rectangle; - if (rectangle == null) return null; - var rectTab = rectangle.Value; + Rectangle rectTab = Tabs[index].Rectangle.Value; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - var path = new GraphicsPath(); - var pathTab = GetTabOutline(Tabs[index], true, true); + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); path.AddPath(pathTab, true); path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); @@ -526,7 +641,6 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); return path; - } private void CalculateTabs() @@ -542,38 +656,38 @@ namespace mRemoteNG.UI.Tabs if (Tabs.Count <= 1 || DockPane.IsAutoHide) return; - var rectTabStrip = TabStripRectangle; + Rectangle rectTabStrip = TabStripRectangle; // Calculate tab widths - var countTabs = Tabs.Count; - foreach (var tab1 in Tabs) + int countTabs = Tabs.Count; + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); tab.Flag = false; } // Set tab whose max width less than average width - bool anyWidthWithinAverage; - var totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; - var totalAllocatedWidth = 0; - var averageWidth = totalWidth / countTabs; - var remainedTabs = countTabs; + bool anyWidthWithinAverage = true; + int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + int totalAllocatedWidth = 0; + int averageWidth = totalWidth / countTabs; + int remainedTabs = countTabs; for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0;) { anyWidthWithinAverage = false; - foreach (var tab1 in Tabs) + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; - if (tab.MaxWidth > averageWidth) continue; - tab.Flag = true; - tab.TabWidth = tab.MaxWidth; - totalAllocatedWidth += tab.TabWidth; - anyWidthWithinAverage = true; - remainedTabs--; + if (tab.MaxWidth <= averageWidth) + { + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; + } } if (remainedTabs != 0) averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; @@ -582,10 +696,9 @@ namespace mRemoteNG.UI.Tabs // If any tab width not set yet, set it to the average width if (remainedTabs > 0) { - var roundUpWidth = totalWidth - totalAllocatedWidth - averageWidth * remainedTabs; - foreach (var tab1 in Tabs) + int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; @@ -601,10 +714,9 @@ namespace mRemoteNG.UI.Tabs } // Set the X position of the tabs - var x = rectTabStrip.X + ToolWindowStripGapLeft; - foreach (var tab1 in Tabs) + int x = rectTabStrip.X + ToolWindowStripGapLeft; + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } @@ -612,11 +724,11 @@ namespace mRemoteNG.UI.Tabs private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) { - var overflow = false; + bool overflow = false; - if (!(Tabs[index] is MremoteNGTab tab)) return false; + var tab = Tabs[index] as MremoteNGTab; tab.MaxWidth = GetMaxTabWidth(index); - var width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); if (x + width < rectTabStrip.Right || index == StartDisplayingTab) { tab.TabX = x; @@ -629,7 +741,6 @@ namespace mRemoteNG.UI.Tabs tab.TabWidth = 0; overflow = true; } - x += width; return overflow; @@ -643,10 +754,10 @@ namespace mRemoteNG.UI.Tabs if (m_startDisplayingTab >= Tabs.Count) m_startDisplayingTab = 0; - var rectTabStrip = TabsRectangle; + Rectangle rectTabStrip = TabsRectangle; - var x = rectTabStrip.X + rectTabStrip.Height / 2; - var overflow = false; + int x = rectTabStrip.X; //+ rectTabStrip.Height / 2; + bool overflow = false; // Originally all new documents that were considered overflow // (not enough pane strip space to show all tabs) were added to @@ -655,11 +766,12 @@ namespace mRemoteNG.UI.Tabs // then we are dealing with making sure a specific tab is kept in focus. if (m_startDisplayingTab > 0) { - var tempX = x; - if (Tabs[m_startDisplayingTab] is MremoteNGTab tab) tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + int tempX = x; + var tab = Tabs[m_startDisplayingTab] as MremoteNGTab; + tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); // Add the active tab and tabs to the left - for (var i = StartDisplayingTab; i >= 0; i--) + for (int i = StartDisplayingTab; i >= 0; i--) CalculateDocumentTab(rectTabStrip, ref tempX, i); // Store which tab is the first one displayed so that it @@ -671,7 +783,7 @@ namespace mRemoteNG.UI.Tabs // Start with the first tab displayed - name is a little misleading. // Loop through each tab and set its location. If there is not enough // room for all of them overflow will be returned. - for (var i = EndDisplayingTab; i < Tabs.Count; i++) + for (int i = EndDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); // If not all tabs are shown then we have an overflow. @@ -680,9 +792,9 @@ namespace mRemoteNG.UI.Tabs } else { - for (var i = StartDisplayingTab; i < Tabs.Count; i++) + for (int i = StartDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); - for (var i = 0; i < StartDisplayingTab; i++) + for (int i = 0; i < StartDisplayingTab; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); FirstDisplayingTab = StartDisplayingTab; @@ -692,14 +804,14 @@ namespace mRemoteNG.UI.Tabs { m_startDisplayingTab = 0; FirstDisplayingTab = 0; - x = rectTabStrip.X + rectTabStrip.Height / 2; - foreach (var tab1 in Tabs) + x = rectTabStrip.X; + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } } + DocumentTabsOverflow = overflow; } @@ -714,14 +826,12 @@ namespace mRemoteNG.UI.Tabs private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) { - var index = Tabs.IndexOf(content); - if (index == -1) - { - //somehow we've lost the content from the Tab collection + int index = Tabs.IndexOf(content); + if (index == -1) // TODO: should prevent it from being -1; return false; - } - if (Tabs[index] is MremoteNGTab tab && tab.TabWidth != 0) + var tab = Tabs[index] as MremoteNGTab; + if (tab.TabWidth != 0) return false; StartDisplayingTab = index; @@ -733,32 +843,44 @@ namespace mRemoteNG.UI.Tabs private int GetMaxTabWidth(int index) { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetMaxTabWidth_ToolWindow(index) : GetMaxTabWidth_Document(index); + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetMaxTabWidth_ToolWindow(index); + else + return GetMaxTabWidth_Document(index); } private int GetMaxTabWidth_ToolWindow(int index) { - var content = Tabs[index].Content; - var sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + IDockContent content = Tabs[index].Content; + Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + ToolWindowImageGapRight + ToolWindowTextGapRight; } + private const int TAB_CLOSE_BUTTON_WIDTH = 30; + private int GetMaxTabWidth_Document(int index) { - var content = Tabs[index].Content; + IDockContent content = Tabs[index].Content; + int height = GetTabRectangle_Document(index).Height; + Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); - var height = GetTabRectangle_Document(index).Height; + int width; + if (DockPane.DockPanel.ShowDocumentIcon) + width = sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; + else + width = sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; - var sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); - - return DockPane.DockPanel.ShowDocumentIcon - ? sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight - : sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; + width += TAB_CLOSE_BUTTON_WIDTH; + return width; } private void DrawTabStrip(Graphics g) { + // IMPORTANT: fill background. + Rectangle rectTabStrip = TabStripRectangle; + g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background), rectTabStrip); + if (Appearance == DockPane.AppearanceStyle.Document) DrawTabStrip_Document(g); else @@ -767,61 +889,76 @@ namespace mRemoteNG.UI.Tabs private void DrawTabStrip_Document(Graphics g) { - var count = Tabs.Count; + int count = Tabs.Count; if (count == 0) return; - var rectTabStrip = TabStripRectangle; + Rectangle rectTabStrip = new Rectangle(TabStripRectangle.Location, TabStripRectangle.Size); + rectTabStrip.Height += 1; // Draw the tabs - var rectTabOnly = TabsRectangle; - Rectangle rectTab; + Rectangle rectTabOnly = TabsRectangle; + Rectangle rectTab = Rectangle.Empty; MremoteNGTab tabActive = null; g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - for (var i = 0; i < count; i++) + for (int i = 0; i < count; i++) { rectTab = GetTabRectangle(i); if (Tabs[i].Content == DockPane.ActiveContent) { tabActive = Tabs[i] as MremoteNGTab; - if (tabActive != null) tabActive.Rectangle = rectTab; + tabActive.Rectangle = rectTab; continue; } - if (!rectTab.IntersectsWith(rectTabOnly)) continue; - if (!(Tabs[i] is MremoteNGTab tab)) continue; - tab.Rectangle = rectTab; - DrawTab(g, tab); + if (rectTab.IntersectsWith(rectTabOnly)) + { + var tab = Tabs[i] as MremoteNGTab; + tab.Rectangle = rectTab; + DrawTab(g, tab); + } } g.SetClip(rectTabStrip); if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Top + 1, - rectTabStrip.Right, rectTabStrip.Top + 1); + { + } else - g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Bottom - 1, - rectTabStrip.Right, rectTabStrip.Bottom - 1); + { + Color tabUnderLineColor; + if (tabActive != null && DockPane.IsActiveDocumentPane) + tabUnderLineColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background; + else + tabUnderLineColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background; + + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(tabUnderLineColor, 4), rectTabStrip.Left, rectTabStrip.Bottom, rectTabStrip.Right, rectTabStrip.Bottom); + } g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - if (tabActive == null) return; - rectTab = tabActive.Rectangle.Value; - if (!rectTab.IntersectsWith(rectTabOnly)) return; - rectTab.Intersect(rectTabOnly); - tabActive.Rectangle = rectTab; - DrawTab(g, tabActive); + if (tabActive != null) + { + rectTab = tabActive.Rectangle.Value; + if (rectTab.IntersectsWith(rectTabOnly)) + { + rectTab.Intersect(rectTabOnly); + tabActive.Rectangle = rectTab; + DrawTab(g, tabActive); + } + } } private void DrawTabStrip_ToolWindow(Graphics g) { - var rectTabStrip = TabStripRectangle; + var rect = TabStripRectangle_ToolWindow; + Color borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; - g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top, - rectTabStrip.Right, rectTabStrip.Top); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, + rect.Right, rect.Top); - for (var i = 0; i < Tabs.Count; i++) + for (int i = 0; i < Tabs.Count; i++) { - if (!(Tabs[i] is MremoteNGTab tab)) continue; + var tab = Tabs[i] as MremoteNGTab; tab.Rectangle = GetTabRectangle(i); DrawTab(g, tab); } @@ -829,26 +966,29 @@ namespace mRemoteNG.UI.Tabs private Rectangle GetTabRectangle(int index) { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabRectangle_ToolWindow(index) : GetTabRectangle_Document(index); + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabRectangle_ToolWindow(index); + else + return GetTabRectangle_Document(index); } private Rectangle GetTabRectangle_ToolWindow(int index) { - var rectTabStrip = TabStripRectangle; + Rectangle rectTabStrip = TabStripRectangle; - var tab = (MremoteNGTab)Tabs[index]; + MremoteNGTab tab = (MremoteNGTab)Tabs[index]; return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height); } private Rectangle GetTabRectangle_Document(int index) { - var rectTabStrip = TabStripRectangle; + Rectangle rectTabStrip = TabStripRectangle; var tab = (MremoteNGTab)Tabs[index]; - var rect = new Rectangle - { - X = tab.TabX, Width = tab.TabWidth, Height = rectTabStrip.Height - DocumentTabGapTop - }; + Rectangle rect = new Rectangle(); + rect.X = tab.TabX; + rect.Width = tab.TabWidth; + rect.Height = rectTabStrip.Height - DocumentTabGapTop; if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) rect.Y = rectTabStrip.Y + DocumentStripGapBottom; @@ -868,12 +1008,15 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) { - return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabOutline_ToolWindow(tab, rtlTransform, toScreen) : GetTabOutline_Document(tab, rtlTransform, toScreen, false); + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); + else + return GetTabOutline_Document(tab, rtlTransform, toScreen, false); } private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) { - var rect = GetTabRectangle(Tabs.IndexOf(tab)); + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); if (rtlTransform) rect = DrawHelper.RtlTransform(this, rect); if (toScreen) @@ -885,10 +1028,8 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full) { - const int curveSize = 6; - GraphicsPath.Reset(); - var rect = GetTabRectangle(Tabs.IndexOf(tab)); + Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); // Shorten TabOutline so it doesn't get overdrawn by icons next to it rect.Intersect(TabsRectangle); @@ -899,207 +1040,75 @@ namespace mRemoteNG.UI.Tabs if (toScreen) rect = RectangleToScreen(rect); - // Draws the full angle piece for active content (or first tab) - if (tab.Content == DockPane.ActiveContent || full || Tabs.IndexOf(tab) == FirstDisplayingTab) - { - if (RightToLeft == RightToLeft.Yes) - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. - // It is not needed so it has been commented out. - //GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); - GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Top, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); - } - else - { - GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom); - GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Bottom, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); - } - } - else - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top. - // It is not needed so it has been commented out. - //GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left - rect.Height / 2, rect.Top); - GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Top, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); - } - else - { - GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left - rect.Height / 2, rect.Bottom); - GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Bottom, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); - } - } - } - // Draws the partial angle for non-active content - else - { - if (RightToLeft == RightToLeft.Yes) - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - GraphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Top + rect.Height / 2); - GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2); - } - else - { - GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Bottom - rect.Height / 2); - GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2); - } - } - else - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left, rect.Top + rect.Height / 2); - GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2); - } - else - { - GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Bottom - rect.Height / 2); - GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2); - } - } - } - - if (RightToLeft == RightToLeft.Yes) - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - // Draws the bottom horizontal line (short side) - GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom); - - // Drawing the rounded corner is not necessary. The path is automatically connected - //GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); - } - else - { - // Draws the bottom horizontal line (short side) - GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Top, rect.Left + curveSize / 2, rect.Top); - GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); - } - } - else - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - // Draws the bottom horizontal line (short side) - GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Bottom, rect.Right - curveSize / 2, rect.Bottom); - - // Drawing the rounded corner is not necessary. The path is automatically connected - //GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom, curveSize, curveSize), 90, -90); - } - else - { - // Draws the top horizontal line (short side) - GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); - - // Draws the rounded corner opposite the angled side - GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); - } - } - - if (Tabs.IndexOf(tab) != EndDisplayingTab && Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent && !full) - { - if (RightToLeft == RightToLeft.Yes) - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Bottom - rect.Height / 2); - GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2, rect.Top); - } - else - { - GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Top + rect.Height / 2); - GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2, rect.Bottom); - } - } - else - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Bottom - rect.Height / 2); - GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2, rect.Top); - } - else - { - GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Top + rect.Height / 2); - GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2, rect.Bottom); - } - } - } - else - { - // Draw the vertical line opposite the angled side - if (RightToLeft == RightToLeft.Yes) - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top); - else - GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Bottom); - } - else - { - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Top); - else - GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom); - } - } - + GraphicsPath.AddRectangle(rect); return GraphicsPath; } private void DrawTab_ToolWindow(Graphics g, MremoteNGTab tab) { - if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; - var rectIcon = new Rectangle( + Rectangle rectIcon = new Rectangle( rect.X + ToolWindowImageGapLeft, - rect.Y + rect.Height - 1 - ToolWindowImageGapBottom - ToolWindowImageHeight, + rect.Y + rect.Height - ToolWindowImageGapBottom - ToolWindowImageHeight, ToolWindowImageWidth, ToolWindowImageHeight); - var rectText = PatchController.EnableHighDpi == true + Rectangle rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + ToolWindowImageGapLeft, - rect.Y - 1 + rect.Height - ToolWindowImageGapBottom - TextFont.Height, + rect.Y + rect.Height - ToolWindowImageGapBottom - TextFont.Height, ToolWindowImageWidth, TextFont.Height) : rectIcon; rectText.X += rectIcon.Width + ToolWindowImageGapRight; rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - - ToolWindowImageGapRight - ToolWindowTextGapRight; + ToolWindowImageGapRight - ToolWindowTextGapRight; - var rectTab = DrawHelper.RtlTransform(this, rect); + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - var path = GetTabOutline(tab, true, false); + Color borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; + + Color separatorColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowSeparator; if (DockPane.ActiveContent == tab.Content) { - var startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor; - var endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor; - var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode; - g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); - g.DrawPath(PenToolWindowTabBorder, path); + Color textColor; + Color backgroundColor; + if (DockPane.IsActiveDocumentPane) + { + textColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabSelectedActive.Text; + backgroundColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabSelectedActive.Background; + } + else + { + textColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabSelectedInactive.Text; + backgroundColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabSelectedInactive.Background; + } - var textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor; + g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(backgroundColor), rect); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, + rect.Left, rect.Bottom); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Bottom - 1, + rect.Right, rect.Bottom - 1); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Right - 1, rect.Top, + rect.Right - 1, rect.Bottom); TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); } else { - var startColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor; - var endColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor; - var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode; - g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path); - - if (Tabs.IndexOf(DockPane.ActiveContent) != Tabs.IndexOf(tab) + 1) + Color textColor; + Color backgroundColor; + if (tab.Content == DockPane.MouseOverTab) { - var pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop); - var pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); - g.DrawLine(PenToolWindowTabBorder, DrawHelper.RtlTransform(this, pt1), DrawHelper.RtlTransform(this, pt2)); + textColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabUnselectedHovered.Text; + backgroundColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabUnselectedHovered.Background; + } + else + { + textColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowTabUnselected.Text; + backgroundColor = DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background; } - var textColor = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor; + g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(backgroundColor), rect); + g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, + rect.Right, rect.Top); TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); } @@ -1109,16 +1118,16 @@ namespace mRemoteNG.UI.Tabs private void DrawTab_Document(Graphics g, MremoteNGTab tab) { - if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; if (tab.TabWidth == 0) return; - var rectIcon = new Rectangle( + var rectCloseButton = GetCloseButtonRect(rect); + Rectangle rectIcon = new Rectangle( rect.X + DocumentIconGapLeft, - rect.Y + rect.Height - 1 - DocumentIconGapBottom - DocumentIconHeight, + rect.Y + rect.Height - DocumentIconGapBottom - DocumentIconHeight, DocumentIconWidth, DocumentIconHeight); - var rectText = PatchController.EnableHighDpi == true + Rectangle rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + DocumentIconGapLeft, rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, @@ -1128,59 +1137,201 @@ namespace mRemoteNG.UI.Tabs { rectText.X += rectIcon.Width + DocumentIconGapRight; rectText.Y = rect.Y; - rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - - DocumentIconGapRight - DocumentTextGapRight; + rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - DocumentIconGapRight - DocumentTextGapRight - rectCloseButton.Width; rectText.Height = rect.Height; } else - rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight; + rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight - rectCloseButton.Width; - var rectTab = DrawHelper.RtlTransform(this, rect); - var rectBack = DrawHelper.RtlTransform(this, rect); + Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + Rectangle rectBack = DrawHelper.RtlTransform(this, rect); rectBack.Width += DocumentIconGapLeft; rectBack.X -= DocumentIconGapLeft; rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - var path = GetTabOutline(tab, true, false); + + Color activeColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background; + Color lostFocusColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background; + Color inactiveColor = DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background; + Color mouseHoverColor = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Background; + + Color activeText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Text; + Color lostFocusText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Text; + Color inactiveText = DockPane.DockPanel.Theme.ColorPalette.TabUnselected.Text; + Color mouseHoverText = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Text; + + Color text; + Image image = null; + Color paint; + var imageService = DockPane.DockPanel.Theme.ImageService; if (DockPane.ActiveContent == tab.Content) { - var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); - var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode; - g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); - g.DrawPath(PenDocumentTabActiveBorder, path); - - var textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Foreground"); - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, - DockPane.IsActiveDocumentPane ? BoldFont : TextFont, rectText, textColor, DocumentTextFormat); + if (DockPane.IsActiveDocumentPane) + { + paint = activeColor; + text = activeText; + image = IsMouseDown + ? imageService.TabPressActive_Close + : rectCloseButton == ActiveClose + ? imageService.TabHoverActive_Close + : imageService.TabActive_Close; + } + else + { + paint = lostFocusColor; + text = lostFocusText; + image = IsMouseDown + ? imageService.TabPressLostFocus_Close + : rectCloseButton == ActiveClose + ? imageService.TabHoverLostFocus_Close + : imageService.TabLostFocus_Close; + } } else { - var startColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); - var endColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Background"); - var gradientMode = DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode; - g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path); - g.DrawPath(PenDocumentTabInactiveBorder, path); - - var textColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Disabled_Foreground"); - TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat); + if (tab.Content == DockPane.MouseOverTab) + { + paint = mouseHoverColor; + text = mouseHoverText; + image = IsMouseDown + ? imageService.TabPressInactive_Close + : rectCloseButton == ActiveClose + ? imageService.TabHoverInactive_Close + : imageService.TabInactive_Close; + } + else + { + paint = inactiveColor; + text = inactiveText; + } } + g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(paint), rect); + TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, text, DocumentTextFormat); + if (image != null) + g.DrawImage(image, rectCloseButton); + if (rectTab.Contains(rectIcon) && DockPane.DockPanel.ShowDocumentIcon) g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon); } + private bool m_isMouseDown = false; + protected bool IsMouseDown + { + get { return m_isMouseDown; } + private set + { + if (m_isMouseDown == value) + return; + + m_isMouseDown = value; + Invalidate(); + } + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + if (IsMouseDown) + IsMouseDown = false; + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + // suspend drag if mouse is down on active close button. + this.m_suspendDrag = ActiveCloseHitTest(e.Location); + if (!IsMouseDown) + IsMouseDown = true; + } + + protected override void OnMouseMove(MouseEventArgs e) + { + if (!this.m_suspendDrag) + base.OnMouseMove(e); + + int index = HitTest(PointToClient(MousePosition)); + string toolTip = string.Empty; + + bool tabUpdate = false; + bool buttonUpdate = false; + if (index != -1) + { + var tab = Tabs[index] as MremoteNGTab; + if (Appearance == DockPane.AppearanceStyle.ToolWindow || Appearance == DockPane.AppearanceStyle.Document) + { + tabUpdate = SetMouseOverTab(tab.Content == DockPane.ActiveContent ? null : tab.Content); + } + + if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) + toolTip = tab.Content.DockHandler.ToolTipText; + else if (tab.MaxWidth > tab.TabWidth) + toolTip = tab.Content.DockHandler.TabText; + + var mousePos = PointToClient(MousePosition); + var tabRect = tab.Rectangle.Value; + var closeButtonRect = GetCloseButtonRect(tabRect); + var mouseRect = new Rectangle(mousePos, new Size(1, 1)); + buttonUpdate = SetActiveClose(closeButtonRect.IntersectsWith(mouseRect) ? closeButtonRect : Rectangle.Empty); + } + else + { + tabUpdate = SetMouseOverTab(null); + buttonUpdate = SetActiveClose(Rectangle.Empty); + } + + if (tabUpdate || buttonUpdate) + Invalidate(); + + if (m_toolTip.GetToolTip(this) != toolTip) + { + m_toolTip.Active = false; + m_toolTip.SetToolTip(this, toolTip); + m_toolTip.Active = true; + } + } + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document) + return; + + var indexHit = HitTest(); + if (indexHit > -1) + TabCloseButtonHit(indexHit); + } + + private void TabCloseButtonHit(int index) + { + var mousePos = PointToClient(MousePosition); + var tabRect = GetTabBounds(Tabs[index]); + if (tabRect.Contains(ActiveClose) && ActiveCloseHitTest(mousePos)) + TryCloseTab(index); + } + + private Rectangle GetCloseButtonRect(Rectangle rectTab) + { + if (Appearance != DockPane.AppearanceStyle.Document) + { + return Rectangle.Empty; + } + + const int gap = 3; + var imageSize = PatchController.EnableHighDpi == true ? rectTab.Height - gap * 2 : 15; + return new Rectangle(rectTab.X + rectTab.Width - imageSize - gap - 1, rectTab.Y + gap, imageSize, imageSize); + } + private void WindowList_Click(object sender, EventArgs e) { SelectMenu.Items.Clear(); - foreach (var tab1 in Tabs) + foreach (MremoteNGTab tab in Tabs) { - var tab = (MremoteNGTab) tab1; - var content = tab.Content; - var item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); + IDockContent content = tab.Content; + ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); item.Tag = tab.Content; - item.Click += ContextMenuItem_Click; + item.Click += new EventHandler(ContextMenuItem_Click); } var workingArea = Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, ButtonWindowList.Height / 2))); @@ -1211,27 +1362,30 @@ namespace mRemoteNG.UI.Tabs private void ContextMenuItem_Click(object sender, EventArgs e) { - if (!(sender is ToolStripMenuItem item)) return; - var content = (IDockContent)item.Tag; - DockPane.ActiveContent = content; + ToolStripMenuItem item = sender as ToolStripMenuItem; + if (item != null) + { + IDockContent content = (IDockContent)item.Tag; + DockPane.ActiveContent = content; + } } private void SetInertButtons() { if (Appearance == DockPane.AppearanceStyle.ToolWindow) { - if (m_buttonClose != null) - m_buttonClose.Left = -m_buttonClose.Width; + if (m_buttonOverflow != null) + m_buttonOverflow.Left = -m_buttonOverflow.Width; if (m_buttonWindowList != null) m_buttonWindowList.Left = -m_buttonWindowList.Width; } else { - ButtonClose.Enabled = DockPane.ActiveContent == null || DockPane.ActiveContent.DockHandler.CloseButton; - m_closeButtonVisible = DockPane.ActiveContent == null || DockPane.ActiveContent.DockHandler.CloseButtonVisible; - ButtonClose.Visible = m_closeButtonVisible; - ButtonClose.RefreshChanges(); + ButtonOverflow.Visible = m_documentTabsOverflow; + ButtonOverflow.RefreshChanges(); + + ButtonWindowList.Visible = !m_documentTabsOverflow; ButtonWindowList.RefreshChanges(); } } @@ -1249,30 +1403,27 @@ namespace mRemoteNG.UI.Tabs private void LayoutButtons() { - var rectTabStrip = TabStripRectangle; + Rectangle rectTabStrip = TabStripRectangle; // Set position and size of the buttons - var buttonWidth = ButtonClose.Image.Width; - var buttonHeight = ButtonClose.Image.Height; - var height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; + int buttonWidth = ButtonOverflow.Image.Width; + int buttonHeight = ButtonOverflow.Image.Height; + int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; if (buttonHeight < height) { buttonWidth = buttonWidth * height / buttonHeight; buttonHeight = height; } - var buttonSize = new Size(buttonWidth, buttonHeight); + Size buttonSize = new Size(buttonWidth, buttonHeight); - var x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft + int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft - DocumentButtonGapRight - buttonWidth; - var y = rectTabStrip.Y + DocumentButtonGapTop; - var point = new Point(x, y); - ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + int y = rectTabStrip.Y + DocumentButtonGapTop; + Point point = new Point(x, y); + ButtonOverflow.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); // If the close button is not visible draw the window list button overtop. // Otherwise it is drawn to the left of the close button. - if (m_closeButtonVisible) - point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0); - ButtonWindowList.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); } @@ -1285,52 +1436,81 @@ namespace mRemoteNG.UI.Tabs } } - protected override int HitTest(Point point) + protected override int HitTest(Point point) { if (!TabsRectangle.Contains(point)) return -1; - foreach (var tab in Tabs) + foreach (Tab tab in Tabs) { - var path = GetTabOutline(tab, true, false); + GraphicsPath path = GetTabOutline(tab, true, false); if (path.IsVisible(point)) return Tabs.IndexOf(tab); } + return -1; } + protected override bool MouseDownActivateTest(MouseEventArgs e) + { + bool result = base.MouseDownActivateTest(e); + if (result && (e.Button == MouseButtons.Left) && (Appearance == DockPane.AppearanceStyle.Document)) + { + // don't activate if mouse is down on active close button + result = !ActiveCloseHitTest(e.Location); + } + return result; + } + + private bool ActiveCloseHitTest(Point ptMouse) + { + bool result = false; + if (!ActiveClose.IsEmpty) + { + var mouseRect = new Rectangle(ptMouse, new Size(1, 1)); + result = ActiveClose.IntersectsWith(mouseRect); + } + return result; + } + protected override Rectangle GetTabBounds(Tab tab) { - var path = GetTabOutline(tab, true, false); - var rectangle = path.GetBounds(); + GraphicsPath path = GetTabOutline(tab, true, false); + RectangleF rectangle = path.GetBounds(); return new Rectangle((int)rectangle.Left, (int)rectangle.Top, (int)rectangle.Width, (int)rectangle.Height); } - protected override void OnMouseHover(EventArgs e) + private Rectangle ActiveClose { - var index = HitTest(PointToClient(MousePosition)); - var toolTip = string.Empty; + get { return _activeClose; } + } - base.OnMouseHover(e); + private bool SetActiveClose(Rectangle rectangle) + { + if (_activeClose == rectangle) + return false; - if (index != -1) - { - if (!(Tabs[index] is MremoteNGTab tab)) return; - if (!string.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) - toolTip = tab.Content.DockHandler.ToolTipText; - else if (tab.MaxWidth > tab.TabWidth) - toolTip = tab.Content.DockHandler.TabText; - } + _activeClose = rectangle; + return true; + } - if (m_toolTip.GetToolTip(this) != toolTip) - { - m_toolTip.Active = false; - m_toolTip.SetToolTip(this, toolTip); - m_toolTip.Active = true; - } + private bool SetMouseOverTab(IDockContent content) + { + if (DockPane.MouseOverTab == content) + return false; - // requires further tracking of mouse hover behavior, - ResetMouseEventArgs(); + DockPane.MouseOverTab = content; + return true; + } + + protected override void OnMouseLeave(EventArgs e) + { + var tabUpdate = SetMouseOverTab(null); + var buttonUpdate = SetActiveClose(Rectangle.Empty); + if (tabUpdate || buttonUpdate) + Invalidate(); + + base.OnMouseLeave(e); } protected override void OnRightToLeftChanged(EventArgs e) @@ -1338,7 +1518,6 @@ namespace mRemoteNG.UI.Tabs base.OnRightToLeftChanged(e); PerformLayout(); } - #region Native Methods [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] @@ -1355,7 +1534,7 @@ namespace mRemoteNG.UI.Tabs } return; } - + } base.WndProc(ref m); @@ -1364,4 +1543,4 @@ namespace mRemoteNG.UI.Tabs #endregion } -} +} \ No newline at end of file From 7603587ce3f55cbf13aa7043100a5445d031b6e4 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 7 Jan 2019 21:31:16 -0500 Subject: [PATCH 071/157] Reubicated the custom dock strip initialization Now it work with all the themes and no theme enabled --- mRemoteV1/Themes/ThemeInfo.cs | 7 +++++++ mRemoteV1/Themes/ThemeManager.cs | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index 86db8d847..f6db90979 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -32,6 +32,8 @@ namespace mRemoteNG.Themes _extendedPalette = inExtendedPalette; IsThemeBase = false; IsExtendable = false; + //Override the dock pane strip factory + _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); } public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion) @@ -42,6 +44,9 @@ namespace mRemoteNG.Themes _version = inVersion; IsThemeBase = false; IsExtendable = false; + //Override the dock pane strip factory + _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + } #endregion @@ -91,6 +96,8 @@ namespace mRemoteNG.Themes return; } _theme = value; + //Override the dock pane strip factory + _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); } } diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index f4d2b422e..baa98b418 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -125,12 +125,6 @@ namespace mRemoteNG.Themes var vs2015Blue = new ThemeInfo("DPSvs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); themes.Add(vs2015Blue.Name, vs2015Blue); - //Override all the themes pane strip for custom event handling - foreach(ThemeInfo overrideTheme in themes) - { - overrideTheme.Theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); - } - } } From 4405a1fbf754c64d840d23cb4a14c6fff11f3e40 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 10:10:07 -0500 Subject: [PATCH 072/157] clean up / resharper fixes --- mRemoteV1/Themes/MremoteNGThemeBase.cs | 1 - mRemoteV1/Themes/ThemeManager.cs | 22 +- mRemoteV1/UI/Tabs/ConnectionTab.cs | 6 +- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 688 ++++++++++--------------- 4 files changed, 273 insertions(+), 444 deletions(-) diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index 3cc6d44ad..2bc98b944 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -18,7 +18,6 @@ Measures.DockPadding = 2; ShowAutoHideContentOnHover = false; } - } public class MremoteDockPaneStripFactory : DockPanelExtender.IDockPaneStripFactory diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index baa98b418..3825fc3d0 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -18,7 +18,7 @@ namespace mRemoteNG.Themes { #region Private Variables - private ThemeInfo _activeTheme; + private ThemeInfo _activeTheme; private Hashtable themes; private bool _themeActive; private static ThemeManager themeInstance; @@ -37,7 +37,7 @@ namespace mRemoteNG.Themes if (themes[Settings.Default.ThemeName] != null) ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else - ActiveTheme = DefaultTheme; + ActiveTheme = DefaultTheme; } #endregion @@ -62,7 +62,7 @@ namespace mRemoteNG.Themes if (themes != null) return themes.Values.OfType().ToList(); themes = new Hashtable(); - //Load the files in theme folder first, to include vstheme light as default + //Load the files in theme folder first, to include vstheme light as default var themePath = App.Info.SettingsFileInfo.ThemeFolder; if (themePath == null) return themes.Values.OfType().ToList(); try @@ -87,8 +87,8 @@ namespace mRemoteNG.Themes { var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0]; - //First we load the default theme, its vs2015light - var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); + //First we load the default theme, its vs2015light + var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); themes.Add(defaultTheme.Name, defaultTheme); //Then the rest foreach (var themeFile in themeFiles) @@ -125,14 +125,14 @@ namespace mRemoteNG.Themes var vs2015Blue = new ThemeInfo("DPSvs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); themes.Add(vs2015Blue.Name, vs2015Blue); - + } } catch(Exception ex) { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true); } - return themes.Values.OfType().ToList(); + return themes.Values.OfType().ToList(); } /// @@ -163,10 +163,10 @@ namespace mRemoteNG.Themes ThemeSerializer.DeleteFile(themeToDelete); } - //Sincronize the theme XML values from memory to disk + //Synchronize the theme XML values from memory to disk public void updateTheme(ThemeInfo themeToUpdate) { - ThemeSerializer.UpdateThemeXMLValues(themeToUpdate); + ThemeSerializer.UpdateThemeXMLValues(themeToUpdate); } //refresh the ui controls to reflect a theme change @@ -183,8 +183,8 @@ namespace mRemoteNG.Themes var badChars = Path.GetInvalidFileNameChars(); return name.IndexOfAny(badChars) == -1; } - - + + #endregion #region Events diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 5d28b759c..d9eecedf1 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -14,7 +14,7 @@ namespace mRemoteNG.UI.Tabs public partial class ConnectionTab : DockContent { public bool silentClose { get; set; } - + public ConnectionTab() { InitializeComponent(); @@ -24,7 +24,7 @@ namespace mRemoteNG.UI.Tabs protected override void OnFormClosing(FormClosingEventArgs e) { if(!silentClose) - { + { if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) { var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); @@ -48,7 +48,7 @@ namespace mRemoteNG.UI.Tabs } base.OnFormClosing(e); } - + #region HelperFunctions public void RefreshInterfaceController() diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 6529abc4e..69101cb40 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -1,5 +1,4 @@ -using mRemoteNG.Themes; -using System; +using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; @@ -7,7 +6,6 @@ using System.Security.Permissions; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; - namespace mRemoteNG.UI.Tabs { /// @@ -23,33 +21,13 @@ namespace mRemoteNG.UI.Tabs { } - private int m_tabX; - public int TabX - { - get { return m_tabX; } - set { m_tabX = value; } - } + public int TabX { get; set; } - private int m_tabWidth; - public int TabWidth - { - get { return m_tabWidth; } - set { m_tabWidth = value; } - } + public int TabWidth { get; set; } - private int m_maxWidth; - public int MaxWidth - { - get { return m_maxWidth; } - set { m_maxWidth = value; } - } + public int MaxWidth { get; set; } - private bool m_flag; - protected internal bool Flag - { - get { return m_flag; } - set { m_flag = value; } - } + protected internal bool Flag { get; set; } } protected override Tab CreateTab(IDockContent content) @@ -60,30 +38,18 @@ namespace mRemoteNG.UI.Tabs [ToolboxItem(false)] private sealed class InertButton : InertButtonBase { - private Bitmap _hovered, _normal, _pressed; - public InertButton(Bitmap hovered, Bitmap normal, Bitmap pressed) - : base() { - _hovered = hovered; - _normal = normal; - _pressed = pressed; + HoverImage = hovered; + Image = normal; + PressImage = pressed; } - public override Bitmap Image - { - get { return _normal; } - } + public override Bitmap Image { get; } - public override Bitmap HoverImage - { - get { return _hovered; } - } + public override Bitmap HoverImage { get; } - public override Bitmap PressImage - { - get { return _pressed; } - } + public override Bitmap PressImage { get; } } #region Constants @@ -123,21 +89,15 @@ namespace mRemoteNG.UI.Tabs #region Members - private ContextMenuStrip m_selectMenu; private InertButton m_buttonOverflow; private InertButton m_buttonWindowList; - private IContainer m_components; private ToolTip m_toolTip; private Font m_font; private Font m_boldFont; - private int m_startDisplayingTab = 0; - private int m_endDisplayingTab = 0; - private int m_firstDisplayingTab = 0; - private bool m_documentTabsOverflow = false; + private int m_startDisplayingTab; + private bool m_documentTabsOverflow; private static string m_toolTipSelect; - private Rectangle _activeClose; - private int _selectMenuMargin = 5; - private bool m_suspendDrag = false; + private bool m_suspendDrag; #endregion #region Properties @@ -148,8 +108,7 @@ namespace mRemoteNG.UI.Tabs { if (Appearance == DockPane.AppearanceStyle.Document) return TabStripRectangle_Document; - else - return TabStripRectangle_ToolWindow; + return TabStripRectangle_ToolWindow; } } @@ -157,7 +116,7 @@ namespace mRemoteNG.UI.Tabs { get { - Rectangle rect = ClientRectangle; + var rect = ClientRectangle; return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom); } } @@ -166,7 +125,7 @@ namespace mRemoteNG.UI.Tabs { get { - Rectangle rect = ClientRectangle; + var rect = ClientRectangle; return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height + DocumentStripGapTop - DocumentStripGapBottom); } } @@ -178,11 +137,11 @@ namespace mRemoteNG.UI.Tabs if (Appearance == DockPane.AppearanceStyle.ToolWindow) return TabStripRectangle; - Rectangle rectWindow = TabStripRectangle; - int x = rectWindow.X; - int y = rectWindow.Y; - int width = rectWindow.Width; - int height = rectWindow.Height; + var rectWindow = TabStripRectangle; + var x = rectWindow.X; + var y = rectWindow.Y; + var width = rectWindow.Width; + var height = rectWindow.Height; x += DocumentTabGapLeft; width -= DocumentTabGapLeft + @@ -196,30 +155,21 @@ namespace mRemoteNG.UI.Tabs } } - private ContextMenuStrip SelectMenu - { - get { return m_selectMenu; } - } + private ContextMenuStrip SelectMenu { get; } - public int SelectMenuMargin - { - get { return _selectMenuMargin; } - set { _selectMenuMargin = value; } - } + public int SelectMenuMargin { get; set; } = 5; private InertButton ButtonOverflow { get { - if (m_buttonOverflow == null) - { - m_buttonOverflow = new InertButton( - DockPane.DockPanel.Theme.ImageService.DockPaneHover_OptionOverflow, - DockPane.DockPanel.Theme.ImageService.DockPane_OptionOverflow, - DockPane.DockPanel.Theme.ImageService.DockPanePress_OptionOverflow); - m_buttonOverflow.Click += new EventHandler(WindowList_Click); - Controls.Add(m_buttonOverflow); - } + if (m_buttonOverflow != null) return m_buttonOverflow; + m_buttonOverflow = new InertButton( + DockPane.DockPanel.Theme.ImageService.DockPaneHover_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPane_OptionOverflow, + DockPane.DockPanel.Theme.ImageService.DockPanePress_OptionOverflow); + m_buttonOverflow.Click += WindowList_Click; + Controls.Add(m_buttonOverflow); return m_buttonOverflow; } @@ -229,34 +179,23 @@ namespace mRemoteNG.UI.Tabs { get { - if (m_buttonWindowList == null) - { - m_buttonWindowList = new InertButton( - DockPane.DockPanel.Theme.ImageService.DockPaneHover_List, - DockPane.DockPanel.Theme.ImageService.DockPane_List, - DockPane.DockPanel.Theme.ImageService.DockPanePress_List); - m_buttonWindowList.Click += new EventHandler(WindowList_Click); - Controls.Add(m_buttonWindowList); - } + if (m_buttonWindowList != null) return m_buttonWindowList; + m_buttonWindowList = new InertButton( + DockPane.DockPanel.Theme.ImageService.DockPaneHover_List, + DockPane.DockPanel.Theme.ImageService.DockPane_List, + DockPane.DockPanel.Theme.ImageService.DockPanePress_List); + m_buttonWindowList.Click += WindowList_Click; + Controls.Add(m_buttonWindowList); return m_buttonWindowList; } } - private static GraphicsPath GraphicsPath - { - get { return MremoteNGAutoHideStrip.GraphicsPath; } - } + private static GraphicsPath GraphicsPath => MremoteNGAutoHideStrip.GraphicsPath; - private IContainer Components - { - get { return m_components; } - } + private IContainer Components { get; } - public Font TextFont - { - get { return DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; } - } + public Font TextFont => DockPane.DockPanel.Theme.Skin.DockPaneStripSkin.TextFont; private Font BoldFont { @@ -270,7 +209,7 @@ namespace mRemoteNG.UI.Tabs m_font = TextFont; m_boldFont = new Font(TextFont, FontStyle.Bold); } - else if (m_font != TextFont) + else if (!Equals(m_font, TextFont)) { m_boldFont.Dispose(); m_font = TextFont; @@ -283,7 +222,7 @@ namespace mRemoteNG.UI.Tabs private int StartDisplayingTab { - get { return m_startDisplayingTab; } + get => m_startDisplayingTab; set { m_startDisplayingTab = value; @@ -291,17 +230,9 @@ namespace mRemoteNG.UI.Tabs } } - private int EndDisplayingTab - { - get { return m_endDisplayingTab; } - set { m_endDisplayingTab = value; } - } + private int EndDisplayingTab { get; set; } - private int FirstDisplayingTab - { - get { return m_firstDisplayingTab; } - set { m_firstDisplayingTab = value; } - } + private int FirstDisplayingTab { get; set; } private bool DocumentTabsOverflow { @@ -317,190 +248,93 @@ namespace mRemoteNG.UI.Tabs #region Customizable Properties - private static int ToolWindowStripGapTop - { - get { return _ToolWindowStripGapTop; } - } + private static int ToolWindowStripGapTop => _ToolWindowStripGapTop; - private static int ToolWindowStripGapBottom - { - get { return _ToolWindowStripGapBottom; } - } + private static int ToolWindowStripGapBottom => _ToolWindowStripGapBottom; - private static int ToolWindowStripGapLeft - { - get { return _ToolWindowStripGapLeft; } - } + private static int ToolWindowStripGapLeft => _ToolWindowStripGapLeft; - private static int ToolWindowStripGapRight - { - get { return _ToolWindowStripGapRight; } - } + private static int ToolWindowStripGapRight => _ToolWindowStripGapRight; - private static int ToolWindowImageHeight - { - get { return _ToolWindowImageHeight; } - } + private static int ToolWindowImageHeight => _ToolWindowImageHeight; - private static int ToolWindowImageWidth - { - get { return _ToolWindowImageWidth; } - } + private static int ToolWindowImageWidth => _ToolWindowImageWidth; - private static int ToolWindowImageGapTop - { - get { return _ToolWindowImageGapTop; } - } + private static int ToolWindowImageGapTop => _ToolWindowImageGapTop; - private static int ToolWindowImageGapBottom - { - get { return _ToolWindowImageGapBottom; } - } + private static int ToolWindowImageGapBottom => _ToolWindowImageGapBottom; - private static int ToolWindowImageGapLeft - { - get { return _ToolWindowImageGapLeft; } - } + private static int ToolWindowImageGapLeft => _ToolWindowImageGapLeft; - private static int ToolWindowImageGapRight - { - get { return _ToolWindowImageGapRight; } - } + private static int ToolWindowImageGapRight => _ToolWindowImageGapRight; - private static int ToolWindowTextGapRight - { - get { return _ToolWindowTextGapRight; } - } + private static int ToolWindowTextGapRight => _ToolWindowTextGapRight; - private static int ToolWindowTabSeperatorGapTop - { - get { return _ToolWindowTabSeperatorGapTop; } - } + private static int ToolWindowTabSeperatorGapTop => _ToolWindowTabSeperatorGapTop; - private static int ToolWindowTabSeperatorGapBottom - { - get { return _ToolWindowTabSeperatorGapBottom; } - } + private static int ToolWindowTabSeperatorGapBottom => _ToolWindowTabSeperatorGapBottom; - private static string ToolTipSelect - { - get - { - if (m_toolTipSelect == null) - m_toolTipSelect = Language.strTabsAndPanels; - return m_toolTipSelect; - } - } + private static string ToolTipSelect => m_toolTipSelect ?? (m_toolTipSelect = Language.strTabsAndPanels); private TextFormatFlags ToolWindowTextFormat { get { - TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + var textFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter; if (RightToLeft == RightToLeft.Yes) return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; - else - return textFormat; + return textFormat; } } - private static int DocumentStripGapTop - { - get { return _DocumentStripGapTop; } - } + private static int DocumentStripGapTop => _DocumentStripGapTop; - private static int DocumentStripGapBottom - { - get { return _DocumentStripGapBottom; } - } + private static int DocumentStripGapBottom => _DocumentStripGapBottom; private TextFormatFlags DocumentTextFormat { get { - TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + var textFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter; if (RightToLeft == RightToLeft.Yes) return textFormat | TextFormatFlags.RightToLeft; - else - return textFormat; + return textFormat; } } - private static int DocumentTabMaxWidth - { - get { return _DocumentTabMaxWidth; } - } + private static int DocumentTabMaxWidth => _DocumentTabMaxWidth; - private static int DocumentButtonGapTop - { - get { return _DocumentButtonGapTop; } - } + private static int DocumentButtonGapTop => _DocumentButtonGapTop; - private static int DocumentButtonGapBottom - { - get { return _DocumentButtonGapBottom; } - } + private static int DocumentButtonGapBottom => _DocumentButtonGapBottom; - private static int DocumentButtonGapBetween - { - get { return _DocumentButtonGapBetween; } - } + private static int DocumentButtonGapBetween => _DocumentButtonGapBetween; - private static int DocumentButtonGapRight - { - get { return _DocumentButtonGapRight; } - } + private static int DocumentButtonGapRight => _DocumentButtonGapRight; - private static int DocumentTabGapTop - { - get { return _DocumentTabGapTop; } - } + private static int DocumentTabGapTop => _DocumentTabGapTop; - private static int DocumentTabGapLeft - { - get { return _DocumentTabGapLeft; } - } + private static int DocumentTabGapLeft => _DocumentTabGapLeft; - private static int DocumentTabGapRight - { - get { return _DocumentTabGapRight; } - } + private static int DocumentTabGapRight => _DocumentTabGapRight; - private static int DocumentIconGapBottom - { - get { return _DocumentIconGapBottom; } - } + private static int DocumentIconGapBottom => _DocumentIconGapBottom; - private static int DocumentIconGapLeft - { - get { return _DocumentIconGapLeft; } - } + private static int DocumentIconGapLeft => _DocumentIconGapLeft; - private static int DocumentIconGapRight - { - get { return _DocumentIconGapRight; } - } + private static int DocumentIconGapRight => _DocumentIconGapRight; - private static int DocumentIconWidth - { - get { return _DocumentIconWidth; } - } + private static int DocumentIconWidth => _DocumentIconWidth; - private static int DocumentIconHeight - { - get { return _DocumentIconHeight; } - } + private static int DocumentIconHeight => _DocumentIconHeight; - private static int DocumentTextGapRight - { - get { return _DocumentTextGapRight; } - } + private static int DocumentTextGapRight => _DocumentTextGapRight; #endregion @@ -516,10 +350,10 @@ namespace mRemoteNG.UI.Tabs SuspendLayout(); - m_components = new System.ComponentModel.Container(); + Components = new System.ComponentModel.Container(); m_toolTip = new ToolTip(Components); - m_selectMenu = new ContextMenuStrip(Components); - pane.DockPanel.Theme.ApplyTo(m_selectMenu); + SelectMenu = new ContextMenuStrip(Components); + pane.DockPanel.Theme.ApplyTo(SelectMenu); ResumeLayout(); } @@ -542,8 +376,7 @@ namespace mRemoteNG.UI.Tabs { if (Appearance == DockPane.AppearanceStyle.ToolWindow) return MeasureHeight_ToolWindow(); - else - return MeasureHeight_Document(); + return MeasureHeight_Document(); } private int MeasureHeight_ToolWindow() @@ -551,7 +384,7 @@ namespace mRemoteNG.UI.Tabs if (DockPane.IsAutoHide || Tabs.Count <= 1) return 0; - int height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + var height = Math.Max(TextFont.Height + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + ToolWindowStripGapTop + ToolWindowStripGapBottom; @@ -560,7 +393,7 @@ namespace mRemoteNG.UI.Tabs private int MeasureHeight_Document() { - int height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), + var height = Math.Max(TextFont.Height + DocumentTabGapTop + (PatchController.EnableHighDpi == true ? DocumentIconGapBottom : 0), ButtonOverflow.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + DocumentStripGapBottom + DocumentStripGapTop; @@ -588,22 +421,21 @@ namespace mRemoteNG.UI.Tabs public override GraphicsPath GetOutline(int index) { - if (Appearance == DockPane.AppearanceStyle.Document) - return GetOutline_Document(index); - else - return GetOutline_ToolWindow(index); + return Appearance == DockPane.AppearanceStyle.Document ? GetOutline_Document(index) : GetOutline_ToolWindow(index); } private GraphicsPath GetOutline_Document(int index) { - Rectangle rectTab = Tabs[index].Rectangle.Value; + var rectangle = Tabs[index].Rectangle; + if (rectangle == null) return null; + var rectTab = rectangle.Value; rectTab.X -= rectTab.Height / 2; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - GraphicsPath path = new GraphicsPath(); - GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + var path = new GraphicsPath(); + var pathTab = GetTabOutline_Document(Tabs[index], true, true, true); path.AddPath(pathTab, true); if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) @@ -623,17 +455,20 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); } return path; + } private GraphicsPath GetOutline_ToolWindow(int index) { - Rectangle rectTab = Tabs[index].Rectangle.Value; + var rectangle = Tabs[index].Rectangle; + if (rectangle == null) return null; + var rectTab = rectangle.Value; rectTab.Intersect(TabsRectangle); rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); - Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + var rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); - GraphicsPath path = new GraphicsPath(); - GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); + var path = new GraphicsPath(); + var pathTab = GetTabOutline(Tabs[index], true, true); path.AddPath(pathTab, true); path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); @@ -641,6 +476,7 @@ namespace mRemoteNG.UI.Tabs path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); return path; + } private void CalculateTabs() @@ -656,38 +492,38 @@ namespace mRemoteNG.UI.Tabs if (Tabs.Count <= 1 || DockPane.IsAutoHide) return; - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; // Calculate tab widths - int countTabs = Tabs.Count; - foreach (MremoteNGTab tab in Tabs) + var countTabs = Tabs.Count; + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); tab.Flag = false; } // Set tab whose max width less than average width - bool anyWidthWithinAverage = true; - int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; - int totalAllocatedWidth = 0; - int averageWidth = totalWidth / countTabs; - int remainedTabs = countTabs; + bool anyWidthWithinAverage; + var totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + var totalAllocatedWidth = 0; + var averageWidth = totalWidth / countTabs; + var remainedTabs = countTabs; for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0;) { anyWidthWithinAverage = false; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; - if (tab.MaxWidth <= averageWidth) - { - tab.Flag = true; - tab.TabWidth = tab.MaxWidth; - totalAllocatedWidth += tab.TabWidth; - anyWidthWithinAverage = true; - remainedTabs--; - } + if (tab.MaxWidth > averageWidth) continue; + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; } if (remainedTabs != 0) averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; @@ -696,9 +532,10 @@ namespace mRemoteNG.UI.Tabs // If any tab width not set yet, set it to the average width if (remainedTabs > 0) { - int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); - foreach (MremoteNGTab tab in Tabs) + var roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; if (tab.Flag) continue; @@ -714,9 +551,10 @@ namespace mRemoteNG.UI.Tabs } // Set the X position of the tabs - int x = rectTabStrip.X + ToolWindowStripGapLeft; - foreach (MremoteNGTab tab in Tabs) + var x = rectTabStrip.X + ToolWindowStripGapLeft; + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } @@ -724,11 +562,11 @@ namespace mRemoteNG.UI.Tabs private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) { - bool overflow = false; + var overflow = false; - var tab = Tabs[index] as MremoteNGTab; + if (!(Tabs[index] is MremoteNGTab tab)) return false; tab.MaxWidth = GetMaxTabWidth(index); - int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + var width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); if (x + width < rectTabStrip.Right || index == StartDisplayingTab) { tab.TabX = x; @@ -741,6 +579,7 @@ namespace mRemoteNG.UI.Tabs tab.TabWidth = 0; overflow = true; } + x += width; return overflow; @@ -754,10 +593,10 @@ namespace mRemoteNG.UI.Tabs if (m_startDisplayingTab >= Tabs.Count) m_startDisplayingTab = 0; - Rectangle rectTabStrip = TabsRectangle; + var rectTabStrip = TabsRectangle; - int x = rectTabStrip.X; //+ rectTabStrip.Height / 2; - bool overflow = false; + var x = rectTabStrip.X; //+ rectTabStrip.Height / 2; + var overflow = false; // Originally all new documents that were considered overflow // (not enough pane strip space to show all tabs) were added to @@ -766,12 +605,12 @@ namespace mRemoteNG.UI.Tabs // then we are dealing with making sure a specific tab is kept in focus. if (m_startDisplayingTab > 0) { - int tempX = x; - var tab = Tabs[m_startDisplayingTab] as MremoteNGTab; - tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + var tempX = x; + if (Tabs[m_startDisplayingTab] is MremoteNGTab tab) + tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); // Add the active tab and tabs to the left - for (int i = StartDisplayingTab; i >= 0; i--) + for (var i = StartDisplayingTab; i >= 0; i--) CalculateDocumentTab(rectTabStrip, ref tempX, i); // Store which tab is the first one displayed so that it @@ -783,7 +622,7 @@ namespace mRemoteNG.UI.Tabs // Start with the first tab displayed - name is a little misleading. // Loop through each tab and set its location. If there is not enough // room for all of them overflow will be returned. - for (int i = EndDisplayingTab; i < Tabs.Count; i++) + for (var i = EndDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); // If not all tabs are shown then we have an overflow. @@ -792,9 +631,9 @@ namespace mRemoteNG.UI.Tabs } else { - for (int i = StartDisplayingTab; i < Tabs.Count; i++) + for (var i = StartDisplayingTab; i < Tabs.Count; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); - for (int i = 0; i < StartDisplayingTab; i++) + for (var i = 0; i < StartDisplayingTab; i++) overflow = CalculateDocumentTab(rectTabStrip, ref x, i); FirstDisplayingTab = StartDisplayingTab; @@ -805,8 +644,9 @@ namespace mRemoteNG.UI.Tabs m_startDisplayingTab = 0; FirstDisplayingTab = 0; x = rectTabStrip.X; - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { + var tab = (MremoteNGTab) tab1; tab.TabX = x; x += tab.TabWidth; } @@ -826,12 +666,11 @@ namespace mRemoteNG.UI.Tabs private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) { - int index = Tabs.IndexOf(content); + var index = Tabs.IndexOf(content); if (index == -1) // TODO: should prevent it from being -1; return false; - var tab = Tabs[index] as MremoteNGTab; - if (tab.TabWidth != 0) + if (Tabs[index] is MremoteNGTab tab && tab.TabWidth != 0) return false; StartDisplayingTab = index; @@ -845,14 +684,13 @@ namespace mRemoteNG.UI.Tabs { if (Appearance == DockPane.AppearanceStyle.ToolWindow) return GetMaxTabWidth_ToolWindow(index); - else - return GetMaxTabWidth_Document(index); + return GetMaxTabWidth_Document(index); } private int GetMaxTabWidth_ToolWindow(int index) { - IDockContent content = Tabs[index].Content; - Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + var content = Tabs[index].Content; + var sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + ToolWindowImageGapRight + ToolWindowTextGapRight; } @@ -861,9 +699,9 @@ namespace mRemoteNG.UI.Tabs private int GetMaxTabWidth_Document(int index) { - IDockContent content = Tabs[index].Content; - int height = GetTabRectangle_Document(index).Height; - Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + var content = Tabs[index].Content; + var height = GetTabRectangle_Document(index).Height; + var sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); int width; if (DockPane.DockPanel.ShowDocumentIcon) @@ -878,7 +716,7 @@ namespace mRemoteNG.UI.Tabs private void DrawTabStrip(Graphics g) { // IMPORTANT: fill background. - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background), rectTabStrip); if (Appearance == DockPane.AppearanceStyle.Document) @@ -889,42 +727,37 @@ namespace mRemoteNG.UI.Tabs private void DrawTabStrip_Document(Graphics g) { - int count = Tabs.Count; + var count = Tabs.Count; if (count == 0) return; - Rectangle rectTabStrip = new Rectangle(TabStripRectangle.Location, TabStripRectangle.Size); + var rectTabStrip = new Rectangle(TabStripRectangle.Location, TabStripRectangle.Size); rectTabStrip.Height += 1; // Draw the tabs - Rectangle rectTabOnly = TabsRectangle; - Rectangle rectTab = Rectangle.Empty; + var rectTabOnly = TabsRectangle; + Rectangle rectTab; MremoteNGTab tabActive = null; g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { rectTab = GetTabRectangle(i); if (Tabs[i].Content == DockPane.ActiveContent) { tabActive = Tabs[i] as MremoteNGTab; - tabActive.Rectangle = rectTab; + if (tabActive != null) tabActive.Rectangle = rectTab; continue; } - if (rectTab.IntersectsWith(rectTabOnly)) - { - var tab = Tabs[i] as MremoteNGTab; - tab.Rectangle = rectTab; - DrawTab(g, tab); - } + if (!rectTab.IntersectsWith(rectTabOnly)) continue; + if (!(Tabs[i] is MremoteNGTab tab)) continue; + tab.Rectangle = rectTab; + DrawTab(g, tab); } g.SetClip(rectTabStrip); - if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) - { - } - else + if (DockPane.DockPanel.DocumentTabStripLocation != DocumentTabStripLocation.Bottom) { Color tabUnderLineColor; if (tabActive != null && DockPane.IsActiveDocumentPane) @@ -936,29 +769,25 @@ namespace mRemoteNG.UI.Tabs } g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); - if (tabActive != null) - { - rectTab = tabActive.Rectangle.Value; - if (rectTab.IntersectsWith(rectTabOnly)) - { - rectTab.Intersect(rectTabOnly); - tabActive.Rectangle = rectTab; - DrawTab(g, tabActive); - } - } + if (tabActive == null) return; + rectTab = tabActive.Rectangle.Value; + if (!rectTab.IntersectsWith(rectTabOnly)) return; + rectTab.Intersect(rectTabOnly); + tabActive.Rectangle = rectTab; + DrawTab(g, tabActive); } private void DrawTabStrip_ToolWindow(Graphics g) { var rect = TabStripRectangle_ToolWindow; - Color borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; + var borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, rect.Right, rect.Top); - for (int i = 0; i < Tabs.Count; i++) + for (var i = 0; i < Tabs.Count; i++) { - var tab = Tabs[i] as MremoteNGTab; + if (!(Tabs[i] is MremoteNGTab tab)) continue; tab.Rectangle = GetTabRectangle(i); DrawTab(g, tab); } @@ -966,29 +795,26 @@ namespace mRemoteNG.UI.Tabs private Rectangle GetTabRectangle(int index) { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return GetTabRectangle_ToolWindow(index); - else - return GetTabRectangle_Document(index); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabRectangle_ToolWindow(index) : GetTabRectangle_Document(index); } private Rectangle GetTabRectangle_ToolWindow(int index) { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; - MremoteNGTab tab = (MremoteNGTab)Tabs[index]; + var tab = (MremoteNGTab)Tabs[index]; return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height); } private Rectangle GetTabRectangle_Document(int index) { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; var tab = (MremoteNGTab)Tabs[index]; - Rectangle rect = new Rectangle(); - rect.X = tab.TabX; - rect.Width = tab.TabWidth; - rect.Height = rectTabStrip.Height - DocumentTabGapTop; + var rect = new Rectangle + { + X = tab.TabX, Width = tab.TabWidth, Height = rectTabStrip.Height - DocumentTabGapTop + }; if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) rect.Y = rectTabStrip.Y + DocumentStripGapBottom; @@ -1010,13 +836,12 @@ namespace mRemoteNG.UI.Tabs { if (Appearance == DockPane.AppearanceStyle.ToolWindow) return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); - else - return GetTabOutline_Document(tab, rtlTransform, toScreen, false); + return GetTabOutline_Document(tab, rtlTransform, toScreen, false); } private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) { - Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + var rect = GetTabRectangle(Tabs.IndexOf(tab)); if (rtlTransform) rect = DrawHelper.RtlTransform(this, rect); if (toScreen) @@ -1029,7 +854,7 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full) { GraphicsPath.Reset(); - Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab)); + var rect = GetTabRectangle(Tabs.IndexOf(tab)); // Shorten TabOutline so it doesn't get overdrawn by icons next to it rect.Intersect(TabsRectangle); @@ -1046,12 +871,13 @@ namespace mRemoteNG.UI.Tabs private void DrawTab_ToolWindow(Graphics g, MremoteNGTab tab) { + if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; - Rectangle rectIcon = new Rectangle( + var rectIcon = new Rectangle( rect.X + ToolWindowImageGapLeft, rect.Y + rect.Height - ToolWindowImageGapBottom - ToolWindowImageHeight, ToolWindowImageWidth, ToolWindowImageHeight); - Rectangle rectText = PatchController.EnableHighDpi == true + var rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + ToolWindowImageGapLeft, rect.Y + rect.Height - ToolWindowImageGapBottom - TextFont.Height, @@ -1059,14 +885,14 @@ namespace mRemoteNG.UI.Tabs : rectIcon; rectText.X += rectIcon.Width + ToolWindowImageGapRight; rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - - ToolWindowImageGapRight - ToolWindowTextGapRight; + ToolWindowImageGapRight - ToolWindowTextGapRight; - Rectangle rectTab = DrawHelper.RtlTransform(this, rect); + var rectTab = DrawHelper.RtlTransform(this, rect); rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - Color borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; + var borderColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowBorder; - Color separatorColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowSeparator; + var separatorColor = DockPane.DockPanel.Theme.ColorPalette.ToolWindowSeparator; if (DockPane.ActiveContent == tab.Content) { Color textColor; @@ -1108,7 +934,7 @@ namespace mRemoteNG.UI.Tabs g.FillRectangle(DockPane.DockPanel.Theme.PaintingService.GetBrush(backgroundColor), rect); g.DrawLine(DockPane.DockPanel.Theme.PaintingService.GetPen(borderColor), rect.Left, rect.Top, - rect.Right, rect.Top); + rect.Right, rect.Top); TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat); } @@ -1118,16 +944,17 @@ namespace mRemoteNG.UI.Tabs private void DrawTab_Document(Graphics g, MremoteNGTab tab) { + if (tab.Rectangle == null) return; var rect = tab.Rectangle.Value; if (tab.TabWidth == 0) return; var rectCloseButton = GetCloseButtonRect(rect); - Rectangle rectIcon = new Rectangle( + var rectIcon = new Rectangle( rect.X + DocumentIconGapLeft, rect.Y + rect.Height - DocumentIconGapBottom - DocumentIconHeight, DocumentIconWidth, DocumentIconHeight); - Rectangle rectText = PatchController.EnableHighDpi == true + var rectText = PatchController.EnableHighDpi == true ? new Rectangle( rect.X + DocumentIconGapLeft, rect.Y + rect.Height - DocumentIconGapBottom - TextFont.Height, @@ -1143,23 +970,23 @@ namespace mRemoteNG.UI.Tabs else rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight - rectCloseButton.Width; - Rectangle rectTab = DrawHelper.RtlTransform(this, rect); - Rectangle rectBack = DrawHelper.RtlTransform(this, rect); + var rectTab = DrawHelper.RtlTransform(this, rect); + var rectBack = DrawHelper.RtlTransform(this, rect); rectBack.Width += DocumentIconGapLeft; rectBack.X -= DocumentIconGapLeft; rectText = DrawHelper.RtlTransform(this, rectText); rectIcon = DrawHelper.RtlTransform(this, rectIcon); - Color activeColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background; - Color lostFocusColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background; - Color inactiveColor = DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background; - Color mouseHoverColor = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Background; + var activeColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background; + var lostFocusColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background; + var inactiveColor = DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background; + var mouseHoverColor = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Background; - Color activeText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Text; - Color lostFocusText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Text; - Color inactiveText = DockPane.DockPanel.Theme.ColorPalette.TabUnselected.Text; - Color mouseHoverText = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Text; + var activeText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Text; + var lostFocusText = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Text; + var inactiveText = DockPane.DockPanel.Theme.ColorPalette.TabUnselected.Text; + var mouseHoverText = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Text; Color text; Image image = null; @@ -1216,10 +1043,10 @@ namespace mRemoteNG.UI.Tabs g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon); } - private bool m_isMouseDown = false; + private bool m_isMouseDown; protected bool IsMouseDown { - get { return m_isMouseDown; } + get => m_isMouseDown; private set { if (m_isMouseDown == value) @@ -1241,39 +1068,47 @@ namespace mRemoteNG.UI.Tabs { base.OnMouseDown(e); // suspend drag if mouse is down on active close button. - this.m_suspendDrag = ActiveCloseHitTest(e.Location); + m_suspendDrag = ActiveCloseHitTest(e.Location); if (!IsMouseDown) IsMouseDown = true; } protected override void OnMouseMove(MouseEventArgs e) { - if (!this.m_suspendDrag) + if (!m_suspendDrag) base.OnMouseMove(e); - int index = HitTest(PointToClient(MousePosition)); - string toolTip = string.Empty; + var index = HitTest(PointToClient(MousePosition)); + var toolTip = string.Empty; - bool tabUpdate = false; - bool buttonUpdate = false; + var tabUpdate = false; + var buttonUpdate = false; if (index != -1) { - var tab = Tabs[index] as MremoteNGTab; - if (Appearance == DockPane.AppearanceStyle.ToolWindow || Appearance == DockPane.AppearanceStyle.Document) + if (Tabs[index] is MremoteNGTab tab) { - tabUpdate = SetMouseOverTab(tab.Content == DockPane.ActiveContent ? null : tab.Content); + if (Appearance == DockPane.AppearanceStyle.ToolWindow || + Appearance == DockPane.AppearanceStyle.Document) + { + tabUpdate = SetMouseOverTab(tab.Content == DockPane.ActiveContent ? null : tab.Content); + } + + if (!string.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) + toolTip = tab.Content.DockHandler.ToolTipText; + else if (tab.MaxWidth > tab.TabWidth) + toolTip = tab.Content.DockHandler.TabText; + + var mousePos = PointToClient(MousePosition); + if (tab.Rectangle != null) + { + var tabRect = tab.Rectangle.Value; + var closeButtonRect = GetCloseButtonRect(tabRect); + var mouseRect = new Rectangle(mousePos, new Size(1, 1)); + buttonUpdate = SetActiveClose(closeButtonRect.IntersectsWith(mouseRect) + ? closeButtonRect + : Rectangle.Empty); + } } - - if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText)) - toolTip = tab.Content.DockHandler.ToolTipText; - else if (tab.MaxWidth > tab.TabWidth) - toolTip = tab.Content.DockHandler.TabText; - - var mousePos = PointToClient(MousePosition); - var tabRect = tab.Rectangle.Value; - var closeButtonRect = GetCloseButtonRect(tabRect); - var mouseRect = new Rectangle(mousePos, new Size(1, 1)); - buttonUpdate = SetActiveClose(closeButtonRect.IntersectsWith(mouseRect) ? closeButtonRect : Rectangle.Empty); } else { @@ -1284,12 +1119,10 @@ namespace mRemoteNG.UI.Tabs if (tabUpdate || buttonUpdate) Invalidate(); - if (m_toolTip.GetToolTip(this) != toolTip) - { - m_toolTip.Active = false; - m_toolTip.SetToolTip(this, toolTip); - m_toolTip.Active = true; - } + if (m_toolTip.GetToolTip(this) == toolTip) return; + m_toolTip.Active = false; + m_toolTip.SetToolTip(this, toolTip); + m_toolTip.Active = true; } protected override void OnMouseClick(MouseEventArgs e) @@ -1326,12 +1159,13 @@ namespace mRemoteNG.UI.Tabs private void WindowList_Click(object sender, EventArgs e) { SelectMenu.Items.Clear(); - foreach (MremoteNGTab tab in Tabs) + foreach (var tab1 in Tabs) { - IDockContent content = tab.Content; - ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); + var tab = (MremoteNGTab) tab1; + var content = tab.Content; + var item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap()); item.Tag = tab.Content; - item.Click += new EventHandler(ContextMenuItem_Click); + item.Click += ContextMenuItem_Click; } var workingArea = Screen.GetWorkingArea(ButtonWindowList.PointToScreen(new Point(ButtonWindowList.Width / 2, ButtonWindowList.Height / 2))); @@ -1362,10 +1196,10 @@ namespace mRemoteNG.UI.Tabs private void ContextMenuItem_Click(object sender, EventArgs e) { - ToolStripMenuItem item = sender as ToolStripMenuItem; + var item = sender as ToolStripMenuItem; if (item != null) { - IDockContent content = (IDockContent)item.Tag; + var content = (IDockContent)item.Tag; DockPane.ActiveContent = content; } } @@ -1403,23 +1237,23 @@ namespace mRemoteNG.UI.Tabs private void LayoutButtons() { - Rectangle rectTabStrip = TabStripRectangle; + var rectTabStrip = TabStripRectangle; // Set position and size of the buttons - int buttonWidth = ButtonOverflow.Image.Width; - int buttonHeight = ButtonOverflow.Image.Height; - int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; + var buttonWidth = ButtonOverflow.Image.Width; + var buttonHeight = ButtonOverflow.Image.Height; + var height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; if (buttonHeight < height) { buttonWidth = buttonWidth * height / buttonHeight; buttonHeight = height; } - Size buttonSize = new Size(buttonWidth, buttonHeight); + var buttonSize = new Size(buttonWidth, buttonHeight); - int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft + var x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft - DocumentButtonGapRight - buttonWidth; - int y = rectTabStrip.Y + DocumentButtonGapTop; - Point point = new Point(x, y); + var y = rectTabStrip.Y + DocumentButtonGapTop; + var point = new Point(x, y); ButtonOverflow.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); // If the close button is not visible draw the window list button overtop. @@ -1441,9 +1275,9 @@ namespace mRemoteNG.UI.Tabs if (!TabsRectangle.Contains(point)) return -1; - foreach (Tab tab in Tabs) + foreach (var tab in Tabs) { - GraphicsPath path = GetTabOutline(tab, true, false); + var path = GetTabOutline(tab, true, false); if (path.IsVisible(point)) return Tabs.IndexOf(tab); } @@ -1453,7 +1287,7 @@ namespace mRemoteNG.UI.Tabs protected override bool MouseDownActivateTest(MouseEventArgs e) { - bool result = base.MouseDownActivateTest(e); + var result = base.MouseDownActivateTest(e); if (result && (e.Button == MouseButtons.Left) && (Appearance == DockPane.AppearanceStyle.Document)) { // don't activate if mouse is down on active close button @@ -1464,7 +1298,7 @@ namespace mRemoteNG.UI.Tabs private bool ActiveCloseHitTest(Point ptMouse) { - bool result = false; + var result = false; if (!ActiveClose.IsEmpty) { var mouseRect = new Rectangle(ptMouse, new Size(1, 1)); @@ -1475,22 +1309,19 @@ namespace mRemoteNG.UI.Tabs protected override Rectangle GetTabBounds(Tab tab) { - GraphicsPath path = GetTabOutline(tab, true, false); - RectangleF rectangle = path.GetBounds(); + var path = GetTabOutline(tab, true, false); + var rectangle = path.GetBounds(); return new Rectangle((int)rectangle.Left, (int)rectangle.Top, (int)rectangle.Width, (int)rectangle.Height); } - private Rectangle ActiveClose - { - get { return _activeClose; } - } + private Rectangle ActiveClose { get; set; } private bool SetActiveClose(Rectangle rectangle) { - if (_activeClose == rectangle) + if (ActiveClose == rectangle) return false; - _activeClose = rectangle; + ActiveClose = rectangle; return true; } @@ -1523,7 +1354,7 @@ namespace mRemoteNG.UI.Tabs [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { - if (m.Msg == (int)mRemoteNG.UI.Tabs.Msgs.WM_LBUTTONDBLCLK) + if (m.Msg == (int)Msgs.WM_LBUTTONDBLCLK) { if (Settings.Default.DoubleClickOnTabClosesIt) { @@ -1538,7 +1369,6 @@ namespace mRemoteNG.UI.Tabs } base.WndProc(ref m); - return; } #endregion From f180a5cd707e3ab6eabbe1e6c10a57d24cf33de8 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 10:14:57 -0500 Subject: [PATCH 073/157] do nothing if double click on close is not set --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 69101cb40..97ca3ec65 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -1356,16 +1356,17 @@ namespace mRemoteNG.UI.Tabs { if (m.Msg == (int)Msgs.WM_LBUTTONDBLCLK) { - if (Settings.Default.DoubleClickOnTabClosesIt) + // If the option is not set, do nothing. Do not send the message to base. + if (!Settings.Default.DoubleClickOnTabClosesIt) return; + + // Option is set, close the tab, then send to base. + DockPane.CloseActiveContent(); + if (PatchController.EnableMemoryLeakFix == true) { - DockPane.CloseActiveContent(); - if (PatchController.EnableMemoryLeakFix == true) - { - ContentClosed(); - } - return; + ContentClosed(); } + return; } base.WndProc(ref m); From a37cd62d7e161c816d59c5fad62f272398a0db17 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 10:49:32 -0500 Subject: [PATCH 074/157] more updates to change themes on restart only --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 43 ++++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index e30db4377..1aaaa46f5 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -49,13 +49,13 @@ namespace mRemoteNG.UI.Forms.OptionsPages { if (!_themeManager.ThemingActive) return; - base.ApplyTheme(); + base.ApplyTheme(); } public override void LoadSettings() { themeEnableChk.CheckedChanged -= ThemeEnableChkCheckedChanged; - base.SaveSettings(); + SaveSettings(); //At first we cannot create or delete themes, depends later on the type of selected theme btnThemeNew.Enabled = false; btnThemeDelete.Enabled = false; @@ -66,19 +66,19 @@ namespace mRemoteNG.UI.Forms.OptionsPages cboTheme.SelectedItem = _themeManager.ActiveTheme; cboTheme_SelectionChangeCommitted(this, new EventArgs()); cboTheme.DisplayMember = "Name"; - - //Load theming active property and disable controls - if (_themeManager.ThemingActive) + + //Load theming active property and disable controls + if (Settings.Default.ThemingActive) { themeEnableChk.Checked = true; - listPalette.FormatCell += ListPalette_FormatCell; //Color cell formatter + listPalette.FormatCell += ListPalette_FormatCell; //Color cell formatter } else { themeEnableChk.Checked = false; cboTheme.Enabled = false; // reset to the default theme when disabling theme support - _themeManager.ActiveTheme = _themeManager.DefaultTheme; + //_themeManager.ActiveTheme = _themeManager.DefaultTheme; } themeEnableChk.CheckedChanged += ThemeEnableChkCheckedChanged; } @@ -95,13 +95,18 @@ namespace mRemoteNG.UI.Forms.OptionsPages { // Save the theme settings form close so we don't run into unexpected results while modifying... // Prompt the user that a restart is required to apply the new theme... - if (!Settings.Default.ThemeName.Equals(((ThemeInfo)cboTheme.SelectedItem).Name)) + if (themeEnableChk != null && cboTheme.SelectedItem != null) // LoadSettings calls SaveSettings, so these might be null the first time around { - Settings.Default.ThemeName = ((ThemeInfo)cboTheme.SelectedItem).Name; - Settings.Default.Save(); + if (Settings.Default.ThemingActive != themeEnableChk.Checked || + !Settings.Default.ThemeName.Equals(((ThemeInfo) cboTheme.SelectedItem).Name)) + { + Settings.Default.ThemingActive = themeEnableChk.Checked; + Settings.Default.ThemeName = themeEnableChk.Checked ? ((ThemeInfo) cboTheme.SelectedItem).Name : _themeManager.DefaultTheme.Name; + Settings.Default.Save(); - CTaskDialog.MessageBox("Theme Changed", "Restart Required.", "Please restart mRemoteNG to apply the selected theme.", - ETaskDialogButtons.Ok, ESysIcons.Information); + CTaskDialog.MessageBox("Theme Changed", "Restart Required.","Please restart mRemoteNG to apply the selected theme.", + ETaskDialogButtons.Ok, ESysIcons.Information); + } } base.SaveSettings(); @@ -134,7 +139,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages btnThemeNew.Enabled = true; var selectedTheme = (ThemeInfo)cboTheme.SelectedItem; - + if (selectedTheme.IsExtendable) { // it's Extendable, so now we can do this more expensive operations... @@ -224,14 +229,14 @@ namespace mRemoteNG.UI.Forms.OptionsPages { if(_themeManager.ThemesCount > 0) { - _themeManager.ThemingActive = true; + //_themeManager.ThemingActive = true; cboTheme.Enabled = true; } else { CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeErrorNoThemes, "", "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, ESysIcons.Information, 0); themeEnableChk.Checked = false; - _themeManager.ThemingActive = false; + //_themeManager.ThemingActive = false; cboTheme.Enabled = false; } @@ -239,11 +244,15 @@ namespace mRemoteNG.UI.Forms.OptionsPages } else { - _themeManager.ThemingActive = false; - themeEnableChk.Checked = false; + //_themeManager.ThemingActive = false; cboTheme.Enabled = false; listPalette.FormatCell -= ListPalette_FormatCell; } + + /* LoadSettings calls save settings first... This will save the selected theme options accordingly... + * Changes to ThemingActive value above have been commented out in order to require a restart for the + * changes to take full effect. + */ LoadSettings(); } } From 71cabea03e9e2c169373340caabb2b22bce51dd9 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:15:25 -0500 Subject: [PATCH 075/157] minor cleanup --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 97ca3ec65..c25f3446a 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -1298,13 +1298,9 @@ namespace mRemoteNG.UI.Tabs private bool ActiveCloseHitTest(Point ptMouse) { - var result = false; - if (!ActiveClose.IsEmpty) - { - var mouseRect = new Rectangle(ptMouse, new Size(1, 1)); - result = ActiveClose.IntersectsWith(mouseRect); - } - return result; + if (ActiveClose.IsEmpty) return false; + var mouseRect = new Rectangle(ptMouse, new Size(1, 1)); + return ActiveClose.IntersectsWith(mouseRect); } protected override Rectangle GetTabBounds(Tab tab) From 8a6294289496754bb372dbeb157c63bf85d97acd Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:16:27 -0500 Subject: [PATCH 076/157] whitespace cleanup --- mRemoteV1/UI/Window/ConnectionWindow.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 4df04dab8..590875c30 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -24,7 +24,7 @@ namespace mRemoteNG.UI.Window { private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private VisualStudioToolStripExtender vsToolStripExtender; - private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); + private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); #region Public Methods public ConnectionWindow(DockContent panel, string formText = "") @@ -129,7 +129,7 @@ namespace mRemoteNG.UI.Window //Show the tab conTab.Show(connDock,DockState.Document); - conTab.Focus(); + conTab.Focus(); return conTab; } catch (Exception ex) @@ -158,7 +158,7 @@ namespace mRemoteNG.UI.Window initiator.OpenConnection(iControl.Info, ConnectionInfo.Force.DoNotJump); } - } + } catch(Exception ex) { Runtime.MessageCollector.AddExceptionMessage("reconnectAll (UI.Window.ConnectionWindow) failed", ex); @@ -574,7 +574,7 @@ namespace mRemoteNG.UI.Window } - private void CloseTabMenu() + private void CloseTabMenu() { var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; if (selectedTab == null) return; @@ -610,17 +610,17 @@ namespace mRemoteNG.UI.Window { var tab = (ConnectionTab) dockContent; if (selectedTab != tab) - { + { tab.Close(); } - } + } } private void CloseOtherTabsToTheRight() { try - { + { var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; if (selectedTab == null) return; var dockPane = selectedTab.Pane; @@ -644,7 +644,7 @@ namespace mRemoteNG.UI.Window catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); - } + } } private void DuplicateTab() @@ -688,7 +688,7 @@ namespace mRemoteNG.UI.Window if (dr != DialogResult.OK) return; if(!string.IsNullOrEmpty(frmInputBox.returnValue)) ((ConnectionTab)interfaceControl.Parent).TabText = frmInputBox.returnValue.Replace("&", "&&"); - } + } } catch (Exception ex) { From 9d10ee2da5bad8e99a86bf0bd340296b6f219cd5 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:45:41 -0500 Subject: [PATCH 077/157] saftey checks --- mRemoteV1/Connection/InterfaceControl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mRemoteV1/Connection/InterfaceControl.cs b/mRemoteV1/Connection/InterfaceControl.cs index 87596e81c..733f03a9a 100644 --- a/mRemoteV1/Connection/InterfaceControl.cs +++ b/mRemoteV1/Connection/InterfaceControl.cs @@ -36,6 +36,7 @@ namespace mRemoteNG.Connection public static InterfaceControl FindInterfaceControl(DockPanel DockPnl) { if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null; + if (ct.Controls.Count < 1) return null; if (ct.Controls[0] is InterfaceControl ic) return ic; @@ -44,6 +45,7 @@ namespace mRemoteNG.Connection public static InterfaceControl FindInterfaceControl(ConnectionTab tab) { + if (tab.Controls.Count < 1) return null; if (tab.Controls[0] is InterfaceControl ic) return ic; From 018a97fb8ec4d8e9ef6dfbddf363a6ea316f001c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:46:22 -0500 Subject: [PATCH 078/157] whitespace cleanup --- mRemoteV1/UI/Forms/frmMain.cs | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 9d31602de..f4ffb7f02 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -50,7 +50,7 @@ namespace mRemoteNG.UI.Forms private readonly FileBackupPruner _backupPruner = new FileBackupPruner(); internal FullscreenHandler Fullscreen { get; set; } - + //Added theming support private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); @@ -86,7 +86,7 @@ namespace mRemoteNG.UI.Forms UpdateWindowTitle(); } } - + public string ConnectionsFileName { get => _connectionsFileName; @@ -100,7 +100,7 @@ namespace mRemoteNG.UI.Forms UpdateWindowTitle(); } } - + public bool ShowFullPathInTitle { get => _showFullPathInTitle; @@ -114,7 +114,7 @@ namespace mRemoteNG.UI.Forms UpdateWindowTitle(); } } - + public ConnectionInfo SelectedConnection { get => _selectedConnection; @@ -151,7 +151,7 @@ namespace mRemoteNG.UI.Forms LockToolbarPositions(Settings.Default.LockToolbars); Settings.Default.PropertyChanged += OnApplicationSettingChanged; - _themeManager.ThemeChanged += ApplyTheme; + _themeManager.ThemeChanged += ApplyTheme; _fpChainedWindowHandle = NativeMethods.SetClipboardViewer(Handle); @@ -194,7 +194,7 @@ namespace mRemoteNG.UI.Forms if (!panelAdder.DoesPanelExist(panelName)) panelAdder.AddPanel(panelName); }*/ - + var frmSplashScreen = FrmSplashScreen.getInstance(); frmSplashScreen.Close(); } @@ -276,7 +276,7 @@ namespace mRemoteNG.UI.Forms { // intentionally ignore exception } - + // Persist settings when rebuilding UI try { @@ -372,7 +372,7 @@ namespace mRemoteNG.UI.Forms } Shutdown.Cleanup(_quickConnectToolStrip, _externalToolsToolStrip, _multiSshToolStrip, this); - + IsClosing = true; if (Runtime.WindowList != null) @@ -384,11 +384,11 @@ namespace mRemoteNG.UI.Forms } Shutdown.StartUpdate(); - + Debug.Print("[END] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); } #endregion - + #region Timer private void tmrAutoSave_Tick(object sender, EventArgs e) { @@ -396,7 +396,7 @@ namespace mRemoteNG.UI.Forms Runtime.ConnectionsService.SaveConnectionsAsync(); } #endregion - + #region Window Overrides and DockPanel Stuff private void frmMain_ResizeBegin(object sender, EventArgs e) { @@ -422,11 +422,11 @@ namespace mRemoteNG.UI.Forms private void frmMain_ResizeEnd(object sender, EventArgs e) { - _inSizeMove = false; + _inSizeMove = false; // This handles activations from clicks that started a size/move operation ActivateConnection(); - } - + } + protected override void WndProc(ref System.Windows.Forms.Message m) { // Listen for and handle operating system messages @@ -506,7 +506,7 @@ namespace mRemoteNG.UI.Forms { Runtime.MessageCollector.AddExceptionStackTrace("frmMain WndProc failed", ex); } - + base.WndProc(ref m); } @@ -524,7 +524,7 @@ namespace mRemoteNG.UI.Forms { var cw = pnlDock.ActiveDocument as ConnectionWindow; var dp = cw?.ActiveControl as DockPane; - + if (!(dp?.ActiveContent is ConnectionTab tab)) return; var ifc = InterfaceControl.FindInterfaceControl(tab); if (ifc == null) return; @@ -538,7 +538,7 @@ namespace mRemoteNG.UI.Forms { ActivateConnection(); } - + internal void UpdateWindowTitle() { if (InvokeRequired) @@ -546,10 +546,10 @@ namespace mRemoteNG.UI.Forms Invoke(new MethodInvoker(UpdateWindowTitle)); return; } - + var titleBuilder = new StringBuilder(Application.ProductName); const string separator = " - "; - + if (Runtime.ConnectionsService.IsConnectionsFileLoaded) { if (Runtime.ConnectionsService.UsingDatabase) @@ -568,7 +568,7 @@ namespace mRemoteNG.UI.Forms } } } - + if (!string.IsNullOrEmpty(SelectedConnection?.Name)) { titleBuilder.Append(separator); @@ -577,11 +577,11 @@ namespace mRemoteNG.UI.Forms Text = titleBuilder.ToString(); } - + public void ShowHidePanelTabs(DockContent closingDocument = null) { DocumentStyle newDocumentStyle; - + if (Settings.Default.AlwaysShowPanelTabs) { newDocumentStyle = DocumentStyle.DockingWindow; // Show the panel tabs @@ -606,7 +606,7 @@ namespace mRemoteNG.UI.Forms pnlDock.Size = new Size(1, 1); } #endregion - + #region Screen Stuff public void SetDefaultLayout() { @@ -623,8 +623,8 @@ namespace mRemoteNG.UI.Forms Windows.ConfigForm.Show(pnlDock); Windows.ConfigForm.DockTo(Windows.TreeForm.Pane, DockStyle.Bottom, -1); Windows.ErrorsForm.DockAreas = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float; - Windows.ErrorsForm.Show( pnlDock, DockState.DockBottomAutoHide ); - Windows.ScreenshotForm.Hide(); + Windows.ErrorsForm.Show( pnlDock, DockState.DockBottomAutoHide ); + Windows.ScreenshotForm.Hide(); pnlDock.Visible = true; } From fd246bc83b98ff15c76ef3f6d1a946137edac8cc Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:52:38 -0500 Subject: [PATCH 079/157] Update title bar on connection change --- mRemoteV1/UI/Window/ConnectionWindow.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 590875c30..a510fdd98 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -43,6 +43,8 @@ namespace mRemoteNG.UI.Window TabText = formText; connDock.DocumentStyle = DocumentStyle.DockingWindow; connDock.ShowDocumentIcon = true; + + connDock.ActiveContentChanged += ConnDockOnActiveContentChanged; } private InterfaceControl GetInterfaceControl() @@ -305,6 +307,15 @@ namespace mRemoteNG.UI.Window } #endregion + #region Events + private void ConnDockOnActiveContentChanged(object sender, EventArgs e) + { + var ic = GetInterfaceControl(); + if (ic?.Info == null) return; + FrmMain.Default.SelectedConnection = ic.Info; + } + #endregion + #region Tab Menu private void ShowHideMenuButtons(object sender, CancelEventArgs e) { From bb90261521765962e7323972afaa62a1d75b05bc Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 11:57:45 -0500 Subject: [PATCH 080/157] designer generated update --- mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs index 1317514e3..f94e688f4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs @@ -309,7 +309,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.Controls.Add(this.chkHostnameLikeDisplayName); this.Controls.Add(this.chkSingleClickOnOpenedConnectionSwitchesToIt); this.Controls.Add(this.pnlConfirmCloseConnection); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "ConnectionsPage"; this.Size = new System.Drawing.Size(610, 490); ((System.ComponentModel.ISupportInitialize)(this.numRDPConTimeout)).EndInit(); From 8a94000d986be7218de4d398273fd38ee8ac1f91 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 12:02:43 -0500 Subject: [PATCH 081/157] clean up / refactoring --- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 39 ++++++++++------------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index c25f3446a..9af49a551 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -102,15 +102,7 @@ namespace mRemoteNG.UI.Tabs #region Properties - private Rectangle TabStripRectangle - { - get - { - if (Appearance == DockPane.AppearanceStyle.Document) - return TabStripRectangle_Document; - return TabStripRectangle_ToolWindow; - } - } + private Rectangle TabStripRectangle => Appearance == DockPane.AppearanceStyle.Document ? TabStripRectangle_Document : TabStripRectangle_ToolWindow; private Rectangle TabStripRectangle_ToolWindow { @@ -280,10 +272,10 @@ namespace mRemoteNG.UI.Tabs { get { - var textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.HorizontalCenter | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter; + const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; if (RightToLeft == RightToLeft.Yes) return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; return textFormat; @@ -298,10 +290,10 @@ namespace mRemoteNG.UI.Tabs { get { - var textFormat = TextFormatFlags.EndEllipsis | - TextFormatFlags.SingleLine | - TextFormatFlags.VerticalCenter | - TextFormatFlags.HorizontalCenter; + const TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; if (RightToLeft == RightToLeft.Yes) return textFormat | TextFormatFlags.RightToLeft; return textFormat; @@ -834,9 +826,7 @@ namespace mRemoteNG.UI.Tabs private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen) { - if (Appearance == DockPane.AppearanceStyle.ToolWindow) - return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen); - return GetTabOutline_Document(tab, rtlTransform, toScreen, false); + return Appearance == DockPane.AppearanceStyle.ToolWindow ? GetTabOutline_ToolWindow(tab, rtlTransform, toScreen) : GetTabOutline_Document(tab, rtlTransform, toScreen, false); } private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen) @@ -1196,12 +1186,9 @@ namespace mRemoteNG.UI.Tabs private void ContextMenuItem_Click(object sender, EventArgs e) { - var item = sender as ToolStripMenuItem; - if (item != null) - { - var content = (IDockContent)item.Tag; - DockPane.ActiveContent = content; - } + if (!(sender is ToolStripMenuItem item)) return; + var content = (IDockContent)item.Tag; + DockPane.ActiveContent = content; } private void SetInertButtons() From a107d0586fa1498fc409906c4ba1912aa09d3139 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 12:16:50 -0500 Subject: [PATCH 082/157] close the protocol properly, just not the DockContent... --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 5 +++++ mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index d9eecedf1..c612ad867 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -41,6 +41,11 @@ namespace mRemoteNG.UI.Tabs ((InterfaceControl)Tag).Protocol.Close(); } } + else + { + // close without the confirmation prompt... + ((InterfaceControl)Tag).Protocol.Close(); + } } else { diff --git a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs index 9af49a551..437e2cce0 100644 --- a/mRemoteV1/UI/Tabs/DockPaneStripNG.cs +++ b/mRemoteV1/UI/Tabs/DockPaneStripNG.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Security.Permissions; using System.Windows.Forms; +using mRemoteNG.Connection; using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Tabs @@ -1250,7 +1251,8 @@ namespace mRemoteNG.UI.Tabs private void Close_Click(object sender, EventArgs e) { - DockPane.CloseActiveContent(); + CloseProtocol(); + if (PatchController.EnableMemoryLeakFix == true) { ContentClosed(); @@ -1332,8 +1334,14 @@ namespace mRemoteNG.UI.Tabs base.OnRightToLeftChanged(e); PerformLayout(); } - #region Native Methods + private void CloseProtocol() + { + var ic = InterfaceControl.FindInterfaceControl(DockPane.DockPanel); + ic?.Protocol.Close(); + } + + #region Native Methods [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { @@ -1343,7 +1351,9 @@ namespace mRemoteNG.UI.Tabs if (!Settings.Default.DoubleClickOnTabClosesIt) return; // Option is set, close the tab, then send to base. - DockPane.CloseActiveContent(); + //DockPane.CloseActiveContent(); + CloseProtocol(); + if (PatchController.EnableMemoryLeakFix == true) { ContentClosed(); From 40ac2124d88c8bcddccefaf01afa19e26de822d5 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 13:09:41 -0500 Subject: [PATCH 083/157] whitespace clean up --- .../UI/Forms/OptionsPages/CredentialsPage.cs | 2 +- .../UI/Forms/OptionsPages/NotificationsPage.cs | 2 +- mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs index b108111b4..119a3f452 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs @@ -12,7 +12,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages ApplyTheme(); PageIcon = Resources.Key_Icon; } - + public override string PageName { get => Language.Credentials; set { } diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs index a8ab93351..9d8724846 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs @@ -112,7 +112,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.SwitchToMCOnInformation = chkSwitchToMCInformation.Checked; Settings.Default.SwitchToMCOnWarning = chkSwitchToMCWarnings.Checked; Settings.Default.SwitchToMCOnError = chkSwitchToMCErrors.Checked; - + } private void SaveLoggingSettings() diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index 0a1552aa2..55ad18f20 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -12,11 +12,11 @@ namespace mRemoteNG.UI.Forms.OptionsPages InitializeComponent(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; } - + #region Public Properties // ReSharper disable once UnusedAutoPropertyAccessor.Global [Browsable(false)]public virtual string PageName {get; set;} - + public virtual Icon PageIcon {get; protected set;} public virtual Image IconImage => PageIcon?.ToBitmap(); @@ -25,22 +25,22 @@ namespace mRemoteNG.UI.Forms.OptionsPages #region Public Methods public virtual void ApplyLanguage() { - + } - + public virtual void LoadSettings() { - + } - + public virtual void SaveSettings() { - + } - + public virtual void RevertSettings() { - + } #endregion From 32cff8af6d2d1644d81ec749891400cbc93ceec8 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 13:10:20 -0500 Subject: [PATCH 084/157] remove old code --- mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index 55ad18f20..87c49ff29 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -44,20 +44,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages } #endregion - /* - private void InitializeComponent() - { - SuspendLayout(); - // - // OptionsPage - // - Name = "OptionsPage"; - Size = new Size(610, 489); - ResumeLayout(false); - - } - */ - protected virtual void ApplyTheme() { if (!ThemeManager.getInstance().ThemingActive) return; From 86e806d021efdb9f8731cab10a154487e93f7cf7 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 13:17:30 -0500 Subject: [PATCH 085/157] code cleanup --- mRemoteV1/UI/Controls/Base/NGListView.cs | 36 +++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/mRemoteV1/UI/Controls/Base/NGListView.cs b/mRemoteV1/UI/Controls/Base/NGListView.cs index 3c551d730..c91fdc10b 100644 --- a/mRemoteV1/UI/Controls/Base/NGListView.cs +++ b/mRemoteV1/UI/Controls/Base/NGListView.cs @@ -1,6 +1,7 @@ -using BrightIdeasSoftware; -using mRemoteNG.Themes; +using System.ComponentModel; using System.Drawing; +using BrightIdeasSoftware; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls.Base { @@ -8,23 +9,19 @@ namespace mRemoteNG.UI.Controls.Base //This is subclassed to avoid repeating the code in multiple places internal class NGListView : ObjectListView { - private CellBorderDecoration deco; //Control if the gridlines are styled, must be set before the OnCreateControl is fired public bool DecorateLines { get; set; } = true; - public NGListView() { + InitializeComponent(); ThemeManager.getInstance().ThemeChanged += OnCreateControl; } - - - protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); var _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; //List back color @@ -33,12 +30,17 @@ namespace mRemoteNG.UI.Controls.Base //Selected item SelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Selected_Background"); SelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Selected_Foreground"); - + //Header style HeaderUsesThemes = false; - var headerStylo = new HeaderFormatStyle(); - headerStylo.Normal.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Background"); - headerStylo.Normal.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); + var headerStylo = new HeaderFormatStyle + { + Normal = + { + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Background"), + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground") + } + }; HeaderFormatStyle = headerStylo; //Border style if(DecorateLines) @@ -69,14 +71,14 @@ namespace mRemoteNG.UI.Controls.Base private void InitializeComponent() { - ((System.ComponentModel.ISupportInitialize)(this)).BeginInit(); - this.SuspendLayout(); + ((ISupportInitialize)(this)).BeginInit(); + SuspendLayout(); // // NGListView // - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - ((System.ComponentModel.ISupportInitialize)(this)).EndInit(); - this.ResumeLayout(false); + Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0); + ((ISupportInitialize)(this)).EndInit(); + ResumeLayout(false); } } From 32c4f984e99fa9deb6f3c995fe40272176f56c81 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 8 Jan 2019 17:10:36 -0500 Subject: [PATCH 086/157] theming updates and minor UI changes --- .../ActiveDirectoryImportWindow.Designer.cs | 16 +++++++++------- .../UI/Window/ActiveDirectoryImportWindow.cs | 10 ++++++++-- mRemoteV1/UI/Window/SSHTransferWindow.cs | 13 +++++++++---- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs index 5761dc31e..9609c39f4 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs @@ -22,7 +22,7 @@ namespace mRemoteNG.UI.Window // this.btnImport._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnImport.Location = new System.Drawing.Point(12, 346); + this.btnImport.Location = new System.Drawing.Point(126, 345); this.btnImport.Name = "btnImport"; this.btnImport.Size = new System.Drawing.Size(75, 23); this.btnImport.TabIndex = 4; @@ -34,6 +34,7 @@ namespace mRemoteNG.UI.Window // this.txtDomain.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.txtDomain.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtDomain.Location = new System.Drawing.Point(12, 25); this.txtDomain.Name = "txtDomain"; this.txtDomain.Size = new System.Drawing.Size(406, 22); @@ -53,9 +54,9 @@ namespace mRemoteNG.UI.Window // this.btnChangeDomain._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnChangeDomain.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnChangeDomain.Location = new System.Drawing.Point(424, 25); + this.btnChangeDomain.Location = new System.Drawing.Point(422, 23); this.btnChangeDomain.Name = "btnChangeDomain"; - this.btnChangeDomain.Size = new System.Drawing.Size(99, 23); + this.btnChangeDomain.Size = new System.Drawing.Size(100, 24); this.btnChangeDomain.TabIndex = 2; this.btnChangeDomain.Text = "Change"; this.btnChangeDomain.UseVisualStyleBackColor = true; @@ -73,7 +74,7 @@ namespace mRemoteNG.UI.Window this.ActiveDirectoryTree.Margin = new System.Windows.Forms.Padding(4); this.ActiveDirectoryTree.Name = "ActiveDirectoryTree"; this.ActiveDirectoryTree.SelectedNode = null; - this.ActiveDirectoryTree.Size = new System.Drawing.Size(510, 271); + this.ActiveDirectoryTree.Size = new System.Drawing.Size(510, 285); this.ActiveDirectoryTree.TabIndex = 3; this.ActiveDirectoryTree.ADPathChanged += new ADTree.ADtree.ADPathChangedEventHandler(this.ActiveDirectoryTree_ADPathChanged); // @@ -81,9 +82,9 @@ namespace mRemoteNG.UI.Window // this.btnClose._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnClose.Location = new System.Drawing.Point(447, 330); + this.btnClose.Location = new System.Drawing.Point(422, 344); this.btnClose.Name = "btnClose"; - this.btnClose.Size = new System.Drawing.Size(75, 39); + this.btnClose.Size = new System.Drawing.Size(100, 24); this.btnClose.TabIndex = 5; this.btnClose.Text = "Close"; this.btnClose.UseVisualStyleBackColor = true; @@ -94,7 +95,8 @@ namespace mRemoteNG.UI.Window this.chkSubOU._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; this.chkSubOU.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkSubOU.AutoSize = true; - this.chkSubOU.Location = new System.Drawing.Point(12, 330); + this.chkSubOU.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkSubOU.Location = new System.Drawing.Point(12, 349); this.chkSubOU.Name = "chkSubOU"; this.chkSubOU.Size = new System.Drawing.Size(108, 17); this.chkSubOU.TabIndex = 6; diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index df27f667e..d5f402bf9 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; using mRemoteNG.App; using mRemoteNG.Container; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Window { @@ -24,10 +25,15 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { base.ApplyTheme(); + if (!(ActiveDirectoryTree.Controls[0] is TreeView tv)) return; + var tm = ThemeManager.getInstance(); + if (!tm.ThemingActive) return; + tv.BackColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Background"); + tv.ForeColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); } #region Private Methods - + #region Event Handlers @@ -37,7 +43,7 @@ namespace mRemoteNG.UI.Window txtDomain.Text = _currentDomain; ActiveDirectoryTree.Domain = _currentDomain; EnableDisableImportButton(); - + // Domain doesn't refresh on load, so it defaults to DOMAIN without this... ChangeDomain(); } diff --git a/mRemoteV1/UI/Window/SSHTransferWindow.cs b/mRemoteV1/UI/Window/SSHTransferWindow.cs index e19457a16..3fa51bcf4 100644 --- a/mRemoteV1/UI/Window/SSHTransferWindow.cs +++ b/mRemoteV1/UI/Window/SSHTransferWindow.cs @@ -89,6 +89,7 @@ namespace mRemoteNG.UI.Window // txtLocalFile // this.txtLocalFile.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtLocalFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtLocalFile.Location = new System.Drawing.Point(105, 28); this.txtLocalFile.Name = "txtLocalFile"; this.txtLocalFile.Size = new System.Drawing.Size(455, 22); @@ -100,18 +101,18 @@ namespace mRemoteNG.UI.Window this.btnTransfer.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnTransfer.Image = global::mRemoteNG.Resources.SSHTransfer; this.btnTransfer.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.btnTransfer.Location = new System.Drawing.Point(566, 140); + this.btnTransfer.Location = new System.Drawing.Point(562, 145); this.btnTransfer.Name = "btnTransfer"; - this.btnTransfer.Size = new System.Drawing.Size(96, 29); + this.btnTransfer.Size = new System.Drawing.Size(100, 24); this.btnTransfer.TabIndex = 10000; this.btnTransfer.Text = "Transfer"; - this.btnTransfer.TextAlign = System.Drawing.ContentAlignment.MiddleRight; this.btnTransfer.UseVisualStyleBackColor = true; this.btnTransfer.Click += new System.EventHandler(this.btnTransfer_Click); // // txtRemoteFile // this.txtRemoteFile.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtRemoteFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtRemoteFile.Location = new System.Drawing.Point(105, 60); this.txtRemoteFile.Name = "txtRemoteFile"; this.txtRemoteFile.Size = new System.Drawing.Size(542, 22); @@ -132,7 +133,7 @@ namespace mRemoteNG.UI.Window this.btnBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnBrowse.Location = new System.Drawing.Point(566, 28); this.btnBrowse.Name = "btnBrowse"; - this.btnBrowse.Size = new System.Drawing.Size(81, 26); + this.btnBrowse.Size = new System.Drawing.Size(81, 22); this.btnBrowse.TabIndex = 30; this.btnBrowse.Text = "Browse"; this.btnBrowse.UseVisualStyleBackColor = true; @@ -231,6 +232,7 @@ namespace mRemoteNG.UI.Window // txtPort // this.txtPort.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtPort.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtPort.Location = new System.Drawing.Point(271, 110); this.txtPort.Name = "txtPort"; this.txtPort.Size = new System.Drawing.Size(30, 22); @@ -241,6 +243,7 @@ namespace mRemoteNG.UI.Window // txtHost // this.txtHost.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtHost.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtHost.Location = new System.Drawing.Point(105, 19); this.txtHost.Name = "txtHost"; this.txtHost.Size = new System.Drawing.Size(471, 22); @@ -249,6 +252,7 @@ namespace mRemoteNG.UI.Window // txtPassword // this.txtPassword.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtPassword.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtPassword.Location = new System.Drawing.Point(105, 81); this.txtPassword.Name = "txtPassword"; this.txtPassword.Size = new System.Drawing.Size(471, 22); @@ -258,6 +262,7 @@ namespace mRemoteNG.UI.Window // txtUser // this.txtUser.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtUser.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtUser.Location = new System.Drawing.Point(105, 51); this.txtUser.Name = "txtUser"; this.txtUser.Size = new System.Drawing.Size(471, 22); From 6a354f87571a50cf913b948c4da454e1a3ba10d7 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 09:46:14 -0500 Subject: [PATCH 087/157] don't default to a dummy domain This causes the control to timeout and takes nearly 30 seconds to load --- mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs index 9609c39f4..d9ec226ae 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs @@ -69,7 +69,7 @@ namespace mRemoteNG.UI.Window | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ActiveDirectoryTree.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.ActiveDirectoryTree.Domain = "DOMAIN"; + this.ActiveDirectoryTree.Domain = ""; this.ActiveDirectoryTree.Location = new System.Drawing.Point(12, 52); this.ActiveDirectoryTree.Margin = new System.Windows.Forms.Padding(4); this.ActiveDirectoryTree.Name = "ActiveDirectoryTree"; From aa546d87ffe02f21c17f8d5b28d3d74221a2485d Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 10:35:28 -0500 Subject: [PATCH 088/157] safety checks --- mRemoteV1/Connection/ConnectionInitiator.cs | 13 +++++++------ mRemoteV1/UI/Forms/frmMain.cs | 1 + mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 613eca5a1..2e0004bd6 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -56,7 +56,7 @@ namespace mRemoteNG.Connection var connectionWindow = (ConnectionWindow)interfaceControl.FindForm(); connectionWindow?.Focus(); var findForm = (ConnectionWindow)interfaceControl.FindForm(); - findForm?.Show(FrmMain.Default.pnlDock); + findForm?.Show(FrmMain.Default.pnlDock); return true; } @@ -126,7 +126,7 @@ namespace mRemoteNG.Connection Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); } } - + private static void StartPreConnectionExternalApp(ConnectionInfo connectionInfo) { if (connectionInfo.PreExtApp == "") return; @@ -142,6 +142,7 @@ namespace mRemoteNG.Connection // the new structure is ConnectionWindow.Controls[0].ActiveDocument.Controls[0] // DockPanel InterfaceControl if (!(Runtime.WindowList[i] is ConnectionWindow connectionWindow)) continue; + if(connectionWindow.Controls.Count < 1) continue; if (!(connectionWindow.Controls[0] is DockPanel cwDp)) continue; return InterfaceControl.FindInterfaceControl(cwDp); @@ -195,7 +196,7 @@ namespace mRemoteNG.Connection if(extT == null) return connectionContainer; if(extT.Icon != null) - ((ConnectionTab)connectionContainer).Icon = extT.Icon; + ((ConnectionTab)connectionContainer).Icon = extT.Icon; return connectionContainer; } @@ -235,10 +236,10 @@ namespace mRemoteNG.Connection } } - Runtime.MessageCollector.AddMessage(msgClass, + Runtime.MessageCollector.AddMessage(msgClass, string.Format( - Language.strProtocolEventDisconnected, - disconnectedMessage, + Language.strProtocolEventDisconnected, + disconnectedMessage, prot.InterfaceControl.Info.Hostname, prot.InterfaceControl.Info.Protocol.ToString())); } diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index f4ffb7f02..b8e9a86aa 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -350,6 +350,7 @@ namespace mRemoteNG.UI.Forms foreach (var dc in pnlDock.Contents) { if (!(dc is ConnectionWindow cw)) continue; + if (cw.Controls.Count < 1) continue; if (!(cw.Controls[0] is DockPanel dp)) continue; if (dp.Contents.Count > 0) openConnections += dp.Contents.Count; diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index d5f402bf9..c072c91ae 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -25,6 +25,7 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { base.ApplyTheme(); + if (ActiveDirectoryTree.Controls.Count < 1) return; if (!(ActiveDirectoryTree.Controls[0] is TreeView tv)) return; var tm = ThemeManager.getInstance(); if (!tm.ThemingActive) return; From e2865fafde4735a30b491e779fc32f03ca5de1a3 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 13:57:33 -0500 Subject: [PATCH 089/157] update changelog --- CHANGELOG.TXT | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index d19bed2c2..d5e5fe45c 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -10,9 +10,12 @@ Features/Enhancements: #951: Added property to Enable/Disable Clipboard Sharing for RDP connections #928: Add context menu items to 'Close all but this' and 'Close all tabs to the right' #765: Port Scan Issues (single port scan option now available) +#155: Replace MagicLibrary with DockPanelSuite +#154: MR-139: Close Button on Each Tab - new default theme has a close button on each tab Fixes: ------ +#1248: RemoveMagicLib Bugs - various bugs that cropped up as a result of removing magiclib #1245: Options form takes nearly 3 seconds to appear when Theming is active #1240: Theming problem with NGNumericUpDown #1238: Connection panel not translated until opened for the first time From 35fada7fcd535777899cd00d99763766ecafd717 Mon Sep 17 00:00:00 2001 From: David Sparer Date: Wed, 9 Jan 2019 16:46:21 -0600 Subject: [PATCH 090/157] prevent exception when removing connection from list --- mRemoteV1/Connection/Protocol/ProtocolList.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/Connection/Protocol/ProtocolList.cs b/mRemoteV1/Connection/Protocol/ProtocolList.cs index 9eee86eba..e3582b48d 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolList.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolList.cs @@ -45,6 +45,9 @@ namespace mRemoteNG.Connection.Protocol { try { + if (!List.Contains(cProt)) + return; + List.Remove(cProt); RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, cProt)); } @@ -55,7 +58,9 @@ namespace mRemoteNG.Connection.Protocol public new void Clear() { - if (Count == 0) return; + if (Count == 0) + return; + List.Clear(); RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } From 41cab2f652839c138e164371e4df7af80ac0afce Mon Sep 17 00:00:00 2001 From: David Sparer Date: Wed, 9 Jan 2019 18:03:24 -0600 Subject: [PATCH 091/157] resolved exception when closing a connection group (top-level dps tab) --- mRemoteV1/UI/Window/ConnectionWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index a510fdd98..214350e33 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -280,7 +280,7 @@ namespace mRemoteNG.UI.Window try { - foreach (var dockContent in connDock.Documents) + foreach (var dockContent in connDock.Documents.ToArray()) { var tabP = (ConnectionTab) dockContent; if (tabP.Tag == null) continue; From ffe44706c2d86d40bc26529664ca48ed90e80f1f Mon Sep 17 00:00:00 2001 From: David Sparer Date: Wed, 9 Jan 2019 19:02:17 -0600 Subject: [PATCH 092/157] fixed issue with connection handlers not updating when settings change --- mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 41 ++++++++++----------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 98d79f69b..8956c247e 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -54,8 +54,8 @@ namespace mRemoteNG.UI.Window } PlaceSearchBar(Settings.Default.PlaceSearchBarAboveConnectionTree); - - } + SetConnectionTreeClickHandlers(); + } private void PlaceSearchBar(bool placeSearchBarAboveConnectionTree) { @@ -118,8 +118,7 @@ namespace mRemoteNG.UI.Window olvConnections.KeyDown += tvConnections_KeyDown; olvConnections.KeyPress += tvConnections_KeyPress; SetTreePostSetupActions(); - SetConnectionTreeDoubleClickHandlers(); - SetConnectionTreeSingleClickHandlers(); + SetConnectionTreeClickHandlers(); Runtime.ConnectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded; } @@ -137,28 +136,26 @@ namespace mRemoteNG.UI.Window olvConnections.PostSetupActions = actions; } - private void SetConnectionTreeDoubleClickHandlers() + private void SetConnectionTreeClickHandlers() { - var doubleClickHandler = new TreeNodeCompositeClickHandler + var singleClickHandlers = new List>(); + var doubleClickHandlers = new List> { - ClickHandlers = new ITreeNodeClickHandler[] - { - new ExpandNodeClickHandler(olvConnections), - new OpenConnectionClickHandler(_connectionInitiator) - } + new ExpandNodeClickHandler(olvConnections) }; - olvConnections.DoubleClickHandler = doubleClickHandler; - } - private void SetConnectionTreeSingleClickHandlers() - { - var handlers = new List>(); - if (Settings.Default.SingleClickOnConnectionOpensIt) - handlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); - if (Settings.Default.SingleClickSwitchesToOpenConnection) - handlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); - var singleClickHandler = new TreeNodeCompositeClickHandler {ClickHandlers = handlers}; - olvConnections.SingleClickHandler = singleClickHandler; + if (Settings.Default.SingleClickOnConnectionOpensIt) + singleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); + else + doubleClickHandlers.Add(new OpenConnectionClickHandler(_connectionInitiator)); + + if (Settings.Default.SingleClickSwitchesToOpenConnection) + singleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); + else + doubleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); + + olvConnections.SingleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = singleClickHandlers }; + olvConnections.DoubleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = doubleClickHandlers }; } private void ConnectionsServiceOnConnectionsLoaded(object o, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) From 764521414fd858df0a9f3c361d199e6ba7b26735 Mon Sep 17 00:00:00 2001 From: David Sparer Date: Wed, 9 Jan 2019 19:08:17 -0600 Subject: [PATCH 093/157] double include switch-to handler for doubleclick yet --- mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 8956c247e..92a9f444c 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -151,8 +151,6 @@ namespace mRemoteNG.UI.Window if (Settings.Default.SingleClickSwitchesToOpenConnection) singleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); - else - doubleClickHandlers.Add(new SwitchToConnectionClickHandler(_connectionInitiator)); olvConnections.SingleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = singleClickHandlers }; olvConnections.DoubleClickHandler = new TreeNodeCompositeClickHandler { ClickHandlers = doubleClickHandlers }; From f6a1d603a9ee0afaf167e0a159013fb096c0bd0b Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 21:30:03 -0500 Subject: [PATCH 094/157] avoid duplicate close() on reconnect --- mRemoteV1/UI/Window/ConnectionWindow.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 214350e33..db864c0d2 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -10,6 +10,7 @@ using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol.RDP; using mRemoteNG.Connection.Protocol.VNC; +using mRemoteNG.Messages; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Forms; @@ -676,9 +677,14 @@ namespace mRemoteNG.UI.Window { try { + var interfaceControl = GetInterfaceControl(); - if (interfaceControl == null) return; - interfaceControl.Protocol.Close(); + if (interfaceControl == null) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Reconnect (UI.Window.ConnectionWindow) failed. Could not find InterfaceControl."); + return; + } + Invoke(new Action(() => Prot_Event_Closed(interfaceControl.Protocol))); _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); } catch (Exception ex) From 2f0550de8ea715267dab7ad886d251485012357d Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 22:21:12 -0500 Subject: [PATCH 095/157] doubleclick on running connection in tree should bring tab to focus Reference #1261 --- mRemoteV1/Connection/ConnectionInitiator.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 2e0004bd6..ceee6241a 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -53,10 +53,10 @@ namespace mRemoteNG.Connection { var interfaceControl = FindConnectionContainer(connectionInfo); if (interfaceControl == null) return false; - var connectionWindow = (ConnectionWindow)interfaceControl.FindForm(); - connectionWindow?.Focus(); - var findForm = (ConnectionWindow)interfaceControl.FindForm(); - findForm?.Show(FrmMain.Default.pnlDock); + var connT = (ConnectionTab)interfaceControl.FindForm(); + connT?.Focus(); + var findForm = (ConnectionTab)interfaceControl.FindForm(); + findForm?.Show(findForm.DockPanel); return true; } @@ -144,8 +144,14 @@ namespace mRemoteNG.Connection if (!(Runtime.WindowList[i] is ConnectionWindow connectionWindow)) continue; if(connectionWindow.Controls.Count < 1) continue; if (!(connectionWindow.Controls[0] is DockPanel cwDp)) continue; - - return InterfaceControl.FindInterfaceControl(cwDp); + foreach (var dockContent in cwDp.Documents) + { + var tab = (ConnectionTab) dockContent; + var ic = InterfaceControl.FindInterfaceControl(tab); + if (ic == null) continue; + if (ic.Info == connectionInfo) + return ic; + } } return null; } From 9da26358ba0826985ec91fe2a266f8073a044756 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 22:27:14 -0500 Subject: [PATCH 096/157] copy hostname on folder causes exception Reference #1261 --- mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs index cfa2edb94..c24eeeee0 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs @@ -320,7 +320,7 @@ namespace mRemoteNG.UI.Controls public void CopyHostnameSelectedNode() { - Clipboard.SetText(SelectedNode.Hostname); + Clipboard.SetText(SelectedNode.IsContainer ? SelectedNode.Name : SelectedNode.Hostname); } public void SortRecursive(ConnectionInfo sortTarget, ListSortDirection sortDirection) From 40682bc84233045e23edfe28233d7c8ae24f100e Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 22:46:59 -0500 Subject: [PATCH 097/157] create empty panel on startup not working Reference #1261 --- mRemoteV1/UI/Forms/frmMain.cs | 22 +++++++++------------- mRemoteV1/UI/Panels/PanelAdder.cs | 6 +++--- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 96332c2b5..45460e1c0 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -26,6 +26,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; +using mRemoteNG.UI.Panels; using WeifenLuo.WinFormsUI.Docking; // ReSharper disable MemberCanBePrivate.Global @@ -180,23 +181,18 @@ namespace mRemoteNG.UI.Forms Opacity = 1; //Fix MagicRemove , revision on panel strategy for mdi - //Fix MagicRemove, this is a setting pnlDock.ShowDocumentIcon = true; - //Fix missing general panel at the first run - /* if (Settings.Default.CreateEmptyPanelOnStartUp) - { - var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) - ? Settings.Default.StartUpPanelName - : Language.strNewPanel; + FrmSplashScreen.getInstance().Close(); - var panelAdder = new PanelAdder(); - if (!panelAdder.DoesPanelExist(panelName)) - panelAdder.AddPanel(panelName); - }*/ + if (!Settings.Default.CreateEmptyPanelOnStartUp) return; + var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) + ? Settings.Default.StartUpPanelName + : Language.strNewPanel; - var frmSplashScreen = FrmSplashScreen.getInstance(); - frmSplashScreen.Close(); + var panelAdder = new PanelAdder(); + if (!panelAdder.DoesPanelExist(panelName)) + panelAdder.AddPanel(panelName); } private void ApplyLanguage() diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index 4c5e41a51..795babf3e 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -13,7 +13,7 @@ namespace mRemoteNG.UI.Panels { public class PanelAdder { - public Form AddPanel(string title = "") + public ConnectionWindow AddPanel(string title = "") { try { @@ -44,12 +44,12 @@ namespace mRemoteNG.UI.Panels private static void PrepareTabSupport(ConnectionWindow connectionForm) { - Runtime.WindowList.Add(connectionForm); + Runtime.WindowList.Add(connectionForm); } private static void SetConnectionWindowTitle(string title, ConnectionWindow connectionForm) { - if (title == "") + if (string.IsNullOrEmpty(title)) title = Language.strNewPanel; connectionForm.SetFormText(title.Replace("&", "&&")); } From 033635fb43f3f73b891c5f345d69fc5c651733af Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 9 Jan 2019 22:49:20 -0500 Subject: [PATCH 098/157] copyright 2019 reference #1261 --- mRemoteV1/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/Properties/AssemblyInfo.cs b/mRemoteV1/Properties/AssemblyInfo.cs index 78e360d69..08b0f1007 100644 --- a/mRemoteV1/Properties/AssemblyInfo.cs +++ b/mRemoteV1/Properties/AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("Multi-protocol remote connections manager")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("mRemoteNG")] -[assembly: AssemblyCopyright("Copyright © 2018 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] +[assembly: AssemblyCopyright("Copyright © 2019 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] From 53fdf2bbbf06f09256119e644c15f58b386b6a1d Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 09:24:42 -0500 Subject: [PATCH 099/157] minor clean up --- .../UI/Controls/QuickConnectToolStrip.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index c1eab8e1b..0da8d9366 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -22,13 +22,13 @@ namespace mRemoteNG.UI.Controls private QuickConnectComboBox _cmbQuickConnect; private ContextMenuStrip _mnuConnections; private IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - private ThemeManager _themeManager; + private readonly ThemeManager _themeManager; private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender; private readonly DisplayProperties _display; public IConnectionInitiator ConnectionInitiator { - get { return _connectionInitiator; } + get => _connectionInitiator; set { if (value == null) @@ -237,17 +237,16 @@ namespace mRemoteNG.UI.Controls if (e.Button != MouseButtons.Left) return; var menuItem = (ToolStripMenuItem) sender; - // While we can connect to a whole folder at once, it is - // probably not the expected behavior when navigating through - // a nested menu. Just return - var containerInfo = menuItem.Tag as ContainerInfo; - if (containerInfo != null) - return; - - var connectionInfo = menuItem.Tag as ConnectionInfo; - if (connectionInfo != null) + switch (menuItem.Tag) { - ConnectionInitiator.OpenConnection(connectionInfo); + // While we can connect to a whole folder at once, it is + // probably not the expected behavior when navigating through + // a nested menu. Just return + case ContainerInfo _: + return; + case ConnectionInfo connectionInfo: + ConnectionInitiator.OpenConnection(connectionInfo); + break; } } #endregion From cc184b7c58e14fe77361470058dcf7d7f5799a74 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Thu, 10 Jan 2019 10:14:31 -0500 Subject: [PATCH 100/157] Float window customization for size It will undock to the original size when it was docked --- mRemoteV1/Themes/MremoteNGThemeBase.cs | 14 ++++++++++++++ mRemoteV1/Themes/ThemeInfo.cs | 19 +++++++++++++------ mRemoteV1/UI/Tabs/FloatWindowNG.cs | 25 +++++++++++++++++++++++++ mRemoteV1/mRemoteV1.csproj | 3 +++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 mRemoteV1/UI/Tabs/FloatWindowNG.cs diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index 2bc98b944..3fa9a202f 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -1,5 +1,6 @@ namespace mRemoteNG.Themes { + using System.Drawing; using UI.Tabs; using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.ThemeVS2015; @@ -27,4 +28,17 @@ return new DockPaneStripNG(pane); } } + + public class MremoteFloatWindowFactory : DockPanelExtender.IFloatWindowFactory + { + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) + { + return new FloatWindowNG(dockPanel, pane, ((ConnectionTab)dockPanel.ActiveDocument).Bounds); + } + + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane) + { + return new FloatWindowNG(dockPanel, pane); + } + } } \ No newline at end of file diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index f6db90979..933d388a8 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -32,8 +32,9 @@ namespace mRemoteNG.Themes _extendedPalette = inExtendedPalette; IsThemeBase = false; IsExtendable = false; - //Override the dock pane strip factory - _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + setCustomExtenders(); + + } public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion) @@ -44,8 +45,7 @@ namespace mRemoteNG.Themes _version = inVersion; IsThemeBase = false; IsExtendable = false; - //Override the dock pane strip factory - _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + setCustomExtenders(); } #endregion @@ -96,8 +96,7 @@ namespace mRemoteNG.Themes return; } _theme = value; - //Override the dock pane strip factory - _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + setCustomExtenders(); } } @@ -145,5 +144,13 @@ namespace mRemoteNG.Themes public bool IsExtendable { get; set; } #endregion + + //Custom extenders for mremote customizations in DPS + private void setCustomExtenders() + { + + _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); + _theme.Extender.FloatWindowFactory = new MremoteFloatWindowFactory(); + } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Tabs/FloatWindowNG.cs b/mRemoteV1/UI/Tabs/FloatWindowNG.cs new file mode 100644 index 000000000..ce15434a4 --- /dev/null +++ b/mRemoteV1/UI/Tabs/FloatWindowNG.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WeifenLuo.WinFormsUI.Docking; + +namespace mRemoteNG.UI.Tabs +{ + class FloatWindowNG : FloatWindow + { + + public FloatWindowNG(DockPanel dockPanel, DockPane pane) + : base(dockPanel, pane) + { + } + + public FloatWindowNG(DockPanel dockPanel, DockPane pane, Rectangle bounds) + : base(dockPanel, pane, bounds) + { + + } + } +} \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index c4fb40f4c..d5900481c 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -692,6 +692,9 @@ Component + + Form + Component From f56f1160baa579a2a4e4a9e91ef793ffc5c19d19 Mon Sep 17 00:00:00 2001 From: David Sparer Date: Thu, 10 Jan 2019 10:22:00 -0600 Subject: [PATCH 101/157] safer cast and value access when creating float window --- mRemoteV1/Themes/MremoteNGThemeBase.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/Themes/MremoteNGThemeBase.cs b/mRemoteV1/Themes/MremoteNGThemeBase.cs index 3fa9a202f..2cadca511 100644 --- a/mRemoteV1/Themes/MremoteNGThemeBase.cs +++ b/mRemoteV1/Themes/MremoteNGThemeBase.cs @@ -33,7 +33,9 @@ { public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) { - return new FloatWindowNG(dockPanel, pane, ((ConnectionTab)dockPanel.ActiveDocument).Bounds); + var activeDocumentBounds = (dockPanel?.ActiveDocument as ConnectionTab)?.Bounds; + + return new FloatWindowNG(dockPanel, pane, activeDocumentBounds ?? bounds); } public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane) From 0c6778b5a3a28940fb253a1e459a9aa32f4a76f8 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 13:57:51 -0500 Subject: [PATCH 102/157] minor clean up --- mRemoteV1/App/Info/GeneralAppInfo.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/App/Info/GeneralAppInfo.cs b/mRemoteV1/App/Info/GeneralAppInfo.cs index 179773898..a6170b4bc 100644 --- a/mRemoteV1/App/Info/GeneralAppInfo.cs +++ b/mRemoteV1/App/Info/GeneralAppInfo.cs @@ -39,15 +39,14 @@ namespace mRemoteNG.App.Info details.Add(Thread.CurrentThread.CurrentUICulture.Name); details.Add($".NET CLR {Environment.Version}"); var detailsString = string.Join("; ", details.ToArray()); - + return $"Mozilla/5.0 ({detailsString}) {ProductName}/{ApplicationVersion}"; } } public static Version GetApplicationVersion() { - Version v; - System.Version.TryParse(ApplicationVersion, out v); + System.Version.TryParse(ApplicationVersion, out var v); return v; } } From 3713f98f7b285df0bd8ef1c4faf5ac8069a498ff Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:00:26 -0500 Subject: [PATCH 103/157] whitespace --- mRemoteV1/UI/Window/ConfigWindow.cs | 128 ++++++++++++++-------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 1d55f9dfd..f1581047d 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -201,9 +201,9 @@ namespace mRemoteNG.UI.Window Text = @"Config"; PropertyGridContextMenu.ResumeLayout(false); ResumeLayout(false); - + } - + #region Public Properties public bool PropertiesVisible { @@ -217,7 +217,7 @@ namespace mRemoteNG.UI.Window _btnShowDefaultProperties.Checked = false; } } - + public bool InheritanceVisible { get => _btnShowInheritance.Checked; @@ -230,7 +230,7 @@ namespace mRemoteNG.UI.Window _btnShowDefaultProperties.Checked = false; } } - + public bool DefaultPropertiesVisible { get => _btnShowDefaultProperties.Checked; @@ -243,7 +243,7 @@ namespace mRemoteNG.UI.Window _btnShowInheritance.Checked = false; } } - + public bool DefaultInheritanceVisible { get => _btnShowDefaultInheritance.Checked; @@ -279,7 +279,7 @@ namespace mRemoteNG.UI.Window #endregion #region Public Methods - + protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData) { // Main form handle command key events @@ -291,15 +291,15 @@ namespace mRemoteNG.UI.Window { gridRoot = gridRoot.Parent; } - + var gridItems = new List(); FindChildGridItems(gridRoot, ref gridItems); - + if (!ContainsGridItemProperty(gridItems)) return true; - + var newItem = selectedItem; - + // ReSharper disable once SwitchStatementMissingSomeCases switch (keyData) { @@ -310,12 +310,12 @@ namespace mRemoteNG.UI.Window newItem = FindNextGridItemProperty(gridItems, selectedItem); break; } - + _pGrid.SelectedGridItem = newItem; - + return true; // Handled } - + private void FindChildGridItems(GridItem item, ref List gridItems) { gridItems.Add(item); @@ -326,7 +326,7 @@ namespace mRemoteNG.UI.Window FindChildGridItems(child, ref gridItems); } } - + private bool ContainsGridItemProperty(IEnumerable gridItems) { return gridItems.Any(item => item.GridItemType == GridItemType.Property); @@ -336,7 +336,7 @@ namespace mRemoteNG.UI.Window { if (gridItems.Count == 0 || startItem == null) return null; - + var startIndex = gridItems.IndexOf(startItem); if (startItem.GridItemType == GridItemType.Property) { @@ -346,7 +346,7 @@ namespace mRemoteNG.UI.Window startIndex = gridItems.Count - 1; } } - + var previousIndex = 0; var previousIndexValid = false; for (var index = startIndex; index >= 0; index--) @@ -356,10 +356,10 @@ namespace mRemoteNG.UI.Window previousIndexValid = true; break; } - + if (previousIndexValid) return gridItems[previousIndex]; - + for (var index = gridItems.Count - 1; index >= startIndex + 1; index--) { if (gridItems[index].GridItemType != GridItemType.Property) continue; @@ -367,15 +367,15 @@ namespace mRemoteNG.UI.Window previousIndexValid = true; break; } - + return !previousIndexValid ? null : gridItems[previousIndex]; } - + private GridItem FindNextGridItemProperty(IList gridItems, GridItem startItem) { if (gridItems.Count == 0 || startItem == null) return null; - + var startIndex = gridItems.IndexOf(startItem); if (startItem.GridItemType == GridItemType.Property) { @@ -385,7 +385,7 @@ namespace mRemoteNG.UI.Window startIndex = 0; } } - + var nextIndex = 0; var nextIndexValid = false; for (var index = startIndex; index <= gridItems.Count - 1; index++) @@ -395,10 +395,10 @@ namespace mRemoteNG.UI.Window nextIndexValid = true; break; } - + if (nextIndexValid) return gridItems[nextIndex]; - + for (var index = 0; index <= startIndex - 1; index++) { if (gridItems[index].GridItemType != GridItemType.Property) continue; @@ -406,7 +406,7 @@ namespace mRemoteNG.UI.Window nextIndexValid = true; break; } - + return !nextIndexValid ? null : gridItems[nextIndex]; } @@ -453,7 +453,7 @@ namespace mRemoteNG.UI.Window _btnHostStatus.Enabled = false; break; } - + _pGrid.SelectedObject = propertyGridObject; } else @@ -461,7 +461,7 @@ namespace mRemoteNG.UI.Window _pGrid.SelectedObject = propertyGridObject; _btnShowProperties.Enabled = true; - _btnShowInheritance.Enabled = + _btnShowInheritance.Enabled = gridObjectAsContainerInfo.Parent != null && !(gridObjectAsContainerInfo.Parent is RootNodeInfo); _btnShowDefaultProperties.Enabled = false; @@ -479,7 +479,7 @@ namespace mRemoteNG.UI.Window _pGrid.SelectedObject = propertyGridObject; _btnShowProperties.Enabled = true; - _btnShowInheritance.Enabled = + _btnShowInheritance.Enabled = !(gridObjectAsConnectionInfo is PuttySessionInfo) && gridObjectAsConnectionInfo.Parent != null && !(gridObjectAsConnectionInfo.Parent is RootNodeInfo); @@ -548,7 +548,7 @@ namespace mRemoteNG.UI.Window else if (propertyGridObject is ConnectionInfoInheritance) //INHERITANCE { _pGrid.SelectedObject = propertyGridObject; - + if (InheritanceVisible) { InheritanceVisible = true; @@ -576,7 +576,7 @@ namespace mRemoteNG.UI.Window DefaultInheritanceVisible = true; } - + } ShowHideGridItems(); @@ -588,7 +588,7 @@ namespace mRemoteNG.UI.Window } } #endregion - + #region Private Methods private void ApplyLanguage() { @@ -602,7 +602,7 @@ namespace mRemoteNG.UI.Window TabText = Language.strMenuConfig; _propertyGridContextMenuShowHelpText.Text = Language.strMenuShowHelpText; } - + private new void ApplyTheme() { if (!ThemeManager.getInstance().ThemingActive) return; @@ -613,9 +613,9 @@ namespace mRemoteNG.UI.Window _pGrid.LineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Border"); _pGrid.HelpBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _pGrid.HelpForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - _pGrid.CategoryForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); + _pGrid.CategoryForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Header_Foreground"); _pGrid.CommandsDisabledLinkColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); - _pGrid.CommandsBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); + _pGrid.CommandsBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Background"); _pGrid.CommandsForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Disabled_Foreground"); } @@ -631,9 +631,9 @@ namespace mRemoteNG.UI.Window customToolStrip.Items.Add(_btnHostStatus); customToolStrip.Items.Add(_btnIcon); customToolStrip.Show(); - + var propertyGridToolStrip = new ToolStrip(); - + ToolStrip toolStrip = null; foreach (Control control in _pGrid.Controls) { @@ -642,23 +642,23 @@ namespace mRemoteNG.UI.Window propertyGridToolStrip = toolStrip; break; } - + if (toolStrip == null) { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strCouldNotFindToolStripInFilteredPropertyGrid, true); return; } - + if (!_originalPropertyGridToolStripItemCountValid) { _originalPropertyGridToolStripItemCount = propertyGridToolStrip.Items.Count; _originalPropertyGridToolStripItemCountValid = true; } Debug.Assert(_originalPropertyGridToolStripItemCount == 5); - + // Hide the "Property Pages" button propertyGridToolStrip.Items[_originalPropertyGridToolStripItemCount - 1].Visible = false; - + var expectedToolStripItemCount = _originalPropertyGridToolStripItemCount + customToolStrip.Items.Count; if (propertyGridToolStrip.Items.Count == expectedToolStripItemCount) return; propertyGridToolStrip.AllowMerge = true; @@ -669,7 +669,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigUiLoadFailed + Environment.NewLine + ex.Message, true); } } - + private void Config_Load(object sender, EventArgs e) { _themeManager = ThemeManager.getInstance(); @@ -678,12 +678,12 @@ namespace mRemoteNG.UI.Window AddToolStripItems(); _pGrid.HelpVisible = Settings.Default.ShowConfigHelpText; } - + private void Config_SystemColorsChanged(object sender, EventArgs e) { AddToolStripItems(); } - + private void pGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { try @@ -741,8 +741,8 @@ namespace mRemoteNG.UI.Window if (rootInfo.Password) { - var passwordName = Settings.Default.UseSQLServer - ? Language.strSQLServer.TrimEnd(':') + var passwordName = Settings.Default.UseSQLServer + ? Language.strSQLServer.TrimEnd(':') : Path.GetFileName(Runtime.ConnectionsService.GetStartupConnectionFileName()); var password = MiscTools.PasswordDialog(passwordName); @@ -773,7 +773,7 @@ namespace mRemoteNG.UI.Window if (_pGrid.PropertySort == PropertySort.CategorizedAlphabetical) _pGrid.PropertySort = PropertySort.Categorized; } - + private void ShowHideGridItems() { try @@ -1435,7 +1435,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridHideItemsFailed + Environment.NewLine + ex.Message, true); } } - + private void btnShowProperties_Click(object sender, EventArgs e) { if (_pGrid.SelectedObject is ConnectionInfoInheritance o) @@ -1467,7 +1467,7 @@ namespace mRemoteNG.UI.Window SetPropertyGridObject((RootNodeInfo)_selectedTreeNode); } } - + private void btnShowDefaultProperties_Click(object sender, EventArgs e) { if (!(_pGrid.SelectedObject is RootNodeInfo) && !(_pGrid.SelectedObject is ConnectionInfoInheritance)) return; @@ -1477,7 +1477,7 @@ namespace mRemoteNG.UI.Window DefaultInheritanceVisible = false; SetPropertyGridObject(DefaultConnectionInfo.Instance); } - + private void btnShowInheritance_Click(object sender, EventArgs e) { if (!(_pGrid.SelectedObject is ConnectionInfo)) return; @@ -1487,7 +1487,7 @@ namespace mRemoteNG.UI.Window DefaultInheritanceVisible = false; SetPropertyGridObject(((ConnectionInfo)_pGrid.SelectedObject).Inheritance); } - + private void btnShowDefaultInheritance_Click(object sender, EventArgs e) { if (!(_pGrid.SelectedObject is RootNodeInfo) && !(_pGrid.SelectedObject is ConnectionInfo)) return; @@ -1497,19 +1497,19 @@ namespace mRemoteNG.UI.Window DefaultInheritanceVisible = true; SetPropertyGridObject(DefaultConnectionInheritance.Instance); } - + private void btnHostStatus_Click(object sender, EventArgs e) { SetHostStatus(_pGrid.SelectedObject); } - + private void btnIcon_Click(object sender, MouseEventArgs e) { try { if (!(_pGrid.SelectedObject is ConnectionInfo) || _pGrid.SelectedObject is PuttySessionInfo) return; CMenIcons.Items.Clear(); - + foreach (var iStr in ConnectionIcon.Icons) { var tI = new ToolStripMenuItem @@ -1529,27 +1529,27 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConfigPropertyGridButtonIconClickFailed + Environment.NewLine + ex.Message, true); } } - + private void IconMenu_Click(object sender, EventArgs e) { try { var connectionInfo = (ConnectionInfo)_pGrid.SelectedObject; if (connectionInfo == null) return; - + var selectedMenuItem = (ToolStripMenuItem)sender; var iconName = selectedMenuItem?.Text; if (string.IsNullOrEmpty(iconName)) return; - + var connectionIcon = ConnectionIcon.FromString(iconName); if (connectionIcon == null) return; - + _btnIcon.Image = connectionIcon.ToBitmap(); - + connectionInfo.Icon = iconName; _pGrid.Refresh(); - + Runtime.ConnectionsService.SaveConnectionsAsync(); } catch (Exception ex) @@ -1558,10 +1558,10 @@ namespace mRemoteNG.UI.Window } } #endregion - + #region Host Status (Ping) private Thread _pThread; - + private void CheckHostAlive(object hostName) { if (string.IsNullOrEmpty(hostName as string)) @@ -1644,7 +1644,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenu_Opening() failed.", ex); } } - + private void propertyGridContextMenuReset_Click(object sender, EventArgs e) { try @@ -1660,12 +1660,12 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenuReset_Click() failed.", ex); } } - + private void propertyGridContextMenuShowHelpText_Click(object sender, EventArgs e) { _propertyGridContextMenuShowHelpText.Checked = !_propertyGridContextMenuShowHelpText.Checked; } - + private void propertyGridContextMenuShowHelpText_CheckedChanged(object sender, EventArgs e) { Settings.Default.ShowConfigHelpText = _propertyGridContextMenuShowHelpText.Checked; From f3ad6e66e8f6d80e4ba13384d4a7aade17be095c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:17:06 -0500 Subject: [PATCH 104/157] whitepsace clean up --- mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs | 2 +- mRemoteV1/UI/Window/ConnectionWindow.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs index 4b26f842f..a3721c275 100644 --- a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs +++ b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs @@ -16,7 +16,7 @@ namespace mRemoteNG.UI.Controls public ExternalToolsToolStrip() { - Initialize(); + Initialize(); Runtime.ExternalToolsService.ExternalTools.CollectionUpdated += (sender, args) => AddExternalToolsToToolBar(); } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index db864c0d2..6dfaf8cbe 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -677,7 +677,6 @@ namespace mRemoteNG.UI.Window { try { - var interfaceControl = GetInterfaceControl(); if (interfaceControl == null) { From a765a71474b22dba28bd6fd718f19386ffab1274 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:22:58 -0500 Subject: [PATCH 105/157] minor cleanup --- mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs index a3721c275..cd198e917 100644 --- a/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs +++ b/mRemoteV1/UI/Controls/ExternalToolsToolStrip.cs @@ -70,16 +70,14 @@ namespace mRemoteNG.UI.Controls foreach (var tool in Runtime.ExternalToolsService.ExternalTools) { - if (tool.ShowOnToolbar) - { - var button = (ToolStripButton)Items.Add(tool.DisplayName, tool.Image, tsExtAppEntry_Click); - if (CMenToolbarShowText.Checked) - button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; - else - button.DisplayStyle = button.Image != null ? ToolStripItemDisplayStyle.Image : ToolStripItemDisplayStyle.ImageAndText; + if (!tool.ShowOnToolbar) continue; + var button = (ToolStripButton)Items.Add(tool.DisplayName, tool.Image, tsExtAppEntry_Click); + if (CMenToolbarShowText.Checked) + button.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + else + button.DisplayStyle = button.Image != null ? ToolStripItemDisplayStyle.Image : ToolStripItemDisplayStyle.ImageAndText; - button.Tag = tool; - } + button.Tag = tool; } } catch (Exception ex) From b5034fd9258adeed14a4a81f297076e3567519d9 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:39:27 -0500 Subject: [PATCH 106/157] whitespace cleanup --- mRemoteV1/Config/Settings/SettingsSaver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Config/Settings/SettingsSaver.cs b/mRemoteV1/Config/Settings/SettingsSaver.cs index f41ed382e..1d4c71d36 100644 --- a/mRemoteV1/Config/Settings/SettingsSaver.cs +++ b/mRemoteV1/Config/Settings/SettingsSaver.cs @@ -12,7 +12,7 @@ namespace mRemoteNG.Config.Settings public static class SettingsSaver { public static void SaveSettings( - Control quickConnectToolStrip, + Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain) @@ -50,7 +50,7 @@ namespace mRemoteNG.Config.Settings SaveExternalAppsToolbarLocation(externalToolsToolStrip); SaveQuickConnectToolbarLocation(quickConnectToolStrip); SaveMultiSshToolbarLocation(multiSshToolStrip); - + mRemoteNG.Settings.Default.Save(); SaveDockPanelLayout(); From 7c22ea6b01de2007a8f20abaa88c97262a34d48b Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:41:25 -0500 Subject: [PATCH 107/157] Add apply button --- mRemoteV1/UI/Forms/frmOptions.Designer.cs | 19 +++++++++++++++++-- mRemoteV1/UI/Forms/frmOptions.cs | 9 +++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmOptions.Designer.cs b/mRemoteV1/UI/Forms/frmOptions.Designer.cs index 7371c779d..72e21c671 100644 --- a/mRemoteV1/UI/Forms/frmOptions.Designer.cs +++ b/mRemoteV1/UI/Forms/frmOptions.Designer.cs @@ -37,12 +37,14 @@ this.pnlMain = new System.Windows.Forms.Panel(); this.lstOptionPages = new mRemoteNG.UI.Controls.Base.NGListView(); this.PageName = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); + this.btnApply = new mRemoteNG.UI.Controls.Base.NGButton(); this.pnlBottom.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.lstOptionPages)).BeginInit(); this.SuspendLayout(); // // pnlBottom // + this.pnlBottom.Controls.Add(this.btnApply); this.pnlBottom.Controls.Add(this.btnCancel); this.pnlBottom.Controls.Add(this.btnOK); this.pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom; @@ -55,7 +57,7 @@ // this.btnCancel._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(681, 6); + this.btnCancel.Location = new System.Drawing.Point(596, 5); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(75, 23); this.btnCancel.TabIndex = 1; @@ -67,7 +69,7 @@ // this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.btnOK.Location = new System.Drawing.Point(600, 6); + this.btnOK.Location = new System.Drawing.Point(515, 6); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(75, 23); this.btnOK.TabIndex = 0; @@ -111,6 +113,7 @@ this.lstOptionPages.Cursor = System.Windows.Forms.Cursors.Default; this.lstOptionPages.DecorateLines = true; this.lstOptionPages.Dock = System.Windows.Forms.DockStyle.Left; + this.lstOptionPages.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lstOptionPages.FullRowSelect = true; this.lstOptionPages.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; this.lstOptionPages.HideSelection = false; @@ -135,6 +138,17 @@ this.PageName.ImageAspectName = "IconImage"; this.PageName.IsEditable = false; // + // btnApply + // + this.btnApply._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; + this.btnApply.Location = new System.Drawing.Point(677, 5); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(75, 23); + this.btnApply.TabIndex = 2; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnOK_Click); + // // FrmOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -172,5 +186,6 @@ private Controls.Base.NGButton btnOK; private Controls.Base.NGButton btnCancel; private BrightIdeasSoftware.OLVColumn PageName; + private Controls.Base.NGButton btnApply; } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index 22f5a4d28..b4fe2e68b 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -33,7 +33,7 @@ namespace mRemoteNG.UI.Forms AddOptionsPagesToListView(); SetInitiallyActivatedPage(); // ApplyLanguage(); - // Handle the main page here and the individual pages in + // Handle the main page here and the individual pages in // AddOptionsPagesToListView() -- one less foreach loop.... Text = Language.strOptionsPageTitle; ApplyTheme(); @@ -111,6 +111,11 @@ namespace mRemoteNG.UI.Forms lstOptionPages.Items[0].Selected = true; } + /* + * This gets called by both OK and Apply buttons. + * OK sets DialogResult = OK, Apply does not (None). + * Apply will no close the dialog. + */ private void btnOK_Click(object sender, EventArgs e) { foreach (var page in _pages.Values) @@ -139,7 +144,7 @@ namespace mRemoteNG.UI.Forms Debug.WriteLine(page.PageName); page.RevertSettings(); } - Debug.WriteLine(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); + Debug.WriteLine(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); } } } \ No newline at end of file From 8bcd6b9e539a2bab4b92f3f2c22e24f834b01173 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:43:46 -0500 Subject: [PATCH 108/157] save settings should only be called on OK/Apply --- mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs | 2 -- mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs | 1 - mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs | 2 -- mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs | 4 ---- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 2 -- mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs | 4 ---- mRemoteV1/UI/Window/ComponentsCheckWindow.cs | 1 - 12 files changed, 36 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs index 218432eea..4ccb54d16 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs @@ -46,8 +46,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - chkAutomaticallyGetSessionInfo.Checked = Settings.Default.AutomaticallyGetSessionInfo; chkAutomaticReconnect.Checked = Settings.Default.ReconnectOnDisconnect; chkLoadBalanceInfoUseUtf8.Checked = Settings.Default.RdpLoadBalanceInfoUseUtf8; @@ -85,8 +83,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.MaxPuttyWaitTime = (int) numPuttyWaitTime.Value; Settings.Default.UVNCSCPort = (int) numUVNCSCPort.Value; - - Settings.Default.Save(); } #endregion diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs index 8cae1d2ed..3c29be533 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs @@ -34,8 +34,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - cboLanguage.Items.Clear(); cboLanguage.Items.Add(Language.strLanguageDefault); @@ -95,8 +93,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages } Settings.Default.MinimizeToTray = chkMinimizeToSystemTray.Checked; - - Settings.Default.Save(); } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs index 29ca59f20..d026d8ce6 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs @@ -45,8 +45,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - chkSingleClickOnConnectionOpensIt.Checked = Settings.Default.SingleClickOnConnectionOpensIt; chkSingleClickOnOpenedConnectionSwitchesToIt.Checked = Settings.Default.SingleClickSwitchesToOpenConnection; chkConnectionTreeTrackActiveConnection.Checked = Settings.Default.TrackActiveConnectionInConnectionTree; @@ -115,8 +113,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages { Settings.Default.ConfirmCloseConnection = (int) ConfirmCloseEnum.Never; } - - Settings.Default.Save(); } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs index 119a3f452..0ed23bdb4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs @@ -32,8 +32,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - // ReSharper disable once SwitchStatementMissingSomeCases switch (Settings.Default.EmptyCredentials) { @@ -73,8 +71,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); Settings.Default.DefaultPassword = cryptographyProvider.Encrypt(txtCredentialsPassword.Text, Runtime.EncryptionKey); Settings.Default.DefaultDomain = txtCredentialsDomain.Text; - - Settings.Default.Save(); } private void radCredentialsCustom_CheckedChanged(object sender, EventArgs e) diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs index 9d8724846..692c8c568 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs @@ -60,7 +60,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); LoadNotificationPanelSettings(); LoadLoggingSettings(); LoadPopupSettings(); @@ -71,7 +70,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages SaveNotificationPanelSettings(); SaveLoggingSettings(); SavePopupSettings(); - Settings.Default.Save(); } private void LoadNotificationPanelSettings() diff --git a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs index cdb184b4b..278084b29 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs @@ -34,7 +34,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); chkEncryptCompleteFile.Checked = Settings.Default.EncryptCompleteConnectionsFile; comboBoxEncryptionEngine.Text = Enum.GetName(typeof(BlockCipherEngines), Settings.Default.EncryptionEngine); comboBoxBlockCipher.Text = Enum.GetName(typeof(BlockCipherModes), Settings.Default.EncryptionBlockCipherMode); diff --git a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs index e7705d167..e3571f9d0 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs @@ -43,8 +43,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - chkUseSQLServer.Checked = Settings.Default.UseSQLServer; txtSQLServer.Text = Settings.Default.SQLHost; txtSQLDatabaseName.Text = Settings.Default.SQLDatabaseName; @@ -72,8 +70,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages ReinitializeSqlUpdater(); else if (!Settings.Default.UseSQLServer && sqlServerWasPreviouslyEnabled) DisableSql(); - - Settings.Default.Save(); } private static void ReinitializeSqlUpdater() diff --git a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs index a8b4db3ff..73ea8cfd9 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs @@ -35,8 +35,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.OpenConsFromLastSession = chkReconnectOnStart.Checked; Settings.Default.SingleInstance = chkSingleInstance.Checked; Settings.Default.StartupComponentsCheck = chkProperInstallationOfComponentsAtStartup.Checked; - - Settings.Default.Save(); } private void StartupExitPage_Load(object sender, EventArgs e) diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs index 32474bd4b..453e7b997 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs @@ -32,8 +32,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - chkAlwaysShowPanelTabs.Checked = Settings.Default.AlwaysShowPanelTabs; chkOpenNewTabRightOfSelected.Checked = Settings.Default.OpenTabsRightOfSelected; chkShowLogonInfoOnTabs.Checked = Settings.Default.ShowLogonInfoOnTabs; @@ -61,8 +59,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.AlwaysShowPanelSelectionDlg = chkAlwaysShowPanelSelectionDlg.Checked; Settings.Default.CreateEmptyPanelOnStartUp = chkCreateEmptyPanelOnStart.Checked; Settings.Default.StartUpPanelName = txtBoxPanelName.Text; - - Settings.Default.Save(); } private void UpdatePanelNameTextBox() diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 1aaaa46f5..d2e5ac6ea 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -55,7 +55,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { themeEnableChk.CheckedChanged -= ThemeEnableChkCheckedChanged; - SaveSettings(); //At first we cannot create or delete themes, depends later on the type of selected theme btnThemeNew.Enabled = false; btnThemeDelete.Enabled = false; @@ -102,7 +101,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages { Settings.Default.ThemingActive = themeEnableChk.Checked; Settings.Default.ThemeName = themeEnableChk.Checked ? ((ThemeInfo) cboTheme.SelectedItem).Name : _themeManager.DefaultTheme.Name; - Settings.Default.Save(); CTaskDialog.MessageBox("Theme Changed", "Restart Required.","Please restart mRemoteNG to apply the selected theme.", ETaskDialogButtons.Ok, ESysIcons.Information); diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs index d7af7c9be..65a013c33 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs @@ -54,8 +54,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - base.SaveSettings(); - chkCheckForUpdatesOnStartup.Checked = Settings.Default.CheckForUpdatesOnStartup; cboUpdateCheckFrequency.Enabled = chkCheckForUpdatesOnStartup.Checked; cboUpdateCheckFrequency.Items.Clear(); @@ -147,8 +145,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.UpdateProxyAuthUser = txtProxyUsername.Text; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); Settings.Default.UpdateProxyAuthPass = cryptographyProvider.Encrypt(txtProxyPassword.Text, Runtime.EncryptionKey); - - Settings.Default.Save(); } #endregion diff --git a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs index 9e70cde86..3d2930504 100644 --- a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs +++ b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs @@ -459,7 +459,6 @@ namespace mRemoteNG.UI.Window private void chkAlwaysShow_CheckedChanged(object sender, EventArgs e) { Settings.Default.StartupComponentsCheck = chkAlwaysShow.Checked; - Settings.Default.Save(); } public new void Show(DockPanel panel) From ef48f5183460cab66c4b2ae80ea60eaca6a66283 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 14:44:27 -0500 Subject: [PATCH 109/157] move base.SaveSettings to top like other pages --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index d2e5ac6ea..3087f70f2 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -92,6 +92,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void SaveSettings() { + base.SaveSettings(); + // Save the theme settings form close so we don't run into unexpected results while modifying... // Prompt the user that a restart is required to apply the new theme... if (themeEnableChk != null && cboTheme.SelectedItem != null) // LoadSettings calls SaveSettings, so these might be null the first time around @@ -107,7 +109,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages } } - base.SaveSettings(); foreach(var updatedTheme in modifiedThemes) { _themeManager.updateTheme(updatedTheme); From 6156ce48acc1000bc10b783ae04c673f8990d358 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 16:08:56 -0500 Subject: [PATCH 110/157] rename ONLY the 4 vsthemes DPS themes are back to their default names. The *.vsthemes provided on the file system get named in memory to *NG If we don't find the the theme name pulled from settings, blank it out. This should ONLY happen after upgrading from previous releases for users of the 4 *.vsthemes providedon the file system: "darcula", "vs2015blue", "vs2015dark" , "vs2015light" The 3 vs2015* ones are NOT to be confsed with the DPS provided versions of the almost identical name. Jumping through hoops rather than renaming files/theme names to avoid unexpected theme changes for as many users as possible. --- mRemoteV1/Themes/ThemeManager.cs | 63 +++++++++++++++++++++-------- mRemoteV1/Themes/ThemeSerializer.cs | 10 ++--- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 3825fc3d0..7b9e3c63b 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Linq; using WeifenLuo.WinFormsUI.Docking; @@ -37,7 +38,16 @@ namespace mRemoteNG.Themes if (themes[Settings.Default.ThemeName] != null) ActiveTheme = (ThemeInfo)themes[Settings.Default.ThemeName]; else + { ActiveTheme = DefaultTheme; + if(string.IsNullOrEmpty(Settings.Default.ThemeName)) return; + + //too early for logging to be enabled... + Debug.WriteLine("Detected invalid Theme in settings file. Resetting to default."); + // if we got here, then there's an invalid theme name in use, so just empty it out... + Settings.Default.ThemeName = ""; + Settings.Default.Save(); + } } #endregion @@ -87,42 +97,61 @@ namespace mRemoteNG.Themes { var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0]; - //First we load the default theme, its vs2015light + + //First we load the default base theme, its vs2015lightNG + //the true "default" in DockPanelSuite built-in VS2015LightTheme named "vs2015Light" + //hence the *NG suffix for this one... var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); + defaultTheme.Name = $"{defaultTheme.Name}NG"; themes.Add(defaultTheme.Name, defaultTheme); //Then the rest foreach (var themeFile in themeFiles) { + // Skip the default theme here, since it will get loaded again without the *NG below... + if (themeFile.Contains("vs2015light.vstheme")) continue; //filter default one var extTheme = ThemeSerializer.LoadFromXmlFile(themeFile, defaultTheme); - if (extTheme.Theme != null && !themes.ContainsKey(extTheme.Name)) - { - themes.Add(extTheme.Name, extTheme); - } + if (extTheme.Theme == null || themes.ContainsKey(extTheme.Name)) continue; + + if (extTheme.Name.Equals("darcula") || extTheme.Name.Equals("vs2015blue") || + extTheme.Name.Equals("vs2015dark")) + extTheme.Name = $"{extTheme.Name}NG"; + + themes.Add(extTheme.Name, extTheme); } //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme - var vs2003 = new ThemeInfo("DPSvs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + + // 2003 + var vs2003 = new ThemeInfo("vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2003.Name, vs2003); - var vs2005 = new ThemeInfo("DPSvs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + + // 2005 + var vs2005 = new ThemeInfo("vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2005.Name, vs2005); - var vs2012Light = new ThemeInfo("DPSvs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + + // 2012 + var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2012Light.Name, vs2012Light); - var vs2012Dark = new ThemeInfo("DPSvs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2012Dark.Name, vs2012Dark); - var vs2012Blue = new ThemeInfo("DPSvs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2012Blue.Name, vs2012Blue); - var vs2013Light = new ThemeInfo("DPSvs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + + // 2013 + var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2013Light.Name, vs2013Light); - var vs2013Dark = new ThemeInfo("DPSvs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2013Dark.Name, vs2013Dark); - var vs2013Blue = new ThemeInfo("DPSvs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2013Blue.Name, vs2013Blue); - var vs2015Light = new ThemeInfo("DPSvs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + + // 2015 + var vs2015Light = new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015lightNG"]).ExtendedPalette); themes.Add(vs2015Light.Name, vs2015Light); - var vs2015Dark = new ThemeInfo("DPSvs2015Dark", new VS2015DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + var vs2015Dark = new ThemeInfo("vs2015Dark", new VS2015DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015darkNG"]).ExtendedPalette); themes.Add(vs2015Dark.Name, vs2015Dark); - var vs2015Blue = new ThemeInfo("DPSvs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + var vs2015Blue = new ThemeInfo("vs2015Blue", new VS2015BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, ((ThemeInfo)themes["vs2015blueNG"]).ExtendedPalette); themes.Add(vs2015Blue.Name, vs2015Blue); @@ -221,7 +250,7 @@ namespace mRemoteNG.Themes } } - public ThemeInfo DefaultTheme => (ThemeInfo) themes["DPSvs2015Light"]; + public ThemeInfo DefaultTheme => (ThemeInfo) themes["vs2015Light"]; public ThemeInfo ActiveTheme { diff --git a/mRemoteV1/Themes/ThemeSerializer.cs b/mRemoteV1/Themes/ThemeSerializer.cs index 2754f65a8..2b0fc449c 100644 --- a/mRemoteV1/Themes/ThemeSerializer.cs +++ b/mRemoteV1/Themes/ThemeSerializer.cs @@ -14,8 +14,8 @@ namespace mRemoteNG.Themes /// public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme) { - var oldURI = baseTheme.URI; - var directoryName = Path.GetDirectoryName(oldURI); + var oldURI = baseTheme.URI; + var directoryName = Path.GetDirectoryName(oldURI); var toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme"; File.Copy(baseTheme.URI, toSaveURI); themeToSave.URI = toSaveURI; @@ -25,9 +25,9 @@ namespace mRemoteNG.Themes { File.Delete(themeToDelete.URI); } - + /// - /// Takes a theme in memory and update the color values that the user might have changed + /// Takes a theme in memory and update the color values that the user might have changed /// /// public static void UpdateThemeXMLValues(ThemeInfo themeToUpdate) @@ -51,7 +51,7 @@ namespace mRemoteNG.Themes var themeBaseLoad = new MremoteNGThemeBase(bytes); //Load the mremote part //Cause we cannot default the theme for the default theme - var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette); + var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette); var loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors()); if(new[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }.Contains(Path.GetFileNameWithoutExtension(filename))) { From ef82df5e72b7b6cd7dcee48f2113b46b4ebe2d96 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 10 Jan 2019 17:19:02 -0500 Subject: [PATCH 111/157] minor cleanup/refactoring --- .../Tree/ConnectionTreeDragAndDropHandler.cs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs b/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs index 95e2a4073..21dd3094f 100644 --- a/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs +++ b/mRemoteV1/Tree/ConnectionTreeDragAndDropHandler.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Windows.Forms; using BrightIdeasSoftware; -using mRemoteNG.App; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Tree.Root; @@ -21,8 +20,7 @@ namespace mRemoteNG.Tree public void HandleEvent_ModelDropped(object sender, ModelDropEventArgs e) { - var dropTarget = e.TargetModel as ConnectionInfo; - if (dropTarget == null) return; + if (!(e.TargetModel is ConnectionInfo dropTarget)) return; var dropSource = (ConnectionInfo)e.SourceModels[0]; DropModel(dropSource, dropTarget, e.DropTargetLocation); e.Handled = true; @@ -30,18 +28,23 @@ namespace mRemoteNG.Tree public void DropModel(ConnectionInfo dropSource, ConnectionInfo dropTarget, DropTargetLocation dropTargetLocation) { - if (dropTargetLocation == DropTargetLocation.Item) - DropModelOntoTarget(dropSource, dropTarget); - else if (dropTargetLocation == DropTargetLocation.AboveItem) - DropModelAboveTarget(dropSource, dropTarget); - else if (dropTargetLocation == DropTargetLocation.BelowItem) - DropModelBelowTarget(dropSource, dropTarget); + switch (dropTargetLocation) + { + case DropTargetLocation.Item: + DropModelOntoTarget(dropSource, dropTarget); + break; + case DropTargetLocation.AboveItem: + DropModelAboveTarget(dropSource, dropTarget); + break; + case DropTargetLocation.BelowItem: + DropModelBelowTarget(dropSource, dropTarget); + break; + } } private void DropModelOntoTarget(ConnectionInfo dropSource, ConnectionInfo dropTarget) { - var dropTargetAsContainer = dropTarget as ContainerInfo; - if (dropTargetAsContainer == null) return; + if (!(dropTarget is ContainerInfo dropTargetAsContainer)) return; dropSource.SetParent(dropTargetAsContainer); } @@ -84,10 +87,16 @@ namespace mRemoteNG.Tree _infoMessage = Language.strNodeNotDraggable; _enableFeedback = false; } - else if (dropTargetLocation == DropTargetLocation.Item) - dragDropEffect = HandleCanDropOnItem(dropSource, dropTarget); - else if (dropTargetLocation == DropTargetLocation.AboveItem || dropTargetLocation == DropTargetLocation.BelowItem) - dragDropEffect = HandleCanDropBetweenItems(dropSource, dropTarget); + else switch (dropTargetLocation) + { + case DropTargetLocation.Item: + dragDropEffect = HandleCanDropOnItem(dropSource, dropTarget); + break; + case DropTargetLocation.AboveItem: + case DropTargetLocation.BelowItem: + dragDropEffect = HandleCanDropBetweenItems(dropSource, dropTarget); + break; + } return dragDropEffect; } @@ -148,14 +157,12 @@ namespace mRemoteNG.Tree private bool AncestorDraggingOntoChild(ConnectionInfo source, ConnectionInfo target) { - var sourceAsContainer = source as ContainerInfo; - return sourceAsContainer != null && sourceAsContainer.GetRecursiveChildList().Contains(target); + return source is ContainerInfo sourceAsContainer && sourceAsContainer.GetRecursiveChildList().Contains(target); } private bool DraggingOntoCurrentParent(ConnectionInfo source, ConnectionInfo target) { - var targetAsContainer = target as ContainerInfo; - return targetAsContainer != null && targetAsContainer.Children.Contains(source); + return target is ContainerInfo targetAsContainer && targetAsContainer.Children.Contains(source); } } } \ No newline at end of file From 4e11baa5790c35e3a46735cb82d096f078de3ec4 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 09:03:57 -0500 Subject: [PATCH 112/157] designer generated change --- mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs index ce80421a7..681227091 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs @@ -111,6 +111,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.listPalette.Cursor = System.Windows.Forms.Cursors.Default; this.listPalette.DecorateLines = true; this.listPalette.Dock = System.Windows.Forms.DockStyle.Fill; + this.listPalette.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.listPalette.Location = new System.Drawing.Point(3, 37); this.listPalette.Name = "listPalette"; this.listPalette.ShowGroups = false; From 9977f33461fd7601bfb8f39cf79dacf68941347f Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 09:25:58 -0500 Subject: [PATCH 113/157] whitespace --- mRemoteV1/Themes/ExtendedColorPalette.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mRemoteV1/Themes/ExtendedColorPalette.cs b/mRemoteV1/Themes/ExtendedColorPalette.cs index 4ecc1c528..2aae9691e 100644 --- a/mRemoteV1/Themes/ExtendedColorPalette.cs +++ b/mRemoteV1/Themes/ExtendedColorPalette.cs @@ -5,7 +5,7 @@ namespace mRemoteNG.Themes { /// - /// Class used for the UI to display the color tables,as the Dictionary value keys cannot be directly replaced + /// Class used for the UI to display the color tables,as the Dictionary value keys cannot be directly replaced /// public class PseudoKeyColor { @@ -35,7 +35,7 @@ namespace mRemoteNG.Themes { ExtColorPalette = new Dictionary(); DefaultColorPalette = new Dictionary(); // If this is the default palette, it will not have a default-default palette - + } #endregion @@ -46,7 +46,7 @@ namespace mRemoteNG.Themes DefaultColorPalette = inPalettte.ExtColorPalette; } #endregion - + /// /// Obtains a color from the extended palette, if not present obtains it from the default palette, in the extreme case it uses Pink as a signal that a color is missing /// @@ -59,7 +59,7 @@ namespace mRemoteNG.Themes if (retColor != Color.Empty && retColor.A != 0) return retColor; if(DefaultColorPalette != null) { - retColor = DefaultColorPalette.ContainsKey(colorKey) ? DefaultColorPalette[colorKey] : Color.Empty; + retColor = DefaultColorPalette.ContainsKey(colorKey) ? DefaultColorPalette[colorKey] : Color.Empty; } //why are we here?, just avoid a crash if(retColor == Color.Empty) From 4e8d336527e927c17d27cd2b9114f83884241b05 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 10:07:09 -0500 Subject: [PATCH 114/157] remove enable themes and default accordingly additional error handling attempts for theme loading. Though, if we can't load \Themes\vs2015light.vstheme we're going to have a bad time... --- mRemoteV1/Properties/Settings.Designer.cs | 4 +- mRemoteV1/Properties/Settings.settings | 2 +- mRemoteV1/Themes/ThemeManager.cs | 85 +++++++++++++++---- .../Forms/OptionsPages/ThemePage.Designer.cs | 29 ++----- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 63 ++------------ mRemoteV1/app.config | 2 +- 6 files changed, 85 insertions(+), 100 deletions(-) diff --git a/mRemoteV1/Properties/Settings.Designer.cs b/mRemoteV1/Properties/Settings.Designer.cs index 33b3dfb46..d9f6f5f0e 100644 --- a/mRemoteV1/Properties/Settings.Designer.cs +++ b/mRemoteV1/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace mRemoteNG { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -2569,7 +2569,7 @@ namespace mRemoteNG { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] + [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool ThemingActive { get { return ((bool)(this["ThemingActive"])); diff --git a/mRemoteV1/Properties/Settings.settings b/mRemoteV1/Properties/Settings.settings index a73b96f9e..1cf5ddf51 100644 --- a/mRemoteV1/Properties/Settings.settings +++ b/mRemoteV1/Properties/Settings.settings @@ -639,7 +639,7 @@ cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW - False + True diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 7b9e3c63b..db25b6e33 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -1,5 +1,4 @@ using mRemoteNG.App; -using mRemoteNG.Messages; using System; using System.Collections; using System.Collections.Generic; @@ -23,6 +22,7 @@ namespace mRemoteNG.Themes private Hashtable themes; private bool _themeActive; private static ThemeManager themeInstance; + private readonly string themePath = App.Info.SettingsFileInfo.ThemeFolder; #endregion #region Constructors @@ -30,7 +30,7 @@ namespace mRemoteNG.Themes { LoadThemes(); SetActive(); - _themeActive = Settings.Default.ThemingActive; + _themeActive = true; } private void SetActive() @@ -66,15 +66,10 @@ namespace mRemoteNG.Themes return null; } - //The manager precharges all the themes at once - public List LoadThemes() + private bool ThemeDirExists() { - if (themes != null) return themes.Values.OfType().ToList(); - themes = new Hashtable(); - //Load the files in theme folder first, to include vstheme light as default - var themePath = App.Info.SettingsFileInfo.ThemeFolder; - if (themePath == null) return themes.Values.OfType().ToList(); + if (themePath == null) return false; try { //In install mode first time is necessary to copy the themes folder @@ -83,6 +78,7 @@ namespace mRemoteNG.Themes Directory.CreateDirectory(themePath); } + var orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder); var files = orig.GetFiles(); foreach (var file in files) @@ -92,17 +88,56 @@ namespace mRemoteNG.Themes file.CopyTo(Path.Combine(themePath, file.Name), true); } - //Check that theme folder exist before trying to load themes - if (Directory.Exists(themePath)) + return Directory.Exists(themePath); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Error loading theme directory", ex); + } + + return false; + } + + private ThemeInfo LoadDefaultTheme() + { + try + { + if (ThemeDirExists()) { - var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); - var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0]; + var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light.vstheme")[0]; //First we load the default base theme, its vs2015lightNG //the true "default" in DockPanelSuite built-in VS2015LightTheme named "vs2015Light" //hence the *NG suffix for this one... var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); defaultTheme.Name = $"{defaultTheme.Name}NG"; + return defaultTheme; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Error loading default theme", ex); + } + + return null; + } + + //The manager precharges all the themes at once + public List LoadThemes() + { + if (themes != null) return themes.Values.OfType().ToList(); + themes = new Hashtable(); + + if (themePath == null) return themes.Values.OfType().ToList(); + try + { + //Check that theme folder exist before trying to load themes + if (ThemeDirExists()) + { + var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); + + //First we load the default base theme, its vs2015lightNG + var defaultTheme = LoadDefaultTheme(); themes.Add(defaultTheme.Name, defaultTheme); //Then the rest foreach (var themeFile in themeFiles) @@ -159,7 +194,7 @@ namespace mRemoteNG.Themes } catch(Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Error loading themes", ex); } return themes.Values.OfType().ToList(); } @@ -250,7 +285,7 @@ namespace mRemoteNG.Themes } } - public ThemeInfo DefaultTheme => (ThemeInfo) themes["vs2015Light"]; + public ThemeInfo DefaultTheme => ThemesCount > 0 ? (ThemeInfo)themes["vs2015Light"] : new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, LoadDefaultTheme().ExtendedPalette); public ThemeInfo ActiveTheme { @@ -258,9 +293,23 @@ namespace mRemoteNG.Themes get => ThemingActive == false ? DefaultTheme : _activeTheme; set { - //You can only enable theming if there are themes loaded - if (value == null) return; - _activeTheme = value; + // You can only enable theming if there are themes loaded + // Default accordingly... + if (value == null) + { + var changed = !Settings.Default.ThemeName.Equals(DefaultTheme.Name); + + Settings.Default.ThemeName = DefaultTheme.Name; + _activeTheme = DefaultTheme; + + if(changed) + NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); + + Settings.Default.Save(); + return; + } + + _activeTheme = value; Settings.Default.ThemeName = value.Name; NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); } diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs index 681227091..7fbfaee29 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs @@ -33,7 +33,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.btnThemeDelete = new mRemoteNG.UI.Controls.Base.NGButton(); this.btnThemeNew = new mRemoteNG.UI.Controls.Base.NGButton(); this.cboTheme = new mRemoteNG.UI.Controls.Base.NGComboBox(); - this.themeEnableChk = new mRemoteNG.UI.Controls.Base.NGCheckBox(); this.listPalette = new mRemoteNG.UI.Controls.Base.NGListView(); this.keyCol = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.ColorCol = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); @@ -84,20 +83,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.cboTheme.TabIndex = 0; this.cboTheme.SelectionChangeCommitted += new System.EventHandler(this.cboTheme_SelectionChangeCommitted); // - // themeEnableChk - // - this.themeEnableChk._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; - this.themeEnableChk.AutoSize = true; - this.themeEnableChk.Dock = System.Windows.Forms.DockStyle.Fill; - this.themeEnableChk.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.themeEnableChk.Location = new System.Drawing.Point(3, 3); - this.themeEnableChk.Name = "themeEnableChk"; - this.themeEnableChk.Size = new System.Drawing.Size(141, 22); - this.themeEnableChk.TabIndex = 5; - this.themeEnableChk.Text = "Enable Themes"; - this.themeEnableChk.UseVisualStyleBackColor = true; - this.themeEnableChk.CheckedChanged += new System.EventHandler(this.ThemeEnableChkCheckedChanged); - // // listPalette // this.listPalette.AllColumns.Add(this.keyCol); @@ -145,9 +130,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages // this.labelRestart.AutoSize = true; this.labelRestart.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelRestart.Location = new System.Drawing.Point(150, 0); + this.labelRestart.Location = new System.Drawing.Point(3, 0); this.labelRestart.Name = "labelRestart"; - this.labelRestart.Size = new System.Drawing.Size(451, 28); + this.labelRestart.Size = new System.Drawing.Size(598, 28); this.labelRestart.TabIndex = 4; this.labelRestart.Text = "Warning: Restart is required to disable the themes or to completely apply a new o" + "ne"; @@ -172,11 +157,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages // // tableLayoutPanel2 // - this.tableLayoutPanel2.ColumnCount = 2; - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 24.33775F)); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 75.66225F)); - this.tableLayoutPanel2.Controls.Add(this.labelRestart, 1, 0); - this.tableLayoutPanel2.Controls.Add(this.themeEnableChk, 0, 0); + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Controls.Add(this.labelRestart, 0, 0); this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 459); this.tableLayoutPanel2.Name = "tableLayoutPanel2"; @@ -221,7 +205,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages internal Controls.Base.NGButton btnThemeDelete; internal Controls.Base.NGButton btnThemeNew; internal Controls.Base.NGComboBox cboTheme; - private Controls.Base.NGCheckBox themeEnableChk; private Controls.Base.NGListView listPalette; private Controls.Base.NGLabel labelRestart; private BrightIdeasSoftware.OLVColumn keyCol; diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 3087f70f2..803865975 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -42,7 +42,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages btnThemeDelete.Text = Language.strOptionsThemeButtonDelete; btnThemeNew.Text = Language.strOptionsThemeButtonNew; labelRestart.Text = Language.strOptionsThemeThemeChaangeWarning; - themeEnableChk.Text = Language.strOptionsThemeEnableTheming; } private new void ApplyTheme() @@ -54,7 +53,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages public override void LoadSettings() { - themeEnableChk.CheckedChanged -= ThemeEnableChkCheckedChanged; //At first we cannot create or delete themes, depends later on the type of selected theme btnThemeNew.Enabled = false; btnThemeDelete.Enabled = false; @@ -66,20 +64,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages cboTheme_SelectionChangeCommitted(this, new EventArgs()); cboTheme.DisplayMember = "Name"; - //Load theming active property and disable controls - if (Settings.Default.ThemingActive) - { - themeEnableChk.Checked = true; - listPalette.FormatCell += ListPalette_FormatCell; //Color cell formatter - } - else - { - themeEnableChk.Checked = false; - cboTheme.Enabled = false; - // reset to the default theme when disabling theme support - //_themeManager.ActiveTheme = _themeManager.DefaultTheme; - } - themeEnableChk.CheckedChanged += ThemeEnableChkCheckedChanged; + listPalette.FormatCell += ListPalette_FormatCell; //Color cell formatter } private void ListPalette_FormatCell(object sender, FormatCellEventArgs e) @@ -94,15 +79,15 @@ namespace mRemoteNG.UI.Forms.OptionsPages { base.SaveSettings(); + Settings.Default.ThemingActive = true; + // Save the theme settings form close so we don't run into unexpected results while modifying... // Prompt the user that a restart is required to apply the new theme... - if (themeEnableChk != null && cboTheme.SelectedItem != null) // LoadSettings calls SaveSettings, so these might be null the first time around + if (cboTheme.SelectedItem != null) // LoadSettings calls SaveSettings, so these might be null the first time around { - if (Settings.Default.ThemingActive != themeEnableChk.Checked || - !Settings.Default.ThemeName.Equals(((ThemeInfo) cboTheme.SelectedItem).Name)) + if (!Settings.Default.ThemeName.Equals(((ThemeInfo) cboTheme.SelectedItem).Name)) { - Settings.Default.ThemingActive = themeEnableChk.Checked; - Settings.Default.ThemeName = themeEnableChk.Checked ? ((ThemeInfo) cboTheme.SelectedItem).Name : _themeManager.DefaultTheme.Name; + Settings.Default.ThemeName = ((ThemeInfo) cboTheme.SelectedItem).Name; CTaskDialog.MessageBox("Theme Changed", "Restart Required.","Please restart mRemoteNG to apply the selected theme.", ETaskDialogButtons.Ok, ESysIcons.Information); @@ -139,7 +124,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages var selectedTheme = (ThemeInfo)cboTheme.SelectedItem; - if (selectedTheme.IsExtendable) + if (selectedTheme != null && selectedTheme.IsExtendable) { // it's Extendable, so now we can do this more expensive operations... listPalette.ClearObjects(); @@ -149,7 +134,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages listPalette.CellClick += ListPalette_CellClick; } - if (selectedTheme.IsThemeBase) return; + if (selectedTheme != null && selectedTheme.IsThemeBase) return; btnThemeDelete.Enabled = true; } @@ -222,37 +207,5 @@ namespace mRemoteNG.UI.Forms.OptionsPages #endregion #endregion - private void ThemeEnableChkCheckedChanged(object sender, EventArgs e) - { - if (themeEnableChk.Checked) - { - if(_themeManager.ThemesCount > 0) - { - //_themeManager.ThemingActive = true; - cboTheme.Enabled = true; - } - else - { - CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeErrorNoThemes, "", "", "", "", "", "", ETaskDialogButtons.Ok, ESysIcons.Error, ESysIcons.Information, 0); - themeEnableChk.Checked = false; - //_themeManager.ThemingActive = false; - cboTheme.Enabled = false; - } - - listPalette.FormatCell += ListPalette_FormatCell; - } - else - { - //_themeManager.ThemingActive = false; - cboTheme.Enabled = false; - listPalette.FormatCell -= ListPalette_FormatCell; - } - - /* LoadSettings calls save settings first... This will save the selected theme options accordingly... - * Changes to ThemingActive value above have been commented out in order to require a restart for the - * changes to take full effect. - */ - LoadSettings(); - } } } \ No newline at end of file diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index 724950a7b..f14d4f37a 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -664,7 +664,7 @@ True - False + True From 82507aabcbcb18b38afc573e191963183e37cb50 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 10:48:03 -0500 Subject: [PATCH 115/157] additional saftey checks and no extended palette for "raw" default theme --- mRemoteV1/Themes/ThemeManager.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index db25b6e33..ba4f4f0f2 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; +using mRemoteNG.Messages; using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Themes @@ -104,7 +105,14 @@ namespace mRemoteNG.Themes { if (ThemeDirExists()) { - var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light.vstheme")[0]; + var defaultThemeURL = $"{themePath}\\vs2015light.vstheme"; + + if (!File.Exists($"{themePath}\\vs2015light.vstheme")) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Could not find default theme file.", true); + return null; + + } //First we load the default base theme, its vs2015lightNG //the true "default" in DockPanelSuite built-in VS2015LightTheme named "vs2015Light" @@ -285,7 +293,7 @@ namespace mRemoteNG.Themes } } - public ThemeInfo DefaultTheme => ThemesCount > 0 ? (ThemeInfo)themes["vs2015Light"] : new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015, LoadDefaultTheme().ExtendedPalette); + public ThemeInfo DefaultTheme => themes != null && ThemesCount > 0 ? (ThemeInfo)themes["vs2015Light"] : new ThemeInfo("vs2015Light", new VS2015LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2015); public ThemeInfo ActiveTheme { From bebc9c9dd47589d1ee3b0f3bea60534f759f6916 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 11:28:57 -0500 Subject: [PATCH 116/157] check themeing active AND/OR IsExtendable Lots of small changes as a result of this other minor clean up Tests should pass now. And if \Themes\vs2015light.vstheme can't ben loaded, we should be OK now... --- mRemoteV1/Themes/ThemeManager.cs | 1 + mRemoteV1/UI/Controls/Base/NGButton.cs | 10 +- mRemoteV1/UI/Controls/Base/NGCheckBox.cs | 12 +-- mRemoteV1/UI/Controls/Base/NGComboBox.cs | 19 ++-- mRemoteV1/UI/Controls/Base/NGGroupBox.cs | 16 ++-- mRemoteV1/UI/Controls/Base/NGLabel.cs | 3 +- mRemoteV1/UI/Controls/Base/NGListView.cs | 1 + mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs | 21 +++-- mRemoteV1/UI/Controls/Base/NGPictureBox.cs | 4 +- mRemoteV1/UI/Controls/Base/NGProgressBar.cs | 4 +- mRemoteV1/UI/Controls/Base/NGRadioButton.cs | 16 ++-- mRemoteV1/UI/Controls/Base/NGTextBox.cs | 32 +++---- mRemoteV1/UI/Controls/IPTextBox.cs | 30 +++--- mRemoteV1/UI/Controls/MultiSshToolStrip.cs | 3 +- .../Controls/PageSequence/SequencedControl.cs | 10 +- mRemoteV1/UI/Forms/ExportForm.cs | 43 ++++----- mRemoteV1/UI/Forms/Input/FrmInputBox.cs | 1 + mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 1 - mRemoteV1/UI/Forms/frmChoosePanel.cs | 18 ++-- mRemoteV1/UI/Forms/frmMain.cs | 4 +- mRemoteV1/UI/Forms/frmOptions.cs | 10 +- mRemoteV1/UI/TaskDialog/CommandButton.cs | 61 ++++++------- mRemoteV1/UI/TaskDialog/frmTaskDialog.cs | 4 +- mRemoteV1/UI/Window/AboutWindow.cs | 38 ++++---- .../UI/Window/ActiveDirectoryImportWindow.cs | 1 + mRemoteV1/UI/Window/BaseWindow.cs | 1 + mRemoteV1/UI/Window/ComponentsCheckWindow.cs | 91 ++++++++++--------- mRemoteV1/UI/Window/ConfigWindow.cs | 1 + mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 2 + mRemoteV1/UI/Window/ConnectionWindow.cs | 2 + mRemoteV1/UI/Window/ErrorAndInfoWindow.cs | 60 ++++++------ mRemoteV1/UI/Window/UpdateWindow.cs | 61 +++++++------ 32 files changed, 303 insertions(+), 278 deletions(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index ba4f4f0f2..8e4b3dca2 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -136,6 +136,7 @@ namespace mRemoteNG.Themes if (themes != null) return themes.Values.OfType().ToList(); themes = new Hashtable(); + return themes.Values.OfType().ToList(); if (themePath == null) return themes.Values.OfType().ToList(); try { diff --git a/mRemoteV1/UI/Controls/Base/NGButton.cs b/mRemoteV1/UI/Controls/Base/NGButton.cs index c4f266a38..321aeea0c 100644 --- a/mRemoteV1/UI/Controls/Base/NGButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGButton.cs @@ -35,7 +35,7 @@ namespace mRemoteNG.UI.Controls.Base /// protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (_themeManager.ThemingActive) { @@ -65,7 +65,7 @@ namespace mRemoteNG.UI.Controls.Base Invalidate(); }; Invalidate(); - } + } } @@ -75,7 +75,7 @@ namespace mRemoteNG.UI.Controls.Base /// protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive) + if (!_themeManager.ThemingActive || _themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; @@ -103,11 +103,11 @@ namespace mRemoteNG.UI.Controls.Base fore = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Foreground"); border = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Border"); break; - } + } } else { - back = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Disabled_Background"); + back = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Disabled_Background"); fore = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Disabled_Foreground"); border = _themeManager.ActiveTheme.ExtendedPalette.getColor("Button_Disabled_Border"); } diff --git a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs index 6550d2157..15547ecfe 100644 --- a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs @@ -7,7 +7,7 @@ namespace mRemoteNG.UI.Controls.Base //Extended CheckBox class, the NGCheckBox onPaint completely repaint the control // - // If this causes design issues in the future, may want to think about migrating to + // If this causes design issues in the future, may want to think about migrating to // CheckBoxRenderer: // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.checkboxrenderer?view=netframework-4.6 // @@ -40,7 +40,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; _mice = MouseState.OUT; @@ -73,7 +73,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; @@ -82,7 +82,7 @@ namespace mRemoteNG.UI.Controls.Base Color fore; Color glyph; Color checkBorder; - + var back = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Background"); if (Enabled) { @@ -104,11 +104,11 @@ namespace mRemoteNG.UI.Controls.Base } else { - + fore = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Text_Disabled"); glyph = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Glyph_Disabled"); checkBorder = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Border_Disabled"); - } + } e.Graphics.Clear(Parent.BackColor); diff --git a/mRemoteV1/UI/Controls/Base/NGComboBox.cs b/mRemoteV1/UI/Controls/Base/NGComboBox.cs index 43ff476e8..6e66251fd 100644 --- a/mRemoteV1/UI/Controls/Base/NGComboBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGComboBox.cs @@ -24,17 +24,16 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); + if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Foreground"); DrawMode = DrawMode.OwnerDrawFixed; SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); DrawItem += NG_DrawItem; - _mice = MouseState.OUT; + _mice = MouseState.OUT; MouseEnter += (sender, args) => { _mice = MouseState.HOVER; @@ -63,7 +62,7 @@ namespace mRemoteNG.UI.Controls.Base private void NG_DrawItem(object sender, DrawItemEventArgs e) { var index = e.Index >= 0 ? e.Index : 0; - Brush itemBrush= new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Foreground")); + Brush itemBrush = new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Foreground")); if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { @@ -94,7 +93,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; @@ -118,10 +117,10 @@ namespace mRemoteNG.UI.Controls.Base ButtFore = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Button_Pressed_Foreground"); } - - + + e.Graphics.Clear(Back); - + //Border using (var p = new Pen(Border)) { @@ -136,7 +135,7 @@ namespace mRemoteNG.UI.Controls.Base //Arrow e.Graphics.DrawString("\u25BC", Font, new SolidBrush(ButtFore), Width-17, Height/2 -5); - + //Text var textRect = new Rectangle(2, 2, Width - 20, Height - 4); TextRenderer.DrawText(e.Graphics, Text, Font, textRect, Fore, Back, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); diff --git a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs index 8b52dbb85..e26cfc0d2 100644 --- a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs @@ -18,7 +18,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (_themeManager.ThemingActive) { @@ -28,14 +28,14 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; } //Reusing the textbox colors - var titleColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Foreground"); - //var backColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Backgorund"); + var titleColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Foreground"); + //var backColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Backgorund"); var lineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Line"); if (!Enabled) @@ -43,18 +43,18 @@ namespace mRemoteNG.UI.Controls.Base titleColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Disabled_Foreground"); //backColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Disabled_Background"); lineColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("GroupBox_Disabled_Line"); - } + } //var state = Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled; var flags = TextFormatFlags.PreserveGraphicsTranslateTransform | TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.TextBoxControl |TextFormatFlags.WordBreak; - + if (!ShowKeyboardCues) flags |= TextFormatFlags.HidePrefix; if (RightToLeft == RightToLeft.Yes) flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right; - //No clear backgorund, this control is transparently + //No clear backgorund, this control is transparently //e.Graphics.FillRectangle(new SolidBrush(backColor), 0, 0, Width, Height); var bounds = new Rectangle(0, 0, Width, Height); @@ -68,7 +68,7 @@ namespace mRemoteNG.UI.Controls.Base else rectangle.X += 8; TextRenderer.DrawText(e.Graphics, Text, Font, rectangle, titleColor, flags); - + if (rectangle.Width > 0) rectangle.Inflate(2, 0); using (var pen = new Pen(lineColor)) diff --git a/mRemoteV1/UI/Controls/Base/NGLabel.cs b/mRemoteV1/UI/Controls/Base/NGLabel.cs index 987bc55d1..e7dc07179 100644 --- a/mRemoteV1/UI/Controls/Base/NGLabel.cs +++ b/mRemoteV1/UI/Controls/Base/NGLabel.cs @@ -26,6 +26,7 @@ namespace mRemoteNG.UI.Controls.Base base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; // Use the Dialog_* colors since Labels generally have the same colors as panels/dialogs/windows/etc... BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); @@ -78,7 +79,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive) + if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGListView.cs b/mRemoteV1/UI/Controls/Base/NGListView.cs index c91fdc10b..a385ea8c6 100644 --- a/mRemoteV1/UI/Controls/Base/NGListView.cs +++ b/mRemoteV1/UI/Controls/Base/NGListView.cs @@ -24,6 +24,7 @@ namespace mRemoteNG.UI.Controls.Base base.OnCreateControl(); var _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; //List back color BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); diff --git a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs index 532470e16..d3b33cd99 100644 --- a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs +++ b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs @@ -6,8 +6,8 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls.Base { - //Repaint of the NumericUpDown, the composite control buttons are replaced because the - //original ones cannot be themed due to protected inheritance + //Repaint of the NumericUpDown, the composite control buttons are replaced because the + //original ones cannot be themed due to protected inheritance internal class NGNumericUpDown : NumericUpDown { @@ -23,12 +23,13 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); - + if (Controls.Count > 0) { for (var i = 0; i < Controls.Count; i++) @@ -82,8 +83,8 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnEnabledChanged(EventArgs e) { - - if (_themeManager.ThemingActive) + + if (_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { if (Enabled) { @@ -94,7 +95,7 @@ namespace mRemoteNG.UI.Controls.Base { BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); } - } + } base.OnEnabledChanged(e); Invalidate(); } @@ -102,9 +103,9 @@ namespace mRemoteNG.UI.Controls.Base //Redrawing border protected override void OnPaint(PaintEventArgs e) - { + { base.OnPaint(e); - if (!_themeManager.ThemingActive) return; + if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) return; //Fix Border if (BorderStyle != BorderStyle.None) e.Graphics.DrawRectangle(new Pen(_themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Border"), 1), 0, 0, Width - 1, Height - 1); diff --git a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs index 04a59b5c0..1f9ffe735 100644 --- a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel; +using System.ComponentModel; using System.Windows.Forms; using mRemoteNG.Themes; @@ -26,6 +25,7 @@ namespace mRemoteNG.UI.Controls.Base base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); Invalidate(); diff --git a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs index f45bfe732..f76d43d90 100644 --- a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs +++ b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs @@ -18,7 +18,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; SetStyle(ControlStyles.UserPaint, true); @@ -28,7 +28,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs index fc16b226b..04d15b7b2 100644 --- a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs @@ -22,7 +22,7 @@ namespace mRemoteNG.UI.Controls.Base _circleSmall = new Rectangle(display.ScaleWidth(4), display.ScaleHeight(4), display.ScaleWidth(6), display.ScaleHeight(6)); _circle = new Rectangle(display.ScaleWidth(1), display.ScaleHeight(1), display.ScaleWidth(12), display.ScaleHeight(12)); _textXCoord = display.ScaleWidth(16); - ThemeManager.getInstance().ThemeChanged += OnCreateControl; + ThemeManager.getInstance().ThemeChanged += OnCreateControl; } @@ -38,7 +38,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; // Allows for Overlaying @@ -74,12 +74,12 @@ namespace mRemoteNG.UI.Controls.Base //This class is painted with the checkbox colors, the glyph color is used for the radio inside protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; } - // Init + // Init var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; @@ -93,7 +93,7 @@ namespace mRemoteNG.UI.Controls.Base if (Enabled) { if (Checked) - { + { center = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Glyph"); } else @@ -104,7 +104,7 @@ namespace mRemoteNG.UI.Controls.Base outline = _themeManager.ActiveTheme.ExtendedPalette.getColor("CheckBox_Border_Hover"); } } - + } else { @@ -114,9 +114,9 @@ namespace mRemoteNG.UI.Controls.Base var textRect = new Rectangle(_textXCoord, Padding.Top, Width - 16, Height); TextRenderer.DrawText(e.Graphics, Text, Font, textRect, fore, Parent.BackColor, TextFormatFlags.PathEllipsis); - + g.FillEllipse(new SolidBrush(centerBack), _circle); - g.FillEllipse(new SolidBrush(center), _circleSmall); + g.FillEllipse(new SolidBrush(center), _circleSmall); g.DrawEllipse(new Pen(outline), _circle); } diff --git a/mRemoteV1/UI/Controls/Base/NGTextBox.cs b/mRemoteV1/UI/Controls/Base/NGTextBox.cs index 4664d14bf..ef67417e7 100644 --- a/mRemoteV1/UI/Controls/Base/NGTextBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGTextBox.cs @@ -9,7 +9,7 @@ namespace mRemoteNG.UI.Controls.Base //There are some glitches on the initial draw of some controls public class NGTextBox : TextBox { - private ThemeManager _themeManager; + private ThemeManager _themeManager; public NGTextBox() { @@ -19,35 +19,31 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor(ReadOnly ? "TextBox_Disabled_Background" : "TextBox_Background"); Invalidate(); } - - protected override void OnEnabledChanged(EventArgs e) { _themeManager = ThemeManager.getInstance(); - if (_themeManager.ThemingActive) + _themeManager = ThemeManager.getInstance(); + if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) { - _themeManager = ThemeManager.getInstance(); - if(_themeManager.ThemingActive) - { - if (Enabled) - { - ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - } - else - { - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); - } + if (Enabled) + { + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } - } + else + { + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); + } + } base.OnEnabledChanged(e); Invalidate(); } diff --git a/mRemoteV1/UI/Controls/IPTextBox.cs b/mRemoteV1/UI/Controls/IPTextBox.cs index 7fb4063bd..35f103ed6 100644 --- a/mRemoteV1/UI/Controls/IPTextBox.cs +++ b/mRemoteV1/UI/Controls/IPTextBox.cs @@ -4,6 +4,7 @@ */ using System; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls { @@ -16,7 +17,7 @@ namespace mRemoteNG.UI.Controls public class IPTextBox: UserControl { private Panel panel1; - public Base.NGTextBox Octet1; + public Base.NGTextBox Octet1; public Base.NGTextBox Octet2; public Base.NGTextBox Octet3; public Base.NGTextBox Octet4; @@ -25,7 +26,7 @@ namespace mRemoteNG.UI.Controls private Base.NGLabel label3; private ToolTip toolTip1; private System.ComponentModel.IContainer components; - + /** Sets and Gets the tooltiptext on toolTip1 */ public string ToolTipText { @@ -40,7 +41,7 @@ namespace mRemoteNG.UI.Controls toolTip1.SetToolTip(label2,value); toolTip1.SetToolTip(label3,value); } - } + } /** Set or Get the string that represents the value in the box */ public override string Text @@ -69,20 +70,21 @@ namespace mRemoteNG.UI.Controls public IPTextBox() { // This call is required by the Windows.Forms Form Designer. - InitializeComponent(); + InitializeComponent(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); ApplyTheme(); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; } private void ApplyTheme() - { - if (Themes.ThemeManager.getInstance().ThemingActive) - panel1.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + { + if (ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + panel1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } protected override void Dispose( bool disposing ) { @@ -225,7 +227,7 @@ namespace mRemoteNG.UI.Controls } #endregion - + /** * \ifnot hide_events * Checks that a string passed in resolves to an integer value between 0 and 255 @@ -235,7 +237,7 @@ namespace mRemoteNG.UI.Controls * */ private static bool IsValid(string inString) { - try + try { var theValue = int.Parse(inString); if(theValue >=0 && theValue <= 255) @@ -272,7 +274,7 @@ namespace mRemoteNG.UI.Controls } e.Handled = true; } - + //If we are not overwriting the whole text else if(Octet1.SelectionLength != Octet1.Text.Length) { @@ -315,7 +317,7 @@ namespace mRemoteNG.UI.Controls Octet2.SelectAll(); } e.Handled = true; - } + } else if(Octet2.SelectionLength != Octet2.Text.Length) { if (Octet2.Text.Length != 2) return; @@ -337,7 +339,7 @@ namespace mRemoteNG.UI.Controls } else e.Handled = true; - + } /// \ifnot hide_events @@ -360,7 +362,7 @@ namespace mRemoteNG.UI.Controls Octet3.SelectAll(); } e.Handled = true; - } + } else if(Octet3.SelectionLength != Octet3.Text.Length) { if (Octet3.Text.Length != 2) return; diff --git a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs index 4771d1e42..4a560ff9e 100644 --- a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs +++ b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs @@ -52,7 +52,8 @@ namespace mRemoteNG.UI.Controls private void ApplyTheme() { if (!_themeManager.ThemingActive) return; - _txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + if (!_themeManager.ActiveTheme.IsExtendable) return; + _txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } diff --git a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs index f503f997d..ca350b945 100644 --- a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs +++ b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls.PageSequence { @@ -11,7 +12,7 @@ namespace mRemoteNG.UI.Controls.PageSequence public SequencedControl() { - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; InitializeComponent(); } @@ -22,9 +23,10 @@ namespace mRemoteNG.UI.Controls.PageSequence protected virtual void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } protected virtual void RaisePreviousPageEvent() diff --git a/mRemoteV1/UI/Forms/ExportForm.cs b/mRemoteV1/UI/Forms/ExportForm.cs index d4396d8cf..008a82ed1 100644 --- a/mRemoteV1/UI/Forms/ExportForm.cs +++ b/mRemoteV1/UI/Forms/ExportForm.cs @@ -19,7 +19,7 @@ namespace mRemoteNG.UI.Forms get => txtFileName.Text; set => txtFileName.Text = value; } - + public SaveFormat SaveFormat { get @@ -38,7 +38,7 @@ namespace mRemoteNG.UI.Forms } } } - + public ExportScope Scope { get @@ -65,7 +65,7 @@ namespace mRemoteNG.UI.Forms } } } - + private ContainerInfo _selectedFolder; public ContainerInfo SelectedFolder { @@ -77,7 +77,7 @@ namespace mRemoteNG.UI.Forms rdoExportSelectedFolder.Enabled = value != null; } } - + private ConnectionInfo _selectedConnection; public ConnectionInfo SelectedConnection { @@ -89,19 +89,19 @@ namespace mRemoteNG.UI.Forms rdoExportSelectedConnection.Enabled = value != null; } } - + public bool IncludeUsername { get => chkUsername.Checked; set => chkUsername.Checked = value; } - + public bool IncludePassword { get => chkPassword.Checked; set => chkPassword.Checked = value; } - + public bool IncludeDomain { get => chkDomain.Checked; @@ -120,7 +120,7 @@ namespace mRemoteNG.UI.Forms set => chkInheritance.Checked = value; } #endregion - + #region Constructors public ExportForm() { @@ -131,7 +131,7 @@ namespace mRemoteNG.UI.Forms btnOK.Enabled = false; } #endregion - + #region Private Methods #region Event Handlers private void ExportForm_Load(object sender, EventArgs e) @@ -157,18 +157,18 @@ namespace mRemoteNG.UI.Forms saveFileDialog.CheckPathExists = true; saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal); saveFileDialog.OverwritePrompt = true; - + var fileTypes = new List(); fileTypes.AddRange(new[] {Language.strFiltermRemoteXML, "*.xml"}); fileTypes.AddRange(new[] {Language.strFiltermRemoteCSV, "*.csv"}); fileTypes.AddRange(new[] {Language.strFilterAll, "*.*"}); - + saveFileDialog.Filter = string.Join("|", fileTypes.ToArray()); SelectFileTypeBasedOnSaveFormat(saveFileDialog); if (saveFileDialog.ShowDialog(this) != DialogResult.OK) return; - + txtFileName.Text = saveFileDialog.FileName; } } @@ -207,11 +207,12 @@ namespace mRemoteNG.UI.Forms //} } #endregion - + private void ApplyTheme() { _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } @@ -220,17 +221,17 @@ namespace mRemoteNG.UI.Forms private void ApplyLanguage() { Text = Language.strExport; - + grpFile.Text = Language.strExportFile; lblFileName.Text = Language.strLabelFilename; btnBrowse.Text = Language.strButtonBrowse; lblFileFormat.Text = Language.strFileFormatLabel; - + grpItems.Text = Language.strExportItems; rdoExportEverything.Text = Language.strExportEverything; rdoExportSelectedFolder.Text = Language.strExportSelectedFolder; rdoExportSelectedConnection.Text = Language.strExportSelectedConnection; - + grpProperties.Text = Language.strExportProperties; chkUsername.Text = Language.strCheckboxUsername; chkPassword.Text = Language.strCheckboxPassword; @@ -238,12 +239,12 @@ namespace mRemoteNG.UI.Forms chkAssignedCredential.Text = Language.strAssignedCredential; chkInheritance.Text = Language.strCheckboxInheritance; lblUncheckProperties.Text = Language.strUncheckProperties; - + btnOK.Text = Language.strButtonOK; btnCancel.Text = Language.strButtonCancel; } #endregion - + #region Public Enumerations public enum ExportScope { @@ -252,7 +253,7 @@ namespace mRemoteNG.UI.Forms SelectedConnection } #endregion - + #region Private Classes [ImmutableObject(true)] private class ExportFormat @@ -262,14 +263,14 @@ namespace mRemoteNG.UI.Forms public SaveFormat Format { get; } #endregion - + #region Constructors public ExportFormat(SaveFormat format) { Format = format; } #endregion - + #region Public Methods public override string ToString() { diff --git a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs index 7fb91b4e5..80759f966 100644 --- a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs +++ b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs @@ -27,6 +27,7 @@ namespace mRemoteNG.UI.Forms.Input private void ApplyTheme() { var activeTheme = ThemeManager.getInstance().ActiveTheme; + if (!activeTheme.IsExtendable) return; BackColor = activeTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = activeTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 803865975..f0a1e73b0 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -195,7 +195,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void btnThemeDelete_Click(object sender, EventArgs e) { - var res = CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Information, 0); if (res != DialogResult.Yes) return; diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.cs b/mRemoteV1/UI/Forms/frmChoosePanel.cs index edc760c81..d75d2986f 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.cs @@ -1,5 +1,6 @@ using System.Windows.Forms; using mRemoteNG.App; +using mRemoteNG.Themes; using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.Panels; @@ -26,7 +27,7 @@ namespace mRemoteNG.UI.Forms ApplyTheme(); AddAvailablePanels(); } - + private void ApplyLanguage() { btnOK.Text = Language.strButtonOK; @@ -37,22 +38,23 @@ namespace mRemoteNG.UI.Forms private void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - lblDescription.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - lblDescription.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + lblDescription.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + lblDescription.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void AddAvailablePanels() { cbPanels.Items.Clear(); - + for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) { cbPanels.Items.Add(Runtime.WindowList[i].Text.Replace("&&", "&")); } - + if (cbPanels.Items.Count > 0) { cbPanels.SelectedItem = cbPanels.Items[0]; diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 45460e1c0..1607b6c2d 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -280,7 +280,9 @@ namespace mRemoteNG.UI.Forms vsToolStripExtender.SetStyle(_quickConnectToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); + + if (!_themeManager.ActiveTheme.IsExtendable) return; + tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index b4fe2e68b..45a6f1a02 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Windows.Forms; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Forms { @@ -37,16 +38,17 @@ namespace mRemoteNG.UI.Forms // AddOptionsPagesToListView() -- one less foreach loop.... Text = Language.strOptionsPageTitle; ApplyTheme(); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; lstOptionPages.SelectedIndexChanged += LstOptionPages_SelectedIndexChanged; lstOptionPages.SelectedIndex = 0; } private void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } #if false diff --git a/mRemoteV1/UI/TaskDialog/CommandButton.cs b/mRemoteV1/UI/TaskDialog/CommandButton.cs index 6c9fc5748..da9a9ee79 100644 --- a/mRemoteV1/UI/TaskDialog/CommandButton.cs +++ b/mRemoteV1/UI/TaskDialog/CommandButton.cs @@ -12,12 +12,12 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- #region PRIVATE MEMBERS //-------------------------------------------------------------------------------- - Image imgArrow1; - Image imgArrow2; - private ThemeManager _themeManager; - const int LEFT_MARGIN = 10; - const int TOP_MARGIN = 10; - const int ARROW_WIDTH = 19; + private Image imgArrow1; + private Image imgArrow2; + private readonly ThemeManager _themeManager; + private const int LEFT_MARGIN = 10; + private const int TOP_MARGIN = 10; + private const int ARROW_WIDTH = 19; enum eButtonState { Normal, MouseOver, Down } eButtonState m_State = eButtonState.Normal; @@ -79,7 +79,7 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- string GetLargeText() { - string[] lines = Text.Split('\n'); + var lines = Text.Split('\n'); return lines[0]; } @@ -88,37 +88,37 @@ namespace mRemoteNG.UI.TaskDialog if (Text.IndexOf('\n') < 0) return ""; - string s = Text; - string[] lines = s.Split('\n'); + var s = Text; + var lines = s.Split('\n'); s = ""; - for (int i = 1; i < lines.Length; i++) + for (var i = 1; i < lines.Length; i++) s += lines[i] + "\n"; return s.Trim('\n'); } SizeF GetLargeTextSizeF() { - int x = LEFT_MARGIN + ARROW_WIDTH + 5; - SizeF mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN - Graphics g = Graphics.FromHwnd(Handle); - SizeF textSize = g.MeasureString(GetLargeText(), Font, mzSize); + var x = LEFT_MARGIN + ARROW_WIDTH + 5; + var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN + var g = Graphics.FromHwnd(Handle); + var textSize = g.MeasureString(GetLargeText(), Font, mzSize); return textSize; } SizeF GetSmallTextSizeF() { - string s = GetSmallText(); + var s = GetSmallText(); if (s == "") return new SizeF(0, 0); - int x = LEFT_MARGIN + ARROW_WIDTH + 8; // <- indent small text slightly more - SizeF mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN - Graphics g = Graphics.FromHwnd(Handle); - SizeF textSize = g.MeasureString(s, SmallFont, mzSize); + var x = LEFT_MARGIN + ARROW_WIDTH + 8; // <- indent small text slightly more + var mzSize = new SizeF(Width - x - LEFT_MARGIN, 5000.0F); // presume RIGHT_MARGIN = LEFT_MARGIN + var g = Graphics.FromHwnd(Handle); + var textSize = g.MeasureString(s, SmallFont, mzSize); return textSize; } #endregion //-------------------------------------------------------------------------------- - #region OVERRIDEs + #region OVERRIDES //-------------------------------------------------------------------------------- protected override void OnCreateControl() { @@ -130,7 +130,7 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) { base.OnPaint(e); return; @@ -138,12 +138,11 @@ namespace mRemoteNG.UI.TaskDialog e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - LinearGradientBrush brush; - LinearGradientMode mode = LinearGradientMode.Vertical; + const LinearGradientMode mode = LinearGradientMode.Vertical; - Rectangle newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1); + var newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1); - Image img = imgArrow1; + var img = imgArrow1; Color back; @@ -185,21 +184,21 @@ namespace mRemoteNG.UI.TaskDialog } else { - brush = new LinearGradientBrush(newRect, back, back, mode); + var brush = new LinearGradientBrush(newRect, back, back, mode); e.Graphics.FillRectangle(brush, newRect); e.Graphics.DrawRectangle(new Pen(border, 1), newRect); } - string largetext = GetLargeText(); - string smalltext = GetSmallText(); + var largetext = GetLargeText(); + var smalltext = GetSmallText(); - SizeF szL = GetLargeTextSizeF(); + var szL = GetLargeTextSizeF(); //e.Graphics.DrawString(largetext, base.Font, new SolidBrush(text_color), new RectangleF(new PointF(LEFT_MARGIN + imgArrow1.Width + 5, TOP_MARGIN), szL)); TextRenderer.DrawText(e.Graphics, largetext, Font, new Rectangle(LEFT_MARGIN + imgArrow1.Width + 5, TOP_MARGIN, (int)szL.Width, (int)szL.Height), fore, TextFormatFlags.Default); if (smalltext != "") { - SizeF szS = GetSmallTextSizeF(); + var szS = GetSmallTextSizeF(); e.Graphics.DrawString(smalltext, SmallFont, new SolidBrush(fore), new RectangleF(new PointF(LEFT_MARGIN + imgArrow1.Width + 8, TOP_MARGIN + (int)szL.Height), szS)); } @@ -243,7 +242,7 @@ namespace mRemoteNG.UI.TaskDialog { if (m_autoHeight) { - int h = GetBestHeight(); + var h = GetBestHeight(); if (Height != h) { Height = h; diff --git a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs index 65096087c..20678be70 100644 --- a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs +++ b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs @@ -323,8 +323,8 @@ namespace mRemoteNG.UI.TaskDialog private void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) - return; + if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; pnlButtons.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); pnlButtons.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index 3b1a92d21..2b1d054cd 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -5,6 +5,7 @@ using System.IO; using System.Text; using mRemoteNG.App; using mRemoteNG.App.Info; +using mRemoteNG.Themes; namespace mRemoteNG.UI.Window { @@ -96,7 +97,7 @@ namespace mRemoteNG.UI.Window // // txtCredits // - this.txtCredits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.txtCredits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.txtCredits.BackColor = System.Drawing.SystemColors.Control; this.txtCredits.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -115,8 +116,8 @@ namespace mRemoteNG.UI.Window // // txtChangeLog // - this.txtChangeLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtChangeLog.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.txtChangeLog.BackColor = System.Drawing.SystemColors.Control; this.txtChangeLog.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -218,7 +219,7 @@ namespace mRemoteNG.UI.Window } #endregion - + #region Public Methods public AboutWindow() { @@ -226,11 +227,11 @@ namespace mRemoteNG.UI.Window DockPnl = new DockContent(); InitializeComponent(); FontOverrider.FontOverride(this); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); } #endregion - + #region Private Methods private void ApplyLanguage() { @@ -242,14 +243,15 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ThemingActive) return; base.ApplyTheme(); - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlBottom.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlBottom.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlTop.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlTop.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlBottom.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlBottom.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlTop.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlTop.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void ApplyEditions() @@ -263,7 +265,7 @@ namespace mRemoteNG.UI.Window private void FillLinkLabel(LinkLabel llbl, string txt, string URL) { llbl.Links.Clear(); - + int Open = txt.IndexOf("["); while (Open != -1) { @@ -277,12 +279,12 @@ namespace mRemoteNG.UI.Window llbl.Links.Add(Open, Close - Open, URL); Open = txt.IndexOf("[", Open); } - + llbl.Text = txt; } #endif #endregion - + #region Form Stuff private void About_Load(object sender, EventArgs e) @@ -349,12 +351,12 @@ namespace mRemoteNG.UI.Window { Runtime.GoToURL(Language.strFAMFAMFAMAttributionURL); } - + private void llblMagicLibrary_LinkClicked(Object sender, LinkLabelLinkClickedEventArgs e) { Runtime.GoToURL(Language.strMagicLibraryAttributionURL); } - + private void llblWeifenLuo_LinkClicked(Object sender, LinkLabelLinkClickedEventArgs e) { Runtime.GoToURL(Language.strWeifenLuoAttributionURL); diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index c072c91ae..31e6bd17d 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -29,6 +29,7 @@ namespace mRemoteNG.UI.Window if (!(ActiveDirectoryTree.Controls[0] is TreeView tv)) return; var tm = ThemeManager.getInstance(); if (!tm.ThemingActive) return; + if (!tm.ActiveTheme.IsExtendable) return; tv.BackColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Background"); tv.ForeColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); } diff --git a/mRemoteV1/UI/Window/BaseWindow.cs b/mRemoteV1/UI/Window/BaseWindow.cs index 877456ebd..2a757f61b 100644 --- a/mRemoteV1/UI/Window/BaseWindow.cs +++ b/mRemoteV1/UI/Window/BaseWindow.cs @@ -33,6 +33,7 @@ namespace mRemoteNG.UI.Window { _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; + if (!_themeManager.ActiveTheme.IsExtendable) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs index 3d2930504..3eee23a78 100644 --- a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs +++ b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs @@ -10,6 +10,7 @@ using mRemoteNG.App; using mRemoteNG.App.Info; using mRemoteNG.Connection.Protocol.RDP; using mRemoteNG.Messages; +using mRemoteNG.Themes; using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window @@ -84,7 +85,7 @@ namespace mRemoteNG.UI.Window // // pnlCheck1 // - this.pnlCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.pnlCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck1.Controls.Add(this.txtCheck1); this.pnlCheck1.Controls.Add(this.lblCheck1); @@ -97,8 +98,8 @@ namespace mRemoteNG.UI.Window // // txtCheck1 // - this.txtCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtCheck1.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.txtCheck1.BackColor = System.Drawing.SystemColors.Control; this.txtCheck1.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -111,7 +112,7 @@ namespace mRemoteNG.UI.Window // // lblCheck1 // - this.lblCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblCheck1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck1.ForeColor = System.Drawing.SystemColors.ControlText; @@ -123,7 +124,7 @@ namespace mRemoteNG.UI.Window // // pbCheck1 // - this.pbCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.pbCheck1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck1.Location = new System.Drawing.Point(3, 3); this.pbCheck1.Name = "pbCheck1"; @@ -133,7 +134,7 @@ namespace mRemoteNG.UI.Window // // pnlCheck2 // - this.pnlCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.pnlCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck2.Controls.Add(this.txtCheck2); this.pnlCheck2.Controls.Add(this.lblCheck2); @@ -146,8 +147,8 @@ namespace mRemoteNG.UI.Window // // txtCheck2 // - this.txtCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtCheck2.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.txtCheck2.BackColor = System.Drawing.SystemColors.Control; this.txtCheck2.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -160,7 +161,7 @@ namespace mRemoteNG.UI.Window // // lblCheck2 // - this.lblCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblCheck2.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck2.Location = new System.Drawing.Point(112, 3); @@ -171,7 +172,7 @@ namespace mRemoteNG.UI.Window // // pbCheck2 // - this.pbCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.pbCheck2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck2.Location = new System.Drawing.Point(3, 3); this.pbCheck2.Name = "pbCheck2"; @@ -181,7 +182,7 @@ namespace mRemoteNG.UI.Window // // pnlCheck3 // - this.pnlCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.pnlCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck3.Controls.Add(this.txtCheck3); this.pnlCheck3.Controls.Add(this.lblCheck3); @@ -194,8 +195,8 @@ namespace mRemoteNG.UI.Window // // txtCheck3 // - this.txtCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtCheck3.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.txtCheck3.BackColor = System.Drawing.SystemColors.Control; this.txtCheck3.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -208,7 +209,7 @@ namespace mRemoteNG.UI.Window // // lblCheck3 // - this.lblCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblCheck3.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck3.Location = new System.Drawing.Point(112, 3); @@ -219,7 +220,7 @@ namespace mRemoteNG.UI.Window // // pbCheck3 // - this.pbCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.pbCheck3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck3.Location = new System.Drawing.Point(3, 3); this.pbCheck3.Name = "pbCheck3"; @@ -229,7 +230,7 @@ namespace mRemoteNG.UI.Window // // pnlCheck4 // - this.pnlCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.pnlCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck4.Controls.Add(this.txtCheck4); this.pnlCheck4.Controls.Add(this.lblCheck4); @@ -242,8 +243,8 @@ namespace mRemoteNG.UI.Window // // txtCheck4 // - this.txtCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtCheck4.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.txtCheck4.BackColor = System.Drawing.SystemColors.Control; this.txtCheck4.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -256,7 +257,7 @@ namespace mRemoteNG.UI.Window // // lblCheck4 // - this.lblCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblCheck4.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck4.Location = new System.Drawing.Point(112, 3); @@ -267,7 +268,7 @@ namespace mRemoteNG.UI.Window // // pbCheck4 // - this.pbCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.pbCheck4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck4.Location = new System.Drawing.Point(3, 3); this.pbCheck4.Name = "pbCheck4"; @@ -277,7 +278,7 @@ namespace mRemoteNG.UI.Window // // pnlCheck5 // - this.pnlCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.pnlCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlCheck5.Controls.Add(this.txtCheck5); this.pnlCheck5.Controls.Add(this.lblCheck5); @@ -290,8 +291,8 @@ namespace mRemoteNG.UI.Window // // txtCheck5 // - this.txtCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.txtCheck5.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.txtCheck5.BackColor = System.Drawing.SystemColors.Control; this.txtCheck5.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -304,7 +305,7 @@ namespace mRemoteNG.UI.Window // // lblCheck5 // - this.lblCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblCheck5.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblCheck5.Location = new System.Drawing.Point(112, 3); @@ -315,7 +316,7 @@ namespace mRemoteNG.UI.Window // // pbCheck5 // - this.pbCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.pbCheck5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.pbCheck5.Location = new System.Drawing.Point(3, 3); this.pbCheck5.Name = "pbCheck5"; @@ -352,8 +353,8 @@ namespace mRemoteNG.UI.Window // // pnlChecks // - this.pnlChecks.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.pnlChecks.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.pnlChecks.AutoScroll = true; this.pnlChecks.Controls.Add(this.pnlCheck1); @@ -412,7 +413,7 @@ namespace mRemoteNG.UI.Window _successImage = display.ScaleImage(Resources.Good_Symbol); _failureImage = display.ScaleImage(Resources.Bad_Symbol); FontOverrider.FontOverride(this); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; } #endregion @@ -435,20 +436,22 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ThemingActive) return; base.ApplyTheme(); - pnlCheck1.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCheck1.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlCheck2.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCheck2.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlCheck3.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCheck3.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlCheck4.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCheck4.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlCheck5.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlCheck5.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlChecks.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlChecks.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + pnlCheck1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck1.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck2.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck2.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck3.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck3.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck4.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck4.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck5.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck5.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlChecks.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlChecks.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void btnCheckAgain_Click(object sender, EventArgs e) @@ -489,7 +492,7 @@ namespace mRemoteNG.UI.Window private void CheckRdp() { pnlCheck1.Visible = true; - + try { using (var rdpClient = new AxMsRdpClient8NotSafeForScripting()) @@ -531,7 +534,7 @@ namespace mRemoteNG.UI.Window private void CheckVnc() { pnlCheck2.Visible = true; - + try { using (var vnc = new VncSharp.RemoteDesktop()) @@ -604,7 +607,7 @@ namespace mRemoteNG.UI.Window private void CheckIca() { pnlCheck4.Visible = true; - + try { using (var ica = new AxICAClient()) diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index f1581047d..1311076c3 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -606,6 +606,7 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; _pGrid.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _pGrid.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); _pGrid.ViewBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Background"); diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 92a9f444c..f3d325840 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -97,6 +97,8 @@ namespace mRemoteNG.UI.Window if (!_themeManager.ThemingActive) return; vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(olvConnections.ContextMenuStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + + if (!_themeManager.ActiveTheme.IsExtendable) return; //Treelistview need to be manually themed olvConnections.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Background"); olvConnections.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Foreground"); diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 6dfaf8cbe..4a8dd5545 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -201,6 +201,8 @@ namespace mRemoteNG.UI.Window DefaultRenderer = _toolStripProfessionalRenderer }; vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); + + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } diff --git a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs index 4b7c2f3df..e06bb33c2 100644 --- a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs +++ b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs @@ -44,7 +44,7 @@ namespace mRemoteNG.UI.Window private void ErrorsAndInfos_Load(object sender, EventArgs e) { } - + private void ApplyLanguage() { clmMessage.Text = Language.strColumnMessage; @@ -54,11 +54,13 @@ namespace mRemoteNG.UI.Window Text = Language.strMenuNotifications; } #endregion - + #region Private Methods private new void ApplyTheme() { if (!_themeManager.ThemingActive) return; + + if (!_themeManager.ActiveTheme.IsExtendable) return; lvErrorCollector.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); lvErrorCollector.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); @@ -78,7 +80,7 @@ namespace mRemoteNG.UI.Window imgListMC.Images.Add(_display.ScaleImage(Resources.WarningSmall)); imgListMC.Images.Add(_display.ScaleImage(Resources.ErrorSmall)); } - + private void LayoutVertical() { try @@ -87,12 +89,12 @@ namespace mRemoteNG.UI.Window pnlErrorMsg.Size = new Size(Width, Height - pnlErrorMsg.Top); pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; txtMsgText.Size = new Size( - pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), + pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), pnlErrorMsg.Height - _display.ScaleHeight(20)); lvErrorCollector.Location = new Point(0, 0); lvErrorCollector.Size = new Size(Width, Height - pnlErrorMsg.Height - _display.ScaleHeight(5)); lvErrorCollector.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; - + _layout = ControlLayout.Vertical; } catch (Exception ex) @@ -100,7 +102,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "LayoutVertical (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void LayoutHorizontal() { try @@ -110,12 +112,12 @@ namespace mRemoteNG.UI.Window pnlErrorMsg.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top; txtMsgText.Size = new Size( - pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), + pnlErrorMsg.Width - pbError.Width - _display.ScaleWidth(8), pnlErrorMsg.Height - _display.ScaleHeight(20)); lvErrorCollector.Location = new Point(pnlErrorMsg.Width + _display.ScaleWidth(5), 0); lvErrorCollector.Size = new Size(Width - pnlErrorMsg.Width - _display.ScaleWidth(5), Height); lvErrorCollector.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; - + _layout = ControlLayout.Horizontal; } catch (Exception ex) @@ -123,7 +125,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "LayoutHorizontal (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void ErrorsAndInfos_Resize(object sender, EventArgs e) { try @@ -138,7 +140,7 @@ namespace mRemoteNG.UI.Window if (_layout == ControlLayout.Horizontal) LayoutVertical(); } - + lvErrorCollector.Columns[0].Width = lvErrorCollector.Width - 20; } catch (Exception ex) @@ -146,7 +148,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ErrorsAndInfos_Resize (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void SetStyleWhenNoMessageSelected() { try @@ -163,7 +165,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "pnlErrorMsg_ResetDefaultStyle (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void MC_KeyDown(object sender, KeyEventArgs e) { try @@ -186,7 +188,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "MC_KeyDown (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void lvErrorCollector_SelectedIndexChanged(object sender, EventArgs e) { try @@ -196,9 +198,9 @@ namespace mRemoteNG.UI.Window SetStyleWhenNoMessageSelected(); return; } - + var sItem = lvErrorCollector.SelectedItems[0]; - var eMsg = (Messages.Message)sItem.Tag; + var eMsg = (Message)sItem.Tag; switch (eMsg.Class) { case MessageClass.DebugMsg: @@ -221,7 +223,7 @@ namespace mRemoteNG.UI.Window break; case MessageClass.WarningMsg: pbError.Image = _display.ScaleImage(Resources.Warning); - if (_themeManager.ThemingActive) + if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) { //Inverse colors for dramatic effect pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); @@ -234,7 +236,7 @@ namespace mRemoteNG.UI.Window break; case MessageClass.ErrorMsg: pbError.Image = _display.ScaleImage(Resources._Error); - if (_themeManager.ThemingActive) + if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) { pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); pnlErrorMsg.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); @@ -245,7 +247,7 @@ namespace mRemoteNG.UI.Window } break; } - + lblMsgDate.Text = eMsg.Date.ToString(CultureInfo.InvariantCulture); txtMsgText.Text = eMsg.Text; } @@ -254,7 +256,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "lvErrorCollector_SelectedIndexChanged (UI.Window.ErrorsAndInfos) failed" + Environment.NewLine + ex.Message, true); } } - + private void cMenMC_Opening(object sender, System.ComponentModel.CancelEventArgs e) { if (lvErrorCollector.Items.Count > 0) @@ -267,7 +269,7 @@ namespace mRemoteNG.UI.Window cMenMCCopy.Enabled = false; cMenMCDelete.Enabled = false; } - + if (lvErrorCollector.SelectedItems.Count > 0) { cMenMCCopy.Text = Language.strMenuCopy; @@ -279,12 +281,12 @@ namespace mRemoteNG.UI.Window cMenMCDelete.Text = Language.strMenuNotificationsDeleteAll; } } - + private void cMenMCCopy_Click(object sender, EventArgs e) { CopyMessagesToClipboard(); } - + private void CopyMessagesToClipboard() { try @@ -298,10 +300,10 @@ namespace mRemoteNG.UI.Window { items = lvErrorCollector.Items; } - + var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("----------"); - + lvErrorCollector.BeginUpdate(); foreach (ListViewItem item in items) @@ -310,13 +312,13 @@ namespace mRemoteNG.UI.Window { continue; } - + stringBuilder.AppendLine(message.Class.ToString()); stringBuilder.AppendLine(message.Date.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(message.Text); stringBuilder.AppendLine("----------"); } - + Clipboard.SetText(stringBuilder.ToString()); } catch (Exception ex) @@ -328,18 +330,18 @@ namespace mRemoteNG.UI.Window lvErrorCollector.EndUpdate(); } } - + private void cMenMCDelete_Click(object sender, EventArgs e) { DeleteMessages(); } - + private void DeleteMessages() { try { lvErrorCollector.BeginUpdate(); - + if (lvErrorCollector.SelectedItems.Count > 0) { foreach (ListViewItem item in lvErrorCollector.SelectedItems) diff --git a/mRemoteV1/UI/Window/UpdateWindow.cs b/mRemoteV1/UI/Window/UpdateWindow.cs index b0e0a8b89..de89acf98 100644 --- a/mRemoteV1/UI/Window/UpdateWindow.cs +++ b/mRemoteV1/UI/Window/UpdateWindow.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.App.Update; using mRemoteNG.Messages; +using mRemoteNG.Themes; using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Window @@ -30,25 +31,25 @@ namespace mRemoteNG.UI.Window FontOverrider.FontOverride(this); } #endregion - + #region Form Stuff private void Update_Load(object sender, EventArgs e) { ApplyTheme(); - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; + ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); CheckForUpdate(); } private new void ApplyTheme() { - if (!Themes.ThemeManager.getInstance().ThemingActive) - return; + if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; - base.ApplyTheme(); - txtChangeLog.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - txtChangeLog.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + base.ApplyTheme(); + txtChangeLog.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + txtChangeLog.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void ApplyLanguage() @@ -84,7 +85,7 @@ namespace mRemoteNG.UI.Window Process.Start(linkUri.ToString()); } #endregion - + #region Private Methods private void CheckForUpdate() { @@ -97,7 +98,7 @@ namespace mRemoteNG.UI.Window { return; } - + lblStatus.Text = Language.strUpdateCheckingLabel; lblStatus.ForeColor = SystemColors.WindowText; lblLatestVersionLabel.Visible = false; @@ -107,12 +108,12 @@ namespace mRemoteNG.UI.Window btnCheckForUpdate.Visible = false; SetVisibilityOfUpdateControls(false); - + _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; - + _appUpdate.GetUpdateInfoAsync(); } - + private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) { if (InvokeRequired) @@ -121,16 +122,16 @@ namespace mRemoteNG.UI.Window Invoke(myDelegate, sender, e); return; } - + try { _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; - + lblInstalledVersion.Text = Application.ProductVersion; lblInstalledVersion.Visible = true; lblInstalledVersionLabel.Visible = true; btnCheckForUpdate.Visible = true; - + if (e.Cancelled) { return; @@ -139,18 +140,18 @@ namespace mRemoteNG.UI.Window { throw e.Error; } - + if (_appUpdate.IsUpdateAvailable()) { lblStatus.Text = Language.strUpdateAvailable; lblStatus.ForeColor = Color.OrangeRed; SetVisibilityOfUpdateControls(true); - + var updateInfo = _appUpdate.CurrentUpdateInfo; lblLatestVersion.Text = updateInfo.Version.ToString(); lblLatestVersionLabel.Visible = true; lblLatestVersion.Visible = true; - + if (updateInfo.ImageAddress == null || string.IsNullOrEmpty(updateInfo.ImageAddress.ToString())) { pbUpdateImage.Visible = false; @@ -161,10 +162,10 @@ namespace mRemoteNG.UI.Window pbUpdateImage.Tag = updateInfo.ImageLinkAddress; pbUpdateImage.Visible = true; } - + _appUpdate.GetChangeLogCompletedEvent += GetChangeLogCompleted; _appUpdate.GetChangeLogAsync(); - + btnDownload.Focus(); } else @@ -184,7 +185,7 @@ namespace mRemoteNG.UI.Window { lblStatus.Text = Language.strUpdateCheckFailedLabel; lblStatus.ForeColor = Color.OrangeRed; - + Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateCheckCompleteFailed, ex); } } @@ -196,7 +197,7 @@ namespace mRemoteNG.UI.Window btnDownload.Visible = visible; prgbDownload.Visible = visible; } - + private void GetChangeLogCompleted(object sender, AsyncCompletedEventArgs e) { if (InvokeRequired) @@ -205,11 +206,11 @@ namespace mRemoteNG.UI.Window Invoke(myDelegate, sender, e); return; } - + try { _appUpdate.GetChangeLogCompletedEvent -= GetChangeLogCompleted; - + if (e.Cancelled) return; if (e.Error != null) @@ -222,7 +223,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector?.AddExceptionStackTrace(Language.strUpdateGetChangeLogFailed, ex); } } - + private void DownloadUpdate() { try @@ -230,14 +231,14 @@ namespace mRemoteNG.UI.Window btnDownload.Enabled = false; prgbDownload.Visible = true; prgbDownload.Value = 0; - + if (_isUpdateDownloadHandlerDeclared == false) { _appUpdate.DownloadUpdateProgressChangedEvent += DownloadUpdateProgressChanged; _appUpdate.DownloadUpdateCompletedEvent += DownloadUpdateCompleted; _isUpdateDownloadHandlerDeclared = true; } - + _appUpdate.DownloadUpdateAsync(); } catch (Exception ex) @@ -246,20 +247,20 @@ namespace mRemoteNG.UI.Window } } #endregion - + #region Events private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) { prgbDownload.Value = e.ProgressPercentage; } - + private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) { try { btnDownload.Enabled = true; prgbDownload.Visible = false; - + if (e.Cancelled) return; if (e.Error != null) From a0935e86130cced3ba012ddf38b7b493a0754826 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 11:29:15 -0500 Subject: [PATCH 117/157] missed 2 files in last commit --- mRemoteV1/UI/Controls/QuickConnectToolStrip.cs | 2 ++ mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index 0da8d9366..238682579 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -138,6 +138,8 @@ namespace mRemoteNG.UI.Controls if (!_themeManager.ThemingActive) return; vsToolStripExtender.SetStyle(_mnuQuickConnectProtocol, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(_mnuConnections, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + + if (!_themeManager.ActiveTheme.IsExtendable) return; _cmbQuickConnect.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _cmbQuickConnect.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index 87c49ff29..c6e587a3a 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -47,6 +47,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages protected virtual void ApplyTheme() { if (!ThemeManager.getInstance().ThemingActive) return; + if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); Invalidate(); From adefd95fb62331c7fcf700631b47d2311a58bcfc Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 11:29:41 -0500 Subject: [PATCH 118/157] undo a line that was added for testing... Sorry. --- mRemoteV1/Themes/ThemeManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 8e4b3dca2..ba4f4f0f2 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -136,7 +136,6 @@ namespace mRemoteNG.Themes if (themes != null) return themes.Values.OfType().ToList(); themes = new Hashtable(); - return themes.Values.OfType().ToList(); if (themePath == null) return themes.Values.OfType().ToList(); try { From f059a7732fa0d99d219ad0b8ed89ef51d1f54b9a Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 11 Jan 2019 13:30:39 -0500 Subject: [PATCH 119/157] Fix some theming issues. New IsExtended propery Done with theme stuff... Or at least I want to be... --- mRemoteV1/Themes/ThemeInfo.cs | 12 ++++++++---- mRemoteV1/Themes/ThemeManager.cs | 2 ++ mRemoteV1/UI/Controls/Base/NGButton.cs | 2 +- mRemoteV1/UI/Controls/Base/NGCheckBox.cs | 2 +- mRemoteV1/UI/Controls/Base/NGComboBox.cs | 4 ++-- mRemoteV1/UI/Controls/Base/NGGroupBox.cs | 2 +- mRemoteV1/UI/Controls/Base/NGLabel.cs | 5 ++--- mRemoteV1/UI/Controls/Base/NGListView.cs | 3 +-- mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs | 7 +++---- mRemoteV1/UI/Controls/Base/NGPictureBox.cs | 3 +-- mRemoteV1/UI/Controls/Base/NGProgressBar.cs | 2 +- mRemoteV1/UI/Controls/Base/NGRadioButton.cs | 2 +- mRemoteV1/UI/Controls/Base/NGTextBox.cs | 5 ++--- mRemoteV1/UI/Controls/IPTextBox.cs | 3 +-- mRemoteV1/UI/Controls/MultiSshToolStrip.cs | 3 +-- .../UI/Controls/PageSequence/SequencedControl.cs | 3 +-- mRemoteV1/UI/Controls/QuickConnectToolStrip.cs | 2 +- mRemoteV1/UI/Forms/ExportForm.cs | 3 +-- mRemoteV1/UI/Forms/Input/FrmInputBox.cs | 8 ++++---- mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs | 3 +-- mRemoteV1/UI/Forms/frmChoosePanel.cs | 3 +-- mRemoteV1/UI/Forms/frmMain.cs | 2 +- mRemoteV1/UI/Forms/frmOptions.cs | 3 +-- mRemoteV1/UI/TaskDialog/CommandButton.cs | 2 +- mRemoteV1/UI/TaskDialog/frmTaskDialog.cs | 3 +-- mRemoteV1/UI/Window/AboutWindow.cs | 2 +- mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs | 3 +-- mRemoteV1/UI/Window/BaseWindow.cs | 3 +-- mRemoteV1/UI/Window/ComponentsCheckWindow.cs | 2 +- mRemoteV1/UI/Window/ConfigWindow.cs | 3 +-- mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 2 +- mRemoteV1/UI/Window/ConnectionWindow.cs | 2 +- mRemoteV1/UI/Window/ErrorAndInfoWindow.cs | 8 +++----- mRemoteV1/UI/Window/ExternalToolsWindow.cs | 12 ++++++------ mRemoteV1/UI/Window/UpdateWindow.cs | 3 +-- 35 files changed, 58 insertions(+), 71 deletions(-) diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index 933d388a8..8440eca65 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -32,9 +32,11 @@ namespace mRemoteNG.Themes _extendedPalette = inExtendedPalette; IsThemeBase = false; IsExtendable = false; + + if(_extendedPalette != null) + IsExtended = true; + setCustomExtenders(); - - } public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion) @@ -45,6 +47,7 @@ namespace mRemoteNG.Themes _version = inVersion; IsThemeBase = false; IsExtendable = false; + IsExtended = false; setCustomExtenders(); } @@ -82,7 +85,7 @@ namespace mRemoteNG.Themes { return; } - _name = value; + _name = value; } } @@ -143,12 +146,13 @@ namespace mRemoteNG.Themes public bool IsExtendable { get; set; } + public bool IsExtended { get; private set; } + #endregion //Custom extenders for mremote customizations in DPS private void setCustomExtenders() { - _theme.Extender.DockPaneStripFactory = new MremoteDockPaneStripFactory(); _theme.Extender.FloatWindowFactory = new MremoteFloatWindowFactory(); } diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index ba4f4f0f2..4890b6dfe 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -323,6 +323,8 @@ namespace mRemoteNG.Themes } } + public bool ActiveAndExtended => ThemingActive && ActiveTheme.IsExtended; + public int ThemesCount => themes.Count; #endregion diff --git a/mRemoteV1/UI/Controls/Base/NGButton.cs b/mRemoteV1/UI/Controls/Base/NGButton.cs index 321aeea0c..0be06fff1 100644 --- a/mRemoteV1/UI/Controls/Base/NGButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGButton.cs @@ -75,7 +75,7 @@ namespace mRemoteNG.UI.Controls.Base /// protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive || _themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs index 15547ecfe..c7432d603 100644 --- a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs @@ -73,7 +73,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGComboBox.cs b/mRemoteV1/UI/Controls/Base/NGComboBox.cs index 6e66251fd..0740926e1 100644 --- a/mRemoteV1/UI/Controls/Base/NGComboBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGComboBox.cs @@ -26,7 +26,7 @@ namespace mRemoteNG.UI.Controls.Base { base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Foreground"); DrawMode = DrawMode.OwnerDrawFixed; @@ -93,7 +93,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if ( !_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs index e26cfc0d2..a4266434a 100644 --- a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs @@ -28,7 +28,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGLabel.cs b/mRemoteV1/UI/Controls/Base/NGLabel.cs index e7dc07179..f2c656a2e 100644 --- a/mRemoteV1/UI/Controls/Base/NGLabel.cs +++ b/mRemoteV1/UI/Controls/Base/NGLabel.cs @@ -25,8 +25,7 @@ namespace mRemoteNG.UI.Controls.Base { base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; // Use the Dialog_* colors since Labels generally have the same colors as panels/dialogs/windows/etc... BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); @@ -79,7 +78,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGListView.cs b/mRemoteV1/UI/Controls/Base/NGListView.cs index a385ea8c6..642134f5a 100644 --- a/mRemoteV1/UI/Controls/Base/NGListView.cs +++ b/mRemoteV1/UI/Controls/Base/NGListView.cs @@ -23,8 +23,7 @@ namespace mRemoteNG.UI.Controls.Base { base.OnCreateControl(); var _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; //List back color BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); diff --git a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs index d3b33cd99..6d4563d09 100644 --- a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs +++ b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs @@ -24,8 +24,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { base.OnCreateControl(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); @@ -84,7 +83,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnEnabledChanged(EventArgs e) { - if (_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (_themeManager.ActiveAndExtended) { if (Enabled) { @@ -105,7 +104,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); - if (!_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; //Fix Border if (BorderStyle != BorderStyle.None) e.Graphics.DrawRectangle(new Pen(_themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Border"), 1), 0, 0, Width - 1, Height - 1); diff --git a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs index 1f9ffe735..7600a4d4d 100644 --- a/mRemoteV1/UI/Controls/Base/NGPictureBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGPictureBox.cs @@ -24,8 +24,7 @@ namespace mRemoteNG.UI.Controls.Base { base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); Invalidate(); diff --git a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs index f76d43d90..a6b065a45 100644 --- a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs +++ b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs @@ -28,7 +28,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs index 04d15b7b2..1de9e7efe 100644 --- a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs @@ -74,7 +74,7 @@ namespace mRemoteNG.UI.Controls.Base //This class is painted with the checkbox colors, the glyph color is used for the radio inside protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGTextBox.cs b/mRemoteV1/UI/Controls/Base/NGTextBox.cs index ef67417e7..00253193b 100644 --- a/mRemoteV1/UI/Controls/Base/NGTextBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGTextBox.cs @@ -21,8 +21,7 @@ namespace mRemoteNG.UI.Controls.Base { base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor(ReadOnly ? "TextBox_Disabled_Background" : "TextBox_Background"); Invalidate(); @@ -32,7 +31,7 @@ namespace mRemoteNG.UI.Controls.Base { _themeManager = ThemeManager.getInstance(); _themeManager = ThemeManager.getInstance(); - if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) + if (_themeManager.ActiveAndExtended) { if (Enabled) { diff --git a/mRemoteV1/UI/Controls/IPTextBox.cs b/mRemoteV1/UI/Controls/IPTextBox.cs index 35f103ed6..3c0f164bb 100644 --- a/mRemoteV1/UI/Controls/IPTextBox.cs +++ b/mRemoteV1/UI/Controls/IPTextBox.cs @@ -82,8 +82,7 @@ namespace mRemoteNG.UI.Controls private void ApplyTheme() { - if (ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (ThemeManager.getInstance().ActiveAndExtended) return; panel1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } protected override void Dispose( bool disposing ) diff --git a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs index 4a560ff9e..bb431a1b8 100644 --- a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs +++ b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs @@ -51,8 +51,7 @@ namespace mRemoteNG.UI.Controls private void ApplyTheme() { - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; _txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } diff --git a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs index ca350b945..ef6b4075a 100644 --- a/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs +++ b/mRemoteV1/UI/Controls/PageSequence/SequencedControl.cs @@ -23,8 +23,7 @@ namespace mRemoteNG.UI.Controls.PageSequence protected virtual void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index 238682579..47e39ffd9 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -139,7 +139,7 @@ namespace mRemoteNG.UI.Controls vsToolStripExtender.SetStyle(_mnuQuickConnectProtocol, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(_mnuConnections, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; _cmbQuickConnect.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _cmbQuickConnect.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } diff --git a/mRemoteV1/UI/Forms/ExportForm.cs b/mRemoteV1/UI/Forms/ExportForm.cs index 008a82ed1..ef67d708d 100644 --- a/mRemoteV1/UI/Forms/ExportForm.cs +++ b/mRemoteV1/UI/Forms/ExportForm.cs @@ -211,8 +211,7 @@ namespace mRemoteNG.UI.Forms private void ApplyTheme() { _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs index 80759f966..1e099e2fb 100644 --- a/mRemoteV1/UI/Forms/Input/FrmInputBox.cs +++ b/mRemoteV1/UI/Forms/Input/FrmInputBox.cs @@ -26,10 +26,10 @@ namespace mRemoteNG.UI.Forms.Input private void ApplyTheme() { - var activeTheme = ThemeManager.getInstance().ActiveTheme; - if (!activeTheme.IsExtendable) return; - BackColor = activeTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = activeTheme.ExtendedPalette.getColor("Dialog_Foreground"); + var _themeManager = ThemeManager.getInstance(); + if (!_themeManager.ActiveAndExtended) return; + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void buttonOk_Click(object sender, System.EventArgs e) diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index c6e587a3a..143073d63 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -46,8 +46,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages protected virtual void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); Invalidate(); diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.cs b/mRemoteV1/UI/Forms/frmChoosePanel.cs index d75d2986f..12d765461 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.cs @@ -38,8 +38,7 @@ namespace mRemoteNG.UI.Forms private void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); lblDescription.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 1607b6c2d..cb3231ad4 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -281,7 +281,7 @@ namespace mRemoteNG.UI.Forms vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index 45a6f1a02..390ffd3a6 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -45,8 +45,7 @@ namespace mRemoteNG.UI.Forms private void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/TaskDialog/CommandButton.cs b/mRemoteV1/UI/TaskDialog/CommandButton.cs index da9a9ee79..dfc7fe1a7 100644 --- a/mRemoteV1/UI/TaskDialog/CommandButton.cs +++ b/mRemoteV1/UI/TaskDialog/CommandButton.cs @@ -130,7 +130,7 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- protected override void OnPaint(PaintEventArgs e) { - if ( !_themeManager.ThemingActive || !_themeManager.ActiveTheme.IsExtendable) + if (!_themeManager.ActiveAndExtended) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs index 20678be70..222ffa30f 100644 --- a/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs +++ b/mRemoteV1/UI/TaskDialog/frmTaskDialog.cs @@ -323,8 +323,7 @@ namespace mRemoteNG.UI.TaskDialog private void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; pnlButtons.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); pnlButtons.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index 2b1d054cd..d2c49b5d2 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -245,7 +245,7 @@ namespace mRemoteNG.UI.Window { if (!ThemeManager.getInstance().ThemingActive) return; base.ApplyTheme(); - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); pnlBottom.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index 31e6bd17d..ea30adcc9 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -28,8 +28,7 @@ namespace mRemoteNG.UI.Window if (ActiveDirectoryTree.Controls.Count < 1) return; if (!(ActiveDirectoryTree.Controls[0] is TreeView tv)) return; var tm = ThemeManager.getInstance(); - if (!tm.ThemingActive) return; - if (!tm.ActiveTheme.IsExtendable) return; + if (!tm.ActiveAndExtended) return; tv.BackColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Background"); tv.ForeColor = tm.ActiveTheme.ExtendedPalette.getColor("List_Item_Foreground"); } diff --git a/mRemoteV1/UI/Window/BaseWindow.cs b/mRemoteV1/UI/Window/BaseWindow.cs index 2a757f61b..8bbaf300f 100644 --- a/mRemoteV1/UI/Window/BaseWindow.cs +++ b/mRemoteV1/UI/Window/BaseWindow.cs @@ -32,8 +32,7 @@ namespace mRemoteNG.UI.Window internal void ApplyTheme() { _themeManager = ThemeManager.getInstance(); - if (!_themeManager.ThemingActive) return; - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } diff --git a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs index 3eee23a78..ad8f45edb 100644 --- a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs +++ b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs @@ -439,7 +439,7 @@ namespace mRemoteNG.UI.Window if (!ThemeManager.getInstance().ThemingActive) return; base.ApplyTheme(); - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; pnlCheck1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); pnlCheck1.ForeColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); pnlCheck2.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 1311076c3..9c79b119e 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -605,8 +605,7 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; _pGrid.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); _pGrid.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); _pGrid.ViewBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("List_Item_Background"); diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index f3d325840..48d7b6e6b 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -98,7 +98,7 @@ namespace mRemoteNG.UI.Window vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); vsToolStripExtender.SetStyle(olvConnections.ContextMenuStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; //Treelistview need to be manually themed olvConnections.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Background"); olvConnections.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Foreground"); diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 4a8dd5545..147679929 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -202,7 +202,7 @@ namespace mRemoteNG.UI.Window }; vsToolStripExtender.SetStyle(cmenTab, ThemeManager.getInstance().ActiveTheme.Version, ThemeManager.getInstance().ActiveTheme.Theme); - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; connDock.DockBackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Tab_Item_Background"); } diff --git a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs index e06bb33c2..90e317c20 100644 --- a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs +++ b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs @@ -58,9 +58,7 @@ namespace mRemoteNG.UI.Window #region Private Methods private new void ApplyTheme() { - if (!_themeManager.ThemingActive) return; - - if (!_themeManager.ActiveTheme.IsExtendable) return; + if (!_themeManager.ActiveAndExtended) return; lvErrorCollector.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); lvErrorCollector.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); @@ -223,7 +221,7 @@ namespace mRemoteNG.UI.Window break; case MessageClass.WarningMsg: pbError.Image = _display.ScaleImage(Resources.Warning); - if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) + if (_themeManager.ActiveAndExtended) { //Inverse colors for dramatic effect pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("WarningText_Foreground"); @@ -236,7 +234,7 @@ namespace mRemoteNG.UI.Window break; case MessageClass.ErrorMsg: pbError.Image = _display.ScaleImage(Resources._Error); - if (_themeManager.ThemingActive && _themeManager.ActiveTheme.IsExtendable) + if (_themeManager.ActiveAndExtended) { pnlErrorMsg.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Foreground"); pnlErrorMsg.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("ErrorText_Background"); diff --git a/mRemoteV1/UI/Window/ExternalToolsWindow.cs b/mRemoteV1/UI/Window/ExternalToolsWindow.cs index 3c96cd4ad..07a1e176e 100644 --- a/mRemoteV1/UI/Window/ExternalToolsWindow.cs +++ b/mRemoteV1/UI/Window/ExternalToolsWindow.cs @@ -20,7 +20,7 @@ namespace mRemoteNG.UI.Window public ExternalToolsWindow() { - InitializeComponent(); + InitializeComponent(); WindowType = WindowType.ExternalApps; DockPnl = new DockContent(); _themeManager = ThemeManager.getInstance(); @@ -58,7 +58,7 @@ namespace mRemoteNG.UI.Window TryToIntegrateColumnHeader.Text = Language.strTryToIntegrateColumnHeader; RunElevateHeader.Text = Language.strRunElevateHeader; ShowOnToolbarColumnHeader.Text = Language.strShowOnToolbarColumnHeader; - + TryToIntegrateCheckBox.Text = Language.strTryIntegrate; ShowOnToolbarCheckBox.Text = Language.strShowOnToolbar; RunElevatedCheckBox.Text = Language.strRunElevated; @@ -70,7 +70,7 @@ namespace mRemoteNG.UI.Window ArgumentsLabel.Text = Language.strLabelArguments; WorkingDirLabel.Text = Language.srtWorkingDirectory; OptionsLabel.Text = Language.strLabelOptions; - + WaitForExitCheckBox.Text = Language.strCheckboxWaitForExit; BrowseButton.Text = Language.strButtonBrowse; BrowseWorkingDir.Text = Language.strButtonBrowse; @@ -191,10 +191,10 @@ namespace mRemoteNG.UI.Window message = string.Format(Language.strConfirmDeleteExternalToolMultiple, _currentlySelectedExternalTools.Count); else return; - + if (MessageBox.Show(FrmMain.Default, message, "Question?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return; - + foreach (var externalTool in _currentlySelectedExternalTools) { Runtime.ExternalToolsService.ExternalTools.Remove(externalTool); @@ -247,7 +247,7 @@ namespace mRemoteNG.UI.Window var selectedTool = _currentlySelectedExternalTools.FirstOrDefault(); if (selectedTool == null) return; - + try { selectedTool.DisplayName = DisplayNameTextBox.Text; diff --git a/mRemoteV1/UI/Window/UpdateWindow.cs b/mRemoteV1/UI/Window/UpdateWindow.cs index de89acf98..060e93b38 100644 --- a/mRemoteV1/UI/Window/UpdateWindow.cs +++ b/mRemoteV1/UI/Window/UpdateWindow.cs @@ -44,8 +44,7 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (!ThemeManager.getInstance().ThemingActive) return; - if (!ThemeManager.getInstance().ActiveTheme.IsExtendable) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; base.ApplyTheme(); txtChangeLog.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); From c8d4a9a6717da971cba23a1b2bf3a5a87f179bf2 Mon Sep 17 00:00:00 2001 From: Faryan Rezagholi Date: Sun, 13 Jan 2019 01:30:23 +0100 Subject: [PATCH 120/157] Set focus to textbox instead of connecting, fixes #1271 --- mRemoteV1/UI/Controls/QuickConnectToolStrip.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index c1eab8e1b..a028a4dda 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -203,7 +203,7 @@ namespace mRemoteNG.UI.Controls private void btnQuickConnect_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { SetQuickConnectProtocol(e.ClickedItem.Text); - btnQuickConnect_ButtonClick(this, e); + _cmbQuickConnect.Focus(); } private void SetQuickConnectProtocol(string protocol) From 6bac9c24323b4ea5524e239bcb4111329c890ed4 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Tue, 15 Jan 2019 17:16:18 -0500 Subject: [PATCH 121/157] Disable AlwaysShowConnectionTabs functinoality This will not work with DPS currently. Reference https://github.com/dockpanelsuite/dockpanelsuite/issues/559 --- .../OptionsPages/TabsPanelsPage.Designer.cs | 41 ++++++++++--------- mRemoteV1/UI/Forms/frmMain.cs | 16 ++++---- mRemoteV1/UI/Window/ConnectionWindow.cs | 2 +- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs index d08cbd180..db575871b 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs @@ -32,8 +32,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void InitializeComponent() { this.chkAlwaysShowPanelTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); - this.chkAlwaysShowConnectionTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); - this.chkIdentifyQuickConnectTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); + this.chkAlwaysShowConnectionTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); + this.chkIdentifyQuickConnectTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); this.chkOpenNewTabRightOfSelected = new mRemoteNG.UI.Controls.Base.NGCheckBox(); this.chkAlwaysShowPanelSelectionDlg = new mRemoteNG.UI.Controls.Base.NGCheckBox(); this.chkShowLogonInfoOnTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox(); @@ -55,22 +55,23 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.chkAlwaysShowPanelTabs.TabIndex = 0; this.chkAlwaysShowPanelTabs.Text = "Always show panel tabs"; this.chkAlwaysShowPanelTabs.UseVisualStyleBackColor = true; - // - // chkAlwaysShowConnectionTabs - // - this.chkAlwaysShowConnectionTabs._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; - this.chkAlwaysShowConnectionTabs.AutoSize = true; + // + // chkAlwaysShowConnectionTabs + // + this.chkAlwaysShowConnectionTabs._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; + this.chkAlwaysShowConnectionTabs.AutoSize = true; this.chkAlwaysShowConnectionTabs.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.chkAlwaysShowConnectionTabs.Location = new System.Drawing.Point(3, 26); - this.chkAlwaysShowConnectionTabs.Name = "chkAlwaysShowConnectionTabs"; - this.chkAlwaysShowConnectionTabs.Size = new System.Drawing.Size(200, 17); - this.chkAlwaysShowConnectionTabs.TabIndex = 0; - this.chkAlwaysShowConnectionTabs.Text = "Always show connection tabs"; - this.chkAlwaysShowConnectionTabs.UseVisualStyleBackColor = true; - // - // chkIdentifyQuickConnectTabs - // - this.chkIdentifyQuickConnectTabs._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; + this.chkAlwaysShowConnectionTabs.Location = new System.Drawing.Point(3, 26); + this.chkAlwaysShowConnectionTabs.Name = "chkAlwaysShowConnectionTabs"; + this.chkAlwaysShowConnectionTabs.Size = new System.Drawing.Size(178, 17); + this.chkAlwaysShowConnectionTabs.TabIndex = 0; + this.chkAlwaysShowConnectionTabs.Text = "Always show connection tabs"; + this.chkAlwaysShowConnectionTabs.UseVisualStyleBackColor = true; + this.chkAlwaysShowConnectionTabs.Visible = false; + // + // chkIdentifyQuickConnectTabs + // + this.chkIdentifyQuickConnectTabs._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; this.chkIdentifyQuickConnectTabs.AutoSize = true; this.chkIdentifyQuickConnectTabs.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.chkIdentifyQuickConnectTabs.Location = new System.Drawing.Point(3, 118); @@ -155,6 +156,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages // // txtBoxPanelName // + this.txtBoxPanelName.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtBoxPanelName.Location = new System.Drawing.Point(43, 246); this.txtBoxPanelName.Name = "txtBoxPanelName"; this.txtBoxPanelName.Size = new System.Drawing.Size(213, 22); @@ -177,14 +179,13 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.Controls.Add(this.txtBoxPanelName); this.Controls.Add(this.chkCreateEmptyPanelOnStart); this.Controls.Add(this.chkAlwaysShowPanelTabs); - this.Controls.Add(this.chkAlwaysShowConnectionTabs); - this.Controls.Add(this.chkIdentifyQuickConnectTabs); + this.Controls.Add(this.chkAlwaysShowConnectionTabs); + this.Controls.Add(this.chkIdentifyQuickConnectTabs); this.Controls.Add(this.chkOpenNewTabRightOfSelected); this.Controls.Add(this.chkAlwaysShowPanelSelectionDlg); this.Controls.Add(this.chkShowLogonInfoOnTabs); this.Controls.Add(this.chkDoubleClickClosesTab); this.Controls.Add(this.chkShowProtocolOnTabs); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "TabsPanelsPage"; this.Size = new System.Drawing.Size(610, 490); this.ResumeLayout(false); diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 793977c91..89aa1b86b 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -28,7 +28,6 @@ using System.Text; using System.Windows.Forms; using mRemoteNG.UI.Panels; using WeifenLuo.WinFormsUI.Docking; -using TabControl = Crownwood.Magic.Controls.TabControl; // ReSharper disable MemberCanBePrivate.Global @@ -604,7 +603,9 @@ namespace mRemoteNG.UI.Forms newDocumentStyle = nonConnectionPanelCount == 0 ? DocumentStyle.DockingSdi : DocumentStyle.DockingWindow; } - foreach (var dockContent in pnlDock.Documents) + // TODO: See if we can get this to work with DPS +#if false + foreach (var dockContent in pnlDock.Documents) { var document = (DockContent)dockContent; if (document is ConnectionWindow) @@ -620,14 +621,15 @@ namespace mRemoteNG.UI.Forms } } } +#endif if (pnlDock.DocumentStyle == newDocumentStyle) return; pnlDock.DocumentStyle = newDocumentStyle; pnlDock.Size = new Size(1, 1); } - #endregion +#endregion - #region Screen Stuff +#region Screen Stuff public void SetDefaultLayout() { pnlDock.Visible = false; @@ -648,16 +650,16 @@ namespace mRemoteNG.UI.Forms pnlDock.Visible = true; } - #endregion +#endregion - #region Events +#region Events public delegate void ClipboardchangeEventHandler(); public static event ClipboardchangeEventHandler ClipboardChanged { add => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Combine(_clipboardChangedEvent, value); remove => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Remove(_clipboardChangedEvent, value); } - #endregion +#endregion private void ViewMenu_Opening(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index d477e56e8..6d8e7b7cb 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -130,7 +130,7 @@ namespace mRemoteNG.UI.Window TabPageContextMenuStrip = cmenTab }; - if (Settings.Default.AlwaysShowConnectionTabs == false) + //if (Settings.Default.AlwaysShowConnectionTabs == false) // TODO: See if we can make this work with DPS... //TabController.HideTabsMode = TabControl.HideTabsModes.HideAlways; From 96af6b252a0417e95ba00cba11d0e3572b8b027c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 16 Jan 2019 11:18:34 -0500 Subject: [PATCH 122/157] themeing fix & update comments --- mRemoteV1/UI/Controls/IPTextBox.cs | 61 +++++++++++++----------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/mRemoteV1/UI/Controls/IPTextBox.cs b/mRemoteV1/UI/Controls/IPTextBox.cs index 3c0f164bb..055a61aa9 100644 --- a/mRemoteV1/UI/Controls/IPTextBox.cs +++ b/mRemoteV1/UI/Controls/IPTextBox.cs @@ -8,11 +8,9 @@ using mRemoteNG.Themes; namespace mRemoteNG.UI.Controls { - /** \class IPTextBox - * \brief An IP Address Box - * + /* class IPTextBox + * An IP Address Box * A TextBox that only allows entry of a valid ip address - ** */ public class IPTextBox: UserControl { @@ -27,7 +25,7 @@ namespace mRemoteNG.UI.Controls private ToolTip toolTip1; private System.ComponentModel.IContainer components; - /** Sets and Gets the tooltiptext on toolTip1 */ + /* Sets and Gets the tooltiptext on toolTip1 */ public string ToolTipText { get => toolTip1.GetToolTip(Octet1); @@ -43,7 +41,7 @@ namespace mRemoteNG.UI.Controls } } - /** Set or Get the string that represents the value in the box */ + /* Set or Get the string that represents the value in the box */ public override string Text { get => Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text; @@ -82,7 +80,7 @@ namespace mRemoteNG.UI.Controls private void ApplyTheme() { - if (ThemeManager.getInstance().ActiveAndExtended) return; + if (!ThemeManager.getInstance().ActiveAndExtended) return; panel1.BackColor = ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } protected override void Dispose( bool disposing ) @@ -225,16 +223,15 @@ namespace mRemoteNG.UI.Controls this.ResumeLayout(false); } - #endregion + #endregion - /** - * \ifnot hide_events + /* IsValid(string inString) * Checks that a string passed in resolves to an integer value between 0 and 255 - * \param inString The string passed in for testing - * \return True if the string is between 0 and 255 inclusively, false otherwise - * \endif - * */ - private static bool IsValid(string inString) + * param inString: The string passed in for testing + * return: True if the string is between 0 and 255 inclusively, false otherwise + * endif + */ + private static bool IsValid(string inString) { try { @@ -251,10 +248,9 @@ namespace mRemoteNG.UI.Controls } } - /// \ifnot hide_events - /// Performs KeyPress analysis and handling to ensure a valid ip octet is - /// being entered in Box1. - /// \endif + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box1. + */ private void Box1_KeyPress(object sender, KeyPressEventArgs e) { //Only Accept a '.', a numeral, or backspace @@ -296,14 +292,13 @@ namespace mRemoteNG.UI.Controls e.Handled = true; } - /// \ifnot hide_events - /// Performs KeyPress analysis and handling to ensure a valid ip octet is - /// being entered in Box2. - /// \endif + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box2. + */ private void Box2_KeyPress(object sender, KeyPressEventArgs e) { //Similar to Box1_KeyPress but in special case for backspace moves cursor - //to the previouse box (Box1) + //to the previous box (Box1) if(e.KeyChar.ToString() == "." || char.IsDigit(e.KeyChar) || e.KeyChar == 8) { if(e.KeyChar.ToString() == ".") @@ -341,10 +336,9 @@ namespace mRemoteNG.UI.Controls } - /// \ifnot hide_events - /// Performs KeyPress analysis and handling to ensure a valid ip octet is - /// being entered in Box3. - /// \endif + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box3. + */ private void Box3_KeyPress(object sender, KeyPressEventArgs e) { //Identical to Box2_KeyPress except that previous box is Box2 and @@ -385,10 +379,9 @@ namespace mRemoteNG.UI.Controls e.Handled = true; } - /// \ifnot hide_events - /// Performs KeyPress analysis and handling to ensure a valid ip octet is - /// being entered in Box4. - /// \endif + /* Performs KeyPress analysis and handling to ensure a valid ip octet is + * being entered in Box4. + */ private void Box4_KeyPress(object sender, KeyPressEventArgs e) { //Similar to Box3 but ignores the '.' character and does not advance @@ -412,9 +405,7 @@ namespace mRemoteNG.UI.Controls e.Handled = true; } - /// \ifnot hide_events - /// Selects All text in a box for overwriting upon entering the box - /// \endif + // Selects All text in a box for overwriting upon entering the box private void Box_Enter(object sender, EventArgs e) { var tb = (TextBox) sender; From 401a518f0f2e5ad47b1a979b76070f04e6b81b5c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 16 Jan 2019 22:35:08 -0500 Subject: [PATCH 123/157] Theme page label text update All theme changes require a restart. --- mRemoteV1/Resources/Language/Language.Designer.cs | 4 ++-- mRemoteV1/Resources/Language/Language.resx | 2 +- mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mRemoteV1/Resources/Language/Language.Designer.cs b/mRemoteV1/Resources/Language/Language.Designer.cs index 835359b95..f3d1e574e 100644 --- a/mRemoteV1/Resources/Language/Language.Designer.cs +++ b/mRemoteV1/Resources/Language/Language.Designer.cs @@ -19,7 +19,7 @@ namespace mRemoteNG { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Language { @@ -4435,7 +4435,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Warning: Restart is required to disable the themes or to completely apply a new one. + /// Looks up a localized string similar to Warning: Restart is required to commit any theme configuration change.. /// internal static string strOptionsThemeThemeChaangeWarning { get { diff --git a/mRemoteV1/Resources/Language/Language.resx b/mRemoteV1/Resources/Language/Language.resx index 882577451..e4e580242 100644 --- a/mRemoteV1/Resources/Language/Language.resx +++ b/mRemoteV1/Resources/Language/Language.resx @@ -2585,7 +2585,7 @@ This page will walk you through the process of upgrading your connections file o Type the new theme name - Warning: Restart is required to disable the themes or to completely apply a new one + Warning: Restart is required to commit any theme configuration change. No themes are loaded, check that the default mRemoteNG themes exist in the 'themes' folder diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs index 7fbfaee29..db0215ecd 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.Designer.cs @@ -134,8 +134,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages this.labelRestart.Name = "labelRestart"; this.labelRestart.Size = new System.Drawing.Size(598, 28); this.labelRestart.TabIndex = 4; - this.labelRestart.Text = "Warning: Restart is required to disable the themes or to completely apply a new o" + - "ne"; + this.labelRestart.Text = "Warning: Restart is required..."; this.labelRestart.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // tableLayoutPanel1 From 968471ec4a70c5a7256d531ce45f84a7c58d43d1 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 16 Jan 2019 22:38:31 -0500 Subject: [PATCH 124/157] white space clean up --- mRemoteV1/App/NativeMethods.cs | 64 +++++++++++----------- mRemoteV1/Connection/Protocol/PuttyBase.cs | 56 +++++++++---------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/mRemoteV1/App/NativeMethods.cs b/mRemoteV1/App/NativeMethods.cs index dd1df64af..45b2ba36e 100644 --- a/mRemoteV1/App/NativeMethods.cs +++ b/mRemoteV1/App/NativeMethods.cs @@ -14,31 +14,31 @@ namespace mRemoteNG.App #region Functions [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool AppendMenu(IntPtr hMenu, int uFlags, IntPtr uIDNewItem, string lpNewItem); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr CreatePopupMenu(); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr GetForegroundWindow(); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, IntPtr uIDNewItem, string lpNewItem); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int IsIconic(IntPtr hWnd); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool MoveWindow(IntPtr hWnd, int x, int y, int cx, int cy, bool repaint); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam); @@ -62,19 +62,19 @@ namespace mRemoteNG.App [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool SetForegroundWindow(IntPtr hWnd); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool SetMenuItemBitmaps(IntPtr hMenu, int uPosition, int uFlags, IntPtr hBitmapUnchecked, IntPtr hBitmapChecked); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int ShowWindow(IntPtr hWnd, int nCmdShow); - + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr WindowFromPoint(Point point); @@ -138,27 +138,27 @@ namespace mRemoteNG.App { return wLow | wHigh << 16; } - + public static int MAKELPARAM(ref int wLow, ref int wHigh) { return MAKELONG(wLow, wHigh); } - + public static int LOWORD(int value) { return value & 0xFFFF; } - + public static int LOWORD(IntPtr value) { return LOWORD(value.ToInt32()); } - + public static int HIWORD(int value) { return value >> 16; } - + public static int HIWORD(IntPtr value) { return HIWORD(value.ToInt32()); @@ -270,12 +270,12 @@ namespace mRemoteNG.App public const int SWP_NOCLIENTMOVE = 0x1000; /// - /// Prevents generation of the WM_SYNCPAINT message. + /// Prevents generation of the WM_SYNCPAINT message. /// public const int SWP_DEFERERASE = 0x2000; /// - /// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. + /// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. /// public const int SWP_ASYNCWINDOWPOS = 0x4000; @@ -304,8 +304,8 @@ namespace mRemoteNG.App /// /// Sent to both the window being activated and the window being deactivated. - /// If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the - /// top-level window being deactivated, then to the window procedure of the top-level window being activated. If the + /// If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the + /// top-level window being deactivated, then to the window procedure of the top-level window being activated. If the /// windows use different input queues, the message is sent asynchronously, so the window is activated immediately. /// public const int WA_CLICKACTIVE = 0x2; @@ -333,7 +333,7 @@ namespace mRemoteNG.App public const int WM_SETTEXT = 0xC; /// - /// Copies the text that corresponds to a window into a buffer provided by the caller. + /// Copies the text that corresponds to a window into a buffer provided by the caller. /// public const int WM_GETTEXT = 0xD; @@ -348,7 +348,7 @@ namespace mRemoteNG.App public const int WM_ACTIVATEAPP = 0x1C; /// - /// Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured. + /// Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured. /// public const int WM_SETCURSOR = 0x20; @@ -373,12 +373,12 @@ namespace mRemoteNG.App public const int WM_WINDOWPOSCHANGED = 0x47; /// - /// Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed. + /// Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed. /// public const int WM_KEYDOWN = 0x100; /// - /// Posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, or a keyboard key that is pressed when a window has the keyboard focus. + /// Posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, or a keyboard key that is pressed when a window has the keyboard focus. /// public const int WM_KEYUP = 0x101; @@ -433,7 +433,7 @@ namespace mRemoteNG.App public const int WM_MBUTTONUP = 0x208; /// - /// Posted when the user presses the first or second X button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse. + /// Posted when the user presses the first or second X button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse. /// public const int WM_XBUTTONDOWN = 0x20B; @@ -448,22 +448,22 @@ namespace mRemoteNG.App public const int WM_PARENTNOTIFY = 0x210; /// - /// Sent one time to a window after it enters the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns. + /// Sent one time to a window after it enters the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns. /// public const int WM_ENTERSIZEMOVE = 0x231; /// - /// Sent one time to a window, after it has exited the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns. + /// Sent one time to a window, after it has exited the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns. /// public const int WM_EXITSIZEMOVE = 0x232; /// - /// Sent to the first window in the clipboard viewer chain when the content of the clipboard changes. This enables a clipboard viewer window to display the new content of the clipboard. + /// Sent to the first window in the clipboard viewer chain when the content of the clipboard changes. This enables a clipboard viewer window to display the new content of the clipboard. /// public const int WM_DRAWCLIPBOARD = 0x308; /// - /// Sent to the first window in the clipboard viewer chain when a window is being removed from the chain. + /// Sent to the first window in the clipboard viewer chain when a window is being removed from the chain. /// public const int WM_CHANGECBCHAIN = 0x30D; #endregion diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index ed93e4654..cfe716282 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -15,7 +15,7 @@ using System.Windows.Forms; namespace mRemoteNG.Connection.Protocol { public class PuttyBase : ProtocolBase - { + { private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID private bool _isPuttyNg; private readonly DisplayProperties _display = new DisplayProperties(); @@ -45,7 +45,7 @@ namespace mRemoteNG.Connection.Protocol Event_Closed(this); } #endregion - + #region Public Methods public override bool Connect() { @@ -65,11 +65,11 @@ namespace mRemoteNG.Connection.Protocol var arguments = new CommandLineArguments {EscapeForShell = false}; arguments.Add("-load", InterfaceControl.Info.PuttySession); - + if (!(InterfaceControl.Info is PuttySessionInfo)) { arguments.Add("-" + PuttyProtocol); - + if (PuttyProtocol == Putty_Protocol.ssh) { var username = ""; @@ -92,7 +92,7 @@ namespace mRemoteNG.Connection.Protocol break; } } - + if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password)) { password = InterfaceControl.Info.Password; @@ -105,9 +105,9 @@ namespace mRemoteNG.Connection.Protocol password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); } } - + arguments.Add("-" + (int)PuttySSHVersion); - + if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials)) { if (!string.IsNullOrEmpty(username)) @@ -120,24 +120,24 @@ namespace mRemoteNG.Connection.Protocol } } } - + arguments.Add("-P", InterfaceControl.Info.Port.ToString()); arguments.Add(InterfaceControl.Info.Hostname); } - + if (_isPuttyNg) { arguments.Add("-hwndparent", InterfaceControl.Handle.ToString()); } - + PuttyProcess.StartInfo.Arguments = arguments.ToString(); - + PuttyProcess.EnableRaisingEvents = true; PuttyProcess.Exited += ProcessExited; - + PuttyProcess.Start(); PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); - + var startTicks = Environment.TickCount; while (PuttyHandle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) { @@ -156,17 +156,17 @@ namespace mRemoteNG.Connection.Protocol Thread.Sleep(0); } } - + if (!_isPuttyNg) { NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle); } - + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyHandle, PuttyHandle), true); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle), true); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyParentHandle, InterfaceControl.Parent.Handle), true); - + Resize(this, new EventArgs()); base.Connect(); return true; @@ -177,7 +177,7 @@ namespace mRemoteNG.Connection.Protocol return false; } } - + public override void Focus() { try @@ -189,7 +189,7 @@ namespace mRemoteNG.Connection.Protocol Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyFocusFailed + Environment.NewLine + ex.Message, true); } } - + public override void Resize(object sender, EventArgs e) { try @@ -203,11 +203,11 @@ namespace mRemoteNG.Connection.Protocol var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); NativeMethods.MoveWindow( - PuttyHandle, - -scaledFrameBorderWidth, - -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), - InterfaceControl.Width + scaledFrameBorderWidth * 2, - InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, + PuttyHandle, + -scaledFrameBorderWidth, + -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), + InterfaceControl.Width + scaledFrameBorderWidth * 2, + InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, true); } catch (Exception ex) @@ -215,7 +215,7 @@ namespace mRemoteNG.Connection.Protocol Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyResizeFailed + Environment.NewLine + ex.Message, true); } } - + public override void Close() { try @@ -229,7 +229,7 @@ namespace mRemoteNG.Connection.Protocol { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyKillFailed + Environment.NewLine + ex.Message, true); } - + try { Console.WriteLine(@"Skipping Dispose for now!"); @@ -242,10 +242,10 @@ namespace mRemoteNG.Connection.Protocol { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + ex.Message, true); } - + base.Close(); } - + public void ShowSettingsDialog() { try @@ -259,7 +259,7 @@ namespace mRemoteNG.Connection.Protocol } } #endregion - + #region Enums protected enum Putty_Protocol From 1f700f7842496315d69a352422fc7394d90fa5a2 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 21 Jan 2019 23:29:26 -0500 Subject: [PATCH 125/157] Fix for #1257 CreateGraphics was the function being disposed in the using, the form handle was still floating around. Suggestion to optimize the dpi function --- .../UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs index d6fdc4812..26fd63ce6 100644 --- a/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs +++ b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs @@ -11,12 +11,16 @@ namespace mRemoteNG.UI.GraphicsUtilities // Dpi of a 'normal' definition screen private const int BaselineDpi = 96; + public SizeF GetResolutionScalingFactor() { - using (var g = new Form().CreateGraphics()) - { - return new SizeF(g.DpiX / BaselineDpi, g.DpiY / BaselineDpi); - } + //This method could be optimized, as it is called for every control / subcontrol + //and causes overhead for 100s in the options page + using (var f = new Form()) + { + var g = f.CreateGraphics(); + return new SizeF(g.DpiX / BaselineDpi, g.DpiY / BaselineDpi); + } } } } From 0699e895fdce2f23e7b3590228aea6109c840bdd Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Mon, 21 Jan 2019 23:49:35 -0500 Subject: [PATCH 126/157] Fix for #1249 screenshot X Corrected casting for disposing the form --- mRemoteV1/UI/Window/ScreenshotManagerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs b/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs index eab5589dc..d38a6c778 100644 --- a/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs +++ b/mRemoteV1/UI/Window/ScreenshotManagerWindow.cs @@ -295,7 +295,7 @@ namespace mRemoteNG.UI.Window { try { - ((PictureBox)sender).Parent.Dispose(); + ((PictureBox)((Button)sender).Parent).Dispose(); } catch (Exception ex) { From c93deb7696d7735666977bfafc5d1eae853348a5 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 22 Jan 2019 15:44:10 -0500 Subject: [PATCH 127/157] Screenshot method change Some screenshots were blank because DrawToBitmap uses the tab drawing graphics, New method uses screen buffer that brings the pixels from the final screen render. --- mRemoteV1/Tools/MiscTools.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index ff66d8676..03722aa2d 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Drawing; +using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Security; @@ -90,8 +91,9 @@ namespace mRemoteNG.Tools var ac = sender.ActiveControl; if (ac != null) { - var bmp = new Bitmap(ac.Width, ac.Height); - ac.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height)); + var bmp = new Bitmap(ac.Width, ac.Height, PixelFormat.Format32bppRgb); + Graphics g = Graphics.FromImage(bmp); + g.CopyFromScreen(ac.PointToScreen(Point.Empty), Point.Empty , bmp.Size, CopyPixelOperation.SourceCopy); return bmp; } } From a6cd5656f84f5cdc72cacedc7a13fc720210dcbe Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Wed, 23 Jan 2019 21:05:15 -0500 Subject: [PATCH 128/157] no borders for puttyng integrated processes fixes #1265 --- mRemoteV1/Connection/Protocol/PuttyBase.cs | 27 ++++++++++++--------- mRemoteV1/Resources/PuTTYNG.exe | Bin 707952 -> 716144 bytes 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index cfe716282..1b26a8024 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -195,20 +195,25 @@ namespace mRemoteNG.Connection.Protocol try { if (InterfaceControl.Size == Size.Empty) - { return; - } - var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height); - var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); + if (_isPuttyNg) + { + // PuTTYNG 0.70.0.1 and later doesn't have any window borders + NativeMethods.MoveWindow(PuttyHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true); + } + else + { + var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height); + var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); - NativeMethods.MoveWindow( - PuttyHandle, - -scaledFrameBorderWidth, - -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), - InterfaceControl.Width + scaledFrameBorderWidth * 2, - InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, - true); + NativeMethods.MoveWindow(PuttyHandle, -scaledFrameBorderWidth, + -(SystemInformation.CaptionHeight + scaledFrameBorderHeight), + InterfaceControl.Width + scaledFrameBorderWidth * 2, + InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, + true); + } + } catch (Exception ex) { diff --git a/mRemoteV1/Resources/PuTTYNG.exe b/mRemoteV1/Resources/PuTTYNG.exe index ca9cea4873b39f3ec2e425b11cdfd26ac4503113..50ba7ca21441dd9219189da3e7f8e1db20a244e5 100644 GIT binary patch literal 716144 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%0Dru`Nmo6M>dF$2N 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

wAa} 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 eQVXFR7F`sXy3 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

c*0!Z`plLUd6?TW;23`25&cOx4 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 z zt(-5Pd&`D;X_-ru$gCp#f(fU{Iu{ZSi?aqn4bpg?#W%W@JQIM;V-=)hd(cclG%D`s zWrC<5yvDlWMa4@~HbxIRn!n2+t=BYUVBZQT$6L@qm=NC8yf{V9=C4dGcX~?S@|56! z5sx4JjvHQ@!l-G{PvP)Ce%nn)L!FUN8-Vu^$m=*2ny!5s z!-9-V=`FTo4k!9%s>JykhzGG>%tQsY?PDQr1#3OAk^C;5me11p4O~<`{}1iTUR}V~ zyM#3A%U9!(Fx2&4%_l@h?B5o04Eh7P#N3M==lsLFPER#apU*Y05?G-4o>p+gte8}-n?T9qqP z1ILYQAPUMwKO<;w%NGpqsSXLaW)n(npL?o7Q}q|wr{??rQvj9UdoTMqG_- zOe<0eQ?zvgaLCcV%i67!ENGJ{Hjdo&i4R;R8Avd662w7&6 zNCwCd3Ew7j`jtD`_0R#8#qDYPHE@xw5>(|aJ)%uqw%w><6%uz6f;W4X;Znj{==jBv zfcidUiH-HAdXEB+4QDJXH{iIZEh|su=WJ70`uY@t=Pu(`jJ=Xl`1&=pWIv^*!8P>seuXMr^?M* z1|?h0G>DF?Ch{09_AS?->L0zt6WK03_`H}V4+787`q<*V`4@O%D>=K};qx-zJJ_&dm6B zeTplYm^_n~OtcQA^euqzL2-dRjaB0uJcgAdk71?DxGJ;}AZS@o4PGu(zm)-Tzh0}Z zpv~S7WFBG8geY&UIJ4s#KXQ_Po(6BiTVhp47Ul{&olKXL|G@eX{aAT^9299m-AL)nLgPliDlJ5D{ESeM)ULQos5i+9JP=zdpk2cyE~y*zDeJX0I~%5RVo4 znlzM?yRz2KeIL2uZlj6IJZ)_5a-c84huN+FcG6>Rvll9Dne6qn&Xck?cvBmXH)q0$ zJ7r7!tn~sQ0d!4Wq zVtWsr7|)9DYx#&p43Ll50gEcI=%UgYmZV!)$KLu(0231_Odi?&3pZv6y%Pg48MLektLOlOv+wHB?BHE zKr&T(A#g~bu>feNfqHWjug{NXg;^l0slQl2#!_p$1N8N-gDA@41g=Y{T*fy%S?7pk zAj7KMdUkeAdSnyO>YFGH{RZZdAF=ySTYYEMM(!X@^`9d%Qk;fi9QGsGe6;W)C=()} z?W?#!&w40VjVgskv1N-`GrA@S*PCr~z3f7>J>M64?|icP<$pd52C|?JN)m_bKZs8q2H%uVxIf+OuM`XGM`iJ76QA{jzN$V7X*t z8}Wq`Ps-6*H0=48sSdpaJ}jvUT%{lfLc46HA-q*Z`-o*TQ`^sXn4>O~^W^!d%ZAlf zwx4UL-|o`v4clzvOc9fK+P-CX)8$znASkuepn<~VIyWg#J2xp$JJ*t@bzF^n#+7(d zpTH8GT4Zn@8#XJj*ln-wU$nrjVwyuHGAl4Hzp~O-N}$>6X#Cb--ZCri%T``2A9~t; zMYyt8UjFrzdFfV4?+t{ZSaR(trzCGR04W3@>eCm80HTgu0HB=3e+kD7f>n&D>Oy&@ zKCV+zgrgc^7h+oCP-1ppayef&KGHLQxC%kspnV^&tePPEY=d+WL!X)Zv{PJH59HI^jgj z-wV4Q{iQRdaWoT+Lw>QF=YVuKrEeV3jz%vNu`vV795reiu~>)LEtVsX)26y)CIE;( zTD6)+r7Z!uTAH2u-&z7PtmD7sfB;Y$Giy`}`(a(*_{f9-UVNzx+i4BkS_j#dKuIL2 zE)xrKL&Ql$v3}hucMa88vSxj%ObXtvAU-LUyM!<^LrW38FoxU@$kP8CymVb%;@W^( z_XBaYwwk|UbU-)CfH?STj{XFS^XXOhlYuolBwZi+k967TEq1z`am7A?JF!Afn|G`X zK3l-F(fSOi$6&8H03ZTlVTv>F6o4LayD{6l&>wkQ$VC2G;PnC*7F5hL)k2KDgpqT) z5;ZQ|9_iMCJ;mC;gh(%D3(25e@kT2DGSyo$!9<-~F^}=D2^AI}7v+hC7$FbP3LoMM zLH|=HX6ya95U&bzgH6%6%Xn#a{k&?`42qcA6$o%92oVMnQ(O{k<=E#h6BSh1N@t4@{lef379KeaqX3y_T1Om40olv<@nS^!p-F2AT- zx#X8EV>sr3NeBG*<&XQBcxo_?Pa6eXO2;yEY@-;K95r$ z>adrvPra$bl5MQoK$yTdwT1wi2IH&IKa;LmYD~9@g3B=8gx@h4DjPb*CNS zC!!>N$fa8ChzaU?LiDYiO|88mcVZ17$*aGpS`}d1qehK98+cGA^aYI2)N6w91splB zRl@{-{cg53jM#96^O3e*zNX@6giWX{xJN?MK5Hxgr)rLzeL|2q+ucoNDh0Z2uvTCvCm9cm!z z5&Z$|N`j}Vd-MlIc-O0L(BO*yb4vL zBfQCo*{W1WxRMbyDvt=V)<(OnTq=tQX(4QM>s(=V8STKq>M!La+1SUG+e*Y=qCLp! zDR#qYSrU?&%V8TT)u%{e2Y}SxEz3FE#L$hW?L9y*!fw5js-Kb++Fjb$JoRdC!&Umy z;BwZIHQm^8t@(!4tz~7dh_oosqfx&|Yiaf}nw8zPB6yl0c9UuGv(4UAyar$G#dYn# zZn)rjy&LY7=iqC+v$z+ry0CMt>|LM`Gg#Lm&E-O}R~#-xm$(oLj3IatQ!%IAnND*@`DxT|Fu z$W&cZk)2ekgb2JiaiGO9v#ciZq-+5ky8P-9wgFrE(bfZY?WOTJ+$zjm94`Zu+`$N}v(Gi3gir%IgBUSw1zu4Nx}!Gcw* zCw2%WisCySo=0kIe0&}jtwb+2m~GuhXhI8ugCmzsw`cMw#M86fr`4iB5gec-n&NsR zK3D;w$Fc;x=pqT#AQuf9)RQpdOXtx>1)mvSNt_X*a5kw>AbwW{H+ub2slnpzhzNup=x%{mXV z-7qflXPsPaCpV-C=}8Ukj-H(>IV#B^I@b8a8O*V*m>k=1GM*vs?J-1l5>;w$BA4ws zS54&e|D)~Q5Tosgokc23=wid?;)hIK9 zH3^9)fgBEl_Ce9MYHhvL=fPjK^#X`u!YzO|#9C3jYwH=u3o6AR$h_aR&kRVP%YX0Z zGv~}cd#`=pd+oK?T6^tqZa71jFV+J;l0~?rR|Zq545lDA2lQtx0aM6Ek4KJr$noA{ zdQe$8{{E|>9@P2UgX)z1ER*Yg^JmG!K5$G_5Ss{PFvmtFIC8CXY)8IzIu6=F|H2WO zj+{7hfe4F#1+`Eb62%C0F*I^px3#2?s~y^Nkm(xN`i!|Q2z!c;3W~rsFfXjX|4=Sc z-OU@X9ORHcWdFoe7#&&!EpP9if+A#&w5TCt|5 z5!*bYz_iiRP(DCi0oK?AQc9c~Dn1`;RUZ~h)WliHUF>i#8*#~L7Xe`G#IR7Ud~Q^q znAaSz&X(Mi$v<1l;-g=p-u|jja~RupI@Yg1Na2i~~f%^oAKB)@9{4IMpTZC3yLt*7}1!8TZb!68=R^89T_XqoXR zw#*gRsg^+sezu;>AY5$F+by?HD)3`F92LCj=7{7Bv_P85?3+0uQ!z~Jt*EoEB!|$E zTb-Pz*l%6Vhq;?3DESO5HmT7V6}vR^IY$RWdq;ACQJ%SgD@HHL!Zjcr|5@y5SBKNF z;V>JCuh%YEYy6jkPvgG^NN!#@x30h1ee?ZXP*UyL%%8QtMB3d5d5w_AnB_A<3=gif z5TT__uQT0xfl2*`~VEfJ1WN zL9PMl0A*RLCqlEfaN9zdYg3oWM^3D}1Bfu!_S`7n?pXI-@(u6;zKN%_>baCr$y3XW zEJ-RaJSb>Y+u`B7p!IhG&DecJWZ+SSk{8ii5OoEV7Ca1oW7+ML(pYwvdf!d)sH8Oo z(mwX!1H?+9F{G`g!aRZDa*xnohJlM>(8J>A30&?H&%13;uU_hq&zO8RSj+fR7v#0! zXs}jZm};iua_p$f7;DURGx7X$eUZ^&Z)nNg0y+oY6D?}YY55M6ev!f49q7Go@j@F^O62urqL&3+c6~?^+{mIKjP2{Sw|;R>+xg((91g;a(VlXe!(V-G$Z{D26_;`)p^>Ezb` zB(&~*E+XyfeBZ(O95`bw_$?Ps#=*^bTK6Ui++4CJJg(`RFXd*;|Az-vj^85zqXMsJ zE1wmYDz3iyJ8X;WFh*g%z_5MZcf#k{)nDTqD#QK#!G*89Y8j*K!1zC*!2-`mMN5L4 z|7u)DjVE46sa0!b&SJ3aKyg7RHKWECU(dfeO8<7aw(?TRQdP$6)88A{7auf8u6r`B zD?s%z?ZutlJ`f9Pf1FCz-_!cy==r%)ZBUaRoBUPyBqnH085@*`OBE)Ji>T6125};q zH3fm1{I=4tbB_PK)*?Pvs4P3)AFMsq;TjHoGqtoVSyMoWp7mYdqtfn9qO|S~J4-&J zizL3*J(x7fC45rQdW-o6jYh$!fD||WKIqD<$#d4^`fCbWCt;E{R)f;{;{al8STzfm z!qhqYgVyh5)-LwaNDbE3Au>sP#(5+KSJDyZ5;07KdSj~9q1nFyz}z8A?IAXNr%)aJ z&{3`Hi%fBN+cXN-Gj(tsrH{`iYIrcMeT9B#L^xBc+ziBARJrs+BaNCOb8|TR3OtRP zV*I1SiHY6{O;A}ngEL#(jG9sk!N7CGM@ePIn$wB`Z)htYA}f1Xl=^5jrvU|snI!(z~IP`I%~NE7=<#*Vv9XyRygBI z=4PPA#pQQo)nK8+1;BZUThu^Qp_62zrNsh-lNOkRe$0u_rP0lr9P_+$W%xDk^>l7| z*n>F!xha{5Raf4Rr+KFg3ozxY@712M*@<<*nhDx-6`6&Wao&n4nXi5V!cZV2OSX>q zP|`$8=vZCP#aH@K>NI7xn&eqwO=ZkmqpIj&C*!okUA{6tDN9D7L%bQ?i7zNNiqHU1}lD|^|%E0oN zelhP9ylsq-ecYA>x4G`DaQuqrQ=Z^m6^=fhRllil{DWudZz~+H@_2t&;b`Ys%kwc0 z>ATRN)0g-h7+%Yu%8@}~=PWiKWnR5^sF;m)Ztfd!f|G3WrBQ!5*}P0Bpe$|O)Z)wq zftMp5?YX|@UI?a%#fg)&b(O`g1%dv^kh>Nb&r}QPl!B+~z6Hk2Vpr;Wfzeu=*}O`n zwZQCZ5YPpN>w?TFR?=C;3%gkZG#;E7-ry>**Q}YIE38%G9VZ zRCFk_Sm(quZd~)Z*X)t9EGYEoPE+I9XAcG9p>mrCd(kbd}h4RVlT1no4x83 zSTXmRnQwOQylIr(iFOpOb}W{TO*mJ$WNUv?_nw<_Y=FXT{|1s3a|Kqo+@(N8hnADv zWNE|y2i;O2q#hs9QO3fzxGDXuQd-neK@AG@!+CAK=Kd`0xrxQ;@^_aB*0dW(?O69| zt8%GQ*f}rIudVux)c-T|hF0B*i!PE)Xs)@VJ9(_^{b~fJ%RX58c7==8BmX2b1KUf! zQmT=z=jIb(VM+_Es>LWl?^W;tGC2xwOm^v;-4Iu~aLu{yAbKmeaC&RZw*$|p5vHxY zT8hnBq#mW1W=54HBQVfjh?j8ci|UefZpK1xlhm^$$&EQxjv8=@GEhbpiV`S@tJt$Rz3sogjk=*gUhJca9{XV*W_{C2#UQ^@LQ2P9p3d08fmR2qGdV zAOknM+hh%l%vFnISw22bMx#tZ%W}{I;0CKha4VbEAEjny>*!D;yI|9rbVmwTzI7h0KH z5M6#zv>kA_`ps%rpxWJfG6oR1$}ssO;U=7SrrO~^`J$;hYDKlD$2Bxr?drSMWD)GSJ4;qR`y-9_B*0uI>qB6f(DV5@IM{ z>*?`!p3B6~hBsGSzc1p4k;iuQu5>S5F`!h;i3y+c?{ z@B!*9816}JT~#JCa{x7P~(-dp+J+Wrz%_j997Sl z>paTF?8$j$K+5;)T!=Z!XC<};ew~M#^6gJ-Xx{G$59-`*Q+nuBxVA|XQ-~)awzPHC z=|Y@zmtck5LfGbY)^7--Agc9f%Ud_n3v=hpL-?qqk72~oRyU;;+*R^fRms6u|51&* z^s-m~$(5b%1}1mDbrk@drz+VOs}}5`?@Ahj&F8y&mz=^r4pL-CCjULTJ7iZkdxxt$ zptb+g{2Cp~d^iGP;TI%Fd9%0#p-zfs`X0kr<2I~%6htSR&%gTZ8KVQEmzFYk^HhS7 z-I5^6mFE>cPrTh+%aSEIc+h+BoLACY_&fx*b9Z2L`)bv%pyRMrP`}aC47OY|Rw~wrkV2qjWwZXl{A+y=<7DLKGhAKuORb;FJ#I#;XSTD|!@}fpCiO!T@!bjZ zC9!9eL3xPcqHJz%GAkdM%`)IEGjOnY<$=e%CHu_n&VAgg^2*Wdy*eh(_v7m`#>rw* zuJ^mhqjyet$SlcmGyE4gFtM)uhnb)3LKA|)SLPQ}W~z*Q8j;4*&4+2{C-X>wym*B?nuUz(etDP|dxoCW<=A0@xtUiHs$Jyjob;nc)r zG%Gx)r^>owMGdEsPX1_eN9)NS;<+7na#Jzx1PE zLvlJ-yW|)(L9TfT-93ugKmJsPwj7M}Se~Q8(~6A~M4bU#6faKjxR=ER*4wzWAi#xCDH$0I6B7i&iAIn0 z`Y$llf!`@;wRx;n--&LSaFpe16G)LAeM)zsWM?_tY)*tYIZVya^BT1x;74|Jk?IT^ zXEJ2nMr}~BqDnpsFR7}xUKmTCG4{><{aL<|RCoWcjwE5pTr2kA^57pWnr>X)0$)$K zd)L+)bEg_}=Nogcg7av7+riOZGQ_3I2Q%IZH@>p-f?uP#?x5ixY0e}_?#}STQ9)6exFt^18aTB5BGtoaP zt)i;MqMuP(&j1`fOS=qR!(g(c(fT>!0vM#~q#GwOVLWKv+iA>(Q0-ZlN($C6@KCrE zmr)(D&ZJPZAz1eZf3QYe;@BXsgcprP%s=#3F3SbiI?N2Xf}bXSqEC`g$8++IoM#R; zYkg)JoXS;Oj-vdh_$dh!t5AlM#)rcSgiDaad$fb>Qn85+Zur zUbrn-Z;qIroWTXt9wrn~%2yzs&G!*wsETp!#9`610bXCg$m?LKPCi?N3!YNdHgiPq zcw9+!3r}p0SreRlr78@Y}IT+_0 zjX1uJ@3I}=#QSW=KwS6{1RaV$YCArUKV&=p6~D)J9Ejg;J3dp#a{&G#ev9q%X`)qc zhoO)W9TLt6dC}%cEDC2TwVp&6z^`KUZZjjCF@tkpZlgLFs~-ZT#MI7_+y^I=7EBZpmJuCK7+A=W_&{$j&4`X7^)Jl~(hp~<)TOPf zgGeqH-1e`v6^^4k*HQh!JYJqLJTLP6fTxgW0?#C#YMyC4>v`7j^z+oqcQO4T)|?pv z{&JUgN3X4)Rm*p$ARI6Jp5OP{orO?MozKpQiuxA)gTV`dNq^REDM>|Fc*v`g(wDd# z5p`zJEOX0QVy+=dF0~JidNv-Ws)8$h{&CUy$eG7QHH4*Tb2V6hwl(Dmfb-)$i?&

s$5t<4i8SZ2EHK)K_y!5U!B(}+sB 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

Wud}9|%O878%{M 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

Tq4t9QhiH2$vbY+9 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%0Afe!g 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 z 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 z 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 f_+e>m(X*BJ#Kn#+kvvLVbf}+BQQK Date: Thu, 24 Jan 2019 17:04:11 -0500 Subject: [PATCH 129/157] whitespace clean up --- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 38 +++++++++---------- mRemoteV1/Connection/Protocol/PuttyBase.cs | 1 - 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index 8b204f045..2a6082e05 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -86,7 +86,7 @@ namespace mRemoteNG.Connection.Protocol } public virtual void ResizeBegin(object sender, EventArgs e) - { + { } public virtual void Resize(object sender, EventArgs e) @@ -96,7 +96,7 @@ namespace mRemoteNG.Connection.Protocol public virtual void ResizeEnd(object sender, EventArgs e) { } - + public virtual bool Initialize() { try @@ -119,7 +119,7 @@ namespace mRemoteNG.Connection.Protocol return false; } } - + public virtual bool Connect() { if (InterfaceControl.Info.Protocol == ProtocolType.RDP) return false; @@ -127,12 +127,12 @@ namespace mRemoteNG.Connection.Protocol ConnectedEvent(this); return true; } - + public virtual void Disconnect() { Close(); } - + public virtual void Close() { var t = new Thread(CloseBG); @@ -140,14 +140,14 @@ namespace mRemoteNG.Connection.Protocol t.IsBackground = true; t.Start(); } - + private void CloseBG() { ClosedEvent?.Invoke(this); try { tmrReconnect.Enabled = false; - + if (Control != null) { try @@ -170,7 +170,7 @@ namespace mRemoteNG.Connection.Protocol { SetTagToNothing(); } - + DisposeInterface(); } catch (Exception ex) @@ -183,7 +183,7 @@ namespace mRemoteNG.Connection.Protocol Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex); } } - + private delegate void DisposeInterfaceCB(); private void DisposeInterface() { @@ -197,7 +197,7 @@ namespace mRemoteNG.Connection.Protocol _interfaceControl.Dispose(); } } - + private delegate void SetTagToNothingCB(); private void SetTagToNothing() { @@ -211,7 +211,7 @@ namespace mRemoteNG.Connection.Protocol _interfaceControl.Parent.Tag = null; } } - + private delegate void DisposeControlCB(); private void DisposeControl() { @@ -226,7 +226,7 @@ namespace mRemoteNG.Connection.Protocol } } #endregion - + #region Events public delegate void ConnectingEventHandler(object sender); public event ConnectingEventHandler Connecting @@ -234,43 +234,43 @@ namespace mRemoteNG.Connection.Protocol add => ConnectingEvent = (ConnectingEventHandler) Delegate.Combine(ConnectingEvent, value); remove => ConnectingEvent = (ConnectingEventHandler) Delegate.Remove(ConnectingEvent, value); } - + public delegate void ConnectedEventHandler(object sender); public event ConnectedEventHandler Connected { add => ConnectedEvent = (ConnectedEventHandler) Delegate.Combine(ConnectedEvent, value); remove => ConnectedEvent = (ConnectedEventHandler) Delegate.Remove(ConnectedEvent, value); } - + public delegate void DisconnectedEventHandler(object sender, string disconnectedMessage, int? reasonCode); public event DisconnectedEventHandler Disconnected { add => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Combine(DisconnectedEvent, value); remove => DisconnectedEvent = (DisconnectedEventHandler) Delegate.Remove(DisconnectedEvent, value); } - + public delegate void ErrorOccuredEventHandler(object sender, string errorMessage, int? errorCode); public event ErrorOccuredEventHandler ErrorOccured { add => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Combine(ErrorOccuredEvent, value); remove => ErrorOccuredEvent = (ErrorOccuredEventHandler) Delegate.Remove(ErrorOccuredEvent, value); } - + public delegate void ClosingEventHandler(object sender); public event ClosingEventHandler Closing { add => ClosingEvent = (ClosingEventHandler) Delegate.Combine(ClosingEvent, value); remove => ClosingEvent = (ClosingEventHandler) Delegate.Remove(ClosingEvent, value); } - + public delegate void ClosedEventHandler(object sender); public event ClosedEventHandler Closed { add => ClosedEvent = (ClosedEventHandler) Delegate.Combine(ClosedEvent, value); remove => ClosedEvent = (ClosedEventHandler) Delegate.Remove(ClosedEvent, value); } - - + + public void Event_Closing(object sender) { ClosingEvent?.Invoke(sender); diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index 1b26a8024..039e4ea7c 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -213,7 +213,6 @@ namespace mRemoteNG.Connection.Protocol InterfaceControl.Height + SystemInformation.CaptionHeight + scaledFrameBorderHeight * 2, true); } - } catch (Exception ex) { From 34c8f21cc6064b8de6e08c3b051f58370d39686a Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 13:43:14 -0500 Subject: [PATCH 130/157] update with appveor publish build --- mRemoteV1/Resources/PuTTYNG.exe | Bin 716144 -> 708976 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mRemoteV1/Resources/PuTTYNG.exe b/mRemoteV1/Resources/PuTTYNG.exe index 50ba7ca21441dd9219189da3e7f8e1db20a244e5..5cb31deedb1628a8f4715d99b07f5bad6b2c321b 100644 GIT binary patch delta 171691 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⩰00jfa-`%X)`7`ZYtQ7B*5G75@g6q)w#H;($^56rkf_kxn0u}NcQ$66 z-MBMrl(Ik9aWmZ(2|dPogB*{$+Q+M~VIoxFh-}uo$%JG|FSwdh~ zhd7$8R%}Tttz8^9`O^DYKlt?Stk!1HyLI5?J5z_!Li}HJNHk{9f9#NgWo;d@;nDxn zA(?2*@Ab(4bsZup_pB_!JqhP6^YV@R(nmU)@3Sv4mOXMPKjai73TAy%Zjj>j)zJ?-1^twAx6jT{vYuqNFvI%Y?kvMrtQeF&4pt>EQ2 z<@gg`LXfm!1vW2-0Jn7!UZ{NQacDXk%jq+_frONah4IGn;Q&WDya-y;sj`O=&BSUZ*8Otr$!ig0n+d7B2OOz{as=1^(@tH+fd zl$o6+4<#xEw+3XEGCNwS=BpoIkzEv|L^2DJWS@28M;~Op>bLgeRux|i~D2II`<)C4|h!p?-8TPK< z|Hol}6?9(vum_)PXdm_&{L=?n@5sNYLAQ^(qfxq3duR!psXGwNKUl)z0(G>eXk60# zdD9X$aKx*$K3_sWCwh6VeHp$?Be)h3Z)0z4cpU2s?{DqAXkq?Z-NRRS#={^LdT`HT z785+`N;^c)@L@|>WdF`;5Fo;NPHN%K$nS8P>j0a!fbU+yhIW3D$W{XFEB@mWHYk1~ z0YH$wOfYwV%nZCOA)~e9gKS#oo%I%`*J_vZSr4-a-4x?RvpZTFJV0g z7}c;2pna38f>!$2NKibnMDg_H+DBL)9}y&jmQYZfJsQlmvJrqTu{;s!;3g>e3X3~v>4n;Z^jYNEn|tg>lgU=Wh^$-PDzoa?m}CZ zI=*ZfdqbPbdoO1Lg1$db5$TC2YbwuN&K}hs<@=YjIGwwM|G1pZ*8apNS}|k~-P^Wv zzls})tZcV7naA2#-%f9%XgA9fZ}K@d2nYVcpSB@=&wJX^&t1s(+K|48uUvujji`~* zf68B8!KTHCC+NHmVgH#0Z8=PM1@@nc0Tcas=auZ@XxkY%<**Y(K(X2I(JTy(vt)F3 zo;(X2F2Uptkr6a%GD1Add#z#Iai8U8JMA)f%QW!I#T-ld5mB#jS~c$xs#MiI3p` zdz;#DsK{wA*mXBw`54>STP+yYWLgI_DQqMV2=(A3lm@rFfyq4naTY%QchdCmj3mv# zL@@sH^LLY%lSMG+-cUvAijulf zFFnrscO|#gKvvtds?~t|4qo*~=)fFV!L_TwU+T-lSF^F&BYe(kHVdrijjMqGJM-Q9Hi-p8#;JVE zpDqQJ{sdP_!G0G<__k6O*6msNQ6VRrMFD6e4bXmWTEhk#^S$8~Jq1?Ez-}?V#ChJt zbJWD&!GXPW*lM7}J!D|WTi(E;QgkncUwDRhUBmkLO?bk}FRfuAc3+*IF-6c_7qd`$ zyJD#W$!5UBwhJ*!4dN(t6(kd#;PGaN{BIdP^JXaW!s^X)1yFe_v6K4p?X_I+)j|#N z=Gf7m3z;>O3Jp&POQ> zjF)kIei`dG?u(hK+(ZgZmVoMk&}3-QLMmY zm6w&XLc6t(GCgR$Qmxv*bjuQ8XkrH7C}QgbuC@pJQvuYry?uoS#QG)cYz$@!NN^*~ zKo-kZ;NXIqHfsbho^$hDj|M4W>y`a7`Lyf%tE`iiBqdcJ*9;VNj{z4bmyFEI%!(23 z&IgEa>#<%=Jae-(&|;d`)QMqE!G#oC&x_Zxz7sA{%iJS!g`GMTlQ~8;ND0IUbjuZ4 zC?r!fu0v52NiK89Dhal_FhhQopI^%&LKRs=A`M)o(4ZK!lKZb?1EX((S52oKbn0g6 z)KB2;uf0>(-{K=Luzp>?L}iOSEUEN5@Ru)z=r%>MPSRasM%X{0!xWUQ#Ca0-Os&X@At z0Ph>-rse)ht<%<=ITs55rE+TG%osFynjx-98{l4S{%P3~Z&}^)1l>@9el?cANF|Vj z1=7c0K=_kV8@C_jx$S-^3>*70W@(*=fK1@8JTW0(j_r9Da(O+sS+j9ERjSP=R_c`f zaZTnE%O;~hcYotP9YniFz&*$(Q+(?fv~xBjs~NY-57`-vQ1O<62KpU$!rbY)u{?xU zOPZ;n7Q?EfO}u6?heL$y#A~hAT}#{Cht??qq{|{)ql4Ep7sD z>u=OE?UoACACj2X1Roq3mmOQAJqxsP$8(Ru zrt+3b78o|h`8!pP=RKAGbCtUMKl7wY7Nu*M!M7;P+E__nu(Gb@=_}2{zPD!Ya73wDpum1%fbVg2!26 zaFzr)OH2)A=%WNr=|qhU_DMlWB|$daM~@@gE~G=JSb$#>NNnjo36JBRTnj9%LWL3h zB`74&n5nK1GR05RF-t_u9q4h5do)m{d0NnlpiISnOpwQYB#rj0gn^Wyt&qci_7-B@ zGu?^Hg|OPZ7>z&%#72^SKSl6XHM|Be;n!qQQg2&-g0nEl)>Xp!JtAloU{j+@b1R@e z>MS(5A1ANhs4Ck|@O~+)itY&S6bbKg{0F=l(BSm}d`vtqi?of)&TfNPY6SCtFXgvs z)aqesDa_l9`M!3LDQb`_jr>wd3z$cE+>@;LIGx0ECKV-tc~@EzDlHccVr~|St4$B3 zdwoglAY=3tAl{wEOP^!~6GHxgB*5lQt!hqi%~1uj8)$i_hFbk9QbV1o24`vzShecr z>S&yrod?xuS4N}QS;pB@Y*5!9aBB6gvH^H)c%Dys3QC4s)G3Be`h!b92__j2U&RKAzqTsmjPFv;7 zjq{P`Z=C8^a3oh;n1dD+mKF;QIkmnZj?i~$F+ckh8yb8?0uf$7P8^Q#F6-HE_9{aE zOD1CVVIL+Vp>Q0l!^F>1+gcHaSL`lD<(^eSB9yO@;s>ZY7t|B7&|d|n1pAQQfB6pY zI8i}O116vsaMXwHx%r?qj3R%uQbHKC!R<(l*=DdBDtapu3k)d7xA#ZVG^-J@0H>yc zrK5=C&en54GAZtzidx<4&=U8mRTMN#;K!b3J)%AYVr#c0Drg{LN#eAEhSgm6XPikM zT)`jtGm8%Ti<}&=r4pRNFw7Yv7C zCG`+W@lL&0Q!s}>PuNHm#QH7FkVErC!b0>DY&fG_t|Gt+hnwe0_=RWLs7`+{lEqA! z_>%Y7z+!ZVM)2_)Sftqvjv}U@7jgW)k=9VmVAV+LQ|{U?*iNUN{zl9P{kj`bQJ zKLXXYYbKaL;kIigpa$Ti_Huf(morC}6UzHM$GYfFR?5N_Y#-jCF!IQR+|r`!-Uw9y znh180k`CFZGfjY11bYoZvQcblu8bCEM!hRTkp5D}Whpkj8&TO6X)WLa&^@6|F!y_&#c03a{hw#|WZ8lNSB^>60#@(Qr;qkZr2fK7VI7cvLtGJ9`+XG;l1p@v`D3{$zsR)EJlcU+s_C*%LQ*jo+ zReZ`ZXPQZwhM5y8>e2EFze>OHYlT|M+9oPx7*cBC+E9kh|SB2Ik)4 zo=yk}2yi#jM-E^3A{%ROR*P}mqGD!X80MguDHQ>ZU;U_{LkWn0 z1V@UIqcM5R&;lyJ!6O;JbbI%?0&s|XN#@$IvCvq+P-A*cf;Z;N2^_5dO~ zn!Fh)in(W!$=g(~$y>s0CU3uM@pe>HpgK%5Y4di-4M`8TZ)C9{rX8~L*M{QP){Ur+ zRK8;)8yKSTMi|;60(jF#)_3Cj-Dt8|W0c~d*lPMaJY>@Ci7kl~BC!p{MB_D~N;$4H zHT(ff1T+Lz_bze&3ZA)%MGSSJCo0d-o@p@{cO1@ghmsxh%G*L~GAjz2#e$W5!zNI! zX1-?=yDPIkfTngmmUcLnHXU93EQSTpVWj+BNeI_XhM5*nz`HVaGc3Wgm4h$L&CJSj zrh#5REr!QN+L(NsFIfkfZ2`0NMqq$)okTG14QF$>qopZ{UYFvmv1g zkSN#sX+$@fOfIfnyweso#draDmX1AyXfF#LpTC7o@A?g4G#q$xt||Ki;XSf5kKD?7 zgG?Nh$*d&S|2SR6rVtYvenCsKVB~#KPgWe+9BNp$*8fc)cCSD4zZ@>k@Vv zSURC|uB(v{9suZ=CqdRpkW()E zK<*-ssBk5BIpO3YXIB7y*atMub_Q_}^N;*Wd*BDn2DP}u7DJX;`6yq#6-HyWQEh;~ zIg-Dzl?@C|Z4Y{EB)_>&&>7sfdA>~M-Rn=}Gs(dhF`JPup$(@{82nzbqP-~F+(V&$f%lyq* z23W**62Kl1qkC-7buZ*;e`Ql9TfxmWI6%pcCh>K&Lj>4DjXO@JD4$e+@8`G_aH_s+ z>Zqx_d%Tsq{j;To$SIR;2I#ibg^ zv5OlS@tNXi?zA!$g0cmhq1y+iXT0WbEa|?!_!@#|6rN-}lkrT)GYijLJj3zi;gP2r z@jSqG%?=lvFh?EDdTUqGNQB58GwEnyLn~-W`hAjqiCK`9g`<%817G+W>l^e%V;jbJ znm_p(>ockWeMkHqsosf{d9K+8;Y4?Uy#cTEB+Bmz(c93u=Hu4R6nB_ke2sOV0_FD> zQI!f5R{;EbYLO#3Q&T(`4j9m}W@I<+$Qx$fZ|y-Fo)dEndR=6SU4mCtJ77T}H~$@) z?%BNX@2n>n3XlDrMNb<~=W$Gi9`sLEE}7LRq_7#R3{dtGABmq}z<^0Xf{t9zqeZSq z4Y}e~x*;K-Dm=>T|IYUIOTcV~4raq)%shm~;?qO(|6uwcjEAOhe!~~M>UH*aP)L?H z*aOw~k-}K^cl?K5RtEI4#zQY_An9d&!>9j)4NH3$QLc3D!O5gI zqiNVmpR=`<+T;XV_tFyGC|iG5x*uX`-ZzxvU-DR6H$;qv{{$HUl%V0-dssx@yPPu& z-jszkYMEG}8uuiqX+=X#%aqKU|G_5fo|wRs-((NjrPhiocPO0X3{E(IFg=Jc;UZ^Y zC|WzJs-iH~Ss3jsjB*x+R}_ZfK;O`U_&kdN`{~X6pWjeQ49dYuV?{sqT}c|E?xnpk<3PkajqX=%M-pBB>02y& z8p)pb{Y}cAU&qgXls&(Q$fxl^@3NA?u4}Y;Ro~&1FW~Mxd6fdJt}^8bR}i|?xt*LjH+1Iz ze3$hKBZrHp;1adGs>GC==aF$Dl1IPCdQ9mM*FD#>o!I%_1P!!KalxMqQx3xgsC2#C zR*)Kzha<@2@8Q6CUo3y=JviU^nD2Ryjl$25??GnxF;9LU25=wqbMHfa{$n1oo$dR> z|2#mnERLi)IBBUccyJ#?wPa-16DMP51e#(C0)H!9OpR{qm(_jbaagKHs&1a{B@+=T zI8eP&wYzzGEbhO$c}l)bUOPy*GsBWHsmxP8_?O+l1Z~zHM zPeDrYWw>BE0zhiStC%j>v<+}H`8{6qult)ICDK{@T6*9<7x?5vq`xH~|I@)1Z4nM! zxCmA3ilWm`5Z>+uic!svpeRC28aRlB-d{0TUtyAS5h1PvI2BI27>@Tg{<~5fPCe$q z%^s2mZ!;yOg|3LjB_h@?xvD7e&oQzgNVB^`nw9@hzHm(jufDO3S8q@zhl9d(2OLam zB8ELU6UtY{w~Iruk(1MFI0rc9w1dM9BefCOrXt619buBcPa z!XLHyjB(vQLM$2AvOS|RvqaBX7~q_69QrWN;|>qL%b@K!xS+W~VjmQr)?}_*cIO(P zdXIgD|8Dw0&jo=;UVX#X1m}b~;db-kl@BYE^$zqJtQD?h&2{QT`e1Z=rU?EM>N>;FWlN@qxlYzD_AR@%aB=Rt&nScZ$>Kdwc) z()CE3uXHij*#aFU;EsL>;@QcNji-Ld!g4lNM1W$j+(1KM&zjQI3D~H{?Sxn@g?g}e zs1F-;7jFOpFEHPLPX%Dy!yFlxA@4l`PiqntVN497wv|`!VBsNQ$lHb_-k>BkJ1>3+ z>tK5+6}_e#%@{Ig8<0tp(reB(3A4$^O(n8Jyo7Wl!;|vaDU?)YT}$@czj??f5j3R1 z3#o=aRKriD6Bd$O+*tk`N<$NO&m$rFI;|XN5(}fZhAI=ta7j4^FY{aOMl@KyT@#ui zBRF-e-RpYM^E44U!!4pMu;>-Mi=Vmy951vAOA5#RYIkExDVl|UVg$~S`T0fnQNTh9 z=q&@3^x=A>46gMjxU|^uYvINJ!>-g>gow}~NC&j2msbaT5XxuoWBr52!;u_ld9cJm zz4Fq1ETMN1mXYLVll2lj;ur)Fk{63Yf&aulaP5J2A!*m+hvLCB(tv%6n}A+{++4-C zS=96L8n`I1F@P?mvt6K^ez`@X5hCvaYj-`3-0eQ03mwI`B%2<7_Q~yX8;2AFyOsJe zf~2{)Sru1K60o@Sl`fgW=Q&>g5ev0{tcH5|vufAlo&)%UFV6%QhhW}}jW}Nx=1oQU zDZ+VMUL0c~xHW;33NL!L-sOjEz2R8WI#5gjrKS3*Tup4gS|~x`(kJT`NXpB@s;uN5 zFrZe8nc@Bp%mjT!g!@zeViilZzYClP72vcWOJ?m8X~C$D4xd6w?}9l9q7OABf8?=)PR$i}flZO0Z$7yE9APy}pm=N+0%#<1 z1vXCz1Dg1}YSt~Xv5QSrD<>l3Evi48BuA24lRz;QfMq+Py`)6`b zH5*|c)Smz7%=Y}!x);q25qAMHwR@gHhl9_*9Cy=z8A>8AY?sM604C$tuQmXk9x7VU z>B{kZcpsP!XT?Az@SUYi#mTZIF5_0JGZ4u~n2)ZAvh@a-hOCxzywX{v@e%eLFT6^Dt+#G4IHjjv=UG1 z*8KI058VgfUscXread|2Y=e8FmziVY&Kh{CD&#NLu;JmLM?}&vR00q0#Z`oj{= zE1&Sj8WuI$Sk{$79+OvylkS(p<8KQ@q4|cChGtsM9zxM|o(4BQfR)j2eB1%HN4jPI zBHvkPaGN}j>XE)3-++yl?@ZS>U`oMY*{f`@bh&MH=lcYewAx1EbefNH_(vbJf#bi$ z=&57c8*fT&!%Z|RPk^Zdck*cdzNM%z!Gk_qiTSl9MMTNCN!qI(8ZN1esZnYm(q8UIHu8z58Qyro=pcBeF%;vwuk`ACzCBmWPz z>;aus;duwyc^$9hqwCll`|>38Gq|*p<}lYS9|Hf7rt0r>O6`r~=IRxZE`1l=6fA}$ zqX`&Jv8jigiJ1D>0ewv_X!zw8F2Pv^ERQMLH_3lB-moLnu?@Jfleh=1L=2NjAYiR= zOrXS2KJ%ly?D9kp5OnAeZaTzzhm|2J!LyZ80QrTYMtGkM=2H(rD|HTEdx#Ai8e>LB z;zmWRppoDOqkRFLeM@9Arh)}57)KRN9Na!|@eu3THxIyoVDX^DS@hcGl+L$~^gQwt z7+*vp(q-2x0mMaX0`)>+vvVyT&p65=)*vmVtg`lkSJOwH07qMF0S0u~59%@YRJiT0m}8xD zg@WLG43cD15erAMWlHog$ABJ^_oS6$$fs*gZrI!awN1qm_hD$v{?wgxGej^}2A!m+ z3`}#1D)mOukq}W0FZ^crc#00}PuJ|G-WM)pDY{6X)NE0LPtO=CPgEm^XAI>RJ1BF0 zO@m|;fqN-lFGIV>&@{$M@!wa0M5E4wjS{`mfK7Qw*?DVZa$lQ&*?Hr$HIj|l7o(5v zCiPo>^f1iZe>x1cxmyScRO);!yoCl%BR4wUwJqC0+6{T`9`eeUF73zwz1Nxg!xm(N zGqg5c2y_^>y6&PJbH$4&_ktf|34?n2mg#_Zy;Ixfpp(CQghiOAwI{XvlJ2IYpoyS3 zCV|L8Z_?aohU#Cnhb=yysEpnVB9(p0W{e_wxOS>(u+}|1sI+2g*dRrZI5kY??ip*R zFn2d^ToC2^)2A%iUQc_}4yZSva8Nn(Q)m_dd+$54Vut1;(&q%FzNYm!zTiZ9qBRg3 zWy=O6%6Br-u)A~{UHBdfYNHGDs4T3)-6ZW!S?6_G3S}-_s0Hld$^g%XPdEy_o{#wa zqY$Vmpe?=qRTF?o3Szd0B5?AMZk`#R00gm9;Qf6qtg{#@J9>uP2n`aosp3*tC znA%>N2EywZbZ;)^SFAI8f>2)ViiY>-83>4<#@c->G`>qx_&_G(N%jliGtF7ZMl= z+0d0Ixs#ug2(Gu>e|G{>x>5z(%_q6aICOww*C$*}xOwX6sbhBPpl6T*q@S^@5--l2 zTh8KZq$u~J-rTzEP9*@YKde_1_A5EJPSq)O&K@{4`_^+4D)JUhN7S>MJ5KMH&{Uvs}qXKS3-`WrQ)y`bfzAdS-`|7YseA2hLW zLA!+)nj_C6;%?4Pvf(4bKqj}7-x4d3jxW};)|_gv1SN_G$BuWpKu3gtD?x03C?DYh7HBDp#aJo1;^Lp_KMSJ&1Aiu$ z;4fhiAQjNv^^Cay5X1?beLQ38@d~G9YS2Cz zM4P`;Mu<0MK(Y*=V6hPam6h>9HAySAn71m^|hBPwoqj>WS4bVzw7}!{lBi}h? zqPn#d743vWPl3aZD0vzYUQp>SBwSpj>Q&>exv$@&))&-tNWSxFe*F|1WPOZz!6EX7FhCzPd>xHqB2_G6Yi z0E>lAgFXcK3fQP#x1%|R-13wB<+a60PqWydHz}a6`&hzt_bGnsG@C|u zBT4TZV5xcX)WhVIUt2x-7Wg@;2f;(4oM3!jt)Z4-^B~@JO`$s^ zFsL_xFyV3ZmV*1c3T~-9zEDdipypp?n&x@t{p1yRpra~&kzYKpPIEf)gBgM&EK|;z zo0c7hy0W=RvE5n*-9{1}gCg^&Hz{o8v(B)jzyTB>Z)#Y;*Pmh0BQWAf0aa~Vs4KnI z(cE`Mh!g~>iJ}pUiEGS;Zz-bu>-ohqEI0anIbvJr#~G}Ch-8quWoA9Z4`uh$GARCkK8kQ0<3UE%VA$kI{J^;a+ z5iCA<0Qd}-Z}@|HaZeMYVEHjDt}(p`|_ ztn)0k`$9r4%ONjmqdY{?Yf?Afz80Y!X^rsLR2)sRdg-|br&I^T!?@q$bu=fPw&v$R zIFoIBV@Kapa?Gba09TC&VRYUa)Q3Wp5vWkkv#WH zR+PP&8g&8$etV;qp+8h=O72U_QS847W2!J$PaOqO>BF1oE8t{t9(lb@&oFsLiq-MF z>sKr+DaIi>!Ju6*YbTPv=tdwxcG`qwJ!jB1N1;~y^m0tk6!SM z!}ZOWXwpKWoA?qELT^`e$E*8{Yn5RX96w)i7GH4Oe_8|A-tc`cjzCBIso;eS?U|f?>u!3shq`Uz?`td2XsZ+cVOf^LZXdt(NX4~t(_gMfpA6F zswcCwdS$xanQ_{&P>(3vMDZ=*3DAni#d(PaaN+}TTaUQDi-RvP?_vvRRLMB*oDSS9CSX&lLAOvb z_OF3K=yJ4=FZ#AtsWUSS7!d5nF?WKp@O0mZ)d~C`o-1-7p2sD5@}j>?aTJnRJNK!Pih^hgd(`zG=0D&)(D%Z|D{@guzh)tYc)A^K~F+D}STo|sB8;Im(u zRNcZBf03vJNqI-@)UJbQ;}6Q!2@C)G*KjrEfbN%fvVRDYQl({6OzTxqDfMyPKU+Pp zgoS`-qQxK{jN{k8W@CdX6k-Phf*y|JN#C&P!=*tT7#(C+<~SJSsQJwm^%C}5_he-p zD!o&+OTuMBw&A(rG=J+G7#~+}#*jJ=>Tx{(fY*P+B8qZj&{EvNAr4`SQUWCN(t5%% z-GmRX0Ua5tiM?RpD&ux*qCr8W2f@H4S7cCO?swbB(mYoQ7$T4d(FI2R6t6KGR1FPcG36ma<2d>%P`_G1;(@t={=hdxZs05k zy1gSGGc;e$PsvAE;8*R|le~?WearfW3{YFg%4*;ZSB0AI{FcoMT}%i_H5Z!hO526` z)>O@Ve8=GTW*JC;x)prRcPzdaU9yE8wjaE29;2mzc?Whz+AY6O61#2uj*W!~ZZy50 z`HqbVmA7lXnHe`ks1y?Yi zvc=A&{Fy7P|Bz9Lt*I=yf)r;c1s$2-s&Xx@Ccx4qQzR}$&;1pZetiW5=CfAbS+L$g z-G6Kw^$b2*u+KWJ2Q}lyv@GJ?8rVGn$9LhjVtba8(Pmf!t!}-> zJsxN>yXb<9t-d{0r*TJF0uXyy#%_I`H#D$*K_hWo^DedrdHDBi)Ie*V+=n4yg>1-U zYr-&QijZ{x`amd_bP{Z`X!GW_?^!(j@FZ06SHEX(4u<(n4hgiB&eyATws6O#Ryaxq zOQo|iL+`kB%W+8WoPmoFMpf}k-?Iq*jGM(r-R&F4EMWurK-b%3;Ci83VAAj87u{^I z-8yYIS#rVpdpSHJ)NNS^S{ojTr}x|M9nCPwlzSdEgA45p`Vv)XbWG7$=k$`s)c zIw){;YsK#8v8{sO=U2B?Ca{3sPeLrpX(+l6FktT4cS7i)G=pmM*m{6D?ioWxi4Y{q z7CoBKSMI7jZ(wV($nu( z90AFzLyfpp3#vuJlM9IL*6>X60E&^f1qTp+X_fooHgKPiRa)=&f!mp&m68Wr_e?KX zMM#q?mY~*rcQTkWvH{sLqs{0`G=&nm&q_#hgMRq3hA{s%o>dAn~=s4OaUr`ObRuiAjP~>um{)yTZo-p zzJ^v1uCTv^DJMxrA5|a|6LSm(um76(N9@fqvFKh-X4C(KJR+Z8yUKdReSDrAzFVVn zg$=tN$sD?q(vz2BeO}%C&boueZ{P5-KeIW#X2#H3ytZbQfzHpim?C1hlNF#r3|_}y z{+XF|&kf-hf5svGR~~eYjq6e~lyE88b9ND5f6cS5!Bq-nf~o%L6@2wI@YBOpd9kf~ zQn6`;2}>Pt=wcFKn)v~+6^Wa%nff^bJ-8+h2O4`WY|L`L_VEOsyaaVU7ZQT61KTEX zt`C9Oh#hk}kcb3xC`krk{0w9snwjUc-4g#?OHh%Xlg?@PgQ9TBB;ki5m3a5qq-{iy z*a{b6o7zoS99zeVB&^?VWZo7GWDg15o6wI(0pciXw+zA6lcmMifUT4a;WP1tvcLk` zFOV^SGTvPgfa=a1^uuPPaUaKq13)sN^^${KGBgij#oR1$B97pSMh65Z*>2gkAjjXF ze(tR*UU4)(ZhP`y0O{`qB%J_}cVOD<(IF4>>R(uou4Dv{P1nmU+k$)N8-9TYM7n@J z@CF;I>$M;f)^%W|q?uNRiub;xG8Q-!MdJmOQN{0UVeyf#fr@}I2ZqeJB)gVr8cGmg zxj$FDbDh7`0tH60e-t4TTvENltKokTatZmj9Xj_)Qkpy`h#8J4+WNxU2i_TtXFnsHoE);)TR6kZ^&=`%ED6m+5H_Y_brRc&a~Wz$R*xL zeY`X0vXXP5B48Srd^c@@=BCxXDQV|rJ&?3BlBOalO3~e7cj-K(yzmzM^WL=ct+!Za zAHQ?H!AU-gN#=DL0JEU^c-K{VbgW*7xTY+SiElkYJT1W*XM~FW(EwJ^awO$ zXa+*UXsFc=OPv7~lwG?}%fYk@b@-8%wN<$y+@JHR!NdA#7Aja;1HyKqpm9FH z?N^m4gOhc}vL{hqvR1vYW=@{as-<|W!}G*1UwKRHn*WcxJerVh-EX4eLc-d2V+6@pGOJXvZL?O5) z;gB{d_zch@SShLmf^`4rxHAbAW{M}lAR$JMu}q;=rWG&RQJzIN-`r#i_=uz*Zd0~c zOMwWnd_+PJl|Sa14bMsIxkVok88`~tl{|(1aGtN%2aJs+eI~huNO8q5R2kHEyzGQS zWkjy{GjGrbOtL=&tweRF=(VtIr+~{EmABDhr+D=QodzJyA%z>rJ7Nz*JQ7X+=nd3} zgN~60Of^Nx6gZmx(Hq+Ipf6?@1#Y8%^oGOu9J?$rD{{2nJjdHpZr=d8= zSf0ZL3+NS?xDufFttV+BHwFX@DEvjvJrvmsoLdu80DGE9q2NKzjwLpBF-u zpW+kaiO}D8@1TG|(4YUPb3mm1No-x{fhRBqfHGD!l+P`?ljhni`bTfz3F;ks>{ z0k4yRa|g9WH-oyOn!T-&MU-#WrDzpp zT}uDx&EhZq_8;P_DL;IIq^luDPV7{O-Wp$SrE5`YzKydb0$HRqd5p?=G57 zgOo!5=*?mh`4kPsFH`yXZq^Cy@F;bVI}Yaay97i;(WJ!4fxVaEXS{I#Z)T4bw-A3bn&aRECqBnASTNhMZT z;$h^aR0qz`oVI$i^lE0!SG|+zx1s78DsPb3s9|1LW7|XzXog6l!q1bo__8mx>O_ou zjmoXsDP6;qwecsA2RwkV3fPi5EUWlb+#2G9fM-cEbAXZ2uk8NhK1VGjJxcxq{LJSD5 zSx5}X%1|?oa=k=!9nDj92ZQQDY@I4>co%gLvj~+)>DWwoB{E@q_!27oUJ(P76#uJ; z;gTs}sC`{qdhroh0N`M^yV+XP2x90qDQysB-Z>^fo}Ih6DG^NCJZH|c&Wvq}YJcIh zy^qV8VCNI+2MhG|PTNLL_fj+jTKs7h*{+N|VkeBZl#D7@@hb^cZzy*d?9Pm`H{MW+ zpM`MD+-h_%oEa3`Yn1^NX`d-++nfcv4yK&}j?^gnav~}r$Wo7*#`0kZR&w5VR1Npr zuN-!!J)an5u(DJ~i~s6hl;Vv_+6A~o%Q%A@-JX=hL)vlUj;Xrg#(kynxUf3~wrXQXf_^wfi+(oVfa$l7@>vaaBzs3) z`}02Mkolc6jO{ybuNmmPt<(x}u4zQvFRQ-cX&$S5d{sN^)JYqw zsziavabBro^)c^RvZ6;&8tKYzY?;VKx7If+BzT<4)ev{w`iGqo$<-WjHkq|>j!mes z^WD=Jo>k}>Ec!7ZcVAv*7N=D+w$CC?XK}l!y~jc6gwZemR3cKcE3#y>GwGPu#mbVM zW0SU9*EL{Vy80u(lF>z-v(uSrK2epl-I!@UaqaU@;Lx#pyUDulamJ@gd(tjW0NNS1 znpnx?hI2+)^E#S!hPFeTC8znSULShB?+h@q-v;lPDHVx+Bl!Acy|~X-HIZ4pE|#u7 z!ia5WOF9qz;Cbl!M-2C0wY=xNZMS@fyf5Xb#zgY8WED}PES+u|?me|-x4XC}?TF1g z!dyqvKKBjuR47#?JE*;#Z87gY`|Pt!E9y0`Xy0~Ihu^e$4K>H2xcZU^$5d~#<5$0u z9z~t!r0c6Z=7H^q2e34B*c`X|(z2s$Ri|65rFB<(*%|(HS>7K)bx?Husfm7gQV&84jZi^0X@3G3L!sHA?xmd2l@qIM` z%w_6d{_S$RyZP%!cV6T=>YTR)IX<6Q*VgH-w_{~G$|y`)ry#YMYmM#+QU~8cCP1== z1gLi%2YY$9dweIolA1vAxYJdS|F^$i2B|CYcWw`L@UZLs?S75F!QyY!CVK`?R#4>dp97(Ni6Hv-s6X!pQVP%)4{+&t7tck;b!0+J|Ycqesy3 z@@2M<*6*kEgev-b`?c?Ss=cyhMcC?K2}f~$TKDUf^=Hl#a(X{5dBn8>y*N`JHi<9h zINn~l`m7;|=CXFqXfj+NZd`=duC_p*zF*7hrN-Dx<(Yat(EZZBS6!sPY1IDus|=uB zLsiGQ2-+5zfoBG7MyqR_EEi--twP%rs=qDI5cU(WdtoZT zcLv#wT#l^fhTL&Cl>TaFrs-FdRPc)uF zR*^+0lzgRTcB0waBa_a_0$WEBT;_cO^tE&|kOK_h%EQ!vO&97ql?>2Lh99nOR=}0z zX}So_A4~S6JL6i>=F@f7PwbOm4#I-d;$2plM~L5ZY1GAU$9!)KM_p($`l@}jj6Uk1 zMAzAyB{4D|!o0-9#RMX*)z$@Vx_+ZeSK^c}p$>5dsO zYLG9YsUhk}(;M2&A!;;dd0(^N^+E!rhQsc&vS#a=<_J*-n^LsrL)4Hi>)*P@j}JoB z7}Gaer+(_l|LDg-mmf#8S^d<(_WO|OGTL=B{fw)78C=VT#+Ucv3rqFBn0ATkK_m-E z9E(kLTH;c?Z8M!nf~4s&47!4&uDw0v=dZ%5Wl1(~qoVYFn z*l2zD#midl+D`p^X3e7A(VF_HJQj|_qAxX{na>ge2ey5e>J>kA8{+!0^}c7J#IhyK)ZPWQ?Va@qb(YsPBClGYA*~> zhj2Ri2Lsd$^WXMs5uxe|8i=Pt)fb^#2dcdmsVR;lmmIaG5;njWIP2#A@#5vVoTbsN zYHhKqD6em#3jO27pE0@i7+_<*QdYuO2heVhA|vyas5l1A%+&wb&fUAK16lNT99Dg} zQcz(@V4ynIG^5&YklJiAx7BL@3R7itvrQ;BDAx##G*8NVKG*s(0!ud0 z&eBVVYo=&5*HU2ULWWl_j8+er%s1}PZWyJ8rdW4e`3%X=$dIBrhwtb*B9a_JtGTFB zWzw>j{uS2l*14a{rQF6N=QGY|)bG?D8l^_q_mYdO)e|aLpIcPU8J+CL*R5qncR1-B z>qCQWJr;4{Atwc96u-7e7T(w1y?-a7KhSu&S;xGi}U1WwTG7k(a}Ghrq4H4&_kq-ZL@JO zz8rmkd;0z5bG5r;)TllUPfKi!S~^g#H#Ds3D*CTaX|G~GcN!g#oR)BDQHZ^7mVWsK zF$i>AZdyKAFE$k> zyMfIp&Yw7P!to2?V2OkSZ~9ovK0uRD`b%ew{{o(CJ$XHl(Z_<)3mAJ5Z^YBzxCL!F`b%UvlTKXEogW8v4)c7tP5{i>MwBa|Y zH`tBz;Ltfqk1X=#;UpbleUjyH(%H@^tkr>w;%*~1_L1yeYesX{)@4y;PqKxiQk#)V z=k6J9twvmQQQVByB1xty?`F4v>A)oRa7;Vmp2j?8mS_`+X+s~jf^`N(eHO9aFL&pelE?Tx^FCK zBi(klqmFVWHIlS(GmHGP7mZE2R1!e)T6mslwG1)RmyPWfeTJWrzHV1GU)M`;s}`k}1N( zFzJRX@6`RbxrRv-`}0h_e*7_4s6K(+1F3FebfjIkQEOirCdp7W%kirW=eD^Y`SX=W zn(cIdIZD1_9vs)tHNH!id9HfrQ7RDk@QAYvU73X=*|pAbYJb16Zm$v_)5gT9IZ+?~ zsl9z*wEhL;uFm_QY;K@jI9GELVt~}j)IBn2*WQRz2Sv?!O_m`M`|U+zQKaaB5PgNp zl54ZmJIM@uy?mg20P9^wKY#`rQ_A%^qXE9ulA9*y)#~&FwmRr4K3$g&Wn8J z#T}-xo5MryPc?q4cEbd<|HOV6IT)ozT(!#AjIZe0smHK9R5Ik<4|T|py13w>pS1tK z!}41ZAp0-*4bgG(+aK`S9mL;j+P@~KF;kzFXX^Da?w2N9b+KZL5mNn=O)|+HT$mss zeEzga>^N=?4%V&$V4 zz1L3eIixrK!BbGA-l?wo73LI3MP)sNa(bEd+|0 z&=Ns*t@k8#aJTE9{b{q7Hc9Pgw$*8OPg28GvDZJ_to><{njIqhUyN?|emQO`OCPh_ zSl^%Ot+zg|b(ySA^a)~(V3Rg$vKrF$=)v}Okty;jGS79sR}*xfwq~+A%#@}*kF8Iz z;qdLrYJc;lgIe=sHLSlFJz$}7yejqTy1k~PQ(p5QwP91#VdmNfEpv)GAX#}tlEmoo z#6H~KPG^Uc!3zzFJG8u;-h`psJ{V=o3^wsPpJc>B6;#r_s^olT+U!}nP1`qx;bBy^ zG%leu1D*AU9@f5|qE4|J(>zoUA#|WPtuSvIealmvd{H?!fFu0qW+XN@ozcqIlrIprYD^yPZ;m&>G@nQJjCbHPx0S*<@o+WI>$` zb=sgLb+LKzO06mh^Wr~hbxG=w$V9q_Q#h6(C+<^r0yD8w(w3!<#4v}t!}Y-=lIeQ$ zgIc$#>QK9-C?MOAMoZ7EnrHGlDd#cV!90o~x`||)Otx@T!RGrU8VEikoKSKp^0O-M z3AFZ1U)_Jj;$~-F5QlvpryIjv4@q(=K>$)BRAOu+%xUp=PVugcc3yN$@%GNr@5eZY z0NLlXtcz*SlAnIlgPu(?YtL=Pm#b@yGEZ_F_gYFv|Ir=4wYSF|w}o+J`O;}P+hD3Fe*x$5<4QtV43ND-v*lQcEFEcNiBGfrV_KsP zhNGBM_~(azo#MxBs4rpFG4eR$(n*z%%c}Xs#>&Tw;mp3Zm5(n)5mv|g23%QQA^#s= z!T*ZKSMgup!e?XOo;;Suwv{A#RX|nMF7$GL0?9w?VnbND_+n3|S}3IGvRF?4DY*Sr ziJpXTvMYqn#^w-dFw4c9Ih;sK-OuLAsxowykIQu|m5*;S{)On8|J(Rq@wl9E zr2D(VBB?--HrNDuv$_mc<`CJB%DP#Qa;r0a$h6C0R@mHs@U#3we}YzuXTs{K`o zDGMk&A)c!&FGWF?$c;7LW#e2!@k4)_nl-1YT;eOUBn3u0X)T{Y*>}go2){E>_U1<( zsB1IxWkwf9#V0F~bzDSM<-H+I4`k|zm$ZbqJ@4lBd@7zhjW_2w8}WS`BZktyOS&s_ zB?OYH`alT*{T0r9lnL$o?spAYU2FDP9PIj7BEGD)RQXNiiXwI=^NqAU4|W=qZR}HA zV;Q@~+a_n%EMt|qWJr;Bk+*)+8%7=4Nq?SNo8xR{4#O7AQ96#=Kz6XSydOECuHC$r zNXij=6swjo>6~y7GBKU4;k~t|Q`AAjW=nGV#$12=5+xkPqo>A|)UmrrLP)A$ud;LnMcj+BiH7T?u$ni_>dplQ6?d?@pY6-2H z)Wq}k6=hv`zN<1R?l}9UJ;#eqzgH`quJ$u+(AG~^2bw>7Mtgp`8a?>i2R!YZ^C!A7 zl*$|#UKmF&lyWOkiI4u_8tw9QwWq&)Mc?+NDf){zQ(?fOub-}){MUe zy=jIKKscn&1LV1W`%eOB>I7rm*?UICO#0 zd(m%tkgK*ju4^sZO|rA&?l`CE z&Nw@EYyLzQl*)e6>Sn6F2fR=IvsTwrN#?t1k+S`m)JR5&Yb+U}{XA3c8<(k{!nfwB zl5gZvCQp{Jl@y9VAJ^4W#FtbUa@m!0y_s7uSH2lS3&SS7)LYewQ)f^JX|vXg8As$L zH!mVZ$Bvf*U@hOx3uO&KcBOUj@2dw4|L#gUi*R34Rq4`++DErCgE~>WbgMeb^pZ9* zP3<*;xXfGRG*`_wGaprzYIb~YD*3+oRZ=TckCeC8GG%_rwd{7wJ=)!A%<+C*r#+CS z-qDo^KO=_&wfD#tW#WC>FKKGZ-Kd?dG405HaM}}cMbdgY8?z!meg9Wx@3Qp0hM-`$ zs|CI(P4Dw0Dc#1d5nF$e!=?GoVsVMxDTX^bQ|$NnEQS&hb1F-JWg}SvIoQweUUrVB z)oFj7rG}W>*J;ORslny|yVg8Q9nw=yJu10>Y+isZWNbe<^T-yY``xPzo~;g={ve&r zbmLSiok?!WX295f;+`8X_!=(fC1KR5CVhe7)HpNggvY7qtYtHC$|+ddBeR(zeaNXD zz-RxithuLix`|%k)V`msPWC^@)-(*-^j=OaKAqk$Pt1XP=Dkd$UFTkj_$@b)Wa^XF zXb+~V;q$&umVN^5Ru|n$b?rDx2Xq)8H&ZX)AhGYFx0QMdE0$UM5;30Vte<0acwPOc z2%NZ&I+Sh+dvZ8V!{|t9T{9SAzVMP3#SDsl%}YkB;T@;9RvKyHh>ufjBie746A(wo z>6xnyQ$jNUX-%hmJACrZoNXD+Kq}w)V;aRrc7*dB>`fn+_)<%HZdBDEWk6 z>75_7RnGgkV%{gL1inq*b6&dsdW9<@R}Yzyfl0ajf^Bem)f4ifEazo*S9fuXFF6j! zvOD%iPEM5v=gGZR#~AU}O68We;xb!3EJ~=NEbFD8T0_$Mvcp0TLPa%pFV^*jAQSR( zAHK@tBE@u>J(~#PtZo{cWLY&}teiMS-c7hs=ct1AN|(d{$sbe{fH>HdP5nK{5G}im zM;)~Z&xjYvEqf7P!s|NmS{s<9cAw^1*`k8-$Y!ywF9(gwag8e$yLU{_XKDFUCQeu& zH)N=cg>m*HI#!uDl4MGjZY$OfXR0@ZOX2pci(jh5mQ2;sQ?DbJxJR?ktk#0E)X=;R zZ+1&_g%oa=MEYX6v4?cS9s)`Bt;{=1)wY@ghfb_*FC|v16Wvk|Ob8P1Y5LPNkyp~e zHpJn>9@mGmkg|}3I+PG$!V8ZK8{&_071iH(M}1X=d_7s{Z!L<==IWrhA8h#-rZQ*H zhnho@Lo~LoXe5LT&T;0|+VW8(gZD#!EQ-y!_;cMqJ5`NVT|3t~UST3~6mHRyLx~oq zA6(OcBeT`slRy0%5%Oejl9&7CR@~`MUz$?HKuBN2KpOGE_{J9!y?A}1W0hBMyKTJw z*CK60HX|M*i46yi>DbW8>#2LKx{|(M-A@h=l^UNF54UtPJEt5!UuG)gh|5y{5O#f! zmMP_LuNWHFSu)5y1DthN#6jFs5-#b7PR>LN_lxNj_qUHSCLbQT;(>m2B`-A2R1%Sp zS-O2QnYqJm)w(U(9XTv-vdv32749!18Mp^0&L`h(@}kQmD9)$AZSt7QBsk8e&}~xb zG6{+EDR!IO>oN(A^I7UPS?DqekMps)P10Q^v2i{X33k`(C%KH`<9s%{9gTFEB*gh_ za+~yXnIy*fY<8RYyG&Bze73qxerC%f(U>0Rv(0VtPcfmiyE^Gc`LX55R<|_6fjvz> z-6m_q#PcS`mahJ1Ona60gKOC= z)jl!qka2O`Nn0RY_cUB5S1s4P=cu;_f4>g<*JOG^KWivuN0@$cowj_AI(ufhVU$hN zrLQ!UxuU$=Q09xW0Hxz#gy-GvOMgq2u)UdO(_Z@i6`qDizj&|KGgn;|`VpN4rfXU1 zRb5L&ee|%auIAjUy^^cW?-4wae$I^Z*6KEvs;cIg+2!mrQH#h^6O3&nZ_yi|O`!f~ zqp|+&9&J?~i<}o~wdeEL%5!D`h59@#e*eRrJPX86Kdk9_>cAVf+(#`*>&cV|(^xV) zu&!3(5Kg~=S*>8%rxwuOBT-5fr%NW)YUAe8?af)J<;`U+I%1r*Ypyz-F6_@@9Ano) z=Bc5By3&TVzg8h>7xpV3Bd2}&D*Y0*xZCiDHQHR&Mcyr{=3ehRbnA(xLl4OaJ&XU&9`t ze4p@=w=~jiWc@Y@_?v zZhe^@jOqIK$4T@?x&xo9k(>3xU`@Aw`RrrLUlk zItGhMPJ1)TuyjIJTiAeNo8=sI(b*sWx;T%z1>-+NEXv|IWHFAORgcavo6j zeOki;wP)uqaL5rMXK`4uQ~POw`lf8A{96HQ|0uMt7OBV0hsIRDcBi_~G(hI?#rJs& zDcxKyd4WTd&oQiX&Grq}F5JcX{hiuP#T1(13$>hLb-)7Gv@=4N1(t}*R7}r)Yh(_i z)nL?49YPCeBzgpAc^GH2R19#prm?w}2y0bW#y8HA@Qa6(1Xbap73AddE~V*9>0Qbe zvhrWF0l!n1*sW!yR8|*~0urp{%TaNtz#Al5Z5VRP&Y#AkOt4vnN^LjB9k7_ZF9Q7!*w)Z9 z7n8x5gdM<4X6*y?I>fS^O0$$;!~^S^2Q*U@+F9Kne;L6lW|Ft#z%>Qk^1=A_%gET4 z^hNB~EPj1*;;LV^R}ZP?mLBf6)ONIajLLJC^-b0J6A3EPcwI#rkCSZZH{qi)7ugCg z)DnfcxE;*#mGwvvT=HUQ%WFnHZ={1El03Z+!Sia2`^kRlirkxP%rU)C>v6XlW~$T1 z-mPW@tYU`DJ$1fE+jh4)J|O0*$z9r4cdK(cA7f1KcH@1gHe;ze-Fzljdu%Bql!%qu zYfJgsaSV3dBN?M1lvNP76y%ZEEO-9dz%fEQQ%deHtG(}D#2r~o&(ys?AYt2_pKt)m z!N9Pi4lW<;sXu^kYhxWGwr!?fg@&necE-9-(vZE(`d{C1fAo@GiyW&*UFuW9)GoDe zv<$vQEZcV280%!}&%ECu^C+MSg%K7P8R(ZyjG;!_r{Ds(rlC=XEKir9iEbFhCT&XQ!;(t@)!Q@=^9uknPmXPL=U-d)EYao_bnsPT34gaYlvJ*=~w_-czy z?L8^B;2h->`0kQ8Kg+tH~O(P!Gi&uAhTAd?rZ=qi?Ix7!fIOVmnjYXAP8 zweX6>t~ZER2slgM{C&)2;cK5w9p+gCJ7-gem;>vzpb|B7_Sv8Dl>5CycfZBQJb%llSusYjd`*@ix zwDlgZkZElGadjo#_bd5057@6HKtB7GQ0l$6ogYtn|C_M)DN?#Qtgh}0|GFkW{|3=| zp>6VYseQugobS~&SsY)R>YBY>QTjTd?sJtW9Wo+yWh^2`K)#`P*_rqtN_?B|%!8?$ zm9<|hwN_=XtoQl1I_t9Jef4$Ub)j!lq|96UxkB+GYDbNz`Rw?mn#Rh-lsm;$^VD3Vl;B4nh+3nxb7RDx+ZV`BmVDbr7J1c z2eqeHs*#qXWL|ml&mXN+<;Vi}8H!r7kc>4b>iBr7khAnxl1It&Z&KL{`<< ziYN;#C-nF^+Kkm|Kkc6f)h8ygXoqO7r*9!s-;Dh7y%l}Y?NV>btkBh=84WC_qEg4D zV(DtA*J<~!R)?B;Y0s=ye;;x>&(%GOsl9R=_u6v>$RmsRX7n1upR3JYgYexmL$u{< z)TDwT&i9=4GUTu-{&gHaT3*WZb>T54=#h4laLjIA*-a)jEou6Ol}00N>+Gx&SBEFb ziTDc5jJ2!)H-=(@M=`>q=-*9?wyP7SsWGQwKA6(Ntq8Q_fvkr*|6YMFQXH&`S6k)Z zccAP3BVl1?zRJ6IWqAz-`f0M(tXXG5!u2mi;x|W+Ow#t*)!BY)f00|_tm{sDX%`&o zz=#Xd$iM9@>%8d~R_Dq(M^l=ubxC4(67n{t79a_s;bxgNSd?)Jc=Fcc;RqNh!KNN00GEu`}&+5C@sp%%u_u77kdV^}5 zyZXx*?MH`tWCmx*-QzFvVdYW0zNJ&;tHOK75Yno030UOg5-aDgb>I6qFLHRl(W!mu zHs1H;0QLqukAB!xSvE#oHh-Y05?+@yq%+)2@&wo%q4F1AqxVz5PC$DK| zH?eY6`ga?lQka6Vb*?HeMxCZV!7)8DTaFCsk}(9I11t)4%1TQ>VUv(gVWX?$IIA}E zz$`s)inRVBYV6zcQelI*`P?&$`Uoq2?!%5ab8}qP)hCqo|i?u^^F07BeJF z&guc{w1tb+f!^UdMQp=jHLd&6Dv3L%>sZT0R#w_#?c2pjGXJ(g>s6$V=$3!g!B{$+ z`u$V1tRi(xm);(8dd9I+v_BQ8ky=BMI?{Z9sb;!M4O(<)vebSp*~n+SrN3@yWDfSn zNffzdA{|SIj9b-Zr#tyT`rzCQ%+N~Yd-Y1(bCk}w1dO8M>X#4XBKCG$PnTt}cxIeb z^Xw$;{=3vs_QO884BbkXQn}O~_Q^+0oLPn{K-KyKDdJOzDtZ#F8@cQzP2ZS{@5(d9c&#Vl#@T}>sy5S5 zXydiNZdQAlj}Ft`*{p_{7u&V(H>-oqlkHm1M_Cx@Zr73?RVSLQ!?g8}GSK{Df>!gW znq@bi|6n47#nvAn>VBh`g&t9=@wKzJ>l6TUkZ8x>cW8PsowyZA(iJESlJUQ&D^2 zDm+1y;g<^Si7o07-v*cVXodFf7ImtB79i0>Tr0rGZa^s?-bF63> z*zV2$E|rzSbS^GnpFmZ48@83>CCpsBGR(+slyyth-{rBEsT@IFGO7Jlaiy=%A#l>& zW!_kykc{<^LFq2Ls&ZKfV8@hxgWC(6S7r-qVZq7T9!(u#*Qpn-uF_4SI+Lo0Mf(I9 z!SA|>U3TH5icAlU;EaW7Hk`{e&K1)Dos(AETiboanP(=w6JJ1om51wjX0ANr%BqfY zQCAa!svzCYlt(ag^)ggRI^j$T;gmooR)XYI-wSg2r2gGS31BNbh;v$eX+5nQhta!p z=5fKwn$EN{?}<9!bX=TWBua-BW3H1! z?UJ&{M@eU83Z(3eVRHuJcx4P*eC(`CuQr}KfF0X_Wy+I%wBbdjOg+@~c6o9Kwpm%s zK%6e}<(eH&u$sh9CNQoE)+kr7y6Zm-C0H`|ntOHb^|efQX0;_B?sP`W_>&rFZ{m0t zd^SmxpJF!MsN0$5%sb2SFX16fjksV+_JrQKSW04x7nYfN299$Kb-JD+Y7T?&EiyM3 zlO@@yxbVo8jUDrEaOG@|Xb2M%vN7qmdvO`cfmBK7*&{>8RK%1#w>lD6~-b>PJPG%D_z_F}BOsb#TD-BAF$>CarXJB3|~4-nGJo=C7t}H*9AHqROJ(v0WWCQx1A& z#pvM8SJL6qO?)<4=pkW?uAHSenimu?uwYCeY;(a z?Mpq#x!acg)|YOxv~VE9{>mhasP&W4TEbIm#?S&P$WwWj9=lLyu?0T%S<|WEVsa+$ z{9|Y?)CJo7P7PoBU8=VCDRrz%a*{=VCiNLg{;cnPie`vewaiMjGRs@vg;q8}GR2W> zi9Et2VBZ6k_Xbxc2T>rh0xE9}lm#-8PLdf&WEN#onJqf9%s@6|LnK02h^aJ&C7m|f zoG{8J2WN*Roi()fAVYu7xmu@%p_FXgPbsk*mz}+UiVIz3Fsq+jV3Y=_yF2UkVxD{~hBC?~Vp;kN0{#PEPcYvaT1W?QF|!?(7kYNgMqy?T!(f{L|#Iu5Hk zmy)gD=!*xd2_0G8v-$WL=XO?!Cww(PKNWhmU}^ zMb>*7MlZ6isa<5v@TsM6t^c!{X3p``8hLWqCS3k#&Bo=&)5E>b@O=Flp9T!;7g-PV z+l`_V&-KHZcH>U9@03PN+Iz&4N1n--ZmqMkkgPuY>&%9>yYzCtM!PJzJZ0E2WlF}r z%<{0Dj;{S-r`oH#^qG3>#2@2GvEjx5;Pstq|L_hL$d`DQMT{FR*91}d1?mO2YA?T_ zhDG+F3(cDZPjr)v#$4oQ}CYLPYj9WiUb>_dk~&%dJf z>s~rmaIQ)G_JILaRDvslx6CURk6Ve1E872& zW86lGQ}N#r26Vrq#a?q#r*%9N+$`~P=zXna8x4iYHp!v)u*JyB2Rn2xTd(0S@U(Fc zh_zhg2?@a&rR4xV>4c}HH;PtK5TvthqTt5x>w`*^t_`aF-@{7PJWGEdT$-1GIB!WL z+*0pd=iC1y#`xl|PcnQNBri>BJJY|zu_&_;b9$3$3cHe7IFY(oZ$H=Geugwnr$eyy{_J6DE!_~ zL%fb)b;BE+Vi2q4yrJ$6Zfm9qo?ywzLDq4D)wnpBdo})S)ducWdwIQUy{yIURez7` z7x%LLe0vwov`?K7bbu+DGgE>Ye<9}?^X^>z)h?H{^nJ|4yrOHX_c6Htqpoe)$K>5| zU3-0>8a2E2msI7#L7)4lx1`YjI{Dq{-V#@z`=ieIh*is|j;1U7yG{FFV@i4wGo{7F z+RcAgzYY#$Wh=+=^=}vI18rR|Bn5_YuS=-@%h%Oo-c-Aq%#**aPT8+cF?C&V7AXa$ zoDuAmGsX7RY1?YmQxl)=BiTtZ0<&I^8XC!4o@Msi*tQbN6mZ?xptqubMry*6;Arc& z>W3E98SvKVpHsEh>eP6D>zCp;f`msc+HZA8aewtib^ilunMq4Hi1_BJc5U84wN!ij zEj6ciDIMa%rj{h7;3?jtq&d#X?UB;qu^v)ScuV7>-FsMl!gNfVdPLpOB`Y%>G2+DV zAphFcLCM;rx7AU-gPqgEgT*Z7gNr{n8&L(qAGS==w!N*62~p!PSZ&N z=wg9AJjm<)WnJQMb*}}+<#J0T@#&ip9t;P-fw$i03HiJ^1pI2NEUH;m)5Gb$J3hC1 z)%AVbzb>cQ&--%w6;st?dfw}DySR6aJ`~%{MyI};#c{TcviPGl$~*jRIz}wE8G5^My20`hwYZUpDR z8*Z~M0e(t27zbv8+d&an1vZ220e*I6H;OmGd*BnGgEkP@*-z;YqCo<<9Tb7(paN_L zJHQ@r2sDBp!DZ013(tW>Fcaj1rC=4<1h#=)U|$!zpYjfhkHJ~+Be)FYH_Ym%OaQk7 z8|VY%_i(76vK|zJxnMdN2Zn(_aAAO-avHn?YQS?~3s?u1fdY^Q62J&M|M~+z@JoMU z4?YG5K@Hdiwtxz-0^9+ng9%^+2myXT0YCO55}*<623tWXCeFdK{m(I6Cb18sc?9B2fGz-!<+umzNX<)9GU4iZ5$2myZJavwjX6?_5? zfSq6~Sl@^5|1?Rq3{5Ub0XKmV5CDGZO(?;~;2_uoo&XPm6`&Yof~jB}7y&{+7w}6k z0S2c*19$`M01tvvungQ0Z1+<#P;BmnC3p?gf+OH#@HJ=y7Tg4bVITp>uhE?!W@A4A zi~`{x5GbIvC!YhH00+PxuoG+p8^Ic|#LmAvKn9oqB0wfkB`PxD@24G=XEF20RD0fOTLwCQC$+>Ka+FTls(Ab1IE1?zwf+yQ2S1Q6Yg@82IqATWaq zT?qha0w=(mU?SI5atjKI}DJ-483RpUGn_=mmgf@Tj_$MF=J{@Sg|IwlFGe9Ac|2Z>A=0>pwukPQle4U~bcU+*=Zv95Leyf|eN2gTJi?{q$?Y#7Sg0dC#|5t*NrS(g+^y=Jj zF+sTuZfz5zNr{%+Nhe&XcQ!V~h_nt%Dzw6q%5AWuUYXmSGS=lT02X&aW2-++wESwa zk9WCe2x$D$&`U7I4@t~i^y1!QUx;4JJ^H2S<>%3_Krdg*qc24-;qd6oI@pUp_Kg_G z%RCOYqVM>^o#@4({Df=Ji-+=)XRZ&xKDWKtiTi`-JNkbNeFy*T?c$+0ln3N@y@yLD zrYNgG1=!@~Z5{MGQ11dYpcWhhjo>Ue2ikylLW&XyLV(A=2-JlM_7r6&3LQjDa-k3w zG!U>x&;)eQ3eJNzpiD?nEFcgBgHR9wqCqT304X31WP^NA2$q5spcGVqO?Lim1>3<+ zup88XT5tq3fJV>+bkGXgfI_S+AP@wDP!Iv4K`clBDIg7GgItgg3W5CQFT6)tP&j`< zbw;XXVW54sE7t|PIRfr#xKoq?a6EeXMu~7QI2)Ej_=;hUOHfw9ec+974|p3K3h#oE zF;VuwEXynV;2`)QEQ{2~U`|F*x}88F^K_@-e(>4Z+O*p(10-CbXyrH1MT&PiW*{0Q zf_zX6O2Jl80~$aRXa$xG+=B!lpH$)@Kl!wh5#=YJSTd>nM*yu z0(H1sy=j6yMH%eYY{g=TTfH6iP`7#~>Ik=bH|iVQ>KfF;-0E7?qulBvsAJsf2Gpb7 z>PFOK-0CLOH;G!}ucNuyZPAK4)~#+sJ=U$3(lE}gmQoStR!ixKcdMn8h%~aqUP{XZ zw^~ZgRJU46kJRhpMoN)g3X5o@IHkJPQmm%A)l$4}ajT`6-R@RPahu~-OR>v!tEKqm zxz!Qhx-wb;ESYb+n@_tr_FPJ&kwd+IbLCp^c4{=QR3+CtRXO%Az7xFJt6Yj5gy>2npRgZYy;uzGU&XuD|d95dB<<@D3j#`F# ztZK26qAkA_b(;CuRVzu6P{V@WMV&UGgHSg-lVPnIFq+u=kxg59m>ErWZVc0VY^PCSrr#9PF2$guxxhYM=* zf0FG$Fm5t%|Kxeg6WzXX#V)kP70TR}lR>yGytUaO;hS-T!uVFw-wna?qdXU}lwW_iv06H)lt(pyX5pWjbdfU`duhBx|eLnFB4G8iQec7q_-Q#bk_L?ej$DW$sC zFP0@<-O$KSKCpx+}bya==xZZYrTz1dg_tMN(J>#01ruPB<50KKaTkh z%){O0ZP$5v=?AJd+ytDz`ZDn+4R`WvXa{rgrx0^%84tyy$N`6j)|>`N?OJ)Ro_^4rUT*`K`dL z;J1|OM|^#km`sXh_V*pym9S)kQ0xUOlPIT3J z_V*35cXOpiJe?a!og?Ta8#KVu4m82i0XYZD*KUJ7{SIl?E!|U%zDF=@K_3D8!tt=D zzaj3XqnAEMF6`-V3`AdD)8F@_q%n+p#p>Dmv%`9jVH$4*CZ44IT8G%J||P^l9a(b|qMI1)x-7yq*A{UpEVl`xoK1&qp7K z{b;vdlDXl5R3*NHeM2PyM*oFm2KO%?{g)l|HuPt&=;*-r^xt&QD_c{QS0zule-`xeD+QazZJ-!o@bcYa#hs6(D*M3LcN4C`=h};Z_U)zF{_Go3-SB7Md~^4- zyQeAJLE;mXHn8uBRPFl@eDk#JfAO_zF)#QImtLfDZhNZI29&2L4ImhVgJ_Tdrh^QS z4~l^el!A>w0<;z04t9cFU^mzUYQR2F3l4$?Z~`=f)4~}kcI99O;}JAxK^ijyI(!ba zg7ctFm?7sSSb3V_4=f-61cD$C3_?IC2nP`$3Pgj^AQr@f6p#UOK_Mu8nv$^*#dc5& znt<{Q9)Sc<07}6Qa1fjWmL0qhgn)1`8f1ffPz+Xqt)K=p0n4)l1muDhU>m3f=Rokl z=kNd|0!hkjxENG`ZD8MX)xYfW{m#cL{(O@5&%gN&t}gtWuWq&1zAgQ7Mfu*%N4=62 z%{y7ieJjbp5}#z{5Ez-8tRw*W^?PTkva5Nj(g==zI#n6?*;M7_X|89!OLn;tcjAZq zCgNUxLtrucC+~U}psqe%@0(-t$szX-s~-H8Z;ZvBdw?VW1)vZVgQdU*R)A7a0XBhc zU?;{)W>=6P0_JCFp{WeJt8bRngcm~SARUj3t?$)m%=i%UjfUo zz7%FiuT;R&nb-s~lD8{cQOGcUJ1mnVJ7MXB?1p7Br3RMCl3G~0?nhvmG--fk(xnlW zxsxVXCS`P3=1^K;nG$G&r9Ys2OzJ=ucpw}I50WW{gQP|n2EiDF!=dnCI07C5N5ezm zSoj7w0hXbC3LFWi!BKEFJRHu4N5X}$4C9x=GJ;hs|&_>;=ce-f#^m<^!jo?*wPSDx42n;9}Sp-bIe~hgYBv zfXm>{@FutmyzL*9X)B7I7zDz5;I6P_)NZh3)b4OC=0Wf=xCh(__k_>F!Eh_w8@>eh zfh~>X2{;H2fkWYba1`7hj)e!niH$T4p(xTY7zpRWgWy6q47S1Ha49?(-UttYx57i= z9qqhRloRA6wR9ffSY3W0BeBjB6i(QquB0FQ;I z!{gv=I1Vm=C%{YLiSQ~o0j_{2!JFYJ@OC&6u7Q)_gYZT06q-|!aCd?J`V@M$|>>!902!$gW-N~G#mxT!*Os1JOR#! zr@+PVT^6!?8443s)@E1^KHmE{on*R0G+X{9cqe+&-#C%F?2#$1}cDD(?NPk>EuEP7HxNrYF!X>c_hioFcW3(+URvFN>} zb+BO|txqZZ0Gxn@54;gQDQR>Nq{FZk{nPLc_#t>VENQe4{u_J*egT$7M_RiR=$&vH z{;BX;^wO$jqqo4V=%10+=@N=}VT(>r1`dMXhC|_p;VAeGI2L{jPK5WsY4FEzF5CbY z!neRSxE3yjKZNsnp)b4<{rm7%_zb)Qw*LdgZWQmp``}mMBXAvj0zLsZ!8_n{@QZL8 z{2A=soT@wm2f|Ho2)q}LfZu~h!=J+m@F{pYEW(o6@JYC!nc{K?MFih63|@-GLO372 z^hj2rFNPD)4}mMt7s7?a$PeC(emY!={RntF`g`D|*!#n~&~Juo;Ai23@Jnz5JOe)6 zOmq1f3LS%eu)?>Kg@p6yD`4r7NLNSs#?_HnfyV)81JFy4qyl^C8U>@b!Hw8c5h>y5 zUxuS$>5!CS-WiTZe=D5Ea}jWg9fKkiffx*cGtke6D|ny_oR6O3YxFLya54Hv;T7;K zcq{G#;WG5I#T?f@|^j zCU_J2HE<2~K~ny=VUQ^fFz5mAM4tukfwzh|yb*4IpM;y>o$wLd_k>%~XNx`hUhpOK zIbzNW<6+CWRHYmag8vMM!pq?(cpL9GI{LlgSPbTf10Ea%C!#Na)8IGZe7GK73h#zX z;Tm`od=%aeABJ@T(g)s+J{Pup#v~KG5B&l71pIgS9Bh9Mh4;6q${*oY9_$N;p#Kvb z0q4Ox2~Z3?8vROGy4MMC0{RVb1NO0S8v0VW5&c*=7yVke4Sz%6LiBTC8@vQoKBoNl zgG(`(2iNf67=1xLfL!13^3;1qZ&obg?1wev?`t6!Idr<0Y^XOopp zVCgf}J1_a3v)D!IT;d_(<&yFum@Ww^vg`xk;9p#MF%%w%J_44~E#lu&Er|5DlJeGNjWGf@&o6I==)mPc}t*6YldhK&B-|pI*SlF9de3ZcNe3bWpl$h}&q6>Ga$_U%S6}Ir-8Tmn} zRh1B|M=UOwZ<`-3SwRVTOI5t#5z)~L7E$Abdh}CfXM|@@nIvw)uQL=Kk9vXcVz?1~;Qa7=R=CWK z54K5r%FnO6J?gTrD|MII7KEoxGW?Fd#_V>(@6jF2GF_=KFGXwf z_Y3H>?R=8*;d#w3z^}jg$;&Q2+ivibGNbG(3Oixj#ShsPC+yLGHAU)%tNQEhH&2wu_@>tFCpt=Q_`VR$ps>y=Qm+KkSR`*FJybs{eK))G-^bb#VO)M!x*N?fqZ* z-}WE;S9@Pqvfa4Hl^p8E*QP4lUUO*{O4|J8)&K4FoY()i{eUy&Ib^jctbD|U=> zDW*)g`PxT2Q! zA_Sa^Sz)KE&pwD*aGk2;Ql)u*?_m}|yX5(P~k~@nRDs#Nj@nC_?Tv7or5VBwVF#Y-h1%B}MF|{2h^C%H*^*upeWJFU->yFIkwufV(FNH@|rC%7tn3 zNpu@=%5^87$6$dg`HZNn5w+VQX^CywVr1IwhMDXA6{7zCI(ri6CaSI{-Jl~&m91Ei z0;N=FVfKCLZVN3fwCpHN+t5bRBqr(h0R{mPq$IVOPlXT(xzjOX`{`BNz?w$AUdw0KY=FJpIEyZCkgZ1L-(9v#K0oY7gL*c&; zO)RfiLE415-w4TdRlzheU=h*)GBms9Rl=#pHqcn?-q3uPqt*dahV`!Tb8r0j(d)2u z+mx|(XQ`_?-{UF)VrN4}*~;u*U^vZT^?Cv0!_qu97(LJ|qb3Ee$)?-9K98$5fWn>% zEhu+Y2LY_g5c}Z0{l8%u&eD7fqW1Xred*wAr=EYOh)0tqXn3{3v=~u zOpeW2h7^wx2oE*_x-f}dY;9-4A0QYnsPzVHbBXayAG}Am0cJ0&2Mh{CFtyNLVZ;71 z?ums}O9Phfu~ui4mVscp!o-}Vxi+uYT4sa6vQf8mM_IPd23PkeH0>Z1nD_8D=L47& zc)-V2G8I~-R{DG{&|hW%Gs;?OcQxY%hGct#O**)oW)E8_ygtBqD;DqO=g>Hru98a7 zc5ieH-sG$F!2EP`yfo}K=*eNTdXa5EV8*I7pN?+ix9>zgafGOu&J=Tg8>=$G(0VG`G0=oq91dK8ck#CW}Kh2!CV6H(= zYq29}p>QPy4V+TqvsX2v&bCf4AO$~`icnz3Q++OXGam~O4yFT^g$)bIaal{#Dm`A8 zCj}c}LfIuQX9_j|sm`2ytAt8X&*8S(VwcrZnq#eXRr;{kLJK`sr`G{SA8ZJhCXskS zy8agNLO6LdB;RJ6+Dh!LwlJKZjfe+Nn|6zBH5Jm@WBuKJ41ID<_FR=97I2l4fW2eq zo4uP0xHmMc{15jYiz&cgvqZXDG9e6<2f;x`S%19G@YNxCZkrQDX_H;JL6GKfdCjmL zKw$k%n{958ZeFFK(TrL;1#sUQjs5W${|{J3h1*x#auTkfwv}gr4@8Jz5+d3x;~?(k z&_Y*=x5RFT;Ae#7ddtRI?cg|`+)9Vf?snJ$*~^QSqrOOXkh?NMhT9#E0PrCiCl+D_ zxOc7%LU9Rr+-`(y#yKnDa>{}@SXHM6+&I_ftTdy+rJ&ihAh0OoSR5WhZv<_i+>1`2 z=nZC2GBw}ju5<@5dxP=3S;z&JhYWH6-o?TjLkECw%rfI?!1OR|peak!4l&J?p?M4* z2`^p`DlZMiHMnIJjLQKKyJ5+)LpC+fJrSU39``XRqC-Rk4=pJ1*lf;17swx3zJ|q` z4N&|Kc*}4E2mN9^I))xDha=lL#f5D*h1Cid8kTsxOI~k;PH~n%qJVngOepZ0WplV8 z{%|G_&9;$O?F5}{M7WWawn`h)D~ftimP|-X0STpGbw)`%-nW0dP-s>N)|}?5M0o|W zHp~kpuF_Huglr7EX1o@U_nG=zP%ee#kh&nOo(saLEwqDK+>c0&v3b09mlNf*v!M_b z$JlMvc~dg&Q2uNQAMLET3*$wDLH@3E*iefR)(Vs#Dh+ZV-bGFdeaPV|wmMQA4p#}L z2cgkUfTqF~)gYW>LQD|K1gXQNf5SfzbpCUwX|k!cKFH)yo7hmPgWV2qJ}h*#oCiaP zndD{UrsZSUUQ?R+rYcGh9>#zg1i>iQheD`IO)JO&DIn6QMA&3O1LxR_JyuUG_E9Jb zb2&x(XPz|`uoJN(+6 z2VN*t00WMPGC=SI7X80**`-)a8*H~@a z!BG5l7^o%<;8bV}Mt`mu4xT^X3?oTEe)M8nz|hPZCb!aO1Is)W9L5A;;sTmlhO^4< zaXFEU##lXel;=~h`z+~W%n%#kzZf+%MPN!9+lr=^g50A$vX`Jj+e$U64cBe)n~jNs z@tE)m)XkVQ81LDwF1*m@sjxdC1vOg)HrLnytzs@CBCXm@@uJz7Gbk~>8H{%u=tu5n zE3PangY^RhD5U2Gvy;#2@m0E!myU%OPRAtTec8{#M)@40oz)QbFba*I)9PxZCBunI za_~hvD7pZYX`1~m0`EW1Pc~L3;sgCF!wVhWpek3PW0>|BtE19}tws#S}rvXMv1Kx;1i3DU#3Dkm>_z)C`mVSgp zwg+UYThW1jCh>a%Q3lM^>w+>4dj!@k_7(^183v0PcO?{SAjtyA(atiUlpUI7v$_K@ zG{Za&aM%}(0M&&p5IUfxze6BxRJ5XA0+*<8Lk4Ui_jYJb8f1VL_!TI8D!t`s>Zz4e zra+VJ$M8@@Zzyr)ln+rQEr&$ICuoi@1+aKxC-1HU#e( zvC&KbM&l5?tEH=98H)Ez8;0gt;A_$4Da1!W7KNZq5aM=(2|550JO+2-13>|aXe`#r zco+x`9%1r^xQ7&uh(b*t%&1r-SZN8GFuDd{^90_p12?I@&*8WGtz_&x{D#7B^Aj2ug69#9>m35L(D7$Y$=H-XlXbJ<@;?IvCkH$JCqV@N zH-cG$v6RE}EMFKGIef_AqwsdZUcjjZ=r@1S_3*eL4n0zf9;byzX$_sn`%-NuExnnB zO@uERr|qQ6;W;TptOuI(0pkT89}$U|jGCQ+oi{G?crQ!kjtBuCW$6Yj%+Ig8&4*X+ zTz?O`8jp#17h@-ZN2j5GF4p$*|A65&A3e~&v}^vjcfvmQUGS*Lp6uuQ_KZaT!wdb_ z-89hfCp)f7xHUW%TIbaM-(P?5vliOtL;L^!HC86$i^8GF^<;xf!6jqFk#;M0bV|kl z3h~3O(F7!^;HTzEcmodH*Kht5&BNh7Ml%GvES`n;1hs-#&2w-YqD}wT7XlpG+CW%* zH~pd|chmQ0ExUVwEi3OHpy-vm2Uxi3?g3)g!3%0y$HSHZ{C*oab}hWtrwu%AJ-iI3 z73Q$hi{J%Btq5$-t9QefphH+2j;?ROu@gJgO#I3KBf)`>FsdCmYixGlgN-u|eAqx- zfi;4yqS#TJT?)y~?yJRPV`HHtL}j(wj~HV9^)qrS;2s=0<%Be#_A_4t(+|Nuh%RbB z$ayr?FLtPAEUdsY2BH&6sSVbcK(wS*y9@TE1V_}2I~91Qk?F)aV}=tSXskm=Upetu z;~ytJ)JSsSF-EovfAB%G|IlWFtpx7I!$8JL7e2^1 zFd)$0>aD1vB`A4eS#4II8m ze*8VoGSfKu4nEqyL|v`!*7j>xwd-1p9;@f+R(+~ot1s5q>2K@D^q=&PHWu*VFsx6SU6kVt!|m+2`4f>?!sd zo5YReCUBd$Z@8P>VZN6zT5t#_go{FvSS>y$z9)Vsc9&vhPR^1ame}buB_Css0ecd*?cmL>%b|TKb_mc)pPIgyZB%DKlnspqBvPB z5zEA>qD%C`Ak##@Xo!Akw)B*=KzdGEBpK36(ks%d(pl*{>5>#Gx0gH0Afea@bC+QS z;iRgl&D3_PGq;7W=YQsJ@+0NZ+QZsn?IjJ`5fNxJ2DXVTrXQu3_~{k&4Gv3=z+wS8 z8l-?RGuZ*^MYWwCqbKQ^`Xt?{WBC#0&P0-YkK9G>CHIqu$YUVdlVk>UjB2D#QfH{I zsq@qY>M}KfzD)l_|3d#x|3UvlTbOXBiV0^U*^cbJY&W(i+nepnVnq?=)}!;JKa1(e zcjZZ*Or%Tb)$|6s2h)d%V-wj&*eUFTNQA2b(s+QF zOq391#8kpXc!_Fa8sR5q6La}z_>KIV{8s*5{(b%{aj7&>o+rN}_yd4i>SY-`{`8r3|+Lqo8R-&zdX`nrkdm_x8$S)GF5<7_lL=$m`=tI3lHBeVU+~IU*x+~p> z9zgH`<;P_SL`12&>QUFK z@2Gp!>uMM6ek}>?ccJ#GhBX8v)rW{D5(z6cotjHo=xBNloyx?s>1-ammfgf|W#3~D zusyj4xc*!MCvksqVSF(^m7mSO#h>H}ffKTXiNdo&gxJe3&Jp*DN5qTbQ0atpN;M8YCb%F{m&fS$>G@0}6T(vL4E9^L ziCw~Z_*(uo(Eka(iSH=%5fX(A;SpiF@TyQR928Cpw}o&qUd$6q#VT>O=wBgj7I%ne z#4F+*u+$7(YzfmqIm>RC)>iudTHBMzzQPn{I1?o7pT&)1f&H_8AQ&&LbUGG=l zRX+eRUr;StXDvn>sL9$$;Ch|*rgl-gt##7-=>zpdJzFo<%OI-F*VpK;>2K(VATYzk zFxXN7)xaQP1n~&?LOIy~GsMfp8satLBchS`ia1YPBrIeU8AHaB1IRRT6giVzOKyia zvYR|ZULyTns02!&R4SD!p}f=^V0JgC!E`xYL3`+@X#>L3YI-+)ly0QIqVLf6Fi}i5 zW)L%!VVE4o&8%hKWj9FtlIP1X6>BzkJd}SiX;%#4oilgTH*qvp=7czlfYbOZZQklSJ*z>IpJB6P%44K zUgfHygE3Fg9NLT8KJ6#%6a7=@@5f@>nNJ?XljF!osJ+y6Due!#Im>*@Tx6~=*O*_K zn+(Ts!g8TN8L#}N%vG1GyVQHMd=1y*^-=m{2+xPnM2L3guJoaV8^X{oqJij2k|5}# zvIQk1ZixIIxx!b^j{%S zwKE?Az=+<&05HnYgafLCoy0yOoa{h$BXuyqNn|CtmHd#rM*c}A`oZvKP;;oysY_G= zZKJE{`SeTlW{7l+^mmZM+A%$u!C-2SfU(VD7Bio)4F3;bEqpAj5W}UR(qw7BbX)2s zv*3QDA}FcK6lJM$T=`MK)qbj~W~qZUtf-y2W%^-a8OX;;?_pK`IRA$jCiRf~eI;EQ zCanVw2g3MlFDkDn>y)EPlM<)8)duz7 z>SVwEsQ#EsrhQLx>4PyKBP^8c)(VIIiF5E_MZ!jF)iI{C#UaU2v{JH`EwqfUt-Qk;|p1~*=QU+$*NR@Nw=DFZdD zJ{{`0*Yz!ss@s{BQg`|R2twWY7(R&~&QIoT{8srmD#P{!+^`oL#}X{V3ar8=Lt@Hj z3)yk(bhbvG3Dv+tC{0$$ughEHr61uLaj>&C3c9`l@Ife6FrqysKva!`6vq$>kxt|g zg*)sY;c*uDFWb-V!)IIajr%^vr*&M|-rV$?i0omDvHW9vpkI~Cae%v30s6c0?;Zl zmLJ6Pdb$Ir=MeLVRm56CV8;oQgdzc(X@nfYtI36trjhu-Gp7SvbAYirU~Mrlw*uHB zG)5CNMN8K5^+J6d6q3f8LwG^hsz@O4$05Adf11O#M4Hb{T;i^CP2ArcJU+^|=R5FG zP!smzWBE8ffluTKp5X;PozLM5`EmRtzKAd7k*Fgv2Z*VO_?y7UFtR;(cof-{j3#?Q zvWX)T$V8GL8B!n>GMP*#v&bAWpDctpJBchJOUZKMq7#c>kH~JpIA2gOW z;IRqGkSnsd9Bz&}5Ax(f^@jSl8m4v7x@x_&I4u$QQnYj}M>94a!CjVy9rqu_hgqVd z^k`VWBF10~cCG*VCuzCOVoCm~o7csfmZ6w~PU*un)TljX{LL8mt2mMVw~8g6#S|dx`y# zy>2XOz<2d663fM9;_G6)co53;>*C)cJohWbf=@xmWLU@>k2S)&c}*k!$h#!2ptnok zzw}ew-u2am`sFi^6-RgS-e4s@i+Bv8>_Jqw~CrEnkh_ ze0J?TqGLqlpt)IdZ*{a-Ea6z#EDK!BT)uPXPYENB9^P9J_h|BRoGfIIC5@T+@weZ9 zGS}kXcJiV4&6UY{KWrZy>FYG_#dhl)4;`5E+uJprLSA~OyLj~|x!ZYg!D!*@}!9+gU>~;UB2gwdtTf|{rl_7ai=!*?D{$W+LhkJRt{~t@y4L}i?ErN2j5>@ z=WW=SyzjpFdxsz1zQnWblRNbMNd=oe&wYQSed@Xix)J|JnS0Ma*NjK5;wStpDbNhT zP9XZXh$u3Q>>k$j?_Y=Bc3yh!zAi(1xMuN(_+*9cEd_f_dm1hh(rwDyWb$*D7mJOSutr+M>4kX)52{3 z6ANw)N=k_SZP~)7m4bZ}Kd868oH_a0gU@d7Kk2#H)i zyd~oIA1b@E%ii=%?~Ri?=Nvv;elY)oF+}~bk)BImM@-AeeBtI_gLY zaZR7cZA@XFn}&=mA9A_5`|?%W9&Y^~cxCH~d7uNYXe<6H@0(Z5$30GLU9mvkwG|J@ z`{or~@^yJ%zDj>MarL%`{l(@Lalrk>yoXEWeai~EPo6iMQy!+j|J#(%b~E$L>SG<7 z-^#dTGBYpM!N+vEjmebiCgBe6x|>YCNL~VFN;T4ElgUGJ@7+xaUM7>pWcq!rmo}9} z_gov(&a|IoYTKDE^=c8O+sExpMWMK#YiHU$9Tr2|nZh`Qb~33oWh4@o1}x}sA&cS7VmrAJdSO)c(Portwrtr-58S? zzt3cHHYviFd6=Bd74_Z~F7qP+j#z#kT;4nM{yuY;Wf~ zzSFw6zs{~|AG$9o7cxX$J6ykf8{H3^L#HT{TP(~q!< zZl-DPDNc!0{Z`z=wbaw4SezcpE|L+>116Ky&C5$XliZ##pR|*^NORhIi6@fXC9?Iz zdpnzEj_YcwO0!vt16;*6Pwsmaj?VtVV#-TAk(UbD_nhs$XKCMf#0>YH1?P$_i6^GL zmuVN5(8jKQ-oV6^zuZmsmh?CM-CN=BAW>0ot?5UK716LVu1#l8*jL3|9}lglO;l(` z2M<%;uHvW0nH=VZ5Fe9?r%C?I4j$U;ZF)qOfy2-O;_EkL)$J+;(D*vfkWzt=y49wq zXC=T>?yH{CdU*zRT?HZsMadAOLuCHWe>BYQ0L$4@=cV=@+FZ}>F(eiQ%cF7}W=N;j z^du|d$6%AGaU0KV1bdc0zd)xRvndfam2M4!foWdJpsj zqKd<9Jv7C8vSe5P+hS^nL$$P;IZ3JbO1GoFRzwv?``9uP46&vDhN^i3F@KIMmY-4 zm(ZW#)h^kk5B^47y4aQ?QhU2g?Ru%*3ua}dcjad#5Z(&-@$(Y!hJ81mAw48<%Hyv1 zbqO471^jrk1fKWs&>TKPJOx$h3=nVl3^j-l5Wlt(=iNQD!M?){juS*>D=`AZ2fi&j zcPt*7zh4V+5JX-pQ3T>yzm|OBKwN1huDW?>-8;7E)Pi`ZV{Wi?C)KURdq18ef!^R= z>e$2J{%O9;O_kj1W)CgOzpvrrTOc0rpU8yvs(+06r5oD6{WpS`8xRpHh5NuZMhP0+ z!{O#gY3!hi;mkwZ84v=gqXAtFE8PKI4S3MV@CY6~vhMwOleF=Y31hiamLWP3#K}&P z1`!S7`%Y83H&Cs<=W=gtGphvNY6bjwtORztv;~2o=Cx00YXVcv%`>&LfobJ5Yn9ba z$22>?*yii)e5@I>=itZg;93?@aU#OuX?GpG393e7V#f1w+}Aut7`l$9SXhg}w2jo9 z>svtI8p}sQxr^uJ8JwE5k1Q^k0nO^rb(pjbK?4Hqm^cM1_Q$2f>RN1ZEwYHde`yzk z7Bagw-Wts&Ym2N84MZU-QVv)lZ7%lbhcIKReB<}%;Khy9dA-4Go@_AdB-2hzwNbMM zZ-k+jf)~S3SjZ7Cve4*Rk+RNe*Di;Qz0a@-h8IfRBIG7|G~9344a|om^AZ_u-=JL% z4bYZ`cJd(EuY|TK)cRkxR@}4oin!mF1-8m0Goca6>ji9emv*NA|Ll0)vlIU}JE%3@ zRx<0z2_Lc(pcRK1K3%%@Up|p|Cn@epMR@Jn{XP*h@Sd%W*R-$0dP|?C{J{A z#s19>wT?|PWdnF!lRlM(8$MmUN?zJBDJOJ_9~*7QMfChm%Zx}tA6_4kWIl35tB+V5O+pQDIcC~BLeK`|TExOM2uP?Xku-(0uMG zt=?t}s+fu=#2HsbeOT2ApY)RtyjO9(aA!cS=CUnfP1>U9QRePVT3z(kj+iEjJ%?A^ zYP0x8V;g6{2c?bsrgsZsSgbFL8O^S1$70?!Pyb=xqp`&d>!;tl$FZNZs2&1*@3*sL;+kSvqtuabG*kxa6d^Gd=kyi4!2-|^Pm^c>O-$;LK` zztz?LqOz~wm~zCyD!D|0Tdo1lCgI!NB3DeC`BKC3-FU~>?bT6RVJ=SyQD zP(mv{8*gsXMh~>1s^$+&V%N0VfiryJOk+Srv-xckvN;UnzRA`AC|8{+Y4f%PSff|P zE%vtO4J{?PGaQ_jwRfcD!i4n`tlJwc&NQ2^ zou8*Zd9uRY)bsq0nt8ATMOZM{j_a|(pbLeJHlMc;ziF3 z+T|h1)}Q}_7;RZRI>YTprn_1@zaciGC!qqaQ*ByQ9FdkYj*E4eue* znXPCM4S{LH2c<#Q!9;+87xS~AvxK`rF5~AxqO}H!Uy{fij~tw8;^M5&=x z3I;rK7}Q3hn8-J%y+kb+6Aen%Lp>ldL;}cc4i}&m@x(xQ_ppctUQwTNe0~2^lU?Nj zzl~{c5`Kno2~YY>dv#P#su7G$-&EWi)+1PTxQR)xqdE|j7jXM;=p3bVp$g3rYtW?~ zD=_GGVehG;J^)tBz!h6SVw}w9yFn?!j657=Vx<%cgU|^QddLte;8my$c$%9}wR zxBZR=&k@_;IZr^E+YKO?a-4-6`%3W$JEzj{TyRAf!{9Pr_Ph4X=#YVg{nlH0Qo#3v zQbYkn9J9qGpy+Td%I8V&14D2zzxlh?G&T z0w%u4ULz(5D|qMx7bSJvMv@pP9~jJd%!H0?aonI}FGzrdcwGVrL<@N~Xw5%8Fw?M8 zAvt7X`F$pG#QghA%pem}T1{XifL6po)IQ&iB;QXL+wa=L>D|gnw1Xj9;3(o(q-Y|F z%Dr!+DU)zPQ}*uiNjetb01RQ3^ zEWZD?)@7`<+)yhq1kVwbDjvK~?INiut!i`l9ngw+3u6$qjktDo(Eb=3T8^X&J6jFSqaYm_;_>_J)B_SrTkS070<!vRPi@Nh-t13p&G?uYGVo^)%FPkrDCR;MNJ1;{Qeu4rmYrMv(k_heI);G# zt+Gpa%3qXOBg)Bhkvz7R=p1noxnnBFLxCt7%Z?G4Vpc%0qCWL_?O)pPi~#nRrexS~ zU6B!*=Yn0UVYig0fl|a{ARVKGSt`*a$4Tgy?$XgEe4`YaNkXH=mq2N{Q29|3`p^(s z#;?1ypE3f=P3b1_l7SWTbWn;2BE@u}-Bm0lp-Mw&4u4e&{Vcgw*$3uH7QX}rT4$<3 zH4$YJ6AVf|-NuVy1|?g^#9%eImqgGH7V%gBSo+hnIaUM$$B2d7*(BG-5Szs-rBDe- z$2f5#wzX_^B=ikPwA5mLg{5m3Cs-Gl0Uj~HLY@Ii5wXzZ6;&FR|AiAnxQtHRo1%CUf3-O{x^ z6Z@KRyExJ6?FLahU0`SPB%42ys;G&PZuiAZy$W&zCPk5WzHwVUDXJV&Xmdz8rU)}` z_h$blu*6T@r2ZUkwUFQgkZAEd1%UYALFst`G2yuvx|||n3gLMvAifaXE$)&s&+>vP1wFXea_X0q(mKk&*KT33gD3mm(hCNDu|pT?YcgL+40nY`cijP6^Y9x=pN_37`kFLZ|AT8T%MOK$`q(y+CRm4s0 z$je7T;_a4Pdfe(NeOb)o!9wS1FzAJxo*vvuzI`eo!?#pOiGLU}v@9-=1|u&Eihu|=U_HQ>D7;rJi}}Wk8ckh5sKkd;~|ABW_V*`=~QY& z8xtC!kJLO7OCB>@Z$IuawSLPq5*j=()=8lZ>rH#kQNs@%WMO%;JHJF1)QR>}uB|uH;weL^z_CD8#HXl1?(3Uw zdOIGMtQ>KQW|kDBd4_MgHX<*&H_~E^q0`qr?n-c8E4+kPf>y*vR1M#PB!3lR%cczRM>yzZZT8i>6SCKDiFfQd^^HWjtD{%CAw5@>zJ-JO%0|E22}m75LuLX$e`V} z8dMTdOgwH-DWFvGutCTbOM6jhP_hQnz!y^`fN@yN3y{H_{NDajE!e;d9Lsq%@E7y@ zV0ZGf{5}SE7v5^47__Nz6x{F!qH>|7i0^@8LdePzv!w*T0~r407?kWbOpGxolRtP~ zBH5s%OBO&PRswLTfJgYJYug{_>JL~IzgS!9u7no=|KNdMX59XKAjUyjYYZ-W5w8WU zh?6J*cFj5ab_X;9Levt+lg1RU;oWHlkX_0vMF0cf0b zT+le_m`8X%(!4YPliReYa->yp28RhyKePCDkd6W3u%wNF@+u&)#}F{9{2WL{xTE`4 z)DKiuvEC59Ns3IYGN?O54HS#-Gh^ulGc#Mvp!IB^74eQXdwS3V#7Z()^Lc?}JO|QY z7oBl4md|TR$j1;`z+aU@k4Uby>Wh-8{34KJmOxp`zO93jTLaUz|4fhW2wc1sC=1ya zVR8oG4m0A~06w+~>C_pKkfaLgjt=j@pcEq@ZRfRME}s$A27^u7+BG9OCJ45!c53NR zi+LJoMTDc;c{Y+%u_jJNf0_|mPO`fV*@e7XN_K={^trzaWA#Ek+YyAEiy==tEXIDv zUNSM$FfoUplP3O8N}$|6RrF$yUjfPktVX^t}o>FkeDG0)oC!!m9!PFf%Ngz~>DRn=4YE%>BIpTCZ8bN#J3q&oN~C z@|#3QiX2HBovE3Or5OU|EN%@>*H+Bx92AUp$i)Q>kc*j#7b1-yP1`#wJQ_)H*$K}3YYTq5HhiaO3+NK5n$PQ zkwg+A-It(i=etAGwT=bRzJx3@tRcF`Tso#8#tdFj!H87i-SLw-(f-<5(5gs8 zUNxh=BXhkK@imwg^)@@-JUkUuM)GG3`Q`i^jQm{Ca}>a1cW^;bKE^b~1H#}>EG__Y z&=F-0!og#bEHks}$&H*(hB|$q-&foO1k1<7N+5wal;Vj9Cnb%ZwY!OlK_#0VqXVxAwNt#~k`oUmX6E99q1 zNjwe`ovvcYM!dgbD`%^sxdZvilZPS(ybc*vT$Kp+>0%>EWiGsTwkLT8K6MZnVo!U5H}E{~)dCd5h!z*&kEQs)gxgbt#Z-Uf_d(xAJv()3Wr$;ZE$(e}>khs>|e z>k$O$V^?s&0HOZCn~~<8QCf^6(l?5{nd2?{#2g+UrR6&MmIFjwh*IF;E%#%BqyWza z15d=Z22}`(>zE%zvzIJ@d}6NxDy~TYTbw0)k2E$C6@|S@eiqcRn*`+uZ}P?41|wm( z0N6mi_X$k#ZRfWS1Y|re6tT&$R?KJEwD|ck(O{|KKL8!U*hCxPa8rc`T;g?Lh!Mc; z{E|&8oge2*fR~|dOh)_W$1|IDX?|`$Vl8b)vNxr@2jL;M*n!X{5x+PxwZ&j2AX;eg zE11j{6ejwSW(Na|MH_iXYi|~Im+1MnQgoza9=AqojfLTf(X!!o8~6eqZ_rx|x{xP< zRz#H~TeH*#FX)koML8;Zj3H;N{m}si7__nY$IjDzda2Rc_638iuy?GMjOGZMf{yP; znqC-b-!F*tLt5CYTIdGp&Qt7_JSlQ zwMshp_HJ6y!r)v&qg&BM{JPY)kp6DcZ+BNeAO@0uAofFT2H-VU3TQ=qjzaJmNFJ*u zI!8`v(&ftw!~99*%@&mhaxm^s$7sF}10rbOL@)*$M87~9FgB5 zh?r0crjX!sBsk)(U?mAAwg@iddt)`{L&3=ewrc_BaL?|P&G#q}-$B|<2o8;G;=vJ@ zLFUQiwJ)JfU|kD{iAQR0C+%lQ`Q!*chnT;j=C5AE^dc=MT!+JWLj zkv%ZC`DMB$TN)#Cc&c2E0&4VXAy)O!)|HIJnTwA~#;`aocxiX@pbh)dmgY0BI1F)) zi>P0_@0DfoW^=zC`#xKKnVBa)sU2MrYVP;szRy-nv_LC%RV0hsH*S^A5+JWS|EL&h zD)Hy*QC~UyCYdOC)HrGJ1>g-5_KpWU?NQC|(HL`D#lAt0wr4C}ORu<%>&VJ~;@Y8V zThOsPc)5?)fWgj*vCh#ppMw@=7cbq>-mdxq5-&YAkj3x&=CL>Ekjm!j@o?g+YKPez zd{Z0e?9!9Y1y@{hOK~fSK@EHI+MXDmX5oo*uX%Ry4;-@vb^CXmP!;KaXxp3-tfzL! zIRmz=YgffUxNbi#KBL~X^Rq}GR7PXt=s<)#a9Ql@O5hiIYRA`xLGR+)@NQBj&X9>W zWPI#AtQV;U$Zq4!!{W6r>$>#;wyx545jEkk{_?zCY{MbYPT7l9)M`nu|1==zL0Y0u$yY55Neb!XorIAt+#eH81Z<*)CF>zeglaD91wPxI7Y zw9nRO2cW*~;&Yt+L>|?YhZwR{8@_?gLQmTe;&q=@tzyFo^Pr{LsEu8GN^yWUk50B# zT+g6WLrXR;kHYZ^SAzI;nY%o(Z>@3_4|XhfEeR9;PM1r?leDNr^Vu{N^*Dc1Y!LFT z_>+NG9QpNuzH?v*p-LfQK!ziEg--1c(EBEGB!^4|NfM4twKrBt*!Y;nNz0Y^+v%zLWd~d$qk8a}i+jP6~MwB0d%7!=5>`vx$$Wqk-sC92w zVy5hk0%dBPdXKYUZ&WWp&TN}+qX%7`r!WTTKu@s`D!#ZKOdOC(ZCg_Nj_vKtV)~?; z9A^G|rMSv8}N=JwVa%vI~(>daCmrkkqU zI8UAw-W8XItyz^$^cYt07hCB|sK;Hj(Y)r}>M`buzsxJ!R$LyoW>fk^P3+rc9{HuV zZhvqn^i*e=%{O_O=Og~S-b^#kX@KJON!rQ%As&=mKS{g1zpMFQ7d7_-{o{Zb65S^m zbCYZ3Fa-g85Wfa(zLxmbNl^nCzrDl#4NJN&HaX~9O91t^3vQ}D5#ck=Z;b4RGmZZ0cCsOA9%Hb!?1IBA(jzpQeoz@DE z#NkBP_9H{gFOJjxb7WSq4~|SZC)`2bb~dePTY080!rq70|le5#&@GEG#gub)LX zr@3m-(YS7p0d+RzRsB{Hy{;+=+B^ZxViy~rZ2)$jI!SXLwPAqnJ=&wU9~2tfC?bG- z`TuG9{av%|J2mF-$7oyL88+_^aPpiu2wZX98~KkjCDvoSdS>M~3vE_KNAIbUr#gQZ2XG|OtvN3b%wo&?ZA@bnF?kFW2ESJ_il@sS_04%L z<=B*NS4RWh)V}wRAHu_Q-^!D(m|3RQqka#|-1kZSXvXaO zLf-#3-I`9h;ila@{gxFSTDbpc%=v{s8&g($Zpqwt>`Yg(a`~T~%;wWiY0YON#{B#( zHCGt5mZw>6G*jyy&d;RB!fBx1tS(y;C+UL`Z(aaG%>16L`o6dN`V0(8RO-IzAGC98 zqo$iO#m#rMqH|rnzE6^0z1Se8`F+$$d+S_$B>3wr-R+|6U1MmUD9Ll}x0S*K&6T`P z)m-PY+O1%wfgV34W-uKJL3sxv{jb=Ov0jKb>i*^5pui1V{#Xi$vS?@I;svi8dv zEKB?0%RxxTewB1j!n2$9;8&Z#yY*EscozG0BGUO^CrF91EZDeU)AX;y&8MTagI~vm zJ{64`Inmaw$-xwnLjE^rt()YD$!@Q9=j$YMMzq%V(izyebE!|qY&?M7xed2W*T;>$ zc~h1)>~a*CvoH6=K-zRUiLq?${cl$E$iZ_w-3^llRw1;SKMkFR0RUE&+5Ak!eyw#rK?hJVF!Sb~P`K)V!}$MUa(d^bsg^!YuS8rVO-H7(We$T|DrL_U4rkJJJ9n zusVK)rmV(H-VCU*k%uX`UEv9I`;w>8?NgphxBue>bUV$<=ysBtKZ0*Z+Ad~CXrbQ? zV~RHQyK%U_@ZB(P46}ya$T~-?>!RKGF34QmMQeAplBwE;tBcJmI%{s%7J(?a7KQ5* z*ZP{@4A(xmwj9J5(OugvdV~xKp##jSYpJgowa?9@VlGcN5!FY#C!-E}P$k`H4WS#Qx&DB;n1f@UP%jK#W9fAHDfy1#i zqkYA;zK|`mrEpuW%*38WW;5u&D8xkN6xci8MiUl&lV`=VwtbFB(=IjiNd67%n$Z@! z)68qmI&cZ#ut^1}^n?j*fMvTAe0W zk*6Z!nKt#ukS;m@l4dMbXNuc6S*FWw$#X5W3E!U7ig6!mTYj_!f96Fd@ZDZ%W_SB8A6q5YC(#WQW*Mh{-<}tbIOA%jz zfgW$?ZhxiXC?LuHt3`G$KRreJ<;HAJ>V`>w*5_)|evZR5z2@gnTA&@d+MHhq+Vsn# zN%(9=IcCDOF$i7N(^Zrvu13-%haTibUp0APgnl>eJ*UUC_jZ!pVUt}Ob2As}wKwzJ zDtz6wJ2w+LTzV3ZmC>GVr|e=Bph3Sz`(vx-eak?TbERiZ=SFLeDt1I@i+}BF<`LQp zzjimj_V&Jyeie*e+jr#m3C!#suC=}OnD0+WER?$83C0ziz zqCUg1f*>xTOcE)Bg)&Kw0Lh!@!?m@N{u<$|t6$|){`d~F$zfK-;21KI>gtD2#tZ(4 z=|$gy^X*dhyW6s*6j6QxHr=M-Y!#26O@99i9OSrrmUj4$urMjSQwpc$@S~F44>E_J zou%FQql;12xuoL>6W67HD&;dA2`V=g!o52ZeV4rNqjFDzyk%Z*5Y$)YVUn6D)dp6b z*jbd1MQ7!|FuS0+Gma5yhn)B^lDwvmX}j~fY3NA(eMDKXJEV?SVfAo8q4vxjYZSy~ z|2UlZgQJ~_Z)b2gDMe-xPZ?qW&elG=(>YK=<+o%dIohKR&=`fYwf298^nkT2u}HFH zb~%kxoWC{(^8hfUE6;Yrn6(@z&et;kjAw<~%0HvaX|Yl&jZUHp@lhRiUMcBg&7ghN zW8{j$H%csyWc*Zx*Ge)>mfr5@sPYu5p}i9IAR&M10`-zEAw!8OKQF00L?yw*B_hkk zXVT#eM?Y!`DKVNP`a{A}Kqab!fFlsx07=FYHwa{yB!fZX^AATDU1<02oODM-KDxK}&7vyYl8i*n?-=R))PS$fhnK9?Z zovzCTeRvBlatEkDTId6LXA|BYAVv)0bFq@*duTjfgqX;4m&;my6GS;SkulfGuj_pj z(R5Vq?vS;{&OCMj%~bzv<#$rVIfGAGin(=^N1nr~Iy`v#R1)nf-FyW?JRiE8OJ|;^ z`UqC(>>%GG0?*ljva5b<4#|kOJ+jt7kcN%PW#| ziz=Wi>hZcH=Rw^O1+rR_Q>3+YhYiiRMIz}W5DkG^NhTB74ctAF>_KD<$i0#bmFjj! zch%L8Ug_~#x?~rY!?B}M;v!|=L*@07D*Y8yPZ&QZ$uB`-5^+SR{H6qQi6781tSob= zTMZ%u1E3Nh$(KoDAjk+wJ|!(=IEKNc1c}s;KzS-8(j@&b(ZfO7B{`qSksu2snJ@M2 zjuAjgB{Gf#(m-yMzS@l4eT)o07e;h9`WkwbW;iO0_wx}0Cz*;V$3X+%uIzp1gM9zgm zyd>uk`5?GSl2lss3o%DZ;3I5mI5@;JB-x+D=V5g6d`Wi$ee4{TnhGzJzyN6=&F*lh z!nSVrL_Q*9je*olQ$Nlg;j~q$)es1CU74J9@BzZd-la^$8vwBV5<34AAdR5JA4cVHn*@&&xZ3b5Ng}hO^cA)XsiLg;Shk2Uw!?@F#d`BEfikc8$IAX)A+MV6E~diA9spehJ)>KmY*;0MHZ6Dh;IoawNCR z8}Sl)8Ren!4Z@isI%qslqW&Z}Sao>vG)cP=or3Y5EyNoJu9~ zF%W)8dhsztoNebd-!oiSe2=ab>>l;l-x0 zTz!rgi=<#e70*73mwZ@&)%aoSkjG2xRl=4jVu=r76i?xEhSk7I@fnRTVH8whOA&HZ z=;ewSEn$kSRFOgI4=bXt#PTIJkgyes=qxb`uyF9mMqn8}`T&UF%`PJ?RkSDAJT*&s zhu(9F>*R%KD@cZRk=&dd!4U;v_yz@{G-KdboTRVYXX#VCS!k$a?j@Jq6|oJh-!Fuo z`2B*N@13P@^hO7prN8FQf{iMePI7q1F-n@aBz4CVhCPfvz@%#wYpEiM;DpvlcGjHT^DiPaF+p|urDXX|ga zXa41qH4`jqIA0tFlo?Zuq>A~Z;irfsiBX`W3YD;qiinUHg-NOyNtnMPJX@WhXh{`b zfO8y)iVT-jQHG;ejwF1aD}ADv30qeaNwpu!+ny?cq9#?GFE_mDuZXv$EJaUvH3QfY zsEA!sltL&~yhKAuqMFEs59E8Ox!Y(lin^d6?hS$+4 z5~IjU6(fLAeRNSAZDiae!zopCL%TVwN=uZ&DMC_(AA!LNmOT`bAX14V^bSf(CPEbP ztv5MWB!wIBj?fXRh)-m0Wd(Ys4;n$TP7({hKlUQTWm8hLp^BFYj>f@%X@x=#Rcs@y zng zVTyTF@h=j^Z1$$aDDY9mA;Pj1@wCJ!@=@c&E&?$@*8r4_K>?5|)&iCR5GE+;)zP{7 zn;lyno=Hk7z9p2FDE3js1YqRIBlu!l!W09kqCbhQR79A>C=gObSHiGC;VChShE&mk zumVNg^lb6ND&gNB20TX*UjnuxEW$!f72gs#R}p6<7%v6?kFW<7aX?}eA*teRVB}IE zK4EJ^`V=Rr!nGWt9Pj6)Xokc#lKMP+hA1%#m@q>U=D-)7z+}}FKA5h*>(4sQm+VYp z&rrkwsj^mLLkOFxh$x9s%!K!Qz{rbPitv{3s}k-=qO%pzEIp&pNfm#=GZ{K5;SP?rUMzNDBo+E6!BG$?bDRxrD8^FkqC5l)i zMJa?*#WE5t#>zor5fYnCSP6EBJgC;^dJtca*|XCUj<1_1Qe;HIlOphYe{jP#PoEToMwQ&Jh-(~*sFhp_npE)u zV8;S9pu{M0QpIM%7Am4tViY~8VkIzY)LeYsAz_N4RPi8*;*84#iBS}#iY&sWC?Z*6 zmGkhPQx(GqdQyE6@3mCod2R&3IS3?Fbjd;;9wR$Kni|9S=CCxz2;WI zY{`0ySQH^CV(VR2fkWS5*m(J_jcFuE?|&6B{I1|yX=5a@UXZMAcUjvV`d?6nA7LTP zO3@LPj!Pi;x)eOms1}b(_;Z5aknlSarmzV=VF{Q92}Mp=XGso4PgrM>0)B3azUzm|W9ffkG=R z9tj?Tkq1%P@DyRG;uOI{74e$1Krxmo_K~|3V_{V-Gou(w74H!IvV_Z}^!EAs&QKN{ zC%N;9`>Nzll-$!2&L;aN8Ez>Y;nsJdtRMmJ!0>iAAd8M$9J)ns=jsAwVkx@l7RS>9K4W+7&TNe?O9SrrKOrwHBt(zBAzOE^^RyARRL6sseCz9iWqUd@l^! zMUROt*G|e_9wG3lqK&64qmrCW>qhOd8#;C|{9CG<7E0F8-5Oa}Wr0Cz@6%VtbTT>D z5$UY*#MR+DCCk+hMJesdV&lnwJZq_*I^CpFSnRtfZ&#=5pc*@@TSxw7!to1N4xR1F z9`Wd8`4-K8&iT){4Lfj*eDH@$+q`}HZGBpIHkG}tAL-6)xP9H7C9$J=Ko2$mw~QX_ zBDS#b8;t{Sn;FL@tXRgi)?V+{#MzL!xvi7(7MuA*|5W_ zS}laT)g3*mm-k@<;ZI#3>7D4q64_NftS|fCqlRAk)#%=dESF6>G$)ZoFt3%E86t2I zU;m%JF^TnLlk{UrEW%vAM@)SMJ z>Dm3*c+_BRKUOL2okm6?^+UaPe-^`PbhSTwl~o^Y%xf9Sqkz zzVTVTb21AF1Liv5i#D&R+K65uo}1-n5idUi5+0piS*?NCb?2v@ z`YXfOBlfked5F5HZl-mWHd=D=Lcn%$nvPWOx&y$pu7bXDz`(LYgvw_ZA^*TAa@g@g zwgtk^;CuYzP-!Yt7+b6V-*A@99?;v4U|%Eih7l|ix4|P>OqX?VF6`9E6bu4+y0Q8? z28>tD_!K(oxazvTdL$d*ff5`(y-q(il66C&z8lF>e5g>~d@bGF`R?_4LK+(f-ikC9 z>H94}-{d7Jb=iMHap0f&t7$C45286@$%AN(QzID8fp5^iOk>Mt!GVTKytw7XC}zXM zl(JH)h*FoRism9!~Q_yDAu5E2V zNwn$EhS6*gV;l8JadoCUGzy|&EbQTk_k%~5SHnoX2da~8E zk2ZhBmp5S5&SN*~kz>(SHt5^NveXbbBL2Mq>pMIpWFHmg$!_>|6T_rwEDL4vy7xFX zoo&_&$FUwEo5{UNnQmBEJOba5L4ywtobkPz^}XX*W;lJ2<5T$=y<*?J1@#_X(cHnO zvVgwpI=@BlJe~yx1IAb5-_rnTsD&UZuMH}%Y|Ehu<5@5ZmRXcfLam)h&C9EFCzHj! zc*5;)s+qM|-5wPs{lV|!k>S$`{oO$gh1x7sgHbTj=XbuD>$#qD|O zRy}kA>l+D)1}9#*@alWAHIQ|V%uf7x1h3tyFPwncy&koNEa}P)#2{nU$FjyrrL+ z%;IK4E=SnEp^`NQ@zovC+}*NSF_k?wpD*73)8-)f1Je@flA9}IjF-YvsqFk>ad|5 z`W3IfSDT(=?l$e7ZTe5yEG8EVNh}S!;OD7k;p`)g542o_(X5XE`k%Ju09)I70n-2f zw%(>M%wdB&kQ2QdU}a=BkI?l)Ip|Efej$fFXdd#0K3rk(@ut_?UGJ{4Nb|b`^$eAD?hKKZ5xF#tzAjYM#u)MEYZepEGoIJ=YL$(F>NyqbfQ|ZV zxp>yUssEUZ+5b&_NFHX^H}&u-tQO<^*c6rkk)NipNZkCUvMhjersCngQLmZGI^(uy zDjswj^_x@KPUvmRXHD!a{qYCbQR|x&INX_lXV=rT@@pI|2SL#$ed;vU#UFjjb%>s9 zV(t((Q{%hTz1B@*4t79qp2lABIEYWQ&K=NSnvQOGP(ME%Vg3OX+BIp0=*V#&`>d`6|&3Mf39VT|tAr38LTre?Ue z(<6&tgn?73)O+#yHF!7%++SFS%f}jiFQiWIvxo(OdWXe$l4*MEVwPdFPdb)Pt?kndX>Kpq*Dl6t zwNC$TG3#btv{`Szgbk&|>4YULhVDz3uyau~iEi14M(ey$PNMuAh?Xj;j=__{v|XQ9 z%oYXVG2T)S7e^R_1G_+2RNN?LSzgpJ-HXGqi}sd2sf0~1e2PFI*6Pz==%GBjSl?g5 z7GUIeU5fYP8}w02S!~+943|X93~6+pI_7dU;(!R4jW%BQ7Ge8<@n$3&`|wJM>;!^k zaP3?An@gF$H-uHOilhSe>*toTP=6Xk?fPMa;6ss`Q2`27%U?^epxLk6ma)FLsmrjA z-K3ve#;zD%d#=Cd^;K+CV#w%cOWBtO*B?l0nQkCDB<{)OY$hy4JH7T8-d)HV0y`ynk)k18VdKDe_1>s!iL9ES0UGR)n&&K|*xtn1N_u*#Og)ZDXl z1K}jq&dEm*1L^whM_BhBb#S#h8Rz639dMYi36CC(5DR8$MO+#}z1Y@p;B(Y=%3Jz` zm3T*9r@y+A{Re}rvK#@+GkVY}b{WI?)+!uJIHCuyMhJLB@4p&goo;=U4GlsDu0u3@ zMTg-OywGIGZ`SDx9>t11S3mwJOG>Uq$HUQ>6UKeudE=gP-MFV(c1nI)m~l@}GVU3< zJN5VqHc-x`Wx#}Kwf;~A>m-4KCjneqrEjQUN3n{}sAPGVd|s$z)4ZQU_Zo)3I ztk-?3SU>ihKDr9i`c9o!v5bI4$ZjMamspuwEQldSrWP&IPgmg~_ndyM3PHgxz3*d) zs`ngP{}>{z#R5rA5T?QT)^#47$CpDLFsMB(w~>|ZA|$aoC>({+TWmoZO7^ltzjRq z-}NC*W@X>%ij(#9Kt&v`?yc82*_M%rdm0ikML8>IrbnjUxW&E$H2lBOfGa@pF5>U9 zMStou*0LjBFglo(Om;q&x=4>+$0EW2xQY_iRd^!^u#3k2=&;$gSo&i=2uI=-@`CnL&=zSa-JQP_f2*7@Dtg z3!81;TBJ8@VWH;IBHd#vriSPA@~v!j1pFxW99{93d)bA?M5pD0Q~=J@1bm?uhK2ae znR>)F_85d;+{Q+sEB&wygY7wezRs?O?xG&>qd)ZkUuP8_Sy1$L6`9FO=k+~LvMwIaL*c3K^@OKcC;giz5uZJONPP-X zJ2Lco8Uu8<9``i*(DQoD(+KIG*E>9e727U-$}@0nm;U%O7~i`OU44cvHr6Nh7vPz9 zfj+wyQQ`}_R*RAHf_|nJv&SOcyp#10H<}Lq`Qk;vi;$ihD4%?Yqf;m8IXl^iD4=x# zxcE$bH}PZph`NkkX#aoWuRY*b{U@Hpkv-ds`jMU33R$avvlAN$YxSBRJn^yVQi27^==k41Q!2yxRu@=ZaXjn@q1}) zsF4DkRkXF1Txu)!a~0Y6xjlN~^K2`Mb>?|ClqLXs&FBE}X9IS#>p_Xx)Ai67SjEVA ze0UzlTuTFl?K(bAnix)jxnPFUXdhRdId8EAFesf zMv~_1Ny4U_xtQl+{Gk>-#oND$+0avb#G6w8K%}?fm^$AZHd=IL2}q}QW-MRxCRE^Q z{`WVfuGCI)w6@cPxhp*&(q23a11dCQq~d_a+ia2EK;rjqkp{_SW9`3hk=~QAYWVI} zNmgL;Yj#LAQoeoePEbj&*xSDYb(UV?iMynX)}$3_X}54!LX#T3p0C^`-FFWzV?95y zOUi5uI-6!n%Zd!61ENtFoAJoqSiM-w$L~g;{|bM0H!}4KuiFg`e}$Xgl~xGFxm<$$ zyg!m}c~{D`7G)UfN^i);?lp}%r~ot;3oHW|ri1PPV|361V5$xp0Z!AwRsc(M&=cTl z9rOaYQwO~P*6W}TzzaHPZ4LOE4x0cP7l@dB0S4<}8-Q^-*cM=x4z>e0O$Yq|7U`fr zz~wp^0C1-c1_C^#gFyf_9c&NK@F+g%Bl{fzM?NaRV1Nla7y>X~2SWkQ(!ovuSLk3E zz|A@s4zNZCBLJS!!Oj4ibTAU2-$D^Z7l4sE*liHtR2_~2n6HD~0WQ?RbbzaLa2UX? zI+#&&62N<`r+tSVMpRnDuh&RF;YJswS3$GX$1b>JRo5bWN&v+x}``Z-1msoUucOKJA@43qmM}Q1!Ct`sLiW``KcqA zis$pIN2G{>^KkX*^V+8gXtxIG3m$m>6Zc^#M=E3JgHsZHaIzhh zP9PCzKlgF#`_chqHu)IVrtv@XxKz!g&fIiTil!MD&0g|p_7X-dWcW#`edu;-z32W# zW;(ibah9RjxAed@*d9Z%$DzyH`I9HHkb{yriQ(i9{=-SBr)X=(nEeA|c8nBF@`?!d1|ZWLCAgY(psR|wSuC~W<>LIvY{Xg$apa250`Jmw>*TLOGE zY}fvMTcPD0jH4q4EY3hmP7+gJAG(uT$Hs8dqBlOYcb zxjKU*mKUDFq-z^rc1r3lX!peOy{Dwg5R@9(8SVP-u7rl=XzlwWVJch4Cw+o3$#(nW zpGapVX**PLEbMZs+x9q&xT6RM^=wpGiY~{)V3VB&OmG9yN{c@yO4m`*an; zhfKO-BU%l^*QC#-E`A_vaI2v!bqF71#+?=WIR9KaD($n6|A(|qA3ZE0Q#-DQ-R}$O zw5+!x!Yq#BKcADP3&cr6ct`Q6=cVt^{vP;JI&4MT#^YnS#lWM+xJZX_wNFi$6UMCt zPe37RQl0+f;?UB?-U=vu9~0Dzy+M*sB-5NEgNoY_iK%=DVPkZ%rW6-8ny}-Y*uhp8 zI)KoNoaiAgEOpa0Yn@n1<9-3-+*sma_)a-PC_NYS5H=PoM;e%1xdV=L z!hV3009z^Z{_vQc0inh5wlt$&Akzd+#I!;ONp#o~x;W(UAq*sHRHwhwU7QPBI8U~4 zCbV$U46UZ*i43bK{fJ`U0V9m2@^*yXDHuwd!is}|M1-0^49Ee&&rr@9vr|mClj}=D zGAFVx7*;#sSirlTa2()MPBIEZ{RvcpTu%PIx?E z-^F@yOaL6?geL+vJK;%yRVO?daD@||0(kx6?mF{B@YFa1rUE|Wgs0Us0xBZy=Q}Q- z-R-kCT|i$V)LB^aP7!wV*V17b*0}ArQYQZS`0w$l%4&b{dkI&gSoy3=Ql7MgAH|l+grBni{LNtdNVDfnV%){bwN4abLNpla}0 zOU)NJyqS%0GVWOY=#Hadm>Rtk_DWy$dI=%9>ba)DSajIQCti`Z%WX1v>mRX3vy(6S zQR;)g?LSI^y<1p1Zo^l_%kbxEbFicZyWJ4n1N$X{-zHSv0nANO-sabSl%@sZt7NwJ zJ&qmHg7z-@xQ^qgVXyKzKOxJn@;85iz1qqD{*&~UG>bplD3v6E!>s+dMaEqMSxCMn zlK&O_xS&Dv{5z7rL_GS&gTR2Es)HII<{Bn9z6Du7 z`n1Rzv{^A63?u3`j$Pub?JltfqIQ714rPT4mB6IaLWxWPHf?oH&C5h_`Vxbvd*#^$(rTK z?Cf`}*Gq5l{F^x6fH_BlTDsT|k5D>_{nQfp9mPg%_fD!s@6yFVhN3Z!;vlt#2nUhn z>4~e$)XPq~|@>VA~Pt*@=6j6RfUo%wGlhmU*v;sNmKK9O=0ZfMlLaEcg=nJ|3WQsG)>_OuivvnWnkBVlDG$0W z-QP_Fz8mCBQyVAyMkhiLGj-=u{uqb@1o4==!;Gr7l%KdQCC+#f)iP-~sXX+^lBdQI zVx$X!N8pkOk?ca?q;)DGqFsoHJT;3D9bJevc=v`7o=!xOf2)aRb^Mcj_8lp)KZWdj zz!_ZvPF50PiwgnXRfKrSi728>hpB6yQgVwB-CPJr^DPA; z;BINYYGf&Y$RQ<4rF@+O>*1yRUHGg-I6u>wu$(-#h7b?A5GaR}gc#*QAodG{NO2($ z`(;A(b|Db^EkcAk5h5=ssdfhmuEXzi0>)bbI?wW_M>a> z){|{mb3=?m#k21w+fZZT;i3+S!&s5O+Dj1C5Yd7g{D!9-?*00OV@tJe2FumbfguF%7Ys)RT1IOu7U+t>Nh)^eCg$r&pCx?lO$)^dbr zG$s$-aSg}yQhv6z92Ib~l%mCfF38Q+`n^JP81*_2Fv(5$3}*6`dn(m#j1TgayM!P| z+1fd5u7mZ&4&}J4;vV8HQao(~lBK?K=UyPm(H0^RIaP5{xa{zKd=aB90KdF`$AL?I zs{STnju2%^{Smtw!1JlE+(UZVe#ci%kODBIM_@E;g~L?#KJ~C}m`(DmwsHu`ZD>wYR)>JbYGE8Y#%Re=x z{a$`TU&~8Pjf}+P)>t!*0#gr{e`?OPT@|UI1@AmnUBe&olf%Oi3?ZKbX-fM99Ntcj zW9HG+9W7kL-}IAH;z4$RQjh#Cj+FPVcKI>2DZg%epI#rSDHBn>PZQjvyiw}{dek4Gig1-|1^83-~xlUx!W9oi^nCwER>QRAs(1plT>jh$<3o%4JDG)tfh(78m zfe3aX!ql^bFlk;c3@)wky2U?lFXy%mUWgG5wl?0fcv3}a-V6D_4sxHiUtouR3;vdN z;!(b|16uHE`|b{Msx-0elHN3F5K`LIyQrO7kHcYk>Q2gWz9s@omdN)b;DiWhq<}$s zfEsM0vbca9?zqb-DF(w7^#ef_g8;3)X3q_l_u&FM-ZoTz2!F+)ayPH9F`~N&N2~wV z{zj-gU9z6eFvPN|m~&V*#jYCDp0rjNAO^*Hm&g1A3c4pvA@E}X%J>EgiV+@o7CXkt zCqhQJgE!c;=Lo(?1jqW7lQgjU5U5L$hy@@;1x}qj&C8bcAQ)T`)Y-nUjR50`*kG3k z6Y(LAmLwvYG*2W^ut5~OZk0K#a)ME$nV$=j=UWd7eCxyC8%=vkV&L;?0$r?B%H%7?#e=4^!D=U)Gjd%bC1radd1obHFeHk!sbBRvIHi4ZORx_iB8Cexk@ zC#&b-e>YRsgVPQE%EgAtVkY=`c!caP9pwEZm}At z)PQMEI`TVGqAC(~nC{1)V1+2KTnpk~JJ@<_C z`43({@CJg{uZ6d*;N@YF@(U=rJ&|%asfL#Z$~K3;Z7yy258vxe_o&1*qozHZ^}0!y z{}Akdum8xs-gGELjg!;;UM;hxOZOt`Fsg{T7nKgBaBAXE&wEvEsN3CsXOY~EGVK}K zu2~z0w!T-}hPFC9{w{5FR>mJ_0-H5*Xxn==a;OiDfbPaY0@`D(3uW)qRgV6HNkN^Z z`=eGOsVamqXjV>ykVyf>$p0`YBgv#B=_Vzq*`%bmZ&uRu5K@2^lL8^0ItxGFO>Sis zCMey@si=tRPfbv|2}yHVAmj#BUP}qpx!WOi!4!>XAtPJ2Sg$0|MuQb8yo=tY<%rGN z3cLs%8F*JR_2xl3-WI$<$I(0>D&`(BK0?R$jO_Rytfb-rU==E^v&P-S+5xP7AP9?v z86|cQwb)MNPB#>lxpYBcOO13Q@MHd7Kly%c?k=y_4QP7kAJqB}TK{KlCaPI`&}Qzj zXX)+l^&h#{o9>0ALls1e>w$#2{~_{_d;N7TFHcI4gPaNWJp4^_qdp56(%pWPGZog| zD3GAFxSHx8`ipe8yPKu6mhMJ@8;wP@RI6#v;I{X+!@;fY_LII)~^*iLKD_d&VY}#~df`5rY0sP+cWv5H{UM)L=s22$`C;5T52m;GuXS$*poRtIRP{mxMs-lE8`lk(Q$+)lvf& z2}u(j)FJ+2FL|!@fZ%o6Uij`A066`w0e~x53;=Xam)WJD#=8apPQPma;0hK40G(5q z+L;D9~|IKZ#tRO^4I(GGne_>iS`5 zH&YFQ+VfuObf0_uuCCw3ExLZ4v$fS}EhwxBqT1Z+r>;NxUX7V|-&lBgY2o!%Fx`=D}?nk)8*?Gx(kTNJMiRVgXvJxnxs6ilKjJQ+WsVll`Y7juu+#`Q0E$^!$1w z38iR638m9uLv;JjXq*|;+ZS?^-U+N?QU{^%%9R1Qqge1$r+@apG?YK6`kyrvG{B1H zhNAcPLOl>k8<%d7y1+W!>uu@pK~MdC>wDW(x@)jO;?Qbc{rv&GzXujPZJnJt(VT_9 z{oQ_4&RzYzi$wJII(NVy+Fr=resH7GYVSrN0@2@toBI0>ceh9QrMvy48N_~16W05C z5&7WId)wY%w?Ft@{XM1o6r_v(9v%pG_4k<7>3zsu{XM$r|Gmh?3rpD1^7r=@`(>-o||IZVLy_4YRsWlyOu#awq-Gsb>!SEJV}whk40 znC_Z)MSR4xXHCoj{!NnHFV@ND3O#(m2-87={#1-<&uTDcCCfz*=vnpCDQ(`)Nvnv0 z^cDkulmvoZk_kyOQXnDPnHWNzw&3!(try<0c!%r8AHIA0n1gR8Nf!KJOah|E2L$>(F}I`oDp(I zsRi@Tcliq=bmO%T%1tfUt-FXUj{jzskGEi7f5(1elsr)um}%D$LGn&} z-!XEiTQo&^o-lrIi3K8TA_*x?+GoIZs}E!8T2+a__csvyvV|`ykRKK@Ruf0*7Jj)v zezpa1=}rFBSb0h3ya%u=pJ6v9jTFunG(3P3G;2R}#nKYa?>yj$kIv)W#>r)ZGnHiT z-E7}8PJUj`ufTMC!#-vLHm=Dl^X&x_Wj8(OA{CDNCO%`5{Fv;X$1hHjKNM0JC1_VQ z-#=N7Y(bP&^M=XJaupP#tL-6EWCs%@*GO2#I(xV2@>IDs5^dA8j=0Sfr>FDyYE|w! zg7Q9|()aorQ8+mM9fenglAfaC`38F$_2OAhB&9kDF+YH1=YU4~EJurq$FZpBi1*9m zUNhvkq&#k)Azu;ki;Ady$-cuPXWUgavpJV%%aa931!YU-_Sv)L7nK&KDbL$m&y^SI zm=#3x)wA}MMRGU2lu9ULTc6=|#d5k}iXxJ6&)EGI$RlNJ0-U-~4s^%=6HDY-)x@oOS)(U(C~1%H8b$d`8Bpn`ZRnBD-k?7TH@c_szG1u+v=_!#w+(=j3u} zydl%zA%1 zdaRYd_zSv#)Rrz_@+*I77x2$l-t4#d>+WJPC=&+9AJ#EID?_u@cbsxVN$U%?nc0-Eg!Hqj}Cd^2!#(l2QEXJ2Gx^ zv-|FnXG{K63iFv}+o%^pQ6SB3?a%F&4`D9JN89Bjk#RdF-Xzq3Q?uH(EPli;mry`z z4Q6-w{DT^~zx+fNSN6*9`9UPER25s-qOnBKR?L?_*((QA`hMCg%d%C)HC%WXDh_|e zscKDYNM23OLUQuSNgyYP9NIgG2Vwdc4144JG7ZPvh*>H<8dm9(0I1R@2`)VbT9P~i z5X8>HAH>$1z`dFrm7D}}jO3iPlH3v@_j!_=BIFXcF1HX+rB4xDU9JTXoGTyAnA!r!fhK!q!E9`gG#%2lUF@TY28Rp z89CF)No^YnSC@RKH%SgY?&b^f{401;%PnatUw%M-*$dIA>)~hv(|MnR^3QTXI`48w z&iD7v#FEH+J8#owJ#1m}?xn7RCOn6rwn(yQ1?P&Jwfz?GvTr8Ot(CjWw^RAjTKTK? zBs&;#G`FF+7$%KDlB1Am?y2^Lhh<+$#4Ysq{9yk45&3ir;!cWvZk@bB5g0Rxn3`<& zK8}rMa&EFcs$R~*wkCV=3Auw#vYbdh>(5_4DL*Xb@A*(ZC(9e+?O%Q@N9oZBf=RL5 z_Y?VL`O{eY)=y-d1Iy?C{1k28FVp_SX&EoQ=kc;L_=b^Z-*rY#WANTMD>ovdAHI-1 zWsw%Ka#I+^9p~i7S`e4J@zV416)?>G63s1-|LaTn1JObpeQXoG%g^OF<}y=iNKl^r zz*q8GNVbpt21W*yf4?YO;T`_1oB*T6%f6R~;P3eNXmELagoXvhJo^kye$E4lz4ep4 z64+-NyeUBec0M|@)r z-|@2?X&P_F;!9Sf(PpTWHh}xO zj7lr*x@;!wM5Vob$94HvFL*Y|N*?}NKcs~6j*7D1x=F&`JTtba;XaarI=UUwo1T*P zRwI{UyIP+1*&d-&uo<2;EF{x#sf4!hRlx2bu%gQ~0Y) z35cqv?9emBll0e+E3irm3oUM7OuLnhSIFE84zBNz$-iVu`(c5ZhN{J9f7w)E@z{89 ze+T#uEX4985ZS5&MY8eW1wt-f`^zT0G(COO#)F2AotNFK|*MM6T>T05eJ4U#L!d(%Z$)|WIxEqka;Gu*K4ZzFXG4%Nim&XKYktj@h zc@pn}dmLJhu!g*B^yk5r6ti}*QeVxkE$RzYkh&JZW-YL_!kavlt{(7ZYh&;5E=DB= z!gGyEcJz3>$w|AFPu`ZH?S9zzTX6%1d8xyYLU&dlQ}(P==>XX~M>K+u72aKE*prZ#s&? zFd7Nch7-25$)~7IX_IG>xHrzMP2cL&vKPOjlZs~EkWKcwLhdizDS435^D8Ug??474Q^eYecRR(qxa<;kYkresiEvl^o z^?--Mi+z=7Z}={`L){PUMAX}Sl?I~-pM$ovzKzn6%Jo1SWf(SwyR}vNT2Z2x3U7nl zK+tqRcyGM)az;z@!hycrJlkS#wF1?IR=MOlG6B8EMG8Z6tJ3z9-lSVydea>kr`kNO z=&3CBuS%;i$JUzj%(&tA74f!M5U$D9KKMoMXefxS#p~&lVn3Xy9a<+FPT*baG87FB zz&>fKB$AG_Zl?q#97b{IWmoKZkkl3@sIg5KYC48euw;oV1v7v$JCpFXtni8LlnLX0 z--MTAwI4R##w#RqUW19&#KWOET82ouA9lKz3=A`sUqjRtq3QaoqG&E*S~n0lo4Kj{ zvp)n!YDOy$@KZ)Bk4g%k>8FHJdToA6YRLAhvbdbiFQuXD!CIs@M@xF+wjS~1g1}J?XV@QA!m+bx%lm#FAQ}M9%tjJWouKL@)geL~SDEy-F3&Sr?OZ~Z}DEFZ# z`K|z^n+H_Uto3y8e+MXmy2s?;jsPW?vJ?`ijMR~9@9=qnN@tIM)4u0sCD=o3 z(|+&{KNP48aPr>ajzDFI?m2dwX9OwX@`BrZW{@&mM~=G94-iti%`Y?~&)?#G+bg|v ziZ^cYN7^gB7+zv$9<3Uleqp4#htC~LDT!~Y<9=% z+QGG=14p;h&@optfhb$s0$gluK}v%W4}5$_+E*~n)wHgzq^6~}YreLV(koP?uo7Ee z&@qH*rb~ZN39XZo;-3R4=yor)hY>GrQi?qHp#*qxm=fMoB>zn^QIw_j(939No>n=L zrt%roK=;A!b6c1)LeFIHU-`enlw{r0aE*5kSF&`^>T7&KIP@Xo8hTL*O=UY_ z0&G5$5k|u*UrS0pc4+_! zqlnOT#(ui&NeYQsN~wTZ6aj;m-q?xZj%h^w5Ix1Xe|XX7r8oQ*yJhT(rHAz>?qJ(MffG}z z=?~hMulFiPVW`HGCQpML+>ZSTV#?0R%~QYXHPmq2jj%|dK{F-GhJ92XP=6}5Z0+F$ zs9_h%58VSEWbw;3Yr!}ohqA*{QqYM;>YfF-Fz?h_}3;GO2nLW?2ZNXon z!mTEfI+4lpT5GVH++4Ezsbt^yO4dsNq;xXXUz?9S30Ybv+=wk03o`W5!7zjI-@3qP zE#*mFm4D$cxSO)c3!`&=fuZ`m{bV=gHK_%2{h#*7x+?=2I)R#=N-j7|y_8LING9LY z3msBE@6}rwBgk(-iuUyxUey~tD#AbLt<1t*BK>2O1p0to7^@5ubP1TRYTHinBeBXZ z;1|Rx2jjqsnM5Mlo1oZp=$(QK#UUzl`8nr-DLigb7FmIURL=|IfKyzJSGt-;K80~| zaIc(WLmdX~-yic=;*|(FOP#S3Y3Vz#z)sNzXe z=H;o%BQ%qv>6*Q5x-y$QCBu{yDV!f3rgR3$x5Je7GQ5sVjF-dhuRfqmm*92JQhLDK zH;Z_}`T7w`FuVswC`-tj^q}w-JgCf+g2OWn%0HBP<@3aPTUqcbR8Gh1O8swNDZ3_z z+b@_EOnk%nsL@J02zYq3@&tMRoh=01$<{;XLI20|l{iTXqoj7^ zfn${mNPW{-Wj+4F#w&h&+c+f(@PzS72>)dqZe|yFDpR0DnG)5$@hw!+1fsI{nxJf_ zqCjDNk3SSsNBf0IiZ|h|OjhtvIZvOW9LFC@?iZ;mm!~Q(w7(A{!9i$urA@s|Pxb*| z=~Xo+Os((2cTQFM;ntb&rz*G|gdd!ygy8S|G-Uw(0v^U+7rXgkWiuWw=QpM+DM-Qn zk0|pceK6DEKE7L3V!gVe`T6yL!Yp26|5;Tc6vXR4ODU9pTg{)IrKDwb!I@3%t<|yt zTPyM^Qe%zUI^pppPb+Pu@EFPCsg=P4z^k+lBl<_-F;}rz*y{76ac_V&eKil7E!yph z*-EX5*^KBlzZdzqzd^$%yusi8oAP*vZorjfU<^AeGU-y9Cz@T>S{fakc%7%sQ3~}W zM}cU^DqcHB8AbQ3SVm`SLD-}NQ`zu1%v&%z8}9_X>MoU?sELW5duRa>Scj+SF#TN!7aZ#YKu0q_>NdW9{}ni+*yrpN$4@agMpZ z+U95Z=f$W!tKDaTf_pPj$y!v3$a2c1%T(KoB2(F7Pc^tZU-zhDZ43FAa-Dcz;0vSd zy%#E2UW(!q9#c9-P;tZ#yp2nA8!>S~C-@!h(u$+njV9rrE#oggrc4mIo<#*bdzoE+ z9Qr6QV+gamg714m`AHxu2=U(2_IDR4lGG9Baq0TJizKLU08%;Jh$SFfA8p&y{FBAX zZvnfXk_{HAYGFrQNRf>2MvI~vJM*uWD22UyAq=XMQ<2_Iix99cU_UKDz(&CSnkQfY z0UB;TTWnQ=dwo+*i19Ij_#T{c_@=M+sS^cr0}w!#P@m_6@v{RgpT- zjl5@s*B4&*bn?G1{6_da$h!w#z{b*Jt;qWZym$~C$5IVd^!$PcVj%ppz$=Z*(md4K zuJ#*GDs9Nrd6g+|N!_@;Oc{us8&)UwN2Hv_=GAO%gZAn|ttGPs0Xx<>#MP=JlYK zAfyE>5`AWDZA14`hg1}(Mj2f#rHCY4e}X?&p?n5w`Cz4z&ZJ)U7ps)EGOo>k^I4^% ze{`mya#)<{Q29H6dNfwXE~|Pcnt$=EGPYZv8q;w<9`h z%9cokf_Pa(FZhD@a71%Sey~WA_5%D4bmf7N%=)2XB*y6Tp0xzku)~!o!RJZaa(#U z3<%R9oa$ij@9bfBds(R<#dv0o@+1BhuT|_)KOX;z@*H0HsDDKnEA{1_*D2G0tXKzY zna3ULl+Z4HG7Uu`dmHiB;A>0qtIA}@Q=baPOwM4FFkZjh(Em_lAN!D3Va&byX3}$I zevSiiefg{Fm3q2jpuq!+OSpM@?gr(3#L)jWi&YDx)Q@w%c)$l8rJl)auGjECWYxj8bP@87KSlb4O>*ETC(8T%oV#j4tm|MN{H z9>l&|(7pHL4{SlV`PEpyev8r}cJ#N@toM(V4bzXOCNM{1X|20$I5X#svbAxHHmb`J zy<@(2Y93cfD}83U{|~_Y3!^aO;J8R=DSds|mL;4($(V6dofAwXP>! z9#`a5s!7FdYa$6#6C~UO;ikmf|Funtkh~Jmco)LarsmkacVK|rg4vtR_w1ypi{0`z zhQCrj`;d2)Fdsp%dLUTjA@>o(&z~fw7g|Hqz4XY(c%qn06azq^2U8PyDjK$8Nuc^(GtpWi z@=LalJC139NRjvbz&H|lVZBn6JPHw zODnP0wfpYV7nq7WV(e(#n}X_kFBQ&!owsm_4Xz5bU2TX}YtWpCLA%-AN#2Rb9Xl&P zq>b~EXaoJh-B_gDTVKTEFDoMk{2oNTdoDi6=V*0wu3$L6jQW-=>f`V%^2J5+^ri`3 zT|o%V-JkF_6!n2^(CUKtzROCd_9Aqi9vXXnzfDvoTKz=lcMWU821+fu&;9yr^!a$zho^?lHVS6?je|7Cy z0scZdurBV9`kwbddqxL#LZT>ebH93*BIPIUqB{^5)vBuCeSN-tVK7@DNocSk>@-pt+Eya*F_h9}0b_JZUB zA$-s9Nil4cKtz$X*nOJsi(wrEqJ$97p0;0zVXYWN*bv7yF{Eqd0G8rah$Samp0S62 zp~}w>U~$%2v?4VUXCm;qsWe%I&rlq#9!X0@dxNE^CJctWI|wlvh=OY3aESNQs!19? zQfYPg-lL;p9Ri6>HN>cG@gcztv+^7Zm?K`q^$o5Zf=*)u;0vl~L3Rg|A&~X43la(Dx^@@HQge?lA5J1s0s?fPh(vELbj7?aLC`Brh*CXjO%yJ#oN(EuD3e z{ZnWpupF7vQyOlWp;n~ws7%&P8ph3;Y@*i)@GOU;?Rk&y&15s>{C)PW53rR|MiCNW z$SqEay`HY_1Vv>$VYE8*>D7w>(R#JNx*s8UkIslpRM%n^59J}pUayQ_2#N-G8~(Xt zI9rZ+?(!@aEsfxNvsi3rFy(5OVyFoP9Z&H_Lp0zfuqXvbJIv&qk~6qz1nX#mM=R@o z3omRS=@&-u0VCKnuaQV|6ghFf^UWjh-5s!YDN0Zksbk>78_{60jMq*Bi`^pT9JP>$ zj_O3y)D?oLFNo9?w}#Py5;!HdcAqX!dqf+d``iYkVEd05=|~a?i-IzUf27l>67GiZr zc{OzvB{5&k0&T7~9n7i`RB8~MJbeA=fufo62}l&mc1)XU_PwQHS)J_Th%<}$Pl?He5-^dSRS z?NfoUNS4{En$53_X3_nB6GZP2QLfgjnW%z@ zI_X3YtGjdfI*5-U7(2tc2q;^79BQqu zh7O<-SA^-6s7_6QU06+W76S##QxBM0sHI4~kjpc3+0*E!Kgq>#B#-}?%Tn;yJCD&m z(Diw&E8Xv`(v`-zTQD52jpp&s^H}sK*C*KQTwAes>^baIFlJ|4`s7yjclhtb>!X#! z@Z?iaPrHWkw&8eM6P7v9uNGb8+4+n%wJytN z1zC7!HP?0)kJ5t6)`ZWyeX{W!D!oZ7KIEq2>Q?yI>VBN2Es7jk`ke&2R(a^^{L8?G zCpkRu^6IP$ymtZXf*j@)u@Kq`*Z zzEEqXo*abhFY<;0_PiGnUJ!EL~65&6N zbr;N06Oo9nZ}QA>?7?ti7KoFZ1v7@xevX*C+4qiPV+CIY@r~NdL&viut4J;(JastbgYP5AkUtHWK2UnmIukScg6z_&E<+bnm zPRcawHNr7ve(=($*dslTm_ZfoU_BbPNk9DeBYU5fu!U zb(2{ik**aJK>I>9|L0`ZEd+{){Yu$b9`?q!R&e=cYny(@#HZ=N`aB*wg$24(F~wE$ z#3`%;k)vuNY#!-}g^`QCRqsQBbJP@4wA-)oc~e+F5rsxP`(NX`rm%1%^Rp@JpZMGP z5DPLw0>)P>F7i_ku^t`aLpzsX8okg4sa?X7(#y-|FYPOtf&4|$&x{>M4u9<; zSEjMvBE>PJLVefs{u&IOX-C$pAv&)HmfChJoaHW6eN#6jLA;3 z?V(T#Jo7N4O{PPpvvKt1fGKTgm>InR2J#qD3xMS#t)C*2A8EgiX$*u=48*nMG-kaxC;{^Frj?_Uom6Fi_%cEyPm-i8>Qm zIN#VSXsI!2IgUc??loeAFD#bIlT?-zLA;v9PJpJcAd~Jwmbs8wcOffW$niST)>N5H z`I|IxoTCegDZT8APdP!@a*2a&P)uGmgN317x6fcR@2MA~&tXG2>P1DLU||D6g03Ne zmswb>jI8dpuu%H{!oqq6Qmmw0cuf;K4I=4Zlt;)+mMLAdKQfcGq7Th;XR$K;U7yAJ zc_VqabTkEZi^@xw%~A&ggJN=`V7o5++HPfIhv+8lZLxzbsv$E^)P~+C)gpC>EUJpm zx)1fHbRL+^y2)kOG%=e^Lp;O(#?Im|at_Otb=;{R@oGZG>+PQZJD$Xvl(>yi`oO9=~ z`&&3&fx!ClkLQU}fb38{Z$69ncd5E)2-q)%&2-TB{qxx)5ENO&;?XybEn-n7s8Z|| zF`chO#1!B-ZsfR3NRd=;dawI_z5i!aDQ+0$#IQRvw&a6C{MDfAK3e9`Ztm&WZN zx;?;V8b4~Ri!N|uG3y*KiUgVSfLW#Yu0?oHas?k;%=`y>`(VKUjooWx`E~1M+J=K| zZ*X%ly0)ZaWd|QP(UTlwL7qba`zmLZrUqQ^RBP5g@s|0jVip#j-+>k#5K5oS@JPJg zs}pCo1L{%+YgWwqWk3yRd#r~#8 zSybQ(C~_Y1>8sYj&^r8UP~_DsRNj9fdo>BAf}Dq8kt7O(f?(~%0Y5$VK8y;uFz#jVqn-Q@JiHrn+EzMB98ZaKXf51?^7SM6Gjc{vJ ze((v_dBA4CDiK%utcUCHA0z73R2GafT2H8o@>R=j303{&rc}5&SJE!KxGboD%jNR@0^~We-YvAC216-dV~I zJjuEU#3DjGxzv8;NrwAEQ26Rr!i+EB?aEjWfjCcyt|dIPjO`YPTZDMTYB!d%&vl*z z>i?cvY`^pr8zUp$ft73!Qo5v)jR{3iRhmTKGZzXwVb*^AmL73NpF|6Vjg?q+qIkvd zWX$9Cj>{O{tL-D*r6Cw8)HiELBWcJN3;ByS4AqH|G*Vl>kbh%ivDSyg5~xx8vC`QQ zdZ;VV)nRd)?j_bN+p+pmr$(zzvg0l?FEg&oRm+If)0H;R=kB0YB465%Zv@*+C))}a zo42}_I?^~y$qVXYYwP$6%h@>VY^3Vq7SK{x69)yl^e!pJVxuiSg|rN}UVjdwy6;uY z*e!FZUl)2nK@x&6l1>0D4kI`x!buRRshDY@sW#>cxo1I=tJPt$jQIyWo z1Q6rHyIMa8jYXeGFC_l%;LoF(2zW64$yI;AJ|H1$vyinAc(HNP$07-|8ED$yJ>iJ2 zVd>@Fq?8zzoUCFN8iLSPuEBYZ-I3@f@tMeX23D8W(HpOLPOq^v`7Hc~q6mk7251xC zFA9o1F~H~i3_j->792qAI)$lBf!)ow)mYFdG8ercN?wYmK7|V?x$8S%;qasus(8=%8#yKL+IbQlJ)c=X+eKO z#q^%fQ&zGB3V3`a>l=?0U~gBT>Q1w~Mk1R3d4YleETXE z+Xd2Su4^j8lBvP=cWe-jT5_MQ!REbvgE!LUh^x@VYm{tADEV!16}eiELW$a5Znn1a zK722bm4B%l^Z4`^*l_Db&=_pL6quel0(rUFc(#;ukhc0@Ks*flZR3e#(YKdgLpXKB zKwhGErkt6%_6RalL(3T=Gc>jrO(Iuo+ZBr%$t2_eZtTd|f$!GOHAnFe9`hn| zZ$&XI2}Sz(pck2c4-w(lv9&1;G(3zf?Xng6jusIOQBV(RNrb0{#H}x)i@?0@Mb@() z@Rez2aK^!WJnbyB)KEF${PDC4N1>|@|0aZH<63w+>s9QH-ZUQwEG1v$cV1*2^!A0O z+KDrND^~f?v3pjfT|{)VKqri^?kyy?MhtCEV5<@~kX&~7t3X*I@*JmO$Mn`c3CE$v zoe(#;TOyEFZ(Z}DDxodDI-HGyFNl8Xsi`PN1xqg|)^NmcJFC_Z>S`x_Lfxdsq15uS zF)i^gxya9O790IA!Z#vZuL)a|8Z`%)=bRjkYG;%IPRZyTv8&nr?WQ4oU<=1tb@DV` zvYG{<1YcUsdVAhN?{4uaH~>xmbTu2&r3rrYkxA51`q?s#j<~n6-Y2YJHw|qCUmjo{ z2E4?&TJ`Qi6l$ZGJYGhrpqQz)@JBWeQ(Vj4?2vO|o-yv8AW;>o>_f=jLi( zKZo{zfW+sJV6^1AcW~xK+xmgSv5(T0tq=R*t>ICTRMgS#OJ%*)|ly~I4miS^kM zGE21~u5zg+JFTuFu(Y87Xm<{`BB$PsNY10lmsE?|9Db*< z4pR1D2?WEzw^4}N8z&r&1C+fSO~o1ReU!ayZ34iYTrC-a*|}Oj{5j&SB7^HGFZ+W3 zB!jO5`JWlg)h6MkC1(aPw*Ny8X}`Um9(2QN|8)}uUT_YPYT0o0%Dz%hwl1vPc)hqa z>U{qiK6ef4-IXrFS(9MB-Yk7bE{TreTTt zWs_O6{X+eZpGC^n+RT8N!y^M{%$hsEf|LT~m|1%h`fl?f(Kde)S;>}FjW{#PtjzQq8_TjuB*h(S2wfg&{%0m9-z zLVuv~WzlJXS5JpF4DaC52AF{|!VCaL40_NQT{fWd6&9b`GOnxJK&geL>tR;=tanEK zH&^7;lrey)7CG{#)-1?{0p{{LmM9N;gb!NBLSQ^5tYe+r5(2TZd?k2h-Dx zDM-v0LCwiKt8Sdizg@=)!imsDr*5VZ>!d%BO?s8}6$6rb()iQU_}W+55UaO^#&F&= zIx_&ox+{HV{RsA6t%m`u_65@6ZxAaa<=0JRPa?#YOe-epDTHH~RNV+Yz#w3zdeMov zrX$9xO-@9Uj>uGvg*wYE9g(0~gPjAs!3EeQBOMVM%jbvz*^$4-_pypP_LiNc)v33mb${g&#z})<*;u!+rT0) z8SS=#^`1aB2t$ErZSUhSN<(#{M00y>Ga<$|Bce4^_*v-T7aXxv1N5v;>M7*$PE zf7tv~)OP(heAfmni)>uOy>Jw{{3q#%t+B6cdNH@Q#I=xQ*T8t zGNB;x1|DyzCJ*SbJ>pYad`zWj-u=I|EcSId+ih^xF zR|(6>KOn={UZUsc91L&vdSZg*@F^Z{5ylP{sKCXwlv*e3-^ZI+ z!SrGrdGPA-Rn<`GQa`XDKfcRK*aBdc22J;Q!`INL!+r!`Jf`$&_`8k>Cd6qSjwJZF z4o4HbPlw|c*q?cwJt~3|> z$DSBG$`L=t!W%ZTp3(w)`#0H>lC*%Y-NJ%BAjYgl58{Wmu=|1geG8j`EiKdDVi6q? zvI!DwN@FdK1IS& z|G25*=5Z|IPC{ce+1X->(^gL{#vbDIm6eBFG=jK|K*cWeA07pIo2`W@!@!`5y??+}IX6ZnD=>gj$gm zdoZ&sJZn3P8cFm6#z!WY%Iy@RC`vr0R8~ShQRD+&IuE!w*|u~AHe4-T=zR(MKZ|+| z2pJDmDegL|Vhr|=-&vx|JhC0DqLAINodpL{U0kARv?HGCPJ7Ks6uN^A@FUE0q-UU( z4>ZR9K46=b(L~ZgGZ6_D#%Oq*Kl!-uXAd# z4<6(wxR_y=bIkMsAw*KtQ<#tet3_S{Z6$Z-#i-|{sFlSte|j~Mmpa-O2U^hiLVXH$ zVm&CI$GpwD1W?x(d#*BsntEjjCG@yk#Tq^nVV%Ut>M{(s=I>6E8A}X(+rI?_Q~@LI z9dEOUu!~SbHqWcLeQ7djq+H~yhRtnW{M(twufEON&8CKdH99eiDC&wSY*DzguNLx` zyS2!V0r#bO7=LXj1bL3x)=*srZtdFOTaNIM5`ZvcMMhgnRyBDrcw4AjZp`V>#KlPL z9Tq76^JBj39d>{8au8AHVf$^F2UbRXlTu9Ow5J;fKt^LkWNT_@V>*~M&@oCY`j|Jq zgSieR)~sbCKBwTh3Jn}+50Z~I5o1s?CsD9&vFDuKie{UN4kLLH7!3u*3~gCK7`~+9 z5)EM!dP4%O0Q+d6PJRtbCK&DL!JB5>#6j<&48yV})tHJc@p;;F|KiJcu`bl!ckN;i z;HCOIyI5pQq^s4IUA==s!UNA3Ig2>_9;Qx<=5bM=K?wB6?;AdPHycSpUfa!Lf>E}) zTKp7!&COJnh;mR@&m&~m6#nCG)+v=lStM-XpeNK4Mw3WiJUVGAyNEJW`@mAD>%pMb z!_i_N6e}H<>Jet~P|piVvmfH4-enQqB2mG!Z#vYA^SJe07V_}W$&vvJ4tjDMW(nC1 zZ7dEK>a0L{=Qfwi>)^hmBAd(H%W8`{nhs(`eCbJ~9!2SqPRQbhgwP_ng65FeJwu|o zw12C_nf~J$d6E z7D)@ssxLatY&GA)!|d4DNI5(17KyeCB>)r!$WK7QfZ7Wv3{Ws2ZO^ou4$}@nZA+$b zOOajzN|W}o9!C7O_%I8vvg5N5;@xIvVU)O!?JVFyip`XIRqFxb(xXYVoaeq2TJ$@1 zRyfPj7eN+dK`b=WvP8$3(r#!sNGp%}qPe&){g}2QlqMIg;c+!A%1T<~Qv}J?)bhy$ zjl#etA83n$tOJJyLGl?ajru^K+7GGJC+%42fj(pX35T?X=mmoyy;}SALv;zTnyg8- zW;hMq*6n4rnBTlH$KkMACOhflL>gnvmibOZXCUx8psSR$cDmnbaphvM#DsxZ7KG{p zlzLQ`n3B5?CxNh7o$^jUMDozZCfQE)$cjwGFH7NL_p+dwl)y^=1mvsIKMrn{pSd!g zs>rsK9+X9`QO#IdSNcRvf!&PJ!`OoWCwHxN4ZN@=Yr?WNMMO?Zz` zK75CncEm?n_?LTG@IVshh$kxSh`{HBylU@7Fm0`6SO*8FnnU9W?-E@kDhorl{_nB4 zhlQmcA6baG5b%{D(Xj57Au(_r{knV73BNT~SPdVMw8Ri`p)Ivd^}KtVWo* zdN~E2#$F5fa@1AuRj(-Kr`}_MR^o#KV7BBqt+M&}!sttD;-{N&zJv=CI5mvm7#)rS z?1*1M?AWz=T1}-ed~d#+Hy=0^t8kD{B!xsWS%=FAF0}CJ`&jGNL`I*FoukYr_pz=4 zgiCR;Iy;iB^ZCJjEXGRq-cZ!~|KaUz;G(Ru`0-(Qu8soEsGz8zsH38wsYrrAVKPdk zHHf^K_>$;8j=i`wqh{zp1I74AnpxM%Hd)-(Ew|j(3dN0k`FnXhRt7G3R<+)7T~F5>S1 zorXlb3JWv{Wjf9U!xex9j_J!#lV^wtQ(+L@Ct(X2S%n1uX91o|y8244z?gk_)6XgFMcdL0ZR zNGY&tx3X?5;k~)yL69ehu{f2{YIlYYWa+>^a=PIQ(<-dnPyp00E&%q-JxYu&>UpzR zuBV7B;1@PRTSO)TIp8OcVpL#o;?Pqi?HyNle=?<9li=!`&;T_j7PsTk+GdTO>WJsY}nYA1=#)GU@B$+E;LSEDoOG)60tgg-uf9pa*2D#$7 ze~&W6O+!K6K8VIS$qF`5uJu@o*H+Ww_C{pNFfC|rL>9v4O5zhRg6LW#Q`7wU!Hnd*(NSL|-tbria8_W#-WQ}ZtQ3oaAkqjaC#cSc_eadLs!zS)iV(DZ$cb^ii3+v)>NE9Q_(cT0%aj+r> zodDnMU;&E#@JzxmpixiQ#i^Od4J0Z9cBM7AIwMGe(|mE)MdWJT*B2sSNTjhsun@Ay zx~+xq@MsOKUib?kbnFhH4OrHeW;cMSzR7a{CdrxVmCbyi_8CHAgI87cT zG;*hgPLG6CshR?CK5f-5kB&q5JI9={z|aLIr9Gwf*i7 zDa(;UHY`v=PqpU&nwhilz))%O#8?M`7>a}?$f3u1BDNI(G@gj9^bmDmHCpe7lPF?*fMm|d znn=e?OazO@bV$u(3(87p5L3UX7qwy+UoO(A`R{jRbeJ|{Jg8G(fW-PS!NVY(RQc=! zN>yeRh(YTMy+P6<$`Eu}(vmCaX#%Om(>V-e`JKriHJhy4L1l})v6Rg#Gc_U$ANr26 zpg#uR`YZZF{rVZtz@YJ|W_i~A+dHt7Y2laNQ8c%NM#kMTfyBmCQDjvV-fm6VWM4XY* zes*(7yIfc3nhrzJ0&@hs~%ZM zr%d>VeS~V5R!h`CdIp_Wr7Ws{SbyC$OPk^2|B;e`yYao6H4$yN+0UQtV24Xef*HJn2cj+M*%4toz~>+ zn&UVP*e*w`Iv$lvrJbGD9c&B-zpD(kQzPOd9P{i+_zL%XndksK>7qRxBL$`lupH`m zAb^xOHaca=eAS$isK2Ta7k+xeMyl`QIV(tG;B zc4pvN{+^PJ5xx7K(m$4F0(v zNUl-$X_j@wJHu-6To`Sxl!in!D)oKX+@9nc-&gv}6F98|fF>H;m>lCsIYyoO#RF`F zF;bJMI$iwK`$~KgG1g|!gW>3G#764hxN>BQR4dTDuXou5LtR;4*btNT%XA2d?JAh? zi67wZSK>E(!3T=n97EOWEUOlabNzu2Ana^=mjCjBvQUb(MA2*r6{8?@Qa@Cd-$2X4 z$7z|tj6M!+S;Vn@I6A}l?YWv6V~}csL4}L&JEE+msh$3jVx`k1k%OSlgG7SJB~Kbr z>yX&m2D%6GM@%Ma1~jA7VwVSKWvNapqa>}2wTtixl15UpH<=QNMgm80o~4}vLddMq z*cEZS@JCHW(u;OqVS?K^ovF38hS$I(G|-cHZI)qu`**Z5%!4-VKb2ZWkM|N z_*%nNyLp_}ln_CiJ+hoJXYWg3w0j3PcZULhW$CCF=70J|WCvCC9I&eFm!v*_3M~iO`n^`DU?VvQAJ4Drxe}?TWojJBzPLB)-IXlm8#Y ztXwYt##C$!RM@|r(k~bN6XL<4!ZaW-a4+sZV~pA=Q^HO1l%60(G34XmzVMIQLmLzB zQv&mwFp`FW?~_Jr?KOlaX_s&WxJ2$2Lf;7>iKd?fq_M&{u^+IMhkUs~nP1fp4>M4K zevC@^-g^&!>~rM{Oz)g8q}@u(7tq>K<(Uh?A&xefryfa=T%lzADFMD0((T&81SvSm zTnGtvc3VO+;h{VMNLDmY8~~PKpjh3BICRnsn_+;by_+DpIiPR7Is2pQ)ok9oKk+Io zNA17Ia+W8K-AGst=^Q5UqoYc%p47k#r0~@TCKE0mRr-!3Vk6m(dyxv84kJ_%F%aQr zBi`;C4v#F+qI^a`oVgL^!`q0yfb-4hnrDcNY=yHJkQf|4`HX*INy41@UoZ+waq~C+r3|p7pkQ@{ zbrVq>sR{h{UrGX{_Bf^t?K6(5t))D==RNgtETv?Bq zi;=J=A{4+b$h={3e0g?g4u3Z}uzom@bTtL)9R<=4g%7BZZ>S_E9mf=FXX=PJ*35?; zR|eBcoO)d0Bb%2J=qk^lXIg`&xg)IsE@jgzWwZWC8=NUn)POLRnBY}Z^SOfsD#s%;(i0^cy7^i2E&af4ocg?46oS`CMbPh6EOmP#Ux1cjdsEL^t2ntPJWx$?)HZ z*YBD!4p~JTRw$5rwl|iF+(m{WQO)Qx;F^rHWYnj6n89Y$XNG}DFro)`ShZ7`?3P8h zlEhYs%t`h875HX>?_l+cEkV$Nq}sNzk&##e$gIFu{t~|K1n7}|1c^bL5jZ2hfWdn+ zC@y#)N(dZ?>`DQ&QN}x9GL}< z(ZSeFhz-oiC*&BFk2yFLMpZb;3BqU9wB4X=zQ_35W`_dNq}c{r$RLoC&k5>mcA`MlqdjoQs-6P*R-o=$#1;fzsvhl5hq!fAbAwX#s0DABN>5{G z`K67hw)F2w=XPe6@?qa7PxQ24cFk*+fCQQFnq}S1h{iz)G zkTw5%*uF1tV#6UoGBQWUQ^xSwz}BvWA8HGq-l7cdOO)WM#p!vGA`G4vo0synElR)S zppBMiWq3%wYowN}U{?H}C$MJpba@v~`&jduOXw*fBpHJGKd)_e^RHW!DE;&^@J3oA zTEq@F5B*jd6upcltA|DhR~k!oWfqOKV;Rr*R_Qzc%B*1%g;AR9dVGfLy6+bBL2;#D z=|T&2fuRef83FC9%j_so*h5IWp=l5gaan9v{U$>xY zy%0;riJmK^y#ACDZG`IMU#FBo13*~m;)<3*lp4}F7-oZew>lU}=E6_#e&3;Kv5eck z!?*D>iZL1B#Q8mAu1LnmNImJ#Z+7wLPlFdBL^j*rqbwGK zvy;}S{YKK(=4Jf&Y2~&%DOpS3-G+MP#Eg5Lg1KOP3-#?328mG>1X1m0?5Sl4Ri1gM z6CDJ7Mu!nm0#Oh)L??X=KAF4DD2F7i#_4&MR;9}ku+@nnp~i-Gbu z!cNro`C<_>4hsxTQo5c1Kf*JB0*!Rq z$inesG!Ao*^WEPo>y7K&Jm&``x-*rp#mkZ(lt|+mH-Gd8WePn%{6UGL=cyl*d)>3B zJLU@9XeB3ULkw7r8Ds)wu6zPfX~`Q=$toBtY`|0e={-;sW4>3$icNR}NvWlzq+?LN z!ZKzAvEOiXSwoRKe}%i8h2HSx@IqS*b}@M_8pGBEE1K0)i;3)H%w3&TYy^9pT0_09 znrck}L}Nn2>j=)Wl4@nS9sD##X(wW)S3!n2lYB#D1{6vl!zRj@gM8z!$;Ze3s7x?! zaP#|qgqbKIV?tBtRBL9=bgTs&8cZi>FU-WX4&az;S^&jtbaao@rVFD(JUzrQiH-KfyK!nDM)w%6j?npOk(R zkh%3DR#|HDR@A(5D0XLR(Q+s-pA;*);Z19&_A@9I?c>SE{H#o#Pm^Qb(17vJ3I*EX z0|TW{#c2%z6>$)x1>#50-lTfZfw&+R+rr^H(j=zr4{mc;Z`tk@|9i`}9n?7$TdUuH*zpIs{h$6t ziRp736M!{Irk}udPsTQS_eLCd^MU7-0Rv^Svm_Ajx(i27eJedpyEVdm-Z>@e)}tr| zw?%sHVGs^e$ezlmHfNaKF1n+BAV9;_#c6z61ZDA@j)bMe@ETON_neaG*6WD`-oyPi z)$KBY%Q}Jc2{}iS8V6Tz5!+Q>eKI?`T&@*-LPKi;;xSWZ=q~_sS~gH+wCEUug|7FX zJTlOw3Cra_{lxkRtbYcAQKK~a7D(_U`zhjS07>=b86^&`omZYQj&|^&?U2giIkjCG z;l|YE(k2B`kDDnw&>|#6I{hV*4r-fjNc+XSCK|L5RgVK!Q2bq(Z>kz7VFDO>)RbZe z@rK|vyrxVB8vq%}O%2Hh`c$FobS=c$Gboks>M&rjN6A6rItX3Flekk#n(3|=l>WVG za{%X0q-I)0jw97U>hh*$e)9#0yqEL4FDN(n402@jl@Al0qc9yiF6c70(-)Lcy3jK2 zCjx|}SZ@J(pF%$7q7oIbjl~_ZJ1#2Z_xak$4HuQTs7%bH*~YT)z}G#t041pOp^E_x z_+HvMe|}jE8;DCA$0iMK!15(NEfnYk8Y;|)|48V^=i3Z}8@#c!Zfl$IBb;#{F-IY> z*|`f+2Jj8>brql(+Jj2vIep3@`#t|}Ovbo==LY{60OB_5E_4Ey(WgR{2IDf5S8`>( z1Z|S3mgsV2{i*?uY{yJUyYw5ex-E&k6np-t%%W9T>rjbfsovRI@N(NPDOp)0ND7#q z$kV*NmWEeDWTODxi18l*(Mz${YzjoA`;S0c46>6RI7LTwH1m`WW%%$bbLWHwoOFSg zBAb>K6o^vTVHFio!>f_qjU7yD^7V(GVci)!-9$S==y!uhVJaR!Pm!S@2tM|%!v z6Ut!qr%kmk=~s_&(cYa@?@uDy6>Yb}qjlqA zlFSB}Z9yzHZQSR^h~xa9!QP+n8QU2MXVMw4jgs*oLo{MSh$*5tVu>y@LV2`dt0cqE za~Sg|nRcjw5WRcxCBjrWVXMZ`wgH@h5TP%`Jqh~@K5C~GaTqnxpnX%)K*afbzbbK~ z5k)2apCMhv3;gzh<;HC-y>rQgRQ}Jr@(mWO|Crg0}7(>&lBUB5w2dxh+1JFJBJ$Pk^n!@3PYXD_{R&k(s2`9JdvAwWS& zpfjj($hVd9^~Q#V1b{>?3Cc+C6agbTLO5D5wE}ol+d@AiI1=d_U_EfNUx~X}?}Q{E zNB7d{ara;>#>!*nioc267{LadFU;}u{h?=(1uf>y0-=6~|TUz@3v@A4}**Z@1J z{sX%;P)jBP3o-;vG_sPE@G26F$k~?-x`^@yYIwc+a>I}k}iJ zROK^x$-h>D9; zd4c_}|DG4%HyK&)0KVyRirqW)-GBFS+Wn;}0%%dwho<;{*Ie+sns>+}_F9;Z{x5k* z9<>9B3O?dAQfzz0K%bfkSfM;5WjUbeB)9R~ac>P$<>hx5=yC)e63T{Wt3YK;5cI`q z=beKg#nJC>E11pTwoT)~;Tsf3MF^g34j+cW9jT(C^=&Px(bc z@zPg-Eu*R@!B1}|G$HjDr-7s(a2C-Dou#}{D)AN<;C{xt5AHwFPJms2dm59%k_Sui zxD)=gO`?KI`I9Mz?qXU%l|WINoB3RY^%<*AFX@J67t>ute=_ar;_){DA!-yJGe*jN zek5)2po1s*%L=oOqPI+k(JrPVrxro4p@(WIXAbT!`rpE`h@dx20hj~+tHOFuqAyFr z*G6t0C_Nou;KRX~FAUUFQNBG_mKKwKmq~IN)pz)lKK7y&UcgxYXc~+8jra1+Z=5eM zzX44RR@1FDSnt)0O>h%HVNU?4`MU2rVG8?zem?YuKSc?|vo>4{F{~Dxovif5FCC2P zpfgzp>>^RoSV=_G5 zUZ~nJy`ncw8AMRwjcf;!!2=k4x7QRRDS?qfErC%s7>|aA?%&sLOlx!BUo%Ull2R&x z&2Zxzd~8sxlnaeP!*&u`N(pJ)FkBhX)p!0*tar(knFacJPABU0 zr0X+foAY7JMO{GQ(Fqt8{^D>Vjjoj%N^nw$NW`BNkz|h*X{aS&I#-a+cMo+oRVvwB z-L*zUP~Xyox#B0xjrjDKeou#QHnCVK-GD4l4lp>pFZKT7RraAlj#leZQabz=c&7Ot*ISkWd zGPwFUy7;=tptBo{!vZ*Y+D#?ofg$?J=7>+3RZkO+$Q)I%kO&8hIO-^fOSMhdg_C?K zOG00pjVTwMFi_BXY6Pw*vI0EBW8L+2?F!8#Gp5>c5(3!kWLt5U+luTE51#Y;$?o_3 zQBVE7m>uky?{{U1MjSydb!B~|Sv~D5q69lGZo5kpSaEiH5QO1kGQIAcdN~aEdu18ja>-^pFeGEsq&fvbwKn=agl!SYj)!VGg!OxeUHbLMO zgis}&Wk@>}RBnB3240Jf?`SyTwQkaa5c$l)5_13%Bo*6*JY+J}Iq<$sf3LQcL6;MV z+o;FE6etj(q0=a&zsW6Ir42jR4}j4n11*Bug2|)4kLQf@9Eh(R?>AR=5aphum-EIF z_IhJ!2E+sc13nX((%%&u5Y5{v{H`)}*Ao6~I2$56AE<5#m~go+3;IdBB*`lzQ;T|h zpp)u@H12V=q#}a8?OJsYwtP~ywQAJ_v^h|05nGY;{$1i+EiR?KQ-xSUAbF8x){HnjL(-hWQ%9~949!lYuBq zr5i6@JQ)J7FaZIJLU=4{|4cjv6(`|Rvv*pHUWGj$4lZb8^-dGwX=IWG`1jpdKR2{Z z(D7o-i{IRgaH!U_m~Wzhr!jnAt4Y^mRXsx5tg6R}QQIdhRjVnWtF5XYk;*Io=m%aS z?}XTUrDN;2KPIVf+vTIf4)h);J&X2v!WY_y2_HZhLnfH+-VTF#5^jM87j+%2s0FodOe%udUgiW1HU zj7zR|`8o%Vn4oqbbdy&){85ugUkUo&szs1l+gl+>&Bp;~|KzlH&3EieJGd$(_iZR0 z3^lr?+jjEN5hzQSPN*3F(!vI~F$R?~(n=@0DfnGOI!3CKipwUZ_84hlT1%FF#Jvy| zc@J|8S(SwZruyv`tv%`7Zt80JuLf9_mG)K>@uJ^X%O-Gj`dNzi;OZOoXjwn4$ z5}I2m`4#N>faD|y#w@`abz{PDZ3VcFiSxG)GAwA6sd@m3Iy>3(js+*vwRd8M@9-%} zaO9zlBmil#q`-xXZnTwjuEvQ6u(>Y|p8*B$XH=2V(9aNj2k#%R?m|z{7@C7>p4)q{ z$R1TF>i;A_G5+SwfKB1j9&B7s$wQOT%VPiq89snJ-`xXXrG#15xZTDwphw1bOgX-u z9D$yPKqo7AfiHs7A5fzAh7bb1B_|zGM-kAKWX+v!&9+nGFK7qo;WFl}F*GiUy zPY5!W6;>zSvC7(54z%h65{f3#ZktTTBqtUny7?V9BKx+ zGR+m4ogpwiW3CvBCzcUzF=Jpz1S#ikJR`}n7ad~S$=WqeaK8x=<6 zXBG;HXMOy$XjWnT=Td%GAC`r_Z|=h)@p!!t8*Uu6lsETbldaS?`67-DOe9u8k9>TV z>y^LAn6gcSc$x6Ts?3)gF7%I5ITT_pZpGk;hjlhu$D~t zOZN+~UNeEupQCAWfw~zThJ+Dmb|gs~5T6;IzzCW2ynf!&msyCHJJ*-dr;6kIfh-#w z{MLSKa3n3FdgtwV1>Of0?}H}tA@&U~>&J$LV=Jz{J>C(QBPRca|Fa((pFnObe97l* zmQdFS&q|Y_G!6tXYCGCawV77-gdX2eO3vF5#iL@-Nc$pwV+`vbK{-0D3?|KsVKL~& zDm;?NM}}|WxrR_@=ek=A<9hg#u`~mGbwsu82#FErqL02Xc#EbNh`8U6VHvPm4vS^C z+-*YDny3jcBVt7OEDd+yWobF)aTr!;EhW*}RM8IlOlmXY?YQbU!x36*LWE`ExN_A< zq~wdXKY~RsO3k1)oCEWTx{8NuBz}_zy(o&$7l)shOscg=jgh6^lBHAwti7dP_^`yW ze6a=jNNxe;nE?U-%)I*{&894Fo1soc!GchiA=7J9JVOnQla)locvoSNY6+!zCyz#O zxgH#cV1*t`L2!c}Oh<5=9?V3rUJqs=_^BSu_J5M^ojg@2ALD~&sz9V$RFZLGyZnfH zIaZc7Od?S+47}Lf0-p;&gw5t`O>bx ztdTDr`pXviVkk3F4f(Z78DBqu4GAM~8l3a<#IA4o{sC-Ef4b&f$7$&oNZ8lGtclK; zI_!D(IMy#p0+$@DRZ;(Oiq2Datl$&lSZt0yY~}wP82PJlEXPEhhYZKfO#|68u@A#U zzPQdrkNmpLrFh&~*N!Z{?7Dj%=6eRRp<`Czt#92?%F?rLGd;rV3hBY>Oe=wBcJbCz z5`}QZcd{ZDVciX4Bclk6Kn7@R7b?=Ba|(7dUNDGd8VzOqnL%uh5svPXUn3&?9awF@Mwcsb~sH+^<)c}*$&tvSlJ?@rHt>g zvVrvc+RBFah{TeVzDp?pCLQs8hp_lCj74q2j~MhdpEiU|=mPl922X_abwk)KRQ}T; zY{UQy<`U~QM#V?r@R1HGc9x12z=t_yjvdM-WBHd1Wgm1y6?ypQodP4r?I(HWFxH>y znLCX2qvuL`Mt{Sf9md9@$os=sbSjE$RbW{Gy%9JxEutO~aD3npO{>lo?#ZyqKqycLst_m_74VUSaW5yb7`o|k2*urKKVKNJ~N_PUDL>oxHL13RxpnvG?wfVCl6eO=WSX(%#5o zkcTLa=tjk;6ve2sWGQd>m10H5__~p-&)w8*@gas?Lm@QOS!<}JAS#@qssyli%;+Bp z%W?JENfm)~1FfM2X{e2pIq6(2D;oAVu9C&dnn<*OoJX)pjbaIlpQUfGK2btD0#2SN z1-{{sb8=bwc!R62qeLx3#p*U{F5+{-Kgxo&h|kK0HrjL47)V}Wq zPllWZ=l%HwDi&$YC>H6a7-{62g}&yCnJ}U(@@2|VVrUksf-D(u7@#VKX%SQaU5fQ& z5Xg`W129L}OtWo26qJ;aDuToXBR`YKraU8jW{BuN(eY3@*O?$G46q~+TJy? zRv6LcL!z$lUQ~@YIkJrB-N0_?P6R@mY)YG~NGoDs>((3CKiy?SDDWe?e5zyQ!Wa+= z5NJiq%%qcdjwd6Y+IEf7_j!i>vX)}73gM{5QciokoF}Majr3{uL?mLJ$tT7+knEr# zVj~yrAE8WlzpFz{L@{yn(M$YaquG# zW7u0EW&EYF?2i%TFQ(H2gY*MEk56L5s23#URnrlG%aU*ToFq1+&uH|dEQ5Xx1+ECy z4@RF{iDHpFpTv?!QXjtbfE*uHX_e#(=~tGh*}A=5oGn9P2#@FKYZF$hZ4L3FZPd1#bl+ zVm2YFT}^+49~#GQ3@Lv)nPt)-^xW2Kb32QJxlz+?dW)b;an*ED1jK8)x~rU*CbKlh zH6Q{SJZ}K9pVDhE9IJ_ zk>X=D^pNRwkMMyvvVNn;pyGhH!Ws{n4lPwAnWbjQ?=IMJnypvYU`Uxb6UW&LFh|^R zBdB{hUwe@-Nkwxlz5^&V7hOY-A$RkINCe}aKmox;HP zs*mv86gI4n@qL3~N@#mg+06#m2dL448UaL9_+$#ZB?g7AD!V-AnjAl-u)WEd0nkYf z_|s5;j$(AsDV}RVm!*R)tBQXMT}8+vy#E9?->4nqo(U|k_m+2o7o=DK0dz*d(JdHI zF(B{FA11Jfkf^dlAXU(z5OqA}`~yC$Ab!o|-P4(KQaY-2O^|$|AabF#L9r}oDoOjG z6VtPJy_%S&pp17UmBd`8RPm;C$e-~%m(GU6I4drLR8auo?#_TqSXOk(I~$a+4AA& zbJ!{nO05x9sWWi=5yvZdmz!8>f^M5rSpmC8t#TcHy|%KNsi;-%`aj!j@NV6ecKxYU z{N9_`ZONz)Ni%R~10gAyv=ZpWy<_B(gs2kqw@jUZNO5@iB|n6DD0=!PmS9|PkoUQn zO^CIldJ$%X_6y$PP2$b1bW^~BAk00g_>!C1$gnk7lc%duMdJa!^=6h5jfeuzs%+Z7 zC*qiiFS=0bvID&RW)|1!afEXY@cx->;+3N80C!|E`@HRF&a*I{D0^P@J=Qhlrw?PU zf+BF+63tdxJ#A}#PW7~Hjkc|2NXwybTtsb?P*^@|p=aebqid+&^$M;iBTlL;T-zaW z!wbHxmB9N=WPM|UNsfutwnPAC2c79EWR@k5^XU`W-@=#REg!N|vsl)^JKw^r)8`@v z76AsBuo?_*bHy4wYVKK$_3d{|Ee4=Vav_|Dcs^*#Ldb4n%+|j4CL= z)vf3pwVotrOIGuhx3E4|s>0Vp{gl8arr=hgthA`;E*Ku+64NTn&gHB5Teq-*-Iwdt zn9XlyVmV`g{PZnsL_a`OKjdf!firanW`Oy4V2RHAjG4p+8|_tZ=1*e1L%I=oNm}qw zJlSCLhqKrg^Hz#$^Ze$AQxS?BWdnu5+^(>(e#x>xTfR_n!3!(KJ=)cI&kVHZgJB&R zapQCKxIIsLbDS*W^U0kxgd*?S*i*(WReauL78Mn&;;|T6#Y3_r*Cw;ajJv9M

&O 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 w#yajlg`U_;3W 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 Date: Fri, 25 Jan 2019 14:54:52 -0500 Subject: [PATCH 131/157] appveyor publish --- Tools/appveyor_after_build.ps1 | 2 +- ...odeSigning_Cert_mRemoteNG_DigiCert.p12.enc | Bin 0 -> 3120 bytes appveyor.yml | 2 +- appveyor_publish.yml | 52 ++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 Tools/cert/CodeSigning_Cert_mRemoteNG_DigiCert.p12.enc create mode 100644 appveyor_publish.yml diff --git a/Tools/appveyor_after_build.ps1 b/Tools/appveyor_after_build.ps1 index ec81233cb..ab85ebd0e 100644 --- a/Tools/appveyor_after_build.ps1 +++ b/Tools/appveyor_after_build.ps1 @@ -32,7 +32,7 @@ if ($ConfigurationName -eq "Release Portable") { Write-Output "Creating portable ZIP file $($PortableZip)" Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue - & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "mRemoteV1\bin\package\*.*" + & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip ".\mRemoteV1\bin\package\*.*" } else { Write-Output "We will not zip anything - this isnt a portable release build." diff --git a/Tools/cert/CodeSigning_Cert_mRemoteNG_DigiCert.p12.enc b/Tools/cert/CodeSigning_Cert_mRemoteNG_DigiCert.p12.enc new file mode 100644 index 0000000000000000000000000000000000000000..3853825984fdedc11b69a12648a9398b8a6a2b0c GIT binary patch literal 3120 zcmV-04A1ip1y*jOL&;jr$QMXzU7h_b(_vNX!|6C&1vJLc`9W( zblGKO4tsgD!MWDz{S`4#L-1-{SZF!Ph7ZpPll!nbY+X=v-{p9x3#ctIDh=Vd*4v+LoG%=Dzxo@ zvw_*6Mvhm7TsAZRF{*4Hli#Q0+IaW)53_H20dy}o3~S@#S|)Ha6Q&wh;|A6x=K}t#$+T# zH$>-Lh&efryGXp3YoPsgl(SvX$pSdGH(MB_5vO_r>D9qHUaY85!*L9V{Lf@tuP>M>5jyE!1}Ob;0z%=B{oY z;d-g^d7#S8LRZ%nqu(7H+in5s;@9jzrE_4li84bZ{##c8QI#b4jR5x|Z{vBX;;>?X zD{nQOwbxWRFVK4byBU;VLh3|LOLABIoBnkmvvR8sx((x_YZg=cp3AsJxtEYOR`9V_u9 zXu{|;?&oc8)l)?NBf9$S`BJC~rhm=GrI_u)_;N$>b=1l0Z z5}m+Jjkvr$p>OtBe~(Cp)Zq~|)IEdNzFhmosu1~a3@usaKVqyIhn$(Ip-xLV@yo>&&I}T1~81Oa!+_bos^Ot!M(Ss-l{*}bV(uS=TbhmM!O&23( zCJtHm{}AKSic*872q}!%-zL-X4e1^+1bYuA{rK7{cwuhM(Sd}Lkn$EbP#&~o**mb7 z7KoUtD`l9>fplRr(*hbW!|tW!pW8Ef7TyzJ=Sa|ow}6x{?#^-4qD1dqFBeRsIOnt& zn;&$gtO$7LRFcD{UFrpsh`QO0irD9KpkB~9zhBlY8hx6%LEIb7hl4{*V`v#ymJ&Bb zWW4&7&%J8s|Ixk6fji(|%&Pr4AO_MMk{qQ|jVt{ZMmJKZQosAKFu!#qx45@R#(AxV zil`LX&);!kU5xi#%<5!xDy>!@25ORKK)+aQM-k8>yEZ?0Ui-O=S6uNo_Ue%E1=6^0`m z`!Co%>5KV_SyR;P!JVCIDzrCt(Pw;WG2JZ-$vov_ci=4EO*H3J524K3pt%v5e;fe<6?i+4-iyQ$bbaCJ**yFNI&dPX?-Jk@Hcr7!rVo8)Oa5IthU+QAI zjJ#{kx-zc4&C=~T@>Qq}kF`CqOg}Ho)5#9hpSrzZ$%M7IdWmgW_d!JNx7L=TyLy+8vpaW@fRu2A45cEz77;^S8 z{W-?h(swg-`{dmJXW;N?Ss<%6xu1;0_NW1G<7nsbLHv=Z02<$S-kq*j&>1dkSly`O z?hvZO3xI(~zkrfs6VXpn)jlYF66iN-$EOp-IP$SAyrlMX)VmR{Wp&;4e3C$wZtHOf%}hE59t5VRPA_Vkpj(UQRg_9z&^TJ5VQ(rMV$J<)LF z2OPEzvl9q-BeP}p!GP>C-@N@aig)n+N6+z9Np}G$#Dk=VA zQgYLPVmMrDb^4%_^JD(;A+P09!*I6AoUaM&d11H7@eq5rKKSsiwfbS=N)k1qX<)%f z#fVDd;8!LmKg(HPf~%esQyIhdsb%q8kHyEy@TZMvj=A!>nju%l_vF#1E;Zw?q@uXU zZJF$w7|{#p=5(=IBI11uOzN!C4|U+^Ee#TT33O44t2Xa@zcRAg%XSbv_VE zlqhZ9>odrq$U$mfk@?zvF>#Q3S=ruLiO&K4R2x>z>627c15#pbJ@C1eSqOdSLxEqh zGV}o?ervZjFPLmkQ9BT*myFn4Xrgoyfqb8{Hx{F zIP+-=z?R(f|341(uJ+niun@kG zv|)R8Hq-D|)+Fq{M&izZr9^Y7Xoi@gASoJ=eD!o?oy|_SvWdLg#w`4z-dtuWUqnaY z)>Td_BTNBpV(cZ7^+Bb?K`ofVCf3Z3frsLoRGV$k0CO;2oK9|H5YP`E=3 zxhYv^*#%Bd!g;5T7jlP_lbZM1BIiP9S(^7!M*{KS(_`7=sFbU)C1YD?hM*ifsQ2J4 KkM45s)_H(RMK#_4 literal 0 HcmV?d00001 diff --git a/appveyor.yml b/appveyor.yml index a8474cb14..2479f7b67 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ build: parallel: true verbosity: normal after_build: -- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \"mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" +- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" test: assemblies: only: diff --git a/appveyor_publish.yml b/appveyor_publish.yml new file mode 100644 index 000000000..33a749a3a --- /dev/null +++ b/appveyor_publish.yml @@ -0,0 +1,52 @@ +version: 1.76.{build} +pull_requests: + do_not_increment_build_number: true +environment: + cert_path: tools\cert\CodeSigning_Cert_mRemoteNG_DigiCert.p12 + cert_decrypt_pwd: + secure: QK1ldldzIUSVA0u+OtbHixPmsXHAO9ksOKcyByq0FHM= + cert_pwd: + secure: Fni66m2OgoTxjRzahUNUUNHl5gGwTXLvXIMQYiOMqX8= +image: Visual Studio 2017 +configuration: +- Release +- Release Portable +- Release Installer +platform: x86 +shallow_clone: true +clone_depth: 1 +install: +- ps: >- + date + + C:\projects\mremoteng\mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null + + date +- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) +- cmd: appveyor-tools\secure-file -decrypt %cert_path%.enc -secret %cert_decrypt_pwd% +before_build: +- cmd: >- + echo %TIME% + + nuget restore + + echo %TIME% +build: + project: mRemoteV1.sln + parallel: true + verbosity: normal +after_build: +- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" +test: + assemblies: + only: + - mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll +artifacts: +- path: Release\*.msi + name: mRemoteNG-installer.msi +- path: Release\mRemoteNG-Portable-1.*.zip + name: mRemoteNG-portable.zip +- path: Release\mRemoteNG-Portable-symbols*.zip + name: mRemoteNG-Portable-symbols.zip +- path: Release\mRemoteNG-symbols*.zip + name: mRemoteNG-symbols.zip \ No newline at end of file From 120d9284029e58265d8a455c7c6b09da5e3ec517 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 15:28:54 -0500 Subject: [PATCH 132/157] use relative path --- appveyor.yml | 2 +- appveyor_publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2479f7b67..9370b432c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ install: - ps: >- date - C:\projects\mremoteng\mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null + mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null date before_build: diff --git a/appveyor_publish.yml b/appveyor_publish.yml index 33a749a3a..9e0290883 100644 --- a/appveyor_publish.yml +++ b/appveyor_publish.yml @@ -19,7 +19,7 @@ install: - ps: >- date - C:\projects\mremoteng\mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null + mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null date - ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) From 531b1dfa335b9446e01eb156646ca4276059c91f Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 15:50:49 -0500 Subject: [PATCH 133/157] build script for signing --- appveyor_publish.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/appveyor_publish.yml b/appveyor_publish.yml index 9e0290883..425970050 100644 --- a/appveyor_publish.yml +++ b/appveyor_publish.yml @@ -31,10 +31,11 @@ before_build: nuget restore echo %TIME% -build: - project: mRemoteV1.sln - parallel: true - verbosity: normal +build_script: +- cmd: >- + msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + + msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" test: From ab2f4b339ac82bda20d9ce00431e755cc5ac41e9 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 16:26:52 -0500 Subject: [PATCH 134/157] faster build targets? --- appveyor_publish.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/appveyor_publish.yml b/appveyor_publish.yml index 425970050..e924cf156 100644 --- a/appveyor_publish.yml +++ b/appveyor_publish.yml @@ -9,7 +9,6 @@ environment: secure: Fni66m2OgoTxjRzahUNUUNHl5gGwTXLvXIMQYiOMqX8= image: Visual Studio 2017 configuration: -- Release - Release Portable - Release Installer platform: x86 @@ -32,10 +31,14 @@ before_build: echo %TIME% build_script: -- cmd: >- - msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - - msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +for: + - + matrix: + only: + - configuration: "Release Installer" + build_script: + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" test: From 1768104d47b89e3307ddae0aeafe7dbdc8f23923 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 16:46:17 -0500 Subject: [PATCH 135/157] add rlease config and decrypt cert later --- appveyor_publish.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/appveyor_publish.yml b/appveyor_publish.yml index e924cf156..aa1613fe8 100644 --- a/appveyor_publish.yml +++ b/appveyor_publish.yml @@ -10,19 +10,20 @@ environment: image: Visual Studio 2017 configuration: - Release Portable +- Release - Release Installer platform: x86 shallow_clone: true clone_depth: 1 install: - ps: >- + iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) + date mRemoteV1\Resources\CitrixReceiver.exe ENABLE_SSON="No" /silent /noreboot /EnableCEIP=false /AutoUpdateCheck=disabled /EnableTracing=false | out-null date -- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) -- cmd: appveyor-tools\secure-file -decrypt %cert_path%.enc -secret %cert_decrypt_pwd% before_build: - cmd: >- echo %TIME% @@ -30,6 +31,8 @@ before_build: nuget restore echo %TIME% + + appveyor-tools\secure-file -decrypt %cert_path%.enc -secret %cert_decrypt_pwd% build_script: - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" for: @@ -38,7 +41,13 @@ for: only: - configuration: "Release Installer" build_script: - - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - + matrix: + only: + - configuration: Release + build_script: + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" test: From 765bb3886d38983824a33d31a901e819f14900f2 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 25 Jan 2019 16:53:17 -0500 Subject: [PATCH 136/157] full path to cert --- appveyor_publish.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor_publish.yml b/appveyor_publish.yml index aa1613fe8..d25aa0746 100644 --- a/appveyor_publish.yml +++ b/appveyor_publish.yml @@ -34,20 +34,20 @@ before_build: appveyor-tools\secure-file -decrypt %cert_path%.enc -secret %cert_decrypt_pwd% build_script: - - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Portable" /p:Platform=x86 /p:CertPath="%APPVEYOR_BUILD_FOLDER%\%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" for: - matrix: only: - configuration: "Release Installer" build_script: - - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release Installer" /p:Platform=x86 /p:CertPath="%APPVEYOR_BUILD_FOLDER%\%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - matrix: only: - configuration: Release build_script: - - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release" /p:Platform=x86 /p:CertPath="%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cmd: msbuild mRemoteV1.sln /t:Clean,Build /p:Configuration="Release" /p:Platform=x86 /p:CertPath="%APPVEYOR_BUILD_FOLDER%\%cert_path%" /p:CertPassword=%cert_pwd% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"mRemoteV1\\bin\\package\"\n\n Copy-Item \"mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"*.txt\" -Destination \"mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \".\\mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}\n\nWrite-Output \"\"\nWrite-Output \"\"\n\nif ($ConfigurationName -match \"Release\" -And $ConfigurationName -ne \"Release Installer\") {\n Write-Output \"Packaging debug symbols\"\n \n $version = & $SIGCHECK /accepteula -q -n \"mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n if ($ConfigurationName -match \"Portable\") {\n $zipFilePrefix = \"mRemoteNG-Portable-symbols\"\n } else {\n $zipFilePrefix = \"mRemoteNG-symbols\"\n }\n\n $outputZipPath=\"Release\\$zipFilePrefix-$($version).zip\"\n\n Write-Output \"Creating debug symbols ZIP file $($outputZipPath)\"\n Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue\n $SymPath = (Join-Path -Path mRemoteV1\\bin\\$($ConfigurationName) -ChildPath \"*.pdb\")\n if(Test-Path \"$SymPath\") {\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath \"$SymPath\"\n } else {\n Write-Output \"No Debugging Symbols Found...\"\n }\n \n}\nelse {\n Write-Output \"We will not package debug symbols for this configuration $($ConfigurationName)\"\n}\n\nWrite-Output \"\"" test: From 41f1a65ce61736787aba71674a9ec0bcde56ae28 Mon Sep 17 00:00:00 2001 From: Faryan Rezagholi Date: Mon, 28 Jan 2019 20:16:39 +0100 Subject: [PATCH 137/157] fixed position of ok button (was 1px off) --- mRemoteV1/UI/Forms/frmOptions.Designer.cs | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mRemoteV1/UI/Forms/frmOptions.Designer.cs b/mRemoteV1/UI/Forms/frmOptions.Designer.cs index 72e21c671..a2163b13e 100644 --- a/mRemoteV1/UI/Forms/frmOptions.Designer.cs +++ b/mRemoteV1/UI/Forms/frmOptions.Designer.cs @@ -30,6 +30,7 @@ { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmOptions)); this.pnlBottom = new System.Windows.Forms.Panel(); + this.btnApply = new mRemoteNG.UI.Controls.Base.NGButton(); this.btnCancel = new mRemoteNG.UI.Controls.Base.NGButton(); this.btnOK = new mRemoteNG.UI.Controls.Base.NGButton(); this.splitter1 = new System.Windows.Forms.Splitter(); @@ -37,7 +38,6 @@ this.pnlMain = new System.Windows.Forms.Panel(); this.lstOptionPages = new mRemoteNG.UI.Controls.Base.NGListView(); this.PageName = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); - this.btnApply = new mRemoteNG.UI.Controls.Base.NGButton(); this.pnlBottom.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.lstOptionPages)).BeginInit(); this.SuspendLayout(); @@ -53,9 +53,20 @@ this.pnlBottom.Size = new System.Drawing.Size(764, 35); this.pnlBottom.TabIndex = 0; // + // btnApply + // + this.btnApply._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.OUT; + this.btnApply.Location = new System.Drawing.Point(677, 5); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(75, 23); + this.btnApply.TabIndex = 2; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnOK_Click); + // // btnCancel // - this.btnCancel._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; + this.btnCancel._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.OUT; this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(596, 5); this.btnCancel.Name = "btnCancel"; @@ -67,9 +78,9 @@ // // btnOK // - this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; + this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.OUT; this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.btnOK.Location = new System.Drawing.Point(515, 6); + this.btnOK.Location = new System.Drawing.Point(515, 5); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(75, 23); this.btnOK.TabIndex = 0; @@ -138,17 +149,6 @@ this.PageName.ImageAspectName = "IconImage"; this.PageName.IsEditable = false; // - // btnApply - // - this.btnApply._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; - this.btnApply.Location = new System.Drawing.Point(677, 5); - this.btnApply.Name = "btnApply"; - this.btnApply.Size = new System.Drawing.Size(75, 23); - this.btnApply.TabIndex = 2; - this.btnApply.Text = "Apply"; - this.btnApply.UseVisualStyleBackColor = true; - this.btnApply.Click += new System.EventHandler(this.btnOK_Click); - // // FrmOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); From b3cfcc1a5ee9020c2e4e8457cb806b796b46e8bc Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 29 Jan 2019 23:19:33 -0500 Subject: [PATCH 138/157] Screenshot only taken from ConnectionTab area Screenshots contained dockstrip area (the tab name with the x icon), now they are only limited to the ConnectionTab area --- mRemoteV1/Tools/MiscTools.cs | 11 +++++------ mRemoteV1/UI/Window/ConnectionWindow.cs | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index 03722aa2d..fc11aeb63 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -84,16 +84,15 @@ namespace mRemoteNG.Tools } - public static Image TakeScreenshot(ConnectionWindow sender) + public static Image TakeScreenshot(UI.Tabs.ConnectionTab sender) { try - { - var ac = sender.ActiveControl; - if (ac != null) + { + if (sender != null) { - var bmp = new Bitmap(ac.Width, ac.Height, PixelFormat.Format32bppRgb); + var bmp = new Bitmap(sender.Width, sender.Height, PixelFormat.Format32bppRgb); Graphics g = Graphics.FromImage(bmp); - g.CopyFromScreen(ac.PointToScreen(Point.Empty), Point.Empty , bmp.Size, CopyPixelOperation.SourceCopy); + g.CopyFromScreen(sender.PointToScreen(Point.Empty), Point.Empty , bmp.Size, CopyPixelOperation.SourceCopy); return bmp; } } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 6d8e7b7cb..3141bf265 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -723,7 +723,9 @@ namespace mRemoteNG.UI.Window { cmenTab.Close(); Application.DoEvents(); - Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(this)); + var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (selectedTab == null) return; + Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(selectedTab)); } #endregion From 4b8d06dfe84e9b71dda8b9ff137d527444c692d3 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 29 Jan 2019 23:30:40 -0500 Subject: [PATCH 139/157] Improvement in protocol to tab focus Tabs are focused now when mouse is clicked inside of the connetiontab, before clicking inside ssh window, for example, will not highlight the tab. --- mRemoteV1/UI/Forms/frmMain.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 89aa1b86b..5f7393ef5 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -438,6 +438,13 @@ namespace mRemoteNG.UI.Forms _inMouseActivate = true; break; case NativeMethods.WM_ACTIVATEAPP: + var candidateTabToFocus = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) + ?? GetChildAtPoint(MousePosition); + + if(candidateTabToFocus is InterfaceControl) + { + candidateTabToFocus.Parent.Focus(); + } _inMouseActivate = false; break; case NativeMethods.WM_ACTIVATE: From 39b919c38ae2c60d530d1ec5bddfcfafa41ed706 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 5 Feb 2019 20:24:39 -0500 Subject: [PATCH 140/157] Improves RDP tab focus Improves rdp tab focus by passing active to focus event between rdp client and DPS tab --- .../Connection/Protocol/RDP/RdpClientWrap.cs | 23 +++++++++++++++++++ .../Connection/Protocol/RDP/RdpProtocol.cs | 2 +- mRemoteV1/UI/Tabs/ConnectionTab.cs | 5 ++++ mRemoteV1/mRemoteV1.csproj | 3 +++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs new file mode 100644 index 000000000..f005814ed --- /dev/null +++ b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace mRemoteNG.Connection.Protocol.RDP +{ + class RdpClientWrap : AxMSTSCLib.AxMsRdpClient8NotSafeForScripting + { + public RdpClientWrap() + : base() + { + } + + protected override void WndProc(ref System.Windows.Forms.Message m) + { + if (m.Msg == 0x0021) + this.Parent.Parent.Focus(); + base.WndProc(ref m); + } + } +} diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs index c803427a8..ce908a757 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs @@ -89,7 +89,7 @@ namespace mRemoteNG.Connection.Protocol.RDP #region Constructors public RdpProtocol() { - Control = new AxMsRdpClient8NotSafeForScripting(); + Control = new RdpClientWrap(); _displayProperties = new DisplayProperties(); } #endregion diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index c612ad867..6f175a7d3 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -18,8 +18,13 @@ namespace mRemoteNG.UI.Tabs public ConnectionTab() { InitializeComponent(); + GotFocus += ConnectionTab_GotFocus; } + private void ConnectionTab_GotFocus(object sender, EventArgs e) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,"Tab got focused: " + TabText); + } protected override void OnFormClosing(FormClosingEventArgs e) { diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index d5900481c..8e32858c4 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -239,6 +239,9 @@ + + Component + From c836e29d2fe4d4fdbd2eb0dc4327ddd24fd84f14 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Tue, 5 Feb 2019 20:50:13 -0500 Subject: [PATCH 141/157] Screenshots correctly taken from windowed tab Screenshots can be taken from undock tabs, created helper tab singleton class to make it easy to determine the current tab in the DPS - mremote model --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 2 +- mRemoteV1/UI/Tabs/TabHelper.cs | 34 +++++++++++++++++++++++++ mRemoteV1/UI/Window/ConnectionWindow.cs | 6 ++--- mRemoteV1/mRemoteV1.csproj | 1 + 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 mRemoteV1/UI/Tabs/TabHelper.cs diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 6f175a7d3..1d0d2c398 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -23,7 +23,7 @@ namespace mRemoteNG.UI.Tabs private void ConnectionTab_GotFocus(object sender, EventArgs e) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,"Tab got focused: " + TabText); + TabHelper.Instance.CurrentTab = this; } protected override void OnFormClosing(FormClosingEventArgs e) diff --git a/mRemoteV1/UI/Tabs/TabHelper.cs b/mRemoteV1/UI/Tabs/TabHelper.cs new file mode 100644 index 000000000..971a5b4e3 --- /dev/null +++ b/mRemoteV1/UI/Tabs/TabHelper.cs @@ -0,0 +1,34 @@ +using mRemoteNG.App; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace mRemoteNG.UI.Tabs +{ + class TabHelper + { + private static readonly Lazy lazyHelper= new Lazy(() => new TabHelper()); + + public static TabHelper Instance { get { return lazyHelper.Value; } } + + private TabHelper() + { + + } + private ConnectionTab currentTab; + public ConnectionTab CurrentTab + { + get + { + return currentTab; + } + set + { + currentTab = value; + Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Tab got focused: " + currentTab.TabText); + } + } + } +} diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 3141bf265..280651fbe 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -723,9 +723,9 @@ namespace mRemoteNG.UI.Window { cmenTab.Close(); Application.DoEvents(); - var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; - if (selectedTab == null) return; - Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(selectedTab)); + //var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; + if (TabHelper.Instance.CurrentTab == null) return; + Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(TabHelper.Instance.CurrentTab)); } #endregion diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 8e32858c4..9843a686f 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -701,6 +701,7 @@ Component + Component From aa9b32a38372b8eacd195dcfe3803e88d3e1db7a Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Wed, 6 Feb 2019 11:27:40 -0500 Subject: [PATCH 142/157] Changed refocusing method for rdp tabs Solve bug reported by Joe Cefoli on gitter --- mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs index f005814ed..53414dc10 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpClientWrap.cs @@ -1,4 +1,6 @@ -using System; +using mRemoteNG.App; +using mRemoteNG.UI.Tabs; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,13 +13,12 @@ namespace mRemoteNG.Connection.Protocol.RDP public RdpClientWrap() : base() { + GotFocus += RdpClientWrap_GotFocus; } - protected override void WndProc(ref System.Windows.Forms.Message m) + private void RdpClientWrap_GotFocus(object sender, EventArgs e) { - if (m.Msg == 0x0021) - this.Parent.Parent.Focus(); - base.WndProc(ref m); - } + ((ConnectionTab)Parent.Parent).Focus(); + } } } From e1fc272e1c7a7112328e64f726abc9041868d36d Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Wed, 6 Feb 2019 11:58:24 -0500 Subject: [PATCH 143/157] new tabs are created in current panel Added current panel to TabHelper, new tabs are created in the current panel --- mRemoteV1/Connection/ConnectionInitiator.cs | 10 +++++++- mRemoteV1/UI/Tabs/TabHelper.cs | 27 +++++++++++++++++++++ mRemoteV1/UI/Window/ConnectionWindow.cs | 6 +++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index ceee6241a..3e61d3812 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -173,7 +173,15 @@ namespace mRemoteNG.Connection } else { - connectionPanel = connectionInfo.Panel; + //Return the current panel if exist, if not return default panel + if(TabHelper.Instance.CurrentPanel != null) + { + connectionPanel = TabHelper.Instance.CurrentPanel.TabText; + } + else + { + connectionPanel = connectionInfo.Panel; + } } return connectionPanel; } diff --git a/mRemoteV1/UI/Tabs/TabHelper.cs b/mRemoteV1/UI/Tabs/TabHelper.cs index 971a5b4e3..1ac973463 100644 --- a/mRemoteV1/UI/Tabs/TabHelper.cs +++ b/mRemoteV1/UI/Tabs/TabHelper.cs @@ -1,9 +1,11 @@ using mRemoteNG.App; +using mRemoteNG.UI.Window; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Tabs { @@ -27,8 +29,33 @@ namespace mRemoteNG.UI.Tabs set { currentTab = value; + findCurrentPanel(); Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Tab got focused: " + currentTab.TabText); } } + private void findCurrentPanel() + { + var currentForm = currentTab.Parent; + while (currentForm != null && ! (currentForm is ConnectionWindow)) + { + currentForm = currentForm.Parent; + } + if (currentForm != null && currentForm is ConnectionWindow) + CurrentPanel = (ConnectionWindow)currentForm; + } + private ConnectionWindow currentPanel; + public ConnectionWindow CurrentPanel + { + get + { + return currentPanel; + } + set + { + currentPanel = value; + Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Panel got focused: " + currentPanel.TabText); + } + } + } } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 280651fbe..183ac9554 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -88,6 +88,12 @@ namespace mRemoteNG.UI.Window cmenTabDisconnectOthers.Click += (sender, args) => CloseOtherTabs(); cmenTabDisconnectOthersRight.Click += (sender, args) => CloseOtherTabsToTheRight(); cmenTabPuttySettings.Click += (sender, args) => ShowPuttySettingsDialog(); + GotFocus += ConnectionWindow_GotFocus; + } + + private void ConnectionWindow_GotFocus(object sender, EventArgs e) + { + TabHelper.Instance.CurrentPanel = this; } public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo) From cda557b6fbb311c38e5badaae6cf6fc84c3fe905 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Wed, 6 Feb 2019 17:53:05 -0500 Subject: [PATCH 144/157] Avoid null pointers when race conditions or faults are present in protocol closing Avoid some of the detected faults --- mRemoteV1/UI/Tabs/ConnectionTab.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 1d0d2c398..b47e913ad 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -43,18 +43,18 @@ namespace mRemoteNG.UI.Tabs } else { - ((InterfaceControl)Tag).Protocol.Close(); + ((InterfaceControl)Tag)?.Protocol.Close(); } } else { // close without the confirmation prompt... - ((InterfaceControl)Tag).Protocol.Close(); + ((InterfaceControl)Tag)?.Protocol.Close(); } } else { - ((InterfaceControl)Tag).Protocol.Close(); + ((InterfaceControl)Tag)?.Protocol.Close(); } base.OnFormClosing(e); } From 7a38c1055ac4fef43d526e02f9b8453e49cdd902 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 7 Feb 2019 14:38:14 -0500 Subject: [PATCH 145/157] typo and link fix --- .../Config/Settings/Providers/PortableSettingsProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs index 51349b26f..28a91025d 100644 --- a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs +++ b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs @@ -21,7 +21,7 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -// https://raw.githubusercontent.com/crdx/PortableSettingsProvider +// https://github.com/crdx/PortableSettingsProvider // using System; @@ -63,7 +63,7 @@ namespace mRemoteNG.Config.Settings.Providers } catch (Exception /*ex*/) { - // This casues hundreds of unit tests to fail for some reason... + // This causes hundreds of unit tests to fail for some reason... //Runtime.MessageCollector.AddExceptionStackTrace("PortableSettingsProvider: Error getting XML", ex); } From 54bb9a8f5a8a3c2995323543b196ddd5a67d5a56 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Thu, 7 Feb 2019 15:58:01 -0500 Subject: [PATCH 146/157] minor code cleanup --- mRemoteV1/UI/Tabs/TabHelper.cs | 25 +++++++------------------ mRemoteV1/UI/Window/ConnectionWindow.cs | 2 +- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/mRemoteV1/UI/Tabs/TabHelper.cs b/mRemoteV1/UI/Tabs/TabHelper.cs index 1ac973463..912d7fc1a 100644 --- a/mRemoteV1/UI/Tabs/TabHelper.cs +++ b/mRemoteV1/UI/Tabs/TabHelper.cs @@ -1,31 +1,23 @@ using mRemoteNG.App; using mRemoteNG.UI.Window; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Tabs { class TabHelper - { + { private static readonly Lazy lazyHelper= new Lazy(() => new TabHelper()); - public static TabHelper Instance { get { return lazyHelper.Value; } } - + public static TabHelper Instance => lazyHelper.Value; + private TabHelper() { - + } private ConnectionTab currentTab; public ConnectionTab CurrentTab { - get - { - return currentTab; - } + get => currentTab; set { currentTab = value; @@ -40,16 +32,13 @@ namespace mRemoteNG.UI.Tabs { currentForm = currentForm.Parent; } - if (currentForm != null && currentForm is ConnectionWindow) + if (currentForm != null) CurrentPanel = (ConnectionWindow)currentForm; } private ConnectionWindow currentPanel; public ConnectionWindow CurrentPanel { - get - { - return currentPanel; - } + get => currentPanel; set { currentPanel = value; diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 183ac9554..e373e53e4 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -730,7 +730,7 @@ namespace mRemoteNG.UI.Window cmenTab.Close(); Application.DoEvents(); //var selectedTab = (ConnectionTab)GetInterfaceControl()?.Parent; - if (TabHelper.Instance.CurrentTab == null) return; + if (TabHelper.Instance.CurrentTab == null) return; Windows.ScreenshotForm.AddScreenshot(MiscTools.TakeScreenshot(TabHelper.Instance.CurrentTab)); } #endregion From b0bf31b29c078425f526c2e90feb1ac58da2cc5f Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Thu, 7 Feb 2019 17:39:40 -0500 Subject: [PATCH 147/157] Remove deadlock in #1247 #1247 was caused by a loop of the putty control calling the tab dispose and back again. Created a flag to indicate the ConnectionTab that the closing process was called by the protocol and not the user. --- mRemoteV1/Connection/Protocol/PuttyBase.cs | 7 ++-- mRemoteV1/UI/Tabs/ConnectionTab.cs | 40 ++++++++++++++-------- mRemoteV1/UI/Window/ConnectionWindow.cs | 2 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index 039e4ea7c..c40a0b069 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -236,11 +236,8 @@ namespace mRemoteNG.Connection.Protocol try { - Console.WriteLine(@"Skipping Dispose for now!"); - PuttyProcess.Close(); - // TODO: Figure out why this hangs... - //PuttyProcess.Dispose(); - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + @"SKIPPING DISPOSE - CAUSES HANG IN THIS BUILD!!!", true); + PuttyProcess.Close(); + PuttyProcess.Dispose(); } catch (Exception ex) { diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index b47e913ad..0f1378593 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -13,11 +13,18 @@ namespace mRemoteNG.UI.Tabs { public partial class ConnectionTab : DockContent { + ///

+ ///Silent close ignores the popup asking for confirmation + /// public bool silentClose { get; set; } + /// + /// Protocol close ignores the interface controller cleanup and the user confirmation dialog + /// + public bool protocolClose { get; set; } public ConnectionTab() { - InitializeComponent(); + InitializeComponent(); GotFocus += ConnectionTab_GotFocus; } @@ -28,34 +35,37 @@ namespace mRemoteNG.UI.Tabs protected override void OnFormClosing(FormClosingEventArgs e) { - if(!silentClose) + if(!protocolClose) { - if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) + if (!silentClose) { - var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); - if (CTaskDialog.VerificationChecked) + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) { - Settings.Default.ConfirmCloseConnection--; - } - if (result == DialogResult.No) - { - e.Cancel = true; + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + e.Cancel = true; + } + else + { + ((InterfaceControl)Tag)?.Protocol.Close(); + } } else { + // close without the confirmation prompt... ((InterfaceControl)Tag)?.Protocol.Close(); } } else { - // close without the confirmation prompt... ((InterfaceControl)Tag)?.Protocol.Close(); } } - else - { - ((InterfaceControl)Tag)?.Protocol.Close(); - } base.OnFormClosing(e); } diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index e373e53e4..1a19f6aa4 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -741,7 +741,7 @@ namespace mRemoteNG.UI.Window var protocolBase = sender as ProtocolBase; if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return; if (tabPage.Disposing) return; - tabPage.silentClose = true; + tabPage.protocolClose = true; Invoke(new Action(() => tabPage.Close())); } From f7bfa82517e1ef3e2779a509a51874ab7c762066 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 12:09:31 -0500 Subject: [PATCH 148/157] Dispose calls Close & Whitespace cleanup --- mRemoteV1/Connection/Protocol/PuttyBase.cs | 1 - mRemoteV1/UI/Tabs/ConnectionTab.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/Connection/Protocol/PuttyBase.cs b/mRemoteV1/Connection/Protocol/PuttyBase.cs index c40a0b069..39de44bcb 100644 --- a/mRemoteV1/Connection/Protocol/PuttyBase.cs +++ b/mRemoteV1/Connection/Protocol/PuttyBase.cs @@ -236,7 +236,6 @@ namespace mRemoteNG.Connection.Protocol try { - PuttyProcess.Close(); PuttyProcess.Dispose(); } catch (Exception ex) diff --git a/mRemoteV1/UI/Tabs/ConnectionTab.cs b/mRemoteV1/UI/Tabs/ConnectionTab.cs index 0f1378593..203c453ee 100644 --- a/mRemoteV1/UI/Tabs/ConnectionTab.cs +++ b/mRemoteV1/UI/Tabs/ConnectionTab.cs @@ -14,7 +14,7 @@ namespace mRemoteNG.UI.Tabs public partial class ConnectionTab : DockContent { /// - ///Silent close ignores the popup asking for confirmation + ///Silent close ignores the popup asking for confirmation /// public bool silentClose { get; set; } /// @@ -24,7 +24,7 @@ namespace mRemoteNG.UI.Tabs public ConnectionTab() { - InitializeComponent(); + InitializeComponent(); GotFocus += ConnectionTab_GotFocus; } From 650f1df0ee0da38ab69515a44cccb39a6bbd6409 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 15:59:52 -0500 Subject: [PATCH 149/157] break out expand/collapse on connection tree Fixes #1273 --- .../Window/ConnectionTreeWindow.Designer.cs | 46 ++++++++----------- mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 1 - 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs index ded8c93e5..c7b8fa7e6 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs @@ -9,7 +9,6 @@ namespace mRemoteNG.UI.Window { #region Windows Form Designer generated code internal System.Windows.Forms.MenuStrip msMain; - internal System.Windows.Forms.ToolStripMenuItem mMenView; internal System.Windows.Forms.ToolStripMenuItem mMenViewExpandAllFolders; internal System.Windows.Forms.ToolStripMenuItem mMenViewCollapseAllFolders; internal System.Windows.Forms.ToolStripMenuItem mMenSortAscending; @@ -19,20 +18,19 @@ namespace mRemoteNG.UI.Window private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - mRemoteNG.Tree.ConnectionTreeModel connectionTreeModel1 = new mRemoteNG.Tree.ConnectionTreeModel(); - mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler1 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler(); - mRemoteNG.Tree.AlwaysConfirmYes alwaysConfirmYes1 = new mRemoteNG.Tree.AlwaysConfirmYes(); - mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler2 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler(); + mRemoteNG.Tree.ConnectionTreeModel connectionTreeModel2 = new mRemoteNG.Tree.ConnectionTreeModel(); + mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler3 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler(); + mRemoteNG.Tree.AlwaysConfirmYes alwaysConfirmYes2 = new mRemoteNG.Tree.AlwaysConfirmYes(); + mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler4 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler(); this.olvConnections = new mRemoteNG.UI.Controls.ConnectionTree(); this.msMain = new System.Windows.Forms.MenuStrip(); this.mMenAddConnection = new System.Windows.Forms.ToolStripMenuItem(); this.mMenAddFolder = new System.Windows.Forms.ToolStripMenuItem(); - this.mMenView = new System.Windows.Forms.ToolStripMenuItem(); this.mMenViewExpandAllFolders = new System.Windows.Forms.ToolStripMenuItem(); this.mMenViewCollapseAllFolders = new System.Windows.Forms.ToolStripMenuItem(); this.mMenSortAscending = new System.Windows.Forms.ToolStripMenuItem(); this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); - this.PictureBoxSearch = new Controls.Base.NGPictureBox(); + this.PictureBoxSearch = new mRemoteNG.UI.Controls.Base.NGPictureBox(this.components); this.txtSearch = new mRemoteNG.UI.Controls.Base.NGTextBox(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); ((System.ComponentModel.ISupportInitialize)(this.olvConnections)).BeginInit(); @@ -46,11 +44,12 @@ namespace mRemoteNG.UI.Window this.olvConnections.AllowDrop = true; this.olvConnections.BorderStyle = System.Windows.Forms.BorderStyle.None; this.olvConnections.CellEditUseWholeCell = false; - this.olvConnections.ConnectionTreeModel = connectionTreeModel1; + this.olvConnections.ConnectionTreeModel = connectionTreeModel2; this.olvConnections.Cursor = System.Windows.Forms.Cursors.Default; this.olvConnections.Dock = System.Windows.Forms.DockStyle.Fill; - treeNodeCompositeClickHandler1.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0]; - this.olvConnections.DoubleClickHandler = treeNodeCompositeClickHandler1; + treeNodeCompositeClickHandler3.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0]; + this.olvConnections.DoubleClickHandler = treeNodeCompositeClickHandler3; + this.olvConnections.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.olvConnections.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; this.olvConnections.HideSelection = false; this.olvConnections.IsSimpleDragSource = true; @@ -59,13 +58,13 @@ namespace mRemoteNG.UI.Window this.olvConnections.Location = new System.Drawing.Point(0, 24); this.olvConnections.MultiSelect = false; this.olvConnections.Name = "olvConnections"; - this.olvConnections.NodeDeletionConfirmer = alwaysConfirmYes1; + this.olvConnections.NodeDeletionConfirmer = alwaysConfirmYes2; this.olvConnections.PostSetupActions = new mRemoteNG.UI.Controls.IConnectionTreeDelegate[0]; this.olvConnections.SelectedBackColor = System.Drawing.SystemColors.Highlight; this.olvConnections.SelectedForeColor = System.Drawing.SystemColors.HighlightText; this.olvConnections.ShowGroups = false; - treeNodeCompositeClickHandler2.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0]; - this.olvConnections.SingleClickHandler = treeNodeCompositeClickHandler2; + treeNodeCompositeClickHandler4.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0]; + this.olvConnections.SingleClickHandler = treeNodeCompositeClickHandler4; this.olvConnections.Size = new System.Drawing.Size(204, 366); this.olvConnections.TabIndex = 20; this.olvConnections.UnfocusedSelectedBackColor = System.Drawing.SystemColors.Highlight; @@ -81,7 +80,8 @@ namespace mRemoteNG.UI.Window this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mMenAddConnection, this.mMenAddFolder, - this.mMenView, + this.mMenViewExpandAllFolders, + this.mMenViewCollapseAllFolders, this.mMenSortAscending}); this.msMain.Location = new System.Drawing.Point(0, 0); this.msMain.Name = "msMain"; @@ -108,29 +108,20 @@ namespace mRemoteNG.UI.Window this.mMenAddFolder.Size = new System.Drawing.Size(28, 20); this.mMenAddFolder.Click += new System.EventHandler(this.cMenTreeAddFolder_Click); // - // mMenView - // - this.mMenView.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.mMenView.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mMenViewExpandAllFolders, - this.mMenViewCollapseAllFolders}); - this.mMenView.Image = global::mRemoteNG.Resources.View; - this.mMenView.Name = "mMenView"; - this.mMenView.Size = new System.Drawing.Size(28, 20); - this.mMenView.Text = "&View"; - // // mMenViewExpandAllFolders // + this.mMenViewExpandAllFolders.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; this.mMenViewExpandAllFolders.Image = global::mRemoteNG.Resources.Expand; this.mMenViewExpandAllFolders.Name = "mMenViewExpandAllFolders"; - this.mMenViewExpandAllFolders.Size = new System.Drawing.Size(172, 22); + this.mMenViewExpandAllFolders.Size = new System.Drawing.Size(28, 20); this.mMenViewExpandAllFolders.Text = "Expand all folders"; // // mMenViewCollapseAllFolders // + this.mMenViewCollapseAllFolders.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; this.mMenViewCollapseAllFolders.Image = global::mRemoteNG.Resources.Collapse; this.mMenViewCollapseAllFolders.Name = "mMenViewCollapseAllFolders"; - this.mMenViewCollapseAllFolders.Size = new System.Drawing.Size(172, 22); + this.mMenViewCollapseAllFolders.Size = new System.Drawing.Size(133, 20); this.mMenViewCollapseAllFolders.Text = "Collapse all folders"; // // mMenSortAscending @@ -160,6 +151,7 @@ namespace mRemoteNG.UI.Window // this.txtSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); this.txtSearch.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.txtSearch.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.txtSearch.ForeColor = System.Drawing.SystemColors.GrayText; this.txtSearch.Location = new System.Drawing.Point(26, 3); this.txtSearch.Margin = new System.Windows.Forms.Padding(0); diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 48d7b6e6b..249edff33 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -84,7 +84,6 @@ namespace mRemoteNG.UI.Window mMenAddConnection.ToolTipText = Language.strAddConnection; mMenAddFolder.ToolTipText = Language.strAddFolder; - mMenView.ToolTipText = Language.strMenuView.Replace("&", ""); mMenViewExpandAllFolders.Text = Language.strExpandAllFolders; mMenViewCollapseAllFolders.Text = Language.strCollapseAllFolders; mMenSortAscending.ToolTipText = Language.strSortAsc; From 7e1bc19a13cc6385a06523a521cbbe99a9d9f4b3 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 16:02:11 -0500 Subject: [PATCH 150/157] cleanup white space --- mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 249edff33..5598c07f6 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -102,8 +102,8 @@ namespace mRemoteNG.UI.Window olvConnections.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Background"); olvConnections.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Foreground"); olvConnections.SelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Background"); - olvConnections.SelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Foreground"); - olvConnections.UnfocusedSelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Background"); + olvConnections.SelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Active_Foreground"); + olvConnections.UnfocusedSelectedBackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Background"); olvConnections.UnfocusedSelectedForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Treeview_SelectedItem_Inactive_Foreground"); //There is a border around txtSearch that dont theme well txtSearch.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); @@ -114,7 +114,7 @@ namespace mRemoteNG.UI.Window #region ConnectionTree private void SetConnectionTreeEventHandlers() { - olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(prompt => + olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(prompt => CTaskDialog.MessageBox(Application.ProductName, prompt, "", ETaskDialogButtons.YesNo, ESysIcons.Question)); olvConnections.KeyDown += tvConnections_KeyDown; olvConnections.KeyPress += tvConnections_KeyPress; From dda2b4af11b8b990ac1728c5a10020f5497e4c5e Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 16:42:21 -0500 Subject: [PATCH 151/157] Allow FIPS check to be overridden. Fixes #222 --- mRemoteV1/App/CompatibilityChecker.cs | 29 ++++++++++++++++++---- mRemoteV1/Properties/Settings.Designer.cs | 12 +++++++++ mRemoteV1/Resources/Language/Language.resx | 4 +-- mRemoteV1/app.config | 3 +++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/mRemoteV1/App/CompatibilityChecker.cs b/mRemoteV1/App/CompatibilityChecker.cs index c26af6cd4..ddb6e517f 100644 --- a/mRemoteV1/App/CompatibilityChecker.cs +++ b/mRemoteV1/App/CompatibilityChecker.cs @@ -1,11 +1,11 @@ using Microsoft.Win32; using mRemoteNG.App.Info; -using mRemoteNG.UI.Forms; using mRemoteNG.UI.TaskDialog; using System; using System.Diagnostics; using System.Windows.Forms; using mRemoteNG.Messages; +using mRemoteNG.UI.Forms; namespace mRemoteNG.App { @@ -19,13 +19,32 @@ namespace mRemoteNG.App private static void CheckFipsPolicy(MessageCollector messageCollector) { + if (Settings.Default.OverrideFIPSCheck) + { + messageCollector.AddMessage(MessageClass.InformationMsg, "OverrideFIPSCheck is set. Will skip check...", true); + return; + } + messageCollector.AddMessage(MessageClass.InformationMsg, "Checking FIPS Policy...", true); if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return; - var errorText = string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, - GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); + + var errorText = string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName); messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true); - MessageBox.Show(FrmMain.Default, errorText); - Environment.Exit(1); + + //About to pop up a message, let's not block it... + FrmSplashScreen.getInstance().Close(); + + var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, errorText, "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning); + if (CTaskDialog.VerificationChecked && ShouldIStayOrShouldIGo == DialogResult.OK) + { + messageCollector.AddMessage(MessageClass.ErrorMsg, "User requests that FIPS check be overridden", true); + Settings.Default.OverrideFIPSCheck = true; + Settings.Default.Save(); + return; + } + + if (ShouldIStayOrShouldIGo == DialogResult.Cancel) + Environment.Exit(1); } private static bool FipsPolicyEnabledForServer2003() diff --git a/mRemoteV1/Properties/Settings.Designer.cs b/mRemoteV1/Properties/Settings.Designer.cs index adfb6728a..4c817b80b 100644 --- a/mRemoteV1/Properties/Settings.Designer.cs +++ b/mRemoteV1/Properties/Settings.Designer.cs @@ -2782,5 +2782,17 @@ namespace mRemoteNG { this["AlwaysShowConnectionTabs"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool OverrideFIPSCheck { + get { + return ((bool)(this["OverrideFIPSCheck"])); + } + set { + this["OverrideFIPSCheck"] = value; + } + } } } diff --git a/mRemoteV1/Resources/Language/Language.resx b/mRemoteV1/Resources/Language/Language.resx index e4e580242..d6f81eac2 100644 --- a/mRemoteV1/Resources/Language/Language.resx +++ b/mRemoteV1/Resources/Language/Language.resx @@ -655,11 +655,11 @@ Starting with new connections file. Encryption failed. {0} - The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled. This setting is not compatible with {0}. + The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled. See the Microsoft Support article at http://support.microsoft.com/kb/811833 for more information. -{0} will now close. +{0} is not fully FIPS compliant. Click OK to proceed at your own discretion, or Cancel to Exit. Errors diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index 9422753b6..c9d603bde 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -717,6 +717,9 @@ True + + False + From 7393159f26960eaccba58d47c2735782723340bb Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 16:42:50 -0500 Subject: [PATCH 152/157] Missed the settings file from previous commit --- mRemoteV1/Properties/Settings.settings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mRemoteV1/Properties/Settings.settings b/mRemoteV1/Properties/Settings.settings index 197eb6153..40257a085 100644 --- a/mRemoteV1/Properties/Settings.settings +++ b/mRemoteV1/Properties/Settings.settings @@ -692,5 +692,8 @@ True + + False + \ No newline at end of file From 89055d2ae998757b93589b870d9ad7214dee161c Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 16:43:43 -0500 Subject: [PATCH 153/157] Remove outdated/incorrect translations for strErrorFipsPolicyIncompatible These will need to be re-translated. --- mRemoteV1/Resources/Language/Language.Designer.cs | 4 ++-- mRemoteV1/Resources/Language/Language.cs-CZ.resx | 7 ------- mRemoteV1/Resources/Language/Language.de.resx | 3 --- mRemoteV1/Resources/Language/Language.es-AR.resx | 3 --- mRemoteV1/Resources/Language/Language.es.resx | 7 ------- mRemoteV1/Resources/Language/Language.fr.resx | 6 ------ mRemoteV1/Resources/Language/Language.it.resx | 7 ------- mRemoteV1/Resources/Language/Language.ja-JP.resx | 7 ------- mRemoteV1/Resources/Language/Language.ko-KR.resx | 5 ----- mRemoteV1/Resources/Language/Language.nb-NO.resx | 7 ------- mRemoteV1/Resources/Language/Language.nl.resx | 7 ------- mRemoteV1/Resources/Language/Language.pt.resx | 3 --- mRemoteV1/Resources/Language/Language.ru.resx | 7 ------- mRemoteV1/Resources/Language/Language.tr-TR.resx | 7 ------- mRemoteV1/Resources/Language/Language.uk.resx | 7 ------- mRemoteV1/Resources/Language/Language.zh-CN.resx | 5 ----- mRemoteV1/Resources/Language/Language.zh-TW.resx | 7 ------- 17 files changed, 2 insertions(+), 97 deletions(-) diff --git a/mRemoteV1/Resources/Language/Language.Designer.cs b/mRemoteV1/Resources/Language/Language.Designer.cs index f3d1e574e..9852deb91 100644 --- a/mRemoteV1/Resources/Language/Language.Designer.cs +++ b/mRemoteV1/Resources/Language/Language.Designer.cs @@ -2072,11 +2072,11 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled. This setting is not compatible with {0}. + /// Looks up a localized string similar to The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled. /// ///See the Microsoft Support article at http://support.microsoft.com/kb/811833 for more information. /// - ///{0} will now close.. + ///{0} is not fully FIPS compliant. Click OK to proceed at your own discretion, or Cancel to Exit.. /// internal static string strErrorFipsPolicyIncompatible { get { diff --git a/mRemoteV1/Resources/Language/Language.cs-CZ.resx b/mRemoteV1/Resources/Language/Language.cs-CZ.resx index 3d98f7a8d..e06a1ed38 100644 --- a/mRemoteV1/Resources/Language/Language.cs-CZ.resx +++ b/mRemoteV1/Resources/Language/Language.cs-CZ.resx @@ -654,13 +654,6 @@ Otevírám nový prázdný soubor seznamu spojení. Začifrování se nezdařilo. {0} - - V nastavení politik zabezepčení systému Windows je aktivována možnost "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing" (Systémová kryptografie: Pro šifrování, hashe a podpisy využívat algoritmy odpovídají FIPS") Toto nastavení není kompatibilní s {0}. - -Pro další informace navštivte článek podpory fy. Microsoft na http://support.microsoft.com/kb/811833 - -{0} se nyní ukončí. - Chyby diff --git a/mRemoteV1/Resources/Language/Language.de.resx b/mRemoteV1/Resources/Language/Language.de.resx index 45fb1bf60..4907e90f3 100644 --- a/mRemoteV1/Resources/Language/Language.de.resx +++ b/mRemoteV1/Resources/Language/Language.de.resx @@ -630,9 +630,6 @@ Starte mit neuer Datei. Verschlüsselung fehlgeschlagen. {0} - - Die Sicherheitseinstellung von Windows "Systemkryptografie: Verwenden sie FIPS-konformen Algorithmus für Verschlüsselung, Hashing und Signatur" ist aktiviert. Diese Einstellung ist nicht kompatibel mit {0}. Weitere Informationen finden sie im Microsoft Support-Artikel unter http://support.microsoft.com/kb/811833. {0} wird jetzt beendet. - Fehler diff --git a/mRemoteV1/Resources/Language/Language.es-AR.resx b/mRemoteV1/Resources/Language/Language.es-AR.resx index 1a129f57d..137b29f55 100644 --- a/mRemoteV1/Resources/Language/Language.es-AR.resx +++ b/mRemoteV1/Resources/Language/Language.es-AR.resx @@ -376,9 +376,6 @@ Descripción del Error: {1} La encriptación falló. {0} - - La configuración de seguridad de Windows, "criptografía de sistema: usar FIPS algoritmos compatibles para codificación, algoritmos hash y firma", está habilitada. Esta configuración no es compatible con {0}. Consulte el artículo de soporte técnico de Microsoft en http://support.microsoft.com/kb/811833 para obtener más información. {0} se cerrará. - Errores diff --git a/mRemoteV1/Resources/Language/Language.es.resx b/mRemoteV1/Resources/Language/Language.es.resx index a41667efa..9f854f178 100644 --- a/mRemoteV1/Resources/Language/Language.es.resx +++ b/mRemoteV1/Resources/Language/Language.es.resx @@ -618,13 +618,6 @@ Arrancando con un nuevo archivo de conexiones. Cifrado fallido. {0} - - La configuración de Seguridad de Windows, "Criptografia del sistema: Usar Algoritmos compatibles FIPS para Encripción, Hashing y Firma", esta habilitada. Esta configuración es incompatible con {0}. - -Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/811833 Para más información. - -{0} Se Cerrará. - Errores diff --git a/mRemoteV1/Resources/Language/Language.fr.resx b/mRemoteV1/Resources/Language/Language.fr.resx index 93a153472..84fe5c4b5 100644 --- a/mRemoteV1/Resources/Language/Language.fr.resx +++ b/mRemoteV1/Resources/Language/Language.fr.resx @@ -608,12 +608,6 @@ Si la vérification des composants ou l'utilisation d'ICA échoue malgré tout, Échec du chiffrement.{0} - - Les paramètres de sécurité Windows, "Système de cryptographie: Utilise FIPS, algorithmes compatible pour le cryptage, hachage et signature", est activé. Ce paramètre n'est pas compatible avec {0}. -Consultez l'article du support de Microsoft pour plus d'informations http://support.microsoft.com/kb/811833 - -{0} va maintenant se fermer. - Erreurs diff --git a/mRemoteV1/Resources/Language/Language.it.resx b/mRemoteV1/Resources/Language/Language.it.resx index f4e50cd47..27fdf6044 100644 --- a/mRemoteV1/Resources/Language/Language.it.resx +++ b/mRemoteV1/Resources/Language/Language.it.resx @@ -613,13 +613,6 @@ Creazione di un nuovo file delle connessioni. Criptaggio fallito. {0} - - L'impostazione Windows di sicurezza "Crittografia di sistema: utilizza algoritmi FIPS compatibili per crittografia, hash e firma" è abilitata. Tale impostazione non è compatibile con {0}. - -Visualizza il supporto Microsoft http://support.microsoft.com/kb/811833/it per ottenere maggiori informazioni. - -{0} sarà chiuso. - Errori diff --git a/mRemoteV1/Resources/Language/Language.ja-JP.resx b/mRemoteV1/Resources/Language/Language.ja-JP.resx index ef9d4ff53..650d4e8d3 100644 --- a/mRemoteV1/Resources/Language/Language.ja-JP.resx +++ b/mRemoteV1/Resources/Language/Language.ja-JP.resx @@ -664,13 +664,6 @@ Starting with new connections file. 暗号化に失敗しました:{0} - - The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled. This setting is not compatible with {0}. - -See the Microsoft Support article at http://support.microsoft.com/kb/811833 for more information. - -{0} will now close. - エラー diff --git a/mRemoteV1/Resources/Language/Language.ko-KR.resx b/mRemoteV1/Resources/Language/Language.ko-KR.resx index d7173f348..ba44d2f4f 100644 --- a/mRemoteV1/Resources/Language/Language.ko-KR.resx +++ b/mRemoteV1/Resources/Language/Language.ko-KR.resx @@ -791,11 +791,6 @@ VncSharp 제어 버전 {0} 암호화에 실패. {0} - - Windows 보안 설정 인 "시스템 암호화 : 암호화, 해시 및 서명에 FIPS 호환 알고리즘 사용"이 사용됩니다. 이 설정은 {0}과 호환되지 않습니다. - -자세한 내용은 http://support.microsoft.com/kb/811833에서 Microsoft 지원 문서를 참조하십시오. - 오류 diff --git a/mRemoteV1/Resources/Language/Language.nb-NO.resx b/mRemoteV1/Resources/Language/Language.nb-NO.resx index 877450fd2..22e51b820 100644 --- a/mRemoteV1/Resources/Language/Language.nb-NO.resx +++ b/mRemoteV1/Resources/Language/Language.nb-NO.resx @@ -625,13 +625,6 @@ Starter med ny tilkoblingsfil. Kryptering mislyktes. {0} - - Innstillingen for Windows-sikkerhet, "Systemkryptografi: Bruk FIPS-kompatible algoritmer til kryptering, nummerering og signering", er aktivert. Denne innstillingen er ikke kompatibel med {0}. - -Se Microsoft Support-artikkelen på http://support.microsoft.com/kb/811833 for mer informasjon. - -{0} vil bli avsluttet. - Feil diff --git a/mRemoteV1/Resources/Language/Language.nl.resx b/mRemoteV1/Resources/Language/Language.nl.resx index 86b083a05..ce32286fd 100644 --- a/mRemoteV1/Resources/Language/Language.nl.resx +++ b/mRemoteV1/Resources/Language/Language.nl.resx @@ -625,13 +625,6 @@ Beginnen met nieuwe Connectie bestand. Encryptie is mislukt. {0} - - De beveiligingsinstelling voor Windows, "Systeemcryptografie: gebruik FIPS-compatibele algoritmes voor codering, hashing en ondertekening", is ingeschakeld. Deze instelling is niet compatibel met {0}. - -Zie het Microsoft Support artikel op http://support.microsoft.com/kb/811833 voor meer informatie. - -{0} wordt nu gesloten. - Foutmeldingen diff --git a/mRemoteV1/Resources/Language/Language.pt.resx b/mRemoteV1/Resources/Language/Language.pt.resx index a29b6cf9e..17a388a6d 100644 --- a/mRemoteV1/Resources/Language/Language.pt.resx +++ b/mRemoteV1/Resources/Language/Language.pt.resx @@ -600,9 +600,6 @@ Descrição do erro: {1} Falha de descriptografia. {0} - - A configuração de segurança do Windows, "criptografia de sistema: usar FIPS compatível com algoritmos para criptografia, hash e assinatura", está habilitado. Essa configuração não é compatível com {0}. Consulte o artigo do Microsoft Support em http://support.microsoft.com/kb/811833 para obter mais informações. {0} agora vai ser fechado. - Erros diff --git a/mRemoteV1/Resources/Language/Language.ru.resx b/mRemoteV1/Resources/Language/Language.ru.resx index 397583444..c7ee50b71 100644 --- a/mRemoteV1/Resources/Language/Language.ru.resx +++ b/mRemoteV1/Resources/Language/Language.ru.resx @@ -630,13 +630,6 @@ VncSharp Control Version {0} Не удалось зашифровать. {0} - - - Настройки системы безопасности Windows: "Использование системной криптографии FIPS-совместимых алгоритмов шифрования, хеширования и подписывания», включено. Эта установка не совместима с {0}. - -См. статью Microsoft Support на http://support.microsoft.com/kb/811833 для получения дополнительной информации. - -{0} будет закрыто. Ошибки diff --git a/mRemoteV1/Resources/Language/Language.tr-TR.resx b/mRemoteV1/Resources/Language/Language.tr-TR.resx index c64c57214..8b69ebc8d 100644 --- a/mRemoteV1/Resources/Language/Language.tr-TR.resx +++ b/mRemoteV1/Resources/Language/Language.tr-TR.resx @@ -675,13 +675,6 @@ Normal bağlantı dosyaları için lütfen Dosya - Bağlantıları Yükle'yi kul Şifreleme başarısız. {0} - - Windows güvenlik ayarlarında "Sistem şifrelemesi: FIPS uyumlu algoritmaları, karıştırma ve imzalama" açıldı. Bu ayarlar {0} ile uyumlu değil. - -Daha fazla bilgi için http://support.microsoft.com/kb/811833 adresindeki Microsoft Destk makalesine bakın. - -{0} şimdi kapanacak. - Hatalar diff --git a/mRemoteV1/Resources/Language/Language.uk.resx b/mRemoteV1/Resources/Language/Language.uk.resx index 0f808cf5d..27f468710 100644 --- a/mRemoteV1/Resources/Language/Language.uk.resx +++ b/mRemoteV1/Resources/Language/Language.uk.resx @@ -616,13 +616,6 @@ VncSharp Control Version {0} Не вдалося зашифрувати. {0} - - Налаштування системи безпеки Windows: "Використання системної криптографії FIPS-сумісних алгоритмів шифрування, хешування та підписування», включено. Це налаштування не сумісне з {0}. - -Див. статтю Microsoft Support на http://support.microsoft.com/kb/811833 для отримання додаткової інформації. - -{0} буде закрито. - Помилки diff --git a/mRemoteV1/Resources/Language/Language.zh-CN.resx b/mRemoteV1/Resources/Language/Language.zh-CN.resx index 8c1f8a6cd..eee163426 100644 --- a/mRemoteV1/Resources/Language/Language.zh-CN.resx +++ b/mRemoteV1/Resources/Language/Language.zh-CN.resx @@ -646,11 +646,6 @@ VncSharp 版本 {0} 加密失败。{0} - - Windows 安全设置中已启用"系统加密:使用 FIPS 兼容算法进行加密、散列和签名操作"。此设置与 {0} 不兼容。 -请参阅 Microsoft 支持文章中的详细信息:http://support.microsoft.com/kb/811833 -{0} 即将关闭。 - 错误 diff --git a/mRemoteV1/Resources/Language/Language.zh-TW.resx b/mRemoteV1/Resources/Language/Language.zh-TW.resx index 3b16b76e0..45d1a7778 100644 --- a/mRemoteV1/Resources/Language/Language.zh-TW.resx +++ b/mRemoteV1/Resources/Language/Language.zh-TW.resx @@ -592,13 +592,6 @@ VncSharp Control 版本 {0} 加密失敗。 {0} - - Windows 安全性設定,「系統加密編譯: 使用 FIPS 相容演算法於加密,雜湊,以及簽章」已啟用。 此設定與 {0} 不相容。 - -更多資訊請查看 Microsoft Support 文章於 http://support.microsoft.com/kb/811833? - -{0} 將關閉。 - 錯誤 From 7ec677f021d4eb52e33e9e746142d50256608098 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 8 Feb 2019 17:20:30 -0500 Subject: [PATCH 154/157] conditinally focus --- mRemoteV1/UI/Controls/QuickConnectToolStrip.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index a028a4dda..06d935841 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -203,7 +203,10 @@ namespace mRemoteNG.UI.Controls private void btnQuickConnect_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { SetQuickConnectProtocol(e.ClickedItem.Text); - _cmbQuickConnect.Focus(); + if (string.IsNullOrEmpty(_cmbQuickConnect.Text)) + _cmbQuickConnect.Focus(); + else + btnQuickConnect_ButtonClick(this, e); } private void SetQuickConnectProtocol(string protocol) From c4a1879ae929818e92d262f36855d08cab6e1452 Mon Sep 17 00:00:00 2001 From: Camilo Alvarez Date: Fri, 8 Feb 2019 23:55:04 -0500 Subject: [PATCH 155/157] Remove IsSimpleDropSink restores item sorting for #1266 #1266 was generated by OLV ignoring some sink cusotmizations by using the IsSimpleDropSink flag --- mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs index c7b8fa7e6..52965e136 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs @@ -53,7 +53,6 @@ namespace mRemoteNG.UI.Window this.olvConnections.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; this.olvConnections.HideSelection = false; this.olvConnections.IsSimpleDragSource = true; - this.olvConnections.IsSimpleDropSink = true; this.olvConnections.LabelEdit = true; this.olvConnections.Location = new System.Drawing.Point(0, 24); this.olvConnections.MultiSelect = false; From 4bc3fe0c1b777b9b110971bebca5ed811a19dba0 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 15 Feb 2019 15:59:09 -0500 Subject: [PATCH 156/157] Use .editorconfig to code style/formatting --- .gitignore | 3 --- mRemoteV1/.editorconfig | 44 ++++++++++++++++++++++++++++++++++++++ mRemoteV1/mRemoteV1.csproj | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 mRemoteV1/.editorconfig diff --git a/.gitignore b/.gitignore index 4485ecca0..18a38611e 100644 --- a/.gitignore +++ b/.gitignore @@ -283,9 +283,6 @@ Installer Projects/Installer/Fragments/HelpFilesFragment.wxs InstallerProjects/Installer/Fragments/FilesFragment.wxs InstallerProjects/Installer/Resources/License.rtf -# user preference: .editorconfig - http://editorconfig.org/ -.editorconfig - # gh-pages info runlocal.bat /_site \ No newline at end of file diff --git a/mRemoteV1/.editorconfig b/mRemoteV1/.editorconfig new file mode 100644 index 000000000..6071b8463 --- /dev/null +++ b/mRemoteV1/.editorconfig @@ -0,0 +1,44 @@ +# top-most EditorConfig file +root = true + +[*] +end_of_line = crlf +indent_style = space + +[*.xml] +indent_size = 4 + +[*.cs] +indent_size = 4 +trim_trailing_whitespace = true +charset = utf-8-bom + +# Organize usings +dotnet_sort_system_directives_first = true + +# this. preferences +dotnet_style_qualification_for_field = false:none +dotnet_style_qualification_for_property = false:none +dotnet_style_qualification_for_method = false:none +dotnet_style_qualification_for_event = false:none + +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 1d8372389..1d52374b8 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -1062,6 +1062,7 @@ + From e143c6b5b4c8c0058257f8def9c047bca6710152 Mon Sep 17 00:00:00 2001 From: Sean Kaim Date: Fri, 15 Feb 2019 16:47:56 -0500 Subject: [PATCH 157/157] resharper code reformat (to allow standard code style going forward) --- mRemoteV1/App/CompatibilityChecker.cs | 22 +- mRemoteV1/App/Export.cs | 171 +- mRemoteV1/App/Import.cs | 14 +- mRemoteV1/App/Info/ConnectionsFileInfo.cs | 2 +- mRemoteV1/App/Info/GeneralAppInfo.cs | 78 +- mRemoteV1/App/Info/SettingsFileInfo.cs | 17 +- mRemoteV1/App/Info/UpdateChannelInfo.cs | 8 +- .../Initialization/ConnectionIconLoader.cs | 2 +- .../App/Initialization/CredsAndConsSetup.cs | 8 +- .../Initialization/MessageCollectorSetup.cs | 42 +- .../App/Initialization/StartupDataLogger.cs | 12 +- mRemoteV1/App/Logger.cs | 7 +- mRemoteV1/App/NativeMethods.cs | 53 +- mRemoteV1/App/ProgramRoot.cs | 5 +- mRemoteV1/App/Runtime.cs | 61 +- mRemoteV1/App/Shutdown.cs | 14 +- mRemoteV1/App/Startup.cs | 18 +- mRemoteV1/App/SupportedCultures.cs | 94 +- mRemoteV1/App/Update/AppUpdater.cs | 75 +- mRemoteV1/App/Update/UpdateFile.cs | 15 +- mRemoteV1/App/Update/UpdateInfo.cs | 6 +- mRemoteV1/App/Windows.cs | 5 +- mRemoteV1/Config/ConfirmCloseEnum.cs | 16 +- .../Connections/ConnectionsLoadedEventArgs.cs | 11 +- .../Connections/ConnectionsSavedEventArgs.cs | 7 +- .../Config/Connections/CsvConnectionsSaver.cs | 5 +- .../ConnectionsUpdateAvailableEventArgs.cs | 3 +- .../Multiuser/RemoteConnectionsSyncronizer.cs | 4 +- .../Multiuser/SqlConnectionsUpdateChecker.cs | 18 +- .../Connections/SaveConnectionsOnEdit.cs | 15 +- mRemoteV1/Config/Connections/SaveFormat.cs | 2 +- .../Connections/SqlConnectionsLoader.cs | 21 +- .../Config/Connections/SqlConnectionsSaver.cs | 41 +- .../Connections/XmlConnectionsLoader.cs | 2 +- .../Config/Connections/XmlConnectionsSaver.cs | 20 +- mRemoteV1/Config/CredentialHarvester.cs | 18 +- mRemoteV1/Config/CredentialRecordLoader.cs | 3 +- mRemoteV1/Config/CredentialRecordSaver.cs | 3 +- .../Config/CredentialRepositoryListLoader.cs | 3 +- .../Config/CredentialRepositoryListSaver.cs | 2 +- .../Config/DataProviders/FileBackupCreator.cs | 6 +- .../Config/DataProviders/FileBackupPruner.cs | 4 +- .../Config/DataProviders/FileDataProvider.cs | 5 +- .../Config/DataProviders/IDataProvider.cs | 3 +- .../Config/DataProviders/SqlDataProvider.cs | 4 +- .../ConnectionTestResult.cs | 2 +- .../DatabaseConnectorFactory.cs | 2 +- .../SqlDatabaseConnectionTester.cs | 7 +- .../SqlDatabaseConnector.cs | 6 +- .../Config/Import/ActiveDirectoryImporter.cs | 30 +- .../Config/Import/MRemoteNGCsvImporter.cs | 7 +- .../Config/Import/MRemoteNGXmlImporter.cs | 35 +- mRemoteV1/Config/Import/PortScanImporter.cs | 20 +- .../Import/PuttyConnectionManagerImporter.cs | 8 +- .../Import/RemoteDesktopConnectionImporter.cs | 10 +- .../RemoteDesktopConnectionManagerImporter.cs | 10 +- .../Putty/AbstractPuttySessionsProvider.cs | 79 +- .../Config/Putty/PuttySessionsManager.cs | 183 +- .../Putty/PuttySessionsRegistryProvider.cs | 165 +- .../Putty/PuttySessionsXmingProvider.cs | 631 +++---- ...vConnectionsDeserializerMremotengFormat.cs | 67 +- ...CsvConnectionsSerializerMremotengFormat.cs | 223 +-- .../MsSql/DataTableDeserializer.cs | 72 +- .../MsSql/DataTableSerializer.cs | 28 +- .../MsSql/LocalConnectionPropertiesModel.cs | 2 +- .../LocalConnectionPropertiesXmlSerializer.cs | 34 +- .../MsSql/SqlConnectionListMetaData.cs | 2 +- .../MsSql/SqlDatabaseMetaDataRetriever.cs | 4 +- .../Xml/XmlConnectionNodeSerializer26.cs | 256 ++- .../Xml/XmlConnectionNodeSerializer27.cs | 261 ++- .../Xml/XmlConnectionsDeserializer.cs | 137 +- .../Xml/XmlConnectionsDocumentCompiler.cs | 11 +- .../Xml/XmlConnectionsSerializer.cs | 14 +- .../Xml/XmlExtensions.cs | 8 +- .../Xml/XmlRootNodeSerializer.cs | 21 +- .../CredentialRepositoryListDeserializer.cs | 4 +- .../CredentialRepositoryListSerializer.cs | 16 +- ...XmlCredentialPasswordDecryptorDecorator.cs | 8 +- ...XmlCredentialPasswordEncryptorDecorator.cs | 9 +- .../XmlCredentialRecordDeserializer.cs | 18 +- .../XmlCredentialRecordSerializer.cs | 26 +- .../ActiveDirectoryDeserializer.cs | 7 +- .../PuttyConnectionManagerDeserializer.cs | 7 +- .../RemoteDesktopConnectionDeserializer.cs | 9 +- ...oteDesktopConnectionManagerDeserializer.cs | 52 +- .../Versioning/SqlDatabaseVersionVerifier.cs | 11 +- .../Versioning/SqlVersion22To23Upgrader.cs | 3 +- .../Versioning/SqlVersion23To24Upgrader.cs | 3 +- .../Versioning/SqlVersion24To25Upgrader.cs | 3 +- .../Versioning/SqlVersion25To26Upgrader.cs | 3 +- .../Versioning/SqlVersion26To27Upgrader.cs | 5 +- .../Serializers/XmlConnectionsDecryptor.cs | 23 +- .../Config/Settings/DockPanelLayoutLoader.cs | 3 +- .../Config/Settings/DockPanelLayoutSaver.cs | 3 +- .../Settings/DockPanelLayoutSerializer.cs | 1 + .../Config/Settings/ExternalAppsLoader.cs | 20 +- .../Config/Settings/ExternalAppsSaver.cs | 2 +- .../Settings/Providers/ChooseProvider.cs | 3 +- .../Providers/PortableSettingsProvider.cs | 8 +- mRemoteV1/Config/Settings/SettingsLoader.cs | 197 +-- mRemoteV1/Config/Settings/SettingsSaver.cs | 15 +- .../Connection/AbstractConnectionRecord.cs | 363 ++-- mRemoteV1/Connection/ConnectionIcon.cs | 82 +- mRemoteV1/Connection/ConnectionInfo.cs | 275 +-- .../Connection/ConnectionInfoInheritance.cs | 661 ++++---- mRemoteV1/Connection/ConnectionInitiator.cs | 72 +- mRemoteV1/Connection/ConnectionsService.cs | 100 +- mRemoteV1/Connection/DefaultConnectionInfo.cs | 47 +- .../DefaultConnectionInheritance.cs | 16 +- mRemoteV1/Connection/InterfaceControl.cs | 32 +- .../Protocol/Http/Connection.Protocol.HTTP.cs | 23 +- .../Http/Connection.Protocol.HTTPBase.cs | 380 +++-- .../Connection.Protocol.HTTPS.CertEvent.cs | 25 +- .../Http/Connection.Protocol.HTTPS.cs | 23 +- .../Connection/Protocol/ICA/IcaProtocol.cs | 650 +++---- .../Connection/Protocol/IntegratedProgram.cs | 288 ++-- mRemoteV1/Connection/Protocol/ProtocolBase.cs | 442 ++--- .../Connection/Protocol/ProtocolFactory.cs | 90 +- mRemoteV1/Connection/Protocol/ProtocolList.cs | 104 +- mRemoteV1/Connection/Protocol/ProtocolType.cs | 16 +- mRemoteV1/Connection/Protocol/PuttyBase.cs | 423 ++--- .../Connection/Protocol/RAW/RawProtocol.cs | 24 +- .../RDP/AzureLoadBalanceInfoEncoder.cs | 2 +- .../Connection/Protocol/RDP/RdpClientWrap.cs | 6 +- .../Connection/Protocol/RDP/RdpErrorCodes.cs | 20 +- .../Connection/Protocol/RDP/RdpProtocol.cs | 1490 ++++++++-------- .../Rlogin/Connection.Protocol.Rlogin.cs | 25 +- .../Protocol/SSH/Connection.Protocol.SSH1.cs | 31 +- .../Protocol/SSH/Connection.Protocol.SSH2.cs | 29 +- .../Serial/Connection.Protocol.Serial.cs | 25 +- .../Telnet/Connection.Protocol.Telnet.cs | 25 +- .../Protocol/VNC/Connection.Protocol.VNC.cs | 500 +++--- mRemoteV1/Connection/Protocol/VNC/VNCEnum.cs | 155 +- mRemoteV1/Connection/PuttySessionInfo.cs | 101 +- mRemoteV1/Container/ContainerInfo.cs | 83 +- .../CredentialDeletionMsgBoxConfirmer.cs | 18 +- .../CredentialRecordTypeConverter.cs | 18 +- .../Credential/CredentialServiceFacade.cs | 14 +- .../Credential/CredentialServiceFactory.cs | 13 +- .../Credential/PlaceholderCredentialRecord.cs | 14 +- .../CredentialRepositoryConfig.cs | 5 +- .../Repositories/CredentialRepositoryList.cs | 13 +- .../Repositories/XmlCredentialRepository.cs | 11 +- .../XmlCredentialRepositoryFactory.cs | 3 +- mRemoteV1/Messages/Message.cs | 14 +- mRemoteV1/Messages/MessageCollector.cs | 20 +- .../NotificationPanelMessageWriter.cs | 2 +- .../MessageWriters/PopupMessageWriter.cs | 12 +- .../WriterDecorators/MessageFocusDecorator.cs | 9 +- .../MessageTypeFilterDecorator.cs | 1 + mRemoteV1/Properties/AssemblyInfo.cs | 1 - mRemoteV1/Properties/Settings.settings | 1396 +++++++-------- mRemoteV1/Resources/Help/Index.htm | 116 +- mRemoteV1/Resources/Help/Introduction.htm | 36 +- mRemoteV1/Resources/Help/Main.css | 108 +- .../Help/gs_command_line_switches.htm | 138 +- mRemoteV1/Resources/Help/gs_installation.htm | 44 +- mRemoteV1/Resources/Help/gs_prerequisites.htm | 170 +- .../Resources/Help/gs_running_mremoteng.htm | 330 ++-- .../Resources/Help/st_common_problems_rdp.htm | 123 +- mRemoteV1/Resources/Help/ui_config.htm | 108 +- mRemoteV1/Resources/Help/ui_connections.htm | 152 +- .../Resources/Help/ui_external_tools.htm | 280 +-- mRemoteV1/Resources/Help/ui_file_transfer.htm | 91 +- .../Resources/Help/ui_import_and_export.htm | 80 +- .../Resources/Help/ui_keyboardshortcuts.htm | 178 +- mRemoteV1/Resources/Help/ui_menus.htm | 274 +-- mRemoteV1/Resources/Help/ui_navigation.htm | 226 +-- mRemoteV1/Resources/Help/ui_notifications.htm | 126 +- mRemoteV1/Resources/Help/ui_options.htm | 656 ++++---- mRemoteV1/Resources/Help/ui_port_scan.htm | 91 +- mRemoteV1/Resources/Help/ui_quick_connect.htm | 48 +- .../Resources/Help/ui_screenshot_manager.htm | 102 +- .../Resources/Help/ui_sql_configuration.htm | 80 +- .../mRemoteNG.VisualElementsManifest.xml | 14 +- mRemoteV1/Schemas/mremoteng_confcons_v2_5.xsd | 264 +-- mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd | 284 ++-- mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd | 296 ++-- .../Schemas/mremoteng_credrepo_list_v1_0.xsd | 42 +- mRemoteV1/Schemas/mremoteng_creds_v1_0.xsd | 54 +- .../Authentication/PasswordAuthenticator.cs | 6 +- mRemoteV1/Security/BlockCipherEngines.cs | 4 +- mRemoteV1/Security/BlockCipherModes.cs | 4 +- mRemoteV1/Security/EncryptedSecureString.cs | 3 +- .../CryptoProviderFactoryFromSettings.cs | 4 +- .../Factories/CryptoProviderFactoryFromXml.cs | 6 +- .../KeyDerivation/IKeyDerivationFunction.cs | 3 +- .../KeyDerivation/Pkcs5S2KeyGenerator.cs | 2 +- ...wordIncludesSpecialCharactersConstraint.cs | 7 +- .../PasswordLengthConstraint.cs | 3 +- mRemoteV1/Security/RandomGenerator.cs | 4 +- mRemoteV1/Security/SaveFilter.cs | 31 +- .../AeadCryptographyProvider.cs | 26 +- .../LegacyRijndaelCryptographyProvider.cs | 102 +- mRemoteV1/Settings.cs | 19 +- mRemoteV1/Themes/ExtendedColorPalette.cs | 31 +- .../Themes/MremoteNGPaletteManipulator.cs | 30 +- mRemoteV1/Themes/MremoteNGThemeBase.cs | 4 +- mRemoteV1/Themes/ThemeInfo.cs | 51 +- mRemoteV1/Themes/ThemeManager.cs | 108 +- mRemoteV1/Themes/ThemeSerializer.cs | 44 +- mRemoteV1/Tools/Authenticode.cs | 9 +- .../Tools/Cmdline/CmdArgumentsInterpreter.cs | 7 + .../Tools/Cmdline/CommandLineArguments.cs | 240 +-- .../Cmdline/StartupArgumentsInterpreter.cs | 27 +- .../ConnectionsTreeToMenuItemsConverter.cs | 5 +- .../FullyObservableCollection.cs | 84 +- mRemoteV1/Tools/DisposableOptional.cs | 2 +- mRemoteV1/Tools/EnumWindows.cs | 93 +- mRemoteV1/Tools/Extensions.cs | 63 +- mRemoteV1/Tools/ExternalTool.cs | 234 +-- mRemoteV1/Tools/ExternalToolArgumentParser.cs | 14 +- mRemoteV1/Tools/ExternalToolsService.cs | 3 +- mRemoteV1/Tools/ExternalToolsTypeConverter.cs | 2 +- mRemoteV1/Tools/IeBrowserEmulation.cs | 39 +- mRemoteV1/Tools/MiscTools.cs | 329 ++-- mRemoteV1/Tools/MouseClickSimulator.cs | 4 +- mRemoteV1/Tools/MultiSSHController.cs | 18 +- mRemoteV1/Tools/NotificationAreaIcon.cs | 8 +- mRemoteV1/Tools/Optional.cs | 126 +- mRemoteV1/Tools/PortScanner.cs | 304 ++-- mRemoteV1/Tools/ProcessController.cs | 263 +-- mRemoteV1/Tools/PropertyGridCommandSite.cs | 307 ++-- mRemoteV1/Tools/PuttyProcessController.cs | 20 +- mRemoteV1/Tools/PuttyTypeDetector.cs | 134 +- mRemoteV1/Tools/ReconnectGroup.cs | 233 +-- mRemoteV1/Tools/ScanHost.cs | 65 +- mRemoteV1/Tools/SecureTransfer.cs | 26 +- mRemoteV1/Tools/Tools.LocalizedAttributes.cs | 259 +-- mRemoteV1/Tools/Tools.SystemMenu.cs | 80 +- mRemoteV1/Tools/Tools.WindowPlacement.cs | 151 +- .../Tools/WindowsRegistry/RegistryHive.cs | 2 +- .../Tools/WindowsRegistry/WindowsRegistry.cs | 2 +- mRemoteV1/Tree/AlwaysConfirmYes.cs | 3 +- .../OpenConnectionClickHandler.cs | 3 +- .../SwitchToConnectionClickHandler.cs | 3 +- .../TreeNodeCompositeClickHandler.cs | 3 +- .../Tree/ConnectionTreeDragAndDropHandler.cs | 35 +- mRemoteV1/Tree/ConnectionTreeModel.cs | 12 +- mRemoteV1/Tree/NodeSearcher.cs | 3 +- mRemoteV1/Tree/NodeType.cs | 2 +- mRemoteV1/Tree/PreviousSessionOpener.cs | 9 +- .../Tree/PreviouslyOpenedFolderExpander.cs | 3 +- mRemoteV1/Tree/Root/RootNodeInfo.cs | 104 +- .../Tree/Root/RootPuttySessionsNodeInfo.cs | 38 +- mRemoteV1/UI/Controls/Base/NGButton.cs | 20 +- mRemoteV1/UI/Controls/Base/NGCheckBox.cs | 9 +- mRemoteV1/UI/Controls/Base/NGComboBox.cs | 47 +- mRemoteV1/UI/Controls/Base/NGGroupBox.cs | 31 +- mRemoteV1/UI/Controls/Base/NGLabel.cs | 9 +- mRemoteV1/UI/Controls/Base/NGListView.cs | 7 +- mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs | 17 +- mRemoteV1/UI/Controls/Base/NGPictureBox.cs | 2 +- mRemoteV1/UI/Controls/Base/NGProgressBar.cs | 7 +- mRemoteV1/UI/Controls/Base/NGRadioButton.cs | 19 +- mRemoteV1/UI/Controls/Base/NGTextBox.cs | 10 +- .../UI/Controls/ConnectionContextMenu.cs | 90 +- .../Controls/ConnectionTree/ConnectionTree.cs | 129 +- .../ConnectionTreeSearchTextFilter.cs | 2 +- .../ConnectionTree/IConnectionTreeDelegate.cs | 3 +- .../UI/Controls/ConnectionTree/NameColumn.cs | 4 +- .../UI/Controls/CredentialRecordListBox.cs | 4 +- .../UI/Controls/CredentialRecordListView.cs | 20 +- .../Controls/CredentialRepositoryListView.cs | 18 +- .../UI/Controls/ExternalToolsToolStrip.cs | 20 +- .../FilteredPropertyGrid.cs | 411 ++--- .../FilteredPropertyGrid/ObjectWrapper.cs | 198 +-- mRemoteV1/UI/Controls/HeadlessTabControl.cs | 4 +- mRemoteV1/UI/Controls/IPTextBox.cs | 498 +++--- mRemoteV1/UI/Controls/MultiSshToolStrip.cs | 102 +- .../Controls/NewPasswordWithVerification.cs | 7 +- .../UI/Controls/PageSequence/PageSequence.cs | 4 +- .../Controls/PageSequence/SequencedControl.cs | 4 +- mRemoteV1/UI/Controls/QuickConnectComboBox.cs | 443 ++--- .../UI/Controls/QuickConnectToolStrip.cs | 39 +- mRemoteV1/UI/Controls/SecureTextBox.cs | 2 - mRemoteV1/UI/Controls/StatusImageList.cs | 14 +- mRemoteV1/UI/Controls/TextBoxExtensions.cs | 6 +- mRemoteV1/UI/Controls/ToolStripSplitButton.cs | 105 +- mRemoteV1/UI/DialogFactory.cs | 26 +- mRemoteV1/UI/DisplayProperties.cs | 4 +- mRemoteV1/UI/FontOverrider.cs | 3 +- mRemoteV1/UI/FormExtensions.cs | 8 +- mRemoteV1/UI/Forms/ExportForm.cs | 320 ++-- mRemoteV1/UI/Forms/FrmSplashScreen.cs | 2 +- mRemoteV1/UI/Forms/FullscreenHandler.cs | 2 + mRemoteV1/UI/Forms/Input/FrmInputBox.cs | 2 +- .../UI/Forms/OptionsPages/AdvancedPage.cs | 12 +- .../UI/Forms/OptionsPages/AppearancePage.cs | 6 +- .../UI/Forms/OptionsPages/ConnectionsPage.cs | 25 +- .../UI/Forms/OptionsPages/CredentialsPage.cs | 11 +- .../Forms/OptionsPages/NotificationsPage.cs | 1 - .../UI/Forms/OptionsPages/OptionsPage.cs | 62 +- .../UI/Forms/OptionsPages/SecurityPage.cs | 8 +- .../UI/Forms/OptionsPages/SqlServerPage.cs | 19 +- .../UI/Forms/OptionsPages/TabsPanelsPage.cs | 12 +- mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs | 35 +- .../UI/Forms/OptionsPages/UpdatesPage.cs | 64 +- mRemoteV1/UI/Forms/PasswordForm.cs | 127 +- mRemoteV1/UI/Forms/TextBox.cs | 59 +- .../UI/Forms/UnhandledExceptionWindow.cs | 20 +- mRemoteV1/UI/Forms/frmChoosePanel.cs | 108 +- mRemoteV1/UI/Forms/frmMain.cs | 654 +++---- mRemoteV1/UI/Forms/frmOptions.cs | 6 +- .../GdiPlusGraphicsProvider.cs | 10 +- .../UI/GraphicsUtilities/IGraphicsProvider.cs | 2 +- mRemoteV1/UI/Menu/HelpMenu.cs | 26 +- mRemoteV1/UI/Menu/MainFileMenu.cs | 25 +- .../UI/Menu/ScreenSelectionSystemMenu.cs | 12 +- mRemoteV1/UI/Menu/ToolsMenu.cs | 24 +- mRemoteV1/UI/Menu/ViewMenu.cs | 179 +- mRemoteV1/UI/Panels/PanelAdder.cs | 16 +- mRemoteV1/UI/Tabs/ConnectionTab.cs | 17 +- mRemoteV1/UI/Tabs/DockPaneStripNG.cs | 183 +- mRemoteV1/UI/Tabs/Enums.cs | 1 - mRemoteV1/UI/Tabs/FloatWindowNG.cs | 10 +- mRemoteV1/UI/Tabs/MremoteNGAutoHideStrip.cs | 58 +- mRemoteV1/UI/Tabs/TabHelper.cs | 20 +- mRemoteV1/UI/TaskDialog/CommandButton.cs | 56 +- mRemoteV1/UI/TaskDialog/cTaskDialog.cs | 291 ++-- mRemoteV1/UI/TaskDialog/frmTaskDialog.cs | 108 +- mRemoteV1/UI/Window/AboutWindow.cs | 144 +- .../UI/Window/ActiveDirectoryImportWindow.cs | 1 - mRemoteV1/UI/Window/BaseWindow.cs | 27 +- mRemoteV1/UI/Window/ComponentsCheckWindow.cs | 199 ++- mRemoteV1/UI/Window/ConfigWindow.cs | 1058 ++++++------ mRemoteV1/UI/Window/ConnectionTreeWindow.cs | 363 ++-- mRemoteV1/UI/Window/ConnectionWindow.cs | 116 +- mRemoteV1/UI/Window/ErrorAndInfoWindow.cs | 555 +++--- mRemoteV1/UI/Window/ExternalToolsWindow.cs | 395 +++-- mRemoteV1/UI/Window/HelpWindow.cs | 370 ++-- mRemoteV1/UI/Window/PortScanWindow.cs | 436 ++--- mRemoteV1/UI/Window/SSHTransferWindow.cs | 77 +- .../UI/Window/ScreenshotManagerWindow.cs | 574 ++++--- mRemoteV1/UI/Window/UltraVNCWindow.cs | 179 +- mRemoteV1/UI/Window/UpdateWindow.cs | 459 ++--- mRemoteV1/UI/WindowList.cs | 155 +- mRemoteV1/UI/WindowType.cs | 36 +- mRemoteV1/app.config | 1497 +++++++++-------- mRemoteV1/packages.config | 21 +- 340 files changed, 17282 insertions(+), 14624 deletions(-) diff --git a/mRemoteV1/App/CompatibilityChecker.cs b/mRemoteV1/App/CompatibilityChecker.cs index ddb6e517f..a5a4d2814 100644 --- a/mRemoteV1/App/CompatibilityChecker.cs +++ b/mRemoteV1/App/CompatibilityChecker.cs @@ -21,7 +21,8 @@ namespace mRemoteNG.App { if (Settings.Default.OverrideFIPSCheck) { - messageCollector.AddMessage(MessageClass.InformationMsg, "OverrideFIPSCheck is set. Will skip check...", true); + messageCollector.AddMessage(MessageClass.InformationMsg, "OverrideFIPSCheck is set. Will skip check...", + true); return; } @@ -34,7 +35,12 @@ namespace mRemoteNG.App //About to pop up a message, let's not block it... FrmSplashScreen.getInstance().Close(); - var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, errorText, "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning); + var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, + Language.strCompatibilityProblemDetected, errorText, "", + "", + Language.strCheckboxDoNotShowThisMessageAgain, + ETaskDialogButtons.OkCancel, ESysIcons.Warning, + ESysIcons.Warning); if (CTaskDialog.VerificationChecked && ShouldIStayOrShouldIGo == DialogResult.OK) { messageCollector.AddMessage(MessageClass.ErrorMsg, "User requests that FIPS check be overridden", true); @@ -58,7 +64,8 @@ namespace mRemoteNG.App private static bool FipsPolicyEnabledForServer2008AndNewer() { - var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa\\FIPSAlgorithmPolicy"); + var regKey = + Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa\\FIPSAlgorithmPolicy"); var fipsPolicy = regKey?.GetValue("Enabled"); if (fipsPolicy == null) return false; fipsPolicy = Convert.ToInt32(fipsPolicy); @@ -83,9 +90,14 @@ namespace mRemoteNG.App } if (proccesses.Length <= 0) return; - CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, Application.ProductName), "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, ESysIcons.Warning, ESysIcons.Warning); + CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, + string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, + Application.ProductName), "", + "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, + ESysIcons.Warning, + ESysIcons.Warning); if (CTaskDialog.VerificationChecked) Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false; } } -} +} \ No newline at end of file diff --git a/mRemoteV1/App/Export.cs b/mRemoteV1/App/Export.cs index a6feb2295..df8baad35 100644 --- a/mRemoteV1/App/Export.cs +++ b/mRemoteV1/App/Export.cs @@ -17,92 +17,101 @@ using mRemoteNG.UI.Forms; namespace mRemoteNG.App { - public static class Export - { - public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel) - { - try - { - var saveFilter = new SaveFilter(); - - using (var exportForm = new ExportForm()) - { - if (selectedNode?.GetTreeNodeType() == TreeNodeType.Container) - exportForm.SelectedFolder = selectedNode as ContainerInfo; - else if (selectedNode?.GetTreeNodeType() == TreeNodeType.Connection) - { - if (selectedNode.Parent.GetTreeNodeType() == TreeNodeType.Container) - exportForm.SelectedFolder = selectedNode.Parent; - exportForm.SelectedConnection = selectedNode; - } - - if (exportForm.ShowDialog(FrmMain.Default) != DialogResult.OK) - return; + public static class Export + { + public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel) + { + try + { + var saveFilter = new SaveFilter(); - ConnectionInfo exportTarget; - switch (exportForm.Scope) - { - case ExportForm.ExportScope.SelectedFolder: - exportTarget = exportForm.SelectedFolder; - break; + using (var exportForm = new ExportForm()) + { + if (selectedNode?.GetTreeNodeType() == TreeNodeType.Container) + exportForm.SelectedFolder = selectedNode as ContainerInfo; + else if (selectedNode?.GetTreeNodeType() == TreeNodeType.Connection) + { + if (selectedNode.Parent.GetTreeNodeType() == TreeNodeType.Container) + exportForm.SelectedFolder = selectedNode.Parent; + exportForm.SelectedConnection = selectedNode; + } + + if (exportForm.ShowDialog(FrmMain.Default) != DialogResult.OK) + return; + + ConnectionInfo exportTarget; + switch (exportForm.Scope) + { + case ExportForm.ExportScope.SelectedFolder: + exportTarget = exportForm.SelectedFolder; + break; case ExportForm.ExportScope.SelectedConnection: - exportTarget = exportForm.SelectedConnection; - break; - default: - exportTarget = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo); - break; - } - - saveFilter.SaveUsername = exportForm.IncludeUsername; - saveFilter.SavePassword = exportForm.IncludePassword; - saveFilter.SaveDomain = exportForm.IncludeDomain; - saveFilter.SaveInheritance = exportForm.IncludeInheritance; - saveFilter.SaveCredentialId = exportForm.IncludeAssignedCredential; - - SaveExportFile(exportForm.FileName, exportForm.SaveFormat, saveFilter, exportTarget); - } - - } - catch (Exception ex) - { + exportTarget = exportForm.SelectedConnection; + break; + default: + exportTarget = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo); + break; + } + + saveFilter.SaveUsername = exportForm.IncludeUsername; + saveFilter.SavePassword = exportForm.IncludePassword; + saveFilter.SaveDomain = exportForm.IncludeDomain; + saveFilter.SaveInheritance = exportForm.IncludeInheritance; + saveFilter.SaveCredentialId = exportForm.IncludeAssignedCredential; + + SaveExportFile(exportForm.FileName, exportForm.SaveFormat, saveFilter, exportTarget); + } + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionMessage("App.Export.ExportToFile() failed.", ex); - } - } - - private static void SaveExportFile(string fileName, SaveFormat saveFormat, SaveFilter saveFilter, ConnectionInfo exportTarget) - { - try - { - ISerializer serializer; - switch (saveFormat) - { - case SaveFormat.mRXML: + } + } + + private static void SaveExportFile(string fileName, + SaveFormat saveFormat, + SaveFilter saveFilter, + ConnectionInfo exportTarget) + { + try + { + ISerializer serializer; + switch (saveFormat) + { + case SaveFormat.mRXML: var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); - var rootNode = exportTarget.GetRootParent() as RootNodeInfo; + var rootNode = exportTarget.GetRootParent() as RootNodeInfo; var connectionNodeSerializer = new XmlConnectionNodeSerializer27( - cryptographyProvider, - rootNode?.PasswordString.ConvertToSecureString() ?? new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(), - saveFilter); - serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer); - break; - case SaveFormat.mRCSV: - serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog); + cryptographyProvider, + rootNode?.PasswordString + .ConvertToSecureString() ?? + new RootNodeInfo(RootNodeType + .Connection) + .PasswordString + .ConvertToSecureString(), + saveFilter); + serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer); break; - default: - throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null); - } - var serializedData = serializer.Serialize(exportTarget); - var fileDataProvider = new FileDataProvider(fileName); + case SaveFormat.mRCSV: + serializer = + new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog); + break; + default: + throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null); + } + + var serializedData = serializer.Serialize(exportTarget); + var fileDataProvider = new FileDataProvider(fileName); fileDataProvider.Save(serializedData); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace($"Export.SaveExportFile(\"{fileName}\") failed.", ex); - } - finally - { - Runtime.ConnectionsService.RemoteConnectionsSyncronizer?.Enable(); - } - } - } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace($"Export.SaveExportFile(\"{fileName}\") failed.", ex); + } + finally + { + Runtime.ConnectionsService.RemoteConnectionsSyncronizer?.Enable(); + } + } + } } \ No newline at end of file diff --git a/mRemoteV1/App/Import.cs b/mRemoteV1/App/Import.cs index 119b98264..0a837cf7a 100644 --- a/mRemoteV1/App/Import.cs +++ b/mRemoteV1/App/Import.cs @@ -44,8 +44,10 @@ namespace mRemoteNG.App } catch (Exception ex) { - MessageBox.Show(string.Format(Language.strImportFileFailedContent, fileName), Language.strImportFileFailedMainInstruction, - MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); + MessageBox.Show(string.Format(Language.strImportFileFailedContent, fileName), + Language.strImportFileFailedMainInstruction, + MessageBoxButtons.OK, MessageBoxIcon.Exclamation, + MessageBoxDefaultButton.Button1); Runtime.MessageCollector.AddExceptionMessage("Unable to import file.", ex); } } @@ -59,7 +61,9 @@ namespace mRemoteNG.App } } - public static void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOu) + public static void ImportFromActiveDirectory(string ldapPath, + ContainerInfo importDestinationContainer, + bool importSubOu) { try { @@ -72,7 +76,9 @@ namespace mRemoteNG.App } } - public static void ImportFromPortScan(IEnumerable hosts, ProtocolType protocol, ContainerInfo importDestinationContainer) + public static void ImportFromPortScan(IEnumerable hosts, + ProtocolType protocol, + ContainerInfo importDestinationContainer) { try { diff --git a/mRemoteV1/App/Info/ConnectionsFileInfo.cs b/mRemoteV1/App/Info/ConnectionsFileInfo.cs index 6017865f1..36793e36d 100644 --- a/mRemoteV1/App/Info/ConnectionsFileInfo.cs +++ b/mRemoteV1/App/Info/ConnectionsFileInfo.cs @@ -1,6 +1,6 @@ namespace mRemoteNG.App.Info { - public static class ConnectionsFileInfo + public static class ConnectionsFileInfo { public static readonly string DefaultConnectionsPath = SettingsFileInfo.SettingsPath; public static readonly string DefaultConnectionsFile = "confCons.xml"; diff --git a/mRemoteV1/App/Info/GeneralAppInfo.cs b/mRemoteV1/App/Info/GeneralAppInfo.cs index a6170b4bc..fe424beb9 100644 --- a/mRemoteV1/App/Info/GeneralAppInfo.cs +++ b/mRemoteV1/App/Info/GeneralAppInfo.cs @@ -9,45 +9,53 @@ using static System.Environment; namespace mRemoteNG.App.Info { - public static class GeneralAppInfo - { - public const string UrlHome = "https://www.mremoteng.org/"; - public const string UrlDonate = "https://mremoteng.org/contribute/"; - public const string UrlForum = "https://www.reddit.com/r/mRemoteNG/"; - public const string UrlBugs = "https://bugs.mremoteng.org/"; - public static string ApplicationVersion = Application.ProductVersion; + public static class GeneralAppInfo + { + public const string UrlHome = "https://www.mremoteng.org/"; + public const string UrlDonate = "https://mremoteng.org/contribute/"; + public const string UrlForum = "https://www.reddit.com/r/mRemoteNG/"; + public const string UrlBugs = "https://bugs.mremoteng.org/"; + public static string ApplicationVersion = Application.ProductVersion; public static readonly string ProductName = Application.ProductName; - public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false)).Copyright; + + public static readonly string Copyright = + ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), + typeof(AssemblyCopyrightAttribute), false)) + .Copyright; + public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); - //public static string ReportingFilePath = ""; - public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe"; + + //public static string ReportingFilePath = ""; + public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe"; + public static string UserAgent - { - get - { - var details = new List - { - "compatible", - OSVersion.Platform == PlatformID.Win32NT - ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}" - : OSVersion.VersionString - }; - if (Is64BitProcess) - { - details.Add("WOW64"); - } - details.Add(Thread.CurrentThread.CurrentUICulture.Name); - details.Add($".NET CLR {Environment.Version}"); - var detailsString = string.Join("; ", details.ToArray()); + { + get + { + var details = new List + { + "compatible", + OSVersion.Platform == PlatformID.Win32NT + ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}" + : OSVersion.VersionString + }; + if (Is64BitProcess) + { + details.Add("WOW64"); + } - return $"Mozilla/5.0 ({detailsString}) {ProductName}/{ApplicationVersion}"; - } - } + details.Add(Thread.CurrentThread.CurrentUICulture.Name); + details.Add($".NET CLR {Environment.Version}"); + var detailsString = string.Join("; ", details.ToArray()); - public static Version GetApplicationVersion() - { + return $"Mozilla/5.0 ({detailsString}) {ProductName}/{ApplicationVersion}"; + } + } + + public static Version GetApplicationVersion() + { System.Version.TryParse(ApplicationVersion, out var v); - return v; - } - } + return v; + } + } } \ No newline at end of file diff --git a/mRemoteV1/App/Info/SettingsFileInfo.cs b/mRemoteV1/App/Info/SettingsFileInfo.cs index a91d9497a..e6007b9f8 100644 --- a/mRemoteV1/App/Info/SettingsFileInfo.cs +++ b/mRemoteV1/App/Info/SettingsFileInfo.cs @@ -8,13 +8,22 @@ namespace mRemoteNG.App.Info { public static class SettingsFileInfo { - private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location); + private static readonly string ExePath = + Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location); + + public static string SettingsPath => + Runtime.IsPortableEdition + ? ExePath + : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName; - public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName; public static string LayoutFileName { get; } = "pnlLayout.xml"; public static string ExtAppsFilesName { get; } = "extApps.xml"; public static string ThemesFileName { get; } = "Themes.xml"; - public static string ThemeFolder { get; } = SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty; - public static string InstalledThemeFolder { get; } = ExePath != null ? Path.Combine(ExePath, "Themes") : String.Empty; + + public static string ThemeFolder { get; } = + SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty; + + public static string InstalledThemeFolder { get; } = + ExePath != null ? Path.Combine(ExePath, "Themes") : String.Empty; } } \ No newline at end of file diff --git a/mRemoteV1/App/Info/UpdateChannelInfo.cs b/mRemoteV1/App/Info/UpdateChannelInfo.cs index e3b3f4e2f..c5f3ec462 100644 --- a/mRemoteV1/App/Info/UpdateChannelInfo.cs +++ b/mRemoteV1/App/Info/UpdateChannelInfo.cs @@ -1,4 +1,5 @@ using System; + // ReSharper disable InconsistentNaming namespace mRemoteNG.App.Info @@ -27,7 +28,9 @@ namespace mRemoteNG.App.Info private static string GetChannelFileName(string channel) { - return Runtime.IsPortableEdition ? GetChannelFileNamePortableEdition(channel) : GetChannelFileNameNormalEdition(channel); + return Runtime.IsPortableEdition + ? GetChannelFileNamePortableEdition(channel) + : GetChannelFileNameNormalEdition(channel); } private static string GetChannelFileNameNormalEdition(string channel) @@ -62,7 +65,8 @@ namespace mRemoteNG.App.Info private static Uri GetUpdateTxtUri(string channel) { - return new Uri(new Uri(Settings.Default.UpdateAddress), new Uri(GetChannelFileName(channel), UriKind.Relative)); + return new Uri(new Uri(Settings.Default.UpdateAddress), + new Uri(GetChannelFileName(channel), UriKind.Relative)); } private static bool IsValidChannel(string s) diff --git a/mRemoteV1/App/Initialization/ConnectionIconLoader.cs b/mRemoteV1/App/Initialization/ConnectionIconLoader.cs index f9282ff8b..b9267f632 100644 --- a/mRemoteV1/App/Initialization/ConnectionIconLoader.cs +++ b/mRemoteV1/App/Initialization/ConnectionIconLoader.cs @@ -11,7 +11,7 @@ namespace mRemoteNG.App.Initialization public ConnectionIconLoader(string folderPath) { - if(string.IsNullOrEmpty(folderPath)) + if (string.IsNullOrEmpty(folderPath)) throw new ArgumentException($"{nameof(folderPath)} must be a valid folder path."); _path = folderPath; diff --git a/mRemoteV1/App/Initialization/CredsAndConsSetup.cs b/mRemoteV1/App/Initialization/CredsAndConsSetup.cs index af4b33299..43a0ac088 100644 --- a/mRemoteV1/App/Initialization/CredsAndConsSetup.cs +++ b/mRemoteV1/App/Initialization/CredsAndConsSetup.cs @@ -3,14 +3,16 @@ using mRemoteNG.Config.Connections; namespace mRemoteNG.App.Initialization { - public class CredsAndConsSetup + public class CredsAndConsSetup { public void LoadCredsAndCons() { new SaveConnectionsOnEdit(Runtime.ConnectionsService); - if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation && !File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName())) - Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService.GetStartupConnectionFileName()); + if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation && + !File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName())) + Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService + .GetStartupConnectionFileName()); Runtime.LoadConnections(); } diff --git a/mRemoteV1/App/Initialization/MessageCollectorSetup.cs b/mRemoteV1/App/Initialization/MessageCollectorSetup.cs index 5f110cc71..faf6a3944 100644 --- a/mRemoteV1/App/Initialization/MessageCollectorSetup.cs +++ b/mRemoteV1/App/Initialization/MessageCollectorSetup.cs @@ -8,7 +8,8 @@ namespace mRemoteNG.App.Initialization { public class MessageCollectorSetup { - public static void SetupMessageCollector(MessageCollector messageCollector, IList messageWriterList) + public static void SetupMessageCollector(MessageCollector messageCollector, + IList messageWriterList) { messageCollector.CollectionChanged += (o, args) => { @@ -37,34 +38,37 @@ namespace mRemoteNG.App.Initialization private static IMessageWriter BuildTextLogMessageWriter() { return new MessageTypeFilterDecorator( - new LogMessageTypeFilteringOptions(), - new TextLogMessageWriter(Logger.Instance) - ); + new LogMessageTypeFilteringOptions(), + new TextLogMessageWriter(Logger.Instance) + ); } private static IMessageWriter BuildNotificationPanelMessageWriter() { - return new OnlyLogMessageFilter( - new MessageTypeFilterDecorator( - new NotificationPanelMessageFilteringOptions(), - new MessageFocusDecorator( - Windows.ErrorsForm, - new NotificationPanelSwitchOnMessageFilteringOptions(), - new NotificationPanelMessageWriter(Windows.ErrorsForm) - ) - ) - ); + new MessageTypeFilterDecorator( + new + NotificationPanelMessageFilteringOptions(), + new MessageFocusDecorator( + Windows.ErrorsForm, + new + NotificationPanelSwitchOnMessageFilteringOptions(), + new + NotificationPanelMessageWriter(Windows + .ErrorsForm) + ) + ) + ); } private static IMessageWriter BuildPopupMessageWriter() { return new OnlyLogMessageFilter( - new MessageTypeFilterDecorator( - new PopupMessageFilteringOptions(), - new PopupMessageWriter() - ) - ); + new MessageTypeFilterDecorator( + new PopupMessageFilteringOptions(), + new PopupMessageWriter() + ) + ); } } } \ No newline at end of file diff --git a/mRemoteV1/App/Initialization/StartupDataLogger.cs b/mRemoteV1/App/Initialization/StartupDataLogger.cs index e5ea3a23e..d4bc791ef 100644 --- a/mRemoteV1/App/Initialization/StartupDataLogger.cs +++ b/mRemoteV1/App/Initialization/StartupDataLogger.cs @@ -43,7 +43,8 @@ namespace mRemoteNG.App.Initialization try { - foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True").Get()) + foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True") + .Get()) { var managementObject = (ManagementObject)o; osVersion = Convert.ToString(managementObject.GetPropertyValue("Caption")).Trim(); @@ -54,6 +55,7 @@ namespace mRemoteNG.App.Initialization { _messageCollector.AddExceptionMessage("Error retrieving operating system information from WMI.", ex); } + var osData = string.Join(" ", osVersion, servicePack); return osData; } @@ -65,6 +67,7 @@ namespace mRemoteNG.App.Initialization { servicePack = $"Service Pack {servicePackNumber}"; } + return servicePack; } @@ -73,7 +76,8 @@ namespace mRemoteNG.App.Initialization var architecture = string.Empty; try { - foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get()) + foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID=\'CPU0\'") + .Get()) { var managementObject = (ManagementObject)o; var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth")); @@ -84,6 +88,7 @@ namespace mRemoteNG.App.Initialization { _messageCollector.AddExceptionMessage("Error retrieving operating system address width from WMI.", ex); } + return architecture; } @@ -110,7 +115,8 @@ namespace mRemoteNG.App.Initialization private void LogCultureData() { - var data = $"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}"; + var data = + $"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}"; _messageCollector.AddMessage(MessageClass.InformationMsg, data, true); } } diff --git a/mRemoteV1/App/Logger.cs b/mRemoteV1/App/Logger.cs index 4031e0587..b39fffb40 100644 --- a/mRemoteV1/App/Logger.cs +++ b/mRemoteV1/App/Logger.cs @@ -4,11 +4,12 @@ using System.Windows.Forms; using log4net; using log4net.Appender; using log4net.Config; + // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.App { - public class Logger + public class Logger { public static readonly Logger Instance = new Logger(); @@ -42,6 +43,7 @@ namespace mRemoteNG.App fileAppender.File = path; fileAppender.ActivateOptions(); } + Log = LogManager.GetLogger("Logger"); } @@ -56,7 +58,8 @@ namespace mRemoteNG.App private static string GetLogPathNormalEdition() { - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName); + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + Application.ProductName); } private static string GetLogPathPortableEdition() diff --git a/mRemoteV1/App/NativeMethods.cs b/mRemoteV1/App/NativeMethods.cs index 45b2ba36e..0e15954b6 100644 --- a/mRemoteV1/App/NativeMethods.cs +++ b/mRemoteV1/App/NativeMethods.cs @@ -12,6 +12,7 @@ namespace mRemoteNG.App public static class NativeMethods { #region Functions + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool AppendMenu(IntPtr hMenu, int uFlags, IntPtr uIDNewItem, string lpNewItem); @@ -19,7 +20,10 @@ namespace mRemoteNG.App internal static extern IntPtr CreatePopupMenu(); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle); + internal static extern IntPtr FindWindowEx(IntPtr parentHandle, + IntPtr childAfter, + string lclassName, + string windowTitle); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr GetForegroundWindow(); @@ -28,7 +32,11 @@ namespace mRemoteNG.App internal static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, IntPtr uIDNewItem, string lpNewItem); + internal static extern bool InsertMenu(IntPtr hMenu, + int uPosition, + int uFlags, + IntPtr uIDNewItem, + string lpNewItem); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int IsIconic(IntPtr hWnd); @@ -55,7 +63,10 @@ namespace mRemoteNG.App internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam); [DllImport("user32.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr SendMessage([In] IntPtr hWnd, [In] uint msg, [Out] StringBuilder wParam, [In] IntPtr lParam); + internal static extern IntPtr SendMessage([In] IntPtr hWnd, + [In] uint msg, + [Out] StringBuilder wParam, + [In] IntPtr lParam); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); @@ -64,7 +75,11 @@ namespace mRemoteNG.App internal static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool SetMenuItemBitmaps(IntPtr hMenu, int uPosition, int uFlags, IntPtr hBitmapUnchecked, IntPtr hBitmapChecked); + internal static extern bool SetMenuItemBitmaps(IntPtr hMenu, + int uPosition, + int uFlags, + IntPtr hBitmapUnchecked, + IntPtr hBitmapChecked); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent); @@ -93,9 +108,11 @@ namespace mRemoteNG.App [DllImport("kernel32", SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] internal static extern bool CloseHandle(IntPtr handle); + #endregion #region Structures + [StructLayout(LayoutKind.Sequential)] internal struct WINDOWPOS { @@ -131,9 +148,11 @@ namespace mRemoteNG.App public long right; public long bottom; } + #endregion #region Helpers + public static int MAKELONG(int wLow, int wHigh) { return wLow | wHigh << 16; @@ -163,28 +182,37 @@ namespace mRemoteNG.App { return HIWORD(value.ToInt32()); } + #endregion #region Constants + public const int TRUE = 1; #region GetWindowLong + public const int GWL_STYLE = (-16); + #endregion #region AppendMenu / ModifyMenu / DeleteMenu / RemoveMenu + public const int MF_BYCOMMAND = 0x0; public const int MF_BYPOSITION = 0x400; public const int MF_STRING = 0x0; public const int MF_POPUP = 0x10; public const int MF_SEPARATOR = 0x800; + #endregion #region WM_LBUTTONDOWN / WM_LBUTTONUP + public const int MK_LBUTTON = 0x1; + #endregion #region ShowWindow + public const uint SW_HIDE = 0; public const uint SW_SHOWNORMAL = 1; public const uint SW_SHOWMINIMIZED = 2; @@ -196,9 +224,11 @@ namespace mRemoteNG.App public const uint SW_SHOWMINNOACTIVE = 7; public const uint SW_SHOWNA = 8; public const uint SW_RESTORE = 9; + #endregion #region SetWindowPos / WM_WINDOWPOSCHANGING / WM_WINDOWPOSCHANGED + /// /// Retains the current size (ignores the cx and cy parameters). /// @@ -283,15 +313,19 @@ namespace mRemoteNG.App /// /// public const int SWP_STATECHANGED = 0x8000; + #endregion #region Window Placement Flags (WPF) + public const uint WPF_SETMINPOSITION = 0x1; public const uint WPF_RESTORETOMAXIMIZED = 0x2; public const uint WPF_ASYNCWINDOWPLACEMENT = 0x4; + #endregion #region WM_ACTIVATE + /// /// /// @@ -309,9 +343,11 @@ namespace mRemoteNG.App /// windows use different input queues, the message is sent asynchronously, so the window is activated immediately. ///

fz$)`~4}R$c~;yfXd9 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%0AJ zif=ihAIN=_huFm9NUu48iO?E}bX0d6iMo#;fKfci`?WfnmhR7kK-(gW)hg@IFv=qm zlnl5ohou|NL#h-og)M!)`Phwsms!Zgy~1z-<&c0}?^&55Ao=A>cJ1Pc!I7;{B!9j% z!bZsj>j8<`0L5c7-LA&5hM$cebnazbtohCnN&qP+0R)2X?UOyO_CPR6jfPFvQz0`R78n^_AFW3*>>s#oH#vh7zH zaaNzzOg&-<%ie7E)fCiah5W(UH$?ABYKUYk!8-cnixEU6VeHw=j+1B(46++@lgdsW zAQ0)OwJAn>4V+hdo_}lm5_IIi1J+-v`Bved01-st zJTd)BYA{p%Tm1w{F#b-nV~sAh{xyFYQisq>4|`iy=md4S)S;#SjdmR$M=!9Nr9TtN zj8y05_O!Tg-?~vsv~O6-+oq-%RbQ_>!&S z+I}>r5ojc#BHbH2{6`Rtqn=@R@Hf!}g%UfQKAfzdhT_~NpK&TVOu#&iy80_J#{Qx1 zpecv95*&1TE(N3rej<Z+ zaIf(;;NO?~67G5@0NUt^Bx1EEZahTLFE#yz@<8Tso2uEQGts0dC5ETynNb~*QA7K* ztZfmYXyQrrS5XnZ_J^t$3Od#<)@Ik=4H4a~+o;lL#zfRmw|&!7;R{bkm@|w1V(};f zv`R$B>AW{ zhng=k_xQIaM^}MmNtBbW4_yfTNuT0SD#iFRoJ0fKWN>A# zczcnNy482-S8zseEiati!WVzUp$bHNh~`7cqEVr&Y@EJE#Qcc+V-tU(ulT~_;y&Z1 zP+=`_nE)M%YC?>kgUew)M1)~Wcu)O)7chM z@uYATv&z+m2Kkv3UZ57u(O0XNsY!FS?GiH840wiYv6}P+;Ajr8?O7955&3MTlR%|~ zjTIy%S(Fo;;R;X1xh6+;??Z5mL+6?&piPN`(g&Su{zj4E=bEoeA?ntFJj^sR%PjX8 zZw$id|M*9MxLjENpQSURXes-DGORCi@1V36V7-Po}!B{vwmh!lWT*7;l98= zd(_M%&fcZjQ9OV$STAPjmp;)-_Tm$Z|He&Tu7w;xi7gY(0^eUR-he||O;>%bm_0dX!1tdKM963RML zRgn>!qu!9x34mx7YP6|6#6eS|u%T0_A!6cS-Xt*CCYACv)&81ke`V<}jYxNlDQ1Tg zbED)Q)PDW2R|_kFhTIT!$WbZ*N7U;+K&UWTR$lz9!2~=a^*&tweb^YAkTJZ);Dd=5Q`1a5L*yXVv!BnwWHi{3)t&m z!MC}iu?|Mpd*$xnjmXA>#;yBY*j1#XOPJ3(tZl1!!?^W%cB0qm=YY$+n#4?VjGRzp z(zMFQfxYC4Y-!i~+uPD8sT1(HSD= z`;41BB!#b12L)|7?mw&c=&kAtf&ry3lQ!dyF-v8llD&7NEYlAik%}G;wHJ!&9+!kx z-v^xN%!-2%cO0ceu-vrqbyxTn>by)H<(!I>*XkibV6AllbHGfP8=r65_y&X?NZft7 zU|e8Wt`P%a3BGJr>|^y&X}bD`9DXaFjVy!XQngC#9Fx^$QU%|WUyYv}^ga4)H~voB7YujChp8#Y1KQ>)-kFTCUs#VZR_xt<>J>uu(le-KsI zE@QZh_Y+IKIjDaH)H8qp&dnODZlv077g8;ku_yNab+?-~hLgx|NGtZbGmd8HGvMGL zL?wx8jBJ-0lc>(Rx#h(A(!%*U95(M+#8ufJ=n7pLayW1IW`-QB!;lj>#mgmHSUiS1 z!E?reu-3Wi`(iLb?LXt&?yP!KOfY+5Ls!$9d#O>sSSw&aug}B&zx-hlnSzpd32$m; zj3^o5CnY@fMDa?l8)285$sTmW!+uW6)fRSzdTP{X<(cg<6Ll9B%aisLz@n<1GJN9W zy{Q%aUdS_jT5+#y>9`y@0r&#y5A;jR_ED#^ZyIdv7wVa){!XH^=q|SV4`nIN&{O)T zOzET-2V?nKP4cRsS3N1p%iObwj{tR#o-z)vkY;~my*ILcYNQ~t-eWAwNcgIEv>&7v zG&mq6>Q_=lf==e|8n#7%o3c?*T<;p0`oHWXk!4dQq22dD+%p_EMd#_*1>Bm5qkf~? zXLP<7o%#^U0#=E+fT34wSLe8G590)V!FK@ydWgSbM<*JT*^|Dz&;Rq$T(;K@;M@Jg zKC+z~P%|YP7bFPne2&?sl3J-aujn zDC1(9TJV&#Na!Rs$AEh5A?mmOOVfBkRjyXJiLsr_&y7>BJ-l}^iTY9R;>ET;bXcED-?~xIjhdj4UIq|bn?-Mt{;(aRq5QQ^ zXng@;&d5{gZF$ZyUpwv;j3%)Le+Br)yW->I&E8V&dkpjeO^p+y+|7E5%9caeHPaYxI)uomJs)_)iwaU z#IDCfjJLZu%h3amfq34waU~IKHg{Ol@^{hi2RUr|qQ2iD4R_g$jV9?mvBZ(6u6K=W z47TKNS+sN;3$zbf*(ChB$-?R znxBO&7MfIB*tdx{+$@2;0C~Xl;wd1s)HpR5y1MNX(>*74xIZk__i6C|hw>Z3-R0RbD44Y7j|oAeR(nG0$Q(rD z=wZ1WK}Sn07JFw~TEf@6X-624BR7AkA98)jfBY6^@n; zq9(G2hHI@`DPS36vwz`k+ik5f)F;rbQ)5HLQvc=B(lp^^$Lac|=K=L4%1NM!+vNKq z@p~OmG6?Ix?B_p7OF!iLOukbC>H)rM+j{cbVZt74Pwp39Y$}u091FS2o373doo+^N zvEXWd%lGMNSDDxL3ldCj%zN<~bZ?ei2ALD0>u-^vAf)b2uGO%=vIE#J3g1;;;19hU zOj%XkI8T?@%3(>DKyhNMTsvAHOcBP-xrsGQpyNh>r;d^;esXlX;bapC;IH7Eket5XQ-&Lx1r!AksI6w*U-pL^fFe15VoFN2O&TsmF0CTXc zFE-Lb;E!Y$ZeNEvYLfh7WRPHF(@jY5g8HS78uWHaHiph@!jjlN!SoBD;-k-1SWD*DRWL_q~$D)#8oEu+9Fcv zN78VV{E{JYAesW@9wK%63QhPqNTt?s|Bqupymq)|5T`WLyXBO0IW)RT-A@MTaqO-l zb)WqlyDLw9HvTwI-4cH+P_^;L9JM_DI7=;wKNhQk_~TMF+j)HKCPu2J^NWZcLqkdt zv56kcu>0BXLY-x>Lsz(c(sxnO3bqBY76yU zYbbM(T({yxi71v~)S!MW{0aCIDZ7q%YoZu6Ro)0SgB5d*bo~$CNFia1>vxT!D? z3PUBaiPz^JvO+o;Wia&BZXG+S7V!1=Ok;ViPVF2wDX}3`%v4!_lai1V}UA?_GOl5-9fH?|+_;=OMHA+UxSJ zcirCgUMti^-3&r>CNfu@_#IOKGIB86DpD$=Z`O*8xKjPQU;&5z5H3Q=9|5*wLTw)M zrJ@(#w!BRp{}cQI4N9eenuDS?A{T9lfp5{6@2=>#lYrVyKyOa~+JRPK9MCakafsfb zbfvn72CJj95@7BkQOLPOrspM7^k5vwPq-ifsp$PQHOQ{u zM=6Bqruj8zWESZ>m!q>YH!hE7R=3`dsjG7HH-2w7nJiuFMZIQRNi0)!&Ut;p_4M{&rnT9_LTO zCqE8;#1YxY`i0tsi#?DlW*Xm3yg6f)4a~UM#&sjrK@S3R_m zyt&KrxA(p^0fj90skJua%~0l-jdu4ZzI35F)52{?q3^>!1GiCf8$sS|FV3-is-yClhO<)cPVSn2U8uPyU`i^{tP5UuJEe zb;Fv$=3Q6_|C7!8mzqs?yQ+5D`)GNrE6ZBr@`Y<$iN>>N{KIoJ9z9Q#5O>L!?cx@0 z2w=Nb8A)Z1K@7Pb5Q7#LR!`XKyO45t(#@Xh{*+jBt=Ix$j1#uGcll4`?}>P2p?98% zND6d*=-v)C_tDkRta4NXdVQJ6l6$3O=Se~7bSdu149!}czdg{^We*ElLzyK}*PlN3 zrzP>)k?TIG@yaKB{A)1M0Hec3`UzvNR3|7tVxrjfz#j(TpE?M?tMPi~itdA}aSo4W zKe{7@GKJ{H(DC@Ed*Qz$(F2Ai(A8}ZO9w`|veIf?{=wnt$O2Xwo-gP_a zdNidzT-NMtFScWb5UC^^vunr3;q+_Y+O+o6=_Rz<;>itFT4x}a=@xltvnSSY6z<v{;&Ll-6Y-tJgb=GFTJZ~>LPEgQl z!=AU@sBq+UqVXtJ+b)ai<(+Ek9&&Eo0W>xC9j>k6n!w4Tb(}HB>|s<;#OiI)ao2Bl zIWR&&M>HI9z_+&)q=#pV{4U^tJACWPjr0tVV)6l=xHI zEd`~~kKCTazLE7Oi~OmC608pw4TPJWQTsqKo}=#_T?JV1g092(p0mJC6sHs1LfIfO zheE0MM2jc(-!odfQXFL<(oW~pGFmfsz>VWbKPtnXzo>gcPpHfW;_ph|NNlAwj%V_t z>AeTN({Z-idt`a@GOKZlcA8-|!cm?2f&%v&9q!$0CRUVHRFt(j0!=Dm%))n;Bt0l6h_+WchB^Cf5cnz7_eC+C;Qxm@y@ znd-v@&93J8R->=J?sdE?azkFUBXJGxSd~1dQBH<i@A9xhWa z)(dqZ9EOzkG?-efKT4oL$1=iG7bH|xmC|yyS8^dm6L*>bQZ!92#O`(AJOjK2T89;R zGS`n&;kObe=&6HjI`QzSkOu@D=~k=9#bPZ>b6LQ69GF6M9iWK;C@VKmB%s^dXgae( z^)f_c1U3ol{#jt=bf%MidT6bcSu>`k#HwfOi6JWmGHrXH+iLHy*buM>q3idGdTEbKvI@^9PbIj`pXH`Vc?go?Nd*%FAf>$0~?2qG{G2$jx;I|Pf& zfO5fOdztFGcW`i1Ezz+OuSpLs&1F@_hc)NSVP%lyqUoQg{xn9;jBNBmQLuu^wxC`D zLS?)6_@())^93%GEBYo+zk> z@h=RgL2M75sk%QXy1`IQAh`QX1g{5C0D^n;6`8E3KwUSz3zx!!*Q5YOn=h9R^7&*$7G>cd5J%_e70Jmo#+!-Z{W7iUv|Nq&Z`LrN;V)VRo6!XuEOeeH_gn5bOEZP1ZKQJv#(QM)(wH?kD+TRnjA)AQX!rZYK8|=)qOfSA;^7J1Z>E0 zZAM#5@g=ituEu|*zF8Q{!)ZXwbE8>F%y)T}Dos>)QI(oCSm71&I8j%G2((%R#P);r z_e`_Yl>nyfhbb`au)D|>$+#Sa_(|<4@^{}m-u2SFD^Fm6ed@mfRg0myBKW&Ed?4tE zj@l+n{%D5o?Q;xvbv3${qHnlL1^>%jgr>R?+vQGc(eRmE$=R8cY#3zy4;_iYru#<7 zWF+{-gZ_hpuqv2!3pY}w*R~v5I_+h#gNU+uTqTL5eDh^7hcKl*p~XZA*Z#=-OSav| zp4vUks!cbi*NW^~-3d!c>mtlK3@Xx0RjSb9Y;5#{iygrch+T2dJs#ntkrqttC~-+9S8r)-8!j{>YOz zTb-9Ej0pD(n(VBOAV;F($3*gLQm-|gE z7At3;=YAPoApAN`NY$&?5>1`YRzyz*{r6O=Hg2-jo9rmUkJq~og59o3VtcgLROs8} zhG~fJcyo~rwS1^86@1T=Kl0?AsH%WE&iwPS>){#*B~#N==^JQ{OcAdaruy*nztYP& zVY+-qwLYnFwfvDM?*+>8Pgi^EKdAOGsqqo{BTwE*ioE|Mw3%OAt*MU04Dk`jG1*sa z^o!#?-S=dC;}VUPq5V`(aqes8{Z!}~3hVp9kTAHXCR?0EPZDP>0L^x-rdHM^T8ri`H3T)(`pRIfzlU!MWqHnda6l^DCx7J0o1*$OCHFRQ0pLT1|VKGe#0{cMMi+k5?RzN;DJ+st0{)J)9RpHppkR z?tRe2=^I~|fBLzJopa5es}uFG84%SKbR;^j9X-Dhuj0OV6qi;@7A?bFTm=O2eOo*Fy1ceP z@=udL^5jidcMRsoS4#&}+hCbhacEzETzA;CYkfZV5qSFAv{ic;+$N_O7Op!@8&~(f z3Ht-@9tmu}Xl}3o|2VL$dy=|ea7PA7?c0BTwE;b%fr=r;-j6^0kWEC*|`` z9)UXr6|;RvubNaQDG{? zt!QvVIqhQhY3&TJeI>U;_m!e=>szLk^bE(-jO_xgTZx9PZ>&y@&3IaUgA-np)ApF> zSR${e!^XxOU>+y)eXkR$QojWzKW!@ zLP}H`S4wf_TJ9a~IaQ%;PQD}Y7HDI`bbS0i_K{+70Yi^yrtzj|z-za#I|>YkcJ^%QoL^X_j8gIfSUnXo!sn~v4w*_O zwTBJyJYN5SUi>q(EZQRCZA9!*HcHdxaubdoM0x6xp{2 zJ+H^cYycl3`Wgs&UMXyahh}*88GUZg>#jgGV_h8d9B%oNR_I#jD9~8Fb2ZcSZExT%pW|Y!a zUB2OYy~uOe71+lF67zb+Rq+RK-C;?f@Zf5EN6*s3^NXVsyw)mlu&LG#`P^!LF5Ef4 zyu8?p)91sYGb6fRstohWS5)l?xh~`eJqQ3@jUwVJ+=*YX1LfRTkCzcG6WT-@2K!dy zJ2c<3&)y+-I1l3I18Z)tuREIVpN@enI$K@vS3;fxy7I0wN`56!cfh)4Cf;;oCD8J( zyY55tH5Q!;YdVhZ<{Ryo#~Haa^;ma%3_Y>(^Gz3^8hpX#fvwN^j z(VHBUYHK}Pl=9)=!I#l{-ZGSK1Mh1GG(D^!tqfkjp@19zB=ziJ)=TligoJ<8;Ah;X z%Z7QL_Mv7Liunq1Vq@;oYYln+5Ju^?Of+fKOFtfn4VkqlYlUH31&+=M_od#kvp{%8 zhC|OYE_A1jdCnY`oxL;I)EAZe(o?~QPw?>6Q|?`B*BUQMV(8g^{_>uKH>+9c{Q#k`CMIq1AX6%>;6M}#z*>q01J6(ZSWL-ZiNuj1P$PV|w z+6yt(W+EdT@(=S4zX?O}Kr5ZbTE!Mx)aMSbIV7$iYL^a2+b$&Ypga_kqWR%YqS}Sa z_$I0=sxqCb*`(PNniSbM*~$wK@%Kt_6go~yejB@k9(xg_JS!k3C&k6~&635?MYXYc zM?Q9#tos)QTGxFgvQM9DZ9o4*6K7BWPs#~4MMzBZu*gv_wlXxi7PW(4^X!Q{0}7Bo zHUAsGrY)5#uu0HzBz!t)-4$HaWjHp=E^Hoe->g(K=dg+P_BPcdz9+!%`{}}%G?~K<<+2^??MYj*W zKMVmD{r%wki!>YknXxbndDrVy#5U-)2myP5bLn^mMl0r-hAEMG#&}*2`Cq4FXu`+A z@f-u?H=$n4#GmX}=$p5{AE zP-AtOiF9A}k(2R*CW+efJu2y+wDmuR>=tl(Gu2UX|1OHTea3>!o^YyvlG;OIvu)-` z(nN~7BCk=mP&3-53L1F0`kBsq5$VzW<`0POdOf^2s-bqU1gEO;GZ-SV|^Pa_Pmq2uA#H>W>4q z#t2ICgBa0W0w-G`NfJoWb{y(?h+U19eR`Tez&$7(#|LLjRJyOo@5a1BdRv;a00Rxg zqLX<;f6cK(Jse+}NZvBt1N2yeXo-Px^mg&?HX(3I!bfZ;_?v0db$0lOo?>=~Hm|L! zYKi*N6pJNqJF6Lz)c?Douyg$xE7Yd5Y>CPVJ$VX1pgxVB&tqD>{HSn5$PMY=4S8r=y^ zjf4usP?yj`?dIU8DlUtb_K9KSGTuXuQK3?&J1ov^d{@r4I4qX+qt$;uMb5+MFkaAM ze--&bbaa`z?{#{0Kz#TP>#)E5Hm5?H6FC`5N}$s)YbTb zjAtEtvG(a*g`8cGqDrw?5)PHCv7HRhOT$e|vwSlRPp;fZH7lB!Rxjlk1;VR#sUBD3g^As~-22jDT z^$VvBvjAW*y>m9ql)j15|1Tj!hWI{x?#fp{Y_YjO$103oGW(G?c%C@>S4YV3KeL~apG#*eC`Mo2Y_0Q50HDmkQRh%DuXs{X zTpw{syEFQ}?j~B9h5IWiUy>pS_+sw8zSNetQ24MtW8J2K+OdABZ*kz{rM?9XCpA+E%8+hH=7iD|J22m>W2VU zxD#g(4~O&XvKqqQlC{#2R!&AP#Co zY5^7I`?IQXfa*;P-M^Ol(6)Xw|K!Tvflz}~Z+vQR_oh8s-Fvbjb|>!=g4^ahuOW6v z{Kf7Y-VhU=*bV7{Qx5F_SlnvZu)-a%i>{M+rm%;uvku~jrJhAES<4tp1A*DW6twiB zX-4}-J9-+4t-idR5vg!(-7b2}H@WV=HHB{WecQF^QybcYjqmW6fWNN$Tc!Kz8@@WB z`_jB$ziG*`=$qQr2iBjM;eLmVblxb<3Y^SvZCb)>eO<0>bOSpk7l=n)lUdJRjUI=3 z1Xdo_i;&yqj8cW#Zr+CxgWQOJv3itxorXVR_ z(2?@UmEhJ`f&YQrhSSTAF0iJw%#1QUt>zBO&YL?kXTvj zU!O@_8X{k&nW~D~SCRRtd%+1KXl|+AuS=*PT*wf zx^e1e+%CqiSr4I{f!f6RvtyAe2Iv<)3tRcTs8s8Ym0n9 z56zd_S9UJ2MDGvut#@szU@&lgt5&-j#od9P^`2U|M8AV2Bv@0KqVL7fH_PI;V_Q6Y_FULO*@}E47Q9@M)zGQ&+X&Ugr{7cmpXLUs8mk2y}?}sddwlSbVlTl z{OXQo>#Zcd=ZJd>bD+ZmJL`|Ky$zXDA#lX%b#3wFnyn=k%A2yazLFF94d{0@ilS?v zZ;@-$b!>R9#xL<#qP}m+1#9t$;A)Di@ga?-iM~6SdA@7)CY72%{uwZdYe|9WQO>Tv z1Il|FJ7A;C`Q_ER-gy$VuVJ5PKYP)1EFVgS1 z(8BcFsLK{IEzA2YnJ|xNl3Y*U;ozmR>VMS>^6u!DqK+?^ov+`9$*2P;cHD_Z#uk5r{{&e=-6mKe?9gs6l zoNZDLNBCOUL*UqS^tO#|cjpFc$(gG(oFqajBX`sOSrbAphAe$D#8yv?t@UdV zgik3uzp)?}`-Rwqoq?kc!{IE8UB$K+gQexaMsFV6A&5RV)>nX!PG5eYuMB0aG<&Pn z9=s}wTS~5S#ra`tTF9|ThRJGwTBt%%imsG@>R)~xi#^!%;$ZX+SmkM`ood^^rhw{tdl`oscdoEOzn$Mwi{*sHHwfciCBZ2mus z6H>-N&!)ol; zW+T@-USnLFRa4BJr-xz6rZ3UYorhTDm_NH357H}r(Te@CiZb))adT&Ilhy8;RT7@h-0y#V7MfzD$&qAWF5Kp7!H zO3e3b1)P1x!1Yc0@4eVqaad&6gwyejGe*?lSF3{_Ss8&?#`Prc-}qOT3KS`V%-g)z$bz{UEyICrf?H0w)*wE()CdnyX3f7PZ^h@ZhlKL%#?= zu_AOsdT^17eqBcSLiv*`f5cIetLYgEc(0ATB0pb`yvPsWSiRrUk^{+>E`NqajKr7H z$Rj+~zM|WBAkju@XnraR``*MHJ^CWjdJr9Pr(wSG%7^Y(ql3xca!X$x=hgL z-r;K0mX=`BiF$V|gZxGzCH#Mhl#@>yKO1D>Bzfm*oqF%rBI&$okZ;qj5(AN1SL5q~ zok)tSQOrF9k<>W8B35DylHBwX$(ocNDSur}zvbOq9eG)P?v7wm$aeU8;BIFIP7om` zzaJ+izc0k3C=X3!*dSSs8BS(6bAZQy1>hr0O?sTJd;C4A25|vBZj?uhUa@e|&AenY zJ9;EqE4>t#Rld~d#kwyQ(XR|i8>Q10MK6-Haqv# zy9`3N;2%+ur;iP{)T|_0TeKpZ8weF3+I4MBH8?=JYuujWev$RE`4W1erpVI`i?-RL zuu1gzhMC5RH^g(K#{7gV?OTG*!wIfx*{Coa#_5Q5<^XX)b8N~Yp~|5`xg{*&sAFpw zgB6e9!zbr_0u0} z2;axxQM_sb+ac`ylU@*fTGhaJAiDom^B-D?Sjs~fWb7n{qYwv~TjxG=)0W)O0!z!q z>Bm~qd{fg~eR)I{Ca&<+AFN5e`n~lw+xu5{@YKdr`_)}IkHpD!XW`DPyL`i*14Xel zw%&tAm@e&1NIJ!JqOp%tH4~9SC4$O?l+x5cG8WFvVfz9OG|w{Y-6$s1FPu5e5lyMT zZRWJoAx8!g&+(IDeC9sj3drVwy#{um=eZgWfYajolf!)(%_B-Uh9Z9?fhZhnr?pJe zW$1N)+)d%?oE<%GAS+=$DDbhCm+Arz!2J>CuY_>Kfx7 z4^1;BlO8M;!!*g_8^)z_=?T%pV9o)%>%K`~F*?D>)H2+bc}3HnEcQDyZOuGI3Hf$j zN&aVNs;LByBja-#JCZ0qX`&dK%G7G=@Ei~_$+$5M)_)fy11wCJH+^MIQK29^%|v#Z zAiKi&OmO|0;QBUj%{s+WhaVj-m^ccu%3O_?@F{e?yePPXosksY-HW={x(Tzu8pQz8 z%bA2G*ooye?%jS{#WJjFvB6()f@#1Q;8&i*HstVdN?PpuBD?iium&kyCZd*p#-b}R z7OqASBM0gZb3{JO6EtX2?3%`yEUF>ke5iz|!^djeOAp}YGaWsMvC%8EhEi%guQ$E< z#9C|~7NjONB&qMkLB!@TFAJ|+8A{%2^PoH?ZB<-&6TSDKgdjNAcm zIzcQAS7U*!03rOGBB4vHrvCU0WIESxNJHN!&A`}NM#(Y0GPF9@GNN(kU1 z@7fZ+HaY@U@A^^h&(@4se64FsYW=o?o34i`6=@m4XV**h^2&CWrLO<6Y&DlsQadRr zCP=8m{%N#=8QU{Y2H?t)=7njO!c$&D#E*V#^Wt4@p6ALBoU)6gx8KM#wc=7sNWCoo z(`a_@TgG;;_0c5^wNnjfZd?}Eqx{d9HT2&4X!olpeo zNCNxaM=+=y*cn&5t3PUMnKy3w_)rR5Jp8Wytt?o z_m`&g+xmqgr`eY0_r`}+Yq#zY-IfLSaYQC`TaIq#;6|bkI~N^G4%ter^r zLWL|n9%-eXxJu1LHJYj~EKrk@EvTv=L4xg*)mqn=EELxX)FMl>tnU?^S#(CYR=Ibq zNg;F?JD?h~Rm|#e!mJ=3xKUZz~ z*@ZY|;&U=M&y~x14c_RQj1L(o8&i4EzyV(jF9JRD?9)ma6IY{9$)vW-vtP>ltaOu4 zD5!eE{4$?#-qeK2b`1LNIPk{nYNtp#Wqcd?Ocn8DYRcC&`M$vke=8pbDrr!q5I{=bso0T@Yg%BnCYt<{68la%G?pwQ9DG225qWcE z1o5cc1DI}Hi=vl6r$bf5Yf9D=rzvhCSJ9$l>zCN;xTZ5J1|hQn*{=i;-?+{Q6lo^> z&Epm7Bc`xKH0g^z(D`wFT^E|+{=*f%banY@JtLxjRef-Kq9;rUy(w_#Ak-guG_jV{ zcXxt775X#rE7b@31N@_M9!HnqkqtLg@; zd-gwcKULobQT5NMbzV$ApWubNM<6D9)9iSm(qy5?PR1Lz63wzNyJwqw(`K0id)b+U z=F#f)`_RKf1yQ>*7TqwbZ$p)OmYt_sJC#3R9DzY&x}H21pT0v>5f1`byvr{LjC5H` zuC(d|_RcgXD;qw@0pl$yO4u%-<7qKoi(U@=nw@a~A%nEprhH~KYU5zdTmPM!_r%x@ z+EvdziM^TI1{z5lG5rxM3J(88$r5tjVhGL|O(5ByOH(M5WQv~6U-7DsQZ$;$dkW&c zslUxR?Qh2RK@qT2jEH**HM4-KnWiJvCxBq~6aLzpQFyjERqJE+>o#Iz?lhO5E3y0x z@>dfGOqNc6-gdl6b;$D`X&nF4Xk^C^;M=a4_O~G_)hOa%hD}hYGK8gwJ<&rwyXpd6 zH4tQRVHF@uxlnr?(3vEynbz%wlQtCK3gV9b?9q!Co5GGb*JQz0bzq|#TAj? z_s1{a2?nQ_bg9O_F$_s}X=i-e4*59blXkzW(fG2MPgkjrpO(V`C0iAS9>PnU_<66c zCOAWJH4b{CBcHP%+TbZvf*_K7tAh9D5CuL^p@9TeRA_!KI7tc?H<& z`mKa(?kPE=2<_fww(BuVQ~8jVhw0+8X&E9IiHBC}x^6xDU^*(TMT2~S|Q zL_f9oQ&&Wa$^=d3q!NsCG|KXct7^#Hi2EhUR?|CK{KU+{DOzDq1k-sAQE}6k#sLmv zW1O1vkjz*aT($n+VzHNG5=3kDkGp-{C^c#DdllcKi;TJx#*byOK)#L+`A<}q;iG~u zI5M!@Hm1kcXO%4}E3dUOqGE41qIOK)5KeUw%SOArt6ArKY%=WLC6!o6ZTA1Fb6Y&RAV>MPJ)XL2Umy& z?AP#tSHtFV>74Si<`o0#Q9#2Z@d&CKE2n5hMY(E`Do}*VVyQ$&hn60oH)@(q`XD;Z zTF0xYSuhFV+wKU$Xh@~}6Gk11Lx-VvR`ln07`?_m%7;(c2xoMyL>t|M9`l5r-Z%2P z@to6PykSAc`{n> zx_yx*furt#Nq%`w5L%vi_Hd7g^w|M5A>O2x8*k*lDgKw(-r$0x)5C?h#da;)6eshS zcJnT$x?GYyDnD#zag?h&@6qE)w|shUl8bLJlfF3Yi=a!155(2}u>Uv0nunQDV0>1g zMnJgXjrFkcX8v}XGlQ%aEj>J8XK!a7{453c>yy}3>U~I#>j>Fh?LLA(YLMpdt5Tgp zhoDGoEBF5~oX|eOv`( z1gOKiGtR~6X>Z^kGDQv}?6BbGZ3C>N z@pwG{l5gCsn|-5aUF~y~SE-sRJsWr6KJdMkk@csp_KyqAw-Wp&i}_qp!Tv}&CT0}J zwe_dI1as-s&AzmjHpyvwn!t3e`FrQ~9;g)EM;&P@*z^ZVgqr@yU%Hxc??4R1n(t-Q z_Xt#_%&5smlYoS`1pjo_K$W`RY=~!X-d?;sQ7!ie_Tr_!UG|Mrq!Rk-0z&Z`9ofP6R@!`;gM`rWh$2+y2C8{_c%cXYqpsCdasG1puzJ$Zj)#q;y_t}I4j|y_EHnVKLB|l8a`jDdq|1s!oQ&nUkpTq?5 z6XFp&i|%zuc&O+aEH?f5UiMh^qd)2sCRN=60fbOWE3xVMvxws)(29kJGx}=&HQ|`e zbl$oCy$bvnPn=Uh%+niiyqhe6|4=T@ncG5+N5nA*p=2?nRKuv2X@Rd8^Jcgray@h{ zUaL!m6gzLN?8aip_>yQmYjSB(rpjdzCnz4d_^6rWOFF7PBw4AAPCaL3PL;E%S&ZV+ zKx+=BZ&%iHQmBVtpyE{RGQC`XOcBSg^0`qyuanPo@0DB$=L&1z4CqRdVQHADeR&H| z3!#jvsXa?RIE`yd;Z&P#;YB>&A;6#hbFP}cX%dTzFkHijgyH&WH&Pa2Vjnkul=*W^ z|0D#YoK4{AVR2zMr5WIa_k(8}|EP`>c?E1DBy};}qL&5w{&r?^jwFx4b(9b_Ck6|k zQgil6l03)dVqRHQE0`;ch1TXkve_XHgZD5qg7;t^lo@ZA6KJ`a-k;G zhyNOU+{VTnrXQjd+)HN*54~*ifSVgr`dJXg?v6DlTADs0b0{Q#+nXdgH#*6+rCio{ zbhx`??eKOpcP_lEbsr;1XtA=NzgCpMY>+0 zu0t0(@Jca7An7FMV4hm>_n*i&LFb!n>~?K!TqMmr3H?&PaK!kmmd4@z)E&)wk{Ife zk}E0H*4#Kka2HK$eoQ~ib?;phj;{9pxbRTue))1!{yq-rhr6gvW5OOL(kn06INP@e z`o^zM*A0Z`=0-0x^cORm{x&>RGTt7pcjkuXb|JQCGaio#QGC9=rKO4Qtv~tR3{0YdZbeR6g7$6 zMl0czvNUtPDo&cS8t&2#=LzGxx>P+ar8?56mWvr5IiX5R`R%C}U(`1LFMCqNHMQ0M zpE_ipj$)l6!Thv0dO5Hm#a5+d)WpswRBZIW;G$FC2U1@f_qfXep-t_<4(HYS*$>Ee;h)u! zA|AG-x{egt-j=PDC)o$fRsi*upK&@!4yL~MZz|h7WZF}tG?6sg^fz_zr{YX%6unJE zt0siv&;`t7Ku)DRAWB;a_(xQ#r+6WFW@IbFAfbNt3XyfJ=#g7i!O&|wK?mj%s+OeL z-8`>(zu~m#mAe}E^XA%$jp3ME^aaq>*h9VoTE{lZR9%U8MP)N9@we93eMFg$d>6KqS~-Nz zb8YE#ZE@lVnPusi>)y4l2OAXe8v0JCVSAdvo(zahIQyW2UxOhpc}Du15N8q!&%ZdI1ZDsQev z@pAT4se_GE8oY*gWcT^)xU**03YNbfT`t$G)4>_d(MpQD8atWdy$8sM zt6uj$*L|V^(!dms&2a^O&$HLTt@~xnE2ykb{hO{#nBxNL5BM$&aj7nNbF)L^Lh!gT zwAh;PGx-VDY$dib0c8_P;b!~@pLqG>1glhO4H|Qh=CF9XjrM$xb1wdnU-HDn{vx}G=>=2LuLgl%&9K_ zDAC?tiTzi*1~amWDP-ObBhc6duFe ziT*~H473(ME-dZ&(HDfWNK+xH*&HG+9tfe&vI^ylPB^lW8L0_*yt;hTlwPj=8n)?2 zq|9kE%BeQVhYJzdU_~MLx+-XB8p->{Z^L z*qBn;trJH3{Xr_gD`0f2`Y+~VoLBxmnVPwp?K-&2ei7Jlzc~|YYX#fC!@Pj*R&Jxa zEWO~0V;t#q{eP*mXvRaKcRZpXBp=OyD;;^6_H{wD6VS+f^(o=%y<2+6cL9V>`M)D#c zBPAf4y*v7se3<|3k9rGGJr9478k&)2#<$&rZwVZP#PtE%CBAJ!H{fQRgdEY)(&tAm zVgVW}WQc#gH95rQJ&f`DMtuBORQNk#{9>s%%ZZ~vWQA73LT<1Vrg65~d?#3E{PGH0 z^Sg%*V3`bHnG9gr-~j3w8CXbBI1OXf$M+^juaie}^ad}AFtUg~i4f=y=128%GJo{C zrk!_9bq^Q3ubpIslP)#lC^sEHq>4ukl%ss{@*9)o)z&)N6IQ9YL8u=1_Cq7EUHT~R zIs#j1Il{JLR@`$^P~qio^rRDve2FKSUlw$l9G_(#P>3o9`2N~c!mS!T)%cS>VCWdI5&*$~R$72%^cE$n~|;kY6kvANqP z9O`{7@1QRW-qJpD&kwDGD|*`BJvd(y!?Ta!@upQOHhZ+S2&ag^NFsKnYzEMKa0hSyiL|`qG~EFjpZ%2MHH}AimqOCvK4_RNfkA1^|5}uMIMjwh{;M~ z5E7D&Z$tcQnZ#4~B!~v}-gjd$wy@YnX7wV}g?#UFuzJVmcP@8rosk|Yc^R)r>r+D| zxvs5fT^5Dr>jYM_;At471Scv4aq=_Q&Ee1dNW*?FW(y?H5-Jx$SX)cE^fwCb5C}Wbcky zjb`aZ@}++0%L9WimE12&r>$(byDt|`2@H^ts2x(?7P$L_v|Zkxcn@dEf&WJAX;B&0 z9+Q(Bfk{zR8TSj*i2mF;Tkku!8zmcfTPb92wQ;|O2Ty$R3eKK^M2c;Z5^6q|0B#=l z*PF!?Ile!bBTtwV)v{4 z1qB%QB`-)w2l zRi>h{9~G)&`~VCx(2XE&tTA7US|ks9P=|b!Z*7i1hv@uMq5o-iK1r7W6|sZd7ED3r z*oKp02r40Zis3XhJPioNE7}r!hGdLy^0}tTC{n2VC6nA*D%F30&Pr9G0ZQygXH{&n zuyn4Lh1}D?7FPcp0XHBN`z?qZjCNL^kx4F$P~^BlCL+yHF{% zG9zx)tSNo@6fR6LyGK*&<9~qp!VcFKm?BR}KFkpJzj7(Xakq9XT2*QERu~sh`-nmJ zphS?Ju`- z8#X=RZ(KZNn;HUwV5P|K^j&~dOZ{Z9We;cY!_E&TIJb=A;%7^KIy z(YH9VhgPdD7rcwD**H#uL8qyrYoEe`0~;m+0bcua*pp3*VcV`Z-n1< zJn8V+1G}70I_1alWS0Ecp3DW70BX3Xm zs9AoeS$?Nkey3S}k1oGAW0w(L6`fThT^2)ht@9#$d1i;J5neLcfd%5Cz`1hTk`lxW`1| z9utXsYz%@uu*d8I7CcTk^!tomdAog=G7|)9ylcdv-t8aTut!5Zf?rw!zC9Z9cQxc$ z^p8}ary>nKzh^+tyTcNgEi=aIdf?mx{*z+rJZZRj5rQVQGDL7<3gQPGz!yh^V z?^=!RvTRaWvl!nFt|XfPohADZzq#}S{L3RZyUv#c(eb(ehA)pXkTDwTev@%{LvYLD z5Zp4Bf?Gz{=xlfwOf&V#Om2T_2Jyi%fJth0=m7>%$(zYUQ6Yh`SckHK90SAy!}PR{ zW-w?g;^@gy{{sIhuFv($Z*ls#T4PHxL2;#Rrz6*oK?Awv#yRkn{28GQc0}>2_{oo zTm41n#(Of7BXuY{JUXqiatOqm6V;%zHZfU+=&T_&)i(_c8hv?6D{9UJo50KakF1?tBzqr79I z%P9IM^#lDPOw-+nZKG@SC6S?J)ZpGRYNFvPA!*GP)Yr*x6hyBsCh0PF+qw&h;}r9a z)y*r9RHmc1-Yb=j@s^?BBLRUI&L1#IVEojbtyZC#(n%6LadS_r&EZCb0weQ`3!1)F zFEAm}{9mQ{zaR!b4_Z33lNL>_JsVF@j@5w?=v1(4 zfaQ#`Y1t$pnWq&V!oZ23O3jnvEXlD88UBjZ@Z;9&ElVeswldDWvX_S zp8u|@s(ViD3ylz^1nk{N;o&*GzG>dOmk0-O({}ogWgj8xJR_1QwGpex^ z`!eLG-uHFPrpBT=0I`T$0o%Iyfj-B&5d`-2&DL>cG`VQ2&=z0auj%=jvE9|UgThFD zAUM@qq$d0=`f5?T2uCJq4Op?x&^#=A91oKF`>#qJcpbZUSZHyq_uzz`d7m)hQKy9e z-e<#4T%X-v)^PIU7hXoCLi)H2QfT%-jD2pLszgI9zA=84N5c}SW{J&?ar^a8sK8OE zG_hbPKyL~{#>7GW($Ft2iji~<#a%C@VPCjHEAx)zuIeA_wZRjYN>@fldF?z4G%F>) zD7_&_YeNa6Uk7e!R@lfO?a+VOxp0@2;hD@uM*A3H zg_-*ED1Oi4B9pihdz{ZRcKEQ=iqhIG-h~X$`Lp#=G-|fc06zC@IjH=T2sE2&svR#| z(Kg${LXvrck00N7_jccSH5sjoIL2-U4$WHjrbPF1F-Y7c*xxdZHs&q1dv+myE%gMA z6&DTjMXOm`!jDmhC>^h8v{_N~(rx5zjpp^X$z;R(PEVUe0l#Pmo4%GXb_iFF3y9HC zA^PCwgPm%W?3j*tSj`XnuHpZc{J)ItzcsP4D>JgvIGaaD!(xtkt0k~F(?OM*=oz*+ zi^p8hoMvXS^|a;shMCXKXl74aR^m%ma=T549^bn?F(I@scgz&J=4deqn@W63X+c8r zWT{qsENpDOyAL^`O>A{5)gAkofqlkX#$Jw!yxjrZ?TuCWpsHbJ0AT%#xs#icSveu# z<9Pb9FsM{HJL3z_KduJF_wxwM2$ybFf$Y5Ez27%RgIB52X&|wl{l8ZNtYL{h6+aD; zZ&m6biK1-GWe3T1GxFJgg9XEy5F4c|HDY4CDFXfNiA5)!>5Hd3ezv%QRyO@^eLUfk zw_803-6PW4AWQnrfa|;%vDaM>(H8 z0Sra{F8_FyLRSL0Y`~cuz8Sh-k+)b(>VaeQaYbg(j$`F<>d0+6Td+`lz*C1M2SB5! zYdLYt9Jsw3iS}F!kcE>GIGz(^HfM)b8uKSiYhc6x$4|RDkQcD6-vuWsfJ@>iZJ)P=?sPkP9?|ixjFd#M)RY3BwCaR3hc`jf}q+EScw? zb|77*PTmS0wWBp8x=(8!iGRLHun|;Ly(OQ|sHAF$eat{?O!j*c?abBmCVQBAm)so| zxkf}fcxRLLr?q%q&n%AOkH^lF-4c;H=$8X*~lDIgkc>A|h7Zli-a`5k(KV7bVw_ zEGf-*PaHT)3HaNoDk=*PU3XENYfJYwx!t&a*DWE?ZIZHM8-xcbJ0!(^QCm&MCpwX} z6HiPTOk{xKiH?h2lhXUm?4j#6lDw)8BNi=Cb&Fr&c)WAu;Cr7-Mn!4-4u8&8T;gQ7_VJ+^Eo{)j0IhnEgZ?n*e;xu zk2CE%10Ps3!WkW_fIOou0eiV{G&QG#z_MH0AZ4)yJ7w$$e_(rFTJ~C2HXM~B+c(U; z%f~gXKbi(%A<#Z2cS>NtNIM(yjh!tW*z{I$8A9|Ct9LlcKvVCB^= zaNEph2XODUw}vAr8tja)Ys+qv5fq0!!_z-xYCznwMk1)g0i&hWH3b!=)(pl9z$)|h zg(G7b6K=O)9EOU?26DOg5yWsHI+Ej-n@760cvUpzj+0jaMGD5=0Nkg@VP6n4bwa<=#NuI+ZTbO@AEI2_xYEkhfI#PPBr%;aHjEUyC_@( z4-jp~8so)ekFl9n8~ad|d3O$D%sv!;*Ot*~>FO4W~Lu6fho6M{=Hs?iB93->j=E9fjFzLKC<^1cJs z;)tylvGaxr8m*oF zalko{qd9^1=7>*%PL;REEPqsEeTUvOlI`i&!S?j4*$|D)BX1yXT^%buNFFtt-l*qSPF5UqZx&*Gw0g47+_5{7)eqNZ(#>yK@OHF z&s46k9D!Nl{o_2DxSWYN^-g*2Z~T~C7CY{`hyjog9hR31uR$;kKY5O;QN);V)zTjS7W16N#G;PL~3f z++t=I9*PbZd7C(`wq9o+xK4wJrm_YRpGc}$0K}3DUrPAVQr}FLALLH8B_hq@nh)OD zST&DKCKINPt1tx852Zbf0@jJ~f4dF2<-HDJl5%4z@?@?brbbDLi=waMY!Gl>stDa= zHQL0|s@+yV=CLi4h@oPiAGJMG(414eplRpE{~=2|SE`+Njjf+^<%W?_d%LBeRNNgE z`92>AH#_UEzQUg(VX`I~yF=eenE2)I5$(;2C2Cu#DYYv^NEYAS8;;*LY^bdbgjcYs zUWhkOPO#}A9zsob^0!P42vYQOfVj7_Ci#c8H~IL2y?r8!OrB~p)hfrZNZP8rxvQFb zHfC&aG#y%-;+?)sZlOjM_%{FjIjSIV~^1$L^uab*nf$k;VC>+ zd)Y_gJ$K@g;4+8$1M*YNzHl`?0*^IvCx0ZMgxY#H+X}bz;bt2hbH&Y#c#?B9P8VjZ zJe;3+7@l}IF_O+^2UUT<*rO zwJ+}^$+hW!0JCwYtLd*YqNmoZ8RlJclUc&p6%74EmxTHAAfJsF1svm3MAi>WFGAVB z$8hNz?$6db3>b5Q#HY!CKYDlD+7#p3eo4#Ia0NcZL{fTTY?dr}n+53Cl%a>~wf79& zP)1v@F(ef)SR8NpBq1yf-Q(!PhVF);yJTp@u);?fdqOWt5jpG3Z!f$GYU3Tv5L@CV z8LVhw@L~O%U)ZX1lm+!DnO{RqGB{-+J>1x#et_2?*{Yt*e$$K>}j)D4qh z+FIP9hfmgNVlK$2;>~w56Q<#mjTcwrC|Rga{KFOgF*W@C3O^_dD!#&#%eCESH+2?1 z%kK;6i5YxWV{lK%@w7SGxH#Uu)@3}TS3>Y%!E7`w@PzzY2w%X`au{P-S^JG9Neg`B z2!D8iz8nS3G7DgvC6~=JhOQq!TJF{cLVJx8Zd zU)3W!KVNTmXoyEsjL#DN`sEzmuMg%Ae^BohIg{@n`SgMqs6_4H{` zxZj&zZLVVkhs`%}zv}&jZ32wSGTXqfC?M9#8PRv~I=lDcWv(rmO{uRDQew-DrZj$y zljfeuO}Yx5TN4HodQk~Fea-)&?oHsUtgijJ%N(f<+Kp+r^ z6*VL$kPwoXa}I-b2!>d~F|F;@UfWu=x3+(4hihxCL#u{C2CEj-+C+&B7VSx66)gpv z$ou{6XFunh0M>u+eLtV~^FFY$)>+Sq0BhRS9*wi~sg86qO#?4m8eYAL7_%{Aj#4~0{^KHDJ z9}$ypK8k!e(h}KuXWzNVB{(ns||!H*?7my^>8gmckSJq0L;!A$7oGB=<8BUUEO+hnL*Q zGYa_25^ZW$+cv+Bd96Ph^xZy|Je)k{_i;GMMA&qX%F_3(=GtCO_n71xMWLxlG{>5I zH8sgWW0QL1MlSP?{Gss~Nj5Ci%uwNuXT0eZF#%$}igKY!QHpf*yMFSoobY*kfT`hc z5*!ab-por5#LzC~tm8Gf^!b-BxF0CY0^%s3b^g(o;%@%zsc-kEK&M4 zYKw$uPw^r|_plLe9rH>oOeO!cSF$^I89y8G;|}+3GG<^Q)6j(|O6+t>zHKNpks?mR z(?lNC+05FA>0cvEcX0cfui<`bA>#HoN^<}kGu#7pAN{1U;buZ&3v`)k_`btlEcu-i zk7G17JjmO4obTLZ;^Y&uo9llhj|>8)r?A_a=(OY8^m@)>_%{A0gj?CF(nfwUWjgG2 zqMf!AMNEoJSNdeqhv9Zr;WGI&-AE0xUN-KHzf0^~lW}mQMY2V0O0q>2A=xtXOJs|r z`xnTT2PVd4i=2J2Z22d;Z=!7Rea+Pdt$Z>4)-78NDU_j#(p<-F#LQQXXwWOnFsh80 z(T@Z%BL&Wg84+W#($>3!A+3pc%yXB0$C&M2Uhq`D)QfF>FL-Nc58_a3P@ zO=f6M6dM{cJh5>fw8VzubagdXY?w6suf>K0)W0h>%z!4bp~M@pVHA&lEjHvNV#S7v zEkSJPc=W$3HYENcMsszOksvlyFzzU0#fD0ny1j61OlqR|Wg4gzN(-PFfMMN6pF|mhpJELi)G~VDmdbV7- z4YxDEzN9CZl#iHfv3a=89G_3;9`P&GJUvMyr>wen`iyt|asxTu`}wZ-$TN4VHjdav z^|fuju=m-M~0@k;ULa~ zr$n~eIh)PUMPHJkCUgEiJ#wtc2t4|uQqLtv9PlXO{=2@uhHq1_T}HubTASp`#T~sz zHM*%r=56LZDQEv|%x=#sKRYt*VkQRSlc6c7oXyp z#aE#@MU!k+f850mhWd>!szsR+kT8GNw5Ujn<`PCkJng*j-APB@Hd#}HuvzTd~MT4 z>p$*;LffY(`NK(%E62VD=~0+gbWT_~i#4Urb0}0jor_ma)$g>G!!!JdXxs6E+q^{w~R}r)Bp=?%Wbz-r9 zbkGc~N%o->JIAx0mtjvTo^#@cvhO#TAk?>GB@%5X9DA5`FyxqKyNHKjl{O8Z{0qS? zG54V#O5Vn%7Pmh+-x;wrvTN_h+<;$k=2s$PU#jUslg~>X@v`rUfuowH*&|=mI8e2R z>-JA_`<{4Z#GcTF4X>={NEX)+9O~?YSyxjL zhgpwuMflg(N)E8(+B=f+QiymHcR`JP+PPZXpMWb??AE1EIY4@YeIhB(=Tq){9n#Am z*T`XoMvLzKBxUY&o+U#PR{OB0i2j&2rcOeC!Ad!P6q7u%+?|9SG@mo>J+*FfsuMo6 zY}?MBzr&Qit_FG7yt8LBGyH{lX|=DNxj+jqLDo{gC7*VAnvv(=2pR<#O*(EV8hLfxm6+( z++sh^U2NFtaAxH*hwH@xM;(<+$R2(AVo3cK6etAjL`qBh+7e;M9@A|q=Gs8(U3Zoy@AqvWOr4K;a z;)e0l>pmF~>fJPL&*VO9lV@~(pexsn%fZPL!{_4sK80%B;E803!iDa0{ zrew5$x(1EMD8*RJNnuzuNX*ID)o|Uyr5Iy1_TK}89rUsZ=bp#!Q0l6klatw)6Qfp) z^dHoLSa0t=Vkbr0nW7CZbEo0K=+>T_@^)I-sk zmO2>CF_c@p*8Yz+=8EAB@1;>H@xz<-{ioC88BBG_SAGBS`oV_QZ<`0qL2oKpsWN2v zH}@n=QIT*oI99i*P0z?%=L|lG70&K@T&|+ESh*Ra8LqXBX3ysJMFsAwriMc};CuCR zy%0jlg`Hdpb2hFb$BNuUM2?I&c;v0K4-YwlIxwK_D$Es@7%Qft&Ys3TxiH!}OC8X= ziR+tZx+4y^ zL9{n(iret=-}2(wcU>AUEyS#@0^rapd*9sb^%_b87ay?yH?Z-ReSC}h!onrdwX894 zB98AY@xdd1!<)CBiFUGF%%Vt3=PB&0-SSr~b$e)UtU&(#BUpdpDmy@yy!PiEsGs_!=Q3@6ulBfzGE%<2dW(2cDOEu_&O-^nY<;bux@q0a8|U8;D~F20eHuloO^hFyTUA0mcO^*wEn`S$kd+-IDKJ{CZd_PUe==_l3Fw(WT7rZpS zYUBH1N=EQQ_7Vv6I{UergyVkFUkbx#vcnm9Ir^86v`&jfEjF-?Gx#J@C*RB+$i6Qz zl6czXIq&c(#Kq}a)5pYf3f`tpnvu39Eg#?S;+wY5<=OJmwMG{IU2Cun>+UHP4_dmu zKiV>hvP6qR)4VQvFP3Mqy?6?HW%C++bm zWt?LZ?%Io07^|aQ_N~PA#qE0q&jn{D* z4EKq4O;pA@uhzzKynG%&P*FZ(zodNnt9(+Yy5-+H`j`pJJq#KR4s;7i77znN$(ynV zHfEiw&8BMZjkQKWauS~OD*CxJ;>ku#_vA_+VuU0`5UdIzZl&qJiB5* zQPUkGmEeC75NAV963RtxD3O*UZ=U^Tj*k4=mUrH12`x``YT6ttno`JPZ7y9sg}bGP zpyykS_ABExdFd=y*|L~^YP5I!-BrBn?8*7uT3t4qOM_O|e~hU(Mj}mxU3{1g+qXFr z7N@T5>-$X)?r}LYg`1CeFwJ?rzCCHgo;fE-fUU-SD%ywZKFpWZ@7@yG;tgw4HF44v z714a6;NVts<1*7{brNBFQu<#l~I&Y&H?oUoObK$~4 zd*MR2o8Zi(2g_ByJH!__enI&X5#wF-`^<~=L8-cj;n71bV5Xt#Fm%sn|FZfmOzJR- z;sEL{m*_m-T)JA3R7UXyN74zSTdyWD3^jZ|nqghneDF1%_b@EuE6R5hD(BL~C6rD+ zYeHGEQJz|rkh4FC_3PZSfiN1 zqNcI5b7jLgognWTG?t>{)KlupVNz-?KAY7I*TC*(E_q9Rcxq@){giyvH7AsoMFP?Kp~ho*UJ}&oxp8(9skk za+}Bkb3)no9H;8MY%ExyGqE~s$JyDvWkd2l8&p)gd4c=VHTG~wAualyagwqfi;xBtJ>>2| zrAaJ_elsD!(0?z9-t{em<&D{52eS34>2Xlt(;p+L$p_}KieZP6jr9CG1a5qYofXPX|+jZ`A z;uc^1V_1S!yQdA!$CWsvDm=jHB`mMUeSuz%)rn2Jo^&sT;6c% z@zg&efw=uO1a_BYj!Hb`N0H@r$T*E_vT~229&vF6m$GQILpV)MH1+M~^HzLnPGGD$ zFF~$wa+jXMIxchO##8EFI6t4`zR{5DEZiEs_gRgyp8i`uCHg&y$yvhNQq3( zNEuppo8wHWJD=l9zShYZWs#JOvikPh7(i}oD$Pg@_w4u)(h~vJHZUW4AxBTlcm5dL zwlyuvNQu6L&Gy3Y;W0Fq(9+5_OwPECI}BPgkEYLYej;nW&~+fJ*0NjQYu(-YVf~c5 zY3`1%L8o?_`nMzNo<17~9Uc63U7peT+D}-bX`%^4^Trw>&Cq37FL-pqWIV4tLM zJDnFs$K#{(Y}e`YuG44b<{G&{mE(Q@8&_TTxT5RH$2Hq*d9af0Qx5;H%f#2vgojS& zAHG{Dz%t*kL5^>Z1KtH3E%OEUj4kus+Fa&a)YETXe6pv^_v#BjF=q+pPU&LUy!n`rM3^Hp1Fg=F95(YR1#=X`l4H^u|RQX_43Jw+@6z1yUNRgOBlp zoHowA6#U}_Vs0t(ZQasqitJ=>9y(=o3PC@rG#sReKk_Xlaj|IHdX6Mv#J2U^bckL! zJ6FzdLbEVIYob)ay?n_lDaffS$K%XB8u`N;v@#m$FQkR+eo?N7>2iN#fb%i-ht1o5 zVBR9kInH*B+wa_?H|}tXxsEGlHOCnzhh2jnl6u6wDd9}-EPJo;h0)&-a5TstE0<63 z5YZ8ZijhyA`=^;s^z`$XylUiQMFQhveWrwC&f2pM^+UEI8#_X@3MA*?=y$SWO2^(z zx+AChm-3G3MN{7P=&V&zs&?tV%*2EJuQl>TU9>y`ZQ)>lHcO3E1PA+Hqd{tyQdj0q za1ZuR)WQDW@tY6zKFxx)Q#Rog-`A>OY);yga)rJqxTObH;s|oz#=Bw9;H3YX9r{*E z{koK-a509{Ly(P;SIZ`he%;Miu%X?c?{d!T7{Xucvx51wysnd19gm~9PSv??UqdtA zn$~u8{1fbQjN)kqIxZXVH9Wuz<+C5bDXoilMdn~5+Vj@rik?MH%i0SH`FgG{5@3;{ zmJgdM3ar9e8S!gbgym2h?(Y;3_Nl)X=aZhkul*FFDP`iMZN9H5&d3feUA%JZc^uc< zJiTXhQ_6&ml-qykRqnp2GkH5{>&@@zwzB3P)cT}PeYdmN(A61={gf&0Q+~2t&B0nR9NU0(*mQXXx*}(iX_~#X&qk- zkIq&sf3UIC-LglTeBO3X`P~^UN5r|Ue_6*|=4EDCLuvqvR0GwzqYI^lPufw`RFiab z57v9N9pz5G_(zZy>TM_(z1)^Dl|hKi^2HVS{dP@wv?|9$Mq#adieS+EV5#B(SCJ zc--y`J=oiX_h8*1BmADMIYoHU!7|^qJIZ`Thrk~pcaA}CCl-7y-GSk=WNk;%hL1nT zyYFk-MBLDE44IYu!biU0ACkDkTlV)&-trVWqPbLvwQ0vUeXr7)j$j8P=!OmQ8@dRo zR`ezzO8^cU3GXBGdsyaOCe20vg#XBcZu;NB9jRIR8Gd%*j&NLmQ{AwT(!-9F`34>4 z{qGUK{3OeAGN_r1YyoxvJIj2hQJ#{LbbnjAxb44(Xg>07-9;Lo-=bu%oh4oRx(y#6 zBd=>K-FlEqufW}cHU+yCpL^tUt9*ufxAi7@oPn}bza_~vGG||x$b%Ehd`ouYd-v1YaOB!TGBGzJHo}NV zt=}qS2AR8A1tx7fk5cRG`4lRFw} zNY1goe-F>m$j|K2eQD8M_WkI;xBl&|-O&*U5vDp@4mT9zi!XR--g9{C)Nqg1&-?y8 z)T6b%;}3}F=nUNTYYq(@{de6_(BtqQ344F%gB_i`?Dz?#)z%^Tj{t?P zla|_%MK(O)M0=>aX+Y2LDP@uGUrTc8{?McDug4x^&!_CSSDjYY`2FjY#-Ho&Z{Jcv z-f6t2k{>p2ZW%b=+uWqQ?AgEP<2_rL$oT%`d$xJQ{uGp*$Q#Km_1pMX+JZpM0vFn(^5@y?#l_dLJ(d6KcYJt0kd4(vJ5cl(#6EUK;0*47vu{BDhI^SqR1IB!0~biC`$pX=}8hI0N+ z4W-(Gv#r$G*Yjlxcbn;-@wnaiPUfEzKI+7LZpIRCZSkVK>tyczt-DXgK0cTvf-(7V zHTt?|OeDA2NRs;Q-p1Oz+mW}EUblPn-5pA8>-jpr-`Y)QkVr^qT`#_}4AFwtYPh5~xc@rlm05ICvXZ zvM_f^ZtJlPPW^j*nK5u)e0oMNen$HG9@^D!%l>}+PH9Zbc=OVX`t5x+d2x8Vjfqfd zLKsPgvCU46l3Op$xMrJ~W=&zHbRLr}e`pXL&Jbx&N~lL=jDO8G<5GQWV1{OD_1oQ0 zI|rV~3r%s;%a=NszbWA13NL(t7w}*caQ!FehI&W8YC?}Li$~Jd^Be|mN{$kv6!-5t zH;vzt0#DMjoZ!xV{V#>l`CMDifyX&a@f=dZ&YJu8_0N#QZ%ZYSKC+#)fOZ`u)93Km zBE&u<#%|+Fcbu8bO^@Ua)Q&{ndl+;y<+bPYU5E9WbZ$>;W9gDR?#WMb>*`dy1ylcC zMtn)7e#*U?PZloWCfjib(1*GP)u9@(&(!m|z}^|?hXeU`x9=Ml(Aiw;gZiTbeBby# zq}I3b>-??gq3ci9>3Wrl`e@Hkq0Wajd=KY4bKA$08CC;08WT?6nY$0B(*`50ZP|e~ zH0XV8%ie42mCu@--N^V8({o=#5$>XwU#Ka@1^DRDM`-zEq7Bb{bsc)F3hKXHzUYqk za7!dANM27B%bd!H`a%opqkTd-CS_9Vc|E;*%2Z8XlCqAi@$fruwlQ@6wlzu(v<>c1 z^R17b9r}t&VorT@P-uc8<+EhTp))dnN~+i=Q_!8AwSD|l57yhlQi=%tGzLeGM0Z$&hjg#=Z%t5;{3_7ofp2bvpmdyBitR28zrx&{J zi;6l+bmFh)4J5k&J+Ng<+qD@Q?<&$NQai7T{*|(5TYMBZbjh~;tlMs%e$%OiZLI}u zEz!0PMarimI?v-8nsA2#Xx$wTAU*mK-qEWP&ir#qIo_Z(d(BJbx_`O^i-jx{9$-Zm z3o+luZx%4oqWq*{3OOOx^k}Cv+ay%<(&!Kxqjhwk7|A4cbON$#Wl@5uL0x zHQm@1SsWd~wg=bybxww6zKjJ}W8cop#vJa{2UmL6-Q4pZ+!d01kibkr^mVN08D@t- zSK5T%=uDoKjNO?1YS=qRyHy-z=^lWr$461o!*_+}#8~TSGO7;>x~QnFRfRobU;p%V zvvp>YYT(%9V&mlK8y#{Y2j;MIAJ)=3Q`%bG6)-d9BAllr*jx7_?GJWM$Qu}*RDVml z6K1ijWv^~s4t-H(Layh3T-<*@`NzS} zPw;!c@oR(rrui`;FD;y(3eb zV?M__2q_Y-tVr)1P;n~vQ=DQi%1XU{0pHzXE#+qjH8soT@XW~7*hi-G5yX#AXO8{x zx!f5UXg=0?Y9zP0ZAN;1`(NsJCATemv@y3?UYlm5<}cvWe2N}>z`FeCJkz}fbJrFl z_T%D5XTQsY=*m<+e9RY*`WoAHzPmLI3UO@~YezHRF@`h}Dzgupwi)@$SM2`J0-8;PH8u5a&={C{7j6sW%` zhmR`ecLh_U_fXz$v0S7=$mb1^&bzdx96v7HEZ<7=#~(sPo~|RyT;d#^)W_uX5*BoZ zw&e^)XCI6hN~f7fn&qU^aR_HgG+>6>jLyMJq9Y)&3o|k_dfGckvYf#f>sVns>Yv@q z1<8hh;)wS@>fb$|`^G}2AI?or3UR@FG#S4|_3s|(_&ycOg&(=;6iqsJVE^radGTq- zMqV7=#zBP7p*z-d!w<+`Cw=aPML{i@R8sv+>sY{=PHmmp%P7 zUwZ9V=XTDDarOIB_f_ZUMD9)JSuO*J4M9B~S+CySX>n_N+nM$69_!ezlx^$b+t}hJ zG2OTEWhewRJ2zWCNNIDpeum;i>L7D`5#4$q<4d zmYEG**Yo-B^l0&4OhtUI+tE&;{QaSR75?beF82d2LOpyP*Sy7VM$w`zSL7v{f_NXw zKF4l-&?Cm|=F7S{jkDOmNnP?BiE3_~#jRYajoj#-$2G6%Aj(IwVV`>!#y9C)kCaac-#{0X;?$H!HNFI+cd{Lhqos2%?fsMXQ!nf z-kJi<=sznh_3+kIk4`zfm5b(FeviXj*{y}{vouZLkwwwqR-tijOXhMRw0z8xb+ZA% zq$cwrPSTrH-+qjnZyS>kcJ9y5`)%uFP-ZvkGlha=BNV@Tg^#>nXx{y$lUq8B_rG$v zac4jKqm!$u`QR)HP~JdpZW)uhVSjs9k~2#6(Pyc@{uaOPekJf5{QD98ty1b*m!_My zH}E&I?40@=Zs1jFYjW#S&Y&sWY`>AfJsPw98ZP9gE#`;!%g%{p-{3h>C~e7YOY@_@ zZpT=KyBYX`q{BUEPinbep`~(xcdz=3j)~Ikz!!ZgDn-;0QEVmEU-W?}T@ZZHpCd_6 zcl|>>BUyJMj??&Zq5kyePk7jd0V?QDf27yYF1lHN6*D`s>H2*{zv+^l?_Y3wB#Fyj z>f3uOj5Fn3if#C;3r_DmJ<@B)R`+J-J}ya_bKeMMbzP`;Yj%F?*_}Pxvh&-{zWyum zR?nhOXi$CgG4R^K(J7~Usw(#SBh8Ns=$)SP#e8es&zXrW69zti*O@Y?omzkN+?zkd zL_Y2LyJ0XV;%=hz9)A6M0&KVt{_FZujD>F7{K`DqK)b?jT%7vk2aMWfLyoem@Wjrt##;t_CDg~<9gh?oK*B2Q zJsG1&4{7ck0;8?PT%E!054+<>;BI+8g$p-W_1y5j7M8D9Nsf%~&mxF?Pngh#`sz^T zmK|+slsm3wHwGNX5=Z$BT;GDeNJ9?u)w%E>26>m&74E}t>6y!z&F2kx`Y5GRHspme zuDh2tYV>IplYX6YBsZ;#%Lm;>C$e72{P zK?biRL(SpI&uL4KFIKL_lJnaA)Me*2O}9J4T;8dy!d^^eZ<)%nIR=OWI;RvaP|e=S zfYO=ul7}_Z+ncf}bbByi= z=OBCJ=&RcUpbQqIs} zgb#?X@9#JDyryxfeSIgkUFp%E($R`y*Xk|nm_a(UIKsn12<>XjE4nvn)?~g0 z`9$_W-xEc>_z-#W7G`8;>o%pDv`NQm`>+q0{PLuaYx_>CZyq-3)!L}JPtY}Mbpvz5 zt2nl@1}mwR?VY(!=?^GUC!fV4A~0I}D4M|YsEh|of2dcDfhc;1sFiH-I?aDVb)+y06|gzrWfTM zipA|7En4sq^?z{8OCLpV|J&zXA9cJzl=-DyIV z)0N}~r-;u(Zs~lq?aRCcPVOyMABC*i4eZw(9u{GzMb;6VPWzCn3RoTlAB=1}QVM@p zWQTC_-p-lODCn$Mrpe9Tj=gX0{oCG_e!Ihmj{GBX5LW|n!LH1aca!(l4w!_ywW+nf zNw{6pXWj^2oV_Sx;Fvd|QlZk0ym6$Z{tbt-J+E?aAMsqbHQk|*59g*P6-GYX*=sCH zZ>VoYT4A)0YEL%2x)cm25+J{#_ZB5KF(pb_>9>o&X`C%&QS!)s!Ynwl-)4&>Cc7Ej zpZw}qcoi!Qh`Nub1_#xB><{+x{b=i}?b{+;omRL1{8!(mD#yICE%E)&_q_VIZ4r*; z>wVO|cU!evmBgLStTep|7{Nxf*T6p;^E~^%`7~_|#;}dCZIn?m*6h_l4yb_?N7X>i z`N!wBLoO*?%n8}Q6EwAU%b=OL)I>T5+25#daaie<6^5$u99|Bb$-BYvcjxeKu&wIB z3LsY1>9MLFtSX=q2b-#Hp$rET$Ux;}Z|B}tQ`K)$)ie!UonxwcaIC5a+Nw@>t9mdM ze2%GVQ|Wo@d!JC-^TQr**>%^eDi$=&%}5==S4e!xTh89yZ%a|fO&yt2gsz}LAVumAXszWV-=!%TyRn_or#GC?+4b+GVEwa{)n;Qe6nfR$keID@gsQ_T z0!zvi&!2D3NdGg{rIJ&oktUPh>OdVhul1aaNLt2*4{3yT8&D>?ZmZwpsBAbv+Igvc z>+)M%{u^95CI?5h%60h3)@w5c3wCeoXxV}B2D_O})6yby-W#(kdegg~cRhKxpVgeI z3yyVR-_g-IJHbgaPL|*#GUqd>JUO0=2<^zmv4qC|f1hhJ`#KfCI^a&=KHy`+!F*?-+RCWqqCDz?Hxp;2NM3*a+MOJP7;( zcouj8XaS;tGqSHU0Pq7NfjPi6KpC(O*a+MWJOum(*af@|ybtsmg+E{{a3zor+yGPp zb-7YrxyU`+%OaM)!5HfH^=Z&==5idrn_x4R9?m510%L2hIW<;N59` zofm6qp4}2F?OffkRhOufTTTVc>3H4R8%G4Hypifpnk; z5WSLm0d@hu0e%d88@K}q0cF5aU=A=A@B?YUCsQa-pdEMt_!V$3unAZLEC;?tnau@{ z2QC8AfX^oPb^Zpt1?&KR4Lk&V9k>-(30w=z04@iH1Lpy0z_CgA1zLa?fo9+l;BMen zpaxhDECi+lBY}+*c@O*;cocXN*a5r_M1i9~D(=n#^z5>2VH*4_;6h*^-~b0FkYC_6 zU_0MW0`>sg zfnNak0vmx^;09nGFclaHWB`4E!(;FV>;amAM}d2RJAe?d94G{40po$;z*#^laF{wg z06aqas{lRU<@YA>06i04nrd)eGuownUV1LqS;z0~U!UQe^3$2l84t{KS~+{;J;UFa z;e7SiGoAasF~ehZ!_3m0bsX}_4=-9&G;gMpQ(aXRC<&EUt?-Ac{X>KPn(Eq+e`u*Z z9sf?e8O7z5fl|3GaecbpCgRl@8tiWpp5 zN=G+uk2buT+Uj-dO$d%tT@xy=uJT_vGuM5D zcBn;D$nuk!57ex6LMsD)FfL6UloVI_tE(#4`Xvu}nsH|~c z?k;$t(i9BRB4}o&ZF-pID3bD0!!KEF+HP$i7^*EV31t?Sm@@T#Uw_6xo=wI1Gjrv@tMd<9%fPhIU48=uQ! zeiu1KPQH^%PoC$@2Ruo%2A7qD75FzpnN1i}Z9*#f!Sg>)mlvWN&i^!B1*D2D`@cws z7lQhoO67l-o*B+;XD+2Z&&hW3Vx^At%Kxz3XPDYk$-B?W_hvfmCpvZDB=9CMb7|*p za0>Wdu*Qm?fqR0tgZ1nK%l#p++^7BBb$2OP{-%Qy-7mHL8?3vPVEL;AD;zJ}8h&pC z?gJhLb^)&e2Y`cs^ZraH4LAoF28;)$151HYAOvg#?gbtKehoAOdw|z~oR!7=A3f4P z4B?eI+6cBwh=0uV+yam@t+IM;S-CrYh?SjNaJ*9|8wpb#u04UDndx6!Tw8^lBoP0~ zKrLdFl__U>d0AO`AahorvJ#=|Ur}2fuJI$wPR<{Da(-Z4$;#rY6#>FqSdg8$yjX%s zgHHTKZqD>s$FZE;($V9_jhf)_t{_`!;V=H3>4CE1aAn9pqq;Vr1XUq?Jl?eG%F@Ia zF@AB$s*}2%7Jrcwt_?CaE()v*IhM|0gbQm7%AQv++dr)m$BDFG(Yfyy1|$MwwEM>X zo>?0RFs7O?44vSwh?1>d>%Mbo&#TLuRvA{g+4#c&`_}xszsJ&q7&89 zyGxP7)wr%gPRHG%5|}5E=V?(R3FRXG`Mde}_d}P~HHB6EGE*kMg0!RTIA+rCd)rc{wqSE>}6PqEv$XtHkAUu%3C< zRYX-&TV7>!($eyv^p{da=VXUN)xz`3%AEOBjMqL30wFmz0SqneGi>C#p(95xy`<03 zl0HU}9afA-LKs$BU3GED9}HBv;SCM;LCf-FsvkQz>7?_V#YkRMIP?6w}V9yehnUc|cw2 z3*45XM3h$GO2m{0 zL%}bIE2jO@F3Ru~s5P}l+Dw~~h_X5~DJbryM&pLIW8;m5gKID1O5(LLp{Ax%O8I=W zSCEraTvZZ4L7G+^EHAMdUeKuJ>m{0*z*wbAak%Q2jcdJ8T@ym3_A@J zk`!viXG6;p&y*X}p0e^4nci=?S%@~rG{afsPCJ~1OgFr_6LXo+`kKH*xntyU3X0bR zOhQV+wVJ$m$pyz6@m!`em->TpN!gYLDg&W_8bSz}jZ$iJMcQytYJaL>d1*ELi8i79 zpmI#SrTzlfFOC(5NfTiRPdBm9htcnAQF;~Ld@28ApoCdVl^O#jGB2>kG{Ef2wZ-dk zBrI`N81u~>BdA$qsJ6NiS+l~+nV;gMJV~>g z+RNtJ->ZvN%BCFsHH;Jc-(!)7O6GpCWbn$Jd&#}xoSVoX)M4Ei{t^ma zMMR4H7ZqLVzbFrwZrVG!4De%-`4K8#tsk?@57VO*!KJ21F3LAtGqHCC2;wL^xXLs` zCU&)c)hXSBFeo$CtG~F0{$>P`=6fQm%b2LDOwIdhe5|cy1Qe4@slKvYagk7RDg~G6 zELq9ymwr}S?JqAgF~^F+>-5%pydKIb!@-q_!Ra?;HbYo7;TC0CZQ#Z*UCGJ`&0UcK zc1o@|<88#NKH4oIdFh7Es$N|lswoZz*H+h-CPZmg6z22JzpAQwZ57SVbwbR6%2L|@ z@nNX#oz%bWC|=_{S^HN}hXS>$k>Hj7!0K?NT~AnKd1^0=b%@g1^6D@vA)Z@zlBzE2 zFcS~d7FRmnyDW`;Yio;ZyhM4wajWsvuXp~{)umcsDG#wcV)}gCe<{=9)t+bb!cTKVzKsJvsWa+jLKujm zRbI@?^~1?^*HFw4$*GW(T%K4yi>rcb1GS3A^BCvgE<5&G5nq=p;V~EG%8zzaQchVw zdR15{9`Di58T6~sbYirTeX%$zt4oRzEi0?NC}Rv{3a|X;T|ABM>r$kz9T;K^>)s?I zfCI8P(ODQ+T^$N!dg7UJ$J5CiCr%}lfyeZM_kNT9e92tI44Iei#%hg0nX_<51SZHV)n<@UCf1^23}+Gjbei{CNy1<4x;3Uv z6oeRs+$6=rT3NlCRu+>h_NNJF7O#wy&ZS^X?&#w=^PR#)qehM#!7+hFV@Hl8{H3aR z|3ayYYCB<;$(-DRoUc^fnvmwQaFv4as=)p<@yrNUvC7K;EC(h+h#FT1$VSJqiS=%paWaAv#01to@IOM{8)&?HBZ%nO8O zQKa3%awAO$%ckOluo%^tvXt1wn>2r^d}Xpu(&KGun)_SwRc$U9TF(k8>9p?5Z`>D_ z2etGou76lrWibPhtK2ZA<`u7^PumH0a6KyQYBbsa>*?t5Otjs(jq%!TUL#JHiNMRN zIBtyDZmrRER#KR(;I3WCpJF!w)g>xLlV970P1;Qi8lkl=j?0y(fSQSWEVAL4I6X#U zwAE`=EY37#P^;~M)hG@OI1CG3qTMvebEejXo%xpXuSQSAi&p7b@X*3B*~rSuB0T;| zX2;(J8CR+_f>H;Rw@EYpY6F?*QkwGli_0W5iv4AQwX{d$S``wMwp9`!(1H_~c)u}R zj+X4oYzb>Ag>J&luhKP|K%m)pV`o{QI22|^t8{pBWk#Imz0RWay-wm4m-j9+;hpj` z-JP^biSoQ8Hg_}Hevv!3iMvj`@UvDk+Q;OO$IUd{#BkOrQ<-kdH7_X+X?wUake*mF-kZd92H8j`S*hxvS>rcQ%ak=i_3;Mf zgfxfBLzO2>wBaX)ePX)p+{3u^o3*rVY1ibYmKd3XoRIp2cmFyL<4_q=`!r!`w2+@A z?#w5a&fL{CAvTOy>Zek8VtKsrx8VuU&ZTObK}}D0*8rb%%>)8%n|6~8cxmfz;#z8#6gMHGFqGv zf#oZYUVk{TZse%Aga)7iM-v^U*5O*K_Qvypqvho#K_nohc0x>+ACD*7IH!xRL-M+w z;$bZ>FD*YI2r=XS^^08~4VQ>|6ATihrm~oU{$%3{+l4_p3fTH~^>j0i(Am@~M7u4K zxd%Lzi~Bn(u|L9c-?DfbUR@P*7FMrK)LBe8@fPNa)Og5*ozVKc@MA15-wBSShX#*p zw$zt08*9l@zG;8dP~4-Mg=7`Nz@+bF?`@&^sp0Z9inHj9^xP%1YYgsTy-&?OnjFn`kcU8a9IGi4}{jD zN4xDo&b=3x8iWz%AcQTKA{<}u!HU3sfA^@Mpsy1NN)@BNYl z*)JunAb`PwMmn2rWuY9Q=Y||aC$pMbmRUm6o>HtNpsTA4n=!@RY+}JSz}j4OP=)RW zd2;#GUCM^&BSCLz!7GbJiOigCQn|Z(^GjtA_mEY>B7ipby~KK=f1x{0b&Fo*KrI%p zqS1E?qheL@>gDAt*3!0O;Z&^3G|WtK(a%_wX3=2I)qcYbYYik8IFlL)VY#zyekCi8 zLxbqeRi%~4I5WR3WqnY^757GZ^hPfro&0K+Tv1+;=-oUF8*!;W(Yt~%+sR?;mDPnWsOUD6~8N;iE@b7xP8dZNUMr!%;+yevfV z#s+TV#&GdpptpX_C2FZVv+(HY%v6CD%{J79jLFRMSr@DIFK78e3RXNGjo4mUh<4v7 zjov;{%&k$c{ll^=LnD+h7A1*UJ>9H+GqeSyM#b``H?H4IUS(>DFtZp#jZCeWx~jUP z235jzP?a8wCo9Gc#3tnlETt{St6q9CzHw)D2eu?^a9Z;_Y5myJktGo$Ossy~eOG?Z zbk_pCwI#C(>^i1k>9304dd@;7#MC0uE}y=n9abc+U6s@rY*tp+yQ?_XdpsO72N^x? za<3-LZyVT&VJQd3g&!|0HYp=+fli|;l)gojy_Xiz-neKZ&RWhUvKNeZ%cX-mspkEc0lPo=!XU4dr_wY-eEayS&yP(Z!AOIgM&ET*z(4t;#sxOJ08 zW){wzrY*Lx210G8+ii2lZh<>)EGHiy)V|4+u>(}ErccM{0;}^Qma4)m3D|uXrE^sv zP(!~kCQh!7M~e~@gE_OQ6b~~i#`a1r#xVK9Woa-rzQ^7L{li8oCMM{ZqLq~)dFNKI z&8%d_xYEBUCqE(8UL#i>gi30hgt)7a(WtXt%=Rbl&~wdB(7fUml>wwpapj6?_B2+m z_75ZQ>*vj%o;x?Y$c9YZ31JdNER|ls@G@ge$pO1=tc1q-Ox5OJe|2tde)inig}Jf7 zXKRHNqs5ppnjeuU<1xa)+$~1W&R=8J0KsE;$HO58w)QurrDi`tLg8fdXJZCwhoqdC z?7560UuWiw*gP@&M@L$;2uoGu;QXAc3;g3O9?O0N4zm)A#&Aq=$h`^3Zo|876L)wG z$GVB{>bvf+v8oKm6;i{@v`qT9`_?~;mK?lncD~Ap^apA4wd%*~)=Qx?`z)@laJ)j~ z)G4A==V8&}##LGs(-GWwV9+0`{nO_a_)V8}d!)>WjRS4Vn*QhdXJaq6S?UHLj^d$R zn@%7)-)>-vcKunCV6Q4&ua>E{AyaC9?6#=;yl#dt4O&sn2Cdn}(T1(5d+XOolj2I`cB~P( zZ{Rpr+x;0MRD*sSob}>WEoErKstT;t+`>zT%dKKpU}3-v#2OqVo?{`+V}X7yKBz>d z9&9-&`Q!akP)FHp(6bttrcNB8gBhRW2V1UV@N;FSm2ezNaT> zPrje1(Je9Zgm%L#$3g2u??$gTA<8y{EelP{?A}F9aTU79YF5XvibrYmmY~cU%_Kga$R3(RVQ_$3UJ?%(5GyzF*+qLbVC|Tw<_-fb4Mr9-a^tF}j$aqBv3+sHtlAJN7aq7x4HIh3SAK5r0 zbFd7Er^BrKB?g4U8pUIE9{tqPpiy87nByor_9Q9pVvA_ zu+=}{OWH{Zkr<$?*3!_w$aUBY$z)0%M)`-$o@W;5bB+Je@RT=C1|?=rJjJ10dG9?{ zP#ykc@=$KoDdQHw-Q*#!*(qnk7&#Dglc4OzT8YxMDzGlgEYKw;3TCEVwabp_$gx>2 z#m!^}!FIB=DP7vr^Q@TJkzx_Y&A;Mue;*%NZ2*7lr>^s33=h5o)QKmy!>GOFRTp zti4)URY@Z#SuX`$1D94)D+8IF0gz5YRqN!@7qI%$6zGV?z~6D;?qJeHnWMXCRDo~rn_H}jjUy&bbO>?vq+uq`c-+x!V8sm zOFTavFN{UA3)JFr)L^P}Fsd=3y6GN8-;9N^Dz&?axJ*vV*2X4MiqYdKUb9|i80wPNqB_C9ySgJK zC9w$O+;|vnNot%j3qnR+@RXZwZ8MfOY^v6f-^73|%Ue6r&tg`^aAk}q-E*LRv~t6y z2m5DWU%|r5@GPu;E^!P}uHyXRa7m@n<+}xDWKj3kW^~k($g;DoYt8Hw3d?3tcBuMM0uuI|l0UcavAELmNzFn#(9g3pY*P+7S3Zezlz z&@6kPHYB==)su~*vV6HLYvOCerY*&DkQsBJvi1fIx`gJJ8USr{F=v#vT_bc^wvMN- zXZnbF)Lau^LJgNzGSwNL1^R*-cIS?n!LTe@Xo=k-Tu)D7%BgvQYmX3HMu=}?9$%jv zIyUte(u$DEqYCY#dxLe?id=mZofDm&_FC+(2?oNY)g0}0SE5zsv2_d0hUlXNYAH8t z@3&Wj-tQCrdMi#7Wp`;u3bL!vFvR!f*^4l2QiHa0f-fB7mW~?Lt?wV#rg@D$-*Il% z!BlyK!U%herugk8TdhK`J>B|vug+3$t=g3NxwYby^^3yKJ5 z?KWC=FE<;HzMJS2u=`<8`mkpeJIUkN{%g}_^Q1=1 zlURQ?9a$$V1gizvmzl>c3NNXyT~%z(0lKGXq}#ev9d;xzmp!horinM5!O_*E(3f1h zc)7J>lJ#!KOufh|XPKuqFgme-;AdJkdtlY87;@0ejJoA_`RE|X`xSI-<*8X9#_~!n z#;pUBzLSTk;TzZLLz1FKYxaCA(`HxS9p%;a6T(|vyslWux7geJnms+Hj`{O3 zPLRNig~?dWq8^R$goMT4P{t>wFFu{|CX=x+-44=ifQa{}Q3-8VIUV)I{fQYzc~#BY z69V%1q-$ZI%;cAm*p&JxD%c)@DJf=O9usJ@ksM1KZRCXT#3QVDpK{ZsmeGAMk)Fe{ zIfh@g7?Jzkg?^SnVCkS9BAlU)(*Wk=T+XcQd~a#wU-&Z%Ti)7fz;Aq+n=Ha=++P?U z`W6{4b=@DI%H#dH_K_UMU=C>_Krp(a3QK-fel@ksyy@e#$?IRMb04KzZDU81o>?Bc z;DmIX5MK8L{EKkhdm(g&Sobqj$IcxG&H3Ugb7O?=ZCK6e+aRZ1-5VlCLEX$hoypam z5+`%vIB!O#I`0D~dwSkE)#(pR*3sK5`EZFp)t-UYofOC40poFW<~hV|3ALn${X26j zgyUSd(7i`SfBVCC^W^4c1!3vja2Dy*qtnytOx`NtmT`}TnM-R63i~j2bIm%c-K1tM z*raF#7h3&U)U$&TmDDdyPnT3~2V*3i{iLreWbXH6WMH*shIVNSXAr2qWx%B2Dx z8uXvk$*ohAkL-e+*|P~pW=6FBZs!y^wV}gh-hOl}-8gr0)e~YVBpe+Akbvdg5}Q4A z35VD{aiqksZE3XEOO#g~!?V}xB$QW>k}Ec)@11;}%Pk-C&21m^xP4-tGm|)m2Kzd> zYf$(6bE{V<5Hd5n3Q_7N!I>Wpt-y@X7(WoFYaZa|4rmTxSFXDh3cXz0k`(7dfx-L0sNZPc2THbg4i4@x+-2*7R_p zLwzj$UP7Av{-GnsuNyjC>0ip2K{M468tNLL@eQ3dG*1=iDCVJMJGA=pZ=@3dpKpE_HeEP7RKE5a0>ao z9JnTdw}#)f=64V0Cg@u~O>#EH-YbqIXCu7ZfjeUSB(%4`@X}$w^01*E{3kv7IfFA)$+anf0&d)8#{iDDy0lE1V@ED-< zJZ=HxJY_-rr!9b-X5e)ZJT1UsLpjb-@Z~++ANgSOnL2*{7J7^2?*Z?%bUXNfrQZh& z%tHk)0aQ23z}1$%2`tca2UwtI6L_#A)OaBo3vZeQc|7qzXVAHtd0l{>; zgcDCa_zpm6*aU90^k(qOfSx_ze_Hw|_+v}!Vjv%&XB4>5(na9wEnN)$nxz}T0zKaZ z{{T?DKLkHz>ED8%vGlWGfwJ%%SRnV!V1f8sz*{YU8(1LzcCbM1_kjOq`3J#=EUgQZ zk^yBW4Qv3qKeRynbnqbkhCUlC5dVCzK=cLRiI$!Uo@42&!Ak-8y#ZVfsE<~F1!|M4 zz?GK28e9!1%o?yjes2W-(ehsh@3Z_iut4tL0w1vacfjvj{$IgS%l{kr@0NZa`~e`p z2f-f$YX6^r`}cPFKCnRjC><=2`%}OIrR`MkWtKk@Jje3$!1FD?4*Vla{}}uzAiuu^ z3lwG&!lMTuelmE1gbB}Nut5AN;Hj3M4W4EBv%zyMKMyRB`+TrK&jRow%U=pEw*2Mb z63Z_I*I51rut4G54z9QS2JoGh{s#CiOaBM>VM{*(e$>*x0t@u~2K1W=VDtdwJ{c^~(-Yj+(mrsyrB4G7v-EHg9UmTz)hC^2Kbwn{txiOmVN~MsHJ}ee$3L3gP*eW@4y1Z`wY0*^0$DWxBQ*p zU6$Sr7U=ms_(e;<1QsZqJz#;JcJO{nzYYEiAUE%VKd}4{!2NaJr>W0}r$GaPUY=j|Pvi^f>SYOHT$16#f+Om6m@MSRnpXus}~XILGp5f@fL& z)!@07&I1eNw-784y#y@Kb1it8rLPAUTe=KL3*=YddK2hr0B^SR*THvL`di?8 zEd3qucP)J%SfJ;A@B^0qA^0InKMa1v(!T&dZs{k$Pg(j|@N<@K1`Cw7E#R$|zXQC> z(l3BtwDe10f!zNIEYR~;@JE*Z7%VXLj-r$-Wr?RJIL*=n!0DDg6+Fz+!@*-LJq|p< z(pQ3~0*W^qJl*nVfM;3$9B`hc7lR8eeFL}{&{GDkw)E}bdP_He@3i#S!FO5uTi}N+ z{RsFmOFs^N%F@3B3zW8Jz}qc<2Y8pIUjYB!(l3Hv0_6UW;MXnxEwDgOJ9xjP-vxhQ z=^l7WmPekR;517Q0H<5}RPZoM4+l@M^p)VLmd*y}0QxzDKeI&e%mL4}bRJlspG){7 z&~pR0*wSU-YD?b^uD5gp_}iBLF8G(0ehmCuOFsh^=xGM;u=ERHfqwphKYK;+yaIj= z(9hTTBM{xfpFfM>`3QW-(n%-|Bc(j>i~cATwOHOOFQ&^h^K?( ziRCW^7g_#;;O8xW5BR91KLrcS!z8;%6K$UB!T)9Hhru6P+Bwy6dI5S;!80s93oOtx z2b^c=d~l(qmx2X)t^qHz^bO!UEWHUV(6brbWa+!Wzp(V9V1b@rfgiW@li+79-3%7! z*$RH%(!0PfTY3-pbxXH^-?#KZ@PN}?zv*Cso>RetEIk-}o~8ZZ8J3;}zQ)qU;F~S| zAo!4_lLm4x$$c$ekx z2ES_guYupN{5Qb@$=H2hfu1(7K;g85J1oE7V0Z%f1Hb~6TRQkmK#w21*3xz0hb{dR zut0vDGacs~K#w1MAt3$`@I{t?F?fXKj|7jh{Lx^6+>Zf|xBLmz#&UJ z=Q76z%)?^W_q5=}^C0+ROKb6KkQTsr27}MFv>%*n=~>`BOXq`^Sh@%-(DN0rK+iI; zK+pByTP$4%{ ztwp`QfanFpY1#*80SRgSw94ttJ9sw4xoZ?&x7BHQ6GQk2Z zb7g@AEGsydfdvY4BzP>Kb~qg@kcxFZSRgkyfJ*?SvjSXg=^C&=>lHVG1$sh$$5{`E ze-rqtfWp5GEYMTuXAKIFo6X<|AU6+!e`)DG;J*QCZ#^z>0n+IWEzr{!e43>PfdzWb z1fOf^46s1YMPPxRVPJut;owY5XMqJu&t>3ImOlnO!O~N}S6Mn2JloPYfa@)N>V>2Y zP&k(lp)3GB_kaa@Hf7Kk0F}di;10k%!}u;8V4jiu1ymP3!M*jH=K}C0mL3ki3{Y8( z0*|x&@!-jp&IW(m(%%7p7m)k!gCDT`AAmox^k?8MOZOZ_y8`scX6oyfz6<<>r4NG7 z8ST39gL5o>1Nf_!z771SrJKROxAY$HF-tpR7$X2ZUj?^Wx*dGX(z@jL@jTZJTWZda z9C|77VF>h}|u9tp0nw8M&iFSDvoU4hTA^toU`GG5LD3shF;gNIrE zC18Q-cR2WR%O4M(Z0Re(0);aboNehG@N`Sh0MEB{KKPeF3hrM8Px;)X^TFS+^tZq} zEqxIDnWdd$$Ob^^^n-_3Iv*@hzg`Fyh+Yg9nEnpF9#CGEgG(%34z93t4LAfSZEL`v zS-J}>kbFq)qKyIyryp1#It^?9x<9l)`~hHr(%=INwEUG0J`+&CI14P0n+w1b0X^B^ zYb;#`e%8`k!8eg*s|OTPi$XX$qEen9DY2mG$3C0+X&39B+q;wJDU6Ynta zL`zQwPqFk>;5xamL3V7 zW9d5Z_bvSZSYVzM_<)`V!9TIIlbYo81k@%|!2;2J!Q(7_1$exrCxZoYa}`)1+S!xj z{1Y(GUdjj1GaOuI=@sB|Ky9)DTxdmRPc05&j1Vb%mL?HdLj6Sue3qRo;zdatl4v}o|`vse*S`m1&bCJE?HW1P4V&)?qpoCvb$Z5!fV#9 zTYuBYQKQF<9e4Q^<0p)`OaZxeCf&bSG~8IjV1w$Ev+o!nZSI$g+;6RT7AvwtS?S1{ zMfb&*@lQ4_$NTYIdu~_aO85QyofB`K4`C5gbCNgMTgX^qHD;={>n~uhHAs0Oh~jy1 z^Xrz!#038Tq=ZIXHidFoV(u{tI@7}Cd>{hjun@+)t1$*C&0Nm;MJ0iB%zwfla@3r_raLeL3&hR^C-Erj9BqP3JG)*o>BOpffO6u7wk;lMc zc-}jHd+ya*^97Fyh?K?|iV6&y+pS}1L) z;O;E$x;Tr=F7CRx+v2_~w%B5ee)p4^Ip?&LefM|$ukVyFGnpilWO8ScC&`l!n7Wr6 znkHg)VpwkI+oNhZ?O44W>tdPh9o^Z6-A81Sv)cEG*)cp;dv{*pN=LkQQ(t7xv>|QY z9feJ8#$~5D=M^QLGZ&~$UeaA_%Y|^$GLi{{OrYZl`Ykm}r#6#w2s%_-{wt@p@z~Km zmq~u#hAs2B#1(5vW1>(?sKrU8LYBnScGDLUlROoe^~2PZYhy1nA8&7W*8ugnNE^{4 zP|4B3F&`!5%&jMt382h;pmsj!CIZ ztPJjqR_|oxRG&zvCj3d=l8Evy7DiBRRJ>JQCeQn%>6FFqM9}I5Sdx`ey0q8BTu*Hy zxzJG7Nuur=m9|M1Q1H<2JlB|L%ZhPh{;Dir1RmKBKyn-v9G#8KML&v2=KSSdc zGJN#?F>PIaIf9u*FDtr**CZB6!_sH%GIk%}#aicBr3;uZ6N_54*Ps)Ch9uey+EzA7 zGl+_X)y*XPz-fulri?26Zc<|KX*fxkffj&ct?C!4awW|&7hjIHk?bwV6O|nWRUO5> z?oj#F9k)~a@yOaVO@FMefI}GW17S`=(#X3|T_d{?|Sux}FL7Vrlw&E=g zJegJ=v`v{8!%@EfFE~oS;yp*224;7r)|$Jl9K~H;j^fS-{Wmg)mQ&WL$90vXKQm_+5_&VtQc)VMbvlVrF6% zV3uRnW42=UVvbL1|jCl37se0=4;f1tlQy6Go=?!JD6X=g?xc@@(ww>r71eubE#{~PP?A=fs~) z0~z|@rVyL-E+eDHB|LndCcMn&D2*del_ZcLRc@`wML)heog zoMI<;D=R;8SFVhkl~pK}#l2>Ydn0TKM-LbG5{`1Mhs_<`t!Asa)xr_CM(k8v^kB3w zR2(Iq|Mx!$x1tl~+dn7lQ~tAZYZBl8_dg>9r~gO)j`;t7`ZN9C;{Hu)^*%3k1--@u zWMSIgjatuFb`6f@PqS^yu|4j4m~7PkmQ_pwdKdjFn)8Yn+j!N@Rx&Po?rCx}qbDjM z_A;*rL-&E|8B5#WTlM<+zQ%MGMHT9j^8l6@8FsGd%~kc8xY4%^lQmad%1&OsdbcXx z%1&AmFk+<>&X;zsx89+0l|AfyqTOXfJJG%E6Rm7azVsfI-cA&+lB6Wp>`fv~3=_&f zy<^-&|EM}|YN$t*n}+@Z6?v;`)gH3CZlF#0QvQ0AcaIwQWldh1FEy-+WU7p)(P z#z6DAQi`TE%9ZJ z(0FGOteiJu(Y>`B6-DDF&+v}%6*UpGFD**M0^)i*n{~{{Nh1^k@N2Aef@l}6N>7R< z@`gg8rYsVcq@vw~^{gz#4UnDgXm8883rod#8UFDR-Z9Qf)q$M5D4jdF5i9i2sAE%4 z?OM}qs(CK3RvSZguV<8Eb-4GYdC-rD|A=4*6&H>!#~ zN29AH=c2w+l`DwGEoCerE(&`UvX;rp8a74mB^nP2LzPc=R`;6E*(FWFHt*{u&yjr* zeWC+mVoi-ul&ocsPc&h>i)vq-n`GYvmAk&$J_`P_U01X_Yv2tTyNj-6jd&%-scON6 zZdg|?#J>xbhjB!|wc4YpCHr^k#YkPtUQDv>ljbfe%DAQpk>q|rvTLa@v{xlNzfg*R zf_?t9ZT_SJ;yx_Iv}C(L{nF&sNbSfM9#6}|)lWZXA3t5Mva{NT1top5D+JyRdl%Vk zh4La*fw7IKT${^})FLe-!<6z;Irj*U>>NRc%YGLUjvSk#!Av@6a^509ixK4et6jHT z4UOp3v2ne9*@KH^pv2$X-&4CqJB@eJ4W;A8wQNT1%ov8gWi@3)&NMlXZCFM1PoC`; z+|$*Y_9I*-g!=`ke!F_7p7AP3rJCeL%1y%GarEUzCs3D;lWr^dzA-K5H)+TEMHb98K^skTz*y6Q4@uBuD< z7UM?FRnb)Z$oIur$v{z+Bz3RU2T3jEN)MP4BjZh-H5C`k*Wlb&v=#Wabd+;c2dJZV zp9ThYvdW$_b?%0&pob7H7MgosG*@WhH1+2Nc)A&G)n`C=hZ;d&G;Sz&K2c$f(N3Yx zDV}Hx(ZZ6?4C*e(=Y-&Hv4IIn@g;S9WVBK5>$}v%`9yn#cSwBQW zB51K8Z1cHKr%swURF}m_Y2m&ShG;DX?OfV0E=sVW-$T;j!P;s~*rC}O(hS4DNG*`! z$PNyqjYRT%X+Bx&eIX`F8>f7a4W+HRouM=nzu(-mD9My|Rx_n?Q2z+aheqEf&!n{f zb6uq-`y5tO|Eu+$QeUa|irzR<=Ss%f!mJA&iH+!~x3P`j<8EUsU#xc0zLcNzX)9WF zXw|t@hqfXe*ox8_w%pKrwpM=sgL~^|$a5)cZXS)@rPwe&6m05A+cx>=u0+c^X!Es- zLDHC6_s8{fON_O?x#c>kf1`h1QT5MNu=LPXqUo#AYc;;z+EVSaASglZSZ5!50Rayn&Gi+@91C$A z%P}9vxg2dcuI8AV<3^5oIPT<_m*YW>GS&73$ATO$a4gL6I>(|M?{h51QGO+~gZU`& zdCGm8WcF#}vBOlxxM4bCqA-InGcj8+XE3)hFEAMsaF1z-5jm2iPktg#64{shM6M)q zG5LvnDXn&@KNmS% z9sOM7adq``k;}=P2=OcOx%&FK$mygpAoe1!121(hayyYviM`10=t8J-k>fSd&qbam zvLSIJa=kYCxybk0>gOWoYp0)!ysy1}ZkNqdm9a36QtlS$$LspBW>!yCHq#dMRN<#B z?rC~j%G1=Yw5RDrK2K9=j#KsX0Lr!eM30Niagby3bGbjNlBa2GclNSJyO3OSbk&B} zJ$<|zqGKtcx9B$RLfstiAR48E;}YZ1Zrd5xE9*O(?qhm4a5gQ$7{7KryBB5@W&sAd zoR6Qop#x0X3!*nz>8&*D5_Ulab60u3XJbT!%zBW9c3fhtCHzjh!?g`FJOw z!5uphL)zFiWpaY%M#PjhcFhx&5@GIp1p3<8dB`S1vE^vHp#)2*u2O2L#lN!)(n>jc z`8AVcBVTvz`6Auq+Sd~cj{feATgWlc-_KD$I?-MWWj71a{H8uwT~Sb$AZ;aeWjzXN z8EBDt5t=SWa1X*$qpWH^hW1>2j63=Gs5u4V5jT;Yv~3^sZ?cS2BQ;4dF`yf4>3lNhASOoJ z8`k1bngb?@zGy-ZrRS`T1JiDfGnt}sF0Vn|*Ok#)N0c{-o=!E@1clI=aEP7KXd%(w z597@v7m*Dm*)axvm2oiJ%KM_8k{6;KGsFO^t&@D6Ija+4+m5Z=j2prz=~*h^Rxe zcNKeocYl94(r>6RlzpJTyPvf?=fD7uAlkvYoeI;i3qlE%mzTSDV@hXAeuDhm{e6AB zk<44dSAKn+{ry||AV0U*`?)s{boUPk(qu9g`<9;GZayu8{5{*qLoD|0t=wIM{5{+? zd4Do{*Jf_k@%0aMbtSomf0c$t&YoU@eo4dh4?qYW-&17RotxYUA=r{U?gSxqz|>Ei(ZwAlmWEdwTQHvOG(3qxrN7Ppg=dyl?U_NhYZY>1`{qzpoSamBASf#*nk3Qks{=H9%RAPt$(k0P zuI@&$A=@qSFzz{1YxwdVHlB}w*V9`YZ#3I^ySJojm8vC)J2#IY<<#sBzt}O%=w;Ny zT0F21;sy#Pji>~%pG%UklHE`7USmI>K*U8U-uoubNuH@i$U2@>_VU$GUyS7TY%ih4 z{gT_e`FKlJn)LbZu0}SbV6SC`IUI9YHCHVbKjwQ$>OcK`8)ZC69iQx;i`27}M639j z!}M($lwuiFpC~s~M>lpSQYrcM^ls#1ytaS2Z}|pl@oMbls*>8{~aC4lDF!ax`vs;ru86f`VzUBL)rP1)G#+%*T-Sm&- zH~zFw<+tHkzFSGdvlNeS{iKv{Mm#J@GmkOGGnd|&Q|oOCGCql{tn1FO*I zvty3ExR#msGOIqAami@LD5J2gh@UdJmZRn>D4820Ea_{y_ezKh?{>5(ve{&ehMAsX^UP z+!(J^ahH>g-qaM{5=xh1oNQNWBd$0Jr>V*gO6*dhVjyg^L7O{Xk~H5@!N@LLC_7%4Gt0YZ3M)ELE4YJ>G>Y=_{=G!)ujO3|!u(g)UuZzKDaPLuG_QP7akFL^eb&=+{;Bqoa-3fB%_A+MJYXUQu+7a}}Nu zt|KS^#XtRVc7jmbXGot{h2#V2lPCh6yGT! zwo+xWtf?%m>}qMY|1BMoWd=hM3FCRh!Th}clAc&KHqAb!y^WpB>``y6WsqBB=SVGG zm6L{FHE9~19IDAvtB5UQoI&D;H)ehAKyf91WjNL?#vXV7C2mU5yB-%uhbq;B07I(A z#!)dL!BNcnLiQr|Hky5H<3?yOLKgMB@0E2;q4vLNQvWaU(?a>C3^-M(rsdDShrz~g z)Zog?5m1X;3yv`S5NR^M+DnV{rhcOl8HU%^(8xRGYe6j-EP_+MS{5OnIcUOSWcs_eMFuD$McG|3F)mD#^;SvqXj#b3e5;>7MCaO2Wr2TK4AR1P?ylKV7L9JQSM`N`c-v(#AJIlf) zS(YVp+Q=Y%iH*gV{%| z5JMZ2eDhNF(Uw+cd$X^yj6z9$X<5gjt?8AqsqgvM;>EtU#Nd1J(rQxbKfU)r|W7S91F3A_m^0fb&zvgUB zo~Qc8knGPCtujQbpTCWmW^YNYb+om6F8WFf>pN=hnWU5|J3Lw~WVR&N!NEcLr<4Rb z=28*c#wYdb$qus=F!7&Ud_Zwfas^F@5EEy;*QJ)pOtXrQ@5C%b#tPMw!)SY3S*jho zd8j2msy>fW%i^>_H0?Y%URLw-UZkMP4f%|#CXc)?*7NacHSWkNart%ytA4zUQ+8r> zlEvc=j@2s5Ew%rwvI81f!OF^T)!R_DihSU46R71Bc_yLX2h^Y}2bNtj+m$HpBZ4oIW4mM2ul5L;lz2GsPxA=c8lLSh( znF}TUjpwjnTH~G7zVJ<#T;iq#J!%!Z;ZAz5wnm*Ov9Jn5d`LxP)UzUcVVp9W3PTBS zj4;GqDFR_7DudF}oYU9xX?ZSrD|06$oyojt@6lLjYp(aD14?Ir;aGO8HtGYm%}Qdg zq)BQcE~6%rNEz!w^#|d}k~`np>D##BQ6?CYm$HtV!mPEKZ zOL)X@4e;R!IW);%M1Ok49RB-8hrhp2+V+&q^?owQw{s*wJ#)`ZWGp-_O{^N&0Y> ze9|B8!q$k$GR>t;YHG&t`S7Cj!s6PhEn=O1tzO@w@D&GdmYzp`EG;4{J`(`YyD+LRMf*|#_E_qJk0X8Ww-#$ali%@M9DIlPw z_sPC>>7Xz4v7|BCcD_2mB02x=9ZPcm#Z8iATf6%&$+x86DiUUoq)+m}>Q>TMX-@xl zT^QMrw2hNA6ec^VO_!~wx2Wd|HHJ*zHol>4JT;_YrvT;ovCK5pdL>5hC$L@O6+?|8KfR3{#dfn%hN>0m1$I}X3dv{i8nS!|NBXVFHK~X%vF}FR)S3R4 z(F;yGa`ErJ5ajc-^o?b-B2?9L3G`tl4bt0_9lT`ZtF4Nu^)oF!I4z7ITqGT_2*RI? zn1!j56Zil0JnR1J|K)kwIsi>m4<8?WzijQJs@lZTaOUm)4|hg$gs(v?Z`A02%ei$P z%9x9$mrLXfhAYWw`CiC8I9>gb-UN`(p+5ghnr2E95_JaYpRnn9sxoXqnq)jG8(}bvu>2mf7p|O#%_Il=FZBoyY4kPCx z<&b%`QVpxWFy)nN^c?XgmwG=@RVAW1$_DqMAxMsD?FNriDIqde??}Z<0>Rlg?lg5M zdMd4a8SdQ@*$Y(~ZhQvSu#=eZ!MUYMl+KpLjh+J($++NKCNHTdrr9e-xjcua3MC8HvX-}E;s>aTx>ysn|X*=j`wRpM7Ah*)h zgOn7}Z33IdN?%8wZ!QB`2TIRjV32hpn*3fmF?0iDZl<&9Wmz1N&H9%lg?mOPnYhTS zweltX1O0Ao)DEd$JmsEgrFzfZ#=QAjW-mybjpyi+r|*5=Yg>Qc{j{1QES%v;V`ezz-FmD? zm7y@REZ6KRGoAbLB7~4}6K}ryHu~2ylrMsfY7f{j2jAV)iW&N{`(*&OQR*9;pn4S2 zDKaLW^9nk%uX;j6H`YbS(j&QPWk=JTqHLcKBg$l?*z3Y8?Mm!57l!>e?)9}d-?-Q9 zzj1H%vh+rz=^MW(xUrtE5JF2pdRm&CU7JNCV@i?a6*yV7L!_tGOJ1SLtcWg2=IGU{ z)sz`=t54Chu6!e9HcG6%hS}VgRJz-kMnLUuXP%I*y=D29`D;0<%L%37$kKXhHml^- zq3w$D!Gt)b*GC|`5rL$t#fYYTO7Ad`%(9lXb`9@^ph6Q0n%}RQsW1JUq;Adk4G+Z8 zO*TZeabu(6$Z&fPCbUzd*{Bs?<|6c+ywe<|l!KPKheZ#FZDQ?N1FB2GRYuAqt-TWu zO*WY<9!lFC6>D@D+tTYkG_gU-@lNt?m1o3H5xk!7y?;%f@$YFsyOJ(>GrtdOZ^S*x zV|5XUCe2p!g;ev(_||FpEt47*iRK_xY#BI3kVa`D#mq9%qi!YB;6oA43ISaZ$VXTL zvbv9ulwn6Jd4T$`DM!T9%z%2lbt0@q|L96He>=3af8$)=U@WJ3?ZyR4purdWl_ZA5h&d^0n%To)F zFHC%lynZRn#*=ON!W)~4EA4@@leEC;{J)2e_~!BzquP+EccPJj2C@;ZD&wm56dO7` z9>#Z0N|9DV_Hyo0tC&@FlcqViIKjZmr z`%KHYNY&7lK95w$apC6gC)q_?O5-I_yy342 zvZ;7{@?ecEzx6h!G0tNBWX;LHjr-d%-zDXde~Z0HWMp29wL7#}m|CC#H^|Dqoa#Zd zUyYh+)$m^yH_93?1}7PNAz>!j)!bfsU8Gw-So%-^Odmrywsemm> z(5WVa2(Fg7D2(7F((+LqRbG)QMzHT{UZ?**{rm^Fme#b?QU5b+{iFP?JMD%hhf8FB zcQ52(j_N2gJEX;FLy3|ZxW=4sDKm}C{aC9`x8#Q2rowAd*9RmWVSw8!3xY zv&(ZuCKRS0zkQ1``rCRt}}$rG!LHF~6GIf3?m|Nl%!C*mGS z-pN={xIWG!asqozPC#2s&Y6W79Ay%rfs8#%r%x@~m2@yaRMZfPK0&oW7du%b%z?UJ zbF6&_nB$H*-bAMCi$+qt-jd*!es!Zf)~vc5iz1}pIb zaiC5R`Db{TCepLi7uIqh6_h6NN%{zqs)@_+XOXDs4~a9YA?7*GXv66itLj$z|N2vj zu*DbFT9i%6_-}5_q8_6h8RU@3GB+{BCn#ae_o7CAnPpje*-REDGNOM8S7v51 z^C3>&qrA_gGd0cS-3SwxN;Iw)H}g0;(a^QmQ!VHk$%7H}{p;KXvma?kT1`wa#@o&ff4`7)v!gERzT1Usv`U0Yn7ET<*R6mJ-nuvO)f zvO9Zy+W|AlNqR53pU7^i`J{N&$I|TCK0{_2>iQ-$RSia5zIFfIciwitbia99GVeh0O!n2$B;Aw=v)wn&^}6yu1T8ZXXfjB7FxP*o#X>}l@p;u7(R9+8 z-RMJLqQ%5;CSiDUE%CCpLv3N4d{YfORJ=z8M|V|yAL#%_q8m?5QKZ_kdTKcth;)~_ zOzBE7d}}iu=vQ=#jO+Hz9bbL+flSp`%_=2o5fXKVl0`VlT+?JF=9_sKHg?)8;7vr! zZZYJWv=i09km`|rD}k8qW|7CRTGFXcj23 zi~jKi1Z&?(nuf-^wVF~VLrCAc4^>TDZEFvsd^0ZfYsN@~Mh?+p^QM1&NXU9hpOGw1H9C5+zD6jXXEL_3{`Q4P!7O$>YppSIOe&yZnGbC%N!)Uwo+fXZA}sF{@h9`l-5x)o}@GHYeE`{a~NVWk)lFE!d8 z6^YJerd7xkdn~QSX(;~*suLmwt}{3F`PjO(CL9raWG~1(>@{a9y;Lf!PdBnd@_;Gw z(m*u6VkT5D#>d--hNHx`lbXdU{2S6u+*`iSWLubxi=Vr5Q@vj&bV=XBQNj(;bxbLR zPh6uQ%A}M$Nf@HsNju6E63V*jdh$MqpLSt`4k%lxWDVx6deD?Ftusdtj5G3!7EmbT zhBBW+!mG^sR{rEv>4>X($HNrbuV>#^U1NT$oT_t$FTbzqacs!Z{vTR5ezE4lqIGkZ z#O>Ykc}kh;4c?uoy7Z5i-7h=lOMAG~fdbRh&CZZ}(A_6xe@)CZv|^#c(QOv^)w#5x z+`US}{Lh;HvibB&+b+j<*J|R`>hziCD?hq6t1{gEpVR|=>&{=^d~w4GlYgrDX6NRs zC31fK``pQ_d7cK%aQorlvH|tN+82!PIN0ZU$?_9NHF~x+@68TbuHAO3o!K*e>2~|i zuMU|s?SAh+kJRWk?xOdKs1~muhxb{VaeFUYhax|3JoNBJLh+`%#{3vte^V!qG;gy9 zS8KU##J-~Q?!2FwEAqZ{`_}DBlPb@TU29Lu`r{d|PM>@NJNMg69S&h@sLeQocTUMJhUE`DQq zl~EZEJN}Y8XX~FSuQ&+1m1N)*pGYqwY}uS;0S4 zNIPJA&r4pZvE@g#*N2kdGX@o(=}_HJ72i4;q#(JL66t1bKf&}ZmD-mmiSMPi@V=; z@7_84w`@r)^7-?fwNs|l>r$qSSDWh9qnsNw7?AqiyEi^3P7G~VwQ9ucrAwPv{o{|b z8DGBqXG-_(cjGT#UghuT7}6kLzVcbqrp@Sg`0%vwQl%PoIB?)6y8;C&FPuKTMvipp zGH;qayHchM8M0T;oxAj$L4yj{yLee%~|2hLASd|WtFrrh&}4lSBc zv0^KSLWQc@7cN}=*XZc$&)T%v_;JC4wr~CXmNctVr$_LmOIuED*wDXkxpIE>@7=r6 zy;7wPGlmVz^Tyx*=ZLdsw+T}f|N3iRM;n`l#Xo(zcjT8}djHk7?dIKGx?E^<{P?&l zyLWePTB}yv%_dEzUhwjo`LI>1^-WHn9^UoLnH}YyKmYBIl`DPnfBg8@Z?3K*es9)n zc3_n%ou&>Sp6j%``;R&Q`R7sk)Tz@B9ysvJ3t!&_ZguPS+CG22?Y-s8oBrLr`Jyk2 z7q{Qru;HK|Crn7UX7c0)JAeAAgh$Pqv1#ADd3kH+&d`0EH}_1udUaiBi4rcAbLO-u z^!4i>+5i6gbGLKn_IRBf#EEr=jvAHaSffT`%RPH``25zbUF+t}YuEec&1H8xbl6!mOP2gSu3cMG z=l1PuEu5UfyldA^D3&>M-fNzolQXAJpEasDKM)*m2`hg1*(M{CzME|4)}&Wqc($BgRL>qU&MZId_$ zhjyil6sh_0=bu|1-ncQo`JqEINNnqn@+#JYgh1yF=Mg~ z|MABh6JujUrwa$ghEcD|^}5`S!VWYw3isW7E7}xUlu0 z(W5i{kS$xGt9$l@J3e^u`ym&XVOt|2&Kz)d9wgKe;D}B0{?N~pAGzXf&VYy9{~Qo;GYKkSAc(i@Gl7dA>jW2{AYu| zJNW+u{tdx@B>3k8|0m#o6#TP*|5Nbq4E~?N|1tRQ0snX4KOOwrg8zQ-F9QB+!M_Xm zw*h}=@J|i?KH%RD{9l8ARq)RU{!_p|9{l~mzXAAX1%E&A4+sAa;BN>13&B4J_-_LL zOyFM~{O5pwJ@79B{*mB+68z_be_`;S2mT4*?*RVx;QuT5KLh`d;Qto{@b>`!wBUaW{P%%>BKU`be`WA51pe8{_fq!1`uLk~=!2b^TF9QD);9m>; zTY~>9@E-#Hjlq94`2Pw16~KQQ_%8tenc#mG{0D-6C-5Ht{;R-$DEJ=(|8n4e9{lTq ze{b-=3;spHzX$l&0sj`@?+yON!2cTfX9oW$@V^iK?ZH19{GWsW&)~lt{Fi`#4e%cW z{!ZZU3jVFZe+&4J1^+PcKL`G|!G9z8e*pgs;BO25>%f0J_&);w0^olU{6~R*4EV=^ ze`)Z43I2z{zd87q0{?#CKNtKP* z@b?7&ui)Pc{QH3a1n_?k{)52(2k^fN{*K^(2>iE#{{iq{5B@#DKNt8P2mepte+m3+ zgMTRa_XGc);NKVgUx9yD@Q(ri-@v~z_@@H@&fs4G{J((z@8G`*{Cj}^G4LM({xlp% z_6PqD;NKej8-xD~@LvP|7r=iJ_^$*1x!}J9{NuoXFZgc(|Igq*1^ml^e|7M00RHd5 z{{;9~1^=bs{|ETL1pn^fe;NE8!9O4Prv?AR;9m;-4}gCG@ShI;>A-(B_-6qB+~7Y5 z{O^MQ6Ywt!{=b5MBKT(l|DoVt5&R2*e_`;C2LCqTzX1IGz`qXoUjqLP;9m~>?}2|M z@E->L{@{OBzW?C=7x>$N|0nSO1^nBBe;4pS4*t8rzZUp60e>&>Zw3CR!T${SKL`Jn z;QtZ)UBSN@_*Vh{;o$EM{{Mh~YVaQj{=VQ}7yRdg|8nqe4*rY5zajWf0RPG0{}cGv z1phbSzZ3j7ga1|VF9H5J!T&4x{|)}OzX$lI0spt)pB?;z!M_^# zw*>!f;6DQV_kn*=@Sg|%cfkKW_|F9YT;LxG{#U?%Jorxq|2g1a4E#re|0D1}1^$8H zZwLOjz<(_GF9iS5;GYfr_kjNc@OJ_K2=I3X|5@N~5B@p8e?9mIfd3Bg&kz2g;NK7Y zdxC#o@P7sVUBN#F{C@-g%HW?0{5ykx1@Qj@{=b9&D)8?C{>Q+72>2fb|Nh|r0sLEo ze`D}}0sd>i{{r|g0{?a3KNtL$fPWnL?*;!Y;Qtx?r+|MM@UIU34Z!~$_@4m(s^GsA z{Qm&|m*C$W{4ayQBlzb7|FqzL82n3t{{iqX0RGd#KOOkb2LBA;pBwxKf&X3be**qx z!T(qAPXzx=;6D`nD}sL^@GlJh(cs?({1|2^=p1pdRo-yi%H z|KR@@_}hU0C-DCT{M&+m7w|t0{=31y7Wg*-e=qQF1^%bO{|xv)2mh7e{}KFM!M_>! zR{{Uw;O`Fp|A2pL@E-{NzTjUM{O5!Ja`0~s{)@rCA^1-K|Hj6Z|)W z|5flW0sc9`|10?a4gTlA|0MWl1^+zY{}lX#z<&n#yMg}?;C~SOmx2EP@UI8{Vc_2$ z{0oAAJotA6|H0tz1OC^+za;pV2mguSKMMRCf&Vk`-wOVD!T%=scL4t^;C~JLZ-c)R z_}2#i%;4_{{^`NLH2Ajz|NY>99{g8>e+c+b0{>~?e;@pNga4o4e+2w%fPXje9|!&y z!QUJFSAc&M__qN6*Wmvc{KLV&5BRSI|BT?j9sGNNzb*JXfPWG2{~7!@g8w1#e+d3J zz&`=}i-Uht@ZSagW5EAM@Q(%m`ry9_{5yfa2l%G}|F__u9sGmAzZ&?r1pjT|KLY&s zfqzl(p9lVT!2dn?&jkNm;2#P8SHOQf_)i7@IpALm{6~WSBk(^3{(<0c2mZIfe=PVf z1pm?CpAG!?fd2#VcLDzh@OK9PS>SIE{yD&ZJ@^NJ{|@la@4M`EbN_JX0SA`+P-uFG zvbB$QT~+6$`%lGJwfeAnN}79313y%@dE2eWnn^uQjI#Ag{pQo}fB5`y2+^UtC zusCFsXPaMcb}qc#c4qd+?sxWnX`ec=(t+GByaq3x(P-SEf6jOPGiXAZX>%v%d(x-d zo~y0>rr8hOec^nGgjVGuZ+p5OIXb?}=>3VkdXInIwSKEvH@a^tyV>W??jP2SdeLdM z&C!juPxUX*gLof@B8|dIv>C4ZtA9SEhiMeSAJDsrwn#aeoeD~Q>EE`e;cthV~z8#M%q>Wb?Kf` z+qQ+sJbBV z??p~`eoUA6C5KV@7AF*|y-H*Pb2e-8gf< zg^zN$^gCK?*n4S13>`5jlgD2boL0x?D&`&6ChFtY?4MiI9G;`t#kKXy*0Qf2b|pvV z5q8Nst)+rwnsVFG1m{3Iv(-qug#$^?{7VJ-SPLF!$VyfmYk8tCfA{1 z{Yy6){=VLhbGe-US=()4xx-B>%`5tMp>%sf5#&Chl>`z$Rpe#_M* zd)73#|5NRX*(Ue$opU0nOGu*u0sHfed;4(f<%u2M)pB^V?!b`UgWAvUH|0#^3j2#O z8*^khI@dDwDs%F6f!5Kfw#GUMr; zB_2G?_x#G7KewN%9@FGPrumOA^;=(V-LFd=9ZNMRUwP`%Lwh?ds#asCcf!xdhJ0Fo zX5#I9mzPy(GBfSVcUPY}XZJlhu+rN}Ka9K7tVgr;&s_tWtvqon?ezQiHl3YUcvKg! zt;H+u8`wO&QQF5HerjKBY^wN#kslnKvwUn*wDShPbJr$UX_50$p2nBDjSc>NcAu;Z zYmCqPzV+z3d7eBgyW&)}qrqGL`lHC5y1z8;)B4uAxeel91@=Cbx4@nnhvOfgeCOYG z<>#QhG4*bZxaQVt@Zal>)jt@qtzy;EHG>*1-XC|MX#T9WcXy8QtZU~yE!)@bsg~Ee zxgl%Dx%W3-p17|?Sn#mpePcH}T})^f<>AtD>lyI(1%H3=KLGyI!T&h;zXbnP;6DZY z1Hu0-_)h|VTk!t`{=b9&An>06{+{698T@C0{~hp84gR^oe=+zU0{=h3e;W8d0spJu zZx8v6%e+&4R0{^?<-xB=GgMS9_PXqq5!G9_EzXJbX!GAmWw*&tQ;6EAsUx5EY z@IMLu7s0A4 z1^?3EKLh+vfPYW$-v$1oz`rK=UjzTf;Qt8xj|%_bKNS2uz<)LPdxQT+@NWVB#lXKT z_=kai3GhD){uVi{|fk@0{;u(e+m58fxjd8R|fyR;9mp$e+K{c;GYltn}Gj2@XrqZ zmB4=-_%{Rp0Pw#B{`bJYF!*l;|AFA27W~_Te?0g*fPWkC_XGbb;GYNl$AW(!@E;HU zqrv|f_*Vn}zrepP__qfC2H@Wt{P%$WWAJYa{&~TF1o#gI|N7ux5&VO|KMwq}g8vxs zcLx9N;C~bR=Ys!4@DB$6Sny8(e;4py2L9pTzXbd{fPYu;cL)Dg;GYKkKY)KX@b3Zs zUf};b_#X#vg?e+Kyf1O7qaKNtM_fPZW79}4~@z&{fF zkAVMZ@b3-&^})Y8`1^qW8t`8Y{w06e=Ybg0RIZ$9|8WK!9NQ8 z--G{o@J|i?6Tp8J_}hX1e(>)L{u#l4B=|1{|1RJ^1pJGD|3>hC1^#!z|26pU2LBN7 z{{sI0;2#M7cfkJ%_&){z=iomd{Bwf;kKmsk{L_K|F7O`*{_Vm40{G_x|BvAR2>e~a ze;)X|fd3fqZwvm;uYmv0;2!|~ z4&dJz{Qm_1>EJ&J{C@*~8}M%m{)NDQJNTCe|J&gI1NdhH|HI(F9Q;>+e?joi0RA_? zza#jU0slAPUkCgLfPXpgKLq}t!2c!qUkCr;;9nB_bAf+p@UI8{PT;=~{40TfW$^a{ z|9jw{AN;q0zX$k-f&WKo@!-D){C@)f$>4ti z{2PIP9`N4^{_ntl9rzCd|0&>a5B|Bqe-`-n2mes;-vR!;z`p?aZvp?=;2#bC55WI4 z_&)^yIpAL%{4;@nKk)w*{7ZrVRPgTv{yV|{82Fz7|I6S%6a24&zc2W|1^-LnzaIRX zfqz=?-vs`nz`r>7HwXX6;9m{=6TsgY{ELGBIq+`*{*A#u82qz>e_rsf3;t!n|0wwX z0sg;$|1I#32me#xUjzJ4g8xeJj{*N{;Qu%H9|ZrZ;NKAZ4}iZd_>cHqAU{L_Gce(*mH{=LCJ1NcXR|5fl$2mV#T|7Y-b0RO+i z|3~nD3;sjFza#i}2mfgBF9H5Hz`s8DKLGy#@IMIt>A~L@{AYsyF7R&%{#U^NA^495 z|AOFu1pNDfzYF*elkY$H4+8%R;GYZp+kk&|@E;ETYr)?h{BwYRJMeD{{?)-hGx)az z|7YMo2mJSf|8?;13I4gke+u|70RNKUUl{x|f&Uor-wgi6!2c!qCxZVh@E-{NslY!D z{5ygFNAPzA|5D)p7x>=?e@E~S1^*e~e+c}Wfd3Bg{|Efbf&V=4{}ud4fd4-5-vIux z;6D}oAA$cT@P7gR{lUKq_GM5^Y29p+JeVtyvHtuEA-HCf~C+Rc*i`xR?fnTo_{6?qXca-i|5@Mr# znoLtu@GEgXjJb|6eoJ(}gRqb|OJ1x`!LP(Qx!;|--@W*eIE&vSDfpE*C--|n_iMyi z{NDbLexLq}-;B3COgk~}F(+=ZUnR$h9NjnuhsQfQ)wB;yV8uInJngx#@pp3#@Z;HX zua=Y5y;@Gz_t*{Da*qq^dn(M3P)nGuF0SVA%=Uz*+pDk)dkIVI<08AT>Ku(Vp&_9S zqk1zTHzv*@Dl*Z59n&26Yo}&1%lar;E2`}P62e^Q7*<1d)#pSTGp0qeuAx=wdv2WA zA>@C#slpm6`N?YG-v9E9l@HyB-$?h7mC+FLyT3QEsxtKO#j$x$! zx&K<*OZ7U(KXo@1xR(y|2j&CD_`S!C_!)#TxEBBN8`Y&j>GK&E4|n*nU>>*l*fb?; zW?FK_aeld(9~?4{j`Du`poE=!&pc;pp6(Q|J1Xm=s$0sf-h0Eh-_cDMhc);iQ{zon zF6N(H_+#(UKWA|~yL!{Dnb+bzSK4x`(3!v1-Pt;QK$$M?6Z>tSHL&8##M-H3pN zQy#_j%a!-phVnaOLfikgqQYCp0txx+w>wpA%E&oYwqIJ;?sVy>!TwHtdXAW8H`8N6 zopsxqb}jsH&%r4r>^hyubUAp^iV`0?uI}gIH0Wvj_U(r~|0QwwqtvC!Tpv|9{K??@ zqf7m^diwdlW4h(2EorY4YMoWQRG$=ea~2Dlt3i(c9p;Sv$WNb$->k z1#Z{WGipugl`hJ~0d3;~g**>%U#{osdUoPyCYF(}Rt&epYmECnn z!4c2KZk!+Eeqiaa{<}MjsdG6o=61ZzzTxxT3N`$>%f1#NE6;nU@7bVw+^sK#>!qIK zQu_BZH9T@>K6CzYj%#!FzVtjA=bxc(;aP(&_r75J?&ia{g?zucN3d5)X=;1ij4 zby%17%)Q;8n^d`(!7fLq4NV;iwp@OEZ;pf`?zMuloV)h%{I*?tdk1EA>R9NIY2l^b zaTObWv7O)f#Ny%~-#=P9{(VWOYq#byEW&}Z!WvTY-ev^ut<{o=28 z7UX)db!NQ}Ikyfi@i}VKrzUOBpSACO-+y+v`}@s1J;$G$IOAi}tFLa{sWRaB66ZW0 zLmnQwf9mQno9C&#dRG53Z@`(2#a~uvcJWc@hNg(Ld2w(r_Zk0w|ql^l9ej;{2}}9 zFZPL#7Zy)FCdY{de>_Zx*>vge)dgnV9ewJy&+?61Zs++txX!_TSC+3i*J)8u{&YR3 z4aysTVoJ}vg-V3mta&iv!=|2ZTmlZCuJ+T%tm{rbSunbO-}8l?FL@3qw$?tot*OI? z?lwD25hd5%-r90b^{~>#wq<%zbW&*G%Aaqw9__lX*FgU^R~EJHZ}Z!>KT`KdQ)cLj z)6+sC3LeSj+$7%nn0@07O;+UX>t||SIA1yc*$rCexOD%}oSi+EbgW=XcrbWV%=V1M z9~Exd_389i`L1LuUm`qo^X7lH{ppad>esLq!+&dUzutf0g!wCGHQt`FONQamk7D~Y zbt|`FlS8J&Yo*E*Jh=Yn=r#RsE%V&k@!8x?zy39$``DFFzy2^gGRiNk#hrP->|dI? zdcksDnGzf3X}zF+?E?2_&kSe~{*z1FOZO*qz0}~{tPFF{Eqqh?;qwPI?VIguZ~J0| z%?+OV?r521bmyyTC7<|J*G#GWf16 zGAu*=c581AeCpPJ{MJ|bTh_Q*dwsU7zAw@iFY@B+22<)nZ?dlaHDOcTR(*!r?kbV# z`agLloqbzrMZfsQPE%7gep7PrAAi)oeszD1sy#LxS$5;^*^PqTR%B0eCP)3lN1i$t zOI$MRWX-#kvOlh~aK|7g#|`xh)EpDwopD1nL^JU2s_xgK#}JeujF&8QOEU0{_XoqyEa>xyZOQJ@~KTz zeQ(^aooC+rTipY_9dlmlxq9%Ng1LfTwy2i2>*2+}*C~*zZlfv7 zchO(gJn2;Yz~gD|JMRrW()Z`HH3t4-_jPQl=Qo@VENv6Ddw7Xf;i+e?ipa6_)U!I% zDqUOC|9Sagm7?3)Z7z{7HaJ7M#Kt$C=FB%gxbpH7d8Y3Qep2j9)ikF=)2y7>E`C$3 zMX_F4=FPj9_vXsuJ4c*&wya`E$5riC&5a)R_pj@UjR`yUVpqX!k);;+?r0P4)Fz_g zhK=RxUVJpq@!i%Edkba>m@{iZ(8vL^-c4KHzh21fQ8nK8w7)kaXv$x?2Ir2*Uv5;j z?3ao^IK1%I&FQnYx9YWY*qfH2aU~0XJur06^hWy&J;}V`WI$yH|N91@ z?Q(e2jxNuO*6|5XSK_4eyxzqwA8s~$M3=@*@B4-fuJ>wT$mvF9#0f3CU~9KBQFnaW1VMzX{A*|Mi-p!LbcW zO@0wq#d*M#aW9_+UAk7MWK`=KH~V!=cy@f*tKki!oqC=cHYmf-^L*bI47~jOVYL}o zf>$n!T(LiW*55v@O55i8u`Gie`nb&-R@MDLy3Q9rADve$`}u3}*G`TK%-Q>DQ0IoO zo$rNLJ^0(@n)SQSdv90I=4-c?f0n49uSvc26DrKV_u$={q1PhX)O+-<;ozx7%6Pr4 zS}t`HT{+v{RRkpo+?OvBl>wk4b#mpbOZGIGz_j-gW(&P6fd$UJ88@I6RqAv}6#;zIpF#YYZ zn>Js1-KSr%Q!Aea)i^(Eaj#P@<-0blHt&ngw&8zYS@nCZXJfo`*LnBhXweo0x;1s| zw7AT#GwwZ3_z+#&$+hi`cYiuZe6;Cx%==B|k25xWxxBhXL-(@NJhs=a?H@RD+)$e> zE4qGZI&J!yot>8lwwj%9VQ9G(C#qb#Gpj|D@<0D$>)4>kfY%-RIhLE4`r-S}v6afE zZI^GypnDbV(s|_DH?3s1L-!lx+2?V6M2^GHj{cJ&NAa}IOL{kM_(Sxl_D`AzIi1}* z=i-EYJ70xW%jI0PS6|zXbIW&J{P6v)!cn2c_ixOdeV)^u)MtG!ApOtO6C^oMC-_D_pGbem?n6)Z8rgn|b?_YPko_qQG8&4K`-6=dPTi57oIRpD1 zs!_3Xw>lTX%cgyJ=KA4ml;gaem)UbNgRAmF4uL1&cf6yE3X$ zo*kvvv~9kp_td^mF4gI=!J$@--mP<;m~pqvAhuk4y=;w3M4bv<4xR8y%w6QAL$4Yx zxx4(?eDanDI~Jz*4gJ`(K+dj(KKyko*X3Qd^^P96bGLPV7q=04a%YZyn)OQg$Ez-S zcU~73w0y+XQIGcQ{&L`cSj#~>e;Tp(-HZ2qdv$EqF-^xtLqDHgU%ckqv}@gap7>P# z_bOdohIU_7?8QjuLF{ih+y|Z^2c6VCPr17nz8^yNVXfrAB;#jYn zsgK@Son_mZbVGJ{ge=cBZ$(1l=7IyaWV*iM_QFi|ovJi)I+(h6n}=g}zsO{}U{;fy zU!sc^t+%bvttCsdp~3R?9i3?k@Bjc+w|Thg`lNhNfS3a8v39 zWzRgwR(93_ZQ@ADqy3VmF&)YKdM z{j28RzrV$^<2!C{-Z^n$|4&bP6m5Mf)BSWYqf+&2S}${4tir8Q3d(d>aYvHk5+$Sz9vHO?kUpGcq?^0=%N6X&P zQ+J;0vG~xD{hr~^-skY|e{)=;qM73_9%^>R>)MW5<$N1$U-7WawAE?vb=dvl;)jK^ zo7;D}JN9{K$!8;GZ{0t7?^}n`t}D|NTe{@TtGU~Q_YQ5=<`MrybN!y@x<_|sdt++oZ)rj>Y*F4BHXUZS->$Lei z@zIRmtIoT!lN* ztIOSfu(aUq&#Turp7UYKU*is*e|Vy09lLU!F21*O$kTgLs-Rwh9TWd@%Rc?x*be9K zUFeoB-}Y{=N7)81Otb4nSh{@ko*Y=za$?=5h04w-pP}}OIo%o*ep4c}*vC$D-xU1& zdKtSbRTAHP4*X?E)fQ=X)ZPALuAa^9-e1YQzjN~wtAZx4Inn%wht0-cuUs>v)lW4h z{bMs_|HM9zPxY<;G3-={=1#kPdJed^d3mFH?t%7WQFn?oQ(x$JE^udVkKjdF?9&6z;iyZEUFb+i}^lC$!Ad_RsG5 zh4ZoKJ;cZf|Kl?_KR3 zZ(P3?y!dLa`<1d4OU~F+{?mhe-9JsrVViI2oZu;ce0VZ<^QqQh%lDsMzCCw`4Er`` z?UL?ZxbL}~E=$rJ&mR5scAaZ8^Y30T(<|&zFDIvI#pmCeeExQYste8+d)0lkb3*3A zW2-K1YSVr9ZKju6q43>GIWLr+bH-iWyMcD6Jl}AlEmWSNkW4q(+xn0%L zMdt2aGIiQt`<*_%xx(BYC->IR<$wNO!~7k0t*ZHAO=H`+HZ`~RIMwLgZwuG;?AS5U z#{0|h;g`of{Biw1EBg#s`Hxq-{T>C!{`fKV{VoSm{d4EZrO5XeCN8+y?q_@3ObzBg z$hhAr*n3OcyFE|cyEUQZgSZ2=tz{4ekUivRrWuhj$S>m?O$K2tS1Ev<{1zaKD01J! zWb6*3gmEGW;}@du7$dT%CqvS^b&=nQc2wCzs~MUfT5(+oc}}V-oURKOy)r?k4pUZ=#7vNk~w6BvLjlO-b`H=~YU3pyf{@(n`_j zX5^RUIwe1;NT=6(57C1u3O1`a*@yHNU7DMRG&G4EQ_S39$i^|TLtRWiVca-xgE{}8 zu`(jNlb@H zcatn^cEfH$08v53cD>jxUhF6;*ik@GX(EECC?G0UEL^*yh+WM4JTvF)ZbH%fdw=i$ z^Iv!}bEfzC&Ud~uGa2dv9XCTI%HW1^l4+VM6=gBZ4*!gO38;mB@4}S9$>ITD92my` zLCJ}=x?$66fRyxV2mbQ~UHQ8uxkW>Q!}9GjlUv=|Wmip$>rc$79eTg>i`6S!cMZDw zUCVu&-&<(?;*Afle*56R2jo80YU|=BE@_dt`Li3lZ@)yA?Z>t) z|M{Zk8$Bz|lY7)Y`;EZ7s(TL{HI12Y$UN!fvbG23Zj8PEx3wFGdRIP~_U7Ja-%b5> z%Ojt74-cv@JCgZY+c)2vKK8)Fk0iexKT7#v@{-AKz1Y#QfBVK08+!EGwSLO2E1r3+ z-ThlP-?cfaZ_BHr%b$F^&Fu?Ut`?bxY@!mXDroJLl5Gu{ACK z?RDL#mN`E?F?sG>Ji^-TaI$+@zEW}gn-wwMi|$vuK6j$!Wm9*x`*HW%>)eH3Y&!SL z&D;L5`0A(sIMV(7ik!rEI{dKs_3PZZhkl>tcrx$R$s0%2DO*;5oc!z|`~62IzO~}; z*qU7j?)&}3o3GFL!jt~T+rA-LS64l{fAj2jf{Esg|8zGEF3*j9Xz${-?~j=mUHFha zs!v>8>upzRZT8wWR!?2O%&)aNRQdGXM;)(Pe*Iw9%Dr#*>$!6Ox(#dJ+S6(5`sqvC zZb%wkwsq5^-e-1bmv8>&srB1$YxD6_rrQoaQ8#kJ8(%)&aPZC!@$Z^1@AzKu+}6%d zt{Cn5*SI+~ZP(72v#9lJmZNtzwz|2`V@m83ceS`UCodInR=XQ;K{HKYgVY3&R z?av>ZeWdhA)!JjreJKmKd9tos?|AwA%PY66I_S3z`?$JjMMIlcOcPo^`*g>so&)2f zOSg@F=7qkkw?28(j12?KbJmxwX?$yE%4_>K{^PE<6S_b4!OV3#UAM;{cYb}x>N)kX zH`hcx7}M&G@xv@%Evsq~IB%*Fec8nAE7~vG{PAN0p15d4*QeUtzWm@#ZMVJgpH0W! zTioNwyR8o$eErI_j}LwS%lh}LeV4y;!M={$md=cS`lpW?*7+MIZ0h{!jFwl|&S}^9 z(&(7VvexQ3jd!`P_dHhd%j=DE9ht9rJ1+P*cGb5B+rCwDxjBF5decZpeASwtJI>yp zH^GzhZi8>!#5o5ZdvC^@Z&$WHlKS1~!^4Xo+w$NGcRl;TrLR3X;fuzN$=!}`-FofL zXI@Iad42H%t2gwH9=89Pn`7SE*Kg_vCEKgs?v=Eta{cCsj$Kh*t1tZ50Du4C+gfk9 zXL+0FyB>+2@y}yXiIH=w6Y~yVLv(~@N#1oCo?+!IRE)Wew;{=yFiqSfnT|Wei!uK8 z2Mqg2n;d0^k||~<`6{My|EcY)?!z+`Z-kJ)mbb|LlimMLQ@#Wm0q%vETjeP6y4~d~ z)0FAJ8i003Tjq$prWUM z@!bvXTek+z1G)mefC0c@U^LJhNC1WaV*rLrGukmvjrx!2WV{^wIaf0t`Z4TTCQLii z$heqhrroe-o>+Fw2Y)Odrp>Tt88KbPH}j?eEE|>`%b9sH?3rek8Ox(Dz&c=l4SSXa z=Sh|~^UwNXof`HmGu9L9i)GESG4`vOZkFrm@K<(t;ejbGn0} z84l=%9_R+&EJ)e`FeZdO{Rp@8Mz{0_JL!jU;DVIzM+r-udqB0OnFx73NSMEJr7-7-EU6pkJr-O?QYH0a=tX@Oh(mhcbL z#=p8>e(Paqx*m3LfZr0`tu$viFo{!IibfN~riS(gHA*x)n8N~k-2f`hVGtE1%%E>6 z{K8y#hPiBjB0#!4@{*)pl8TZSRriYP_gB1{<`;|-^S?&w(eL;r?fYM2I*E(R;p z28~F&u%MlAqlYci6v}IqqM`toYKp)Tg@uD}WeHjdpuvDYm=Q|}VE}jdC)@~o{-JxC z@+bYW(w0(B6X=C4RV^GA%@~dnVFu^&2Q$N;5soU{AzTgNz|~TILuDL_Mit>fT_Vg4 zy@DV0OYoOJ{MGOm-@>EH(g9Q@jm0a>6eU%fwWLZj*h4Sfq(QIX2RoQ6!VUFw2RAKg z4+uM|(hkdBn8Q8Ig&v9sn{N1{d8&+8*fT!EO!}2+(A^sGh_ui?P57m)NRu9iNV^DE z*a$nO1L;EV&=93Y+qhJy(2G$(>hY;)FjuId+c-Le84O^KzxdG%dW}{}s?>`xL|6xwiX z57-m*x=OFp6-{l8{=02(zpEmmERL*@%vtj9Ay>I8E#5|!MMcL;L+6uJh;m)kq=i3E}pcL z{JID`L)=a=yhgknE&S=`sm8_05q>?m%RP{&^9Uo?B)mo6kcnd+ncrVxbA+n3mUMj? zRD&Me+wPrvdsOcnvTJw6KbE}L?Lfb%{Fc{Ny;2v|dfNk|&%3?n-UXH@0vUyw&r+w`{4y24Xvq}yfgFYvW@dAW?i!TL~hy_4-EfiZtKRfr%uFd`sUja zbAO+4&E5Auc6aY{7Eik1)11DQlfVA7c&QPuq5gjw|IwLacPfiF-{agKz4D#xVckk! zzs=Ke{MwVfUn{@dePOTnRzG@6w~8O8Xv>P8z3YvBEoyJMrKYOQ(EN#8a5|{Y+w!H( zJr)nTVOCbsuvbTaa#uq_XUmnQ+xuL8@7FEvy?)~h7k=l@E!z9RfR}$-F|AYQkt=c* zf4O4Le>xnD@4WK2=(rAn(i+ zqIe}JB{5j-z~V@L@b0n8Ld1f2>A!PAG;#2wFM?4ritTu#N|<(EDikC ze?}iOR2ZYA!au_t>K`+94?X(oKaGBM%(y-WXHTMA z`ZWA(`SiC(*L1q;iXWbSY3CnK+vK^O4jlg|A#K7hTR#1d^S;#M4W^5iCVn+|)rosX zW*%O-^Ok~7(mww4{7Y|N{@GU(7q`2s(!T^O06Egee#b+xMxuRq`8su zGq{N~Ztnh%^(h0_d_3;6qbrw3&;8_=#4eq?-{Jdnsr_72`o(?dKg;GHXO&e(a`Uoj#a&OMHU= z!n;;(zv-s;`u%dE`_{girzW9bOE#+!tBK}8u zS$hB1;ryW}m!3WTZ%#K}D3e!=d)l$Q+ie%zbX$*APc2LR_TF~_GjCnr;fKu|uDNmf z_pLsf(q-i2uP?dzqK-v7wvK*cdyApLBUg`281ntG%nJ_9EhKO4tiKjDF(+QclI84a zYi#^&@|9OzzJ1^=b1!{G&HlO7{rg96+`IXjJ0?8#tbddB#u2VoXN`rH>S6RZ{y2tk zKIwK2zIQKM9<#}8{$k%<<6f@pwPHis9j>J#qsMRT@k`&wXV1+W`^-I)W;Go9Y6^&#>3``HKJCao@)&C*ORp%#*NZ_6pmYC-+WCoPE9Rjq@wd z{+njUxE=ZHe`WToV@+xc=AY$#0^=-c*a1t;N>8X+sQ0Ti%>Aer&SNwupYu+b-v{&F zy7@27>g^BI8~wIvAFfY^QwVqTt3{YIoNAa~0Y77)mH=LW^Pt-`Xz0+Ck&4^t3OdBR zo`@UF>uNc@H#ZwRV#q0GLkFcO;@LeBj7}J&;^9ydy#7EHvO+)A&4O-j#-N*VaoC|uwLJ3r$>>R#6 z#$(D1koVaa7UfK_mt<;_GN)@i!DrOG>6E@|DrVNqDX_3+YH4gm_M8j;?T8 zbEZqU=X)bYfsnYy9oV!JY1X6*UUWSO&#`&t>rY_9KGWw6EX4ajejnfas^Pmh2(JR~ zbtmR}eC{B_z`g495i&5oQAHuUY`nHfw-G-`#g0CJZ3$S@p@5744Uxi@@H{DmG`MCpU4%|pzF^b6k9nnrj z_d#pd#{#B{{XQk4Y7Mg{jfwAkYeR;o4AVVgu&2MKZj3sS125+TJ?ti9%9%zR!?zx8 z*bm+@_qw#g%)D^iXK~Bh{X+@R`D*NPr;KfQ`z^C5-=3>w78Ml~X?^udDYuuF6fo^g z?VHNY@r6qtW=W&18{dA&Y?Z@KzL!l}!Kg>fHM*Zu-AH=-y6)iJ4N6yjNJ&@jg}Mj$ zXmGl+d}z87JuF?h4d9;cqLJy!lR)3m=}PaV*~-7*kH6EdO_F;gw~C1#U@=9VAFY_% z-=Vuz;hwx9{vL@iBMr*m0+_h~%#WOMsHP+j(wRW=dr zE)6scdsg!@45CD238skFO?kDZ@^pzX86rOX9i zMU-#38`2r&O121x@*0t$NVz{l3Zr@7^M%gs%J*sKA~iB?{SlrF$1q{4{OFf;AwN>) zZ?2wRYfic{9B=_1pa{@lmkK)ka_FxI?gQpcOjq^+o1lLg_!PJS-`Q|C4WJ)l0rdQ> z9C&TojTyt|z4rT#jrYI1@r#)|r;PmmobRXKciH%x-k8EJQhGms zahuY*3%3RSeBy&8YhvEJz3%(lpL@=8`_U^WY&*95&ga^_a!;Gy{)8_QAG)G$;(HIS zD|_eaU*{K19=Eb)cgorq`Ydv`8fmJqnb6O3-d%J3udeRd8zH+rhxmd0(?FY}o0YFZ+P)zQe-ZPqOU~C=Pt`>bO2H-QkG;a?j=~54701qsN;Uzw@Q_s}J{GT5$1? z3l8|ceW>cYm}mT*0xw+bjD29`i}#vWjz8zIw!dy0+In8st`oYQ_hZAmeXqFK-0Px; zUmA3C?>(up+wK~(W!v5kyQ;dU=eCWzW80w@a-T{Y_wpV6E}h>0689eu`(G~q`nNYn zUDqYU+iBW_iR?l{QwAwixeV`AiGBlI2vh)*fcEGsuk_AQ7DInEa3?UY3gaB`JoIk? z$AKI0eF*M81n7tOBf{Uhzwig=!VlM#*|w(fl~kuI?*c}AouI!9XbE?n0m^eRz7Y}r z7~k3a!MX6q_+0SEGT@rb7<-!N&oTxzbvKgYVc{?mM-DrUSGg8OgekD6dpxS0$hVd7 z$Q@oU)r{edL7&l%UL{=?@uV~s0bW0zW5N@S^ReRMTc`|!4_RYRF!2P8^h!Od&Y@j`-4*uKsi(>&2eAtD!w!grfX#5n@`sYS`~&K0bW@fGHJvGhpgco74sHn-r61)ygwNXnNbSpypl zYm|V{bNxb}tReC@O9J&iCsy??Z9;BAnmxC?D06aYW^sw}))?bp?Py39({7YFlUiSk z*YMnq8k7niO4b_i^lN#*U5jS~E4>cTo#C+4v+Zb)x#gtrjgZe|Uyin$l|#l3T5rg4 zWC*8op~+YCj91%m)&RTrUd>jIbmsUxe3TLojq>d>yau*NtiH4bDJh|9u0geeNrAWM zG_)e>%qDXr7GjdZJetfR!V}9Va@jMXQTJu&h#T^Lpbv(2T z!3=Z+#8xtgF~Os2X7BR2#0!zt4!n~adg@NHM}+$fJczEhGO!6Ff|gG|DrpWrktzDL z&Z@B0(<9y(#nX38LQwR0qp$zBV`C5W6Zy7l5P9~YCzR{`jJ+ZtMl>?fZNXHsDx|8v z{jERS4gd1iBx4+m>_Z$agQ6F+kI8ikW!cGp&O}@pc+GbzdY$BEXTm%WvFN`gsXMe) zvpTily4vqrUY-47-?i1BcV0Q|@QBR|elcH>v8(reuA}Y$RdQ&^hPo4NuFHKT z;SulG-R>xRZ_Jj(e?(oDwzKEG6(66AOVtKF88{w$?ZlV*KQ!md^KYB+&ZuV={T6d& z*6#QRDnIRb%ak{VJvIL)%kunJlOFSZYrSjM2jjL~@~67g{#=iH93P!?mcXRRUgVzUtX#I~#FAsQl?pIxJpZV_SXD|A_#Z?pb^jTB&S*L$b zeQWrphM(JAU+~(%$Nk4HxV!ww`0bZAQrejN@8f>o|`f}Znj0O$-o+u>zE7d2YB9O}Km`OvS1x)bOM{qs;i2D(B22~=c5 z=?<_QiMVslRa&-a6%!lX+T6y}Hp-$h$8wV&)?%|i3aSAU^ahN2p!_!LK$Jc7EO(Z7 z41BSyS*|UhXSuR0TOtIOWoMuj^pyA4fLPRO52(pNYv@Txr2=gbx*h6lpe^(cs7n9~ zVps}w2ha}s=b$pdafpriTmqZ}{ZgpR0CK9JT0{oUqn;T-CfXwvC{B@q4%9Ov$UsM= zNQl%T1D&X6Mv#HdNS(@zAOl^fXGS!(fi{W?l^N(tJu{NZGZ<|Z6)H2(oqDLuz`B7s z%4XpDf2AuItVmbfx1=lMpjx0__wRIN)t%VOf&C(Ele4*OlopB`Nj+zg&2FEz=DfzJbWb8N@{2FjRP~O~GgN)8u{AeK#PoxinCnIB$ z{Fw^GREMx6SDKtB<6ClhXyyzSem>F(p$G%6q!^zn12I5j6=L2K|E?^08 z2e2791n^h>V7hV@a2WU#;Ez%>?7N!>NjGBx@;vB^_-6R~p)#ExLS_EHhRVGD0@cVD z>!RggdG@I@RHnNxRHktZRF1>^(OoXSIUbimWtZcx2Vf7lwdwwPtptzRyYXGT(C4g% zn#oN@4aZ6Y4kuOw`Zu@D@SeC|vvbP`&J?^q4R&@wyh+Y)dj;Oj)d~ZCC!Y8XeHYZ% zVJSuX9KMGgsIQH5Q(PYe&mT;3-B%{`1(jM6HmCxOME~XZ;d2l#waG{-!^6gV)UWyAdGhvXMm0K_s=D9ifnRx{n zB5%_&a*7K@2naJbqdYTzN={Khz5@P#c4mG_PP$kEAa1#rqvU5!4Y?`FXRMjX7aSv8 z(A`DF$WKvmp^{#ZS6*09RD$IO*APl^Zl+RPVlOHw$rWjulv$LQgIpG4FR;9{NR%(O zlBe2>GRmhRtimGuggkpWi%PJ#i;D|$j4$0TI}^dBW!gnqWlk$7WFTYo)d$bwP0h&_ z;Z7~c7j7~NP~N(J%=qzi0$OoYE4=C~=tig4!>wJsOV0P@4Rutj;xw&96rsk{V%;y? zMVjXnGX&``(tJ$NU*oQ;CJEf&_5@txnz&)L>OnRMQ<%#jPj!Dvkn&CUh`5oRQ_=}D z1ULpeVN48i9+3xOM>+=uF_s0Na)bML_fi{J(hA#xdk5SmrV>?gb6km3zI){ zRE!#JYSC67HI~3=6~Ny;z;=M+?OQsi|5*q1mte3WsJ{v-LH&$qjDG<2*FYtx=K$Om zpnhT;+Au)4Im53DyWURo`hxN-O^lnL{V0wFz81473RN5ee$1> zg#|?Tji8|b>d%L&>H5)7Q+54Js4iXq9n`QiB?Fc}Nq>;T697ko^o0ZSwxmEfr+bw! zcf{CnHO#r|N{WR%4ub~p3Mv<6iID+wfjrElkM~F*q-BWhGr3W|R{qEqQ7f zq#d{;7LR}Ar!wT-Go zd~!FM+#hnz9L-9G_A<|Ba>2EOyj8<+nGC6*EWI)HK$-IFwHyDyZWKRCZ;TzAUz(fC zZG0(5?eHc!V`<^@kF~k9h5XaNKh^jXD(BO(~sP;Ik!EbWIUZVCCEG4rMO}#78R2`7`jZ&6*`JaU=``h0stw=ZI=5P#Q z&k5jflDHe@)Uc!sA5R-BVAh+|`RT*pXcZX~b0tTsNK@%ouC|Q0oBN|wp%L@h{mM}# z(oHy4>`x;_azCAIcUU7s`=zJnwtpnof>q>{kJ-|BRX`$0%m_<_hpkt`-O>ovye`hw==`$|Xz| z*5mR!#rU2%Mr0A0vx#)hG(Pi?hdi5;|L6~YyA}v7%%wVOyrRqkF>1_pa`cqD9mZOl zanjt2c4zEu7-=TQFIOKgC>v3N+{n8r{+^Es@WEe^TaJgxNy9l+$bF?m-84~}4tBay zl7}XbbPP>#yDEn|2BkP%&JoEDM@8ju_b|su9LmAd(nE&RKM4dsaJd<8YynpT*8n$y z4%!NA*YOO1z?X3F7`}79MA!n1k3_zb-W4nDDWBZIq)U$4bTp>6>*M^WT+E? z2Y_|JSHKT|ip63SFh++RYBrFkV=~kdpaO6LOLc64N<0Vb0`}?n80sg0ip6IXFh++R zY8o&B$Oa|>c|a{N4_FFZ25iys9Ml(pJ-~~=J{=!J{RB|4m?g&O7!Q@O1L;7Xjww)y z%XI93O6=1yt_^50APdL_CIWdtDKG`tqGLN$Vz-W0pzZ@c20j7oSj?vbc{*N#N*n|Z z0dML^vEVKbUdfun*`A7Gf7*sE*-KiIF57SLnUlLJYfA@g3PgYfClse8g={%n*Mjv_pz#C0-}K!pbgLt7y*m|#_Om$pei09 z2wVm%1O5R#1Uw3)9aNPJKn16k(11$;MYSl$05XBgf%AKzsDOSzf8Yz?Yv4N_KR_i; z+E6w?`*@5mKsHbeT&m+{sKh-w9)kKXuoc(_>;hf@Ue$33D)FU`<4}J9e$??BRN|zL z=sw`#0kJ@9ps$Wxs6@VwVyLCSR2?gz{u@}QV>?u$>j3bEfkGXnP>Cf;s7v5>;0J&g z)4TzE2mB6@bRP%Ufm;C9JJ)^DDUfXiQh?>a4Zt(N4&W2uJHQH7sRm2{3V}ZXt`)cE zLCwc|7x%#*up5~DprR}WjP;|jc8o)N=>l;5SOk;+l|VHh){|&Mvw;tRPpSG<0i{+| zzP?Ju#G)$4uZ6k}Z38fWC-E9oV)^$HH$uG)P>$oW2p|p^4Wt6uKp`+0P<~Jq4M+rr z0>gpDz$L)Vz$)M+;5FcN;6va$;DnA}ppH9%aCM|X{R3zO#{Q@(lYo4n5U2tc=~w~v z7T`V|ze6qfNmZ5rF95IT*bns}@D=bia02)Vi2GGltbhje0g`nLhB^*N1ttN7z${=1 za3ioo2RQ~O8_6{=K{W~9$36H$)d{SDif*qwq~lSjj{)m|4Zu^tGr$&LJFr{FeyGG- zz+vD6;3MEu9iKz}68IYU2KY|Lai~84KLcPf2wpt-@n{wTDyoV&N5^?kiLN^0q4og= z=tzM&7#N{rJk&HGLq|5$NkE>CBB;ecB~S&-)$uA+V!w`qP>Dl2-h@gV*6|Kh;yoRc zQN)Bp$1bSE9vyq3z6|Wsu^%dN7R@1~j?qwwaXRXt5|`>&3iS%$ z5gn!;NIDR$qZL%*JRKdO5Euo1egiT0%ikqfm&c8aE*=|pxz2>2A&2E z>No_I_)Le=Q$a-N1%L@?0ki~K>u3j+I7deZsKog?x)ZxGw zU@VZWBNr-Bq+>Qz2jBv#fH}Zizz6t&%Ye&)D}k$k6*_K(O5CqwJ5=J_UJ|o=V@?FV z0w!VpD+GeT65x8^CSV1y3b+SY4Lk@u39JX60yY6#fUUp|;5lG7@FMWCj#r@`06qr( z102&4jrlJIXr;pfwH?q+hZQQ3sv`|5F&l6IPQVRR0doK^Py_gN+y(V+V7rdpQ1=0^ z0j~pZ03QLL==dD!7rk~)B^tmt_N-aZU-I#LUavwqfa)rLjZA5&t2mWECd}; z;TIcL*=}zwB2_Xx!CJ3lp=R*o#A&I@dasuz;KXS)ewQ2WGJTXZgg8!Jz`;{U6@JJh zX_YwqRUdE%M=6GmVH(y+6nOLp-J`&StMo|uM|>)FZ`}llFM|%#k z-jbKfQ%lkA`qbecZOWVZV_6ika2=Wx zqGU*45T^}MYTWR{FU{?))#`csj9@wzrfb+Qbj)=JU{{RwI@p#KxD%v_uc;J@;*McZ z>)Su6!7;y|(m!dceF_TI8#eC`Q^tU`Tl0t^dZmdPN6|Y(_@n5qxDFeisDLal4h14b zG(+29rMswSLclZ);u6__Q71Ihjg%5;HPGo02NS_Nb$Og(_mn(Ux*UabdcL`CAC50q zxixI3@@QV)px0AXT?g?%Yy?4KE6@*dAuANg6D2^oF+VRG33!;6#9B|ClSj{dbwMS= zUFoRz)+y;=Z3Idd*0NCZ{k}xIkD`4Zuzy`jq&^G2w0ZTgs$0lRqbd7>UXjQo=fZ%; zixZSa-teuYJ8FYkE=0w`ZB=)r1sj+Sgb~_FMtbYOf)0hqY(qlN?V0a(X)Z^d1CH_Q zn~wfe>!?Eg1?y{Tv8fE}iiO%#A%_^$D(dTm@SBiT;|a!qI{_|{XLgms5yOTtU|bV} zF1rxoY&F3I&4~l973iDXf<|btL>|2hS(J)h2&Zb*C{P=_i|Fk^d6dx=a6tUAit>(f zH#~^?XBkx^u4zV!+&-sYo*BZaS5flh^jBc#PP6A1=Lp_;0gi!jpa?3FZVXeT*vr11 zC64~qF-lY^`0dPlMC6j&&V5d{eRACcb(KbiKr4J8oI?6!JI1DAtsIDuqN0*4mQe$H z3{%}{lSirLd0Z}xXd=*{C@YRc7)5Y&RO_qThFnX}VaG=4 zoWWrQB^`qr1dkyXOkvS*o>0SeeqYeYSB<}(r=IO1!z>qJz;+;9u@0SnFP{AiCVBl; zwGOZ0QGU7W>cm)Lhgt*a1C$EFgNS$)x}O)h^U?+O7W6P=qcOt3m$VS|Chf3gBBB%Z zRRLK{jPIUBqMe|85S*KpiFOYmblDt)@GR?CYpCXo;aK2dA&PNBcgIZ?>8w(Wb?m@K z7_{@%*HmCQK=uRv1`JFXC6SE!8XuaZE@z!2(h-_W&~h1|7u}O(G?g*KjKaK_7o=O) zD2!VWBlV#8k}#Q64lyz=K7>E%#p%TqB({I-xh08NLz?;vLYg!bF}#XzjG3YXiW=4& zwHUesp%9AcgW)%cpJf!00=-+DB^>N``F*E^1EKXG%FkaL4l88DI5T}gOv(|Z;qcO) z0|z`cOOqHijDR@t%Xy#SWJQnx@QcYcF_U8q?fz%;CS|fH%~gT(3%O%B zQF7CA&`Gl}#1x8e*fr$%ASr>b+??W)w1R1rNr8|HXoJ#{5=xq6W>6{x{jDG`t$+^j zi!ZHJ;wc0Tz1&wIy?8oWhtkO0XOi?z50rkb*b|oL1h~h=9TQ61%>*t)cz^9e?p4%9 zP(@5rUxXxM3-8ABREAH)PP$9(cp0=*io*TBSwLU7Ih`%{v%}_cH%p!bm8Yzwoe>8I zaLQ$e)6krz@+bFMI3IEUi2F+1k!@MCmLwLTW&PKyr7`z&Oj!jCAm<G^C*#wIk29xNy5U{Tjdjo%B)mly|~Rg6wnw-bdj$ z_P>#D-VejqRE$s~!)4Eqed2#oqPYl{a{e-8WAE?(F3hH>J#+q>j@EKj6h!Of4n23t z`{AGQ``;{&(`7 zg>H&3}kL!Wt$xV>=NCRks z6e!{cIcKauDJR+|h}9krtMO71P{O=y#OZKWW2wdU5S#^Y?GBDlEli?-bgVdK<@0M* z^;iUgy2HY%8VBA4!7jpMApF9Ng2<7Kh44kO&AA%xPx1tlVw=Q`RVHJu#Dc*cz#T$Z zPI`i)Vr{|LoJxAd8kxuH5P(c)f>w=Sri1v#(glYGMO+M_&JRz>j7Yp(5jX;Yg`{FZ zEg((NO}e6RZ`g1Ziu)U(y2+Ydi_9bG$ZRh9u^30S$vQBi7c@BQT(lH$?F4hdr~^7iy-|=Cfrr`%PU~@*jWUjfHJB4j zw2W4^7hVYSmrbPs{0#jBpsX$ANG4IV2ct%?d_-ud$As93wp3pWt_w@4X&b`A$>YPt zwniQO%{D~7jNW*#sz=BoYwQ-MZ8Ju5bc9<)C`QqMjg_=$ZLzW$C2857I>8>%o0Z=4 z3i5NOhx?~X3py&%#;W}ur(3iylw+|Q7y4lVghiTIPAI1{V^b_ak}Ev{bO^X;!hs6c zP%PrLB@G*bflvroas&Ve4=ZcBLBWBUiv=dcFC77KoU*PO>+NccqDiqCe$mN|{KK&< zZk8RqvjRh%V>~*?U#HV(hguytd|>aOp@Ibpb}D&YJP9j8m2FF;{I8OYL&>Kko5f=E z3U3e`(tv-y2mCCN<4Q=X`oUYkc!4Bf9bFk3VPmDFD9a^O2u7(Psrt|nkzz3t{A-|rwgjf_cmc(KkAR+`@;fB}TyJfvtUHBybYOJw`sEFS$nGiEN$IVZ z1DnGa%j>F)mgR ztDd_bMyPBUn6kkC0&f7@lXVg? zJ)!Pm_0-0ODjBJv8S*3hmXSs9l#Q}sR+$^j#eR9MAa1ypBPh9MK`_Wrho~?|6?mqi zyff!>PbF8787%)?j5U}*!F%QXhb$7OzZT4Ja#T}BjvSsiC^==gR_p=)Lo0D$zNtxS z8{0Ov5d3ZMaU)$9`N8PJjf-wA4ek=OiD29W!QTf17gKnHXU^ONEyE4&y^jj!k!3FmvXT4SJq(=gPb~A49dXo^oZ*kTz+Rg@1c?a~|xxrD>$w9*^G`(Rg$3cC;k4}Iir?+0vO2+Kx1#?%AfkBHl zAc!~cov{~zW|6?X0NmaQ)h)6mZYT_*fYG%PH0Dyc42qi`-Qa(Tq8o@I1Wa--L+~Ko zdKWcPCyN*D7iEL^^&%4SHdJG0jY%=wvUyh4V~h`y>V+Q+!$H4@k;4DR&=wxn(cxUU z4uV{Hw%QVeCCBw}BgY7UE}(ZBgfEgI>s7bHWmZT%NF7;Zh#3V;BO^n|UwuWe4y~LQ zPjKr;bd6>i6|Dwm-L&F@tP)U-nLH>}SX3}2CnGaM>uE2>cTY6=oRVyuxzpgH$excb zS&)V8nCaT2ocxRgEpu97QD$+mh8y&9@(OcvGGUgJpPpNqK^hdiMJ>OeM9a;=kv9Zd zQlK$HJ*XT!pMk*gGK+X`MTtEvCl@qo0&Z6=$!C~26{p#?LY#HWNiWT{7vXx(qQZjW zOhli7U_s?(6(N?)JW#nw8lr`vmN^Aq8t%ivIT6N{UQjr_C}%=;iI$C1ewjtZxGxmx zv8Tx!Tt!yWbL}~K7!2%r_6bZ=kyZe&MZ%e$rm5MP!U&Pr@n2kS!^Gpdkdh*NCLnJ` zB_XdBR}C zl>8=+!L8Hx+CgVg|KOR1Nlr3B7=j0i#o|CYW~U3XEzQ3`!MN=6?9PsO=3qFIvQ9IQ>UnxM!q^$j^w&~z>=7T>$K82nR%$6Kl zNTxu%1BL|us6Z580?a@(z+X#%S|ktBdA!p=?lZK8Y6jW>+;eCP!~hnc1;G6X`ZdC) z8zX$WVH^bgF)jkFwulux!Cfb}t@7L)+}4D@2s4y#UF3J6&H}+c zQ+-W_+)>t@2N}Mu&%x;_d!(BT_k0YYL2!t9#MeHZbtjHZ`!F0D6!Bs{)2ktOvJ|(XhV-RjJDk{j$ z%`2XuWQkjl*$yys3o!&-ECfc482iP3A>yeWCGH^dOHqlQHqh|Aq{oB)j~NDZZIzhD znWjYj0xRnI6I3b+#_4v+JwA>eknO>eh+}J!&fB3d0C+~h*a+%CEWya#BGu3UX$QmUwg>FC(lSp^F5;4`GhyqFd zz{ALv6IMDW3m$pKAX!{eR4`qeUQk-372Bs^$|;5=j$s!k#o9r}fZj$jFjs^_D~YvLwUyY*Jo|V>*`FkE;+pSSaioL%hd4_-N*Ohf_w>&7VMh%uinB6S zR>7W1d?5u56eT`_8qRmeHyCY(J2CMY^|cTiA*UhKl8PPi6#CG=g9`V+0LzbeH)H2aldi6t=?<~n0e{UHk|=X#3@}1YKnU!x+o00PonW{aJ2Dr5 zE)|m%7nI02&5h=LYP+VyflkiLazYD7T^51I4B3x`sK$7GpfJ8uQL{pii+fqey!$%Q zXlCd@Vn9P33v<}BM;bfSU|-bK2&q8ut|{Xs2e(X+14@a%)Q3fr%Z)F}s}*ycwL?xI zEsE2UGG}6}U}O67Eu3DI>TK~0sN&6S!zoHxIK4|3s&gl`=G3Lsmv-ntwd;6!22SbP zt-JMtOF2oIqfIf2mYtiInKMDj%P%OLTvS|AI%Vp#=`-Y8PgT`e0eWkE{@Qt9Qq|9I zSg>$W>ddkWXO+*sh+$^uCS}1Z&ezEUc3o#?VP;6vGtzF2$*ZDuwLQSMl+5waF%SYGC@~Ct-w22 zIPj+^7t_vJX>(~%tFiVKvTNc~DXY)`N>9VC-fO5nGHPjdQCYncVbwD}`4{7lXtCUp zUVs+M9uVFylDh57Sw53f}_B=Wc!xQH#}Dg zp}(*IB4)_gQXzY2Y;{OGh}BROFdU9(4dKo}3+2P{SUG?x6Tn*DAJirk7uySS(9|-- z1s8c9j9x*kIKh%B#8Q}SZo{$^Z88yJj!qArJi`Tp!lx$vRbe$>>k(uq>*+ZnGvH`pntkt8D4J&rd}sV zpoNM-?Ux~gWkv?!A95O?4CoMLU*QpbyUa+i-mheF>RA%w`kZho?+~=rq%WqH@O+%4>0tnv`beC7u zQ!uuv872%-uMFF8CjvzNkf3^Fu#ou>btiHWS%G$^pi|Nj6bJweuEA`KtX{WWl#xO4 z80=__hRh-?voKldUuk;Mq*?QT5Dxf0D5GX!zX3x6=pOVXst}ZnWFV5shleQ^iS-@rK|6ues1y{V;RoWTn6QkzYj#7j zi40wGA;Di@y8$IDg5f$VdUkSCA_ZZVx30g(sU>hCAp4CpJ)z zJu8ydwIGI3ae^Hz*8NB;GQvGg!6SyyB|8lgi|sO0XXw2{#KX)>%7_#Y_K#5g4zPN? zWWFL$j}J353?bkgme)nvX@JrYS3?PBQbrg|Z{|$cf&m1U5uA`WMVUrX8iuW&Xu-Q> zDar?PPN`B2w5k}*4S#y`G~U+{6)$!Lss-y^^MLCp?hO*l0rU?rj=`UE30}9)jayF1 zQxp{kni1@-(>5cFi#pjTI*g?K&PJ1mCF>nZs;m8SIQ7F;X4aqa1}58hNT?B;gFkA1AmnJrzAgR=on8} z`k(SHyc2~yjroX=cjr1pj7EA+pLSBUM#=@vmQ*bcTu8lB$PnoI>KevbO=+zpzY_#m zc3q8^Bt6H}vzI0LEVXdsWEMs0YLPZ4r1_+D9Hk26%{CXJWTb3NAEgXbFvmUIH8pCW zEtph|_{Onc!)#(s-`RZv#;tcRwxKc3gggCSN5^>kyRI#!EsVIK( zO%_U+$=WMNeDZ#vz6jBXoh^y4-_)TU$QyLXp^`0%D+j?p$;X)CD#WH1mTedw3+3%@ zIgsU$It`u3=Ea>B-?jO^VdL1!oQ>M17YbgV^`_chkkiTz5t5SiT=kH|HN&1tf28;8 z-wk|w_M-cq7&PVDPhwMVy7tgMXRoLg-!^l<{ewZyjaSuX-LPZU)D11~yKCQ_FWuC0 z$}^MJM$fvtr0e0mUoEe>`uKHO8UKvh_e}S#uig6Lvb&G}T2LML@Qp2%0e#lL&DdG7 zHqaMZD$cIq8`CM*HXP36){eet(_neFwl@c*#M@_#wkM?z4Za@ziZ!Ul_@G4%QnF9- z12wDyxng4tu!Yh=A?77;#*^F&+>&33Eh_N=yJEhKtCMV4L*wZq87F&IXRUQ93c6hlL&Tg{2uLARmT*d2h6! z%yCPZasM#GIm=J|^o>+y%%n`^THr8{hr8?82bV#OzAjaH0qXyjn}*<^a)UZ<;5Etm zM|d5ZebPRCgiK}~_ybk{+y1|mO|7>Pmeg+7ou*pX-ucGzVEog0vo1?(C) zrw@}vH2De$0|i&&F9wO{tFkxaH9*$C*e*CSlJ`K`mFGo-IjSxfOdC)i{M=sPs&8s>lz?M&`-TS1c4? z!jAK4=o`$0x^fl<{0Th*aYX15wF07!{ZPTuLeS_qO~ld%I|})eNz(7HW`1=y)%A6P z8N;yr5J%S?%1h@(I%?fy>L86EF6P4-^P5Ab)Q9WT;8lVn0lolhmG%bDM^w}(t@(Fh zcxw~%CsuQ(@uSyeNJK&M2~Q0>T~fECVXAm;YF<6K8Kl)@TR0^xM!1!Z8V|UJq>RIS zW9+bED3+{a>EIOqp}RdJQwC31^NZ^}o98vOwdizUEy2SnA(oJXH-k2JuMewaCF;)y zoF>oVFc2#i3QRZZt9e);W5G5Q#II2vqJ*$!bv1X(tIy9=X4#YqB=t)EU9-Byav%WS zp&)AoORJfExV*q6<+|c5WhF>LUWJNs3ayT?su69jS-3g+^LinccQbo7MU)IuZ3wyO zCC}E@%xwu?Pz0L~5`xA{Yv`!W+!!M=NqdS5G`BaL8^v@cdlyLJ+NSM5R5hyclsF^8 zj9BuV+8$5``T|6pFKYU}hY^V07g^7tHZFPAr^FjBJ9dvVmz(a6G`?(P$O-sXi9vnX zX~a=lb&X*2-P1l##?s91lug%p)i~D_*2U=7x2$lTamT3>K6&Q70*fg&VyDx}I3 zVa8nQn{fL4C+E24%zxC!*=R@d>v_8#S1mk8?ZWztw7;R3v?2c*)IPcUZk^h!hwDJd zt>pF_J{byWP#I=89NeWeDn&^dG@N8<#Jq=GfPA5Ja3zKVa$a%@jqy{`ca;c@cawU> zjdF4&U>7UPQmjUd-3;6#(!`xyX`Rkpme}{8{JH!YtDwmIN9x0Q2$zL?IfAbKs$9+# z`svF^uBha_>VJ1#-IPyltf}M)Eh9Xhk`J$^$V=6E20po|#C<9p>W4g#TbXGKUdX31 z>V0?%RrW#2Jqu6o7@mX_6d2ldq_>qa5bzGye8D@GR3z3ly!*glR))Bcy7>gR55i{P zW$EAgHF)Txf+1U0mQ+@Y^&M&Zv$x|~v|-tfSrY-YJ*QX|^+j9t09@}#Ne8}E)Dx=( z`7cSRh8vpo6mJ)e6cQ1U>rEN1yzBMUQ01<{Na2_3`ZBEP!YkIuH$}pn773mNKbn;1vbO)ykJ!u4p+qZSM_O}mBhG<=E!9+*sElO zg~N#`vCz8ptnH*0Tq?@J7;T05;4Y`+Wc0*aE|I4CAp?phA zLwMo0op^d~p=f)&5tu7#_TgaY{G7hFE|OHWEqMfZOxO<$*82V4Bv(MJ3&ck-D7p{j zI`CdJdnvf<;IV?9(!cqM`xdZusT=THET%I2&PX?zK3CYpaKnT|_=B4!CQ~V^9APgR z68c7KtxOOnPVmi?BKuSsFPrLVP6!)o>u|f*>yd39;(=(~ATuIQ6yqMM)@>9lAi+Nt zvh);S;o85+w=4@mpOlb$%lyNS(9?sl^_vrt{xH0g8y)b}VwZ`2BEk(@h|VDFGNt%N zj?eD&iZYLAkJwQcJZ*M5kr7=QLr7p4`97O_Y~*_l=EK?C$zly+s7Mr@oa;()M>0;a zV+$2ybf}Mn(geAJW_BR_F|(ovg+>8as3c@+!{J1%L(k}%vKmIbTs2`egAoKvk~8{f z>OKQWJgf7Fag5>X)F>q;^uon?ENqu>bi%q#2v(fx$awdHb=?ENAc@T~p3N8X^g^&4 z1B;NX6--m<0CLe3l7c%Sg>g0)h8s%wiy4#x7mOqn2IezyQiHY?j(XhWz-kbzN%H+d zcD8zPL5Wu3!KEtrQ5w%!n1wH95F+h#qV@GrKqw_aOGz5a&6h!76gLSEYfQ*dg~Ic@ zu*VI7a)w<4iAAdV6$;J$VMhiVRj_XsUL{YTI59s%EGD9UU?R_=7+L2g>DlZ_d}9O& ziZPAl(xk}PsPW_cPqj4E&cvLlI~7qVS!k+4yjVA_KvgkgVl0dZSeR?rPZB*yXKcV7 z*zV$g(|EW_)=s^)NpE+#q)^Mmt^wYX^!Xrh9B?PrVA;L^^bTjKJnH*Wc&VShuc&(! zc@i{DGw+Na`v4;6XPX;&nmzIz$Nr#*{g|gnmoLCyLsGIoC_V0(aL(e*Nm72YznG5< zQ^r}hGDlentOdevWZToyGcvObW=okkPf+5ZENhvV49X_fhBI_^0c zZ(w0jO zIO+@S;(3l!<$=0fOo8E1E$M#;QJfZaN-MV*YTb!+pt-WoG z?U`QB_EKzHdTs61&DPsC#Fk)-vblP?d+spJ?zvjog!Z^fxd(5bt;U^~_bU%5YjEe~ zgShkZVO(4KDDJy_9QR#5p**Rq$DNlOap&bGWwY`$?!9~#_g-#Qw&CW>9m;dcPUU%J zm+}Jcz}%y}sO(i81AK{I)Pn4s|e{e_UXUgZw7q}nuE8LIyjq4EJMxuN=qCm?xAUm7j1s<}bKN z^*6lc^aoyT`cr8{`pxR$D7$)}GFF|TGX1mFS*lB2s6MJ(tX`z9gS79vQEBQ1Wt=)w z-4nH0aj500TV15SA9abkSS?YR{wQ^qGE$9E_u#F%y?7t)WxNH)^jp+8HC>&cGW~@r z(?3o1sqf%2R;Ir~J))GVOutDzs*F-wsGs3|yD#vj+*i1llj(1#o}*@{*(%dNS!MdC ztA6!2WuD6PJJq+NRw?mFKg<7QV{eiEWTfA!4ng`)HZuKvRHOWDD$73w>Ayf7s&0k- zVpW#^$;MrHeXk|b-@N=!HX7xxiS&0-ZWk|m)|C5bJmDXx2q`!IjpKLVBzlTVF zchxBW8udbvezQ74or3c3tB%&o|6H}FS}Dq(?T6(*73JSg9ix~3d1^1UN}Z@)qT&Wp zQT|5zNm7mS?*W`F9fKKLF*QrRJ%_ z)o}X>qWsx@JnCGLe$^ahHkr-lXmgCYg}J4N#=p( zWOIsnka@6qhBUGdyNQ%*dEgx^IS&8e@-1i%E~kh{=q}ikT3T9g`C?F=kRsZcJWGeoR43Va(*1 zq6qiRQ?v>SyZbN_Pu;rzw%$C$sW)x(N0 z{>b_3?BfsTFOEOP{N+)9QH=42^VbM(M)bhUJ|bhlV77g#h)4@*x=FH3KW%@S|vW9e(@ zXX$SlU`enfT9PaSEyU@5drwiH>4EhUyx%M{C0%QVY$%M8oRPzbAVYqD(rR*n7l zFzAOVszE>O4$%+YG)X`F0{UU9YS0g#V)jnL91w%~_XW(m=Zf)vq1q8OIt+C>8g-eD z8Q^s#SC#E2pxQCd&%ykA5$gB|YImTjV&*0N&;>Qk@qdxp2{k?(bv_1loq-wP2i$Wl z+fPtU1066I^Y3D`fiBuACCX~DuEy-yT8*`?QI=RAR4%i&wjQ^V{#l?}tru7|wTGH& zwOgN3rdXF+r&=$!&bIzwy~4W8>ahM5{ZrSZ{m-#R(m(V6M*FXC(*EaKBk7+8(f(!s zeMGw-l+PMaH>aoHE>>mvU!qF-tw=3a7pVXLpx>fVr;lh>%}9UesD~BOZ;J%|_5^6M zG}Lu>jr8XwsNpVA&nhzg2K__&Ek->Z{Ym;w(x0T?W~j9x`lqvcev~o(kbY~So{s(` z{U+&8(r+`>c_I3zi`q4c)FMx_X49faH zpof0}g}e)t@tdH2_JTG(0;=>m(B7Y5l==?z_A8*X4}#AA5iP+1Dro`Q#|Ic?HVN8& zo6=q*)&3CZ_lK2Lwr4@vBQz)c@5REhplvFNg zqv4>E@<1m|0Hu^9D71J%pY;ZvW;=yK8yKR|I)ai*0BzO@R9YhFv_7EJcxdoRs|n`| zH&`FCw!k^URycRq8fOjL;(TE{+(La0-abB0`N`S=ZyI;PGlaib&&T5=-S8Um3F`$| zLGf0$UP^Dp2L5#)ob2RP!vnAbk%%?#K=8Hs2Hs$0h%!_erVLj`C?oM^^=NU9VI1ys zOU3?I8qQ5-U9AzTzW6M?Ygsf(vG8wXByz#75nF7xEG)QXAfIMRvZYP`t zzQSy9Au6yo=BWwZ(2qTrd01I_`2 zKeVn=-?qMQJz{;?`knQ2>zCHAt@o(!S|8WfFV8FYTBFqU){R!VetE{q^yOs=m5;3JRAc?P+G9K z<7?J^*8fF`n(h?AlrFg3FNF1tZnNpi^c4kHW~{uvOTm*h=xX*JRsN+l96=^l^?GkDmO(bruzH%5eM7$u5rbJ6cRW4yT<;|oWZCAKF_N0ggEWv>Q}y;0c(8hs@w^bIC! z&)uNN`}K76d_r+!)X{qN==C#R4_K#k>A4B75L~J~i7{-Ia$-Zy|6%W2;G(MfcGqwb zL{#!F84ieo${;wXcpZiT1mrRT3SL5ni!cH+BLf0vhGj)}Dl;oBGb=JPD=SMg%zL4t zSza?LGb<}HD{tv}{%h?Gdl0Pm``+(8=lsrD`tYp(f88&8@3q&gy%ziaFPaGv<_cso zSwO?nam@ei7P;mb?53uWjmzU$sY3Qzfis;Ias%W#gu+N+H)gAIAz5vT;=$t5(QfFT}C63b_GtgF>!ZjkBl~vhl?@*5_T3eifDXC8Q7e z&dCrY6DYZ7LH2@sm?YCjK@Bg*v2hCbhF6eZ$Y0~GD4Q(E-zel#$fp!?HRNv<@-oP$ z74llh-znre$Y&JtA;{k=sHbTqlTR3EK696 z3RzhnA&}|YrxqWMHbYsS2_`2GXJ?wtdVTbeAy%uktgJG5N{;_DquqqPlPyUmt8VDf zAwzt}O&Bm>zyg?|LkVOwngtpza0`8UDD*>zlFtFA$TVZLy|Q!&H_=JshfWxWK;!WZ ztlBbsh+58#+BYX5c-n$gKZ9wUMw7D8I&`=;plm^KP^fjnuwlb=dSMLFFmW(ZNy%g? zlBd8-Ge%M&V5l5a5X=dq7*^{r6a|H`(N79EFN!i@T{vWjlyfPw3rL;7mxjO>&JV&@ zW-j>hz5~9tZ}0iogUQdwzD#~T`rt%zdOm7gD|Pjp{Axd-4$-yhHNK+L<`jOTq2=3NHkSx)mYLoqwk9dj}?19J;zU7|4( ziFe6lE-qOt3L^?VMh*syG-$ph7V|D+G2TePyh|L$5;Pw(39~a=%*oIU%y`VY48%xf zhzmU*(QHhwk6?j;GuW_UGuhz5x3WOZZA>%xb~Y??0nTfAo*9O%Vul5)Sc2vSmN0&` zIwN^C%LrM`rfFVe)5gEZ7A$xP-_gB{GhBd>mzkemEi)v)!VDp=F#W7GY}~k4S&(Ke zzF&Qfr6jLon#|W(NalJrRPzQKp7|!zX1>J&0yeN=Q{HAq-*;GW=DRE?2s441@3G`r z@3RRLHnGsK%~;R#0n>(UVLIK1EK6U<0`yy1rv4+gP`{1&>9?~X`W;Lky^{qQcCoDJ z-7Fw_56g`HnE6G2!m{G(SwP%gmKnE?`Ni#Lny3c0FzEoxN=RjC2fRrY`x zs?^MxDtqRws??xNl|5*dDlI5mRT`9|nzFD!RkqNqnxdJbD$^9IrVO#D%7$1~>6xXf z^2{>Tw9I*`%FJ@rG`|Yf^ngm${DAqYi2>(T`2oMHlCmzSELj&-(LsSuc|n7nrfG&d zRcf?OQ9)ilxj{GiOw_1-@-@Cbv3`Sm3j6|mVuJ#G3W5gvObQ6`DGUhpNer0aQyif4 zF$Sdh*aD{bOkKFZXWqiwebTe4e9E)%<{NOQPkF#yKIwjoeaijr_Q~*j(5J%hA)o1) zH9qq*AN48qd(x+T$TFYGAy4^4FWl^tx9|g>X<6rdDzkp`nYQqPPvydkK5_BGRpvQb zRYLqORl=Ozs-ii2R7vq4tCHq?qO#1XS4B<#RTVY=oGN$zZ>r$nfofmhacZ4!tlC!> zr%tigVz;zjzNv|7-?T(O-?%uFZ`{-z->GqVzHu1^z8P_Ie9h*$zUFy$-+AUTUvou; zZ-sfjZ)k|wKQwfXf9UW+|4?m_e`r{-f9ME{f9Oc7f9NQie`xqz|IpDT{=-A;{-MFu z{=;79yN2iN%Lno6|#DR!-OYMIuSGf!*N zS7|N!McQKhUD`tZV(p~JyS0gt_h=_Z-mA66+^@C7JfJPke^^_X|A;nrevNi^@l#q$ z@zdJk;^o?$;uYG$;%Bu+(<@q=eZAIVe?wbre@kndxbu&)sT;M4Q{U6t z(%;uw(l=>~(?8G_rf<J&xt8%F`962Txzl=Jbc7xP3RcxaTcx)Ou+hBiv~Y@r{i~jb#xhh z7dKepZ#elIE&CgeeVFhqLL2_H4*s-3YJ6i|TF~sVIo&Xabi-)xypp#3jZnrn%pe_7 zf}APxHqyb5zQmMm&Qa!l6x_o{NqHYO5ua}qQUuL;33mt|n};8^%a!3rE8R6Cu=7$` zNg;kBSNaJJAy3T}Ig%F$=fpVp2^}*$BqUVMNLqo(?2wO8UU|)Nj0(a=Z$X!4r{H%@qXyea z>6576OieY!#et)u4VpwlD#JS5(BUIO)PV;4WL<&<8lvY=G?E*Nt7tXhf4Dl3x*5LT zfH%pXRvjp{jPMhN4O*J3S@JVN9oXDDa=4M|z~&a0b!hA6nv->?R_p}DziP2l&&Kb~ z#xU(D&LfAT1c|2k*cj6^82a$g(Oe%sVz}T@RQ4(OgoHL+zy>t(u`%#FFhrYsm;L78TQvI6331E*NTng221+K@+}net?RmzO(Z{!n&3b5i8fc^~ zknLk2Bbc2TCmOM}PKyJoj2nDkjGDuG4*tch(ue$=wO9>D;j!%@x&^jhsI&*G5fGnS zV}DD0zKt~|{JV5?8?2DR#iz#CzWx}`D9@wiQ z7@wYtEZ|EDZ1l_5m+_CQ6-zgRJ+Qk=Y2FyhDmAyFIQWnnI}uTQP}1tjTx~^^qgO)gz(|Bh?{cBS)!6#*8v}cqC&-LfR%r`kqmdmPjBpWO!I} z0^u=gq&#|*I!dn|K0>VxL7Zx&sSXcUM}?|K4_A)}Q->nu7`|0`huF2D zT7y~}J!+&nEOJzs+A!QOLLD<)AC2g>`fznv%!p|9$f%eR>XG`A>@x=iDrIlqS;h{%%`U( zveHd>_XfloAKGUp6!T~0m`4-WoC)(~w0B$UubDHr&smsb}H{3E%xVx~oA z*mnRs#qzx$=v$-NCMrNBHVBId9wx-!CSn z$gZb_t3o68=YuW=<07u2Z>b?;;nP$T_6JhxusloXRM3*YmbJhJTC0ggd{`4qTWUmC zuq$g1vwqKp&tVpa%SbKp+SR z0m6WAU>pzuL;4k6sQ3<0Ed7pK%ebM4+sLn zfGD5^p_8$(gLB4ARElAcn=iw0REh$~dcc z0>fMjUB`@#hr$<_aVySJ^4yFCX7=F_MPZ)wDWfd#-IcwPX@5V#EmG{7)mATR*|#v$+^*cSkqK-Rq3e9RGmuvzo4xiQ8c!cMgl zz_RF5I_qpwu`FrvIkrPG=kU$%bA_H3TwC&meIB(BN-WmHTT7tL64foLfyN*Xu5g!k zyTUC|4u*|Tth7HHMVduzh?_O9#|Qe{YsR~7kb?Kb09WwWv@jA!xn32gy?!^&&zugwaiytUNvb+yz|(+>XRx^7jc zExxmIX$Jvxclk4j`55KXmnu|t*$u0_X`ewwz9b*;(_FT8lW6wyx0#_bURP%~h}YqI zrLz$5g)*HfgUeRF->Cik)QGl4&auui(dTB+snh6mhp6T+L+Dz{XX19mI4D_m$X zeV~JzzNExdi2#zRm>6JPp_4A)c@XP#-^XQB8j6AJ;91DSV2-JoDVhXfc9(>Oy9my35ABfj&rPekLH@Exbk?7i*d9X^+P9bwO5C^NS{tjly|nK z5wK%Um8sEqIgr`6>(Q@TG?w>}dd#@%YEJ$_Rn7ZHA!?E8+QOgu2zaVf z8jWG`Yif=rb624&x3h>JekzS=SRVA8C&{MY-+T4L)ibyKIymPR?w58gZb zv5P&&7Db6LUPo*4mIOs+A67;CJ>7dyK=O0YM>svepoS!E-d8Aa&_C@Ii8zm5AQ!Z*x4z1`oIeZ z=T43PXxlM2nYZiF>J{+;{{@*(7+rBuU(~k?bEgAS)TsMS{@c!ah+H>_E znx>t2_0^fXJfmEH&+oPQK+5ayULO3=BUwvmK!o9v=lz>{uYUOTsjoaYvBStWC*9gO z>qM2unyXC_M<1?jsPZlxfVYF(@Py$@cctI;S!Dbvliw>x$9s+Ypyao2A1&=Ut*-M+ zx123HI>hVK(}>OMZl4*ZWQ%#oZGHNEZFCtL_QkND1B^LO&E4}-ukYg@4h(khZMDRC zTl!LMM+_en@tTXV#OLB?2bK)pw0FkrrNLuY9l!lj-rCfY<?GSgI|gIN9J^)T zs&AuH?(n7pY^qrDr&C?&%@49$o7R`@JpM|L_l|!3Wl7h(gh_$ry&C^0{^(J|DeYsIW-!q}Z`zz1v-v8Z{ zx=UZZ8KwGV{X(_BePGFfMHe@oTIbr+Eh2mD{N!6#@6+nPPA)F)>U&N*_1mf4w+?*r z@Q;Cue_Z-$`Pew0b(;PY)#0x#J+SZ6{m1v7OuDD8V9N8in%}%{TsQx@(YJeHMxZNKoCr&rUgb2k-j z8yNY(#XTz??PPy_!8O;rHHP)(vZ0!w#py43{nEdIMatO8p?+?u^vfh5`neUE{z4*K}yL@uk13S-58+tP1E1? zs;{oV1r?Zk_4X~pT=q;_|I_bZ9ZP!t5&Q9urz^Dt>j_)YSUANcsY7iOdka~_}kT_oL` znb#NRQ#wZ9`c>qHb-`h8y|#V*gdbkHFbAUrxh!n zU|VBnjK6o8o2>j~(** z)n!XbZXeIBBk#TZYDJI1uTQ=*`pF*$_6!-C(5Z{_^JB+d4SfGfb$N#2*^R4DjkkYv zE@r{9?9xZN`u07(?wuEc-|S&r^U$lKe~1iQ`s6ELeyO_p>2C+CoGMq+?*gi4mK%S4 z?ZmF2*T#pBO5AC0$S?k(L+vw@FPwAUzUr%#m172Y9e%}rchvhwyX|-GbFb~0F(*>a zq`diU(&gT6!(K|<^3~y2J(7RQe(<)l@9p!An0<)d)${q&W#81F8$4|BBFg@$-sQQM zfB$su_<1Y8AJ*gc*$L;h!M|?&?cvT{yPKCJ*lW8E%8KZ&8s||xx87It;;3Kt9J_x* z=%z@0!o|;vTp!rIQRVvef}fsD*>2jFz2?ZVdr$tL-DoOkTJpiu_1))uw)G(m?=W87 z&y1YE^Vz|@&U@(Me%t@ji{&p2*s}W08LR4tm3WP~BWlH#jom-0O&XrC=QZuKo8P~> zcHVH`gy7+OyHD8g=vCXuqcb<%{bY~Gzr5>XE_@Mw`ry58=H3UKys!TH_Jnn>zPHW# zvwOcS;vpKb=A(#3N6Rk+jX(U=+-1YQ`>bQmw>~vzs!;?>kR!!aZaBar0ut*=52YP(_;nnU} zuDN!t%*p?2qOFv7WdlcpN)Q`ba&drSJHQu z)*sroG18KAG`)Vt+atce+P%m$dAs-V_n&xsMbfX&8^61FV(uL|ZbP3Nc5;OurN_MP z`yg}N)KTT%gun2~_~d5~E(&_~&()>7E^d4ByMA-RPt97p{DI%xE}gCZZ0*+R6ZX}= zez#56f5oT8nlqk#ZtrbfV$S?3=;7Sh(a%3|Q)Ab#jB&j;Ecqig;Dhu*3xbb5P`0wB zYHas+j%#XS_ZKg8IpzP9k*7(Up*v&z=E}mxQ>RHBIJKxD%yVNk(uFtU!UDvS=URzj)oAxuen;My0 zw{y&`yQ|8*dmoj1PmRjGmqFFB*EChf-ZoXoKGiCZJ}Xroecw}gcz>$$xcO&Qr<*%E zb?P_JsnacV|Df5|Gk9Wo;YDWUJt`Iv*_Bl-U54l9@2>3Qr?GQ6zPsilY~_sTO#a?L zr?bq&$dBG3N@1gMcn+B6eQ9hg^s~60zV)R&PUyXY_Rpk|ERA9-Fv_I)b~3Z@PY$E> zfm0SR>Zb2n#fX-6>ZcQ9#O|%7u+QW1(ry>zm&VbvP%;|ti%~7bP46|Wwf__8w&avz z_iZO-oOHzSvlxp@!U0L}N3ZSlCY7X5ViuEyrNTlZaXSQJ9L+Qs+xzjsIWEx-4EG){ z=G=jGaPo4&x;9rbBSP@T028PVH)goGvr!=-=|&7{)oOSAW$sx8Sul)M*eYP$-Jr!P zHQJCLc1Hj4&S62V(O1OcJs{A6qw9nfN#gSn!~=j8c38~k=+iE@%}P~#a@kJrGWjn7`6vEJyV3~KVA4Ce-sCqaqv%O0GM>2 zA+1dS*{N}Q0rWT`P~M2Cp85dve%BeGM+oJa`W%&k>Wi3k#B|>wH>zvdjpC)S#9aZ3 z7Xw(Xy9rFMUIfzn0_1muB`y=c()8=O-_HO3$DbE2Ub=kcudCOX%E{TqwS${`M~_aPox61Px~W_D9zA>Y?$g(s zpHidt^&8+na8N+t;2}eUG{M7K_9huKcHH<0x`_6VsS&5twC{e~g4-9~@xQzL|GU%w zZ`Z%rB4%Q2T>PX2#{+~!{kQM_e?=*Lk45F>kbnFjT1jC_xCQYdY)%0f;mtIbMff}r#X+x<6b}xtrab|% zpLQ{h+ky^p(jnRuudJf@o9+5U{7wfXCJxKZ9ahQX$%P40C&H-7QVGLiW5*O1j}iNw zr}AHa==VhW#SLYLOc_bX-&`&iKtsRvmEbKL`Qh*J#NyNxlk^*+2v57c@?@oW?1)2X zM11t?V2dsdvj_A`T#H6dM-C;YN4{Eg@raZ18iUxf!HJNme)Rk|E+JDc;&~ngQyuFe z=Yvxbj@}oN@pehSK_{W?^T1Ki=YU20^gF8fg;bp>mqMDS7&| ze=r%5HvK|LDav`EnH5^yO!F&perVTRA&Yz|eaLxq)Zrv79;Z>_MDQ@wS1$fmO6ikC z|L9j{a;JalW)1lgK4bA^_88=ee&eOzPsz}4j2e8GP48mz`@B5Y0S=VsJ22f5D9?G2 zp5{F$Jn7~6kG!EFAtBJM$938S1bv756R;leI)im@z%t+v(Bpet_dpHM2!#KDdl%3E zoB}QY?mxm0@OSG4srOKA%fExms|LlI!`ABq|GjG!CpL z`Y45_KGG7pz3`NlJVT~IzG?RZvF1TuZ%Z?&<^MQ86qeRG(7m2kgliC6CC?e%ac0AX zW{KsM363o*`ikSaTKPJ1%vmmCryfoFNM_@2MH~71C-I2bMG2|TTz_@6)FAalnrWt0 z#qye9<*c}@qnyg~jP18M#bZN_SmBpe8Ea5u%2hVX_7_*W+%9rDj(zd^^~hdGTwjt$ z+b-&DX1hKqHIC2Ck)D<_;fs+}z9JH9iD{fhdga<>g^sUXR>;k3mle9^waYZ8)g6E* zJwG)Y9~|M}5NJdi&_`h@S`6Rt7-`eonB<=h;1OYrRvVqG)1}2tnyVF&VXstvOfJnI zB0h00c^Vea8*y5V*`BAjQ?W?_4=_|V_#;Jgx{A2*=~0PT*rnKrndS>=o|3}eXdO1q zgOZ;FL!!ynT%%%slWkL>FZ?Qmn&JJ}dh0~%lqKy#o&fq}sJpD>>P8DnOk4=@KIG#IrQ;Wi(4a1GXw zCBa^Zey+h@Eh)|VG>i}NodI0PgaDxfXkPj`c9?zI6-{qP8w`b8s{=AqAksSTUJ zGthidR3a1A&BybMeOr+ngKc2Cq$|L8fUCeN zbb!TRCvXke8N3|q0;WFc3a*9R0lWe12Cf6UgX_T^!Sv48348>yC-@Y&Gq?%d1$+hE z73_Wi{Q=wqd=r@Ze>X7o|L$Nl^gX~q;GW=ca4&EaxDVI}?hBp?_68S#Zw8lw`+=*# zw}2l6`+%2$`-4}5)!_ADU+`wIA9y!-0QeBtAKVBY2tErQ1ik(87vrFhV;6C7Jus=8k90HyQ9tVyC$AaU*Y2ZoVEN}w22%H42 z04IYNgN@)Ca0+-icq+ISoDSXqo(|p)&I2C;7lKcLi@@i>i@@wM`WJ2>o?sWck)WON zLn-S6xg*#g>;Vn|dxFP-y}+^H?%*_V4{#Q^7q|%Q4Xyy+0jp{tug>G0^kPomYxFfg^*aPejrjyk}z~10-;IZH|a3MGgj0rDh1G|71 zfZf2=;Ev!WU=Q$0uqSve*c-eNJQlnitilcN5ZDFW2zCRX1$P8r0DFL4{z7=L7uXxz z4?Gqe23Fz57zOSKHiA9CGr^wV0 z=vUy5;PYS)FuMwOuqRmMk9>eTf&;-G;4pFrN056U@Lwax(>A??@ zJ_Oe%>A|Z>4_;6DFkGLc2k$05_z>yCQC}p3&yqY2^+ht+ba4`6P}- zK8X{MPhumkQ?SbdT&G}fZ~<7%U@(k_^HFg8o(K&Y`8gcR-@Zw2=X!ddB}3y+GBgSm zY>`;_qjyg-biOJXT4^kpW_7T3L5h#Y`($VgK!%?AWGqs=v^toKO_FVrfBGJj42^%u z(0d;lyEHbiV_!BQ(+msR0zL!_fAp?F#*C7Xp}7w-_U7`4d=>E-8v5N=$h3x@%si=l z1$a*(V?vFQ$&>O^Eak(58X!|Bg`+j+WN05bGPKr!OrhkzP>RovwK_`60!UANgz`-BQ$Nwb zMt-QTke%YE{z7SyAL=tyUdli98x2ZM@z_x#q^Gh_|Ir`^xU68OuxUIj^&?7`!ct$N zeBu&BN)+c5sSc@(k$epS^)HH(>Vf7xs6Huv>Sr3HO5+#mYheaQzoNcQc8Z_+ zJJnn3vQYn*+b)~uU!+UdgPaGtCS*HZ7cF+t$0(n4eaQM^-WGEHsU3ygt_Vxl4b>Zk z&Ea{Th?W%BkzBXpT9QLkdFYy=R-Oi*^0h^=Q0p>&#uAk>lGh^jW4e|^z0=Xx;ClKL>-I!Nu-pIVm!~}D?m;oinpmqBayefoQAj;P#U7$MH&Wv&5QDhe9(L; z^%_0?I<}EWPd?>O^qWMU7g28*AETW_yhg4U@h0*X5cSq}ymS@GXWEN+(|Fs8ctxKT z@ka47DdTc%1NzQN?j>@aB%|k2zNqZ+lAX#pmFL&apN{fVLk=@dDvM|nx)$a7qI(jB zAs5lwau{(XigY4*JIHlG^&-j@&+{+*(23o0yn5aa!cPLf_T{qEJEn+7^km^@5`Xs; zevH!fN@X&j&E&N7iuRbo`<@6Jsqk-9=qF2UDcYaPDbh{lcNAfdmD+{;BuUQ~vKx8+ zTgG!#GODK%&h#!!bx7~0v`ll0lxxvcZk3+1iuen2HpW)4c-7=5B?my8QcKg4W?)NA#feI z5&S8b=Bzq`&q6)`z5xCL?9wrwuO;*Xe+;=F_-$|?cq=#zd`ZVH!dnd3bT`=E!v59?;(h_6Mhe8T7+J zA&}_}XBqqt1doH953Ygi4~~UA8=MAy7)*15L%~^)i@`wyf^P%Y!e0P5 z0Mdes-JqeM&s9 zv-v$q*mHS3340#DMugqWpQpk;hv!My3wi$*_99+Z*aS?j@E9+@RLW`a5 z4Px$s_Ee%PjK)Uvj!oa{lbuF`w2PE%&*u3MdNJE2+bK`NF7hYrW}ddN&*5z#>=s2l zHr@|}Ud+@8JN^19$0_=d(9h>>FUD=uLgYu(BlTHf&*9HM*{;;L_^02XW&dIgk?>D{ zWj&plDBBBon+ZR~{J9|P7G9^qE@qfyJJq{vZ%Nn2`-ITb8=~x|Orf7A)f>HI(vD-~ zhu+UAlsvCt=4BUiLt@5I%rA&pGVzWgX6A%lw3lqB@qntr@Ak#Kjm3Nq{gvn8#7wQ2 zYY=TF?DUuX&~+&Lp*Y3$Am(pG9>g4;nCTUBc(h-LJfA0Ke&zRfTE9U?mPPMxk?AaS zGGhKu%odCJKQUu0=6FQ9VtzpMKVcX76n6Sc?@QD+Vs=@~;n9j6@xDp-K6##+-akne zp@cil1t{G~R=QKoh}4CDs+|^@<|Ap<3c1PslJ2H7$3$93z49I`{M*sb+VU^-j{a#5 zQmzNG%VnqeIa;+sX^FWl@uZ=-L@KSQN3n`aw$ps6m~|KPjiSB9+$sH~uyk(_?IGq% zX{9600a7__ypM{RBJo#QW~E+P1~ErE5A}^_J+4)`pNaQhx)$lmlz-nKnR;-GOyPvz z0-nCG(~28eZ|B#V(3kT2xR^H;=i{aX}uKY{}Vs7e=i}b)=7s&mQNSWbY z1;riBT=AT-d(@}8jJLY=5B;V8co6}U;-j#_$a=vo<#E)@Qiws=WNx}9g}Xz=EltgQ zao>|Wd)zl7V*H}Pxg8&OubZ-X#GI-<1M3csSbD-~&K2FCPxV>&+^fAJM!Zpe;@tdm zAG+&%*dLhunR2YW z!`tWLpz3BL=crksu$=O!bzY#m`OnFka97%e@8mlx(jU;dhFredu`ql*KJ-4h&bCB% z%U6$jR$Lhk_X!UNAA4HoZL>Uk;N}tIS>3chkG!^0_dJ&TOdfJG+;evRdFch6?)OE% zW{-4-`!CacdcUkYp0;1-{Xs9d?{cb{uts;!rwzN)4`Ro_h;16}@Yi(xqmEuUJ|E#% zer~%daJ_Dx@%6w5euJF#>)HOx-_RYJlIo*tME>gX{<^v6Te>ImA9ShudKBDuR0TY~ zLHFB>*?ZS+$L@et-)Gug-_bpH`||_#Z|jZt;vXt6d{;N$va;J5=Y9x(Dyh@w8+CUk zB-MY*P@V{XzYW^=btBUA!)(8fMEIA}-g#n^ZdcMg|I99f$74aT)1V(V>puA;_|Cxx zejLYE7H!=SxkdMV;zPf6{T4eBX3crS^`Q@SFPFc&>cxk#Q=xj?j%SMNbkUc-`uU+n z!>K;kPUyTVqT|}D<5=VQ zej$H;q|@hkci#1T$arR~>}p%GO_y8ZU8(yX*W=0!silLr>%t~&-qCR%)yLIK{vU7G zO)fYcX;24`XCWQCm1XbHX?m}D>+F{Z&;IcCKDR^H-84aS^DjEcHN93nv{Tpc)Y2#ox^)B7sw216lHFj|{_Ph4PhF!WH+D8k5R4CudeY02TcI%!SaPK`^cdEy; zrm3D?>UZnDT)F@G4d0-?8ovAG%V~Rb-!@*G@1*ueehyCT|NS1F+W%Zp7cKfng!2Qd zEg$Rdm@)LdwLfYRK4r(d>=T`RO>TnuJkqmWTyVPj6J5#53cmr@P+t+j?|;*wUbomEHG<~<&Z2VR}_++Ll%=SN=Wp2wRG=)UaYIUqPA zU_6VBOztx1pzdP-)q!3Mdm_G@UdqlssO#3(GuV55xAE+Vp>FQ7gSyI5&#pC(#x9vv zo#t)*?4a&L_pVz`{xAmpVbjZRd48%Je&n6LPd$d~xvl%V;`zXD43nkjg~Ux~j`2I2 z%#Bq-mbtFKkY!%Em-%vJ9TS!Q;ZkY&D*BxIQ@dQ0IYwtaI@lt<#mH-#+ok%dB* zIW|eiGH<*^$TF`)|D=8*bM-bM%WPXJWSKL}LY8@>PRKH^>?UNH+4l`RewmMaBxISx zpAxdnUUnhNY>N}J%yol=Eb}rZWSJW`;C=ujbCp%dGOLFOS?0P^`?!CZvz`;O%xt=l zWv;nd$TEj~zL$rWx$a3J%WRw`WSJYig)DQ{H}yQc%uTC>EVHdx$TG8GLYBGe&rf)G znOU8XiF=?PB5sQ3b9PZ+Z^&U_nllUs_Xk&a$MZSYDzGo)YH$~DEZjSTjbIvi)<93A znPp&Ca0c`=x3>~b_y&CzZK)12aVa9?menC7q#f%||@fN5^_ z6qx2@&w~BH=fMNO7r-<&z5*TyW;e(4-xl1#7%tIt0>f~LbE!$lCRj*MJRD5JDjHIe zIwy~RLdRwoS^4J1vvK|d`7O5Q(v&zW$`wP%SvkUCRzaoBic#2Xcp&%LC6aq(2%A+I z3Ru`I4CZJaYL+FhqSQ1Sd+3r+*)-kZI5uQeOR!I9&qI!*(a=6|Gbses{dOmmx1R^Q z;!eMspsxAf|Jt7(8ThRS>Cr1lzi%DWm(hy%SIWG9H#L{ zS7!X#mHqmgD@*v(m7NAIeeT9?IZU+*gA3%+PB#{eZFfuki+SH8_gFXyT?KATZmb_J zpkRC=T59sA>2tJ)8>3gp;E<4<+4=bWLY56FY5o}oJ^Ar(r6XmaqmIA5207^Bc-W9u zI#PzU($Py@ICON42lI5}_x|tde7K0n3)mEs{$(x>Ev=K^LhAUG&>HEk=>Q$Tzn~-RRd(6 zQ;B@K_{K9z%L^O?kfD1M899&Crz0f)@;y-LW`|o_>Gg1nVUqwdvb!?Br2nbgjom|g z+}Qm1k8bS#>W&+`&)s=r_xfGJ{gjk1W%}VCW8W@-j9lNX>o0zfqq{OZg|qIx zvAcHPjorH+yRrLS$8YRDTyk%#e0Md*uzLYAa`{^4f5sW%E{EUPs{O2IZydhE4>xvS z_|uKuLw~uk`v=%dO_~4J?NfB|#_k1|ZtTAIZ^HL!6~6WLpNqZVl=*92zf1c$y0;Er zJ>bUf_r%=TT|LRsz4i5XbAqFL>-@P&`_sw&qjmk>G{rIe_E!BPGS|_)b@^sxJG!?{ z|Ni0|yZ>l)bZ;I1%nC>M*7=WE-M+i?YZF<207bgi^YBFe+@fbwRDk32iZ?L+D4$!( zbSe){WDf!~mXOWzVAwJ4tXAlnpo@iWxkAT=d$5_%Wejc!yAZlQU%BD@-WJ^!=sYnN zD;?URI|5zUH*Rc!LRT@y1AEN4F`FX3;0O;Eg814pG}f5|Q~(bG%Yj;8JFpKp30wud zk@s-QKQJAb11tdU2gtk+-VK}p)=0Xm;2y&~*bra>5D!cTih#vH4X_ee2W$a8295w{ z04zLXT>v!@0>lH;f!RO>uozeZtOnizb^~7nKLZ^?5e^6gCICht3n&7rfCqu)z*^va zU?*@0_!{^bAmfd?4F=+YT)+b$bEm!lvNx(Q@2;dDc;B=%1s|Vf(YJsJ|JwOSN z2_yj#Krr9~cmS95C^PUmupQV4tOb?=)j$Q14I}^)fMB2>;0atp+cp7T1BZa!z)GMR zumKrBEHDo62Hb)3IU^Rs#I;$32LpaU4}bwpqfuVq5U?G16Icx_10Dnx02UwV}hCLIt9gaLkl7m!V52LC()Wd;rcJAnev*=H zc@_wIwv437WqBo){4BX>Y%RcW@^xM*?Q)QWZ3rNHtD@)Pn5a}UX0OzYA6JJh8T6Li zmW>X$+uhhH!d6MvNfbi@KOd31Jfc!~#gU*mp02Xx3?8h0b;5=aIIOOfLzF3}i2cyE zTXMOD=E$;n*>DO_DHTr7avWqTP6276_-SR_M@fs!i>zlAq=~ka6?6AmlH~mu{0KH?D6pa~4b~!S32Mhll4Echtse81C^^+GZ7CtuUuVAS1P&}!=nTn; zQ3(^}I769%7lH4zQEJ9{Wl@+xiIB7ubDSmDjNK}b!Zb;niftZpBXQ~~<}FK9qJR{t zOtOnDDzH-12{}r|v6qFirj9gem}iQvD8-3iMyuIUsvWLpH#w&u1sqyil*dw?Q&D9( zrE-|*kV_*Ad7-hZElCuEBtPLyLUI|hhgHR*ETTS&DJ^U)Va~}jm~3{o*)i?t3ZA;2 z&7~NzB?fIPfjg7z3maCHm~-rUdWEXtf!t2tAeKbmOLS3>f z=ULcCs_2TGqO#mPLy_4=g=G^drN}~_YzEm41*Vd8b8cyYp55vor?aUJGSygmD@{6^ zENieoB#*`(gR^|8US1*>qq!olh_NS~(@IPhdl7mqrDxAW`_9HvlUZ_TQx0Z;jq)*M z>6q(winBmvN1mJWe#|MsY{5Pu*!cu4htvAz=gEa;X;S;iiW#E)csa|-E;&Twq-b-V zomFt1$lW5cQ-kX106^SNoTu0@T_k!uX1Z5UE=9*cxz0KzVt=?aD>i3gyHUS9B<~7) z6jD0t=!}g?DvOX~#-4JXVnHKOj-?JZF-pF`#hE>r9 zYs=jWGpCS64~xUOcqU5@%403clfu8LN-fAMDvIU@ALHhk8XKLEAi33I_q^F6McSGL zb@!DM?lopQWtpEo28~_nt->4Ke%?hWoWEzSl=52bOnbFR0^@Bd#YrnZyjUb+v=~je zrtzCUi?-xS_CDxA^H3&gN#6C@ZPd;pEN^YJCEd3jG(S0N#62DP)RG=O5%&)s*_jr9 zT>gM$?6f0p5KEoKraMMc2_7lbkEy@wSs;%Edkd9DqGJ^DEqJar*NMo8w8IV3{FFtN zn98Gb^HJlyk#|dOi(3N46jhWThusVDK&FyOk|MiP4m5j5VhW?Vu(*?s(Y65xI@zsT-II*D3GF zxKTgoBn9OA`8?1p@>w7gytI!zBO)1S)t9BdZow!Z$;#36H=uNp#YNV zJoPuB#43CAc2tq*>H(BmbA2$m9-1}3A|##DDd(;~<-=h|sK%E3N_7%V8eANOrB<69 z?qSj)H|Upal2ZbXQ8!?7O?pr#b14p|S?bv!YE_>1mio%4kQf1ETXC3Rf~k^@QLb&d zPfH#dzEW#d*SP1r;bhFqD{P7DO{EO?dnj(nS?n|QHgBDl5U)7i8xY3GOJ^-ZrQkZt z5f=wL)qHjEI|lrfwz^}av+*dMTpztvF*w(-KoW<-g=zpBJK>ktNIKzExTIOrtaz%f zcA}vRJz#h(;EO3fY-~}mLA+nf9-{bfDI+PT&3=ULTSY#l*u-91=r=#G=we%GWpfCu zY*yAiZP$fsW;~@Nw}+&A);Z0px96D6c-TDclxWXS$El8pH?gd!)NCt~9wu0!OJS*^ zF+z-Snq)3262ewWN8E~}kp+ImQR*yZSn+A#9~F zC}nq53^tP!RipI1P0j@%0rCea#R#v2Zf0)~%6=@^x!Ojzltl6d_{)WcJO41Yy zj!ea}|1e3$VWf~kBuN}JzD>#}WdZrI;l6m6g7<-Ur|v$63p2+P_>eM z;7s>zN#bu{MJ^cM=JE<+9v#y0`pD}-jL>Nx!03_^T8goR=K^QV7oiY&xhZ*e6o7Sc zML&$5$NT7hSLv3KiZaSK3_Qt1J8@4a`EiOz+$W;=YnQbI@0OdD`GT+2Dsf9|xr+~? zltg<_X-kU5#)AyM%%Lapp2EtxJ;q#OFQoz@o@%a1!eCb@VqEwOxiPPVM}Z4~cSzjK z-lu%Y+xp@5W@kM~gDaaJc#;F_b-gYwm-SU><^HMSJ)U23bb~|>|Au^tlJf`EDMwkK zI|tiD7gJUGQdn_u;aOUO7ZYAd7<-9cn3z`#g?uf3r08LKwg)wdF2OtBXS_w|RXNva zwo!dNgAumHf(VNanLZ*z#trVF^a2Q=f$pR($@-WJl)tG!uJ@BxFuVPm;v@ z{}$z4CAtEo8;U&VU><}|ji8xkxTKh{O=)xM;Zz_|OSz&#unRcJ)N$x^Yi4VyG1Ac` zgIMh?S`mz=)lu9{alzT~5}VFu;+?(asH<)+c#*f2VUUehYJS6xc1H8r#FInM?V`Z_ zDFqDwq+L^yrn`8e%KNB7^E9q)#cs0DtaVOk*$Wl&3XE7WsYN-DESo(Wk4ij=#C6H@ zNY}t6h0LckSS-&+N}kAxnLjU@3&n1xUO_QRRZ7pCO2_*!uZ{a1?!@Wr9`sPOmpRu! z&0)fe=OOtHfh&q;U-ay=R+@CCrFu|Yq zDa9_Lq}E2Pe1=cDD5+%_c6JbV9V&7<^N?F%y4Av;!p+a6cwTF%n1(@Hi5%og0}BgA^d;y@2`RO>c2gG zdpY=bwa>p25Ba5h-U#HUwLe*w-CE0S#V7kwx;g(%+Opr){^Yon>C1KsBfGb@%kll6 zz{))S)BLoqhql7GNOk&8{3`3Lt+@V)uB~#&I%OVY-9L%*Mt<6ghsrEN4om(z0=33i z<_`n`VZb;b3P=Fb05W5Lk6^?8h+w1lMzA#Se93+%xbuS%Y%Ta_;630tK>i3Hz)tRD znu0`JWDmO#!FF8~elCM4zDbva+&Vsz+lntXBUbcd6y$WUo~;Pgvm;@8{ML%S=_cq| z)fhc~gV(b!A^$X5&!Qk-0=t5PfN)?rbY0@QBV; zms-^rLg%V&B^Vu*P8g%6G6ZGgy9Yc6<@zM1Uv&K?U2f+%?8}04jR21|2Dar@1G@|a zt~IdjKxwUk)q}&<864_w4CEO=>-sCuioLXYBaKf_PvrX@;m4|G(;11=8Y40us1rF~ z?m0BtNbGsA5wNCe+gm&`(*Ps1#?I;bc{iQYX?U~l) zuVNk^)K^lzjN^4UPcleBS;ODYSpErbxa0gCGAB zx%s(tdHfHg^nZDGP&x6F2-s>21hej}ywg{zvX{OTmgip-yy&^c zD`bmUSjD*({;<)OzV7d$t3nka@!S8IUJu{q1kEw#i}mgBVfAuTmbh0d#P9zNMStr*d`Eq z8b3vV(al%}nBGlnV2ZCA+yT52OsmN^f@y5k0H*hqGhiA!Venr?-y!z_)A%a{3{n^u z?3#q{ouRjYv%pqx1$ZvF<~sjQd~e%Y==Z?A?mBlmB^>2!N8i+jp3b9jr$Ray6+fq@ zPdoa+cJ$%x=wsW_XSAa)Xh&bsj=s7b{jzrSwe9FPwxi$Oj{ZnH`ZMk5FSMhlvw<9q zRR8Vh1KZKl**NrVCHil(sdy3VsHrncCaV_f#;Nm4X7@U*7nTKZ#p_sGtO#Gb9j`7#jImWNvfi>}p{49g~zCu=S$9j5&oUs#Y!WHt7 zx3Df;A=hnll+VDwi=sSDd$4Z%y85J5dbAdfF*TrK!b278ZJR3GQQ%TlB?y0EWp#CR zU~<5#CB0qZ6_XSG(%Yu;mD8=dx|)1;y>_j-8q6SbuDG|H^z8hGU7W8>iWMBS34U-h z+q7xD2uc=m>a_9R3J`Ojl)$;`_6>sTqXb{O#+m%EsypyU2lR)X06Pcjs0#g{3Ql#v z71&$jD*RAAseuSUt|#30+A&okLevRt0RF-9uhbKQaYOaRjU;z1hpA%j6;(pPWvD86 zCGvWu$J@0(C7FM;46k>{GOOUxxm}PVHfv$iXM-{jZXoRj2?rnp)HR5>0CUnmWhz$YQ zH3-)rT)V>kGpOsI%{7TjMWLq(mrRA+ZOFf@1plef^Nk8caJOqpy<77YSanBp_acui zSDxFoDiMBQR5qf19@a=Few zZ!28#t;@@+p$T_yW$mCMc!QO9Qr;7I#nA;`UT*8OzLkIOh(F>Qm!%e#F8&q;+2{@- z-Bgf2g&TKp7yV0_vraq!-F28lN0MUVg;5rPRSnNVauH!p)9K zUQykuBOxYA_PPpRT!))gn+->IwKf{AzV2V|0G@5dQ;)k|+xoWCg|@By(9JO_>bi1C zjiRh&s!92hb*N=>ph_bnKLtofMsy@NRB^G*KXB5~*aW7(#7KwBbRQ(+tmG<5u9LV? zV%%c6e=v{l-_5vv^LVdFjF)^a^SpJ%y`A3r@p8sxj8m@BjUQte&TwjB{bX8`XkT`zxl!ENh_aZLB!RS0-8V;eB%4}Zow*(RpSvN2T%;12vR z_TB@!s_^%z~vR;=X>ll;$zJuZW6K)U8I<60ovA0i!$C%sShexa~68(wE zh#qfW2xft0`bYGNOJC0z6Z~D^R=8FpMPj1ITxsDKZbae^-hMB5K4!%2)8X;u=$*$* zkIfAKelF`cF6)@~Z1nN8T3N^J$Nz(4)=0)=9a-Yx`xxrzF%tZwW%(8Uw{+HW`yYS! zf7B1+h{E&zdw+?Yvf>8gy>%Zs}aj9bMVTTkkg3cmC?Tf zMk6P$%=!z{c)W7+cXM!iw(xM0c<$wQMd3}&Ir$u7ZF(T40J3UN& zVoBiwoX?*D&JX^K+-z7q_%m{|w!AHoMD3z%hd4i0-p2o=MeJ?s1Dqe5o+mxP`LU7M zEm53r7YK2Fp5P{MkkG@GWZStpWzF*(SYBiy9Mn6 zuL;H}ncwRCX5$|Q|3COii=L3d;s5yMKmO-`2mjnb8Js8h`A=~^_s30#KLMtUwRyv! z@NFT^m$wB2dI#sn+QB%p?D&>AP`$I#1t?^LaYYwjc)%E}Nh1&yM1J zIe0pHy0JVj%fZuka6V6N+jbYukLAzwyKugp&LfcmcW^#q$T$^fbQjLIdHr2DKQ{XJ z9h@&StObHZHVfwmqa04le-r1QVJv3yn~)ZXkIjh0C1get3uH!w(wXeakx5A8_jV=_ zK9iJ`|4-oe9-MzOjb#&wM0h+VBQBDVkvEc%#_>6R5Agpt`Mp+>Ux)wy|3A)W75}|H z0;A6Y4sx(6{uSqAD8b|Zg7f9TUikS3&X3wv@c7u^+;`v^FVA}YJvjf)%m0D@@4Wop z$Nzr$y^sI>^6>F&oPXEL!^g8>-d!&bAJ4-1cfUM({wU7B`{g{2NryQ9o|i`ogzzk& z_U?IkmL~$|-}~}xc$SAnoi#GSX!4VV^Z)ts=##-BzxU-?kN*cRkDfieH2%pxN8l4V zO`gQ8C(`ab5uP0~F_lN|!uipc^TFYi{*6GhFDB}4?;z0V%R}=B&XYwL#R}1v{{!da zn1YMJ7u|#N32@tZ93OKp&JWJP4+eHG&W}FMXF??1jq~wJa2H$#kKcv!!=PXXCK(V< ze-k~i!ByXRJn->%;qY)NghbW7IREd*@4@p7L-ce1f%Bt&Iy59~>CX8Bha0>;Yf|ov zau#9ocSuVMUiSA-2=f0g;QU)4BYt9Uj*T9#`4J*GzO{6iBgAHsuVwOg2KmE9ra6tj zIr;&9<>&?V1ddMd1&ADtpy0GPW246qeermR#DZgh%7UYxbsWp_8h;0QH(4Ty zI`wltH#i2rVcy6C5w0Wr8xI#^2y&JHt_MH2gA)YDS@M=nMJFdW=Z$?$xc z!ME^*_ctay?#hh*{Xy38hs@~Xx3iA{h~f3O1KC4x41jfTjLkZ}_V4rBAfHO&H<{o6 zGR_}Q(A&cs8iDf{fb#`#ekaaxG7>5CDg)Dn!Cw@Kl;ipM%IxFJtrg=kf}j7h`5yxo zoHP9QU;n{Zgb$9r7v~Gfk&CI|{EG!{kIPJqeKsR8c2Zhmt(oBbSHbxX-=&xuNsPM~ zDRBM5wS*7A`Q?{`^GDwT<(G=MJAX~McIIM%OPvOl{#qDR>{8;Oq)TywB43l?@f))% zGAK6Y-{Sl;7|2Y1{~zWNS>qKw{L6r4k5}--*#82~k4Xzs`Iu`YMIp{l$mH%w1`Duw z0-Rr(zXP1_^L%g|n-)C=v%=q@z=h+pfoa6Y6_^w(k@y@1X7ct(d`yAYGJ|8}VDNU% zHz0UB$MkSgV{ac1Rve4*+bqk=T`%eG+IRAhAVc;LfgnsS+mOl)<;Jr9M;U1iycn{9cbq~&GC$+n9ex7@9J}xl) z$%yPt3;rjLZ)dF#$sZFbBFOASk1$4V@+h|ie^04EE0UzUqAj! zj@0Jgp5eLh*G+@}Ifha};2R5Kh(2k2BS0-)F_0a2x`(d{{)xUWp4Zjkbw3li()jk+ z;F}>waK>^t^4@$STkzeE!N1X;=zFGTz32R$_XOV?7hGpKzHhcW*BxA4@JRH1ITOcm zO*zo_$D@xJ5c!GsjmtV?aLB&@=tGr5`uFcUuEli^K#SCyJFLn7r}DDDpH1e@{(e6A zmbKvfHhYJUMNpOhXJeK9xv_lPW}!&s7;4!6IQOI6X)pr8y*1*T!5IJN=gc1eNnCN| z|HAk`p7pw5OwzcQa(qhkn<&vJCN2)=68cspI zK79As{BsWfYu7%9-H86a_9o$Xa0jQ3yEBjMYZ#O9FY_1|tMICp%za1xeU$HTZpQbC z2jAh=k>g|7S(ESzcf?)5Psi|g@GrZVWF7N_&qjM~g2(Uv=?0$@!})@5*$cjnuP5&c zzU8tzXAZ1mATO>SzD6La6ZqaRD zt~vOw$85Wda3{_9{)5WlCkCr{0Iv+JEV#OE9G?i+Yfs)0TvhPBslmz&EHV3g16zjD2tw(K80G&%Vas-O-V__kC44cPhWxdxD?S*p z;O7Y*31*^m=wFf)Atkwc(Dlx?9BxXB=5?wVDak|FUacED zObzJnri|=9B*pjg<#x(csghiKVDf;0Lz6qRzaQ;VLHAU*fytc*j2zmFwlH7wHtIElpha?Xf*uQ)BhYm>|*dt%=;U!za8sHNYu>y~^npOf>!z@Uf-I#ZSL3r77N=YHAzcUe9u(}D;MGVT(0%BLfrI-p zyuo%q3^#3S(fuL%C3o*XjLi%O4tA>D{hsWz1lu1mSR?P8Hu}KO8d)O~eLS3saC(F7 zUy_4uHwF&izz&52`wdCfl6$k?9{WZxZ^>#fF+IBv4W_Pj)8ql{vogGUmGJYz(}e%< z^*nt;d&oXT?*ZXtX5RpNeq_y2_IvKkRrUZU-#sq>IDK>s8)wg8)hsKj8olr;*%uxi z-|SCF&Ne?cMa!D5SJsm1HFW48 zt6H_JRaN!Qs;bJWs@AM={c4gRsMWG2DEl;bJ|(d9LA`4PH{lH(JghtSp8aRmM>*A^ zcl3`7$+G9HC-1slo(SF&UHAMEc)b7l`A&va>4)P#5 zRUR*YDA!j8DrdObD@v?dkZUcjeW9JvD(Zsn>5cU#^{M&_{T+RWzF$9~=Q7G0RSm~z zXtXgV8_SHhjBUop#xWzG`G_f*)y*bmdvm(E%3N#iG!K|3&C6yEtF6`18fA^MW?HXW zYph?aD^?D>pk3OoW_$KW_I~>Z+jXWps@ulh=N@uTyT7=9y0%x-YwC6M`g?DA8@%_u z!`>OMn4j!d^G!)O~09c#=q!Cst4GJ9gv09LLYIUs7o!RA<}rMk^H#)f;>;I ziXHS;UR7=@xzzk>c~wv?wT(JQO;@+5*VSjW1=<1aC+(^h!3wrx17Dhg^|Ae}UCPm& z>P~;>Y3CK^4d)%_bLW_I%E{{%bj!GP-9~OZcfPya-Q@0ZKXFgEzq>iT2fT+p)w8?? zUTa3H7vr_WTj{;){p4Nn9`-BwhTp;O>ObYr^%wdp{LlSk{^elIng)A9aTM|iC4^)_ z5Nx5k&{S9~qzf6s0pWAuTj82;OUNS@7AuG~#3tBMUvZF_Ce9TXiL1n8Vy1Xi{8Nlb z#ia6*CpD7VN*$%Xtd=RPmPOJ!X|wd9^c8F6S1CcxD;Jjq?5>vF2CM5Q&yZh~-<02$ z*UJaxQ}TKFhJ0Htpj1$*D~~D7l&;DEWr&ihEL2`o-chzHJC#qAL&|yOhLWh}Qy)|{ zR@4(}E48PZrp{0osjC>%J?atlxcZ}dh0%RLE2~MGuGQ5#X{p+C+BEHDZJD-O+p6u< zzS4fw{?Kyjx%J}u!+IsXwq9Rvt&h+r>#Oy2JwyM5HF-t9j+GZOiec%#@u<<<=wpmD zW*BpgH;t{vUgM1MixFquXI3}QTL$C@+EW#$I+6Z5$Fn;B!3uqs-rWm$Es zHdY7hevY-&+G`!RezUGwe_5sMhit`eV7IXc+RxZ?>^JRq?e|y*$Lv$~kM>PF#wqPo zb9|?<^MupY8R<-RUUU{<5u2QC&OYaebKJS?{NdzuliUYf-F2{w)^2;Zw>t)#UE;2E zx4NIZ-?$gtD{fw|pjX*V zv5{L+Ir$O%Qd_yB++SWGzap>1J`TxW$lu9-$`PfgQd+6PntB57+C>?syr3*r-d5Ht zpDQPnZ&#a>t3A}=>SXmrb%*+idPvPwFR546Kh;uLhN3msx@iNo zq1xNpdTqCMPP?u>pqJHa=}+h*_2c?!{TJ3_VWX@eG5d{;CyXx4{fovDV~=r^dCz4Q zHwDu-TbkX>!DgB{(VWY?ziWPM{%GDXOIZ(Dveg)m*UK7ijkcy)E3CJycdhrVZ>`H# z#Lj6KvLCTcyRO~HZf6g%N7|F@SM4>-{s;C!`-pwj{?pFm7>?_7a)vuEJByw7osXQO z&Nt2v&Uq)!&E*zxA9gFb)k1I3)*a*yb4R&z-G%N7cfI?bd(=JY{^Z7biC$r^j91Qk z#H-`A^tySyy;N_3_X?ijZSNy*zjwm>F7yyZ{E~iU{Ap9ali$}L?vL}I^Jn|>{k8rk zf4Bd&|GodS52%YwXWrw40)i-LLT#a!&|g?1tQB?%Cxx$t3qmRJA+egMh>gT2#LnU~ z;`8F0;tFx2ctHG|`16N&Q_L+rAQhKn$&l(0RXa2L6Q!v{)i z7nW1x3UW2sl6|?6+(YgwkCbQ1bL2PVwel``5BBi2d_|5?5|sQ(Nu`WZO{u3eR-ROP zD1EVt8Ojo6rIJ%kQY)#|R979NPRBp2RNq$5sAtszS|Kf2dswT9XK0CMn4-O*rE9yi zJ=&MVRMv`oFS&x8s~rP8DY=t9_X>$W3)8yA{2v%-3Nr$uH-R@gr$bP0d81 zFXKFowN*sgF1;o%k;^&toJ{vOH@8#6__cISis%#d>3Tjq z>m+lAS>74o4t9rQz0bJg-RIn??hHO-9-s26`-Z#BUFE**t|QWI#j4*Y-hJ#Ia6fau zB)Ay_VD^}-Gja1-YD-GZ@l-MH`SZr&GzPb3%Q#&yk*`hR?0eWleg7-kGtFBee50Z zKJ&h0<(&4u@xEvE{OVoyu6j4TTV4)7-p}pl_wU1#7WYf}Da=(RG8M_!g7HX?L?*C) zB-V~4ctTB~j?h4OOn5?QDYO+j2wj98LLXs(FjyEaj1rz93w=(QD$EdO3-g49!mH$R z?~%>y5k4j^eoDfb6-!Q5_3BL-Lg{%19TZ}N@+9T!{?;~Cp7fXpLVmYyrSXGon zO|(Q$tSQ#PGe5@qY$>)CJBVGxZ^ZA#pTu9q%f#^;;w>?U6ffnL@=Nzgg;}Ykq!g)~ zR7t8TNs=a6MEIJl+y>HP(i2ikVtofZcn`AU0n%V;xHL+7hTP{lR`d*Mwlq&#D7{L) zyo`+bZ8CvP(pKp`>3wMr8R!A&GwDm|gmhZ^M*3d*3D197x+>kk|L2h7<=k?9`96F= zak-RyS-whMa7)gi#4EX3?e{5#mEuY%B}FNxR8p!clA2z@V zI5VBKM9Ht*AKVyky0_Zj#>7`~sKyovKv5Dp7PrC;UC%2IW^dPciylryWD zj#;1Vw-*`PU(Vz14p+jKKJX%$5$XZ#=}b=bmRLY4Bt0ZmkaWojBjM;U3YL|7$zRE~ zT2Fr-Zkq4(-PWFF&$4egm0j6&-OlbzcehvFf86iw zpTt)OMeqfD&MaZ2@FCW6N;oV0jD=i>U`r717u$$Sh{MlITksee(r#%lSmuy)L>eN` zmmgJDE3MRN>Z^Kl<0WGVzU&F>S^E|Hd;4emqFvOH?&Ke*h((v2+r*-BZe`bYpLF}M zc3*PWvQ|HIPq8*Hxh=eQ-ej*GdFRZ){sWc}`@c^pO3v^o7TrPIEpCx#5TAcle^V!E zYqZ1KH`*mFMlVPtmO&l0^d@>2eVRT?U!`x>kLcg(7xV%~DWjU9;EC%REsXBQP-ZFc zWgCqTK_ExLPkGF8MCK;u81oHtxw+Z=kbLX}BY4q_Soy67t!kD>Y;I=_B^KdbwoX6i zDdO{JXA0x8(%I~6cRq1W5TXABpA~Z-aV@t#Iawcfq&v}FgeTkK?gz8|;@))g;Grs$ zjWzJvc>TOF-t%~!*U82Lgp-L!iSd*C(!SvPeiLHy81k?;{Vo1S{_!9ZhmJMyB@trr zgF*^f*rP%-JjgIS#vagkiADABXJ+1wmtPBLFM-!VU6wtfXK79$QhR#U4d8PrT`nYGnAV0~l#4jK;T zsI*pqs>F!6&#|1Z@*{Di-8v}JqMn=ieJNT!P-h=4p#U(!A?K;e+F}q z91~GOdoCxqLMuG?cs%u6WJ6z&3CH4pMX@0sc9i%cIOzeYvQ!HcIuvBIMf!jhS6bE> z_nz`I@@#pTyn|8yPQEE8DPlN`TdJT!QortW9y)_{Btwhcue$X7= zj-jisw!@OPsHfEXxQp_7M}3_hV?1umHdHc@oUFB?j_M2s`|fdW;$sT9#mRRC{7fD9 zanNs1KKW@p&G&9`a7%7H3@5D~6PduFjW9u&B5Wr*zAAnv20pefs62-}S1F*DRCO@p zMYS=bmX5EftG}slfz8Niv^07cqmA*#bUf|~SeU)WS4JiCP4lK%!8&P)jMy0aHG8F9 z-tnAI-Ro|G_k(Bpo&CZ7Sbwv>-9H6B;=`N9M7D597Rp10j}%@OmI|xDMqdfdK+ZkI zr^H#}Lh%Rjn%JJ)_jzfuyjO0Zi~_|RQzB|tcVoEm zG&yIwaf@87nAr&2(a(I|TxxDLce7f~nzgNlR%>ervwYa9YCi^s_{C0iOS=u+r^p{S z;d#!wiCzIRw))<0UV@+3f5@+nT`%$v1=rmvI(9XM1;VGoQQ;Ti0We%mGWjlIzc7dY zQtT%^MU3t(KPMlMSA(={kar1fl(t>_MJvEcpQJC-FYB?!9Alzc6TCYT)N|E(!(Pss zEa41t#yQiR*PKHjm|5;p*4;VxFIV*%c_Z*{zXjJYD2BQk3Tq)vcttn_o~!`k8?Ah- zJf;4jj?}&-FF$Vh<`8qXxff39sCnK}iG`!=3HC<&u>F(WgwJ@+d7aPr1*<6tI;w-O zE$0m(tNYe#=no}tj)`pGGae=LY9;g(j)Piii;cyX#dTsb>$4v$-xO(<^fGzNJFLQFt)FJ=&GqrjQAzM@J)?tB%zTK9zoWT}*!aC!7M|j!y}_x6JqN=5fJYlI3>Tjk zZ;MG}foalG>09Y%X1}S@N6F19>Wn8ktp224Q)R6MR%c8k43x{dhP?#ap|mdfowIWoFtc!%gLhb$aUo>>K!eqZGQe%+$cvit&sjVC^ zZQtuZ>jCDiXXdsFTPc+joBOaW5S1I+9qm5$FnglC z&|ZxIk4EhnFCpfd5MIha`h|sqCSjb{M0AE!bU&UBl zjES`7kR-NcT>Gf+6Z=Z&&GdG9Go!unpedSl%vNSQGv3MryS&EQZ5^?GfMscA_s93_ zw)feFGmJCGyCuj}MfYp>b$=O*R-kv;&Ut4FlVK_riWNaQwZSvPz%jGPjNg$r5RYRN zU2zms?W*=7^LZCfbW?4qrxIUZhZESP@6*45DJ*MDHC{H>fTj>HK0EMiFLDY3w7k%OMw^;kEQ&us%5+l_J?7zrfZ(m?+3c@+d#NO7<9A_!Hz!EFuC$aKRwadhcVtNI=soqH+k1yH?Lpca0@;IL8 z5vvCLV>3Q`khK{8@lz|2yfz<s4&|Y}SRBs}la;~=#j9UPP`$<2NoFj6U z&q;w9_Jzj6lR|f45@>X}aE=&p4Q@Rjd|!Z}0`_~XI91GG-3E5lfLg;67@gem^RPBs z;oP#W(d=pJCN5R@X9{>$HfGWK=XXqluA31bdmQ%Y3%@fWaiqEu3x{2qn*M-qF2D+{0Q2Zs^{wVqTLxJp ztSPY0@$ijhi9XfI3_7qbM%k0?1+2_1_8wN|Wjk1V+sL)Pa85cuIltqv6TmNJ$+&c~ z<>qcjw+9$z0<6sIjP_2q8=T2_?*$l=bT7j@=$(WIx#8s_a#f(x(9mz~_kcy5;?MJ! zfLcDGP7>XF>V^;#j%zjei25MWZd4P3k$p{ECcca1oCtZs98yuKG>n5QHG^a5FQtN7 z=E4wekzT;Bz5_xD>IJ{BI`b(dlt-|uW=dz}DP;nDa8N6FUpc6pQhp($%BPl4A5p>6 zYFl-HI$nK*=+IhgtB=wb>p!t>a~cJVhm0!ZRlAKZjjxTOW?9oV8xX?}kzbrP&xb62 zBL1zQUD(D}n&t?5+2X-0W#NBqv#Z(5oI>sBd3&}U;J+QPRJ^WJ4m3_^sf9;`CTeqa zkU9+Z`8#!#Hdc$J;;@Q3T0OI|+1~DAr(@G+oU`OBg?<>L_)J`m*{44DUhpOGf#M8mrx>mDb9EOPguk;rO2=pI!tu z-KQN28HR{{AO12~Z$upF3R)Vgzo;+7qgOOy&D>^5YM2%rPE%N%H1e63$m%wm`$C)e z%Zy`ua3#qVL0us~d|Qsl8cb^p=WR+P*d%Y0 zYbbk_?ab79^^$&#GsPLXjQqy^Mp2^z6=lQl$WNPq$DTAg!S3`i1{!0HiN;LoZm)%P z=5@wqW4p17I?R{GN#lFtJdDp@VMQjtc|TdvBV+`IS&LQtgxQ)I>|*u=E2Y6@O*J33 zDp_OTbAGh1+s&K~ZdZ2_>|l4lPndH>*HT2zDGyPDTF)&bsI(mOQpuTepe+k>;aQCZrIa7%SB)v9wzsY;e%?p z_1q@#-0!&4sAzu<*HbKbFZ$779Y=(*V8s+_^>d^*iD6WjiS@A|W{IUn8{kSys39~b z5)XjwnJmnO;X6URiWQ4ecN-#>l_uaPuSnOWB67*Fic%GYf+bg%>rhE~BCPj!g>~pF z4Ff2KCxyo1NO2s<_YX0jR2_aeoecU9 zskq#SsJU7GL$0oDR4S<*)z8%;+PC`qFs?VrpgO?brL*qpTV1T#us`Rl2hl(*B%k}v zw%{iQlieP5O1J}H|Kq$oT*WMJK79RVn1(My4lT)l5FAy__o!$#p{CgjtUk?unV1x< zYaIo(pM{f%4Y5a@kcWDvE7TKO!^01Rg&!+S1Hr#8yhDZaeJWhP3w6a7jjL zs?CQ_EyXHZYJ6icQSXZl}0|;=U^38a5Zq`CihYAk01x0 z6{y0|bP5~EDlULidxOhlqRMy>SWqcEAvY%X>aPq|uA#tatUh4OF_%+e{nS2+il!-f zc0VeoLqSJl+%&SA$?kNt9&_9UFoQF~YFlJ+Y*;^QCbgz|_MP+sYJ^W&9mR-0x>^fP zuD3b_RPdhqmHGo%I98jkkA`pCW0tX=qrzX33V(I`MQZk!oE~`ci`3$;!Tv_PIBK(b zy(F)YR}^2K?3MK@zy}BQv@g7`y?Vi%rN>6f5|95~{id_nKdh|Jhus~`ikcz)As<$c zsrj{fFo8d7h2XU|z-yJJYTeW5Zwx`X5O~pP#tU%eub^O9N%e9gnw?$7M|kqjVPel1 z-x)s}myAE~rmKH2dO%1ayc}g>|Ye%y?^}(mWG*6?OnS$q^3tRg-nD#AmJ(cfI zsCgd6AD$%_JrCD@1s>!k_%zN+wDMX>V4$K_Nh{eZONLt65{RG%>~3|?WId}9EN^oV zN;@hX-Kd%OBXb>UrCMXGG;0EN$m!NBve*T1^^2_~Vf}m+s+eAGBqQoKtBY-!{ZwfZ znwzC^XHXL3cPKX03r{Dr%n*a@CsEEv-ce0%A~%=2q05of8fqQ&A+3T|&Ul1cLR;d? zYNIxhe-o>yqu&j`9~&vksUkv7yh3~74Kktk;jSVVW5fLJDb<2$xTrm@f1n@LFX>m& z3{*8_;|<31lCjY2hu``HmMXW~oGAP{vlcn=8H~zCwPtR9q>(C9b8K|E{=0tSu)S<&54i5r>Grftn@IvQ%>v zrx~m29cM$RPT``e#|088u5Bi4(Frw4D@9f&pvtL7vn2LCSg_gh*n z6mbSxvpyhf-q0tM>pTb{H zw_mX5+39eKAJ_-%&tb+dfz6Ad22-6{&f`uOXP`3_G&&DnJh;;g=Ti{rY3El*c76O) z=diX=E3Aw6@&dtL*mj`-p^i9;!+Ci>tlGvsMcZ{jKl^wi9`NrP$_I^ zr?_b21$I}Os8pLOac^?*8E}B>v-B3lnA1vPU9zBp7HXk>m?u7f2~sO2t<-PLRA^Yukk z-0q`d(+0M148CI_Ya<w}exjOhxhVe7!|+x4&Y@2QDhCIik*?t4F8_9dz`Ywe+ol?m$Z?5;(3@HP2712HQu z=wU{mnwJcvrf`!L-c76mMm|La-9h1Un2Ox5p|(ZSEh?uqsRK38A49>?65ZxZywgej z0az9R&1Q2l>mkM@;{s#w7uC`tW-=91$#l({W()G=0p@UOr{m1UWM3bfD*m~()!FLL zikW4-Mh$!$JmW#@3+n<*(*1U+kXbNo-(JP4`39aZw^P6=Lyfc-3YM8Dm*SaqlPJ5| zeV1|l45sEj#`Y2FZG*gNRNFrG4tbZnn_eQQrLx}`?O8v#`XBr&(Y#@CTtE+lON){H zt`Rc1`+D5{TJcj9W#7QXT*mhA19NIH27$)49~#W3rI%oz&JeS&!r&J{sVmDh@ z_wVWr^|qQ zuMcr}65Qf@__mMDBj^*pr(${qBo;v>FdBu?VX9W&S{_VnOS?U4fw}hS5cS+bTT}>d zR>rABHQ&agHG+q2?{o)=4tK_aMd!0xUx$rd?F7ukcB&~kKrbz+xuv>O(B!OzV{70w z0pTV1`QX=l6oZYZQBQzjUK8dmabcbRWnm}!1DzUZsyG1+;0hRmPsQ@gQA4Sf)Qd`J z8oYX(k_WV33zUBpPOJ#3Z*}d)g_F6D_POA7R zXe%2yt*9AIb!IrT@#qVkSE)HJ1K+$2bH2&h3MPLaUhHGmwPNB$m;>{oF5 zRp*9ti_wX9bG!N7``~YigY;5RL{xQKz`A!uFEtB>av9ap!|=CfQ7c^ltK{~Ip-!si znXG`uD3QA1XLeJ^EC_<~;9UnZmTRMVdj@d;eQt`NqZSHuxrbpV^AXhrJWqY_-qU1& zo2l>L7E{Q~C35rOSpFXA82Qex()}oC0-g7x#T^JS{|*4_8@DbB6TN~H8G6(^f)RpGqe}Am$X;4CDf`nYTKw+??d_ggLXwr)CCX_$%2|UL(jeDpRvEP+>M?eRMSX8H0^fV-{?{YSbP#iTDNa zVC7g9W6VI^@i6RXJFB-fm}Hp?g!A_o+BqO8`i(;+0D^<52F@01Lf@- z*u+lzOT5<~b}T%6Ik@qutb{j1RmUE(ne$FQqI(C{z|-#YAcWPZ(srOyKS|B|cQX1M zCHTMc9Xf%hp`|BUxzSgnrYQW+I_J5;v)seexNUx1f> ziyUCD|0OD(Z~PyloZO+fh=K3Rf!4O5P?(ys65{`QXvW%M375$BVnF_-VC1Hfr!5z+ zi_cNLSPj>I5n-03kuazMK?LvKRG`?=SHV2i5h;DkUzE?j7n;MJn+6JCD z0%H&dJ6anKrYT(IJo4!e(LD`P1XV7;1elg6H2x`{j_`z69sIiJaoN_-%-6b5Z*%CRIV5>Pe5IX&WlF zhm99xbpzV-GgKjyv=U^vruL}z zIJUom9*S?ZBz(VzmT7FLhS{LM561t3_LPJ@YFfJN`8-gbjd zhJ1LsGGyi!xoZ#n+?#Oy>+x)Xo+BR_Svgm7YteJj5qvrZoze`rsSn(}#OYJm_K#S0 zqL&YpTFUdiR$gb6<4=d35G%<}_RtM+mg?nAD%VM9h#!XS-{)UIgBIOwF9EA9PyTA- zyV}54rJ-qj9$nft6ro?DOuK^hmc^IZVyjRe@ie$&HnCz&nA4snvX?|(7*qfj!WzAY zSNoHyYcVun5U+y&lEK^gNb73uxjDQaWI;Ial7Z!VwM$)m`(5h8e_xubd0` z`$QD?mEbq}QGa@gh`1Tf|1jLlRksLg>q=-%Yr=@V>Mh5sA4Dm76*X5bzldKRE@}k2 z>NV7#_ECTOooJbp@AM6{^a|*50KG@kgcsnOb_x51R^oWj*IRh^PsuQUg4++OBGsk( zR7Kj*Wzh{!|1|3PK+&}v1^o`{^VhoK$h|NBL#J4AenG(Sm%YCsn}=Ymb#_eNWDLm8>(# zE^3#t%iEQ)dyQIi_Yk{Hppv>39moaP-FPR-DM^H{;8Z22nG0w6Ha7o(bC6D&vqbJh zxFm->znR+!kN&JX&E1Hn2_p0@B6M*y!w$NPC#iEyL@&QQ^x>z-dCq&cz0$CX4t2%4 zP^s@bU+CdaEY%7Z({ogQ6_yS{00M-j8^_p z^tdg+Hq)qneM&dY1$3x!QZA_=HB<>4*GC#j{bUaIzZebe7S_Nw(nXYeg<*HgqdTaH zhO8NEZYou=Jydtjp_IL!x?@#E0Toq8Nj8wU{wn@zzw#Aq!ZoF!noNExs*c(SzuuE* zK31KG|5~FSP)~v(uAu8n)Cy=1pfC%(SQqpz)3w*BNPa?(#QjvS>Y{q-i5-mA$AQup zQcGJ&1UP`k?~)#G4KwxtQx z`<`ZhSf!WDSFwf7a7l-#zFnZEA7}t2%f<86w;m6>Xa=GznuHI0C9Jw^!!C|k=dp?W z)HolcrY>L+zWpefZ#y&ygFy51QLw&8jQP_pj4$-*rfE<0yARsUQBE2WXCBtE6NTVm z_~bvRzT~FQsswCfO>(#{FoYZ7x<5trev!<#0G(DPQMVahEvg*dyrCfbZJ_#}yz8v; z1ai3Ibf;CM^3ov8h*uHQ57R4liCQ{)h_cor)C4u`VikGZvoI?=#4nlmt$4PM@>Kd= zHozfglAT?Wo0An!g>l@c98g|W*Q*bMH0sf{(ieS85PcVtPpzhN;UnZDJMTwu)Ruy_MmcT>ok--4$+gj%OCF_5q3KW(? z&PXA~>ruvPD~k71LLz)tQMju*;&b8*xPV(?-f*3iMYSQ~@q$jq(ef<%hCZPN|GS(B zvM8xM3jW_h-{m2&+b>iY%4r&-_&BxpShRI%*zPCjB(G41dXUlT21hyvcJw1Mm;$Cu z46aKClgfy#gynn>HODdY3=HRG^DnAiDt6ft57omOhWchM=y)SNKKrfHc&dwxTYkF) zUP>W0H@2H$hs)rd+d3UXob>|A$~W*zn?M$~=&g8!u{h@%-U_1XNg`?qx(6O(B-&#~ zQ>j`UrdkoHo-=X<6RI5Mfz5@k)K_K*%c$7BOLg{^;8T-*f~vwOqQ?8=H9zA`Zi9{s zpyn?v*&wfWAg@`{KJ?xVU{CU*qBoS9a6>OBNAM39l%O;5eHfw7@de+aADbAi;FT~x z?;1O)xm__znZxkfGtBvBMySI(#X8M_#-tV8ZC~ptYZJbDA0zOS)eI|HWWR2ofk7*R zD!(fp_%OIBp894nY@z`@tbe+XkTJI)ujoM?a~{5Sg|{VKPY)0+8`IMoX__5&^gy%fqX(XwIC9}5|pzF6Tiu;sJS&@2V_ZXv(k4^MLj{Ck;hqj*%)#o%cx zqh{@E4~Ogg%9iOaTuANtkn^K+%}GFM8+4YfM4LH<`fYpixxMrhg!+I^IU_@vhZ3mG zYZK4X=|efqnk)>TT#p#m6Er##CFNA<1?v4Dp}4Im*Cs<-1;#MRKsuo1TudA~qtt|1 z=}$NGOnApYkMT78?^aloOl_&Y70z)0NdHwL#y;5PV4Qw5euJk<0Oyr}d8|gCRV_SO zE3-58h+*_xP9cYQg*wDqc)Snk=RIzIn>9*#tOu;pXd7iJ4R!Hw+pG^!s};tZ*~Exi zc(jHn$eY0nJV_SO751_(y_iGjcp7bwwV$OcZyMF&7g@P4qyBvpJ=tpe9n@Nz(X{P^ zA2wLc-O(n!;;djL@677T{1*M`AF!Rd-9qkz_&<>@jhb|4jzR&so8G+N+y|)mXlP%1 zhHCR|sQ!b@q7>Shmi`Phxhu#Ij|MSgP|ip@#ynn7!F@f2RBBxx(eZPgdT%-MW`}%v z88zRIpp`{r$Ooiqa9n-B`LjWJACnK@kMx+J#~X%5m4-V^>ZgNUC@SL7!~rtt$z z;-AbmtJJovz;w;vmXe% zCVs>I3Nm6rt-OZY&~1gv`&l@r7s;`ggG#p3S#r=lPQCx}KMicW(+iSx4vSgBVwUo!uZTC5<+oEVy1W@AB$`rVhpyPi% z9rU?ip{uB}+8U+o6m_<`8-?nRszyFFUt7#bp41dnK!4F;T+WzBSLs?t@)skX+C^Jd z`VG4OA403(QwJLjDp`R~{lWT`I!g{a7fe>su=`;ER=E^i$t7^gU|9C4Sm8!=Tt{K2 zZqXfNxsSRdz$lB|WAp<)fXet~G$NJZnELw9!?u4MB9O?eoZ)`wMTCby%3bK`dmBVcF$q;c}qpDDr4v`k%t?eL+vEbkLzz_wrVwwo{>Vc|e zEef@>`h$4FUtpO>o8zexo+hVjK%Oy{N?swjmzysi@Mj9sEMjuoqv#A^Gp>oiiJaYxr?-AsZLBIZGr!)w$H<)^u zI~oPgB=;3~z(B)ujLyXXXIum?{>44!pWHpq2)hov=)Fn* z#3}UaKZ3J=hwaD#mP`UomI7^8_7#vwZE7dY{kGIA2ZWuwj8R7PUUI@1&81fH1$KRg z{;!;L1~#I)7bq8}qO3ko>@0&mq&i-sGu+^Gn4uMLLmBuE3ErazJ@}K9JybGIQ#p#E zs#05hJY+jo!H3U)?cPGQITzjYO{f?x)|ZB=#KX*b3|(5C@Z?j-rh-i0#5YWVt<3=E zeFk6sqj?ps`hBY`{U$BQ3<^>&Yr>tkre~}Z%)+1O5aRqq`V=CEa)#Q4rBt~DDGn|x z*g@cuQi0xH1xC_=lbi^Jx zy;)Dfde01ZpV&=?AGw$__^wcDG$mkbYX}WtJchCd#|!iXeTu5*8#J@|(CBFNRXj#t zMJlTEkEq+_ltd~QHvN=csa!loMia!(DNfub(ncQE}53;lPZ`vfG#hnl9M!UU-{TKJ&ea)z~3L*c`dJy(w;1zy`5&R9LRt>x8?Fxc7NUE9)cDYhbc$YUTd{=Xuui&wF(6rSw>cI3pMh5)^y*q7DH+3P)>qD(AGAN#1 z=1>M`eGLIUcvE~yYp`o4yBj#G9|(3RU5NYaN`bg6EuP)YB9ZHK=k;M_7G)QVj_O#g zf_?^ev;f}HB@*_BAAK1W_lLy6U&FduA?nQ%d_@QR!#v{PyL3W)ffDd)Fc!1oLrrUL z;eKHb?C5#{QdeG!8uk%(HdsqdDUaJf^tE6lEFI%YOrXKmER};x%ik8n~t-jC49zdBS*)tNOuoK(q~5>m5+EZX#dKV5fo?$=?#- z(*n(E53v2WV1+-O{N!lwl8@5<0Uh{_K+a<{mA4f+L#L|r@-;R(^=WvtR>!KZ; z>qxS}mGIM-=-MpGt~VZCBF(&EWPUHRpUGaj^B;nLna7nRggTlbRWquGZ{y8eF2}n z9=`fpc)DMxxKx9q^U2IRqh5H8irW=dv_d_hwpw59hU#Z3n02B08l7CbiElrX+x$*_ zp*Rdipap7(c4i3JX$ReCe^E)xhpM@Xu2V;Q26pxxu+&as+IQ5L3$lMrZ!{cB(0W}q zT>3#9qmJzx@*3k&@CJIPPs}gKJ9DyMMF9{~RWMT%c-JLZ!TVGiE|GiYr_vwrt+iQ2 z)94-8Nk{ZC(EWGlV*>lA#hmp91DzpvYl?Dtk=u!V6n0YIKjA$_jcW<3dv~-?GC3jC zX2l6l3G>NMz82bHEvxCRc#f>(Ge#|iYJCP;)V+$LdSuXjsrs3837J^OZ zIrhG)3SZO>pS}iWB+2RnN4b?6%@cT>rPN~nIP%W4eO)uLJo9N<*#eOUSX8I3gd*m@N{stj16 zYN)95z+H{#{ODyp%V(dplEJN?QwMs~Imc)J2F9-ek}3d)*%)@aCp|yU(Z|sy`20=@ zVgB+Cxo@yvM+R9zVd-J&VNFp#j>G%DCT*ne?JC+&pOG0%C3z+p$anOLmqEqZks3p~ zvRO%>=i)ha0sAp+hf&Vt%Hz;URG>Gnk=6l~M9?F?5hQs-@5ydgt5D1z1V?v4QT2x- zu*Q3$4;jFE9?MP~>rlTG^hGkQUZA)YbjKY46DNf6a;-o|qPl@f@d*uS3|R;C2rI-3)xLAr8TVi zQsb_OZ12zvj7Ft4l3 zcsCYW&@DC`{r3;-MR1KuUoEoD7xAF0*$wIx^{iyHI!|%sQ{XN#r0V2|r@(P9(Z^X% zYo)E$$tb8BRc2?Mh0YsPf;SVRqw^W;IhGHtn=d^ol|j>91_b)6QWN{itDAvtFf$>{ zA4;la*>f!$CDcX{)*M7WR86Hy8Zg%j?8RgP>G-k?b`Lm&H_L>hxQIR^LVrwNd|Dy; z6-zqF^ek4OH(sEQYQSDpr!%b{%9*BUXIg_;JF(M1Bsnq68`p5Yy{z^~)5NfLUxDrl zgKnC7)IeKPwco&gINR}gd#Ujq5{@uFnd}!(QcR{2S^<7jpekh0cUBu#tr0nT5}aaD zYHJD_2*;?-P8Un)G~7TB#O_cHbJ945uHhOLkfL@4+aSAYP2QLqc6hDe&h~Ow=eVPr z+*90t`>uMS_aB7bF%^CxjZV$U#Q$0JCoVuGv={~C3TF+mbOS8Tc2Lr8aMFIP^$6JD zq?1Xd?HtO9i_R7N&P^DxIBKVPsh$>ci&A+`ro*fPT#tZ0%%DP09rYx0*C{dVmYjZxQLYLcVPSnbdx2vS-=V?GljekU_A?6-)Z6Uj?YPa*bLDVe2ws3$by+M8p0-QW+? zh?SGMgIVPIi?PMP5_f0W;z^jVYpClYVw{*L=B3tBIkZLRjx{E-hhGv%v?$fbWFlmB z;y@!XQFGQ{J22@Os`8WNYj<-0r0l$(+I(eLGDm5uL@p+V{T7Q+nXFLO5HmKA`5eI? zWh%SxAn$W%BQH{wxkfKUgqmXZDoAEWwhAbM1X!hdMk6EJZt9V7G^e`Mj(To4vc#ci z85oxcd;OEs-Hr7#!1qyfAN`D*dQ!N)vd?UA*5>R{(hmNj8$0j}g}a{xi?M)}=b&k6 zWFBEp&a$At#w_sSB{xCBh2S zpXs5^9zxZ84Avu)Jo-F4u3ovz=Aw8LteItV3KcGgN_cJdh-DU=Aa&4M1A6Ko7_U~d6WB!)ADLb>={>-T>}MeGJB5Ry&6|UHIG8BQ0Jb# znj=!2l)a)$66eaY3yFbtqh6Rxb)p8Biu!RfXmT-qt<1}yTw$NV^ej7DOua25z|(2D z!XBK65O>eYP8Nc7Hl14M9IBm*UU=+5D1%eUx6<(3|86eQ$%?kHA4>*aa_>EU@+_?XdA$1- z*eN`GB$AOU)R_P4*p|g}RwimI_0s8#A zEp^L1{`ClKMiA}K!UUej*IvQfo}-`gBKRb)o*@@}KPG z8hFd?)M0jqtR?r8nJdy9U)Ne}N9^fF^y&96@h4dGcSoS~Fa~X>KV~=8)cxWi6xGMX zljsr7f^5&|iK1FoB3VC)}T9P3WI?liLNE-C5@O3K2DqXj+K;plldX9df%yVsqxH8*?<2{9r3GmZc+WM;2I@h(sV^QO zqMv1-pewLsacW-nIw(mtUYTs%f!}CECf*K?qn|p6^_=#+ zChIdps1!nyB~q!VOm^8vwt6i?)1r-}qOzAH*-E8_Ea{b{#j8Y0$Wl=$Tg!JpV`=hs zy~`ip_qndFuJb(4d7d-p+`r$woco*uSUv(4PAYgc`GDUtz-}YhH!lFQgRE#W36l%5 zjoLSYVB3%Zq3l+*BOua`W!>xr%LdgJ*`O(|vaIYzK-~*K9BSKOz^)MlyM_#w8p5)& z(N&mJwi+7g+Y5T}1XyU#YukxnrHKOultBJ}W^})4PCvn7 z^?Z=-GT3RY5waFvKsNRu_+}VQBG^yjU^^*+rqyNHPu5^NIf9n;11%c~tbPO-Jr&qI zADFxhSiBK59jfOBLC0Yro+=176&Z9J0(#8=bec72HAm2BexS`FVU5ob&}6A#S>Wz_?D+#`_5O@v)h#UTSs3H%~mm^oPqKG6oq0Cb0y4k56U@?Kc$a02oH zvsrsomo2OTZT|!`eGkN*MnD@9K^Ka{{;5i!3w5;(Ad|)#X7C*W!+wC@NWd;eki?2( zB*6}U>5!X}0CU2b5D_U}bOTl^pxLagkj3x@Rx5mgwe-A@#~=x70#zY;p$C}^7LbeS z0BZofAbTGHYYNp2*|3gCkmZA^g5QODToYbN2xy#C@Ig@TqYOL_l;J@}$Rw7HgKA7v zO0*{ZE-#RbQ=s$igV%+!?+8m8P+X$2V9a98NErDt7;OxUumLbxB#dMkj2;F?ObggEh ztc0DIP%g(TU2Oo29qpG6?xh`n?jG=`Vu#?PM&_NEr z&_YM1bxtGOOxc7jJz=lobvHnM=Ml(U$%pyAM#z>LVyy)ghmnTyaU`+UPEPnFKkL(( zx)cHb!w(RdOM!a-#Xmm@csUOC%V0>*2;9odmCRv2EEg`7A+ZK7S>do)3J=0f;8fw~ zz|Dm;J_`a#g@DCl89F#DK6M#r1TnTN0thz;7L$rk$3g zB(mlF>|<1#-sJ+NnEm@(Q%JngVqu4mPsIj#H@{Ce=TrI46VP(TvGLH6h1DVJ_K?#Wy1Yp>X1gdSG`(bd_cT&B zrC%3j%zC>>?DWaS0cqW1nNORuP;iuUoWC`jqkXlgOJ6B&PPk5%}h2N zU+6J6+q7?eb?615CvH(O?GfC13Efu}RmnG(7Afr;-uhj(<9Lj8ugk!m7wzS4W<{I( z3%Qm172k&3`b}TuV~OHI@2&f=SIq2Fu$;*kmMWCrzY=lhy)UzR%-Ov^N-d#(dCAy; zd2QR?-?DZq@w)l(z4UfoZ7$IWon7bcy~ExMt#FKPo{zs}UVr>ng`2YbtoF#)yqd1J zh51B$K1N783CX=&l8Hw8 z;0J*2JNRce3El9c{o}i;tv2?VCj~zyd|ARSxhQm_V%e~}$#4q0L}6Y#ICIG*0L~nu z`MFR;5Fr=~JeM$!@s5CPG@l?3FE1C00KAO_bi!J9T5zBXMGBEXFYpM9Ok5zN;P-Hy zJokno%^Glkx#;BWwI1H^6`HpndNR=j!eMi0Ds>XmfN&~8p=u&jP1tdC5o}A%)>t5# z$^rDgy`^TvKrZx z3K0HlXcy!bnXNTHE-6HMq7WJeI=*$)$WG19P}2C|j=hGbzE^SBoXlzVN;&GW z$7MnE?mLbml{NR4h_sYN4NCI`K985Z@cZz1;I8@I!>c4B&Q+XI%iG^~wmWCO=x?;) z6aKSqbXcdEcWoZ);yt^dzyTW>=QgO5^WyI*hsEd79m0A~$=6IGfZtt_WXS zF1)KM^!>eZ{|RVEjUiFPY}nnJ^vTEJ{{6tD$8En2=s$a75vksWPzglPNt~QqSS(%< zJQdlgGJ<7_P99O@>qPfc4`hiBss>mxHo*@>gaG`2!(tG97(yv&*h@qk(MqMJB24wk z%1!}ZY;`pzB#K?2j11M`8I~@RQo!>fq^TBg5N9wG0Z~G~G7B$*NN0jjO{pplVL|kT zEO}9*f`zL_nSmdUs3;5vckO zyMMzjq-WIQpd6h?$k+6I-lAC}$_2^!b1M$@Z%o8otmm~XY^0neIw*&I=?Iguv&eQ4 z?+rEBrjY1!_pXj-v<&f(VPD%*JAJ8Ovpve9ge_-vJ!OS5Z01CVUqKl73_yJBB;xrS zhIDJb-CpQ}f8u#UVy^X!7XQ~V1X>y}4DQUdmPRoQD?ukQyzO6MSPKM+g<+My!?3M~ zn-3gx2RPRHTO6l5@hmdFS}J$W*sPTQd)gq4WP3FK#IuX40;{TgzBBb~*9pw7$Lp(n zJ)fBP^cF3Y$NruLGpOr@k-6-#cXw2b%2S@W7auZM{cgAJwOLhiADlM~&ZhcW*`?*} z&BQe;&#N*hn=9t>=k1{c<7iv+GjRT)%+V z@vpbm30|v=c21acQz7zY&qLX)#_PDSwBV!mE*0;@0&f^Hm0O7x2jUOJshtTnmUjOm zJ23bezdbc}eXQoqr%p9yrx#aM^=a}ve4imP6npDwkzMSP=lFABvW4<_>UaIBZdpYu z632ONo?m^E_)<_QAg68u#|*3;^pq{aiwZwWE#nXjB8rw2P$m5rkl~6%=u>b4fV;ue zn(|Z`06uRLqk(ia7RH0=>hwv5W&vGi`dJ)P<;Sx$51RUnM>PWJbTucMnj2LetVKi* zZJacIA)<*;QZ-W5*lVMN@E5g#3jQg|schu7qS_;af0f9*CX1FePGb67v~Tcr|74i_ zlKp;Rn1n1Tj#I{13?ANw=!9g%%;)kIFMO`hn)*0_BZq0FkdkD;A=y^{DzsL{ozQZH zTI_v$NLA5Ev(wDko3FdVjenRkbD`I+eWKO9h3$pCZRBcyfx2UXtydhL-_(&d3h55H zT&IL5XXLy$uiU#Jjz99jtS@a2K|ZUu@SChK^x@0z(@iQ^+`{cI_(d|bIC5vM$I#bP zS9nEL-bdJTFHN@Z5dB>^${VAu%a^_2uE_x zQ`oLFq>|Yj3nO1=um*rP*vtaA@q2*9BF;m_0K_`DZa^zR!OZo zlVm>j$J{lWH)vmf9xEBbZ2gjZpO@n(hljkUekT2B>(#4|Z&lPuB=E57@6( zTjaX7v?(_v>iORB>O${`zNU;zVWZppM--T9w{4Oe)~0pdT#$Kz7&6x;No|U{s-UOJ ze*)sB%4<87Nf}vv{v2hFqiUaBcJOat1F|uZ7Kg;Xwe*%=VgEXd&xSkRfA7zB0FWB$ zxXv&ZIFR58((!{8u?tf*Qz=Z1A0~+APmZhx-JM2NgR>4%*Hz7luI5Hz*&u(aruC1i zS)d;#<4s^=WE}#xBXcE|`PGX93;SUzO%W&#D=LY$h7Kn_&UC9ajI3=DB7xu*#S6g! zBr0aA5-@fMq(aC~m4UIvCw~%)uGxKa#A^B}9CP{952vB7JN@S$F$FUeWs@K?Ge#jc zi7=Ku7C1xOun{Gop5?(=3GrXNa@J#^<-0L~{k|cYaj_4n2$%KUm@|r&W}L%@enVYf z`_$T367JW&KT&w?O)ZhBt7m?+>EN4v9k}GZaXANM`)co%+S~Bv7dRKhZ2W94H$clH zmUOrud$VTs)(cV5@z1`Dyj(3hluVI+D_OF~=IL*R4GH)57SgtL8Rb}gbKZWOUM|b| zdBbU`KGSB!jl_^6t3wG(RQqI3?hD_-R2`BM-5yq?NYr}s0RO7?JO5er%Bn+#vrGmJ z>a0v=i*$r(Jw%zC1b%O9$=IK20P+oS671@rGd+9{XN87G%` zB$zRp79-~>v{utPus}(%RNmvxoi!gs-1hG?d90R}(Ysfbd@N6L)gEFy@23t+NAX)Z zm4$hJ6jx3EWx0Oo7wRK=ch$zHbuFPtHuQZUb=sA#y4)Mst@6#QHau{VHs6tf&dXMr z=leWK7h*o;SW96s=XtRUAB>R9v@0BaFvXR1z?JuY>0Ql?(EO7BLZ=u2c*7gEOZ;cNVKh|> z!7+9I32#hu1{&|1B#Wr13GNMp*_6epx~bYst*KW9c+DWuDgOEMd%XT!cLs0&Ro&GS zEW8r7ywN3)CRrGR!~ZK92Iq5%zu9!sFICpRiF!?O=CU_@o8*f=%08G~qq<9BK~T2T zW=XZhb1MfBT5~v$@zu3IhIP{~o2x0&5sTEcZ-;WeXaPh~@9>0F+vdx`?@_F*rcjqgoEl`@f*k1{! zryiG4rZB7Hl!$3sn7jL>&?OxbquL~UuRBq3C!>%nLQjKR|F*zezT2&{j$8EvAjU!_}%LvLtsvdtbkW4zB>^&AbQcB`UoKUbiO5)HXV{xTeOG?Cz40cx{?w zWcPCW+xy9*heD{tXH{J{MhC<{97W=3>wB3!+iuk>h;jD_4=$V?nx5+7-kPzQ7A*ed z+mM^`y71l2p9D6}s+8Z6cslv~gRnl&kKS8)_#VC;#nZj6&;8_3HyA0!74C2*emP!h zkNUw*Erqg{vF#S!`Eui#swRB}1BC0Tg!;(OD$8CPjxU!Ej5u=7!NN2|{JOD#l2&O{ z`u@DAFYaZ_Vt=3CYH~Jm^{dE75yb^Di^pNFc~a2#m~|5AX$%|>Om1-f=sg03fgJ&k z974q>;J+Oq!3q8;M8hU2n?X{hrhGsic%}-xyUOpY zI*(};HuM%OkzJNHOk8j;2D5aOAahYrLz1LTHHjd{eE*lPb22*YS0erg%U;qFB literal 707952 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

public const int WA_CLICKACTIVE = 0x2; + #endregion #region Window Messages + /// /// Sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. (The message is sent before the function returns.) The window procedure of the new window receives this message after the window is created, but before the window becomes visible. /// @@ -466,29 +502,38 @@ namespace mRemoteNG.App /// Sent to the first window in the clipboard viewer chain when a window is being removed from the chain. ///