diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 05ea38240..8fa19fbea 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,14 +1,62 @@ -1.75 Beta 3 (2016-12-01): +1.75 (2017-03-01): -Fixes: ------- -#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2) +Known Issue: +------------ +File hash check will fail when updating from 1.75 Beta 1 to newer versions. + Exception will be: "MD5 Hashes didn't match!" for 1.75 Beta 1 - 1.75 RC1 + + +Features/Enhancements: +---------------------- +#344 - Use SHA512 File Hashes to validate downloads (in the update mechanism & posted to the Downloads page) + + +1.75 RC1 (2017-01-27): Known Issue: ------------ Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions. +Features/Enhancements: +---------------------- +Added Release Channels to the update check functionality allowing users to select one of 3 release channels for updates: Stable, Beta, Dev +#360: Help -> About, Version # is now selectable/copyable +#221: RDP: Optional disconnect after X number of minutes of inactivity + + +Fixes: +------ +#369: Reset Layout Option Does Not Reset Notification Pane +#362: Invalid cast exception when using the Notification Area Icon minimize/restore +#334: Quick Connect displays warning when clicking on a folder +#325: When using a connection with an external app, results in opening the same external app continuously +#311: Import from Active Directory does not use machine's domain by default +#258: Rename Tab dialog - populate original name in dialog (1.72 functionality) +#211, #267: Recursive AD Import wasn't fully functional + + +General Changes: +---------------- +The usual general code clean up and refactoring +#325: Code clean up and additional logging for External Tools based connections +#298: Code clean up and additional logging around application startup +#291, #236: External Tools code clean up and additional logging + + + +1.75 Beta 3 (2016-12-01): + +Known Issue: +------------ +Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions. + + +Fixes: +------ +#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2) + + 1.75 Beta 2 (2016-12-01): Features/Enhancements: @@ -21,7 +69,7 @@ Fixes: ------ #254: Component check window position issues and uncaught exception #260: Crash when attempting to load fully encrypted confCons v2.5 -#261: Double clicking folder in treeview doesnt expand it in 1.75 beta1 +#261: Double clicking folder in treeview doesn't expand it in 1.75 beta1 #271: Install package is not using the last installation path #278: Silent installs not detecting prerequisites @@ -65,7 +113,7 @@ Fixes: MR-965, MR-871, MR-629: Error 264 on RDP Connect attempt - Added timeout value to Tools -> Options -> Connections MR-946: Remove old/insecure SharpSSH and related components. Replace with SSH.NET for File Transfer Functionality MR-896: Added prerequisite installer check for KB2574819. Prevents "Class not registered" errors when opening RDP connections. -PR-130: Fix Scan button width to fit russian translation +PR-130: Fix Scan button width to fit Russian translation @@ -73,7 +121,7 @@ PR-130: Fix Scan button width to fit russian translation General Changes: ---------------- -Updated GeckoFx pacakge +Updated GeckoFx package Updated DockPanelSuite library to 2.10 Final Japanese translation updated MR-942: Refactored code relating to loading the connections file @@ -148,7 +196,7 @@ Port Scan is now Asynchronous (and is significantly faster) Fixes: ------ MR-874: Added work-around to installer to ignore installation prerequisites -MR-884: Slow startup in some scnearios checking authenticode certificate +MR-884: Slow startup in some scenarios checking authenticode certificate MR-872: Crash in External Tools when arguments aren't quoted MR-854: crashes when right clicking on connection tab MR-852: Option "Allow only a single instance of the application" non-functional @@ -289,7 +337,7 @@ Fixed issue MR-398 - Full Screen mode doesn't correctly make use of available sp Fixed issue MR-402 - scrollbar touch moves putty window Fixed issue MR-406 - Items disappear from External Tools toolbar when accessing External Tools panel Fixed issue MR-410 - Unhandled exception when clicking New button under Theme -Fixed issue MR-413 - Can't use aplication +Fixed issue MR-413 - Can't use application Fixed new connections having a globe icon. Fixed the category names in the themes tab of the options dialog on Windows XP not showing correctly. Fixed PuTTY saved sessions with spaces or special characters not being listed. diff --git a/CREDITS.TXT b/CREDITS.TXT index d5f858bc9..2b5922afd 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -8,9 +8,12 @@ Sean Kaim (github.com/kmscode) Thanks for the awesome new website! Bennett Blodinger (github.com/benwa) +Joe Cefoli (github.com/jcefoli) +countchappy (github.com/countchappy) Tony Lambert + Past Contributors ================= diff --git a/README.MD b/README.MD index ecad8f95e..539b9861d 100644 --- a/README.MD +++ b/README.MD @@ -4,12 +4,17 @@ [![Join the chat at https://gitter.im/mRemoteNG/PublicChat/](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mRemoteNG/PublicChat) [![PayPal](https://img.shields.io/badge/%24-PayPal-blue.svg)](https://www.paypal.me/DavidSparer) -[![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) -[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG) -[![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74) - [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/529/badge)](https://bestpractices.coreinfrastructure.org/projects/529) +[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG) + +| Update Channel | Build Status | Downloads | +| ---------------|--------------|-----------| +| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74) | +| Beta | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/beta_channel)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/beta_channel/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Beta3/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Beta3) | +| Development | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - | + + mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager. @@ -35,8 +40,8 @@ https://support.microsoft.com/en-us/kb/2923545 Windows 8+ support RDP version 8+ out of the box. -RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connection successfully to a Windows 2003 host (for example). +RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connect successfully to a Windows 2003 host (for example). -[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/) \ No newline at end of file +[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/) diff --git a/Tools/create_upg_chk_files.ps1 b/Tools/create_upg_chk_files.ps1 index d81f992b9..28d539549 100644 --- a/Tools/create_upg_chk_files.ps1 +++ b/Tools/create_upg_chk_files.ps1 @@ -18,7 +18,7 @@ Write-Host Version: $version Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT -$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash } +$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash } Write-Host Checksum: $hash @@ -38,5 +38,5 @@ Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$ Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT Write-Host CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA -$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash } +$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash } Write-Host Checksum: $hash \ No newline at end of file diff --git a/mRemoteNGTests/App/UpdaterTests.cs b/mRemoteNGTests/App/UpdaterTests.cs new file mode 100644 index 000000000..ab81bf6ff --- /dev/null +++ b/mRemoteNGTests/App/UpdaterTests.cs @@ -0,0 +1,84 @@ +using System; +using mRemoteNG.App.Info; +using mRemoteNG.App.Update; +using mRemoteNGTests.Properties; +using NUnit.Framework; + +namespace mRemoteNGTests.App +{ + [TestFixture] + public class UpdaterTests + { + [Test] + public void UpdateStableChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + + [Test] + public void UpdateBetaChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + + [Test] + public void UpdateDevChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + + [Test] + public void UpdateStablePortableChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update_portable); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + + [Test] + public void UpdateBetaPortableChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update_portable); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + + [Test] + public void UpdateDevPortableChannel() + { + GeneralAppInfo.ApplicationVersion = "1.0.0.0"; + var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update_portable); + Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True); + Version v; + Version.TryParse(GeneralAppInfo.ApplicationVersion, out v); + var IsNewer = CurrentUpdateInfo.Version > v; + Assert.That(IsNewer, Is.True); + } + } +} diff --git a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs index 8b6f5a759..0d9cf4a37 100644 --- a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs +++ b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs @@ -1,4 +1,5 @@ using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; using NUnit.Framework; @@ -30,5 +31,43 @@ namespace mRemoteNGTests.Connection DefaultConnectionInfo.Instance.SaveTo(saveTarget); Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain)); } + + [Test] + public void CanSaveEnumValuesToString() + { + const ProtocolType targetProtocol = ProtocolType.RAW; + var saveTarget = new AllStringPropertySaveTarget(); + DefaultConnectionInfo.Instance.Protocol = targetProtocol; + DefaultConnectionInfo.Instance.SaveTo(saveTarget); + Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString())); + } + + [Test] + public void CanSaveIntegerValuesToString() + { + const int targetValue = 123; + var saveTarget = new AllStringPropertySaveTarget(); + DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue; + DefaultConnectionInfo.Instance.SaveTo(saveTarget); + Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString())); + } + + [Test] + public void CanSaveStringValuesToString() + { + const string targetName = "hello"; + var saveTarget = new AllStringPropertySaveTarget(); + DefaultConnectionInfo.Instance.Username = targetName; + DefaultConnectionInfo.Instance.SaveTo(saveTarget); + Assert.That(saveTarget.Username, Is.EqualTo(targetName)); + } + + + private class AllStringPropertySaveTarget + { + public string Username { get; set; } + public string Protocol { get; set; } + public string RDPMinutesToIdleTimeout { get; set; } + } } } \ No newline at end of file diff --git a/mRemoteNGTests/Properties/Resources.Designer.cs b/mRemoteNGTests/Properties/Resources.Designer.cs index b47fce602..ebc09adb6 100644 --- a/mRemoteNGTests/Properties/Resources.Designer.cs +++ b/mRemoteNGTests/Properties/Resources.Designer.cs @@ -60,6 +60,32 @@ namespace mRemoteNGTests.Properties { } } + /// + /// Looks up a localized string similar to Version: 1.75.6164.27544 + ///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi + ///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT + ///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA + ///Checksum: A1E50ACAC4CB8023527E1E7A0E682459 + ///. + /// + internal static string beta_update { + get { + return ResourceManager.GetString("beta_update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version: 1.75.6170.27478 + ///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip + ///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT + ///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C. + /// + internal static string beta_update_portable { + get { + return ResourceManager.GetString("beta_update_portable", resourceCulture); + } + } + /// /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<Connections Name="Connections" Export="False" Protected="95syzRuZ4mRxpNkZQzoyX8SDpQXLyMq3GncO8o4SyTBoYvn3TAWgn05ZEU2DrjkM" ConfVersion="2.5"> @@ -142,6 +168,32 @@ namespace mRemoteNGTests.Properties { } } + /// + /// Looks up a localized string similar to Version: 1.75.6164.27544 + ///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi + ///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT + ///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA + ///Checksum: A1E50ACAC4CB8023527E1E7A0E682459 + ///. + /// + internal static string dev_update { + get { + return ResourceManager.GetString("dev_update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version: 1.75.6170.27478 + ///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip + ///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT + ///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C. + /// + internal static string dev_update_portable { + get { + return ResourceManager.GetString("dev_update_portable", resourceCulture); + } + } + /// /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-16"?> ///<!-- ****************************************************************--> @@ -276,5 +328,30 @@ namespace mRemoteNGTests.Properties { return ResourceManager.GetString("test_remotedesktopconnection_rdp", resourceCulture); } } + + /// + /// Looks up a localized string similar to Version: 1.72.5065.32737 + ///dURL: http://downloads.mremoteng.org/mRemoteNG-Installer-1.72.exe + ///clURL: http://update.mremoteng.org/changes-1.72.txt + ///CertificateThumbprint: 1cbd910dbd6e77f26506e7f600736972f700673f + ///. + /// + internal static string update { + get { + return ResourceManager.GetString("update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version: 1.75.6170.27478 + ///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip + ///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT + ///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C. + /// + internal static string update_portable { + get { + return ResourceManager.GetString("update_portable", resourceCulture); + } + } } } diff --git a/mRemoteNGTests/Properties/Resources.resx b/mRemoteNGTests/Properties/Resources.resx index 0fe45ee4d..902712d20 100644 --- a/mRemoteNGTests/Properties/Resources.resx +++ b/mRemoteNGTests/Properties/Resources.resx @@ -118,6 +118,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\beta-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\beta-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + ..\Resources\confCons_v2_5.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 @@ -142,6 +148,12 @@ ..\Resources\confCons_v2_6_passwordis_Password_fullencryption.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\dev-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\dev-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + ..\Resources\test_puttyConnectionManager_database.dat;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16 @@ -163,4 +175,10 @@ ..\Resources\test_remotedesktopconnection.rdp;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16 + + ..\Resources\update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + \ No newline at end of file diff --git a/mRemoteNGTests/Resources/beta-update-portable.txt b/mRemoteNGTests/Resources/beta-update-portable.txt new file mode 100644 index 000000000..5d4e02f26 --- /dev/null +++ b/mRemoteNGTests/Resources/beta-update-portable.txt @@ -0,0 +1,5 @@ +Version: 1.75.6170.27478 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: 1C35EA199F58001BC4EBB164D8B3D11C \ No newline at end of file diff --git a/mRemoteNGTests/Resources/beta-update.txt b/mRemoteNGTests/Resources/beta-update.txt new file mode 100644 index 000000000..1e6beeb0d --- /dev/null +++ b/mRemoteNGTests/Resources/beta-update.txt @@ -0,0 +1,5 @@ +Version: 1.75.6164.27544 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: A1E50ACAC4CB8023527E1E7A0E682459 \ No newline at end of file diff --git a/mRemoteNGTests/Resources/dev-update-portable.txt b/mRemoteNGTests/Resources/dev-update-portable.txt new file mode 100644 index 000000000..5d4e02f26 --- /dev/null +++ b/mRemoteNGTests/Resources/dev-update-portable.txt @@ -0,0 +1,5 @@ +Version: 1.75.6170.27478 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: 1C35EA199F58001BC4EBB164D8B3D11C \ No newline at end of file diff --git a/mRemoteNGTests/Resources/dev-update.txt b/mRemoteNGTests/Resources/dev-update.txt new file mode 100644 index 000000000..1e6beeb0d --- /dev/null +++ b/mRemoteNGTests/Resources/dev-update.txt @@ -0,0 +1,5 @@ +Version: 1.75.6164.27544 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: A1E50ACAC4CB8023527E1E7A0E682459 \ No newline at end of file diff --git a/mRemoteNGTests/Resources/update-portable.txt b/mRemoteNGTests/Resources/update-portable.txt new file mode 100644 index 000000000..5d4e02f26 --- /dev/null +++ b/mRemoteNGTests/Resources/update-portable.txt @@ -0,0 +1,5 @@ +Version: 1.75.6170.27478 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: 1C35EA199F58001BC4EBB164D8B3D11C \ No newline at end of file diff --git a/mRemoteNGTests/Resources/update.txt b/mRemoteNGTests/Resources/update.txt new file mode 100644 index 000000000..1e6beeb0d --- /dev/null +++ b/mRemoteNGTests/Resources/update.txt @@ -0,0 +1,5 @@ +Version: 1.75.6164.27544 +dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi +clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT +CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA +Checksum: A1E50ACAC4CB8023527E1E7A0E682459 \ No newline at end of file diff --git a/mRemoteNGTests/Tree/ClickHandlers/ExpandNodeClickHandlerTests.cs b/mRemoteNGTests/Tree/ClickHandlers/ExpandNodeClickHandlerTests.cs new file mode 100644 index 000000000..e4ffcb641 --- /dev/null +++ b/mRemoteNGTests/Tree/ClickHandlers/ExpandNodeClickHandlerTests.cs @@ -0,0 +1,46 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using mRemoteNG.UI.Controls; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class ExpandNodeClickHandlerTests + { + private ExpandNodeClickHandler _clickHandler; + private IConnectionTree _connectionTree; + + [SetUp] + public void Setup() + { + _connectionTree = Substitute.For(); + _clickHandler = new ExpandNodeClickHandler(_connectionTree); + } + + [Test] + public void TargetedNodeIsExpanded() + { + var folder = new ContainerInfo(); + _clickHandler.Execute(folder); + _connectionTree.Received().ToggleExpansion(folder); + } + + [Test] + public void NothingHappensWhenConnectionInfoProvided() + { + _clickHandler.Execute(new ConnectionInfo()); + _connectionTree.DidNotReceiveWithAnyArgs().ToggleExpansion(new ConnectionInfo()); + } + + [Test] + public void ExceptionThrownOnConstructorNullArg() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new ExpandNodeClickHandler(null)); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/ClickHandlers/OpenConnectionClickHandlerTests.cs b/mRemoteNGTests/Tree/ClickHandlers/OpenConnectionClickHandlerTests.cs new file mode 100644 index 000000000..a6f19f96a --- /dev/null +++ b/mRemoteNGTests/Tree/ClickHandlers/OpenConnectionClickHandlerTests.cs @@ -0,0 +1,51 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class OpenConnectionClickHandlerTests + { + private OpenConnectionClickHandler _clickHandler; + private IConnectionInitiator _connectionInitiator; + + [SetUp] + public void Setup() + { + _connectionInitiator = Substitute.For(); + _clickHandler = new OpenConnectionClickHandler(_connectionInitiator); + } + + [Test] + public void ConnectionOpened() + { + var connectionInfo = new ConnectionInfo(); + _clickHandler.Execute(connectionInfo); + _connectionInitiator.Received().OpenConnection(connectionInfo); + } + + [Test] + public void DoesNothingWhenGivenContainerInfo() + { + _clickHandler.Execute(new ContainerInfo()); + _connectionInitiator.DidNotReceiveWithAnyArgs().OpenConnection(new ConnectionInfo()); + } + + [Test] + public void ExceptionThrownWhenConstructorGivenNullArg() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new OpenConnectionClickHandler(null)); + } + + [Test] + public void ThrowWhenExecuteGivenNullArg() + { + Assert.Throws(() => _clickHandler.Execute(null)); + } + } +} diff --git a/mRemoteNGTests/Tree/ClickHandlers/SwitchToConnectionClickHandlerTests.cs b/mRemoteNGTests/Tree/ClickHandlers/SwitchToConnectionClickHandlerTests.cs new file mode 100644 index 000000000..5cbdcd89c --- /dev/null +++ b/mRemoteNGTests/Tree/ClickHandlers/SwitchToConnectionClickHandlerTests.cs @@ -0,0 +1,51 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class SwitchToConnectionClickHandlerTests + { + private SwitchToConnectionClickHandler _clickHandler; + private IConnectionInitiator _connectionInitiator; + + [SetUp] + public void Setup() + { + _connectionInitiator = Substitute.For(); + _clickHandler = new SwitchToConnectionClickHandler(_connectionInitiator); + } + + [Test] + public void SwitchesToConnection() + { + var connectionInfo = new ConnectionInfo(); + _clickHandler.Execute(connectionInfo); + _connectionInitiator.Received().SwitchToOpenConnection(connectionInfo); + } + + [Test] + public void DoesNothingWhenGivenContainerInfo() + { + _clickHandler.Execute(new ContainerInfo()); + _connectionInitiator.DidNotReceiveWithAnyArgs().SwitchToOpenConnection(new ConnectionInfo()); + } + + [Test] + public void ExceptionThrownWhenConstructorGivenNullArg() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new SwitchToConnectionClickHandler(null)); + } + + [Test] + public void ThrowWhenExecuteGivenNullArg() + { + Assert.Throws(() => _clickHandler.Execute(null)); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/ClickHandlers/TreeNodeCompositeClickHandlerTests.cs b/mRemoteNGTests/Tree/ClickHandlers/TreeNodeCompositeClickHandlerTests.cs new file mode 100644 index 000000000..d024bcebf --- /dev/null +++ b/mRemoteNGTests/Tree/ClickHandlers/TreeNodeCompositeClickHandlerTests.cs @@ -0,0 +1,39 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Tree; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class TreeNodeCompositeClickHandlerTests + { + private TreeNodeCompositeClickHandler _clickHandler; + private ConnectionInfo _connectionInfo; + + [SetUp] + public void Setup() + { + _clickHandler = new TreeNodeCompositeClickHandler(); + _connectionInfo = new ConnectionInfo(); + } + + [Test] + public void ExecutesAllItsHandlers() + { + var handler1 = Substitute.For(); + var handler2 = Substitute.For(); + _clickHandler.ClickHandlers = new[] {handler1, handler2}; + _clickHandler.Execute(_connectionInfo); + handler1.Received().Execute(_connectionInfo); + handler2.Received().Execute(_connectionInfo); + } + + [Test] + public void ThrowWhenExecuteGivenNullArg() + { + Assert.Throws(() => _clickHandler.Execute(null)); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/ConnectionTreeTests.cs b/mRemoteNGTests/Tree/ConnectionTreeTests.cs new file mode 100644 index 000000000..be6f30204 --- /dev/null +++ b/mRemoteNGTests/Tree/ConnectionTreeTests.cs @@ -0,0 +1,51 @@ +using System.Threading; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; +using mRemoteNG.UI.Controls; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class ConnectionTreeTests + { + private ConnectionTree _connectionTree; + private ConnectionTreeModel _connectionTreeModel; + + [SetUp] + public void Setup() + { + _connectionTreeModel = CreateConnectionTreeModel(); + _connectionTree = new ConnectionTree + { + PostSetupActions = new IConnectionTreeDelegate[] {new RootNodeExpander()} + }; + } + + [TearDown] + public void Teardown() + { + _connectionTree.Dispose(); + } + + + [Test, Apartment(ApartmentState.STA)] + public void CanDeleteLastFolderInTheTree() + { + var lastFolder = new ContainerInfo(); + _connectionTreeModel.RootNodes[0].AddChild(lastFolder); + _connectionTree.ConnectionTreeModel = _connectionTreeModel; + _connectionTree.SelectObject(lastFolder); + _connectionTree.DeleteSelectedNode(); + Assert.That(_connectionTree.GetRootConnectionNode().HasChildren, Is.False); + } + + private ConnectionTreeModel CreateConnectionTreeModel() + { + var connectionTreeModel = new ConnectionTreeModel(); + connectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection)); + return connectionTreeModel; + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/PreviousSessionOpenerTests.cs b/mRemoteNGTests/Tree/PreviousSessionOpenerTests.cs new file mode 100644 index 000000000..372296fad --- /dev/null +++ b/mRemoteNGTests/Tree/PreviousSessionOpenerTests.cs @@ -0,0 +1,50 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; +using mRemoteNG.UI.Controls; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class PreviousSessionOpenerTests + { + private PreviousSessionOpener _previousSessionOpener; + private IConnectionInitiator _connectionInitiator; + private IConnectionTree _connectionTree; + + [SetUp] + public void Setup() + { + _connectionInitiator = Substitute.For(); + _previousSessionOpener = new PreviousSessionOpener(_connectionInitiator); + _connectionTree = Substitute.For(); + _connectionTree.GetRootConnectionNode().Returns(BuildTree()); + } + + [Test] + public void AllRequestedSessionsAreReopened() + { + _previousSessionOpener.Execute(_connectionTree); + _connectionInitiator.ReceivedWithAnyArgs(2).OpenConnection(new ConnectionInfo()); + } + + [Test] + public void ExceptionThrownWhenConstructorGivenNullArg() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new PreviousSessionOpener(null)); + } + + private RootNodeInfo BuildTree() + { + var root = new RootNodeInfo(RootNodeType.Connection); + root.AddChild(new ConnectionInfo { PleaseConnect = true }); + root.AddChild(new ConnectionInfo()); + root.AddChild(new ConnectionInfo { PleaseConnect = true }); + return root; + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/PreviouslyOpenedFolderExpanderTests.cs b/mRemoteNGTests/Tree/PreviouslyOpenedFolderExpanderTests.cs new file mode 100644 index 000000000..45df7c9d6 --- /dev/null +++ b/mRemoteNGTests/Tree/PreviouslyOpenedFolderExpanderTests.cs @@ -0,0 +1,49 @@ +using System.Linq; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; +using mRemoteNG.UI.Controls; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class PreviouslyOpenedFolderExpanderTests + { + private PreviouslyOpenedFolderExpander _folderExpander; + private IConnectionTree _connectionTree; + + [SetUp] + public void Setup() + { + _folderExpander = new PreviouslyOpenedFolderExpander(); + _connectionTree = Substitute.For(); + } + + [Test] + public void ExpandsAllFoldersThatAreMarkedForExpansion() + { + var connectionTreeModel = GenerateConnectionTreeModel(); + _connectionTree.ConnectionTreeModel.Returns(connectionTreeModel); + _connectionTree.GetRootConnectionNode().Returns(connectionTreeModel.RootNodes[0]); + _folderExpander.Execute(_connectionTree); + Assert.That(_connectionTree.ExpandedObjects, Is.EquivalentTo(connectionTreeModel.GetRecursiveChildList().OfType().Where(info => info.IsExpanded))); + } + + private ConnectionTreeModel GenerateConnectionTreeModel() + { + var connectionTreeModel = new ConnectionTreeModel(); + var root = new RootNodeInfo(RootNodeType.Connection) { IsExpanded = true }; + var folder1 = new ContainerInfo { IsExpanded = true }; + var folder2 = new ContainerInfo(); + var con1 = new ConnectionInfo(); + root.AddChild(folder1); + folder1.AddChild(folder2); + root.AddChild(con1); + connectionTreeModel.AddRootNode(root); + return connectionTreeModel; + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/Tree/SelectedConnectionDeletionConfirmerTests.cs b/mRemoteNGTests/Tree/SelectedConnectionDeletionConfirmerTests.cs new file mode 100644 index 000000000..ffab4e6b2 --- /dev/null +++ b/mRemoteNGTests/Tree/SelectedConnectionDeletionConfirmerTests.cs @@ -0,0 +1,47 @@ +using System.Windows.Forms; +using mRemoteNG.Connection; +using mRemoteNG.Tree; +using mRemoteNG.UI.Controls; +using NSubstitute; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tree +{ + public class SelectedConnectionDeletionConfirmerTests + { + private SelectedConnectionDeletionConfirmer _deletionConfirmer; + private IConnectionTree _connectionTree; + + [SetUp] + public void Setup() + { + _connectionTree = Substitute.For(); + _connectionTree.SelectedNode.Returns(new ConnectionInfo()); + } + + [Test] + public void ClickingYesReturnsTrue() + { + _deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickYes); + Assert.That(_deletionConfirmer.Confirm(), Is.True); + } + + [Test] + public void ClickingNoReturnsFalse() + { + _deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickNo); + Assert.That(_deletionConfirmer.Confirm(), Is.False); + } + + private DialogResult MockClickYes(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon) + { + return DialogResult.Yes; + } + + private DialogResult MockClickNo(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon) + { + return DialogResult.No; + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/UI/Window/ConnectionTreeWindowTests.cs b/mRemoteNGTests/UI/Window/ConnectionTreeWindowTests.cs new file mode 100644 index 000000000..1ea17109f --- /dev/null +++ b/mRemoteNGTests/UI/Window/ConnectionTreeWindowTests.cs @@ -0,0 +1,32 @@ +using System.Threading; +using mRemoteNG.UI.Window; +using NUnit.Framework; +using WeifenLuo.WinFormsUI.Docking; + + +namespace mRemoteNGTests.UI.Window +{ + public class ConnectionTreeWindowTests + { + private ConnectionTreeWindow _connectionTreeWindow; + + [SetUp] + public void Setup() + { + _connectionTreeWindow = new ConnectionTreeWindow(new DockContent()); + } + + [TearDown] + public void Teardown() + { + _connectionTreeWindow.Close(); + } + + [Test, Apartment(ApartmentState.STA)] + public void CanShowWindow() + { + _connectionTreeWindow.Show(); + Assert.That(_connectionTreeWindow.Visible); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index b1343dc61..b1d9ac8af 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -22,7 +22,7 @@ bin\Debug\ DEBUG;TRACE full - AnyCPU + x86 prompt MinimumRecommendedRules.ruleset @@ -31,7 +31,7 @@ TRACE true pdbonly - AnyCPU + x86 prompt MinimumRecommendedRules.ruleset @@ -40,7 +40,7 @@ bin\x86\Debug Portable\ TRACE;DEBUG;PORTABLE full - AnyCPU + x86 prompt MinimumRecommendedRules.ruleset @@ -49,7 +49,7 @@ TRACE;PORTABLE true pdbonly - AnyCPU + x86 prompt MinimumRecommendedRules.ruleset @@ -101,12 +101,15 @@ - + + False + + @@ -127,6 +130,7 @@ + @@ -146,8 +150,15 @@ + + + + + + + Form @@ -157,6 +168,7 @@ + @@ -207,6 +219,14 @@ + + + + + + + + diff --git a/mRemoteNGTests/mRemoteNGTests.csproj.DotSettings b/mRemoteNGTests/mRemoteNGTests.csproj.DotSettings new file mode 100644 index 000000000..1b5bada58 --- /dev/null +++ b/mRemoteNGTests/mRemoteNGTests.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/mRemoteV1/App/CompatibilityChecker.cs b/mRemoteV1/App/CompatibilityChecker.cs index a7e29265c..c69da026d 100644 --- a/mRemoteV1/App/CompatibilityChecker.cs +++ b/mRemoteV1/App/CompatibilityChecker.cs @@ -8,24 +8,23 @@ using System.Windows.Forms; namespace mRemoteNG.App { - public class CompatibilityChecker + public static class CompatibilityChecker { - public void CheckCompatibility() + public static void CheckCompatibility() { CheckFipsPolicy(); CheckLenovoAutoScrollUtility(); } - private void CheckFipsPolicy() + private static void CheckFipsPolicy() { - if (FipsPolicyEnabledForServer2003() || FipsPolicyEnabledForServer2008AndNewer()) - { - MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)); - Environment.Exit(1); - } + Logger.Instance.InfoFormat("Checking FIPS Policy..."); + if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return; + MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)); + Environment.Exit(1); } - private bool FipsPolicyEnabledForServer2003() + private static bool FipsPolicyEnabledForServer2003() { var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa"); var fipsPolicy = regKey?.GetValue("FIPSAlgorithmPolicy"); @@ -34,7 +33,7 @@ namespace mRemoteNG.App return (int)fipsPolicy != 0; } - private bool FipsPolicyEnabledForServer2008AndNewer() + private static bool FipsPolicyEnabledForServer2008AndNewer() { var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa\\FIPSAlgorithmPolicy"); var fipsPolicy = regKey?.GetValue("Enabled"); @@ -43,12 +42,14 @@ namespace mRemoteNG.App return (int)fipsPolicy != 0; } - private void CheckLenovoAutoScrollUtility() + private static void CheckLenovoAutoScrollUtility() { + Logger.Instance.InfoFormat("Checking Lenovo AutoScroll Utility..."); + if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility) return; - Process[] proccesses = new Process[] { }; + var proccesses = new Process[] { }; try { proccesses = Process.GetProcessesByName("virtscrl"); @@ -58,12 +59,10 @@ namespace mRemoteNG.App Runtime.MessageCollector.AddExceptionMessage("Error in CheckLenovoAutoScrollUtility", ex); } - if (proccesses.Length > 0) - { - 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; - } + 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); + if (CTaskDialog.VerificationChecked) + Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false; } } } diff --git a/mRemoteV1/App/Export.cs b/mRemoteV1/App/Export.cs index 15af5ac03..bcbb52c92 100644 --- a/mRemoteV1/App/Export.cs +++ b/mRemoteV1/App/Export.cs @@ -34,7 +34,7 @@ namespace mRemoteNG.App } if (exportForm.ShowDialog(frmMain.Default) != DialogResult.OK) - return ; + return; ConnectionInfo exportTarget; switch (exportForm.Scope) @@ -76,12 +76,17 @@ namespace mRemoteNG.App var factory = new CryptographyProviderFactory(); var cryptographyProvider = factory.CreateAeadCryptographyProvider(mRemoteNG.Settings.Default.EncryptionEngine, mRemoteNG.Settings.Default.EncryptionBlockCipherMode); cryptographyProvider.KeyDerivationIterations = Settings.Default.EncryptionKeyDerivationIterations; - serializer = new XmlConnectionsSerializer(cryptographyProvider); - ((XmlConnectionsSerializer) serializer).SaveFilter = saveFilter; + serializer = new XmlConnectionsSerializer(cryptographyProvider) + { + Export = true, + SaveFilter = saveFilter + }; break; case ConnectionsSaver.Format.mRCSV: - serializer = new CsvConnectionsSerializerMremotengFormat(); - ((CsvConnectionsSerializerMremotengFormat)serializer).SaveFilter = saveFilter; + serializer = new CsvConnectionsSerializerMremotengFormat + { + SaveFilter = saveFilter + }; break; default: throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null); diff --git a/mRemoteV1/App/Info/GeneralAppInfo.cs b/mRemoteV1/App/Info/GeneralAppInfo.cs index 304fcd652..ff98ea5b7 100644 --- a/mRemoteV1/App/Info/GeneralAppInfo.cs +++ b/mRemoteV1/App/Info/GeneralAppInfo.cs @@ -11,23 +11,27 @@ namespace mRemoteNG.App.Info { public static class GeneralAppInfo { - public static readonly string UrlHome = "http://www.mremoteng.org/"; - public static readonly string UrlDonate = "http://donate.mremoteng.org/"; - public static readonly string UrlForum = "http://forum.mremoteng.org/"; - public static readonly string UrlBugs = "http://bugs.mremoteng.org/"; - public static readonly string ApplicationVersion = Application.ProductVersion; + public const string UrlHome = "http://www.mremoteng.org/"; + public const string UrlDonate = "http://donate.mremoteng.org/"; + public const string UrlForum = "http://forum.mremoteng.org/"; + public const string UrlBugs = "http://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 HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); - public static string ReportingFilePath = ""; + //public static string ReportingFilePath = ""; public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe"; public static string UserAgent { get { - var details = new List(); - details.Add("compatible"); - details.Add(OSVersion.Platform == PlatformID.Win32NT ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}": OSVersion.VersionString); + var details = new List + { + "compatible", + OSVersion.Platform == PlatformID.Win32NT + ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}" + : OSVersion.VersionString + }; if (Is64BitProcess) { details.Add("WOW64"); diff --git a/mRemoteV1/App/Info/UpdateChannelInfo.cs b/mRemoteV1/App/Info/UpdateChannelInfo.cs index 1dac711c6..1ec19d9fb 100644 --- a/mRemoteV1/App/Info/UpdateChannelInfo.cs +++ b/mRemoteV1/App/Info/UpdateChannelInfo.cs @@ -1,34 +1,72 @@ -namespace mRemoteNG.App.Info +using System; + +namespace mRemoteNG.App.Info { public static class UpdateChannelInfo { - public static string FileName + public const string STABLE = "Stable"; + public const string BETA = "Beta"; + public const string DEV = "Development"; + + /* no #if here since they are used for unit tests as well */ + public const string STABLE_PORTABLE = "update-portable.txt"; + public const string BETA_PORTABLE = "beta-update-portable.txt"; + public const string DEV_PORTABLE = "dev-update-portable.txt"; + + public const string STABLE_MSI = "update.txt"; + public const string BETA_MSI = "beta-update.txt"; + public const string DEV_MSI = "dev-update.txt"; + + + public static Uri GetUpdateChannelInfo() + { + var channel = IsValidChannel(Settings.Default.UpdateChannel) ? Settings.Default.UpdateChannel : STABLE; + return GetUpdateTxtUri(channel); + } + + private static string GetChannelFileName(string channel) { #if PORTABLE - get - { /* */ /* return PORTABLE update files here */ /* */ -#if DEBUG - return "update-portable-debug.txt"; -#else - return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-portable-debug.txt" : "update-portable.txt"; -#endif - } + switch (channel) + { + case STABLE: + return STABLE_PORTABLE; + case BETA: + return BETA_PORTABLE; + case DEV: + return DEV_PORTABLE; + default: + return STABLE_PORTABLE; + } #else //NOT portable - get - { /* */ /* return INSTALLER update files here */ /* */ -#if DEBUG - return "update-debug.txt"; -#else - return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-debug.txt" : "update.txt"; -#endif - } + switch (channel) + { + case STABLE: + return STABLE_MSI; + case BETA: + return BETA_MSI; + case DEV: + return DEV_MSI; + default: + return STABLE_MSI; + } #endif //endif for PORTABLE } + + private static Uri GetUpdateTxtUri(string channel) + { + return new Uri(new Uri(Settings.Default.UpdateAddress), new Uri(GetChannelFileName(channel), UriKind.Relative)); + } + + private static bool IsValidChannel(string s) + { + return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV); + } } } \ No newline at end of file diff --git a/mRemoteV1/App/NativeMethods.cs b/mRemoteV1/App/NativeMethods.cs index 6b3ed452a..41127e1ee 100644 --- a/mRemoteV1/App/NativeMethods.cs +++ b/mRemoteV1/App/NativeMethods.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Runtime.InteropServices; +#pragma warning disable 169 namespace mRemoteNG.App { @@ -326,6 +327,11 @@ 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. + /// + public const int WM_SETCURSOR = 0x20; + /// /// Sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function. /// diff --git a/mRemoteV1/App/Runtime.cs b/mRemoteV1/App/Runtime.cs index d99b8e5ed..f17259b38 100644 --- a/mRemoteV1/App/Runtime.cs +++ b/mRemoteV1/App/Runtime.cs @@ -33,7 +33,7 @@ namespace mRemoteNG.App #region Public Properties public static WindowList WindowList { get; set; } public static MessageCollector MessageCollector { get; set; } - public static Controls.NotificationAreaIcon NotificationAreaIcon { get; set; } + public static NotificationAreaIcon NotificationAreaIcon { get; set; } public static bool IsConnectionsFileLoaded { get; set; } public static RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; } // ReSharper disable once UnusedAutoPropertyAccessor.Local @@ -42,8 +42,8 @@ namespace mRemoteNG.App public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(); public static ConnectionTreeModel ConnectionTreeModel { - get { return Windows.TreeForm.ConnectionTreeModel; } - set { Windows.TreeForm.ConnectionTreeModel = value; } + get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; } + set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; } } #endregion @@ -237,7 +237,7 @@ namespace mRemoteNG.App // Load config connectionsLoader.ConnectionFileName = filename; ConnectionTreeModel = connectionsLoader.LoadConnections(false); - Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel; + Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel; } catch (Exception ex) { @@ -274,7 +274,7 @@ namespace mRemoteNG.App { if (withDialog) { - var loadDialog = Controls.ConnectionsLoadDialog(); + var loadDialog = ConnectionsLoadDialog(); if (loadDialog.ShowDialog() != DialogResult.OK) return; connectionsLoader.ConnectionFileName = loadDialog.FileName; } @@ -288,7 +288,7 @@ namespace mRemoteNG.App connectionsLoader.UseDatabase = Settings.Default.UseSQLServer; ConnectionTreeModel = connectionsLoader.LoadConnections(false); - Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel; + Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel; if (Settings.Default.UseSQLServer) { @@ -353,6 +353,16 @@ namespace mRemoteNG.App } } + private static OpenFileDialog ConnectionsLoadDialog() + { + return new OpenFileDialog + { + CheckFileExists = true, + InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath, + Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*" + }; + } + private static void CreateBackupFile(string fileName) { // This intentionally doesn't prune any existing backup files. We just assume the user doesn't want any new ones created. @@ -593,7 +603,8 @@ namespace mRemoteNG.App connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP; connectionInfo.SetDefaultPort(); connectionInfo.IsQuickConnect = true; - ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); + var connectionInitiator = new ConnectionInitiator(); + connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); } public static void GoToWebsite() diff --git a/mRemoteV1/App/Startup.cs b/mRemoteV1/App/Startup.cs index cd067324a..e78376c9e 100644 --- a/mRemoteV1/App/Startup.cs +++ b/mRemoteV1/App/Startup.cs @@ -1,11 +1,4 @@ -using mRemoteNG.App.Info; -using mRemoteNG.App.Update; -using mRemoteNG.Config.Connections; -using mRemoteNG.Connection; -using mRemoteNG.Messages; -using mRemoteNG.Tools; -using mRemoteNG.UI.Forms; -using System; +using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; @@ -14,22 +7,26 @@ using System.IO; using System.Management; using System.Threading; using System.Windows.Forms; +using mRemoteNG.App.Info; +using mRemoteNG.App.Update; +using mRemoteNG.Config.Connections; using mRemoteNG.Config.Connections.Multiuser; +using mRemoteNG.Connection; +using mRemoteNG.Messages; +using mRemoteNG.Tools; using mRemoteNG.UI; -using WeifenLuo.WinFormsUI.Docking; +using mRemoteNG.UI.Forms; namespace mRemoteNG.App { public class Startup { - private CompatibilityChecker _compatibilityChecker; private AppUpdater _appUpdate; public static Startup Instance { get; } = new Startup(); private Startup() { - _compatibilityChecker = new CompatibilityChecker(); _appUpdate = new AppUpdater(); } @@ -41,49 +38,31 @@ namespace mRemoteNG.App { Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture)); LogStartupData(); - _compatibilityChecker.CheckCompatibility(); + CompatibilityChecker.CheckCompatibility(); ParseCommandLineArgs(); IeBrowserEmulation.Register(); 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); } - public void SetDefaultLayout() + private static void GetConnectionIcons() { - frmMain.Default.pnlDock.Visible = false; - - frmMain.Default.pnlDock.DockLeftPortion = frmMain.Default.pnlDock.Width * 0.2; - frmMain.Default.pnlDock.DockRightPortion = frmMain.Default.pnlDock.Width * 0.2; - frmMain.Default.pnlDock.DockTopPortion = frmMain.Default.pnlDock.Height * 0.25; - frmMain.Default.pnlDock.DockBottomPortion = frmMain.Default.pnlDock.Height * 0.25; - - Windows.TreePanel.Show(frmMain.Default.pnlDock, DockState.DockLeft); - Windows.ConfigPanel.Show(frmMain.Default.pnlDock); - Windows.ConfigPanel.DockTo(Windows.TreePanel.Pane, DockStyle.Bottom, -1); - - Windows.ScreenshotForm.Hide(); - - frmMain.Default.pnlDock.Visible = true; - } - - private void GetConnectionIcons() - { - string iPath = GeneralAppInfo.HomePath + "\\Icons\\"; + var iPath = GeneralAppInfo.HomePath + "\\Icons\\"; if (Directory.Exists(iPath) == false) { return; } - foreach (string f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories)) + foreach (var f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories)) { - FileInfo fInfo = new FileInfo(f); + var fInfo = new FileInfo(f); Array.Resize(ref ConnectionIcon.Icons, ConnectionIcon.Icons.Length + 1); ConnectionIcon.Icons.SetValue(fInfo.Name.Replace(".ico", ""), ConnectionIcon.Icons.Length - 1); } } - private void LogStartupData() + private static void LogStartupData() { if (!Settings.Default.WriteLogFile) return; LogApplicationData(); @@ -93,17 +72,17 @@ namespace mRemoteNG.App LogCultureData(); } - private void LogSystemData() + private static void LogSystemData() { - string osData = GetOperatingSystemData(); - string architecture = GetArchitectureData(); + var osData = GetOperatingSystemData(); + var architecture = GetArchitectureData(); Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(Convert.ToString(s))))); } - private string GetOperatingSystemData() + private static string GetOperatingSystemData() { - string osVersion = string.Empty; - string servicePack = string.Empty; + var osVersion = string.Empty; + var servicePack = string.Empty; try { @@ -118,13 +97,13 @@ namespace mRemoteNG.App { Logger.Instance.WarnFormat($"Error retrieving operating system information from WMI. {ex.Message}"); } - string osData = string.Join(" ", new string[] { osVersion, servicePack }); + var osData = string.Join(" ", osVersion, servicePack); return osData; } - private string GetOSServicePack(string servicePack, ManagementObject managementObject) + private static string GetOSServicePack(string servicePack, ManagementObject managementObject) { - int servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion")); + var servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion")); if (servicePackNumber != 0) { servicePack = $"Service Pack {servicePackNumber}"; @@ -132,15 +111,15 @@ namespace mRemoteNG.App return servicePack; } - private string GetArchitectureData() + private static string GetArchitectureData() { - string architecture = string.Empty; + var architecture = string.Empty; try { foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get()) { var managementObject = (ManagementObject) o; - int addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth")); + var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth")); architecture = $"{addressWidth}-bit"; } } @@ -151,7 +130,7 @@ namespace mRemoteNG.App return architecture; } - private void LogApplicationData() + private static void LogApplicationData() { #if !PORTABLE Logger.Instance.InfoFormat($"{Application.ProductName} {Application.ProductVersion} starting."); @@ -161,17 +140,17 @@ namespace mRemoteNG.App #endif } - private void LogCmdLineArgs() + private static void LogCmdLineArgs() { Logger.Instance.InfoFormat($"Command Line: {Environment.GetCommandLineArgs()}"); } - private void LogCLRData() + private static void LogCLRData() { Logger.Instance.InfoFormat($"Microsoft .NET CLR {Environment.Version}"); } - private void LogCultureData() + private static void LogCultureData() { Logger.Instance.InfoFormat( $"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}"); @@ -197,7 +176,7 @@ namespace mRemoteNG.App return; } - DateTime 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; @@ -211,7 +190,7 @@ namespace mRemoteNG.App { if (frmMain.Default.InvokeRequired) { - frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), new object[] { sender, e }); + frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), sender, e); return; } @@ -225,7 +204,7 @@ namespace mRemoteNG.App } if (e.Error != null) { - throw (e.Error); + throw e.Error; } if (_appUpdate.IsUpdateAvailable()) @@ -240,13 +219,13 @@ namespace mRemoteNG.App } - private void ParseCommandLineArgs() + private static void ParseCommandLineArgs() { try { - CmdArgumentsInterpreter cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs()); + var cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs()); - string ConsParam = ""; + var ConsParam = ""; if (cmd["cons"] != null) { ConsParam = "cons"; @@ -256,7 +235,7 @@ namespace mRemoteNG.App ConsParam = "c"; } - string ResetPosParam = ""; + var ResetPosParam = ""; if (cmd["resetpos"] != null) { ResetPosParam = "resetpos"; @@ -266,7 +245,7 @@ namespace mRemoteNG.App ResetPosParam = "rp"; } - string ResetPanelsParam = ""; + var ResetPanelsParam = ""; if (cmd["resetpanels"] != null) { ResetPanelsParam = "resetpanels"; @@ -276,7 +255,7 @@ namespace mRemoteNG.App ResetPanelsParam = "rpnl"; } - string ResetToolbarsParam = ""; + var ResetToolbarsParam = ""; if (cmd["resettoolbar"] != null) { ResetToolbarsParam = "resettoolbar"; @@ -293,7 +272,7 @@ namespace mRemoteNG.App ResetToolbarsParam = "rtbr"; } - string NoReconnectParam = ""; + var NoReconnectParam = ""; if (cmd["noreconnect"] != null) { NoReconnectParam = "noreconnect"; @@ -313,7 +292,7 @@ namespace mRemoteNG.App Settings.Default.CustomConsPath = GeneralAppInfo.HomePath + "\\" + cmd[ConsParam]; return; } - else if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam])) + if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam])) { Settings.Default.LoadConsFromCustomLocation = true; Settings.Default.CustomConsPath = ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam]; diff --git a/mRemoteV1/App/Update/AppUpdater.cs b/mRemoteV1/App/Update/AppUpdater.cs index 7f406f07f..94462bce4 100644 --- a/mRemoteV1/App/Update/AppUpdater.cs +++ b/mRemoteV1/App/Update/AppUpdater.cs @@ -9,116 +9,120 @@ using mRemoteNG.Security.SymmetricEncryption; using System.Security.Cryptography; #if !PORTABLE using mRemoteNG.Tools; + #else using System.Windows.Forms; #endif namespace mRemoteNG.App.Update { - public class AppUpdater - { - private WebProxy _webProxy; + public class AppUpdater + { + private WebProxy _webProxy; private Thread _getUpdateInfoThread; private Thread _getChangeLogThread; -#region Public Properties + #region Public Properties + public UpdateInfo CurrentUpdateInfo { get; private set; } - public string ChangeLog { get; private set; } + public string ChangeLog { get; private set; } - public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive; + public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive; - private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive; + private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive; - public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null; + public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null; -#endregion - -#region Public Methods - public AppUpdater() - { - SetProxySettings(); - } + #endregion - private void SetProxySettings() - { - var shouldWeUseProxy = Settings.Default.UpdateUseProxy; - var proxyAddress = Settings.Default.UpdateProxyAddress; - var port = Settings.Default.UpdateProxyPort; - var useAuthentication = Settings.Default.UpdateProxyUseAuthentication; - var username = Settings.Default.UpdateProxyAuthUser; + #region Public Methods + + public AppUpdater() + { + SetProxySettings(); + } + + private void SetProxySettings() + { + var shouldWeUseProxy = Settings.Default.UpdateUseProxy; + var proxyAddress = Settings.Default.UpdateProxyAddress; + var port = Settings.Default.UpdateProxyPort; + var useAuthentication = Settings.Default.UpdateProxyUseAuthentication; + var username = Settings.Default.UpdateProxyAuthUser; var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey); + var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey); SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password); - } - - public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password) - { - if (useProxy && !string.IsNullOrEmpty(address)) - { - _webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address); + } - _webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null; - } - else - { - _webProxy = null; - } - } - - public bool IsUpdateAvailable() - { - if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) - { - return false; - } - - return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion(); - } - - public void GetUpdateInfoAsync() - { - if (IsGetUpdateInfoRunning) - { - _getUpdateInfoThread.Abort(); - } - - _getUpdateInfoThread = new Thread(GetUpdateInfo); - _getUpdateInfoThread.SetApartmentState(ApartmentState.STA); - _getUpdateInfoThread.IsBackground = true; - _getUpdateInfoThread.Start(); - } - - public void GetChangeLogAsync() - { - if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) - { - throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."); - } - - if (IsGetChangeLogRunning) - { - _getChangeLogThread.Abort(); - } - - _getChangeLogThread = new Thread(GetChangeLog); - _getChangeLogThread.SetApartmentState(ApartmentState.STA); - _getChangeLogThread.IsBackground = true; - _getChangeLogThread.Start(); - } - - public void DownloadUpdateAsync() - { - if (_downloadUpdateWebClient != null) - { - throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress."); - } - - if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) - { - throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); - } + public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password) + { + if (useProxy && !string.IsNullOrEmpty(address)) + { + _webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address); + + _webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null; + } + else + { + _webProxy = null; + } + } + + public bool IsUpdateAvailable() + { + if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) + { + return false; + } + + return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion(); + } + + public void GetUpdateInfoAsync() + { + if (IsGetUpdateInfoRunning) + { + _getUpdateInfoThread.Abort(); + } + + _getUpdateInfoThread = new Thread(GetUpdateInfo); + _getUpdateInfoThread.SetApartmentState(ApartmentState.STA); + _getUpdateInfoThread.IsBackground = true; + _getUpdateInfoThread.Start(); + } + + public void GetChangeLogAsync() + { + if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) + { + throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."); + } + + if (IsGetChangeLogRunning) + { + _getChangeLogThread.Abort(); + } + + _getChangeLogThread = new Thread(GetChangeLog); + _getChangeLogThread.SetApartmentState(ApartmentState.STA); + _getChangeLogThread.IsBackground = true; + _getChangeLogThread.Start(); + } + + public void DownloadUpdateAsync() + { + if (_downloadUpdateWebClient != null) + { + throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress."); + } + + if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) + { + throw new InvalidOperationException( + "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); + } #if !PORTABLE CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); #else @@ -138,166 +142,174 @@ namespace mRemoteNG.App.Update } #endif DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, CurrentUpdateInfo.UpdateFilePath); - } -#endregion - -#region Private Properties - private WebClient _downloadUpdateWebClient; - private WebClient DownloadUpdateWebClient - { - get - { - if (_downloadUpdateWebClient != null) - { - return _downloadUpdateWebClient; - } - - _downloadUpdateWebClient = CreateWebClient(); - - _downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged; - _downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted; - - return _downloadUpdateWebClient; - } - } -#endregion - -#region Private Methods - private WebClient CreateWebClient() - { - var webClient = new WebClient(); - webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent); - webClient.Proxy = _webProxy; - return webClient; - } - - private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, Exception exception, bool cancelled, object userToken) - { - var type = typeof(DownloadStringCompletedEventArgs); - const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; - Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)}; - var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null); - object[] arguments = {result, exception, cancelled, userToken}; + } - return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments); - } - - private DownloadStringCompletedEventArgs DownloadString(Uri address) - { - var webClient = CreateWebClient(); - var result = string.Empty; - Exception exception = null; - var cancelled = false; - - try - { - result = webClient.DownloadString(address); - } - catch (ThreadAbortException) - { - cancelled = true; - } - catch (Exception ex) - { - exception = ex; - } - - return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null); - } - - private void GetUpdateInfo() - { - var updateFileUri = new Uri(new Uri(Convert.ToString(Settings.Default.UpdateAddress)), new Uri(UpdateChannelInfo.FileName, UriKind.Relative)); - var e = DownloadString(updateFileUri); - - if (!e.Cancelled && e.Error == null) - { - CurrentUpdateInfo = UpdateInfo.FromString(e.Result); + #endregion + + #region Private Properties + + private WebClient _downloadUpdateWebClient; + + private WebClient DownloadUpdateWebClient + { + get + { + if (_downloadUpdateWebClient != null) + { + return _downloadUpdateWebClient; + } + + _downloadUpdateWebClient = CreateWebClient(); + + _downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged; + _downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted; + + return _downloadUpdateWebClient; + } + } + + #endregion + + #region Private Methods + + private WebClient CreateWebClient() + { + var webClient = new WebClient(); + webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent); + webClient.Proxy = _webProxy; + return webClient; + } + + private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, + Exception exception, bool cancelled, object userToken) + { + var type = typeof(DownloadStringCompletedEventArgs); + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; + Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)}; + var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null); + object[] arguments = {result, exception, cancelled, userToken}; + + return (DownloadStringCompletedEventArgs) constructor.Invoke(arguments); + } + + public DownloadStringCompletedEventArgs DownloadString(Uri address) + { + var webClient = CreateWebClient(); + var result = string.Empty; + Exception exception = null; + var cancelled = false; + + try + { + result = webClient.DownloadString(address); + } + catch (ThreadAbortException) + { + cancelled = true; + } + catch (Exception ex) + { + exception = ex; + } + + return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null); + } + + private void GetUpdateInfo() + { + var e = DownloadString(UpdateChannelInfo.GetUpdateChannelInfo()); + + if (!e.Cancelled && e.Error == null) + { + CurrentUpdateInfo = UpdateInfo.FromString(e.Result); Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow; - if (!Settings.Default.UpdatePending) - { + if (!Settings.Default.UpdatePending) + { Settings.Default.UpdatePending = IsUpdateAvailable(); - } - } + } + } GetUpdateInfoCompletedEventEvent?.Invoke(this, e); } - - private void GetChangeLog() - { - var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress); - - if (!e.Cancelled && e.Error == null) - { - ChangeLog = e.Result; - } + + private void GetChangeLog() + { + var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress); + + if (!e.Cancelled && e.Error == null) + { + ChangeLog = e.Result; + } GetChangeLogCompletedEventEvent?.Invoke(this, e); } - - private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { + + private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { DownloadUpdateProgressChangedEventEvent?.Invoke(sender, e); } - - private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) - { - var raiseEventArgs = e; - - if (!e.Cancelled && e.Error == null) - { - try - { + + private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) + { + var raiseEventArgs = e; + + if (!e.Cancelled && e.Error == null) + { + try + { #if !PORTABLE var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath) - { - RequireThumbprintMatch = true, - ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint - }; + { + RequireThumbprintMatch = true, + ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint + }; - if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified) - { - if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException) - { - throw (updateAuthenticode.Exception); - } + if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified) + { + if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException) + { + throw updateAuthenticode.Exception; + } - throw (new Exception(updateAuthenticode.StatusMessage)); - } + throw new Exception(updateAuthenticode.StatusMessage); + } #endif - using (var md5 = MD5.Create()) + using (var cksum = SHA512.Create()) { using (var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath)) { - var hash = md5.ComputeHash(stream); + var hash = cksum.ComputeHash(stream); var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant(); if (!hashString.Equals(CurrentUpdateInfo.Checksum)) - throw new Exception("MD5 Hashes didn't match!"); + throw new Exception("SHA512 Hashes didn't match!"); } } } - catch (Exception ex) - { - raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null); - } - } - - if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null) - { - File.Delete(CurrentUpdateInfo.UpdateFilePath); - } + catch (Exception ex) + { + raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null); + } + } + + if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null) + { + File.Delete(CurrentUpdateInfo.UpdateFilePath); + } DownloadUpdateCompletedEventEvent?.Invoke(this, raiseEventArgs); _downloadUpdateWebClient.Dispose(); - _downloadUpdateWebClient = null; - } -#endregion - -#region Events + _downloadUpdateWebClient = null; + } + + #endregion + + #region Events + private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent; + public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent { add @@ -311,6 +323,7 @@ namespace mRemoteNG.App.Update } private AsyncCompletedEventHandler GetChangeLogCompletedEventEvent; + public event AsyncCompletedEventHandler GetChangeLogCompletedEvent { add @@ -323,7 +336,8 @@ namespace mRemoteNG.App.Update } } - private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent; + private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent; + public event DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEvent { add @@ -337,6 +351,7 @@ namespace mRemoteNG.App.Update } private AsyncCompletedEventHandler DownloadUpdateCompletedEventEvent; + public event AsyncCompletedEventHandler DownloadUpdateCompletedEvent { add @@ -348,6 +363,7 @@ namespace mRemoteNG.App.Update DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value); } } -#endregion - } + + #endregion + } } \ No newline at end of file diff --git a/mRemoteV1/App/Update/UpdateInfo.cs b/mRemoteV1/App/Update/UpdateInfo.cs index 2deee4040..9255ef16e 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 { @@ -14,7 +15,8 @@ namespace mRemoteNG.App.Update #if !PORTABLE public string CertificateThumbprint { get; private set; } #endif - public string FileName { get; private set; } + // ReSharper disable once MemberCanBePrivate.Global + public string FileName { get; set; } public string Checksum { get; private set; } public static UpdateInfo FromString(string input) @@ -30,16 +32,45 @@ namespace mRemoteNG.App.Update newInfo.Version = updateFile.GetVersion(); newInfo.DownloadAddress = updateFile.GetUri("dURL"); newInfo.ChangeLogAddress = updateFile.GetUri("clURL"); +#if false newInfo.ImageAddress = updateFile.GetUri("imgURL"); newInfo.ImageLinkAddress = updateFile.GetUri("imgURLLink"); +#endif #if !PORTABLE newInfo.CertificateThumbprint = updateFile.GetThumbprint(); #endif newInfo.FileName = updateFile.GetFileName(); newInfo.Checksum = updateFile.GetChecksum(); - newInfo.IsValid = true; + newInfo.IsValid = newInfo.CheckIfValid(); } return newInfo; } + + public bool CheckIfValid() + { + if (string.IsNullOrEmpty(Version.ToString())) + return false; + if(string.IsNullOrEmpty(DownloadAddress.AbsoluteUri)) + return false; + if (string.IsNullOrEmpty(ChangeLogAddress.AbsoluteUri)) + return false; +#if false + if (string.IsNullOrEmpty(ImageAddress.AbsoluteUri)) + return false; + if (string.IsNullOrEmpty(ImageLinkAddress.AbsoluteUri)) + return false; +#endif +#if !PORTABLE + if (string.IsNullOrEmpty(CertificateThumbprint)) + return false; +#endif + if (string.IsNullOrEmpty(FileName)) + return false; + // ReSharper disable once ConvertIfStatementToReturnStatement + if (string.IsNullOrEmpty(Checksum)) + return false; + + return true; + } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Connections/ConnectionsSaver.cs b/mRemoteV1/Config/Connections/ConnectionsSaver.cs index 6b4339e62..0059ca1b4 100644 --- a/mRemoteV1/Config/Connections/ConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/ConnectionsSaver.cs @@ -89,7 +89,7 @@ namespace mRemoteNG.Config.Connections if (!VerifyDatabaseVersion(sqlConnector)) { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed); - return ; + return; } var rootTreeNode = Runtime.ConnectionTreeModel.RootNodes.OfType().First(); diff --git a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs index 98366a945..5801a57bf 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs @@ -130,7 +130,7 @@ namespace mRemoteNG.Config.Putty if (_eventWatcher != null) { - return ; + return; } try @@ -158,7 +158,7 @@ namespace mRemoteNG.Config.Putty if (_eventWatcher == null) { - return ; + return; } _eventWatcher.EnableRaisingEvents = false; _eventWatcher.Dispose(); @@ -231,7 +231,7 @@ namespace mRemoteNG.Config.Putty { if (!File.Exists(_puttyConfFile)) { - return ; + return; } using (var streamReader = new StreamReader(_puttyConfFile)) { @@ -299,7 +299,7 @@ namespace mRemoteNG.Config.Putty { if (!File.Exists(_sessionFile)) { - return ; + return; } using (var streamReader = new StreamReader(_sessionFile)) { diff --git a/mRemoteV1/Config/Serializers/ActiveDirectoryDeserializer.cs b/mRemoteV1/Config/Serializers/ActiveDirectoryDeserializer.cs index f98beb5f2..c8835c92d 100644 --- a/mRemoteV1/Config/Serializers/ActiveDirectoryDeserializer.cs +++ b/mRemoteV1/Config/Serializers/ActiveDirectoryDeserializer.cs @@ -66,7 +66,7 @@ namespace mRemoteNG.Config.Serializers // check/continue here so we don't create empty connection objects if(!_importSubOU) continue; - ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer); + ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOU); continue; } diff --git a/mRemoteV1/Config/Serializers/DataTableDeserializer.cs b/mRemoteV1/Config/Serializers/DataTableDeserializer.cs index 1b06134e7..86098c628 100644 --- a/mRemoteV1/Config/Serializers/DataTableDeserializer.cs +++ b/mRemoteV1/Config/Serializers/DataTableDeserializer.cs @@ -84,6 +84,8 @@ namespace mRemoteNG.Config.Serializers connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), (string)dataRow["RenderingEngine"]); connectionInfo.ICAEncryptionStrength = (ProtocolICA.EncryptionStrength)Enum.Parse(typeof(ProtocolICA.EncryptionStrength), (string)dataRow["ICAEncryptionStrength"]); connectionInfo.RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel)Enum.Parse(typeof(ProtocolRDP.AuthenticationLevel), (string)dataRow["RDPAuthenticationLevel"]); + connectionInfo.RDPMinutesToIdleTimeout = (int)dataRow["RDPMinutesToIdleTimeout"]; + connectionInfo.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"]; connectionInfo.LoadBalanceInfo = (string)dataRow["LoadBalanceInfo"]; connectionInfo.Colors = (ProtocolRDP.RDPColors)Enum.Parse(typeof(ProtocolRDP.RDPColors) ,(string)dataRow["Colors"]); connectionInfo.Resolution = (ProtocolRDP.RDPResolutions)Enum.Parse(typeof(ProtocolRDP.RDPResolutions), (string)dataRow["Resolution"]); @@ -153,6 +155,8 @@ namespace mRemoteNG.Config.Serializers connectionInfo.Inheritance.Username = (bool)dataRow["InheritUsername"]; connectionInfo.Inheritance.ICAEncryptionStrength = (bool)dataRow["InheritICAEncryptionStrength"]; connectionInfo.Inheritance.RDPAuthenticationLevel = (bool)dataRow["InheritRDPAuthenticationLevel"]; + connectionInfo.Inheritance.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"]; + connectionInfo.Inheritance.RDPMinutesToIdleTimeout = (bool)dataRow["RDPMinutesToIdleTimeout"]; connectionInfo.Inheritance.LoadBalanceInfo = (bool)dataRow["InheritLoadBalanceInfo"]; connectionInfo.Inheritance.PreExtApp = (bool)dataRow["InheritPreExtApp"]; connectionInfo.Inheritance.PostExtApp = (bool)dataRow["InheritPostExtApp"]; diff --git a/mRemoteV1/Config/Serializers/DataTableSerializer.cs b/mRemoteV1/Config/Serializers/DataTableSerializer.cs index 50974069a..0e2daefa0 100644 --- a/mRemoteV1/Config/Serializers/DataTableSerializer.cs +++ b/mRemoteV1/Config/Serializers/DataTableSerializer.cs @@ -65,6 +65,8 @@ namespace mRemoteNG.Config.Serializers _dataTable.Columns.Add("RenderingEngine", typeof(string)); _dataTable.Columns.Add("ICAEncryptionStrength", typeof(string)); _dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string)); + _dataTable.Columns.Add("RDPMinutesToIdleTimeout", typeof(int)); + _dataTable.Columns.Add("RDPAlertIdleTimeout", typeof(bool)); _dataTable.Columns.Add("Colors", typeof(string)); _dataTable.Columns.Add("Resolution", typeof(string)); _dataTable.Columns.Add("DisplayWallpaper", typeof(bool)); @@ -128,6 +130,8 @@ namespace mRemoteNG.Config.Serializers _dataTable.Columns.Add("InheritRenderingEngine", typeof(bool)); _dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool)); _dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool)); + _dataTable.Columns.Add("InheritRDPMinutesToIdleTimeout", typeof(bool)); + _dataTable.Columns.Add("InheritRDPAlertIdleTimeout", typeof(bool)); _dataTable.Columns.Add("InheritUsername", typeof(bool)); _dataTable.Columns.Add("InheritPreExtApp", typeof(bool)); _dataTable.Columns.Add("InheritPostExtApp", typeof(bool)); @@ -200,6 +204,8 @@ namespace mRemoteNG.Config.Serializers dataRow["RenderingEngine"] = connectionInfo.RenderingEngine; dataRow["ICAEncryptionStrength"] = connectionInfo.ICAEncryptionStrength; dataRow["RDPAuthenticationLevel"] = connectionInfo.RDPAuthenticationLevel; + //dataRow["RDPMinutesToIdleTimeout"] = connectionInfo.RDPMinutesToIdleTimeout; + //dataRow["RDPAlertIdleTimeout"] = connectionInfo.RDPAlertIdleTimeout; dataRow["LoadBalanceInfo"] = connectionInfo.LoadBalanceInfo; dataRow["Colors"] = connectionInfo.Colors; dataRow["Resolution"] = connectionInfo.Resolution; @@ -270,6 +276,8 @@ namespace mRemoteNG.Config.Serializers dataRow["InheritUsername"] = connectionInfo.Inheritance.Username; dataRow["InheritICAEncryptionStrength"] = connectionInfo.Inheritance.ICAEncryptionStrength; dataRow["InheritRDPAuthenticationLevel"] = connectionInfo.Inheritance.RDPAuthenticationLevel; + //dataRow["InheritRDPMinutesToIdleTimeout"] = connectionInfo.Inheritance.RDPMinutesToIdleTimeout; + //dataRow["InheritRDPAlertIdleTimeout"] = connectionInfo.Inheritance.RDPAlertIdleTimeout; dataRow["InheritLoadBalanceInfo"] = connectionInfo.Inheritance.LoadBalanceInfo; dataRow["InheritPreExtApp"] = connectionInfo.Inheritance.PreExtApp; dataRow["InheritPostExtApp"] = connectionInfo.Inheritance.PostExtApp; @@ -325,6 +333,8 @@ namespace mRemoteNG.Config.Serializers dataRow["InheritUsername"] = false; dataRow["InheritICAEncryptionStrength"] = false; dataRow["InheritRDPAuthenticationLevel"] = false; + //dataRow["InheritRDPMinutesToIdleTimeout"] = false; + //dataRow["InheritRDPAlertIdleTimeout"] = false; dataRow["InheritLoadBalanceInfo"] = false; dataRow["InheritPreExtApp"] = false; dataRow["InheritPostExtApp"] = false; diff --git a/mRemoteV1/Config/Serializers/XmlConnectionNodeSerializer.cs b/mRemoteV1/Config/Serializers/XmlConnectionNodeSerializer.cs index fd75bad05..0ec493f24 100644 --- a/mRemoteV1/Config/Serializers/XmlConnectionNodeSerializer.cs +++ b/mRemoteV1/Config/Serializers/XmlConnectionNodeSerializer.cs @@ -44,6 +44,7 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("Descr", connectionInfo.Description)); element.Add(new XAttribute("Icon", connectionInfo.Icon)); element.Add(new XAttribute("Panel", connectionInfo.Panel)); + element.Add(new XAttribute("Id", connectionInfo.ConstantID)); element.Add(_saveFilter.SaveUsername ? new XAttribute("Username", connectionInfo.Username) @@ -67,6 +68,8 @@ namespace mRemoteNG.Config.Serializers 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)); element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); element.Add(new XAttribute("Colors", connectionInfo.Colors)); element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); @@ -159,6 +162,8 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString())); element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString())); element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString())); element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString())); element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString())); element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString())); @@ -214,6 +219,8 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("InheritUsername", false.ToString())); element.Add(new XAttribute("InheritICAEncryptionStrength", false.ToString())); element.Add(new XAttribute("InheritRDPAuthenticationLevel", false.ToString())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", false.ToString())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", false.ToString())); element.Add(new XAttribute("InheritLoadBalanceInfo", false.ToString())); element.Add(new XAttribute("InheritPreExtApp", false.ToString())); element.Add(new XAttribute("InheritPostExtApp", false.ToString())); diff --git a/mRemoteV1/Config/Serializers/XmlConnectionsDeserializer.cs b/mRemoteV1/Config/Serializers/XmlConnectionsDeserializer.cs index 3fd113c93..2ddf19538 100644 --- a/mRemoteV1/Config/Serializers/XmlConnectionsDeserializer.cs +++ b/mRemoteV1/Config/Serializers/XmlConnectionsDeserializer.cs @@ -485,8 +485,13 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 2.6) { + connectionInfo.ConstantID = xmlnode.Attributes["Id"]?.Value ?? connectionInfo.ConstantID; connectionInfo.SoundQuality = (ProtocolRDP.RDPSoundQuality)Tools.MiscTools.StringToEnum(typeof(ProtocolRDP.RDPSoundQuality), Convert.ToString(xmlnode.Attributes["SoundQuality"].Value)); connectionInfo.Inheritance.SoundQuality = bool.Parse(xmlnode.Attributes["InheritSoundQuality"].Value); + connectionInfo.RDPMinutesToIdleTimeout = Convert.ToInt32(xmlnode.Attributes["RDPMinutesToIdleTimeout"]?.Value ?? "0"); + connectionInfo.Inheritance.RDPMinutesToIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPMinutesToIdleTimeout"]?.Value ?? "False"); + connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False"); + connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False"); } } catch (Exception ex) diff --git a/mRemoteV1/Config/Settings/LayoutSettingsLoader.cs b/mRemoteV1/Config/Settings/LayoutSettingsLoader.cs index 027cfb896..1728e8b97 100644 --- a/mRemoteV1/Config/Settings/LayoutSettingsLoader.cs +++ b/mRemoteV1/Config/Settings/LayoutSettingsLoader.cs @@ -48,7 +48,7 @@ namespace mRemoteNG.Config.Settings } else { - Startup.Instance.SetDefaultLayout(); + frmMain.Default.SetDefaultLayout(); } } catch (Exception ex) diff --git a/mRemoteV1/Config/Settings/SettingsLoader.cs b/mRemoteV1/Config/Settings/SettingsLoader.cs index cd1d475c1..0680e07dd 100644 --- a/mRemoteV1/Config/Settings/SettingsLoader.cs +++ b/mRemoteV1/Config/Settings/SettingsLoader.cs @@ -9,6 +9,7 @@ using mRemoteNG.Themes; using mRemoteNG.Connection.Protocol; using mRemoteNG.App.Info; using mRemoteNG.Security.SymmetricEncryption; +using mRemoteNG.Tools; using mRemoteNG.UI.Forms; @@ -137,14 +138,14 @@ namespace mRemoteNG.Config.Settings private void SetKioskMode() { if (!mRemoteNG.Settings.Default.MainFormKiosk) return; - MainForm.Fullscreen.Value = true; + MainForm._fullscreen.Value = true; MainForm.mMenViewFullscreen.Checked = true; } private static void SetShowSystemTrayIcon() { if (mRemoteNG.Settings.Default.ShowSystemTrayIcon) - Runtime.NotificationAreaIcon = new Tools.Controls.NotificationAreaIcon(); + Runtime.NotificationAreaIcon = new NotificationAreaIcon(); } private static void SetPuttyPath() diff --git a/mRemoteV1/Config/Settings/SettingsSaver.cs b/mRemoteV1/Config/Settings/SettingsSaver.cs index 53ebaa708..90be71668 100644 --- a/mRemoteV1/Config/Settings/SettingsSaver.cs +++ b/mRemoteV1/Config/Settings/SettingsSaver.cs @@ -36,9 +36,9 @@ namespace mRemoteNG.Config.Settings mRemoteNG.Settings.Default.MainFormState = with1.WindowState; - if (with1.Fullscreen != null) + if (with1._fullscreen != null) { - mRemoteNG.Settings.Default.MainFormKiosk = with1.Fullscreen.Value; + mRemoteNG.Settings.Default.MainFormKiosk = with1._fullscreen.Value; } mRemoteNG.Settings.Default.FirstStart = false; diff --git a/mRemoteV1/Connection/AbstractConnectionInfoData.cs b/mRemoteV1/Connection/AbstractConnectionInfoData.cs index a10a9d8e1..86e4fd7f2 100644 --- a/mRemoteV1/Connection/AbstractConnectionInfoData.cs +++ b/mRemoteV1/Connection/AbstractConnectionInfoData.cs @@ -30,6 +30,8 @@ namespace mRemoteNG.Connection private ProtocolICA.EncryptionStrength _icaEncryption; private bool _useConsoleSession; private ProtocolRDP.AuthenticationLevel _rdpAuthenticationLevel; + private int _rdpMinutesToIdleTimeout; + private bool _rdpAlertIdleTimeout; private string _loadBalanceInfo; private HTTPBase.RenderingEngine _renderingEngine; private bool _useCredSsp; @@ -225,6 +227,30 @@ namespace mRemoteNG.Connection set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); } } + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPMinutesToIdleTimeout"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")] + public virtual int RDPMinutesToIdleTimeout + { + get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); } + set { + if(value < 0) { + value = 0; + } else if(value > 240) { + value = 240; + } + SetField(ref _rdpMinutesToIdleTimeout, value, "RDPMinutesToIdleTimeout"); + } + } + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPAlertIdleTimeout"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")] + public bool RDPAlertIdleTimeout + { + get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); } + set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); } + } + [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), LocalizedAttributes.LocalizedDisplayName("strPropertyNameLoadBalanceInfo"), LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")] diff --git a/mRemoteV1/Connection/ConnectionInfo.cs b/mRemoteV1/Connection/ConnectionInfo.cs index 19b388e8c..8d00dec50 100644 --- a/mRemoteV1/Connection/ConnectionInfo.cs +++ b/mRemoteV1/Connection/ConnectionInfo.cs @@ -248,6 +248,8 @@ namespace mRemoteNG.Connection ICAEncryptionStrength = (ProtocolICA.EncryptionStrength) Enum.Parse(typeof(ProtocolICA.EncryptionStrength), Settings.Default.ConDefaultICAEncryptionStrength); UseConsoleSession = Settings.Default.ConDefaultUseConsoleSession; RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel) Enum.Parse(typeof(ProtocolRDP.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); UseCredSsp = Settings.Default.ConDefaultUseCredSsp; diff --git a/mRemoteV1/Connection/ConnectionInfoInheritance.cs b/mRemoteV1/Connection/ConnectionInfoInheritance.cs index fb1862238..3d149c088 100644 --- a/mRemoteV1/Connection/ConnectionInfoInheritance.cs +++ b/mRemoteV1/Connection/ConnectionInfoInheritance.cs @@ -83,9 +83,19 @@ namespace mRemoteNG.Connection [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationLevel"), LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationLevel"), - TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4), + 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;} diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index e6cd952a4..68729e225 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -12,14 +12,52 @@ using TabPage = Crownwood.Magic.Controls.TabPage; namespace mRemoteNG.Connection { - public static class ConnectionInitiator + public class ConnectionInitiator : IConnectionInitiator { - public static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) + public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) { OpenConnection(containerInfo, force, null); } - private static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm) + 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) + { + 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 tabPage = (TabPage)interfaceControl.Parent; + tabPage.Selected = true; + return true; + } + + #region Private + private void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm) { var children = containerInfo.Children; if (children.Count == 0) return; @@ -33,31 +71,7 @@ namespace mRemoteNG.Connection } } - public static void OpenConnection(ConnectionInfo connectionInfo) - { - try - { - OpenConnection(connectionInfo, ConnectionInfo.Force.None); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message); - } - } - - public static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force) - { - try - { - OpenConnection(connectionInfo, force, null); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message); - } - } - - private static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm) + private void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm) { try { @@ -104,7 +118,7 @@ namespace mRemoteNG.Connection } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex); } } @@ -115,19 +129,6 @@ namespace mRemoteNG.Connection extA?.Start(connectionInfo); } - public static bool SwitchToOpenConnection(ConnectionInfo nCi) - { - var IC = FindConnectionContainer(nCi); - if (IC == null) return false; - var connectionWindow = (ConnectionWindow)IC.FindForm(); - connectionWindow?.Focus(); - var findForm = (ConnectionWindow)IC.FindForm(); - findForm?.Show(frmMain.Default.pnlDock); - var tabPage = (TabPage)IC.Parent; - tabPage.Selected = true; - return true; - } - private static InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo) { if (connectionInfo.OpenConnections.Count <= 0) return null; @@ -185,11 +186,15 @@ namespace mRemoteNG.Connection { Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo); - if (connectionInfo.Protocol == ProtocolType.IntApp) - { - if (Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon != null) - ((TabPage)connectionContainer).Icon = Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon; - } + if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer; + + var extT = Runtime.GetExtAppByName(connectionInfo.ExtApp); + + if(extT == null) return connectionContainer; + + if (extT.Icon != null) + ((TabPage)connectionContainer).Icon = extT.Icon; + return connectionContainer; } @@ -210,10 +215,9 @@ namespace mRemoteNG.Connection { newProtocol.InterfaceControl = new InterfaceControl(connectionContainer, newProtocol, connectionInfo); } + #endregion - - - + #region Event handlers private static void Prot_Event_Disconnected(object sender, string disconnectedMessage) { try @@ -230,7 +234,7 @@ namespace mRemoteNG.Connection } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strProtocolEventDisconnectFailed, ex.Message), true); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strProtocolEventDisconnectFailed, ex); } } @@ -240,7 +244,15 @@ namespace mRemoteNG.Connection { var Prot = (ProtocolBase)sender; Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent, true); - Runtime.MessageCollector.AddMessage(MessageClass.ReportMsg, string.Format(Language.strConnenctionClosedByUser, Prot.InterfaceControl.Info.Hostname, Prot.InterfaceControl.Info.Protocol.ToString(), Environment.UserName)); + string connDetail; + 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.ReportMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, Prot.InterfaceControl.Info.Protocol, Environment.UserName)); Prot.InterfaceControl.Info.OpenConnections.Remove(Prot); if (Prot.InterfaceControl.Info.PostExtApp == "") return; @@ -249,7 +261,7 @@ namespace mRemoteNG.Connection } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnenctionCloseEventFailed + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnenctionCloseEventFailed, ex); } } @@ -273,8 +285,9 @@ namespace mRemoteNG.Connection } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionEventConnectionFailed + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionEventConnectionFailed, ex); } } + #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Connection/DefaultConnectionInfo.cs b/mRemoteV1/Connection/DefaultConnectionInfo.cs index 8f7e3b742..156df57ad 100644 --- a/mRemoteV1/Connection/DefaultConnectionInfo.cs +++ b/mRemoteV1/Connection/DefaultConnectionInfo.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using mRemoteNG.App; namespace mRemoteNG.Connection @@ -39,15 +40,17 @@ namespace mRemoteNG.Connection var inheritanceProperties = GetProperties(_excludedProperties); foreach (var property in inheritanceProperties) { - var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name)); - var localValue = property.GetValue(Instance, null); - - var descriptor = TypeDescriptor.GetProperties(Instance)[property.Name]; - var converter = descriptor.Converter; - if (converter != null && converter.CanConvertFrom(localValue.GetType())) - propertyFromDestination.SetValue(destinationInstance, converter.ConvertFrom(localValue), null); - else - propertyFromDestination.SetValue(destinationInstance, localValue, null); + try + { + var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name)); + var localValue = property.GetValue(Instance, null); + var convertedValue = Convert.ChangeType(localValue, propertyFromDestination.PropertyType); + propertyFromDestination.SetValue(destinationInstance, convertedValue, null); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace($"Error saving default connectioninfo property {property.Name}", ex); + } } } } diff --git a/mRemoteV1/Connection/IConnectionInitiator.cs b/mRemoteV1/Connection/IConnectionInitiator.cs new file mode 100644 index 000000000..5a0ff1d32 --- /dev/null +++ b/mRemoteV1/Connection/IConnectionInitiator.cs @@ -0,0 +1,15 @@ +using mRemoteNG.Container; + +namespace mRemoteNG.Connection +{ + public interface IConnectionInitiator + { + void OpenConnection(ConnectionInfo connectionInfo); + + void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None); + + void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force); + + bool SwitchToOpenConnection(ConnectionInfo connectionInfo); + } +} \ 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 429b96d03..f66f94445 100644 --- a/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs +++ b/mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs @@ -172,7 +172,7 @@ namespace mRemoteNG.Connection.Protocol.Http WebBrowser objWebBrowser = wBrowser as WebBrowser; if (objWebBrowser == null) { - return ; + return; } // This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise. diff --git a/mRemoteV1/Connection/Protocol/ICA/Connection.Protocol.ICA.cs b/mRemoteV1/Connection/Protocol/ICA/Connection.Protocol.ICA.cs index 568d8e4fb..00f918b68 100644 --- a/mRemoteV1/Connection/Protocol/ICA/Connection.Protocol.ICA.cs +++ b/mRemoteV1/Connection/Protocol/ICA/Connection.Protocol.ICA.cs @@ -137,7 +137,7 @@ namespace mRemoteNG.Connection.Protocol.ICA { if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) == (int)ConnectionInfo.Force.NoCredentials) { - return ; + return; } string _user = _Info.Username; diff --git a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs index 81013aeaa..c87d6da76 100644 --- a/mRemoteV1/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteV1/Connection/Protocol/IntegratedProgram.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Drawing; using System.Threading; using System.Windows.Forms; +using mRemoteNG.Messages; namespace mRemoteNG.Connection.Protocol @@ -20,41 +21,52 @@ namespace mRemoteNG.Connection.Protocol #region Public Methods public override bool Initialize() { - if (InterfaceControl.Info != null) - { - _externalTool = Runtime.GetExtAppByName(Convert.ToString(InterfaceControl.Info.ExtApp)); - _externalTool.ConnectionInfo = InterfaceControl.Info; - } - - return base.Initialize(); + if (InterfaceControl.Info == null) return base.Initialize(); + + _externalTool = Runtime.GetExtAppByName(InterfaceControl.Info.ExtApp); + _externalTool.ConnectionInfo = InterfaceControl.Info; + + return base.Initialize(); } public override bool Connect() { try { - if (_externalTool.TryIntegrate == false) + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true); + + if (_externalTool.TryIntegrate == false) { _externalTool.Start(InterfaceControl.Info); - Close(); - return false; + /* 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); + return false; } - ExternalToolArgumentParser argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo); - _process = new Process(); - - _process.StartInfo.UseShellExecute = true; - _process.StartInfo.FileName = argParser.ParseArguments(_externalTool.FileName); - _process.StartInfo.Arguments = argParser.ParseArguments(_externalTool.Arguments); - - _process.EnableRaisingEvents = true; - _process.Exited += ProcessExited; + 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.Exited += ProcessExited; _process.Start(); - _process.WaitForInputIdle(Convert.ToInt32(Settings.Default.MaxPuttyWaitTime * 1000)); + _process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000); - int startTicks = Environment.TickCount; - while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + (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") @@ -68,10 +80,10 @@ namespace mRemoteNG.Connection.Protocol } NativeMethods.SetParent(_handle, InterfaceControl.Handle); - Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, Language.strIntAppStuff, true); - Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle.ToString()), true); - Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true); - Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle.ToString()), true); + 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(); @@ -88,15 +100,12 @@ namespace mRemoteNG.Connection.Protocol { try { - if (ConnectionWindow.InTabDrag) - { - return ; - } + if (ConnectionWindow.InTabDrag) return; NativeMethods.SetForegroundWindow(_handle); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppFocusFailed, ex: ex, logOnly: true); + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex); } } @@ -104,45 +113,49 @@ namespace mRemoteNG.Connection.Protocol { try { - if (InterfaceControl.Size == Size.Empty) - { - return ; - } - NativeMethods.MoveWindow(_handle, Convert.ToInt32(-SystemInformation.FrameBorderSize.Width), Convert.ToInt32(-(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height)), InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width * 2), InterfaceControl.Height + SystemInformation.CaptionHeight + (SystemInformation.FrameBorderSize.Height * 2), true); + 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(message: Language.strIntAppResizeFailed, ex: ex, logOnly: true); + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppResizeFailed, ex); } } public override void Close() { - try - { - if (!_process.HasExited) - { - _process.Kill(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppKillFailed, ex: ex, logOnly: true); - } - - try - { - if (!_process.HasExited) - { - _process.Dispose(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppDisposeFailed, ex: ex, logOnly: true); - } - - base.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. + * 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.Dispose(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppDisposeFailed, ex); + } + } + + base.Close(); } #endregion diff --git a/mRemoteV1/Connection/Protocol/ProtocolBase.cs b/mRemoteV1/Connection/Protocol/ProtocolBase.cs index dfb80df60..76a6cf326 100644 --- a/mRemoteV1/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteV1/Connection/Protocol/ProtocolBase.cs @@ -23,12 +23,12 @@ namespace mRemoteNG.Connection.Protocol #region Public Properties #region Control - public string Name { get; set; } + private string Name { get; } protected UI.Window.ConnectionWindow ConnectionWindow { get { return _connectionWindow; } - set + private set { _connectionWindow = value; _connectionWindow.ResizeBegin += ResizeBegin; @@ -61,7 +61,7 @@ namespace mRemoteNG.Connection.Protocol Name = name; } - public ProtocolBase() + protected ProtocolBase() { } @@ -78,7 +78,7 @@ namespace mRemoteNG.Connection.Protocol } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t focus Control (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Couldn't focus Control (Connection.Protocol.Base)", ex); } } @@ -112,7 +112,7 @@ namespace mRemoteNG.Connection.Protocol } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t SetProps (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Couldn't SetProps (Connection.Protocol.Base)", ex); return false; } } @@ -132,7 +132,7 @@ namespace mRemoteNG.Connection.Protocol public virtual void Close() { - Thread t = new Thread(CloseBG); + var t = new Thread(CloseBG); t.SetApartmentState(ApartmentState.STA); t.IsBackground = true; t.Start(); @@ -153,31 +153,31 @@ namespace mRemoteNG.Connection.Protocol } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not dispose control, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex); } } - - if (_interfaceControl != null) - { - try - { - if (_interfaceControl.Parent == null) return; - if (_interfaceControl.Parent.Tag != null) - { - SetTagToNothing(); - } + + if (_interfaceControl == null) return; + + try + { + if (_interfaceControl.Parent == null) return; + + if (_interfaceControl.Parent.Tag != null) + { + SetTagToNothing(); + } - DisposeInterface(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true); - } - } + 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.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t Close InterfaceControl BG (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex); } } @@ -186,7 +186,7 @@ namespace mRemoteNG.Connection.Protocol { if (_interfaceControl.InvokeRequired) { - DisposeInterfaceCB s = new DisposeInterfaceCB(DisposeInterface); + var s = new DisposeInterfaceCB(DisposeInterface); _interfaceControl.Invoke(s); } else @@ -200,7 +200,7 @@ namespace mRemoteNG.Connection.Protocol { if (_interfaceControl.Parent.InvokeRequired) { - SetTagToNothingCB s = new SetTagToNothingCB(SetTagToNothing); + var s = new SetTagToNothingCB(SetTagToNothing); _interfaceControl.Parent.Invoke(s); } else @@ -214,7 +214,7 @@ namespace mRemoteNG.Connection.Protocol { if (Control.InvokeRequired) { - DisposeControlCB s = new DisposeControlCB(DisposeControl); + var s = new DisposeControlCB(DisposeControl); Control.Invoke(s); } else diff --git a/mRemoteV1/Connection/Protocol/RDP/Connection.Protocol.RDP.cs b/mRemoteV1/Connection/Protocol/RDP/Connection.Protocol.RDP.cs index ebdc551c9..a7d85433f 100644 --- a/mRemoteV1/Connection/Protocol/RDP/Connection.Protocol.RDP.cs +++ b/mRemoteV1/Connection/Protocol/RDP/Connection.Protocol.RDP.cs @@ -30,6 +30,7 @@ namespace mRemoteNG.Connection.Protocol.RDP private ConnectionInfo _connectionInfo; private bool _loginComplete; private bool _redirectKeys; + private bool _alertOnIdleDisconnect; #endregion #region Properties @@ -129,9 +130,12 @@ namespace mRemoteNG.Connection.Protocol.RDP SetCredentials(); SetResolution(); _rdpClient.FullScreenTitle = _connectionInfo.Name; - - //not user changeable - _rdpClient.AdvancedSettings2.GrabFocusOnConnect = true; + + _alertOnIdleDisconnect = _connectionInfo.RDPAlertIdleTimeout; + _rdpClient.AdvancedSettings2.MinutesToIdleTimeout = _connectionInfo.RDPMinutesToIdleTimeout; + + //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) @@ -176,8 +180,8 @@ namespace mRemoteNG.Connection.Protocol.RDP { _loginComplete = false; SetEventHandlers(); - - try + + try { _rdpClient.Connect(); base.Connect(); @@ -616,7 +620,8 @@ namespace mRemoteNG.Connection.Protocol.RDP _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); @@ -625,7 +630,20 @@ namespace mRemoteNG.Connection.Protocol.RDP #endregion #region Private Events & Handlers - private void RDPEvent_OnFatalError(int errorCode) + private void RDPEvent_OnIdleTimeoutNotification() + { + Close(); //Simply close the RDP Session if the idle timeout has been triggered. + + if (_alertOnIdleDisconnect) + { + string message = "The " + _connectionInfo.Name + " session was disconnected due to inactivity"; + const string caption = "Session Disconnected"; + MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + + + private void RDPEvent_OnFatalError(int errorCode) { Event_ErrorOccured(this, Convert.ToString(errorCode)); } diff --git a/mRemoteV1/Connection/PuttySessionInfo.cs b/mRemoteV1/Connection/PuttySessionInfo.cs index ce0470fe6..8edce2a38 100644 --- a/mRemoteV1/Connection/PuttySessionInfo.cs +++ b/mRemoteV1/Connection/PuttySessionInfo.cs @@ -75,7 +75,7 @@ namespace mRemoteNG.Connection var puttyProcess = new PuttyProcessController(); if (!puttyProcess.Start()) { - return ; + return; } if (puttyProcess.SelectListBoxItem(PuttySession)) { diff --git a/mRemoteV1/Messages/MessageCollector.cs b/mRemoteV1/Messages/MessageCollector.cs index 5168e7810..993b4e9c0 100644 --- a/mRemoteV1/Messages/MessageCollector.cs +++ b/mRemoteV1/Messages/MessageCollector.cs @@ -116,7 +116,7 @@ namespace mRemoteNG.Messages return lvItem; } - public void AddExceptionMessage(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = false) + public void AddExceptionMessage(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = true) { AddMessage(msgClass, message + Environment.NewLine + Tools.MiscTools.GetExceptionMessageRecursive(ex), logOnly); } @@ -186,7 +186,7 @@ namespace mRemoteNG.Messages } } - delegate void AddToListCB(ListViewItem lvItem); + private delegate void AddToListCB(ListViewItem lvItem); private void AddToList(ListViewItem lvItem) { if (MCForm.lvErrorCollector.InvokeRequired) diff --git a/mRemoteV1/Properties/AssemblyInfo.cs b/mRemoteV1/Properties/AssemblyInfo.cs index f28dff039..16ac88715 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 © 2016 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] +[assembly: AssemblyCopyright("Copyright © 2017 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] [assembly:AssemblyTrademark("")] [assembly:ComVisible(false)] diff --git a/mRemoteV1/Properties/Settings.Designer.cs b/mRemoteV1/Properties/Settings.Designer.cs index 78a7bb2a8..c8701775d 100644 --- a/mRemoteV1/Properties/Settings.Designer.cs +++ b/mRemoteV1/Properties/Settings.Designer.cs @@ -2099,13 +2099,16 @@ namespace mRemoteNG { } } - [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("release")] public string UpdateChannel { get { return ((string)(this["UpdateChannel"])); } + set { + this["UpdateChannel"] = value; + } } [global::System.Configuration.UserScopedSettingAttribute()] @@ -2347,5 +2350,53 @@ namespace mRemoteNG { this["InhDefaultSoundQuality"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int ConDefaultRDPMinutesToIdleTimeout { + get { + return ((int)(this["ConDefaultRDPMinutesToIdleTimeout"])); + } + set { + this["ConDefaultRDPMinutesToIdleTimeout"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool InhDefaultRDPMinutesToIdleTimeout { + get { + return ((bool)(this["InhDefaultRDPMinutesToIdleTimeout"])); + } + set { + this["InhDefaultRDPMinutesToIdleTimeout"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ConDefaultRDPAlertIdleTimeout { + get { + return ((bool)(this["ConDefaultRDPAlertIdleTimeout"])); + } + set { + this["ConDefaultRDPAlertIdleTimeout"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool InhDefaultRDPAlertIdleTimeout { + get { + return ((bool)(this["InhDefaultRDPAlertIdleTimeout"])); + } + set { + this["InhDefaultRDPAlertIdleTimeout"] = value; + } + } } } diff --git a/mRemoteV1/Properties/Settings.settings b/mRemoteV1/Properties/Settings.settings index 4d0fa8ea3..d25ee254f 100644 --- a/mRemoteV1/Properties/Settings.settings +++ b/mRemoteV1/Properties/Settings.settings @@ -521,7 +521,7 @@ False - + release @@ -584,5 +584,17 @@ False + + 0 + + + False + + + False + + + False + \ No newline at end of file diff --git a/mRemoteV1/Resources/Help/QuickConnect.htm b/mRemoteV1/Resources/Help/QuickConnect.htm index 943e82e9a..3f784d495 100644 --- a/mRemoteV1/Resources/Help/QuickConnect.htm +++ b/mRemoteV1/Resources/Help/QuickConnect.htm @@ -1,13 +1,60 @@ - - - - Quick Connect - - - - -

- Sorry, not yet...

- - + + + + Quick Connect + + + + +

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

+ +

+ 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 +

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

OR

+
    +
  • A predefined mRemoteNG connection
  • +
+ +

+ 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 +
+
+ Select the appropriate network protocol by clicking the arrow next to the Connect box. +
+ 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/Screenshots/Quick Connect/01.png b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/01.png new file mode 100644 index 000000000..3fa15b94d Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/01.png differ diff --git a/mRemoteV1/Resources/Help/Screenshots/Quick Connect/02.png b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/02.png new file mode 100644 index 000000000..897788fd6 Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/02.png differ diff --git a/mRemoteV1/Resources/Help/Screenshots/Quick Connect/03.png b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/03.png new file mode 100644 index 000000000..2d662fd52 Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quick Connect/03.png differ diff --git a/mRemoteV1/Resources/Help/Screenshots/Quickconnect/01.png b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/01.png new file mode 100644 index 000000000..3fa15b94d Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/01.png differ diff --git a/mRemoteV1/Resources/Help/Screenshots/Quickconnect/02.png b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/02.png new file mode 100644 index 000000000..897788fd6 Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/02.png differ diff --git a/mRemoteV1/Resources/Help/Screenshots/Quickconnect/03.png b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/03.png new file mode 100644 index 000000000..2d662fd52 Binary files /dev/null and b/mRemoteV1/Resources/Help/Screenshots/Quickconnect/03.png differ diff --git a/mRemoteV1/Resources/Language/Language.Designer.cs b/mRemoteV1/Resources/Language/Language.Designer.cs index 899f6bc5e..4b674afca 100644 --- a/mRemoteV1/Resources/Language/Language.Designer.cs +++ b/mRemoteV1/Resources/Language/Language.Designer.cs @@ -4117,6 +4117,24 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Select whether to receive an alert after the RDP session disconnects due to inactivity. + /// + internal static string strPropertyDescriptionRDPAlertIdleTimeout { + get { + return ResourceManager.GetString("strPropertyDescriptionRDPAlertIdleTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The number of minutes for the RDP session to sit idle before automatically disconnecting (for no limit use 0). + /// + internal static string strPropertyDescriptionRDPMinutesToIdleTimeout { + get { + return ResourceManager.GetString("strPropertyDescriptionRDPMinutesToIdleTimeout", resourceCulture); + } + } + /// /// Looks up a localized string similar to Select whether local disk drives should be shown on the remote host.. /// @@ -4603,6 +4621,24 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Alert on Idle Disconnect. + /// + internal static string strPropertyNameRDPAlertIdleTimeout { + get { + return ResourceManager.GetString("strPropertyNameRDPAlertIdleTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minutes to Idle. + /// + internal static string strPropertyNameRDPMinutesToIdleTimeout { + get { + return ResourceManager.GetString("strPropertyNameRDPMinutesToIdleTimeout", resourceCulture); + } + } + /// /// Looks up a localized string similar to Disk Drives. /// diff --git a/mRemoteV1/Resources/Language/Language.resx b/mRemoteV1/Resources/Language/Language.resx index 34cff4195..a928e5068 100644 --- a/mRemoteV1/Resources/Language/Language.resx +++ b/mRemoteV1/Resources/Language/Language.resx @@ -2421,4 +2421,16 @@ mRemoteNG will now quit and begin with the installation. Download + + The number of minutes for the RDP session to sit idle before automatically disconnecting (for no limit use 0) + + + Minutes to Idle + + + Select whether to receive an alert after the RDP session disconnects due to inactivity + + + Alert on Idle Disconnect + \ 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 a3fbb4c83..8f2b79160 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd @@ -34,6 +34,7 @@ + @@ -46,6 +47,8 @@ + + @@ -114,6 +117,8 @@ + + diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index 41ae1f189..fc72f5801 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -117,7 +117,7 @@ namespace mRemoteNG.Themes { if (_name == value) { - return ; + return; } _name = value; NotifyPropertyChanged("Name"); @@ -135,7 +135,7 @@ namespace mRemoteNG.Themes { if (_windowBackgroundColor == value) { - return ; + return; } _windowBackgroundColor = value; NotifyPropertyChanged("WindowBackgroundColor"); @@ -152,7 +152,7 @@ namespace mRemoteNG.Themes { if (_menuBackgroundColor == value) { - return ; + return; } _menuBackgroundColor = value; NotifyPropertyChanged("MenuBackgroundColor"); @@ -169,7 +169,7 @@ namespace mRemoteNG.Themes { if (_menuTextColor == value) { - return ; + return; } _menuTextColor = value; NotifyPropertyChanged("MenuTextColor"); @@ -187,7 +187,7 @@ namespace mRemoteNG.Themes { if (_toolbarBackgroundColor == value || value.A < 255) { - return ; + return; } _toolbarBackgroundColor = value; NotifyPropertyChanged("ToolbarBackgroundColor"); @@ -204,7 +204,7 @@ namespace mRemoteNG.Themes { if (_toolbarTextColor == value) { - return ; + return; } _toolbarTextColor = value; NotifyPropertyChanged("ToolbarTextColor"); @@ -223,7 +223,7 @@ namespace mRemoteNG.Themes { if (_connectionsPanelBackgroundColor == value || value.A < 255) { - return ; + return; } _connectionsPanelBackgroundColor = value; NotifyPropertyChanged("ConnectionsPanelBackgroundColor"); @@ -240,7 +240,7 @@ namespace mRemoteNG.Themes { if (_connectionsPanelTextColor == value) { - return ; + return; } _connectionsPanelTextColor = value; NotifyPropertyChanged("ConnectionsPanelTextColor"); @@ -260,7 +260,7 @@ namespace mRemoteNG.Themes { if (_connectionsPanelTreeLineColor == value) { - return ; + return; } _connectionsPanelTreeLineColor = value; NotifyPropertyChanged("ConnectionsPanelTreeLineColor"); @@ -280,7 +280,7 @@ namespace mRemoteNG.Themes { if (_searchBoxBackgroundColor == value || value.A < 255) { - return ; + return; } _searchBoxBackgroundColor = value; NotifyPropertyChanged("SearchBoxBackgroundColor"); @@ -300,7 +300,7 @@ namespace mRemoteNG.Themes { if (_searchBoxTextPromptColor == value) { - return ; + return; } _searchBoxTextPromptColor = value; NotifyPropertyChanged("SearchBoxTextPromptColor"); @@ -320,7 +320,7 @@ namespace mRemoteNG.Themes { if (_searchBoxTextColor == value) { - return ; + return; } _searchBoxTextColor = value; NotifyPropertyChanged("SearchBoxTextColor"); @@ -342,7 +342,7 @@ namespace mRemoteNG.Themes { if (_configPanelBackgroundColor == value || value.A < 255) { - return ; + return; } _configPanelBackgroundColor = value; NotifyPropertyChanged("ConfigPanelBackgroundColor"); @@ -362,7 +362,7 @@ namespace mRemoteNG.Themes { if (_configPanelTextColor == value) { - return ; + return; } _configPanelTextColor = value; NotifyPropertyChanged("ConfigPanelTextColor"); @@ -382,7 +382,7 @@ namespace mRemoteNG.Themes { if (_configPanelCategoryTextColor == value) { - return ; + return; } _configPanelCategoryTextColor = value; NotifyPropertyChanged("ConfigPanelCategoryTextColor"); @@ -402,7 +402,7 @@ namespace mRemoteNG.Themes { if (_configPanelHelpBackgroundColor == value || value.A < 255) { - return ; + return; } _configPanelHelpBackgroundColor = value; NotifyPropertyChanged("ConfigPanelHelpBackgroundColor"); @@ -422,7 +422,7 @@ namespace mRemoteNG.Themes { if (_configPanelHelpTextColor == value) { - return ; + return; } _configPanelHelpTextColor = value; NotifyPropertyChanged("ConfigPanelHelpTextColor"); @@ -442,7 +442,7 @@ namespace mRemoteNG.Themes { if (_configPanelGridLineColor == value) { - return ; + return; } _configPanelGridLineColor = value; NotifyPropertyChanged("ConfigPanelGridLineColor"); diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 4516c8874..6584f67f8 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -81,7 +81,7 @@ namespace mRemoteNG.Themes { if (e.PropertyName == "Name") { - return ; + return; } ThemeChangedEvent?.Invoke(); } diff --git a/mRemoteV1/Tools/ExternalTool.cs b/mRemoteV1/Tools/ExternalTool.cs index 9e25ae3c1..279e31de6 100644 --- a/mRemoteV1/Tools/ExternalTool.cs +++ b/mRemoteV1/Tools/ExternalTool.cs @@ -11,6 +11,7 @@ namespace mRemoteNG.Tools { public class ExternalTool { + private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); #region Public Properties public string DisplayName { get; set; } public string FileName { get; set; } @@ -57,7 +58,7 @@ namespace mRemoteNG.Tools private void StartExternalProcess() { - Process process = new Process(); + var process = new Process(); SetProcessProperties(process, ConnectionInfo); process.Start(); @@ -69,7 +70,7 @@ namespace mRemoteNG.Tools private void SetProcessProperties(Process process, ConnectionInfo startConnectionInfo) { - ExternalToolArgumentParser argParser = new ExternalToolArgumentParser(startConnectionInfo); + var argParser = new ExternalToolArgumentParser(startConnectionInfo); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = argParser.ParseArguments(FileName); process.StartInfo.Arguments = argParser.ParseArguments(Arguments); @@ -79,18 +80,18 @@ namespace mRemoteNG.Tools { try { - ConnectionInfo newConnectionInfo = BuildConnectionInfoForIntegratedApp(); - ConnectionInitiator.OpenConnection(newConnectionInfo); + var newConnectionInfo = BuildConnectionInfoForIntegratedApp(); + _connectionInitiator.OpenConnection(newConnectionInfo); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(message: "ExternalApp.StartIntegrated() failed.", ex: ex, logOnly: true); + Runtime.MessageCollector.AddExceptionMessage("ExternalApp.StartIntegrated() failed.", ex); } } private ConnectionInfo BuildConnectionInfoForIntegratedApp() { - ConnectionInfo newConnectionInfo = GetAppropriateInstanceOfConnectionInfo(); + var newConnectionInfo = GetAppropriateInstanceOfConnectionInfo(); SetConnectionInfoFields(newConnectionInfo); return newConnectionInfo; } diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index c67b67e33..b09c86150 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -14,7 +14,7 @@ using static System.String; namespace mRemoteNG.Tools { - public class MiscTools + public static class MiscTools { public static Icon GetIconFromFile(string FileName) { @@ -112,7 +112,7 @@ namespace mRemoteNG.Tools } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Taking Screenshot failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionStackTrace("Taking Screenshot failed", ex); } return null; @@ -120,7 +120,7 @@ namespace mRemoteNG.Tools public class EnumTypeConverter : EnumConverter { - private Type _enumType; + private readonly Type _enumType; public EnumTypeConverter(Type type) : base(type) { @@ -135,8 +135,8 @@ namespace mRemoteNG.Tools 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: value)); - var dna = (DescriptionAttribute) (Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute))); + var fi = _enumType.GetField(Enum.GetName(_enumType, value)); + var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); return dna != null ? dna.Description : value.ToString(); } @@ -150,9 +150,9 @@ namespace mRemoteNG.Tools { foreach (var fi in _enumType.GetFields()) { - var dna = (DescriptionAttribute) (Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute))); + var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); - if ((dna != null) && ((string) value == dna.Description)) + if (dna != null && (string) value == dna.Description) { return Enum.Parse(_enumType, fi.Name); } @@ -167,12 +167,7 @@ namespace mRemoteNG.Tools public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if (sourceType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, sourceType); + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) @@ -193,7 +188,7 @@ namespace mRemoteNG.Tools return false; } - throw (new Exception("Values must be \"Yes\" or \"No\"")); + throw new Exception("Values must be \"Yes\" or \"No\""); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) @@ -220,63 +215,5 @@ namespace mRemoteNG.Tools return svc; } } - - public class Fullscreen - { - public Fullscreen(Form handledForm) - { - _handledForm = handledForm; - } - - private readonly Form _handledForm; - private FormWindowState _savedWindowState; - private FormBorderStyle _savedBorderStyle; - private Rectangle _savedBounds; - - private bool _value; - public bool Value - { - get - { - return _value; - } - set - { - if (_value == value) - { - return ; - } - if (!_value) - { - EnterFullscreen(); - } - else - { - ExitFullscreen(); - } - _value = value; - } - } - - private void EnterFullscreen() - { - _savedBorderStyle = _handledForm.FormBorderStyle; - _savedWindowState = _handledForm.WindowState; - _savedBounds = _handledForm.Bounds; - - _handledForm.FormBorderStyle = FormBorderStyle.None; - if (_handledForm.WindowState == FormWindowState.Maximized) - { - _handledForm.WindowState = FormWindowState.Normal; - } - _handledForm.WindowState = FormWindowState.Maximized; - } - private void ExitFullscreen() - { - _handledForm.FormBorderStyle = _savedBorderStyle; - _handledForm.WindowState = _savedWindowState; - _handledForm.Bounds = _savedBounds; - } - } } } \ No newline at end of file diff --git a/mRemoteV1/Tools/NotificationAreaIcon.cs b/mRemoteV1/Tools/NotificationAreaIcon.cs new file mode 100644 index 000000000..cd66a8554 --- /dev/null +++ b/mRemoteV1/Tools/NotificationAreaIcon.cs @@ -0,0 +1,128 @@ +using System; +using System.Linq; +using System.Windows.Forms; +using mRemoteNG.App; +using mRemoteNG.Connection; +using mRemoteNG.UI.Forms; + + +namespace mRemoteNG.Tools +{ + public class NotificationAreaIcon + { + private readonly NotifyIcon _nI; + private readonly ContextMenuStrip _cMen; + private readonly ToolStripMenuItem _cMenCons; + private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); + + public bool Disposed { get; private set; } + + public NotificationAreaIcon() + { + try + { + _cMenCons = new ToolStripMenuItem + { + Text = Language.strConnections, + Image = Resources.Root + }; + + var cMenSep1 = new ToolStripSeparator(); + + var cMenExit = new ToolStripMenuItem {Text = Language.strMenuExit}; + cMenExit.Click += cMenExit_Click; + + _cMen = new ContextMenuStrip + { + Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)), + RenderMode = ToolStripRenderMode.Professional + }; + _cMen.Items.AddRange(new ToolStripItem[] {_cMenCons, cMenSep1, cMenExit}); + + _nI = new NotifyIcon + { + Text = @"mRemoteNG", + BalloonTipText = @"mRemoteNG", + Icon = Resources.mRemote_Icon, + ContextMenuStrip = _cMen, + Visible = true + }; + + _nI.MouseClick += nI_MouseClick; + _nI.MouseDoubleClick += nI_MouseDoubleClick; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Creating new SysTrayIcon failed", ex); + } + } + + public void Dispose() + { + try + { + _nI.Visible = false; + _nI.Dispose(); + _cMen.Dispose(); + Disposed = true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Disposing SysTrayIcon failed", ex); + } + } + + private void nI_MouseClick(object sender, MouseEventArgs e) + { + if (e.Button != MouseButtons.Right) return; + _cMenCons.DropDownItems.Clear(); + var menuItemsConverter = new ConnectionsTreeToMenuItemsConverter + { + MouseUpEventHandler = ConMenItem_MouseUp + }; + + // ReSharper disable once CoVariantArrayConversion + ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionTreeModel).ToArray(); + _cMenCons.DropDownItems.AddRange(rootMenuItems); + } + + private static void nI_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (frmMain.Default.Visible) + HideForm(); + else + ShowForm(); + } + + private static void ShowForm() + { + frmMain.Default.Show(); + frmMain.Default.WindowState = frmMain.Default.PreviousWindowState; + + if (Settings.Default.ShowSystemTrayIcon) return; + Runtime.NotificationAreaIcon.Dispose(); + Runtime.NotificationAreaIcon = null; + } + + private static void HideForm() + { + frmMain.Default.Hide(); + frmMain.Default.PreviousWindowState = frmMain.Default.WindowState; + } + + private void ConMenItem_MouseUp(object sender, MouseEventArgs e) + { + if (e.Button != MouseButtons.Left) return; + if (!(((ToolStripMenuItem) sender).Tag is ConnectionInfo)) return; + if (frmMain.Default.Visible == false) + ShowForm(); + _connectionInitiator.OpenConnection((ConnectionInfo) ((ToolStripMenuItem) sender).Tag); + } + + private static void cMenExit_Click(object sender, EventArgs e) + { + Shutdown.Quit(); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/ProcessController.cs b/mRemoteV1/Tools/ProcessController.cs index 13c11145b..625b73fe0 100644 --- a/mRemoteV1/Tools/ProcessController.cs +++ b/mRemoteV1/Tools/ProcessController.cs @@ -83,7 +83,7 @@ namespace mRemoteNG.Tools public void WaitForExit() { if (Process == null || Process.HasExited) - return ; + return; Process.WaitForExit(); } #endregion diff --git a/mRemoteV1/Tools/Tools.Controls.cs b/mRemoteV1/Tools/Tools.Controls.cs deleted file mode 100644 index 1e92b03a2..000000000 --- a/mRemoteV1/Tools/Tools.Controls.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Linq; -using System.Windows.Forms; -using mRemoteNG.App; -using mRemoteNG.Connection; -using mRemoteNG.UI.Forms; - - -namespace mRemoteNG.Tools -{ - public class Controls - { - public class NotificationAreaIcon - { - private NotifyIcon _nI; - private ContextMenuStrip _cMen; - private ToolStripMenuItem _cMenCons; - - public bool Disposed { get; set; } - - public NotificationAreaIcon() - { - try - { - _cMenCons = new ToolStripMenuItem - { - Text = Language.strConnections, - Image = Resources.Root - }; - - var cMenSep1 = new ToolStripSeparator(); - - var cMenExit = new ToolStripMenuItem {Text = Language.strMenuExit}; - cMenExit.Click += cMenExit_Click; - - _cMen = new ContextMenuStrip - { - Font = - new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, - System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)), - RenderMode = ToolStripRenderMode.Professional - }; - _cMen.Items.AddRange(new ToolStripItem[] {_cMenCons, cMenSep1, cMenExit}); - - _nI = new NotifyIcon - { - Text = "mRemote", - BalloonTipText = "mRemote", - Icon = Resources.mRemote_Icon, - ContextMenuStrip = _cMen, - Visible = true - }; - - _nI.MouseClick += nI_MouseClick; - _nI.MouseDoubleClick += nI_MouseDoubleClick; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Creating new SysTrayIcon failed" + Environment.NewLine + ex.Message, true); - } - } - - public void Dispose() - { - try - { - _nI.Visible = false; - _nI.Dispose(); - _cMen.Dispose(); - Disposed = true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Disposing SysTrayIcon failed" + Environment.NewLine + ex.Message, true); - } - } - - private void nI_MouseClick(object sender, MouseEventArgs e) - { - if (e.Button != MouseButtons.Right) return; - _cMenCons.DropDownItems.Clear(); - var menuItemsConverter = new ConnectionsTreeToMenuItemsConverter - { - MouseUpEventHandler = ConMenItem_MouseUp - }; - - ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionTreeModel).ToArray(); - _cMenCons.DropDownItems.AddRange(rootMenuItems); - } - - private void nI_MouseDoubleClick(object sender, MouseEventArgs e) - { - if (frmMain.Default.Visible) - { - HideForm(); - } - else - { - ShowForm(); - } - } - - private void ShowForm() - { - frmMain.Default.Show(); - frmMain.Default.WindowState = frmMain.Default.PreviousWindowState; - - if (Settings.Default.ShowSystemTrayIcon) return; - Runtime.NotificationAreaIcon.Dispose(); - Runtime.NotificationAreaIcon = null; - } - - private void HideForm() - { - frmMain.Default.Hide(); - frmMain.Default.PreviousWindowState = frmMain.Default.WindowState; - } - - private void ConMenItem_MouseUp(Object sender, MouseEventArgs e) - { - if (e.Button != MouseButtons.Left) return; - if (!(((Control) sender).Tag is ConnectionInfo)) return; - if (frmMain.Default.Visible == false) - { - ShowForm(); - } - ConnectionInitiator.OpenConnection((ConnectionInfo)((Control)sender).Tag); - } - - private void cMenExit_Click(Object sender, EventArgs e) - { - Shutdown.Quit(); - } - } - - public static SaveFileDialog ConnectionsSaveAsDialog() - { - var saveFileDialog = new SaveFileDialog(); - saveFileDialog.CheckPathExists = true; - saveFileDialog.InitialDirectory = App.Info.ConnectionsFileInfo.DefaultConnectionsPath; - saveFileDialog.FileName = App.Info.ConnectionsFileInfo.DefaultConnectionsFile; - saveFileDialog.OverwritePrompt = true; - - saveFileDialog.Filter = Language.strFiltermRemoteXML + "|*.xml|" + Language.strFilterAll + "|*.*"; - - return saveFileDialog; - } - - public static OpenFileDialog ConnectionsLoadDialog() - { - var lDlg = new OpenFileDialog - { - CheckFileExists = true, - InitialDirectory = App.Info.ConnectionsFileInfo.DefaultConnectionsPath, - Filter = Language.strFiltermRemoteXML + "|*.xml|" + Language.strFilterAll + "|*.*" - }; - - return lDlg; - } - } -} \ No newline at end of file diff --git a/mRemoteV1/Tree/AlwaysConfirmYes.cs b/mRemoteV1/Tree/AlwaysConfirmYes.cs new file mode 100644 index 000000000..40d0989ec --- /dev/null +++ b/mRemoteV1/Tree/AlwaysConfirmYes.cs @@ -0,0 +1,11 @@ + +namespace mRemoteNG.Tree +{ + public class AlwaysConfirmYes : IConfirm + { + public bool Confirm() + { + return true; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ClickHandlers/ExpandNodeClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/ExpandNodeClickHandler.cs new file mode 100644 index 000000000..63ae56e6e --- /dev/null +++ b/mRemoteV1/Tree/ClickHandlers/ExpandNodeClickHandler.cs @@ -0,0 +1,28 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.UI.Controls; + + +namespace mRemoteNG.Tree +{ + public class ExpandNodeClickHandler : ITreeNodeClickHandler + { + private readonly IConnectionTree _connectionTree; + + public ExpandNodeClickHandler(IConnectionTree connectionTree) + { + if (connectionTree == null) + throw new ArgumentNullException(nameof(connectionTree)); + + _connectionTree = connectionTree; + } + + public void Execute(ConnectionInfo clickedNode) + { + var clickedNodeAsContainer = clickedNode as ContainerInfo; + if (clickedNodeAsContainer == null) return; + _connectionTree.ToggleExpansion(clickedNodeAsContainer); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ClickHandlers/ITreeNodeClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/ITreeNodeClickHandler.cs new file mode 100644 index 000000000..40b2852a7 --- /dev/null +++ b/mRemoteV1/Tree/ClickHandlers/ITreeNodeClickHandler.cs @@ -0,0 +1,10 @@ +using mRemoteNG.Connection; + + +namespace mRemoteNG.Tree +{ + public interface ITreeNodeClickHandler + { + void Execute(ConnectionInfo clickedNode); + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs new file mode 100644 index 000000000..078d94e81 --- /dev/null +++ b/mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs @@ -0,0 +1,26 @@ +using System; +using mRemoteNG.Connection; + + +namespace mRemoteNG.Tree +{ + public class OpenConnectionClickHandler : ITreeNodeClickHandler + { + private readonly IConnectionInitiator _connectionInitiator; + + public OpenConnectionClickHandler(IConnectionInitiator connectionInitiator) + { + if (connectionInitiator == null) + throw new ArgumentNullException(nameof(connectionInitiator)); + _connectionInitiator = connectionInitiator; + } + + public void Execute(ConnectionInfo clickedNode) + { + if (clickedNode == null) + throw new ArgumentNullException(nameof(clickedNode)); + if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; + _connectionInitiator.OpenConnection(clickedNode); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs new file mode 100644 index 000000000..5ed5ddf95 --- /dev/null +++ b/mRemoteV1/Tree/ClickHandlers/SwitchToConnectionClickHandler.cs @@ -0,0 +1,26 @@ +using System; +using mRemoteNG.Connection; + + +namespace mRemoteNG.Tree +{ + public class SwitchToConnectionClickHandler : ITreeNodeClickHandler + { + private readonly IConnectionInitiator _connectionInitiator; + + public SwitchToConnectionClickHandler(IConnectionInitiator connectionInitiator) + { + if (connectionInitiator == null) + throw new ArgumentNullException(nameof(connectionInitiator)); + _connectionInitiator = connectionInitiator; + } + + public void Execute(ConnectionInfo clickedNode) + { + if (clickedNode == null) + throw new ArgumentNullException(nameof(clickedNode)); + if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; + _connectionInitiator.SwitchToOpenConnection(clickedNode); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs b/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs new file mode 100644 index 000000000..39c7a7c25 --- /dev/null +++ b/mRemoteV1/Tree/ClickHandlers/TreeNodeCompositeClickHandler.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using mRemoteNG.Connection; + + +namespace mRemoteNG.Tree +{ + public class TreeNodeCompositeClickHandler : ITreeNodeClickHandler + { + public IEnumerable ClickHandlers { get; set; } = new ITreeNodeClickHandler[0]; + + public void Execute(ConnectionInfo clickedNode) + { + if (clickedNode == null) + throw new ArgumentNullException(nameof(clickedNode)); + foreach (var handler in ClickHandlers) + { + handler.Execute(clickedNode); + } + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/IConfirm.cs b/mRemoteV1/Tree/IConfirm.cs new file mode 100644 index 000000000..e4434cb5b --- /dev/null +++ b/mRemoteV1/Tree/IConfirm.cs @@ -0,0 +1,7 @@ +namespace mRemoteNG.Tree +{ + public interface IConfirm + { + bool Confirm(); + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/ObjectListViewExtensions.cs b/mRemoteV1/Tree/ObjectListViewExtensions.cs deleted file mode 100644 index 2e7c1b554..000000000 --- a/mRemoteV1/Tree/ObjectListViewExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Windows.Forms; -using BrightIdeasSoftware; - - -namespace mRemoteNG.Tree -{ - public static class ObjectListViewExtensions - { - public static void Invoke(this Control control, MethodInvoker action) - { - control.Invoke(action); - } - - public static void InvokeExpand(this TreeListView control, object model) - { - control.Invoke(() => control.Expand(model)); - } - - public static void InvokeRebuildAll(this TreeListView control, bool preserveState) - { - control.Invoke(() => control.RebuildAll(preserveState)); - } - } -} \ No newline at end of file diff --git a/mRemoteV1/Tree/PreviousSessionOpener.cs b/mRemoteV1/Tree/PreviousSessionOpener.cs new file mode 100644 index 000000000..5df20c8ac --- /dev/null +++ b/mRemoteV1/Tree/PreviousSessionOpener.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.UI.Controls; + + +namespace mRemoteNG.Tree +{ + public class PreviousSessionOpener : IConnectionTreeDelegate + { + private readonly IConnectionInitiator _connectionInitiator; + + public PreviousSessionOpener(IConnectionInitiator connectionInitiator) + { + if (connectionInitiator == null) + throw new ArgumentNullException(nameof(connectionInitiator)); + _connectionInitiator = connectionInitiator; + } + + public void Execute(IConnectionTree connectionTree) + { + var connectionInfoList = connectionTree.GetRootConnectionNode().GetRecursiveChildList().Where(node => !(node is ContainerInfo)); + var previouslyOpenedConnections = connectionInfoList.Where(item => item.PleaseConnect); + foreach (var connectionInfo in previouslyOpenedConnections) + { + _connectionInitiator.OpenConnection(connectionInfo); + } + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs b/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs new file mode 100644 index 000000000..8b26236f7 --- /dev/null +++ b/mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs @@ -0,0 +1,19 @@ +using System.Linq; +using mRemoteNG.Container; +using mRemoteNG.UI.Controls; + + +namespace mRemoteNG.Tree +{ + public class PreviouslyOpenedFolderExpander : IConnectionTreeDelegate + { + public void Execute(IConnectionTree connectionTree) + { + var rootNode = connectionTree.GetRootConnectionNode(); + var containerList = connectionTree.ConnectionTreeModel.GetRecursiveChildList(rootNode).OfType(); + var previouslyExpandedNodes = containerList.Where(container => container.IsExpanded); + connectionTree.ExpandedObjects = previouslyExpandedNodes; + connectionTree.InvokeRebuildAll(true); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/RootNodeExpander.cs b/mRemoteV1/Tree/RootNodeExpander.cs new file mode 100644 index 000000000..bc02f0ae8 --- /dev/null +++ b/mRemoteV1/Tree/RootNodeExpander.cs @@ -0,0 +1,14 @@ +using mRemoteNG.UI.Controls; + + +namespace mRemoteNG.Tree +{ + public class RootNodeExpander : IConnectionTreeDelegate + { + public void Execute(IConnectionTree connectionTree) + { + var rootConnectionNode = connectionTree.GetRootConnectionNode(); + connectionTree.InvokeExpand(rootConnectionNode); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs b/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs new file mode 100644 index 000000000..cb49f726d --- /dev/null +++ b/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs @@ -0,0 +1,56 @@ +using System; +using System.Windows.Forms; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.UI.Controls; + + +namespace mRemoteNG.Tree +{ + public class SelectedConnectionDeletionConfirmer : IConfirm + { + private readonly IConnectionTree _connectionTree; + private readonly Func _confirmationFunc; + + public SelectedConnectionDeletionConfirmer(IConnectionTree connectionTree, Func confirmationFunc) + { + _connectionTree = connectionTree; + _confirmationFunc = confirmationFunc; + } + + public bool Confirm() + { + var deletionTarget = _connectionTree.SelectedNode; + var deletionTargetAsContainer = deletionTarget as ContainerInfo; + if (deletionTargetAsContainer != null) + return deletionTargetAsContainer.HasChildren() + ? UserConfirmsNonEmptyFolderDeletion(deletionTargetAsContainer) + : UserConfirmsEmptyFolderDeletion(deletionTargetAsContainer); + return UserConfirmsConnectionDeletion(deletionTarget); + } + + private bool UserConfirmsEmptyFolderDeletion(AbstractConnectionInfoData deletionTarget) + { + var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolder, deletionTarget.Name); + return PromptUser(messagePrompt); + } + + private bool UserConfirmsNonEmptyFolderDeletion(AbstractConnectionInfoData deletionTarget) + { + var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolderNotEmpty, deletionTarget.Name); + return PromptUser(messagePrompt); + } + + private bool UserConfirmsConnectionDeletion(AbstractConnectionInfoData deletionTarget) + { + var messagePrompt = string.Format(Language.strConfirmDeleteNodeConnection, deletionTarget.Name); + return PromptUser(messagePrompt); + } + + private bool PromptUser(string promptMessage) + { + var msgBoxResponse = _confirmationFunc.Invoke(promptMessage, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question); + return msgBoxResponse == DialogResult.Yes; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionContextMenu.cs b/mRemoteV1/UI/Controls/ConnectionContextMenu.cs index 3816d08ae..9ff0f1457 100644 --- a/mRemoteV1/UI/Controls/ConnectionContextMenu.cs +++ b/mRemoteV1/UI/Controls/ConnectionContextMenu.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Linq; using System.Windows.Forms; using mRemoteNG.App; @@ -6,13 +7,14 @@ using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Container; using mRemoteNG.Tools; +using mRemoteNG.Tree; using mRemoteNG.Tree.Root; // ReSharper disable UnusedParameter.Local namespace mRemoteNG.UI.Controls { - internal sealed class ConnectionContextMenu : ContextMenuStrip + public sealed class ConnectionContextMenu : ContextMenuStrip { private ToolStripMenuItem _cMenTreeAddConnection; private ToolStripMenuItem _cMenTreeAddFolder; @@ -44,14 +46,23 @@ namespace mRemoteNG.UI.Controls private ToolStripMenuItem _cMenTreeImportFile; private ToolStripMenuItem _cMenTreeImportActiveDirectory; private ToolStripMenuItem _cMenTreeImportPortScan; + private readonly ConnectionTree _connectionTree; + private readonly IConnectionInitiator _connectionInitiator; - public ConnectionContextMenu() + public ConnectionContextMenu(ConnectionTree connectionTree) { + _connectionTree = connectionTree; + _connectionInitiator = new ConnectionInitiator(); InitializeComponent(); ApplyLanguage(); EnableShortcutKeys(); - Opening += (sender, args) => AddExternalApps(); + Opening += (sender, args) => + { + AddExternalApps(); + ShowHideMenuItems(); + }; + Closing += (sender, args) => EnableMenuItemsRecursive(Items); } private void InitializeComponent() @@ -384,104 +395,129 @@ namespace mRemoteNG.UI.Controls _cMenTreeMoveDown.Text = Language.strMoveDown; } - internal void ShowHideTreeContextMenuItems(ConnectionInfo connectionInfo) + internal void ShowHideMenuItems() { - if (connectionInfo == null) + if (_connectionTree.SelectedNode == null) return; try { Enabled = true; EnableMenuItemsRecursive(Items); - if (connectionInfo is RootPuttySessionsNodeInfo) + if (_connectionTree.SelectedNode is RootPuttySessionsNodeInfo) { - _cMenTreeAddConnection.Enabled = false; - _cMenTreeAddFolder.Enabled = false; - _cMenTreeConnect.Enabled = false; - _cMenTreeConnectWithOptions.Enabled = false; - _cMenTreeDisconnect.Enabled = false; - _cMenTreeToolsTransferFile.Enabled = false; - _cMenTreeConnectWithOptions.Enabled = false; - _cMenTreeToolsSort.Enabled = false; - _cMenTreeToolsExternalApps.Enabled = false; - _cMenTreeDuplicate.Enabled = false; - _cMenTreeRename.Enabled = true; - _cMenTreeDelete.Enabled = false; - _cMenTreeMoveUp.Enabled = false; - _cMenTreeMoveDown.Enabled = false; + ShowHideMenuItemsForRootPuttyNode(); } - else if (connectionInfo is RootNodeInfo) + else if (_connectionTree.SelectedNode is RootNodeInfo) { - _cMenTreeConnect.Enabled = false; - _cMenTreeConnectWithOptions.Enabled = false; - _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; - _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; - _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Enabled = false; - _cMenTreeDisconnect.Enabled = false; - _cMenTreeToolsTransferFile.Enabled = false; - _cMenTreeToolsExternalApps.Enabled = false; - _cMenTreeDuplicate.Enabled = false; - _cMenTreeDelete.Enabled = false; - _cMenTreeMoveUp.Enabled = false; - _cMenTreeMoveDown.Enabled = false; + ShowHideMenuItemsForRootConnectionNode(); } - else if (connectionInfo is ContainerInfo) + else if (_connectionTree.SelectedNode is ContainerInfo) { - _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; - _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; - _cMenTreeDisconnect.Enabled = false; - - var openConnections = ((ContainerInfo)connectionInfo).Children.Sum(child => child.OpenConnections.Count); - if (openConnections > 0) - _cMenTreeDisconnect.Enabled = true; - - _cMenTreeToolsTransferFile.Enabled = false; - _cMenTreeToolsExternalApps.Enabled = false; + ShowHideMenuItemsForContainer(_connectionTree.SelectedNode); } - else if (connectionInfo is PuttySessionInfo) + else if (_connectionTree.SelectedNode is PuttySessionInfo) { - _cMenTreeAddConnection.Enabled = false; - _cMenTreeAddFolder.Enabled = false; - - if (connectionInfo.OpenConnections.Count == 0) - _cMenTreeDisconnect.Enabled = false; - - if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2)) - _cMenTreeToolsTransferFile.Enabled = false; - - _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; - _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; - _cMenTreeToolsSort.Enabled = false; - _cMenTreeDuplicate.Enabled = false; - _cMenTreeRename.Enabled = false; - _cMenTreeDelete.Enabled = false; - _cMenTreeMoveUp.Enabled = false; - _cMenTreeMoveDown.Enabled = false; + ShowHideMenuItemsForPuttyNode(_connectionTree.SelectedNode); } else { - if (connectionInfo.OpenConnections.Count == 0) - _cMenTreeDisconnect.Enabled = false; - - if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2)) - _cMenTreeToolsTransferFile.Enabled = false; - - if (!(connectionInfo.Protocol == ProtocolType.RDP | connectionInfo.Protocol == ProtocolType.ICA)) - { - _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; - _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; - } - - if (connectionInfo.Protocol == ProtocolType.IntApp) - _cMenTreeConnectWithOptionsNoCredentials.Enabled = false; + ShowHideMenuItemsForConnectionNode(_connectionTree.SelectedNode); } } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionStackTrace("ShowHideTreeContextMenuItems (UI.Window.ConnectionTreeWindow) failed", ex); + Runtime.MessageCollector.AddExceptionStackTrace("ShowHideMenuItems (UI.Controls.ConnectionContextMenu) failed", ex); } } + internal void ShowHideMenuItemsForRootPuttyNode() + { + _cMenTreeAddConnection.Enabled = false; + _cMenTreeAddFolder.Enabled = false; + _cMenTreeConnect.Enabled = false; + _cMenTreeConnectWithOptions.Enabled = false; + _cMenTreeDisconnect.Enabled = false; + _cMenTreeToolsTransferFile.Enabled = false; + _cMenTreeConnectWithOptions.Enabled = false; + _cMenTreeToolsSort.Enabled = false; + _cMenTreeToolsExternalApps.Enabled = false; + _cMenTreeDuplicate.Enabled = false; + _cMenTreeRename.Enabled = true; + _cMenTreeDelete.Enabled = false; + _cMenTreeMoveUp.Enabled = false; + _cMenTreeMoveDown.Enabled = false; + } + + internal void ShowHideMenuItemsForRootConnectionNode() + { + _cMenTreeConnect.Enabled = false; + _cMenTreeConnectWithOptions.Enabled = false; + _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; + _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; + _cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Enabled = false; + _cMenTreeDisconnect.Enabled = false; + _cMenTreeToolsTransferFile.Enabled = false; + _cMenTreeToolsExternalApps.Enabled = false; + _cMenTreeDuplicate.Enabled = false; + _cMenTreeDelete.Enabled = false; + _cMenTreeMoveUp.Enabled = false; + _cMenTreeMoveDown.Enabled = false; + } + + internal void ShowHideMenuItemsForContainer(ConnectionInfo connectionInfo) + { + _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; + _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; + _cMenTreeDisconnect.Enabled = false; + + var openConnections = ((ContainerInfo)connectionInfo).Children.Sum(child => child.OpenConnections.Count); + if (openConnections > 0) + _cMenTreeDisconnect.Enabled = true; + + _cMenTreeToolsTransferFile.Enabled = false; + _cMenTreeToolsExternalApps.Enabled = false; + } + + internal void ShowHideMenuItemsForPuttyNode(ConnectionInfo connectionInfo) + { + _cMenTreeAddConnection.Enabled = false; + _cMenTreeAddFolder.Enabled = false; + + if (connectionInfo.OpenConnections.Count == 0) + _cMenTreeDisconnect.Enabled = false; + + if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2)) + _cMenTreeToolsTransferFile.Enabled = false; + + _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; + _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; + _cMenTreeToolsSort.Enabled = false; + _cMenTreeDuplicate.Enabled = false; + _cMenTreeRename.Enabled = false; + _cMenTreeDelete.Enabled = false; + _cMenTreeMoveUp.Enabled = false; + _cMenTreeMoveDown.Enabled = false; + } + + internal void ShowHideMenuItemsForConnectionNode(ConnectionInfo connectionInfo) + { + if (connectionInfo.OpenConnections.Count == 0) + _cMenTreeDisconnect.Enabled = false; + + if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2)) + _cMenTreeToolsTransferFile.Enabled = false; + + if (!(connectionInfo.Protocol == ProtocolType.RDP | connectionInfo.Protocol == ProtocolType.ICA)) + { + _cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false; + _cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false; + } + + if (connectionInfo.Protocol == ProtocolType.IntApp) + _cMenTreeConnectWithOptionsNoCredentials.Enabled = false; + } + internal void DisableShortcutKeys() { _cMenTreeConnect.ShortcutKeys = Keys.None; @@ -553,183 +589,218 @@ namespace mRemoteNG.UI.Controls _cMenTreeToolsExternalApps.DropDownItems.Clear(); } - #region Events - public event EventHandler ConnectClicked; - + #region Click handlers private void OnConnectClicked(object sender, EventArgs e) { - var handler = ConnectClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DoNotJump); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.DoNotJump); } - public event EventHandler ConnectToConsoleSessionClicked; - private void OnConnectToConsoleSessionClicked(object sender, EventArgs e) { - var handler = ConnectToConsoleSessionClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); } - - public event EventHandler DontConnectToConsoleSessionClicked; private void OnDontConnectToConsoleSessionClicked(object sender, EventArgs e) { - var handler = DontConnectToConsoleSessionClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); } - public event EventHandler ConnectInFullscreenClicked; - private void OnConnectInFullscreenClicked(object sender, EventArgs e) { - var handler = ConnectInFullscreenClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); } - public event EventHandler ConnectWithNoCredentialsClick; - private void OnConnectWithNoCredentialsClick(object sender, EventArgs e) { - var handler = ConnectWithNoCredentialsClick; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.NoCredentials); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.NoCredentials); } - public event EventHandler ChoosePanelBeforeConnectingClicked; - private void OnChoosePanelBeforeConnectingClicked(object sender, EventArgs e) { - var handler = ChoosePanelBeforeConnectingClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo; + if (selectedNodeAsContainer != null) + _connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); + else + _connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); } - - public event EventHandler DisconnectClicked; - private void OnDisconnectClicked(object sender, EventArgs e) { - var handler = DisconnectClicked; - handler?.Invoke(this, e); + DisconnectConnection(_connectionTree.SelectedNode); } - public event EventHandler TransferFileClicked; + public void DisconnectConnection(ConnectionInfo connectionInfo) + { + try + { + if (connectionInfo == null) return; + var nodeAsContainer = connectionInfo as ContainerInfo; + if (nodeAsContainer != null) + { + foreach (var child in nodeAsContainer.Children) + { + for (var i = 0; i <= child.OpenConnections.Count - 1; i++) + { + child.OpenConnections[i].Disconnect(); + } + } + } + else + { + for (var i = 0; i <= connectionInfo.OpenConnections.Count - 1; i++) + { + connectionInfo.OpenConnections[i].Disconnect(); + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("DisconnectConnection (UI.Window.ConnectionTreeWindow) failed", ex); + } + } private void OnTransferFileClicked(object sender, EventArgs e) { - var handler = TransferFileClicked; - handler?.Invoke(this, e); + SshTransferFile(); } - public event EventHandler DuplicateClicked; + public void SshTransferFile() + { + try + { + Windows.Show(WindowType.SSHTransfer); + Windows.SshtransferForm.Hostname = _connectionTree.SelectedNode.Hostname; + Windows.SshtransferForm.Username = _connectionTree.SelectedNode.Username; + Windows.SshtransferForm.Password = _connectionTree.SelectedNode.Password; + Windows.SshtransferForm.Port = Convert.ToString(_connectionTree.SelectedNode.Port); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("SSHTransferFile (UI.Window.ConnectionTreeWindow) failed", ex); + } + } private void OnDuplicateClicked(object sender, EventArgs e) { - var handler = DuplicateClicked; - handler?.Invoke(this, e); + _connectionTree.DuplicateSelectedNode(); } - public event EventHandler RenameClicked; - private void OnRenameClicked(object sender, EventArgs e) { - var handler = RenameClicked; - handler?.Invoke(this, e); + _connectionTree.RenameSelectedNode(); } - public event EventHandler DeleteClicked; - private void OnDeleteClicked(object sender, EventArgs e) { - var handler = DeleteClicked; - handler?.Invoke(this, e); + _connectionTree.DeleteSelectedNode(); } - public event EventHandler ImportFileClicked; - private void OnImportFileClicked(object sender, EventArgs e) { - var handler = ImportFileClicked; - handler?.Invoke(this, e); + var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent; + Import.ImportFromFile(selectedNodeAsContainer); } - public event EventHandler ImportActiveDirectoryClicked; - private void OnImportActiveDirectoryClicked(object sender, EventArgs e) { - var handler = ImportActiveDirectoryClicked; - handler?.Invoke(this, e); + Windows.Show(WindowType.ActiveDirectoryImport); } - public event EventHandler ImportPortScanClicked; - private void OnImportPortScanClicked(object sender, EventArgs e) { - var handler = ImportPortScanClicked; - handler?.Invoke(this, e); + Windows.Show(WindowType.PortScan); } - public event EventHandler ExportFileClicked; - private void OnExportFileClicked(object sender, EventArgs e) { - var handler = ExportFileClicked; - handler?.Invoke(this, e); + Export.ExportToFile(_connectionTree.SelectedNode, Runtime.ConnectionTreeModel); } - public event EventHandler AddConnectionClicked; - private void OnAddConnectionClicked(object sender, EventArgs e) { - var handler = AddConnectionClicked; - handler?.Invoke(this, e); + _connectionTree.AddConnection(); + Runtime.SaveConnectionsAsync(); } - public event EventHandler AddFolderClicked; - private void OnAddFolderClicked(object sender, EventArgs e) { - var handler = AddFolderClicked; - handler?.Invoke(this, e); + _connectionTree.AddFolder(); + Runtime.SaveConnectionsAsync(); } - public event EventHandler SortAscendingClicked; - private void OnSortAscendingClicked(object sender, EventArgs e) { - var handler = SortAscendingClicked; - handler?.Invoke(this, e); + SortNodesRecursive(_connectionTree.SelectedNode, ListSortDirection.Ascending); } - public event EventHandler SortDescendingClicked; - private void OnSortDescendingClicked(object sender, EventArgs e) { - var handler = SortDescendingClicked; - handler?.Invoke(this, e); + SortNodesRecursive(_connectionTree.SelectedNode, ListSortDirection.Descending); } - public event EventHandler MoveUpClicked; - private void OnMoveUpClicked(object sender, EventArgs e) { - var handler = MoveUpClicked; - handler?.Invoke(this, e); + _connectionTree.SelectedNode.Parent.PromoteChild(_connectionTree.SelectedNode); + Runtime.SaveConnectionsAsync(); } - public event EventHandler MoveDownClicked; - private void OnMoveDownClicked(object sender, EventArgs e) { - var handler = MoveDownClicked; - handler?.Invoke(this, e); + _connectionTree.SelectedNode.Parent.DemoteChild(_connectionTree.SelectedNode); + Runtime.SaveConnectionsAsync(); } - public event EventHandler ExternalToolClicked; - private void OnExternalToolClicked(object sender, EventArgs e) { - var handler = ExternalToolClicked; - handler?.Invoke(sender, e); + StartExternalApp((ExternalTool)((ToolStripMenuItem)sender).Tag); + } + + private void StartExternalApp(ExternalTool externalTool) + { + try + { + 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); + } } #endregion + + private void SortNodesRecursive(ConnectionInfo sortTarget, ListSortDirection sortDirection) + { + if (sortTarget == null) + sortTarget = _connectionTree.GetRootConnectionNode(); + + var sortTargetAsContainer = sortTarget as ContainerInfo; + if (sortTargetAsContainer != null) + sortTargetAsContainer.SortRecursive(sortDirection); + else + _connectionTree.SelectedNode.Parent.SortRecursive(sortDirection); + + Runtime.SaveConnectionsAsync(); + } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs new file mode 100644 index 000000000..2c3c0b1c5 --- /dev/null +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs @@ -0,0 +1,36 @@ +namespace mRemoteNG.UI.Controls +{ + partial class ConnectionTree + { + /// + /// 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 Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs new file mode 100644 index 000000000..ea0769394 --- /dev/null +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; +using BrightIdeasSoftware; +using mRemoteNG.App; +using mRemoteNG.Config.Putty; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; + + +namespace mRemoteNG.UI.Controls +{ + public partial class ConnectionTree : TreeListView, IConnectionTree + { + private ConnectionTreeModel _connectionTreeModel; + private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); + private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; + + public ConnectionInfo SelectedNode => (ConnectionInfo) SelectedObject; + + public NodeSearcher NodeSearcher { get; private set; } + + public IConfirm NodeDeletionConfirmer { get; set; } = new AlwaysConfirmYes(); + + public IEnumerable PostSetupActions { get; set; } = new IConnectionTreeDelegate[0]; + + public ITreeNodeClickHandler DoubleClickHandler { get; set; } = new TreeNodeCompositeClickHandler(); + + public ITreeNodeClickHandler SingleClickHandler { get; set; } = new TreeNodeCompositeClickHandler(); + + public ConnectionTreeModel ConnectionTreeModel + { + get { return _connectionTreeModel; } + set + { + _connectionTreeModel = value; + PopulateTreeView(); + } + } + + + public ConnectionTree() + { + InitializeComponent(); + SetupConnectionTreeView(); + } + + #region ConnectionTree Setup + private void SetupConnectionTreeView() + { + var imageList = new StatusImageList(); + SmallImageList = imageList.GetImageList(); + AddColumns(imageList.ImageGetter); + LinkModelToView(); + SetupDropSink(); + SetEventHandlers(); + } + + private void AddColumns(ImageGetterDelegate imageGetterDelegate) + { + Columns.Add(new NameColumn(imageGetterDelegate)); + } + + private void LinkModelToView() + { + CanExpandGetter = item => + { + var itemAsContainer = item as ContainerInfo; + return itemAsContainer?.Children.Count > 0; + }; + ChildrenGetter = item => ((ContainerInfo)item).Children; + } + + private void SetupDropSink() + { + DropSink = new SimpleDropSink + { + CanDropBetween = true + }; + } + + private void SetEventHandlers() + { + Collapsed += (sender, args) => + { + var container = args.Model as ContainerInfo; + if (container != null) + container.IsExpanded = false; + }; + Expanded += (sender, args) => + { + var container = args.Model as ContainerInfo; + if (container != null) + container.IsExpanded = true; + }; + SelectionChanged += tvConnections_AfterSelect; + MouseDoubleClick += OnMouse_DoubleClick; + MouseClick += OnMouse_SingleClick; + CellToolTipShowing += tvConnections_CellToolTipShowing; + ModelCanDrop += _dragAndDropHandler.HandleEvent_ModelCanDrop; + ModelDropped += _dragAndDropHandler.HandleEvent_ModelDropped; + } + + private void PopulateTreeView() + { + UnregisterModelUpdateHandlers(); + SetObjects(ConnectionTreeModel.RootNodes); + RegisterModelUpdateHandlers(); + NodeSearcher = new NodeSearcher(ConnectionTreeModel); + ExecutePostSetupActions(); + } + + private void RegisterModelUpdateHandlers() + { + _puttySessionsManager.PuttySessionsCollectionChanged += OnPuttySessionsCollectionChanged; + ConnectionTreeModel.CollectionChanged += HandleCollectionChanged; + ConnectionTreeModel.PropertyChanged += HandleCollectionPropertyChanged; + } + + private void UnregisterModelUpdateHandlers() + { + _puttySessionsManager.PuttySessionsCollectionChanged -= OnPuttySessionsCollectionChanged; + ConnectionTreeModel.CollectionChanged -= HandleCollectionChanged; + ConnectionTreeModel.PropertyChanged -= HandleCollectionPropertyChanged; + } + + private void OnPuttySessionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) + { + RefreshObjects(GetRootPuttyNodes().ToList()); + } + + private void HandleCollectionPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + { + //TODO for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication + var property = propertyChangedEventArgs.PropertyName; + if (property != "Name" && property != "OpenConnections") return; + var senderAsConnectionInfo = sender as ConnectionInfo; + if (senderAsConnectionInfo != null) + RefreshObject(senderAsConnectionInfo); + } + + private void ExecutePostSetupActions() + { + foreach (var action in PostSetupActions) + { + action.Execute(this); + } + } + #endregion + + #region ConnectionTree Behavior + public RootNodeInfo GetRootConnectionNode() + { + return (RootNodeInfo)Roots.Cast().First(item => item is RootNodeInfo); + } + + public void InvokeExpand(object model) + { + Invoke((MethodInvoker)(() => Expand(model))); + } + + public void InvokeRebuildAll(bool preserveState) + { + Invoke((MethodInvoker)(() => RebuildAll(preserveState))); + } + + public IEnumerable GetRootPuttyNodes() + { + return Objects.OfType(); + } + + public void AddConnection() + { + try + { + AddNode(new ConnectionInfo()); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("UI.Window.Tree.AddConnection() failed.", ex); + } + } + + public void AddFolder() + { + try + { + AddNode(new ContainerInfo()); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.strErrorAddFolderFailed, ex); + } + } + + private void AddNode(ConnectionInfo newNode) + { + if (SelectedNode == null) return; + DefaultConnectionInfo.Instance.SaveTo(newNode); + DefaultConnectionInheritance.Instance.SaveTo(newNode.Inheritance); + var selectedContainer = SelectedNode as ContainerInfo; + var parent = selectedContainer ?? SelectedNode?.Parent; + newNode.SetParent(parent); + Expand(parent); + SelectObject(newNode, true); + EnsureModelVisible(newNode); + } + + public void DuplicateSelectedNode() + { + var newNode = SelectedNode.Clone(); + newNode.Parent.SetChildBelow(newNode, SelectedNode); + Runtime.SaveConnectionsAsync(); + } + + public void RenameSelectedNode() + { + SelectedItem.BeginEdit(); + Runtime.SaveConnectionsAsync(); + } + + public void DeleteSelectedNode() + { + if (SelectedNode is RootNodeInfo || SelectedNode is PuttySessionInfo) return; + if (!NodeDeletionConfirmer.Confirm()) return; + ConnectionTreeModel.DeleteNode(SelectedNode); + Runtime.SaveConnectionsAsync(); + } + + private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) + { + RefreshObject(sender); + } + + private void tvConnections_AfterSelect(object sender, EventArgs e) + { + try + { + Windows.ConfigForm.SelectedTreeNode = SelectedNode; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterSelect (UI.Window.ConnectionTreeWindow) failed", ex); + } + } + + private void OnMouse_DoubleClick(object sender, MouseEventArgs mouseEventArgs) + { + if (mouseEventArgs.Clicks < 2) return; + OLVColumn column; + var listItem = GetItemAt(mouseEventArgs.X, mouseEventArgs.Y, out column); + var clickedNode = listItem.RowObject as ConnectionInfo; + if (clickedNode == null) return; + DoubleClickHandler.Execute(clickedNode); + } + + private void OnMouse_SingleClick(object sender, MouseEventArgs mouseEventArgs) + { + if (mouseEventArgs.Clicks > 1) return; + OLVColumn column; + var listItem = GetItemAt(mouseEventArgs.X, mouseEventArgs.Y, out column); + var clickedNode = listItem.RowObject as ConnectionInfo; + if (clickedNode == null) return; + SingleClickHandler.Execute(clickedNode); + } + + private void tvConnections_CellToolTipShowing(object sender, ToolTipShowingEventArgs e) + { + try + { + var nodeProducingTooltip = (ConnectionInfo)e.Model; + e.Text = nodeProducingTooltip.Description; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_MouseMove (UI.Window.ConnectionTreeWindow) failed", ex); + } + } + #endregion + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTree.cs new file mode 100644 index 000000000..3edc92875 --- /dev/null +++ b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTree.cs @@ -0,0 +1,25 @@ +using System.Collections; +using mRemoteNG.Connection; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; + + +namespace mRemoteNG.UI.Controls +{ + public interface IConnectionTree + { + ConnectionTreeModel ConnectionTreeModel { get; set; } + + ConnectionInfo SelectedNode { get; } + + IEnumerable ExpandedObjects { get; set; } + + RootNodeInfo GetRootConnectionNode(); + + void InvokeExpand(object model); + + void InvokeRebuildAll(bool preserveState); + + void ToggleExpansion(object model); + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs new file mode 100644 index 000000000..77643a1e5 --- /dev/null +++ b/mRemoteV1/UI/Controls/ConnectionTree/IConnectionTreeDelegate.cs @@ -0,0 +1,8 @@ + +namespace mRemoteNG.UI.Controls +{ + public interface IConnectionTreeDelegate + { + void Execute(IConnectionTree connectionTree); + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs b/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs new file mode 100644 index 000000000..8903f1839 --- /dev/null +++ b/mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs @@ -0,0 +1,18 @@ +using BrightIdeasSoftware; +using mRemoteNG.Connection; + + +namespace mRemoteNG.UI.Controls +{ + public class NameColumn : OLVColumn + { + public NameColumn(ImageGetterDelegate imageGetterDelegate) + { + AspectName = "Name"; + FillsFreeSpace = true; + IsButton = true; + AspectGetter = item => ((ConnectionInfo) item).Name; + ImageGetter = imageGetterDelegate; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/QuickConnectComboBox.cs b/mRemoteV1/UI/Controls/QuickConnectComboBox.cs index 0ea734364..2161a1e67 100644 --- a/mRemoteV1/UI/Controls/QuickConnectComboBox.cs +++ b/mRemoteV1/UI/Controls/QuickConnectComboBox.cs @@ -9,7 +9,7 @@ namespace mRemoteNG.UI.Controls { public class QuickConnectComboBox : ToolStripComboBox { - private ComboBox _comboBox; + private readonly ComboBox _comboBox; private bool _ignoreEnter; public QuickConnectComboBox() @@ -53,7 +53,7 @@ namespace mRemoteNG.UI.Controls // 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. - object item = _comboBox.SelectedItem; + var item = _comboBox.SelectedItem; _comboBox.DroppedDown = false; _comboBox.Items.Remove(item); _comboBox.SelectedIndex = -1; @@ -66,29 +66,29 @@ namespace mRemoteNG.UI.Controls } } - private void ComboBox_SelectedIndexChanged(Object sender, EventArgs e) + private void ComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (!(_comboBox.SelectedItem is HistoryItem)) { - return ; + return; } - HistoryItem historyItem = (HistoryItem) _comboBox.SelectedItem; + var historyItem = (HistoryItem) _comboBox.SelectedItem; OnProtocolChanged(new ProtocolChangedEventArgs(historyItem.ConnectionInfo.Protocol)); } private static void ComboBox_DrawItem(object sender, DrawItemEventArgs e) { - ComboBox comboBox = sender as ComboBox; + var comboBox = sender as ComboBox; if (comboBox == null) { - return ; + return; } - object drawItem = comboBox.Items[e.Index]; + var drawItem = comboBox.Items[e.Index]; string drawString; if (drawItem is HistoryItem) { - HistoryItem historyItem = (HistoryItem) drawItem; + var historyItem = (HistoryItem) drawItem; drawString = historyItem.ToString(true); } else @@ -116,11 +116,8 @@ namespace mRemoteNG.UI.Controls { return false; } - if (ConnectionInfo.Protocol != other.ConnectionInfo.Protocol) - { - return false; - } - return true; + + return ConnectionInfo.Protocol == other.ConnectionInfo.Protocol; } public override string ToString() @@ -130,31 +127,25 @@ namespace mRemoteNG.UI.Controls public string ToString(bool includeProtocol) { - string port = string.Empty; + var port = string.Empty; if (ConnectionInfo.Port != ConnectionInfo.GetDefaultPort()) { port = $":{ConnectionInfo.Port}"; } - if (includeProtocol) - { - return $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})"; - } - else - { - return $"{ConnectionInfo.Hostname}{port}"; - } + + return includeProtocol ? $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})" : $"{ConnectionInfo.Hostname}{port}"; } } private bool Exists(HistoryItem searchItem) { - foreach (object item in _comboBox.Items) + foreach (var item in _comboBox.Items) { if (!(item is HistoryItem)) { continue; } - HistoryItem historyItem = (HistoryItem) item; + var historyItem = (HistoryItem) item; if (historyItem.Equals(searchItem)) { return true; @@ -167,7 +158,7 @@ namespace mRemoteNG.UI.Controls { try { - HistoryItem historyItem = new HistoryItem {ConnectionInfo = connectionInfo}; + var historyItem = new HistoryItem {ConnectionInfo = connectionInfo}; if (!Exists(historyItem)) { _comboBox.Items.Insert(0, historyItem); @@ -175,7 +166,7 @@ namespace mRemoteNG.UI.Controls } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex, Messages.MessageClass.ErrorMsg, true); + Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex); } } @@ -209,7 +200,8 @@ namespace mRemoteNG.UI.Controls private void OnConnectRequested(ConnectRequestedEventArgs e) { - ConnectRequestedEvent?.Invoke(this, new ConnectRequestedEventArgs(e.ConnectionString)); + // TODO: Any reason to not jsut pass "e"? + ConnectRequestedEvent?.Invoke(this, new ConnectRequestedEventArgs(e.ConnectionString)); } public class ProtocolChangedEventArgs : EventArgs @@ -241,6 +233,7 @@ namespace mRemoteNG.UI.Controls private void OnProtocolChanged(ProtocolChangedEventArgs e) { + // TODO: Any reason to not jsut pass "e"? ProtocolChangedEvent?.Invoke(this, new ProtocolChangedEventArgs(e.Protocol)); } #endregion diff --git a/mRemoteV1/UI/Controls/StatusImageList.cs b/mRemoteV1/UI/Controls/StatusImageList.cs new file mode 100644 index 000000000..b5a2413d2 --- /dev/null +++ b/mRemoteV1/UI/Controls/StatusImageList.cs @@ -0,0 +1,57 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using mRemoteNG.App; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Tree.Root; + + +namespace mRemoteNG.UI.Controls +{ + public class StatusImageList + { + public ImageList GetImageList() + { + var imageList = new ImageList + { + ColorDepth = ColorDepth.Depth32Bit, + ImageSize = new Size(16, 16), + TransparentColor = Color.Transparent + }; + FillImageList(imageList); + return imageList; + } + + public object ImageGetter(object rowObject) + { + if (rowObject is RootPuttySessionsNodeInfo) return "PuttySessions"; + if (rowObject is RootNodeInfo) return "Root"; + if (rowObject is ContainerInfo) return "Folder"; + var connection = rowObject as ConnectionInfo; + if (connection == null) return ""; + return connection.OpenConnections.Count > 0 ? "Play" : "Pause"; + } + + private void FillImageList(ImageList imageList) + { + try + { + imageList.Images.Add(Resources.Root); + imageList.Images.SetKeyName(0, "Root"); + imageList.Images.Add(Resources.Folder); + imageList.Images.SetKeyName(1, "Folder"); + imageList.Images.Add(Resources.Play); + imageList.Images.SetKeyName(2, "Play"); + imageList.Images.Add(Resources.Pause); + imageList.Images.SetKeyName(3, "Pause"); + imageList.Images.Add(Resources.PuttySessions); + imageList.Images.SetKeyName(4, "PuttySessions"); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace($"Unable to fill the image list of type {nameof(StatusImageList)}", ex); + } + } + } +} \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/ToolStripSplitButton.cs b/mRemoteV1/UI/Controls/ToolStripSplitButton.cs index 033b448f9..ed7090851 100644 --- a/mRemoteV1/UI/Controls/ToolStripSplitButton.cs +++ b/mRemoteV1/UI/Controls/ToolStripSplitButton.cs @@ -22,7 +22,7 @@ namespace mRemoteNG.UI.Controls { if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked) { - return ; + return; } Rectangle dropDownButtonBoundsClient = DropDownButtonBounds; // Relative to the ToolStripSplitButton diff --git a/mRemoteV1/UI/Forms/ExportForm.cs b/mRemoteV1/UI/Forms/ExportForm.cs index 652124597..a7a74c3b2 100644 --- a/mRemoteV1/UI/Forms/ExportForm.cs +++ b/mRemoteV1/UI/Forms/ExportForm.cs @@ -205,7 +205,7 @@ namespace mRemoteNG.UI.Forms SelectFileTypeBasedOnSaveFormat(saveFileDialog); if (saveFileDialog.ShowDialog(this) != DialogResult.OK) - return ; + return; txtFileName.Text = saveFileDialog.FileName; } diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs index 3a9a229fd..fd5c2a34c 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs @@ -1,6 +1,7 @@ using System; using System.Windows.Forms; using mRemoteNG.App; +using mRemoteNG.Tools; namespace mRemoteNG.UI.Forms.OptionsPages { @@ -79,7 +80,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { if (Runtime.NotificationAreaIcon == null) { - Runtime.NotificationAreaIcon = new Tools.Controls.NotificationAreaIcon(); + Runtime.NotificationAreaIcon = new NotificationAreaIcon(); } } else diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs index 78e3ce2ac..06617d63a 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs @@ -29,243 +29,294 @@ namespace mRemoteNG.UI.Forms.OptionsPages //Do not modify it using the code editor. [System.Diagnostics.DebuggerStepThrough()]private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdatesPage)); - this.lblUpdatesExplanation = new System.Windows.Forms.Label(); - this.pnlUpdateCheck = new System.Windows.Forms.Panel(); - this.btnUpdateCheckNow = new System.Windows.Forms.Button(); - this.btnUpdateCheckNow.Click += new System.EventHandler(this.btnUpdateCheckNow_Click); - this.chkCheckForUpdatesOnStartup = new System.Windows.Forms.CheckBox(); - this.chkCheckForUpdatesOnStartup.CheckedChanged += new System.EventHandler(this.chkCheckForUpdatesOnStartup_CheckedChanged); - this.cboUpdateCheckFrequency = new System.Windows.Forms.ComboBox(); - this.pnlProxy = new System.Windows.Forms.Panel(); - this.pnlProxyBasic = new System.Windows.Forms.Panel(); - this.lblProxyAddress = new System.Windows.Forms.Label(); - this.txtProxyAddress = new System.Windows.Forms.TextBox(); - this.lblProxyPort = new System.Windows.Forms.Label(); - this.numProxyPort = new System.Windows.Forms.NumericUpDown(); - this.chkUseProxyForAutomaticUpdates = new System.Windows.Forms.CheckBox(); - this.chkUseProxyForAutomaticUpdates.CheckedChanged += new System.EventHandler(this.chkUseProxyForAutomaticUpdates_CheckedChanged); - this.chkUseProxyAuthentication = new System.Windows.Forms.CheckBox(); - this.chkUseProxyAuthentication.CheckedChanged += new System.EventHandler(this.chkUseProxyAuthentication_CheckedChanged); - this.pnlProxyAuthentication = new System.Windows.Forms.Panel(); - this.lblProxyUsername = new System.Windows.Forms.Label(); - this.txtProxyUsername = new System.Windows.Forms.TextBox(); - this.lblProxyPassword = new System.Windows.Forms.Label(); - this.txtProxyPassword = new System.Windows.Forms.TextBox(); - this.btnTestProxy = new System.Windows.Forms.Button(); - this.btnTestProxy.Click += new System.EventHandler(this.btnTestProxy_Click); - this.pnlUpdateCheck.SuspendLayout(); - this.pnlProxy.SuspendLayout(); - this.pnlProxyBasic.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize) this.numProxyPort).BeginInit(); - this.pnlProxyAuthentication.SuspendLayout(); - this.SuspendLayout(); - // - //lblUpdatesExplanation - // - this.lblUpdatesExplanation.Location = new System.Drawing.Point(3, 0); - this.lblUpdatesExplanation.Name = "lblUpdatesExplanation"; - this.lblUpdatesExplanation.Size = new System.Drawing.Size(536, 40); - this.lblUpdatesExplanation.TabIndex = 3; - this.lblUpdatesExplanation.Text = "mRemoteNG can periodically connect to the mRemoteNG website to check for updates."; - // - //pnlUpdateCheck - // - this.pnlUpdateCheck.Controls.Add(this.btnUpdateCheckNow); - this.pnlUpdateCheck.Controls.Add(this.chkCheckForUpdatesOnStartup); - this.pnlUpdateCheck.Controls.Add(this.cboUpdateCheckFrequency); - this.pnlUpdateCheck.Location = new System.Drawing.Point(0, 48); - this.pnlUpdateCheck.Name = "pnlUpdateCheck"; - this.pnlUpdateCheck.Size = new System.Drawing.Size(610, 120); - this.pnlUpdateCheck.TabIndex = 4; - // - //btnUpdateCheckNow - // - this.btnUpdateCheckNow.Location = new System.Drawing.Point(3, 80); - this.btnUpdateCheckNow.Name = "btnUpdateCheckNow"; - this.btnUpdateCheckNow.Size = new System.Drawing.Size(120, 32); - this.btnUpdateCheckNow.TabIndex = 2; - this.btnUpdateCheckNow.Text = "Check Now"; - this.btnUpdateCheckNow.UseVisualStyleBackColor = true; - // - //chkCheckForUpdatesOnStartup - // - this.chkCheckForUpdatesOnStartup.AutoSize = true; - this.chkCheckForUpdatesOnStartup.Location = new System.Drawing.Point(3, 8); - this.chkCheckForUpdatesOnStartup.Name = "chkCheckForUpdatesOnStartup"; - this.chkCheckForUpdatesOnStartup.Size = new System.Drawing.Size(213, 17); - this.chkCheckForUpdatesOnStartup.TabIndex = 0; - this.chkCheckForUpdatesOnStartup.Text = "Check for updates"; - this.chkCheckForUpdatesOnStartup.UseVisualStyleBackColor = true; - // - //cboUpdateCheckFrequency - // - this.cboUpdateCheckFrequency.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.cboUpdateCheckFrequency.FormattingEnabled = true; - this.cboUpdateCheckFrequency.Location = new System.Drawing.Point(48, 40); - this.cboUpdateCheckFrequency.Name = "cboUpdateCheckFrequency"; - this.cboUpdateCheckFrequency.Size = new System.Drawing.Size(128, 21); - this.cboUpdateCheckFrequency.TabIndex = 1; - // - //pnlProxy - // - this.pnlProxy.Controls.Add(this.pnlProxyBasic); - this.pnlProxy.Controls.Add(this.chkUseProxyForAutomaticUpdates); - this.pnlProxy.Controls.Add(this.chkUseProxyAuthentication); - this.pnlProxy.Controls.Add(this.pnlProxyAuthentication); - this.pnlProxy.Controls.Add(this.btnTestProxy); - this.pnlProxy.Location = new System.Drawing.Point(0, 200); - this.pnlProxy.Name = "pnlProxy"; - this.pnlProxy.Size = new System.Drawing.Size(610, 224); - this.pnlProxy.TabIndex = 5; - // - //pnlProxyBasic - // - this.pnlProxyBasic.Controls.Add(this.lblProxyAddress); - this.pnlProxyBasic.Controls.Add(this.txtProxyAddress); - this.pnlProxyBasic.Controls.Add(this.lblProxyPort); - this.pnlProxyBasic.Controls.Add(this.numProxyPort); - this.pnlProxyBasic.Enabled = false; - this.pnlProxyBasic.Location = new System.Drawing.Point(3, 32); - this.pnlProxyBasic.Name = "pnlProxyBasic"; - this.pnlProxyBasic.Size = new System.Drawing.Size(604, 40); - this.pnlProxyBasic.TabIndex = 1; - // - //lblProxyAddress - // - this.lblProxyAddress.Location = new System.Drawing.Point(8, 4); - this.lblProxyAddress.Name = "lblProxyAddress"; - this.lblProxyAddress.Size = new System.Drawing.Size(96, 24); - this.lblProxyAddress.TabIndex = 0; - this.lblProxyAddress.Text = "Address:"; - this.lblProxyAddress.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - // - //txtProxyAddress - // - this.txtProxyAddress.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtProxyAddress.Location = new System.Drawing.Point(104, 8); - this.txtProxyAddress.Name = "txtProxyAddress"; - this.txtProxyAddress.Size = new System.Drawing.Size(240, 20); - this.txtProxyAddress.TabIndex = 1; - // - //lblProxyPort - // - this.lblProxyPort.Location = new System.Drawing.Point(350, 5); - this.lblProxyPort.Name = "lblProxyPort"; - this.lblProxyPort.Size = new System.Drawing.Size(64, 23); - this.lblProxyPort.TabIndex = 2; - this.lblProxyPort.Text = "Port:"; - this.lblProxyPort.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - // - //numProxyPort - // - this.numProxyPort.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.numProxyPort.Location = new System.Drawing.Point(420, 8); - this.numProxyPort.Maximum = new decimal(new int[] {65535, 0, 0, 0}); - this.numProxyPort.Minimum = new decimal(new int[] {1, 0, 0, 0}); - this.numProxyPort.Name = "numProxyPort"; - this.numProxyPort.Size = new System.Drawing.Size(64, 20); - this.numProxyPort.TabIndex = 3; - this.numProxyPort.Value = new decimal(new int[] {80, 0, 0, 0}); - // - //chkUseProxyForAutomaticUpdates - // - this.chkUseProxyForAutomaticUpdates.AutoSize = true; - this.chkUseProxyForAutomaticUpdates.Location = new System.Drawing.Point(3, 8); - this.chkUseProxyForAutomaticUpdates.Name = "chkUseProxyForAutomaticUpdates"; - this.chkUseProxyForAutomaticUpdates.Size = new System.Drawing.Size(168, 17); - this.chkUseProxyForAutomaticUpdates.TabIndex = 0; - this.chkUseProxyForAutomaticUpdates.Text = "Use a proxy server to connect"; - this.chkUseProxyForAutomaticUpdates.UseVisualStyleBackColor = true; - // - //chkUseProxyAuthentication - // - this.chkUseProxyAuthentication.AutoSize = true; - this.chkUseProxyAuthentication.Enabled = false; - this.chkUseProxyAuthentication.Location = new System.Drawing.Point(27, 80); - this.chkUseProxyAuthentication.Name = "chkUseProxyAuthentication"; - this.chkUseProxyAuthentication.Size = new System.Drawing.Size(216, 17); - this.chkUseProxyAuthentication.TabIndex = 2; - this.chkUseProxyAuthentication.Text = "This proxy server requires authentication"; - this.chkUseProxyAuthentication.UseVisualStyleBackColor = true; - // - //pnlProxyAuthentication - // - this.pnlProxyAuthentication.Controls.Add(this.lblProxyUsername); - this.pnlProxyAuthentication.Controls.Add(this.txtProxyUsername); - this.pnlProxyAuthentication.Controls.Add(this.lblProxyPassword); - this.pnlProxyAuthentication.Controls.Add(this.txtProxyPassword); - this.pnlProxyAuthentication.Enabled = false; - this.pnlProxyAuthentication.Location = new System.Drawing.Point(3, 104); - this.pnlProxyAuthentication.Name = "pnlProxyAuthentication"; - this.pnlProxyAuthentication.Size = new System.Drawing.Size(604, 72); - this.pnlProxyAuthentication.TabIndex = 3; - // - //lblProxyUsername - // - this.lblProxyUsername.Location = new System.Drawing.Point(8, 4); - this.lblProxyUsername.Name = "lblProxyUsername"; - this.lblProxyUsername.Size = new System.Drawing.Size(96, 24); - this.lblProxyUsername.TabIndex = 0; - this.lblProxyUsername.Text = "Username:"; - this.lblProxyUsername.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - // - //txtProxyUsername - // - this.txtProxyUsername.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtProxyUsername.Location = new System.Drawing.Point(104, 8); - this.txtProxyUsername.Name = "txtProxyUsername"; - this.txtProxyUsername.Size = new System.Drawing.Size(240, 20); - this.txtProxyUsername.TabIndex = 1; - // - //lblProxyPassword - // - this.lblProxyPassword.Location = new System.Drawing.Point(8, 36); - this.lblProxyPassword.Name = "lblProxyPassword"; - this.lblProxyPassword.Size = new System.Drawing.Size(96, 24); - this.lblProxyPassword.TabIndex = 2; - this.lblProxyPassword.Text = "Password:"; - this.lblProxyPassword.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - // - //txtProxyPassword - // - this.txtProxyPassword.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtProxyPassword.Location = new System.Drawing.Point(104, 40); - this.txtProxyPassword.Name = "txtProxyPassword"; - this.txtProxyPassword.Size = new System.Drawing.Size(240, 20); - this.txtProxyPassword.TabIndex = 3; - this.txtProxyPassword.UseSystemPasswordChar = true; - // - //btnTestProxy - // - this.btnTestProxy.Location = new System.Drawing.Point(3, 184); - this.btnTestProxy.Name = "btnTestProxy"; - this.btnTestProxy.Size = new System.Drawing.Size(120, 32); - this.btnTestProxy.TabIndex = 4; - this.btnTestProxy.Text = "Test Proxy"; - this.btnTestProxy.UseVisualStyleBackColor = true; - // - //UpdatesPage - // - this.AutoScaleDimensions = new System.Drawing.SizeF((float) (6.0F), (float) (13.0F)); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.lblUpdatesExplanation); - this.Controls.Add(this.pnlUpdateCheck); - this.Controls.Add(this.pnlProxy); - this.Name = "UpdatesPage"; - this.PageIcon = (System.Drawing.Icon) (resources.GetObject("$this.PageIcon")); - this.Size = new System.Drawing.Size(610, 489); - this.pnlUpdateCheck.ResumeLayout(false); - this.pnlUpdateCheck.PerformLayout(); - this.pnlProxy.ResumeLayout(false); - this.pnlProxy.PerformLayout(); - this.pnlProxyBasic.ResumeLayout(false); - this.pnlProxyBasic.PerformLayout(); - ((System.ComponentModel.ISupportInitialize) this.numProxyPort).EndInit(); - this.pnlProxyAuthentication.ResumeLayout(false); - this.pnlProxyAuthentication.PerformLayout(); - this.ResumeLayout(false); - + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdatesPage)); + this.lblUpdatesExplanation = new System.Windows.Forms.Label(); + this.pnlUpdateCheck = new System.Windows.Forms.Panel(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.lblReleaseChannel = new System.Windows.Forms.Label(); + this.cboReleaseChannel = new System.Windows.Forms.ComboBox(); + this.btnUpdateCheckNow = new System.Windows.Forms.Button(); + this.chkCheckForUpdatesOnStartup = new System.Windows.Forms.CheckBox(); + this.cboUpdateCheckFrequency = new System.Windows.Forms.ComboBox(); + this.pnlProxy = new System.Windows.Forms.Panel(); + this.pnlProxyBasic = new System.Windows.Forms.Panel(); + this.lblProxyAddress = new System.Windows.Forms.Label(); + this.txtProxyAddress = new System.Windows.Forms.TextBox(); + this.lblProxyPort = new System.Windows.Forms.Label(); + this.numProxyPort = new System.Windows.Forms.NumericUpDown(); + this.chkUseProxyForAutomaticUpdates = new System.Windows.Forms.CheckBox(); + this.chkUseProxyAuthentication = new System.Windows.Forms.CheckBox(); + this.pnlProxyAuthentication = new System.Windows.Forms.Panel(); + this.lblProxyUsername = new System.Windows.Forms.Label(); + this.txtProxyUsername = new System.Windows.Forms.TextBox(); + this.lblProxyPassword = new System.Windows.Forms.Label(); + this.txtProxyPassword = new System.Windows.Forms.TextBox(); + this.btnTestProxy = new System.Windows.Forms.Button(); + this.pnlUpdateCheck.SuspendLayout(); + this.pnlProxy.SuspendLayout(); + this.pnlProxyBasic.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numProxyPort)).BeginInit(); + this.pnlProxyAuthentication.SuspendLayout(); + this.SuspendLayout(); + // + // lblUpdatesExplanation + // + this.lblUpdatesExplanation.Location = new System.Drawing.Point(3, 0); + this.lblUpdatesExplanation.Name = "lblUpdatesExplanation"; + this.lblUpdatesExplanation.Size = new System.Drawing.Size(536, 40); + this.lblUpdatesExplanation.TabIndex = 3; + this.lblUpdatesExplanation.Text = "mRemoteNG can periodically connect to the mRemoteNG website to check for updates." + + ""; + // + // pnlUpdateCheck + // + this.pnlUpdateCheck.Controls.Add(this.textBox1); + this.pnlUpdateCheck.Controls.Add(this.lblReleaseChannel); + this.pnlUpdateCheck.Controls.Add(this.cboReleaseChannel); + this.pnlUpdateCheck.Controls.Add(this.btnUpdateCheckNow); + this.pnlUpdateCheck.Controls.Add(this.chkCheckForUpdatesOnStartup); + this.pnlUpdateCheck.Controls.Add(this.cboUpdateCheckFrequency); + this.pnlUpdateCheck.Location = new System.Drawing.Point(0, 48); + this.pnlUpdateCheck.Name = "pnlUpdateCheck"; + this.pnlUpdateCheck.Size = new System.Drawing.Size(610, 120); + this.pnlUpdateCheck.TabIndex = 4; + // + // textBox1 + // + this.textBox1.BackColor = System.Drawing.SystemColors.Control; + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox1.Location = new System.Drawing.Point(226, 68); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.Size = new System.Drawing.Size(366, 44); + this.textBox1.TabIndex = 5; + this.textBox1.Text = "Stable channel includes final releases only.\r\nBeta channel includes Betas & Relea" + + "se Candidates.\r\nDevelopment Channel includes Alphas, Betas & Release Candidates." + + ""; + // + // lblReleaseChannel + // + this.lblReleaseChannel.AutoSize = true; + this.lblReleaseChannel.Location = new System.Drawing.Point(223, 12); + this.lblReleaseChannel.Name = "lblReleaseChannel"; + this.lblReleaseChannel.Size = new System.Drawing.Size(91, 13); + this.lblReleaseChannel.TabIndex = 4; + this.lblReleaseChannel.Text = "Release Channel:"; + // + // cboReleaseChannel + // + this.cboReleaseChannel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboReleaseChannel.FormattingEnabled = true; + this.cboReleaseChannel.Location = new System.Drawing.Point(226, 41); + this.cboReleaseChannel.Name = "cboReleaseChannel"; + this.cboReleaseChannel.Size = new System.Drawing.Size(121, 21); + this.cboReleaseChannel.TabIndex = 3; + // + // btnUpdateCheckNow + // + this.btnUpdateCheckNow.Location = new System.Drawing.Point(3, 80); + this.btnUpdateCheckNow.Name = "btnUpdateCheckNow"; + this.btnUpdateCheckNow.Size = new System.Drawing.Size(120, 32); + this.btnUpdateCheckNow.TabIndex = 2; + this.btnUpdateCheckNow.Text = "Check Now"; + this.btnUpdateCheckNow.UseVisualStyleBackColor = true; + this.btnUpdateCheckNow.Click += new System.EventHandler(this.btnUpdateCheckNow_Click); + // + // chkCheckForUpdatesOnStartup + // + this.chkCheckForUpdatesOnStartup.AutoSize = true; + this.chkCheckForUpdatesOnStartup.Location = new System.Drawing.Point(3, 8); + this.chkCheckForUpdatesOnStartup.Name = "chkCheckForUpdatesOnStartup"; + this.chkCheckForUpdatesOnStartup.Size = new System.Drawing.Size(113, 17); + this.chkCheckForUpdatesOnStartup.TabIndex = 0; + this.chkCheckForUpdatesOnStartup.Text = "Check for updates"; + this.chkCheckForUpdatesOnStartup.UseVisualStyleBackColor = true; + this.chkCheckForUpdatesOnStartup.CheckedChanged += new System.EventHandler(this.chkCheckForUpdatesOnStartup_CheckedChanged); + // + // cboUpdateCheckFrequency + // + this.cboUpdateCheckFrequency.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboUpdateCheckFrequency.FormattingEnabled = true; + this.cboUpdateCheckFrequency.Location = new System.Drawing.Point(3, 41); + this.cboUpdateCheckFrequency.Name = "cboUpdateCheckFrequency"; + this.cboUpdateCheckFrequency.Size = new System.Drawing.Size(128, 21); + this.cboUpdateCheckFrequency.TabIndex = 1; + // + // pnlProxy + // + this.pnlProxy.Controls.Add(this.pnlProxyBasic); + this.pnlProxy.Controls.Add(this.chkUseProxyForAutomaticUpdates); + this.pnlProxy.Controls.Add(this.chkUseProxyAuthentication); + this.pnlProxy.Controls.Add(this.pnlProxyAuthentication); + this.pnlProxy.Controls.Add(this.btnTestProxy); + this.pnlProxy.Location = new System.Drawing.Point(0, 200); + this.pnlProxy.Name = "pnlProxy"; + this.pnlProxy.Size = new System.Drawing.Size(610, 224); + this.pnlProxy.TabIndex = 5; + // + // pnlProxyBasic + // + this.pnlProxyBasic.Controls.Add(this.lblProxyAddress); + this.pnlProxyBasic.Controls.Add(this.txtProxyAddress); + this.pnlProxyBasic.Controls.Add(this.lblProxyPort); + this.pnlProxyBasic.Controls.Add(this.numProxyPort); + this.pnlProxyBasic.Enabled = false; + this.pnlProxyBasic.Location = new System.Drawing.Point(3, 32); + this.pnlProxyBasic.Name = "pnlProxyBasic"; + this.pnlProxyBasic.Size = new System.Drawing.Size(604, 40); + this.pnlProxyBasic.TabIndex = 1; + // + // lblProxyAddress + // + this.lblProxyAddress.Location = new System.Drawing.Point(8, 4); + this.lblProxyAddress.Name = "lblProxyAddress"; + this.lblProxyAddress.Size = new System.Drawing.Size(96, 24); + this.lblProxyAddress.TabIndex = 0; + this.lblProxyAddress.Text = "Address:"; + this.lblProxyAddress.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // txtProxyAddress + // + this.txtProxyAddress.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtProxyAddress.Location = new System.Drawing.Point(104, 8); + this.txtProxyAddress.Name = "txtProxyAddress"; + this.txtProxyAddress.Size = new System.Drawing.Size(240, 20); + this.txtProxyAddress.TabIndex = 1; + // + // lblProxyPort + // + this.lblProxyPort.Location = new System.Drawing.Point(350, 5); + this.lblProxyPort.Name = "lblProxyPort"; + this.lblProxyPort.Size = new System.Drawing.Size(64, 23); + this.lblProxyPort.TabIndex = 2; + this.lblProxyPort.Text = "Port:"; + this.lblProxyPort.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // numProxyPort + // + this.numProxyPort.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.numProxyPort.Location = new System.Drawing.Point(420, 8); + this.numProxyPort.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numProxyPort.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numProxyPort.Name = "numProxyPort"; + this.numProxyPort.Size = new System.Drawing.Size(64, 20); + this.numProxyPort.TabIndex = 3; + this.numProxyPort.Value = new decimal(new int[] { + 80, + 0, + 0, + 0}); + // + // chkUseProxyForAutomaticUpdates + // + this.chkUseProxyForAutomaticUpdates.AutoSize = true; + this.chkUseProxyForAutomaticUpdates.Location = new System.Drawing.Point(3, 8); + this.chkUseProxyForAutomaticUpdates.Name = "chkUseProxyForAutomaticUpdates"; + this.chkUseProxyForAutomaticUpdates.Size = new System.Drawing.Size(168, 17); + this.chkUseProxyForAutomaticUpdates.TabIndex = 0; + this.chkUseProxyForAutomaticUpdates.Text = "Use a proxy server to connect"; + this.chkUseProxyForAutomaticUpdates.UseVisualStyleBackColor = true; + this.chkUseProxyForAutomaticUpdates.CheckedChanged += new System.EventHandler(this.chkUseProxyForAutomaticUpdates_CheckedChanged); + // + // chkUseProxyAuthentication + // + this.chkUseProxyAuthentication.AutoSize = true; + this.chkUseProxyAuthentication.Enabled = false; + this.chkUseProxyAuthentication.Location = new System.Drawing.Point(27, 80); + this.chkUseProxyAuthentication.Name = "chkUseProxyAuthentication"; + this.chkUseProxyAuthentication.Size = new System.Drawing.Size(216, 17); + this.chkUseProxyAuthentication.TabIndex = 2; + this.chkUseProxyAuthentication.Text = "This proxy server requires authentication"; + this.chkUseProxyAuthentication.UseVisualStyleBackColor = true; + this.chkUseProxyAuthentication.CheckedChanged += new System.EventHandler(this.chkUseProxyAuthentication_CheckedChanged); + // + // pnlProxyAuthentication + // + this.pnlProxyAuthentication.Controls.Add(this.lblProxyUsername); + this.pnlProxyAuthentication.Controls.Add(this.txtProxyUsername); + this.pnlProxyAuthentication.Controls.Add(this.lblProxyPassword); + this.pnlProxyAuthentication.Controls.Add(this.txtProxyPassword); + this.pnlProxyAuthentication.Enabled = false; + this.pnlProxyAuthentication.Location = new System.Drawing.Point(3, 104); + this.pnlProxyAuthentication.Name = "pnlProxyAuthentication"; + this.pnlProxyAuthentication.Size = new System.Drawing.Size(604, 72); + this.pnlProxyAuthentication.TabIndex = 3; + // + // lblProxyUsername + // + this.lblProxyUsername.Location = new System.Drawing.Point(8, 4); + this.lblProxyUsername.Name = "lblProxyUsername"; + this.lblProxyUsername.Size = new System.Drawing.Size(96, 24); + this.lblProxyUsername.TabIndex = 0; + this.lblProxyUsername.Text = "Username:"; + this.lblProxyUsername.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // txtProxyUsername + // + this.txtProxyUsername.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtProxyUsername.Location = new System.Drawing.Point(104, 8); + this.txtProxyUsername.Name = "txtProxyUsername"; + this.txtProxyUsername.Size = new System.Drawing.Size(240, 20); + this.txtProxyUsername.TabIndex = 1; + // + // lblProxyPassword + // + this.lblProxyPassword.Location = new System.Drawing.Point(8, 36); + this.lblProxyPassword.Name = "lblProxyPassword"; + this.lblProxyPassword.Size = new System.Drawing.Size(96, 24); + this.lblProxyPassword.TabIndex = 2; + this.lblProxyPassword.Text = "Password:"; + this.lblProxyPassword.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // txtProxyPassword + // + this.txtProxyPassword.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtProxyPassword.Location = new System.Drawing.Point(104, 40); + this.txtProxyPassword.Name = "txtProxyPassword"; + this.txtProxyPassword.Size = new System.Drawing.Size(240, 20); + this.txtProxyPassword.TabIndex = 3; + this.txtProxyPassword.UseSystemPasswordChar = true; + // + // btnTestProxy + // + this.btnTestProxy.Location = new System.Drawing.Point(3, 184); + this.btnTestProxy.Name = "btnTestProxy"; + this.btnTestProxy.Size = new System.Drawing.Size(120, 32); + this.btnTestProxy.TabIndex = 4; + this.btnTestProxy.Text = "Test Proxy"; + this.btnTestProxy.UseVisualStyleBackColor = true; + this.btnTestProxy.Click += new System.EventHandler(this.btnTestProxy_Click); + // + // UpdatesPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lblUpdatesExplanation); + this.Controls.Add(this.pnlUpdateCheck); + this.Controls.Add(this.pnlProxy); + this.Name = "UpdatesPage"; + this.PageIcon = ((System.Drawing.Icon)(resources.GetObject("$this.PageIcon"))); + this.Size = new System.Drawing.Size(610, 489); + this.pnlUpdateCheck.ResumeLayout(false); + this.pnlUpdateCheck.PerformLayout(); + this.pnlProxy.ResumeLayout(false); + this.pnlProxy.PerformLayout(); + this.pnlProxyBasic.ResumeLayout(false); + this.pnlProxyBasic.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numProxyPort)).EndInit(); + this.pnlProxyAuthentication.ResumeLayout(false); + this.pnlProxyAuthentication.PerformLayout(); + this.ResumeLayout(false); + } internal System.Windows.Forms.Label lblUpdatesExplanation; internal System.Windows.Forms.Panel pnlUpdateCheck; @@ -286,6 +337,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages internal System.Windows.Forms.Label lblProxyPassword; internal System.Windows.Forms.TextBox txtProxyPassword; internal System.Windows.Forms.Button btnTestProxy; - - } + private System.Windows.Forms.Label lblReleaseChannel; + private System.Windows.Forms.ComboBox cboReleaseChannel; + private System.Windows.Forms.TextBox textBox1; + } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs index b1d49f2b0..2ea1fea1e 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs @@ -2,6 +2,7 @@ using System; using System.ComponentModel; using System.Windows.Forms; using mRemoteNG.App; +using mRemoteNG.App.Info; using mRemoteNG.App.Update; using mRemoteNG.Security.SymmetricEncryption; using mRemoteNG.Tools; @@ -84,6 +85,25 @@ namespace mRemoteNG.UI.Forms.OptionsPages break; } + var stable = cboReleaseChannel.Items.Add(UpdateChannelInfo.STABLE); + var beta = cboReleaseChannel.Items.Add(UpdateChannelInfo.BETA); + var dev = cboReleaseChannel.Items.Add(UpdateChannelInfo.DEV); + switch (Settings.Default.UpdateChannel) + { + case UpdateChannelInfo.STABLE: + cboReleaseChannel.SelectedIndex = stable; + break; + case UpdateChannelInfo.BETA: + cboReleaseChannel.SelectedIndex = beta; + break; + case UpdateChannelInfo.DEV: + cboReleaseChannel.SelectedIndex = dev; + break; + default: + cboReleaseChannel.SelectedIndex = stable; + break; + } + chkUseProxyForAutomaticUpdates.Checked = Convert.ToBoolean(Settings.Default.UpdateUseProxy); pnlProxyBasic.Enabled = Convert.ToBoolean(Settings.Default.UpdateUseProxy); txtProxyAddress.Text = Convert.ToString(Settings.Default.UpdateProxyAddress); @@ -116,6 +136,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages Settings.Default.CheckForUpdatesFrequencyDays = 31; } + Settings.Default.UpdateChannel = cboReleaseChannel.Text; + Settings.Default.UpdateUseProxy = chkUseProxyForAutomaticUpdates.Checked; Settings.Default.UpdateProxyAddress = txtProxyAddress.Text; Settings.Default.UpdateProxyPort = (int) numProxyPort.Value; diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.resx b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.resx index 90e6d05ef..cef4dd5fc 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.resx +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.resx @@ -112,12 +112,12 @@ 2.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 - + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 5d632e74f..d76d507b9 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -44,6 +44,8 @@ namespace mRemoteNG.UI.Forms private ConnectionInfo _selectedConnection; private SystemMenu _systemMenu; private ConnectionTreeWindow ConnectionTreeWindow { get; set; } + private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); + @@ -51,7 +53,7 @@ namespace mRemoteNG.UI.Forms { _showFullPathInTitle = Settings.Default.ShowCompleteConsPathInTitle; InitializeComponent(); - Fullscreen = new MiscTools.Fullscreen(this); + _fullscreen = new Fullscreen(this); pnlDock.Theme = new VS2012LightTheme(); } @@ -120,10 +122,68 @@ namespace mRemoteNG.UI.Forms } } - public MiscTools.Fullscreen Fullscreen { get; set; } + internal Fullscreen _fullscreen { get; set; } + + internal class Fullscreen + { + public Fullscreen(Form handledForm) + { + _handledForm = handledForm; + } + + private readonly Form _handledForm; + private FormWindowState _savedWindowState; + private FormBorderStyle _savedBorderStyle; + private Rectangle _savedBounds; + + private bool _value; + public bool Value + { + get + { + return _value; + } + set + { + if (_value == value) + { + return; + } + if (!_value) + { + EnterFullscreen(); + } + else + { + ExitFullscreen(); + } + _value = value; + } + } + + private void EnterFullscreen() + { + _savedBorderStyle = _handledForm.FormBorderStyle; + _savedWindowState = _handledForm.WindowState; + _savedBounds = _handledForm.Bounds; + + _handledForm.FormBorderStyle = FormBorderStyle.None; + if (_handledForm.WindowState == FormWindowState.Maximized) + { + _handledForm.WindowState = FormWindowState.Normal; + } + _handledForm.WindowState = FormWindowState.Maximized; + } + private void ExitFullscreen() + { + _handledForm.FormBorderStyle = _savedBorderStyle; + _handledForm.WindowState = _savedWindowState; + _handledForm.Bounds = _savedBounds; + } + } #endregion - + #region Startup & Shutdown private void frmMain_Load(object sender, EventArgs e) { @@ -164,7 +224,7 @@ namespace mRemoteNG.UI.Forms ConnectionTreeWindow = Windows.TreeForm; } - private void ApplyLanguage() + private void ApplyLanguage() { mMenFile.Text = Language.strMenuFile; mMenFileNew.Text = Language.strMenuNewConnectionFile; @@ -384,11 +444,11 @@ namespace mRemoteNG.UI.Forms } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorAddExternalToolsToToolBarFailed, ex.Message), true); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strErrorAddExternalToolsToToolBarFailed, ex); } } - private void tsExtAppEntry_Click(object sender, EventArgs e) + private static void tsExtAppEntry_Click(object sender, EventArgs e) { var extA = (ExternalTool)((ToolStripButton)sender).Tag; @@ -426,6 +486,7 @@ namespace mRemoteNG.UI.Forms private void mMenFile_DropDownOpening(object sender, EventArgs e) { var selectedNodeType = ConnectionTreeWindow.SelectedNode?.GetTreeNodeType(); + // ReSharper disable once SwitchStatementMissingSomeCases switch (selectedNodeType) { case TreeNodeType.Root: @@ -494,19 +555,19 @@ namespace mRemoteNG.UI.Forms private void mMenFileNewConnection_Click(object sender, EventArgs e) { - ConnectionTreeWindow.AddConnection(); + ConnectionTreeWindow.ConnectionTree.AddConnection(); Runtime.SaveConnectionsAsync(); } private void mMenFileNewFolder_Click(object sender, EventArgs e) { - ConnectionTreeWindow.AddFolder(); + ConnectionTreeWindow.ConnectionTree.AddFolder(); Runtime.SaveConnectionsAsync(); } private void mMenFileNew_Click(object sender, EventArgs e) { - var saveFileDialog = Tools.Controls.ConnectionsSaveAsDialog(); + var saveFileDialog = ConnectionsSaveAsDialog(); if (saveFileDialog.ShowDialog() != DialogResult.OK) { return; @@ -546,19 +607,19 @@ namespace mRemoteNG.UI.Forms private void mMenFileDelete_Click(object sender, EventArgs e) { - ConnectionTreeWindow.DeleteSelectedNode(); + ConnectionTreeWindow.ConnectionTree.DeleteSelectedNode(); Runtime.SaveConnectionsAsync(); } private void mMenFileRename_Click(object sender, EventArgs e) { - ConnectionTreeWindow.RenameSelectedNode(); + ConnectionTreeWindow.ConnectionTree.RenameSelectedNode(); Runtime.SaveConnectionsAsync(); } private void mMenFileDuplicate_Click(object sender, EventArgs e) { - ConnectionTreeWindow.DuplicateSelectedNode(); + ConnectionTreeWindow.ConnectionTree.DuplicateSelectedNode(); Runtime.SaveConnectionsAsync(); } @@ -584,7 +645,7 @@ namespace mRemoteNG.UI.Forms foreach (var i in ICList) { i.Protocol.Close(); - ConnectionInitiator.OpenConnection(i.Info, ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(i.Info, ConnectionInfo.Force.DoNotJump); } // throw it on the garbage collector @@ -623,6 +684,18 @@ namespace mRemoteNG.UI.Forms { Shutdown.Quit(); } + + public static SaveFileDialog ConnectionsSaveAsDialog() + { + return new SaveFileDialog + { + CheckPathExists = true, + InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath, + FileName = ConnectionsFileInfo.DefaultConnectionsFile, + OverwritePrompt = true, + Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*" + }; + } #endregion #region View @@ -733,7 +806,7 @@ namespace mRemoteNG.UI.Forms MessageBoxIcon.Question); if (msgBoxResult == DialogResult.Yes) { - Startup.Instance.SetDefaultLayout(); + Default.SetDefaultLayout(); } } @@ -772,8 +845,8 @@ namespace mRemoteNG.UI.Forms private void mMenViewFullscreen_Click(object sender, EventArgs e) { - Fullscreen.Value = !Fullscreen.Value; - mMenViewFullscreen.Checked = Fullscreen.Value; + _fullscreen.Value = !_fullscreen.Value; + mMenViewFullscreen.Checked = _fullscreen.Value; } #endregion @@ -834,7 +907,7 @@ namespace mRemoteNG.UI.Forms } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("PopulateQuickConnectProtocolMenu() failed.", ex, MessageClass.ErrorMsg, true); + Runtime.MessageCollector.AddExceptionStackTrace("PopulateQuickConnectProtocolMenu() failed.", ex); } } @@ -859,11 +932,11 @@ namespace mRemoteNG.UI.Forms return; } cmbQuickConnect.Add(connectionInfo); - ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("btnQuickConnect_ButtonClick() failed.", ex, MessageClass.ErrorMsg, true); + Runtime.MessageCollector.AddExceptionStackTrace("btnQuickConnect_ButtonClick() failed.", ex); } } @@ -935,13 +1008,14 @@ namespace mRemoteNG.UI.Forms btnConnections.DropDownItems.AddRange(rootMenuItems); } - private static void ConnectionsMenuItem_MouseUp(object sender, MouseEventArgs e) + private void ConnectionsMenuItem_MouseUp(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; + if (((ToolStripMenuItem) sender).Tag is ContainerInfo) return; var tag = ((ToolStripMenuItem)sender).Tag as ConnectionInfo; if (tag != null) { - ConnectionInitiator.OpenConnection(tag); + _connectionInitiator.OpenConnection(tag); } } #endregion @@ -959,7 +1033,7 @@ namespace mRemoteNG.UI.Forms if (!Settings.Default.MinimizeToTray) return; if (Runtime.NotificationAreaIcon == null) { - Runtime.NotificationAreaIcon = new Tools.Controls.NotificationAreaIcon(); + Runtime.NotificationAreaIcon = new NotificationAreaIcon(); } Hide(); } @@ -1056,7 +1130,7 @@ namespace mRemoteNG.UI.Forms } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("frmMain WndProc failed", ex, MessageClass.ErrorMsg, true); + Runtime.MessageCollector.AddExceptionStackTrace("frmMain WndProc failed", ex); } base.WndProc(ref m); @@ -1068,6 +1142,9 @@ namespace mRemoteNG.UI.Forms if (w?.TabController.SelectedTab == null) return; var tab = w.TabController.SelectedTab; var ifc = (InterfaceControl)tab.Tag; + + if (ifc == null) return; + ifc.Protocol.Focus(); ((ConnectionWindow) ifc.FindForm())?.RefreshInterfaceController(); } @@ -1201,6 +1278,26 @@ namespace mRemoteNG.UI.Forms _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); } + + public void SetDefaultLayout() + { + Default.pnlDock.Visible = false; + + Default.pnlDock.DockLeftPortion = Default.pnlDock.Width * 0.2; + Default.pnlDock.DockRightPortion = Default.pnlDock.Width * 0.2; + Default.pnlDock.DockTopPortion = Default.pnlDock.Height * 0.25; + Default.pnlDock.DockBottomPortion = Default.pnlDock.Height * 0.25; + + Windows.TreePanel.Show(Default.pnlDock, DockState.DockLeft); + Windows.ConfigPanel.Show(Default.pnlDock); + Windows.ConfigPanel.DockTo(Windows.TreePanel.Pane, DockStyle.Bottom, -1); + Windows.ErrorsPanel.Show(Default.pnlDock, DockState.Document); + + Windows.ErrorsForm.Hide(); + Windows.ScreenshotForm.Hide(); + + Default.pnlDock.Visible = true; + } #endregion #region Events diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index a97f17d12..0eb418789 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -5,6 +5,8 @@ using System.IO; using System.Text; using mRemoteNG.App; using mRemoteNG.App.Info; +// ReSharper disable ArrangeRedundantParentheses +// ReSharper disable RedundantCast namespace mRemoteNG.UI.Window { @@ -22,6 +24,7 @@ namespace mRemoteNG.UI.Window internal Label lblEdition; internal Label lblCredits; internal TextBox txtCredits; + private TextBox verText; internal Panel pnlTop; private void InitializeComponent() @@ -38,6 +41,7 @@ namespace mRemoteNG.UI.Window this.lblChangeLog = new System.Windows.Forms.Label(); this.lblLicense = new System.Windows.Forms.Label(); this.lblCopyright = new System.Windows.Forms.Label(); + this.verText = new System.Windows.Forms.TextBox(); this.pnlTop.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pbLogo)).BeginInit(); this.pnlBottom.SuspendLayout(); @@ -86,6 +90,7 @@ namespace mRemoteNG.UI.Window | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlBottom.BackColor = System.Drawing.SystemColors.Control; + this.pnlBottom.Controls.Add(this.verText); this.pnlBottom.Controls.Add(this.lblCredits); this.pnlBottom.Controls.Add(this.txtCredits); this.pnlBottom.Controls.Add(this.txtChangeLog); @@ -206,6 +211,18 @@ namespace mRemoteNG.UI.Window this.lblCopyright.Text = "Copyright"; this.lblCopyright.UseCompatibleTextRendering = true; // + // verText + // + this.verText.BackColor = System.Drawing.SystemColors.Control; + this.verText.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.verText.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.verText.Location = new System.Drawing.Point(69, 51); + this.verText.Name = "verText"; + this.verText.Size = new System.Drawing.Size(147, 20); + this.verText.TabIndex = 12; + this.verText.TabStop = false; + this.verText.Text = "w.x.y.z"; + // // AboutWindow // this.BackColor = System.Drawing.SystemColors.Control; @@ -282,34 +299,37 @@ namespace mRemoteNG.UI.Window #endregion #region Form Stuff - private void About_Load(object sender, EventArgs e) - { - ApplyLanguage(); - ApplyEditions(); - - try - { - lblCopyright.Text = GeneralAppInfo.Copyright; - - lblVersion.Text = @"Version " + GeneralAppInfo.ApplicationVersion; - - if (File.Exists(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) - { - using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) - txtChangeLog.Text = sR.ReadToEnd(); - } - if (File.Exists(GeneralAppInfo.HomePath + "\\CREDITS.TXT")) - { - using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CREDITS.TXT", Encoding.Default, true)) - txtCredits.Text = sR.ReadToEnd(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Loading About failed" + Environment.NewLine + ex.Message, true); - } - } + private void About_Load(object sender, EventArgs e) + { + ApplyLanguage(); + ApplyEditions(); + + try + { + lblCopyright.Text = GeneralAppInfo.Copyright; + + lblVersion.Text = @"Version "; + verText.Text = GeneralAppInfo.ApplicationVersion; + + if (File.Exists(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) + { + using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) + txtChangeLog.Text = sR.ReadToEnd(); + } + + if (File.Exists(GeneralAppInfo.HomePath + "\\CREDITS.TXT")) + { + using (var sR = new StreamReader(GeneralAppInfo.HomePath + "\\CREDITS.TXT", Encoding.Default, true)) + txtCredits.Text = sR.ReadToEnd(); + } + } + 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) diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs index 1713a9584..b842e70c6 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs @@ -64,9 +64,9 @@ 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 = "tant-a01"; + this.ActiveDirectoryTree.Domain = "DOMAIN"; this.ActiveDirectoryTree.Location = new System.Drawing.Point(12, 52); - this.ActiveDirectoryTree.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.ActiveDirectoryTree.Margin = new System.Windows.Forms.Padding(4); this.ActiveDirectoryTree.Name = "ActiveDirectoryTree"; this.ActiveDirectoryTree.SelectedNode = null; this.ActiveDirectoryTree.Size = new System.Drawing.Size(506, 280); diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index f97dc9534..373806c54 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -8,81 +8,96 @@ using mRemoteNG.Container; namespace mRemoteNG.UI.Window { - public partial class ActiveDirectoryImportWindow - { + public partial class ActiveDirectoryImportWindow + { + private string CurrentDomain; + #region Constructors - public ActiveDirectoryImportWindow(DockContent panel) - { - InitializeComponent(); - Runtime.FontOverride(this); - WindowType = WindowType.ActiveDirectoryImport; - DockPnl = panel; - } + + public ActiveDirectoryImportWindow(DockContent panel) + { + InitializeComponent(); + Runtime.FontOverride(this); + WindowType = WindowType.ActiveDirectoryImport; + DockPnl = panel; + CurrentDomain = Environment.UserDomainName; + } + #endregion - + #region Private Methods + #region Event Handlers - private void ADImport_Load(object sender, EventArgs e) - { - ApplyLanguage(); - txtDomain.Text = ActiveDirectoryTree.Domain; - EnableDisableImportButton(); - } + private void ADImport_Load(object sender, EventArgs e) + { + ApplyLanguage(); + txtDomain.Text = CurrentDomain; + ActiveDirectoryTree.Domain = CurrentDomain; + EnableDisableImportButton(); + + // Domain doesn't refresh on load, so it defaults to DOMAIN without this... + ChangeDomain(); + } - private void btnImport_Click(object sender, EventArgs e) - { - var selectedNode = Windows.TreeForm.SelectedNode; - ContainerInfo importDestination; - if (selectedNode != null) - importDestination = selectedNode as ContainerInfo ?? selectedNode.Parent; - else - importDestination = Runtime.ConnectionTreeModel.RootNodes.First(); + private void btnImport_Click(object sender, EventArgs e) + { + var selectedNode = Windows.TreeForm.SelectedNode; + ContainerInfo importDestination; + if (selectedNode != null) + importDestination = selectedNode as ContainerInfo ?? selectedNode.Parent; + else + importDestination = Runtime.ConnectionTreeModel.RootNodes.First(); - Import.ImportFromActiveDirectory(ActiveDirectoryTree.ADPath, importDestination, chkSubOU.Checked); - } + Import.ImportFromActiveDirectory(ActiveDirectoryTree.ADPath, importDestination, chkSubOU.Checked); + } + /* private static void txtDomain_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) { if (e.KeyCode == Keys.Enter) e.IsInputKey = true; } + */ - private void txtDomain_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode != Keys.Enter) return; - ChangeDomain(); - e.SuppressKeyPress = true; - } + private void txtDomain_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode != Keys.Enter) return; + ChangeDomain(); + e.SuppressKeyPress = true; + } - private void btnChangeDomain_Click(object sender, EventArgs e) - { - ChangeDomain(); - } + private void btnChangeDomain_Click(object sender, EventArgs e) + { + ChangeDomain(); + } + + private void ActiveDirectoryTree_ADPathChanged(object sender) + { + EnableDisableImportButton(); + } - private void ActiveDirectoryTree_ADPathChanged(object sender) - { - EnableDisableImportButton(); - } #endregion - - private void ApplyLanguage() - { - btnImport.Text = Language.strButtonImport; - lblDomain.Text = Language.strLabelDomain; - btnChangeDomain.Text = Language.strButtonChange; - } - - private void ChangeDomain() - { - ActiveDirectoryTree.Domain = txtDomain.Text; - ActiveDirectoryTree.Refresh(); - } - - private void EnableDisableImportButton() - { - btnImport.Enabled = !string.IsNullOrEmpty(ActiveDirectoryTree.ADPath); - } + + private void ApplyLanguage() + { + btnImport.Text = Language.strButtonImport; + lblDomain.Text = Language.strLabelDomain; + btnChangeDomain.Text = Language.strButtonChange; + } + + private void ChangeDomain() + { + CurrentDomain = txtDomain.Text; + ActiveDirectoryTree.Domain = CurrentDomain; + ActiveDirectoryTree.Refresh(); + } + + private void EnableDisableImportButton() + { + btnImport.Enabled = !string.IsNullOrEmpty(ActiveDirectoryTree.ADPath); + } + #endregion private void btnClose_Click(object sender, EventArgs e) diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index ff947b279..f529aab83 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -812,6 +812,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); @@ -870,6 +872,10 @@ namespace mRemoteNG.UI.Window strHide.Add("VNCProxyUsername"); strHide.Add("VNCSmartSizeMode"); strHide.Add("VNCViewOnly"); + if (conI.RDPMinutesToIdleTimeout <= 0) + { + strHide.Add("RDPAlertIdleTimeout"); + } if (conI.RDGatewayUsageMethod == ProtocolRDP.RDGatewayUsageMethod.Never) { strHide.Add("RDGatewayDomain"); @@ -910,7 +916,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -953,7 +961,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -995,7 +1005,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1038,7 +1050,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1082,7 +1096,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1126,7 +1142,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1170,7 +1188,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1212,7 +1232,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1250,7 +1272,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1291,7 +1315,9 @@ namespace mRemoteNG.UI.Window strHide.Add("RDGatewayUseConnectionCredentials"); strHide.Add("RDGatewayUsername"); strHide.Add("RDPAuthenticationLevel"); - strHide.Add("LoadBalanceInfo"); + strHide.Add("RDPMinutesToIdleTimeout"); + strHide.Add("RDPAlertIdleTimeout"); + strHide.Add("LoadBalanceInfo"); strHide.Add("RedirectDiskDrives"); strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); @@ -1372,6 +1398,10 @@ namespace mRemoteNG.UI.Window strHide.Add("ICAEncryptionStrength"); if (conI.Inheritance.RDPAuthenticationLevel) strHide.Add("RDPAuthenticationLevel"); + if (conI.Inheritance.RDPMinutesToIdleTimeout) + strHide.Add("RDPMinutesToIdleTimeout"); + if (conI.Inheritance.RDPAlertIdleTimeout) + strHide.Add("RDPAlertIdleTimeout"); if (conI.Inheritance.LoadBalanceInfo) strHide.Add("LoadBalanceInfo"); if (conI.Inheritance.Username) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs index 82865b44a..ed23b42f3 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs @@ -7,7 +7,6 @@ namespace mRemoteNG.UI.Window #region Windows Form Designer generated code internal System.Windows.Forms.TextBox txtSearch; internal System.Windows.Forms.Panel pnlConnections; - internal System.Windows.Forms.ImageList imgListTree; internal System.Windows.Forms.MenuStrip msMain; internal System.Windows.Forms.ToolStripMenuItem mMenView; internal System.Windows.Forms.ToolStripMenuItem mMenViewExpandAllFolders; @@ -17,13 +16,10 @@ namespace mRemoteNG.UI.Window internal System.Windows.Forms.ToolStripMenuItem mMenAddConnection; internal System.Windows.Forms.ToolStripMenuItem mMenAddFolder; public System.Windows.Forms.TreeView tvConnections; - public BrightIdeasSoftware.TreeListView olvConnections; private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.olvConnections = new BrightIdeasSoftware.TreeListView(); - this.olvNameColumn = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); - this.imgListTree = new System.Windows.Forms.ImageList(this.components); + this.olvConnections = new mRemoteNG.UI.Controls.ConnectionTree(); this.pnlConnections = new System.Windows.Forms.Panel(); this.PictureBox1 = new System.Windows.Forms.PictureBox(); this.txtSearch = new System.Windows.Forms.TextBox(); @@ -42,20 +38,16 @@ namespace mRemoteNG.UI.Window // // olvConnections // - this.olvConnections.AllColumns.Add(this.olvNameColumn); this.olvConnections.AllowDrop = true; this.olvConnections.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.olvConnections.BorderStyle = System.Windows.Forms.BorderStyle.None; this.olvConnections.CellEditUseWholeCell = false; - this.olvConnections.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.olvNameColumn}); this.olvConnections.Cursor = System.Windows.Forms.Cursors.Default; 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, 0); this.olvConnections.MultiSelect = false; @@ -64,7 +56,6 @@ namespace mRemoteNG.UI.Window this.olvConnections.SelectedForeColor = System.Drawing.SystemColors.HighlightText; this.olvConnections.ShowGroups = false; this.olvConnections.Size = new System.Drawing.Size(192, 410); - this.olvConnections.SmallImageList = this.imgListTree; this.olvConnections.TabIndex = 20; this.olvConnections.UnfocusedSelectedBackColor = System.Drawing.SystemColors.Highlight; this.olvConnections.UnfocusedSelectedForeColor = System.Drawing.SystemColors.HighlightText; @@ -72,18 +63,6 @@ namespace mRemoteNG.UI.Window this.olvConnections.View = System.Windows.Forms.View.Details; this.olvConnections.VirtualMode = true; // - // olvNameColumn - // - this.olvNameColumn.AspectName = "Name"; - this.olvNameColumn.FillsFreeSpace = true; - this.olvNameColumn.IsButton = true; - // - // imgListTree - // - this.imgListTree.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; - this.imgListTree.ImageSize = new System.Drawing.Size(16, 16); - this.imgListTree.TransparentColor = System.Drawing.Color.Transparent; - // // pnlConnections // this.pnlConnections.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -214,6 +193,6 @@ namespace mRemoteNG.UI.Window #endregion private System.ComponentModel.IContainer components; - private BrightIdeasSoftware.OLVColumn olvNameColumn; + private Controls.ConnectionTree olvConnections; } } diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index c3d8ad3bc..3ce13648c 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -3,17 +3,10 @@ using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Tree; using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.Specialized; using System.ComponentModel; using System.Drawing; -using System.Linq; using System.Windows.Forms; -using BrightIdeasSoftware; -using mRemoteNG.Config.Putty; -using mRemoteNG.Tools; -using mRemoteNG.Tree.Root; using mRemoteNG.UI.Controls; using WeifenLuo.WinFormsUI.Docking; @@ -22,22 +15,16 @@ namespace mRemoteNG.UI.Window { public partial class ConnectionTreeWindow { - private ConnectionTreeModel _connectionTreeModel; - private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); - private NodeSearcher _nodeSearcher; - private readonly ConnectionContextMenu _contextMenu = new ConnectionContextMenu(); - private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; + private readonly ConnectionContextMenu _contextMenu; + private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); - public ConnectionInfo SelectedNode => (ConnectionInfo) olvConnections.SelectedObject; - public ConnectionTreeModel ConnectionTreeModel + public ConnectionInfo SelectedNode => olvConnections.SelectedNode; + + public ConnectionTree ConnectionTree { - get { return _connectionTreeModel; } - set - { - _connectionTreeModel = value; - PopulateTreeView(); - } + get { return olvConnections; } + set { olvConnections = value; } } public ConnectionTreeWindow(DockContent panel) @@ -45,235 +32,12 @@ namespace mRemoteNG.UI.Window WindowType = WindowType.Tree; DockPnl = panel; InitializeComponent(); - - FillImageList(); - LinkModelToView(); - SetupDropSink(); - SetEventHandlers(); - } - - private void FillImageList() - { - try - { - imgListTree.Images.Add(Resources.Root); - imgListTree.Images.SetKeyName(0, "Root"); - imgListTree.Images.Add(Resources.Folder); - imgListTree.Images.SetKeyName(1, "Folder"); - imgListTree.Images.Add(Resources.Play); - imgListTree.Images.SetKeyName(2, "Play"); - imgListTree.Images.Add(Resources.Pause); - imgListTree.Images.SetKeyName(3, "Pause"); - imgListTree.Images.Add(Resources.PuttySessions); - imgListTree.Images.SetKeyName(4, "PuttySessions"); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("FillImageList (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void LinkModelToView() - { - olvNameColumn.AspectGetter = item => ((ConnectionInfo)item).Name; - olvNameColumn.ImageGetter = ConnectionImageGetter; - olvConnections.CanExpandGetter = item => - { - var itemAsContainer = item as ContainerInfo; - return itemAsContainer?.Children.Count > 0; - }; - olvConnections.ChildrenGetter = item => ((ContainerInfo)item).Children; + _contextMenu = new ConnectionContextMenu(olvConnections); olvConnections.ContextMenuStrip = _contextMenu; - } - - private void SetupDropSink() - { - var dropSink = (SimpleDropSink)olvConnections.DropSink; - dropSink.CanDropBetween = true; - } - - private static object ConnectionImageGetter(object rowObject) - { - if (rowObject is RootPuttySessionsNodeInfo) return "PuttySessions"; - if (rowObject is RootNodeInfo) return "Root"; - if (rowObject is ContainerInfo) return "Folder"; - var connection = rowObject as ConnectionInfo; - if (connection == null) return ""; - return connection.OpenConnections.Count > 0 ? "Play" : "Pause"; - } - - private void SetEventHandlers() - { - SetTreeEventHandlers(); - SetContextMenuEventHandlers(); SetMenuEventHandlers(); - } - - private void SetTreeEventHandlers() - { - olvConnections.Collapsed += (sender, args) => - { - var container = args.Model as ContainerInfo; - if (container != null) - container.IsExpanded = false; - }; - olvConnections.Expanded += (sender, args) => - { - var container = args.Model as ContainerInfo; - if (container != null) - container.IsExpanded = true; - }; - olvConnections.BeforeLabelEdit += tvConnections_BeforeLabelEdit; - olvConnections.AfterLabelEdit += tvConnections_AfterLabelEdit; - olvConnections.SelectionChanged += tvConnections_AfterSelect; - olvConnections.CellClick += tvConnections_NodeMouseSingleClick; - olvConnections.CellClick += tvConnections_NodeMouseDoubleClick; - olvConnections.CellToolTipShowing += tvConnections_CellToolTipShowing; - olvConnections.ModelCanDrop += _dragAndDropHandler.HandleEvent_ModelCanDrop; - olvConnections.ModelDropped += _dragAndDropHandler.HandleEvent_ModelDropped; - olvConnections.KeyDown += tvConnections_KeyDown; - olvConnections.KeyPress += tvConnections_KeyPress; - } - - private void SetContextMenuEventHandlers() - { - _contextMenu.Opening += (sender, args) => _contextMenu.ShowHideTreeContextMenuItems(SelectedNode); - _contextMenu.ConnectClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DoNotJump); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.DoNotJump); - }; - _contextMenu.ConnectToConsoleSessionClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump); - }; - _contextMenu.DontConnectToConsoleSessionClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump); - }; - _contextMenu.ConnectInFullscreenClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump); - }; - _contextMenu.ConnectWithNoCredentialsClick += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.NoCredentials); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.NoCredentials); - }; - _contextMenu.ChoosePanelBeforeConnectingClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - ConnectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); - else - ConnectionInitiator.OpenConnection(SelectedNode, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump); - }; - _contextMenu.DisconnectClicked += (sender, args) => DisconnectConnection(SelectedNode); - _contextMenu.TransferFileClicked += (sender, args) => SshTransferFile(); - _contextMenu.DuplicateClicked += (sender, args) => DuplicateSelectedNode(); - _contextMenu.RenameClicked += (sender, args) => RenameSelectedNode(); - _contextMenu.DeleteClicked += (sender, args) => DeleteSelectedNode(); - _contextMenu.ImportFileClicked += (sender, args) => - { - var selectedNodeAsContainer = SelectedNode as ContainerInfo ?? SelectedNode.Parent; - Import.ImportFromFile(selectedNodeAsContainer); - }; - _contextMenu.ImportActiveDirectoryClicked += (sender, args) => Windows.Show(WindowType.ActiveDirectoryImport); - _contextMenu.ImportPortScanClicked += (sender, args) => Windows.Show(WindowType.PortScan); - _contextMenu.ExportFileClicked += (sender, args) => Export.ExportToFile(SelectedNode, Runtime.ConnectionTreeModel); - _contextMenu.AddConnectionClicked += cMenTreeAddConnection_Click; - _contextMenu.AddFolderClicked += cMenTreeAddFolder_Click; - _contextMenu.SortAscendingClicked += (sender, args) => SortNodesRecursive(SelectedNode, ListSortDirection.Ascending); - _contextMenu.SortDescendingClicked += (sender, args) => SortNodesRecursive(SelectedNode, ListSortDirection.Descending); - _contextMenu.MoveUpClicked += cMenTreeMoveUp_Click; - _contextMenu.MoveDownClicked += cMenTreeMoveDown_Click; - _contextMenu.ExternalToolClicked += (sender, args) => StartExternalApp((ExternalTool)((ToolStripMenuItem)sender).Tag); - } - - private void SetMenuEventHandlers() - { - mMenViewExpandAllFolders.Click += (sender, args) => olvConnections.ExpandAll(); - mMenViewCollapseAllFolders.Click += (sender, args) => - { - olvConnections.CollapseAll(); - olvConnections.Expand(GetRootConnectionNode()); - }; - mMenSortAscending.Click += (sender, args) => SortNodesRecursive(GetRootConnectionNode(), ListSortDirection.Ascending); - } - - private void PopulateTreeView() - { - UnregisterModelUpdateHandlers(); - olvConnections.SetObjects(ConnectionTreeModel.RootNodes); - RegisterModelUpdateHandlers(); - _nodeSearcher = new NodeSearcher(ConnectionTreeModel); - ExpandPreviouslyOpenedFolders(); - ExpandRootConnectionNode(); - OpenConnectionsFromLastSession(); - } - - private void RegisterModelUpdateHandlers() - { - _puttySessionsManager.PuttySessionsCollectionChanged += OnPuttySessionsCollectionChanged; - ConnectionTreeModel.CollectionChanged += HandleCollectionChanged; - ConnectionTreeModel.PropertyChanged += HandleCollectionPropertyChanged; - } - - private void UnregisterModelUpdateHandlers() - { - _puttySessionsManager.PuttySessionsCollectionChanged -= OnPuttySessionsCollectionChanged; - ConnectionTreeModel.CollectionChanged -= HandleCollectionChanged; - ConnectionTreeModel.PropertyChanged -= HandleCollectionPropertyChanged; - } - - private void OnPuttySessionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) - { - RefreshTreeObjects(GetRootPuttyNodes().ToList()); - } - - private void HandleCollectionPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) - { - //TODO for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication - var property = propertyChangedEventArgs.PropertyName; - if (property != "Name" && property != "OpenConnections") return; - var senderAsConnectionInfo = sender as ConnectionInfo; - if (senderAsConnectionInfo != null) - RefreshTreeObject(senderAsConnectionInfo); - } - - private void ExpandRootConnectionNode() - { - var rootConnectionNode = GetRootConnectionNode(); - olvConnections.InvokeExpand(rootConnectionNode); - } - - private RootNodeInfo GetRootConnectionNode() - { - return (RootNodeInfo)olvConnections.Roots.Cast().First(item => item is RootNodeInfo); - } - - private IEnumerable GetRootPuttyNodes() - { - return olvConnections.Objects.OfType(); - } + SetConnectionTreeEventHandlers(); + Settings.Default.PropertyChanged += (sender, args) => SetConnectionTreeEventHandlers(); + } #region Form Stuff private void Tree_Load(object sender, EventArgs e) @@ -316,226 +80,88 @@ namespace mRemoteNG.UI.Window } #endregion - private void ExpandPreviouslyOpenedFolders() - { - var containerList = ConnectionTreeModel.GetRecursiveChildList(GetRootConnectionNode()).OfType(); - var previouslyExpandedNodes = containerList.Where(container => container.IsExpanded); - olvConnections.ExpandedObjects = previouslyExpandedNodes; - olvConnections.InvokeRebuildAll(true); - } - - private void OpenConnectionsFromLastSession() - { - if (!Settings.Default.OpenConsFromLastSession || Settings.Default.NoReconnect) return; - var connectionInfoList = GetRootConnectionNode().GetRecursiveChildList().Where(node => !(node is ContainerInfo)); - var previouslyOpenedConnections = connectionInfoList.Where(item => item.PleaseConnect); - foreach (var connectionInfo in previouslyOpenedConnections) - { - ConnectionInitiator.OpenConnection(connectionInfo); - } - } - - public void EnsureRootNodeVisible() + #region ConnectionTree + private void SetConnectionTreeEventHandlers() { - olvConnections.EnsureModelVisible(GetRootConnectionNode()); + olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(olvConnections, MessageBox.Show); + olvConnections.BeforeLabelEdit += tvConnections_BeforeLabelEdit; + olvConnections.AfterLabelEdit += tvConnections_AfterLabelEdit; + olvConnections.KeyDown += tvConnections_KeyDown; + olvConnections.KeyPress += tvConnections_KeyPress; + SetTreePostSetupActions(); + SetConnectionTreeDoubleClickHandlers(); + SetConnectionTreeSingleClickHandlers(); } - public void DuplicateSelectedNode() - { - var newNode = SelectedNode.Clone(); - newNode.Parent.SetChildBelow(newNode, SelectedNode); - Runtime.SaveConnectionsAsync(); - } - - public void RenameSelectedNode() - { - olvConnections.SelectedItem.BeginEdit(); - Runtime.SaveConnectionsAsync(); - } - - public void DeleteSelectedNode() - { - if (SelectedNode is RootNodeInfo || SelectedNode is PuttySessionInfo) return; - if (!UserConfirmsDeletion()) return; - ConnectionTreeModel.DeleteNode(SelectedNode); - Runtime.SaveConnectionsAsync(); - } - - private bool UserConfirmsDeletion() + private void SetTreePostSetupActions() { - var selectedNodeAsContainer = SelectedNode as ContainerInfo; - if (selectedNodeAsContainer != null) - return selectedNodeAsContainer.HasChildren() - ? UserConfirmsNonEmptyFolderDeletion() - : UserConfirmsEmptyFolderDeletion(); - return UserConfirmsConnectionDeletion(); - } - - private bool UserConfirmsEmptyFolderDeletion() - { - var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolder, SelectedNode.Name); - return PromptUser(messagePrompt); - } - - private bool UserConfirmsNonEmptyFolderDeletion() - { - var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolderNotEmpty, SelectedNode.Name); - return PromptUser(messagePrompt); - } - - private bool UserConfirmsConnectionDeletion() - { - var messagePrompt = string.Format(Language.strConfirmDeleteNodeConnection, SelectedNode.Name); - return PromptUser(messagePrompt); - } - - private static bool PromptUser(string promptMessage) - { - var msgBoxResponse = MessageBox.Show(promptMessage, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question); - return (msgBoxResponse == DialogResult.Yes); - } - - #region Private Methods - private void tvConnections_BeforeLabelEdit(object sender, LabelEditEventArgs e) - { - _contextMenu.DisableShortcutKeys(); - } - - private void tvConnections_AfterLabelEdit(object sender, LabelEditEventArgs e) - { - try - { - _contextMenu.EnableShortcutKeys(); - ConnectionTreeModel.RenameNode(SelectedNode, e.Label); - Windows.ConfigForm.SelectedTreeNode = SelectedNode; - Runtime.SaveConnectionsAsync(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterLabelEdit (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void tvConnections_AfterSelect(object sender, EventArgs e) - { - try - { - Windows.ConfigForm.SelectedTreeNode = SelectedNode; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterSelect (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void tvConnections_NodeMouseSingleClick(object sender, CellClickEventArgs e) - { - try - { - if (e.ClickCount > 1) return; - var clickedNode = e.Model as ConnectionInfo; - - if (clickedNode == null) return; - if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return; - if (Settings.Default.SingleClickOnConnectionOpensIt) - ConnectionInitiator.OpenConnection(SelectedNode); - - if (Settings.Default.SingleClickSwitchesToOpenConnection) - ConnectionInitiator.SwitchToOpenConnection(SelectedNode); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_NodeMouseClick (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void tvConnections_NodeMouseDoubleClick(object sender, CellClickEventArgs e) - { - if (e.ClickCount < 2) return; - var clickedNodeAsContainer = e.Model as ContainerInfo; - if (clickedNodeAsContainer != null) - { - olvConnections.ToggleExpansion(clickedNodeAsContainer); - } - - var clickedNode = e.Model as ConnectionInfo; - if (clickedNode?.GetTreeNodeType() == TreeNodeType.Connection | - clickedNode?.GetTreeNodeType() == TreeNodeType.PuttySession) - { - ConnectionInitiator.OpenConnection(SelectedNode); - } - } - - private void tvConnections_CellToolTipShowing(object sender, ToolTipShowingEventArgs e) - { - try - { - var nodeProducingTooltip = (ConnectionInfo) e.Model; - e.Text = nodeProducingTooltip.Description; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_MouseMove (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) - { - var senderAsContainerInfo = sender as ContainerInfo; - // ReSharper disable once SwitchStatementMissingSomeCases - switch (args?.Action) + var actions = new List { - case NotifyCollectionChangedAction.Add: - var childList = senderAsContainerInfo?.Children; - ConnectionInfo otherChild = null; - if (childList?.Count > 1) - otherChild = childList.First(child => !args.NewItems.Contains(child)); - RefreshTreeObject(otherChild ?? senderAsContainerInfo); - break; - case NotifyCollectionChangedAction.Remove: - RefreshTreeObjects(args.OldItems); - break; - case NotifyCollectionChangedAction.Move: - RefreshTreeObjects(args.OldItems); - break; - case NotifyCollectionChangedAction.Reset: - RefreshTreeObject(senderAsContainerInfo); - break; - case NotifyCollectionChangedAction.Replace: - break; - case null: - break; - } + new PreviouslyOpenedFolderExpander(), + new RootNodeExpander() + }; + + if (Settings.Default.OpenConsFromLastSession && !Settings.Default.NoReconnect) + actions.Add(new PreviousSessionOpener(_connectionInitiator)); + + olvConnections.PostSetupActions = actions; } - private void RefreshTreeObject(ConnectionInfo modelObject) + private void SetConnectionTreeDoubleClickHandlers() { - olvConnections.RefreshObject(modelObject); + var doubleClickHandler = new TreeNodeCompositeClickHandler + { + ClickHandlers = new ITreeNodeClickHandler[] + { + new ExpandNodeClickHandler(olvConnections), + new OpenConnectionClickHandler(_connectionInitiator) + } + }; + olvConnections.DoubleClickHandler = doubleClickHandler; } - private void RefreshTreeObjects(IList modelObjects) - { - olvConnections.RefreshObjects(modelObjects); - } + 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; + } + #endregion + + #region Top Menu + private void SetMenuEventHandlers() + { + mMenViewExpandAllFolders.Click += (sender, args) => olvConnections.ExpandAll(); + mMenViewCollapseAllFolders.Click += (sender, args) => + { + olvConnections.CollapseAll(); + olvConnections.Expand(olvConnections.GetRootConnectionNode()); + }; + mMenSortAscending.Click += (sender, args) => SortNodesRecursive(olvConnections.GetRootConnectionNode(), ListSortDirection.Ascending); + } #endregion #region Tree Context Menu private void cMenTreeAddConnection_Click(object sender, EventArgs e) { - AddConnection(); + olvConnections.AddConnection(); Runtime.SaveConnectionsAsync(); } private void cMenTreeAddFolder_Click(object sender, EventArgs e) { - AddFolder(); + olvConnections.AddFolder(); Runtime.SaveConnectionsAsync(); } private void SortNodesRecursive(ConnectionInfo sortTarget, ListSortDirection sortDirection) { if (sortTarget == null) - sortTarget = GetRootConnectionNode(); + sortTarget = olvConnections.GetRootConnectionNode(); var sortTargetAsContainer = sortTarget as ContainerInfo; if (sortTargetAsContainer != null) @@ -546,115 +172,25 @@ namespace mRemoteNG.UI.Window Runtime.SaveConnectionsAsync(); } - private void cMenTreeMoveUp_Click(object sender, EventArgs e) - { - SelectedNode.Parent.PromoteChild(SelectedNode); - Runtime.SaveConnectionsAsync(); - } - - private void cMenTreeMoveDown_Click(object sender, EventArgs e) - { - SelectedNode.Parent.DemoteChild(SelectedNode); - Runtime.SaveConnectionsAsync(); - } - #endregion - - #region Context Menu Actions - public void AddConnection() - { - try - { - AddNode(new ConnectionInfo()); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("UI.Window.Tree.AddConnection() failed.", ex); - } - } - - public void AddFolder() - { - try - { - AddNode(new ContainerInfo()); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.strErrorAddFolderFailed, ex); - } - } - - private void AddNode(ConnectionInfo newNode) - { - if (SelectedNode == null) return; - DefaultConnectionInfo.Instance.SaveTo(newNode); - DefaultConnectionInheritance.Instance.SaveTo(newNode.Inheritance); - var selectedContainer = SelectedNode as ContainerInfo; - var parent = selectedContainer ?? SelectedNode?.Parent; - newNode.SetParent(parent); - olvConnections.Expand(parent); - olvConnections.SelectObject(newNode); - olvConnections.EnsureModelVisible(newNode); + private void tvConnections_BeforeLabelEdit(object sender, LabelEditEventArgs e) + { + _contextMenu.DisableShortcutKeys(); } - private void DisconnectConnection(ConnectionInfo connectionInfo) - { - try - { - if (connectionInfo == null) return; - var nodeAsContainer = connectionInfo as ContainerInfo; - if (nodeAsContainer != null) - { - foreach (var child in nodeAsContainer.Children) - { - for (var i = 0; i <= child.OpenConnections.Count - 1; i++) - { - child.OpenConnections[i].Disconnect(); - } - } - } - else - { - for (var i = 0; i <= connectionInfo.OpenConnections.Count - 1; i++) - { - connectionInfo.OpenConnections[i].Disconnect(); - } - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("DisconnectConnection (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void SshTransferFile() - { - try - { - Windows.Show(WindowType.SSHTransfer); - Windows.SshtransferForm.Hostname = SelectedNode.Hostname; - Windows.SshtransferForm.Username = SelectedNode.Username; - Windows.SshtransferForm.Password = SelectedNode.Password; - Windows.SshtransferForm.Port = Convert.ToString(SelectedNode.Port); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("SSHTransferFile (UI.Window.ConnectionTreeWindow) failed", ex); - } - } - - private void StartExternalApp(ExternalTool externalTool) - { - try - { - if (SelectedNode.GetTreeNodeType() == TreeNodeType.Connection | SelectedNode.GetTreeNodeType() == TreeNodeType.PuttySession) - externalTool.Start(SelectedNode); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("cMenTreeToolsExternalAppsEntry_Click failed (UI.Window.ConnectionTreeWindow)", ex); - } - } + private void tvConnections_AfterLabelEdit(object sender, LabelEditEventArgs e) + { + try + { + _contextMenu.EnableShortcutKeys(); + ConnectionTree.ConnectionTreeModel.RenameNode(SelectedNode, e.Label); + Windows.ConfigForm.SelectedTreeNode = SelectedNode; + Runtime.SaveConnectionsAsync(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterLabelEdit (UI.Window.ConnectionTreeWindow) failed", ex); + } + } #endregion #region Search @@ -683,13 +219,13 @@ namespace mRemoteNG.UI.Window } else if (e.KeyCode == Keys.Up) { - var match = _nodeSearcher.PreviousMatch(); + var match = olvConnections.NodeSearcher.PreviousMatch(); JumpToNode(match); e.Handled = true; } else if (e.KeyCode == Keys.Down) { - var match = _nodeSearcher.NextMatch(); + var match = olvConnections.NodeSearcher.NextMatch(); JumpToNode(match); e.Handled = true; } @@ -707,8 +243,8 @@ namespace mRemoteNG.UI.Window private void txtSearch_TextChanged(object sender, EventArgs e) { if (txtSearch.Text == "") return; - _nodeSearcher?.SearchByName(txtSearch.Text); - JumpToNode(_nodeSearcher?.CurrentMatch); + olvConnections.NodeSearcher?.SearchByName(txtSearch.Text); + JumpToNode(olvConnections.NodeSearcher?.CurrentMatch); } private void JumpToNode(ConnectionInfo connectionInfo) @@ -755,7 +291,7 @@ namespace mRemoteNG.UI.Window if (e.KeyCode == Keys.Enter) { e.Handled = true; - ConnectionInitiator.OpenConnection(SelectedNode); + _connectionInitiator.OpenConnection(SelectedNode); } else if (e.Control && e.KeyCode == Keys.F) { diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.resx b/mRemoteV1/UI/Window/ConnectionTreeWindow.resx index dfeabba7a..584bd6853 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.resx +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - 119, 19 diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index 4c8c12b3d..c4e04f289 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -15,7 +15,6 @@ using mRemoteNG.UI.Forms; using mRemoteNG.UI.TaskDialog; using mRemoteNG.App.Info; using mRemoteNG.Container; -using mRemoteNG.Messages; using mRemoteNG.Tools; using mRemoteNG.UI.Forms.Input; using Message = System.Windows.Forms.Message; @@ -28,7 +27,8 @@ namespace mRemoteNG.UI.Window public partial class ConnectionWindow : BaseWindow { public TabControl TabController; - + private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); + #region Public Methods public ConnectionWindow(DockContent panel, string formText = "") @@ -144,7 +144,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "AddConnectionTab (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("AddConnectionTab (UI.Window.ConnectionWindow) failed", ex); } return null; @@ -223,8 +223,8 @@ 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))) + (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All & TabController.TabPages.Count > 0 || + Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple & TabController.TabPages.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) @@ -249,7 +249,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "UI.Window.Connection.Connection_FormClosing() failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.Connection_FormClosing() failed", ex); } } @@ -308,7 +308,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "UI.Window.Connection.CloseConnectionTab() failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.CloseConnectionTab() failed", ex); } UpdateSelectedConnection(); @@ -334,9 +334,9 @@ namespace mRemoteNG.UI.Window var modelAsContainer = model as ContainerInfo; var modelAsConnection = model as ConnectionInfo; if (modelAsContainer != null) - ConnectionInitiator.OpenConnection(modelAsContainer); + _connectionInitiator.OpenConnection(modelAsContainer); else if (modelAsConnection != null) - ConnectionInitiator.OpenConnection(modelAsConnection); + _connectionInitiator.OpenConnection(modelAsConnection); } } @@ -413,7 +413,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ShowHideMenuButtons (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("ShowHideMenuButtons (UI.Window.ConnectionWindow) failed", ex); } } #endregion @@ -440,7 +440,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ToggleSmartSize (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("ToggleSmartSize (UI.Window.ConnectionWindow) failed", ex); } } @@ -458,7 +458,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "TransferFile (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("TransferFile (UI.Window.ConnectionWindow) failed", ex); } } @@ -479,7 +479,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "SSHTransferFile (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("SSHTransferFile (UI.Window.ConnectionWindow) failed", ex); } } @@ -493,7 +493,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "VNCTransferFile (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("VNCTransferFile (UI.Window.ConnectionWindow) failed", ex); } } @@ -509,7 +509,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ToggleViewOnly (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("ToggleViewOnly (UI.Window.ConnectionWindow) failed", ex); } } @@ -523,7 +523,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "StartChat (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("StartChat (UI.Window.ConnectionWindow) failed", ex); } } @@ -537,7 +537,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "RefreshScreen (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("RefreshScreen (UI.Window.ConnectionWindow) failed", ex); } } @@ -551,7 +551,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "SendSpecialKeys (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("SendSpecialKeys (UI.Window.ConnectionWindow) failed", ex); } } @@ -565,7 +565,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ToggleFullscreen (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("ToggleFullscreen (UI.Window.ConnectionWindow) failed", ex); } } @@ -579,7 +579,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("ShowPuttySettingsDialog (UI.Window.ConnectionWindow) failed", ex); } } @@ -627,7 +627,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("cmenTabExternalAppsEntry_Click failed (UI.Window.ConnectionWindow)", ex); } } @@ -640,7 +640,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "CloseTabMenu (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); } } @@ -650,12 +650,12 @@ namespace mRemoteNG.UI.Window { var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; if (interfaceControl == null) return; - ConnectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); _ignoreChangeSelectedTabClick = false; } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "DuplicateTab (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("DuplicateTab (UI.Window.ConnectionWindow) failed", ex); } } @@ -666,11 +666,11 @@ namespace mRemoteNG.UI.Window var interfaceControl = TabController.SelectedTab?.Tag as InterfaceControl; if (interfaceControl == null) return; interfaceControl.Protocol.Close(); - ConnectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); + _connectionInitiator.OpenConnection(interfaceControl.Info, ConnectionInfo.Force.DoNotJump); } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Reconnect (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("Reconnect (UI.Window.ConnectionWindow) failed", ex); } } @@ -678,13 +678,13 @@ namespace mRemoteNG.UI.Window { try { - var newTitle = ""; + var newTitle = TabController.SelectedTab.Title; if (input.InputBox(Language.strNewTitle, Language.strNewTitle + ":", ref newTitle) == DialogResult.OK && !string.IsNullOrEmpty(newTitle)) TabController.SelectedTab.Title = newTitle.Replace("&", "&&"); } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "RenameTab (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("RenameTab (UI.Window.ConnectionWindow) failed", ex); } } @@ -724,7 +724,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Couldn\'t close tab" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("Couldn't close tab", ex); } } else @@ -740,7 +740,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Couldn\'t close tab" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("Couldn't close tab", ex); } if (TabController.TabPages.Count == 0) @@ -784,7 +784,7 @@ namespace mRemoteNG.UI.Window 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); + _doubleClickRectangle = new Rectangle(MousePosition.X - SystemInformation.DoubleClickSize.Width / 2, MousePosition.Y - SystemInformation.DoubleClickSize.Height / 2, SystemInformation.DoubleClickSize.Width, SystemInformation.DoubleClickSize.Height); FocusInterfaceController(); } else @@ -805,7 +805,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "TabController_MouseUp (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("TabController_MouseUp (UI.Window.ConnectionWindow) failed", ex); } } @@ -818,7 +818,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "FocusIC (UI.Window.ConnectionWindow) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("FocusIC (UI.Window.ConnectionWindow) failed", ex); } } @@ -832,7 +832,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "RefreshIC (UI.Window.Connection) failed" + Environment.NewLine + ex.Message, true); + Runtime.MessageCollector.AddExceptionMessage("RefreshIC (UI.Window.Connection) failed", ex); } } #endregion @@ -862,7 +862,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(message: "UI.Window.Connection.WndProc() failed.", ex: ex, logOnly: true); + Runtime.MessageCollector.AddExceptionMessage("UI.Window.Connection.WndProc() failed.", ex); } base.WndProc(ref m); diff --git a/mRemoteV1/UI/Window/PortScanWindow.cs b/mRemoteV1/UI/Window/PortScanWindow.cs index 073bebb5c..10ea61c4d 100644 --- a/mRemoteV1/UI/Window/PortScanWindow.cs +++ b/mRemoteV1/UI/Window/PortScanWindow.cs @@ -211,7 +211,7 @@ namespace mRemoteNG.UI.Window if (InvokeRequired) { Invoke(new PortScannerHostScannedDelegate(PortScanner_HostScanned), new object[] {host, scannedCount, totalCount}); - return ; + return; } Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Host scanned " + host.HostIp, true); @@ -233,7 +233,7 @@ namespace mRemoteNG.UI.Window if (InvokeRequired) { Invoke(new PortScannerScanComplete(PortScanner_ScanComplete), new object[] {hosts}); - return ; + return; } Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPortScanComplete); diff --git a/mRemoteV1/UI/Window/UpdateWindow.cs b/mRemoteV1/UI/Window/UpdateWindow.cs index 55489483b..31027bc18 100644 --- a/mRemoteV1/UI/Window/UpdateWindow.cs +++ b/mRemoteV1/UI/Window/UpdateWindow.cs @@ -6,6 +6,7 @@ using System.Net; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.App.Update; +using mRemoteNG.Messages; using WeifenLuo.WinFormsUI.Docking; #if !PORTABLE @@ -163,17 +164,13 @@ namespace mRemoteNG.UI.Window { lblStatus.Text = Language.strNoUpdateAvailable; lblStatus.ForeColor = Color.ForestGreen; - - if (_appUpdate.CurrentUpdateInfo != null) - { - var updateInfo = _appUpdate.CurrentUpdateInfo; - if (updateInfo.IsValid && updateInfo.Version != null) - { - lblLatestVersion.Text = updateInfo.Version.ToString(); - lblLatestVersionLabel.Visible = true; - lblLatestVersion.Visible = true; - } - } + + 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) @@ -181,7 +178,7 @@ namespace mRemoteNG.UI.Window lblStatus.Text = Language.strUpdateCheckFailedLabel; lblStatus.ForeColor = Color.OrangeRed; - Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateCheckCompleteFailed, ex); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strUpdateCheckCompleteFailed, ex); } } @@ -207,7 +204,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateGetChangeLogFailed, ex); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strUpdateGetChangeLogFailed, ex); } } @@ -230,7 +227,7 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateDownloadFailed, ex); + Runtime.MessageCollector.AddExceptionStackTrace(Language.strUpdateDownloadFailed, ex); } } #endregion @@ -267,8 +264,9 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateDownloadCompleteFailed, ex); - } + Runtime.MessageCollector.AddExceptionStackTrace(Language.strUpdateDownloadCompleteFailed, ex); + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, ex.Message); + } } #endregion } diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index 9f5783443..41ac45650 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -415,6 +415,18 @@ False + + 0 + + + False + + + False + + + False + 5500 @@ -544,6 +556,9 @@ False + + release + @@ -601,6 +616,18 @@ False + + 0 + + + False + + + False + + + False + @@ -608,9 +635,6 @@ de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW - - release - https://mremoteng.org/ diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 65fb2a1b5..fb3569c37 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -187,6 +187,7 @@ + @@ -209,17 +210,34 @@ + + + + + + - + + + + + + Component + + Component + + + ConnectionTree.cs + Component @@ -227,12 +245,18 @@ FilteredPropertyGrid.cs + UserControl + + + Component + Component + Component @@ -389,8 +413,6 @@ UserControl - - @@ -763,6 +785,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/mRemoteV1/mRemoteV1.csproj.DotSettings b/mRemoteV1/mRemoteV1.csproj.DotSettings new file mode 100644 index 000000000..07f70d627 --- /dev/null +++ b/mRemoteV1/mRemoteV1.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file