mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Merge pull request #352 from mRemoteNG/299_better_testing_of_connection_tree
Refactor connection tree to be more testable
This commit is contained in:
@@ -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<IConnectionTree>();
|
||||
_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<ArgumentNullException>(() => new ExpandNodeClickHandler(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IConnectionInitiator>();
|
||||
_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<ArgumentNullException>(() => new OpenConnectionClickHandler(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ThrowWhenExecuteGivenNullArg()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IConnectionInitiator>();
|
||||
_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<ArgumentNullException>(() => new SwitchToConnectionClickHandler(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ThrowWhenExecuteGivenNullArg()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<ITreeNodeClickHandler>();
|
||||
var handler2 = Substitute.For<ITreeNodeClickHandler>();
|
||||
_clickHandler.ClickHandlers = new[] {handler1, handler2};
|
||||
_clickHandler.Execute(_connectionInfo);
|
||||
handler1.Received().Execute(_connectionInfo);
|
||||
handler2.Received().Execute(_connectionInfo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ThrowWhenExecuteGivenNullArg()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
51
mRemoteNGTests/Tree/ConnectionTreeTests.cs
Normal file
51
mRemoteNGTests/Tree/ConnectionTreeTests.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
mRemoteNGTests/Tree/PreviousSessionOpenerTests.cs
Normal file
50
mRemoteNGTests/Tree/PreviousSessionOpenerTests.cs
Normal file
@@ -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<IConnectionInitiator>();
|
||||
_previousSessionOpener = new PreviousSessionOpener(_connectionInitiator);
|
||||
_connectionTree = Substitute.For<IConnectionTree>();
|
||||
_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<ArgumentNullException>(() => 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
mRemoteNGTests/Tree/PreviouslyOpenedFolderExpanderTests.cs
Normal file
49
mRemoteNGTests/Tree/PreviouslyOpenedFolderExpanderTests.cs
Normal file
@@ -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<IConnectionTree>();
|
||||
}
|
||||
|
||||
[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<ContainerInfo>().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IConnectionTree>();
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
mRemoteNGTests/UI/Window/ConnectionTreeWindowTests.cs
Normal file
32
mRemoteNGTests/UI/Window/ConnectionTreeWindowTests.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,9 @@
|
||||
</When>
|
||||
<Otherwise>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
@@ -128,6 +130,7 @@
|
||||
<Compile Include="Security\KeyDerivation\Pkcs5S2KeyGeneratorTests.cs" />
|
||||
<Compile Include="Security\SecureStringExtensionsTests.cs" />
|
||||
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\ConnectionTreeDragAndDropHandlerTests.cs" />
|
||||
<Compile Include="Tree\ConnectionTreeModelTests.cs" />
|
||||
<Compile Include="Connection\ConnectionInfoInheritanceTests.cs" />
|
||||
@@ -147,8 +150,15 @@
|
||||
<Compile Include="Security\CryptographyProviderFactoryTests.cs" />
|
||||
<Compile Include="Security\EncryptedSecureStringTests.cs" />
|
||||
<Compile Include="Security\LegacyRijndaelCryptographyProviderTests.cs" />
|
||||
<Compile Include="Tree\ConnectionTreeTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\ExpandNodeClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\NodeSearcherTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\OpenConnectionClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\PreviouslyOpenedFolderExpanderTests.cs" />
|
||||
<Compile Include="Tree\PreviousSessionOpenerTests.cs" />
|
||||
<Compile Include="Tree\RootNodeInfoTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
|
||||
<Compile Include="UI\Controls\TestForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -158,6 +168,7 @@
|
||||
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
|
||||
<Compile Include="UI\Forms\PasswordFormTests.cs" />
|
||||
<Compile Include="UI\WindowListTests.cs" />
|
||||
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
2
mRemoteNGTests/mRemoteNGTests.csproj.DotSettings
Normal file
2
mRemoteNGTests/mRemoteNGTests.csproj.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tree_005Cclickhandlers/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
@@ -593,7 +593,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()
|
||||
|
||||
@@ -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.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenConnection(connectionInfo, force, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
|
||||
private void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -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;
|
||||
@@ -214,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
|
||||
@@ -288,5 +288,6 @@ namespace mRemoteNG.Connection
|
||||
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionEventConnectionFailed, ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
15
mRemoteV1/Connection/IConnectionInitiator.cs
Normal file
15
mRemoteV1/Connection/IConnectionInitiator.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
@@ -80,7 +81,7 @@ namespace mRemoteNG.Tools
|
||||
try
|
||||
{
|
||||
var newConnectionInfo = BuildConnectionInfoForIntegratedApp();
|
||||
ConnectionInitiator.OpenConnection(newConnectionInfo);
|
||||
_connectionInitiator.OpenConnection(newConnectionInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -15,8 +15,10 @@ namespace mRemoteNG.Tools
|
||||
private NotifyIcon _nI;
|
||||
private ContextMenuStrip _cMen;
|
||||
private ToolStripMenuItem _cMenCons;
|
||||
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
|
||||
|
||||
public bool Disposed { get; set; }
|
||||
|
||||
public bool Disposed { get; set; }
|
||||
|
||||
public NotificationAreaIcon()
|
||||
{
|
||||
@@ -124,7 +126,7 @@ namespace mRemoteNG.Tools
|
||||
{
|
||||
ShowForm();
|
||||
}
|
||||
ConnectionInitiator.OpenConnection((ConnectionInfo)((Control)sender).Tag);
|
||||
_connectionInitiator.OpenConnection((ConnectionInfo)((Control)sender).Tag);
|
||||
}
|
||||
|
||||
private void cMenExit_Click(Object sender, EventArgs e)
|
||||
|
||||
11
mRemoteV1/Tree/AlwaysConfirmYes.cs
Normal file
11
mRemoteV1/Tree/AlwaysConfirmYes.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
namespace mRemoteNG.Tree
|
||||
{
|
||||
public class AlwaysConfirmYes : IConfirm
|
||||
{
|
||||
public bool Confirm()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
mRemoteV1/Tree/ClickHandlers/ExpandNodeClickHandler.cs
Normal file
28
mRemoteV1/Tree/ClickHandlers/ExpandNodeClickHandler.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
mRemoteV1/Tree/ClickHandlers/ITreeNodeClickHandler.cs
Normal file
10
mRemoteV1/Tree/ClickHandlers/ITreeNodeClickHandler.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
|
||||
namespace mRemoteNG.Tree
|
||||
{
|
||||
public interface ITreeNodeClickHandler
|
||||
{
|
||||
void Execute(ConnectionInfo clickedNode);
|
||||
}
|
||||
}
|
||||
26
mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs
Normal file
26
mRemoteV1/Tree/ClickHandlers/OpenConnectionClickHandler.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
|
||||
namespace mRemoteNG.Tree
|
||||
{
|
||||
public class TreeNodeCompositeClickHandler : ITreeNodeClickHandler
|
||||
{
|
||||
public IEnumerable<ITreeNodeClickHandler> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
mRemoteV1/Tree/IConfirm.cs
Normal file
7
mRemoteV1/Tree/IConfirm.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace mRemoteNG.Tree
|
||||
{
|
||||
public interface IConfirm
|
||||
{
|
||||
bool Confirm();
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
31
mRemoteV1/Tree/PreviousSessionOpener.cs
Normal file
31
mRemoteV1/Tree/PreviousSessionOpener.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs
Normal file
19
mRemoteV1/Tree/PreviouslyOpenedFolderExpander.cs
Normal file
@@ -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<ContainerInfo>();
|
||||
var previouslyExpandedNodes = containerList.Where(container => container.IsExpanded);
|
||||
connectionTree.ExpandedObjects = previouslyExpandedNodes;
|
||||
connectionTree.InvokeRebuildAll(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
mRemoteV1/Tree/RootNodeExpander.cs
Normal file
14
mRemoteV1/Tree/RootNodeExpander.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
56
mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs
Normal file
56
mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs
Normal file
@@ -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<string, string, MessageBoxButtons, MessageBoxIcon, DialogResult> _confirmationFunc;
|
||||
|
||||
public SelectedConnectionDeletionConfirmer(IConnectionTree connectionTree, Func<string, string, MessageBoxButtons, MessageBoxIcon, DialogResult> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs
generated
Normal file
36
mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace mRemoteNG.UI.Controls
|
||||
{
|
||||
partial class ConnectionTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
280
mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
Normal file
280
mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
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<IConnectionTreeDelegate> 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;
|
||||
CellClick += tvConnections_NodeMouseSingleClick;
|
||||
CellClick += tvConnections_NodeMouseDoubleClick;
|
||||
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<ConnectionInfo>().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<RootPuttySessionsNodeInfo> GetRootPuttyNodes()
|
||||
{
|
||||
return Objects.OfType<RootPuttySessionsNodeInfo>();
|
||||
}
|
||||
|
||||
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 tvConnections_NodeMouseSingleClick(object sender, CellClickEventArgs e)
|
||||
{
|
||||
if (e.ClickCount > 1) return;
|
||||
var clickedNode = e.Model as ConnectionInfo;
|
||||
SingleClickHandler.Execute(clickedNode);
|
||||
}
|
||||
|
||||
private void tvConnections_NodeMouseDoubleClick(object sender, CellClickEventArgs e)
|
||||
{
|
||||
if (e.ClickCount < 2) return;
|
||||
var clickedNode = e.Model as ConnectionInfo;
|
||||
DoubleClickHandler.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
|
||||
}
|
||||
}
|
||||
25
mRemoteV1/UI/Controls/ConnectionTree/IConnectionTree.cs
Normal file
25
mRemoteV1/UI/Controls/ConnectionTree/IConnectionTree.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
namespace mRemoteNG.UI.Controls
|
||||
{
|
||||
public interface IConnectionTreeDelegate
|
||||
{
|
||||
void Execute(IConnectionTree connectionTree);
|
||||
}
|
||||
}
|
||||
18
mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs
Normal file
18
mRemoteV1/UI/Controls/ConnectionTree/NameColumn.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
mRemoteV1/UI/Controls/StatusImageList.cs
Normal file
57
mRemoteV1/UI/Controls/StatusImageList.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -495,13 +497,13 @@ 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();
|
||||
}
|
||||
|
||||
@@ -547,19 +549,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();
|
||||
}
|
||||
|
||||
@@ -585,7 +587,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
|
||||
@@ -860,7 +862,7 @@ namespace mRemoteNG.UI.Forms
|
||||
return;
|
||||
}
|
||||
cmbQuickConnect.Add(connectionInfo);
|
||||
ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
|
||||
_connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -936,14 +938,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
|
||||
|
||||
25
mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs
generated
25
mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ConnectionInfo>().First(item => item is RootNodeInfo);
|
||||
}
|
||||
|
||||
private IEnumerable<RootPuttySessionsNodeInfo> GetRootPuttyNodes()
|
||||
{
|
||||
return olvConnections.Objects.OfType<RootPuttySessionsNodeInfo>();
|
||||
}
|
||||
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<ContainerInfo>();
|
||||
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<IConnectionTreeDelegate>
|
||||
{
|
||||
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<ITreeNodeClickHandler>();
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -117,9 +117,6 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="imgListTree.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="msMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>119, 19</value>
|
||||
</metadata>
|
||||
|
||||
@@ -27,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 = "")
|
||||
@@ -333,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +650,7 @@ 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)
|
||||
@@ -665,7 +666,7 @@ 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)
|
||||
{
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
<Compile Include="Connection\Converter.cs" />
|
||||
<Compile Include="Connection\DefaultConnectionInfo.cs" />
|
||||
<Compile Include="Connection\DefaultConnectionInheritance.cs" />
|
||||
<Compile Include="Connection\IConnectionInitiator.cs" />
|
||||
<Compile Include="Connection\IInheritable.cs" />
|
||||
<Compile Include="Connection\IHasParent.cs" />
|
||||
<Compile Include="Connection\Protocol\ProtocolFactory.cs" />
|
||||
@@ -211,15 +212,31 @@
|
||||
<Compile Include="Tools\ExternalToolsTypeConverter.cs" />
|
||||
<Compile Include="Tools\ScanHost.cs" />
|
||||
<Compile Include="Tools\SecureTransfer.cs" />
|
||||
<Compile Include="Tree\AlwaysConfirmYes.cs" />
|
||||
<Compile Include="Tree\SelectedConnectionDeletionConfirmer.cs" />
|
||||
<Compile Include="Tree\ConnectionTreeDragAndDropHandler.cs" />
|
||||
<Compile Include="Tree\ConnectionTreeModel.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\ExpandNodeClickHandler.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\ITreeNodeClickHandler.cs" />
|
||||
<Compile Include="Tree\IConfirm.cs" />
|
||||
<Compile Include="Tree\NodeSearcher.cs" />
|
||||
<Compile Include="Tree\NodeType.cs" />
|
||||
<Compile Include="Tree\ObjectListViewExtensions.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\OpenConnectionClickHandler.cs" />
|
||||
<Compile Include="Tree\PreviouslyOpenedFolderExpander.cs" />
|
||||
<Compile Include="Tree\PreviousSessionOpener.cs" />
|
||||
<Compile Include="Tree\RootNodeExpander.cs" />
|
||||
<Compile Include="Tree\Root\RootNodeTypeEnum.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandler.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandler.cs" />
|
||||
<Compile Include="UI\Controls\ConnectionContextMenu.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\ConnectionTree\ConnectionTree.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\ConnectionTree\ConnectionTree.Designer.cs">
|
||||
<DependentUpon>ConnectionTree.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\FilteredPropertyGrid\FilteredPropertyGrid.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
@@ -227,12 +244,18 @@
|
||||
<DependentUpon>FilteredPropertyGrid.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\FilteredPropertyGrid\ObjectWrapper.cs" />
|
||||
<Compile Include="UI\Controls\ConnectionTree\IConnectionTree.cs" />
|
||||
<Compile Include="UI\Controls\IPTextBox.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\ConnectionTree\IConnectionTreeDelegate.cs" />
|
||||
<Compile Include="UI\Controls\ConnectionTree\NameColumn.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\QuickConnectComboBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\Controls\StatusImageList.cs" />
|
||||
<Compile Include="UI\Controls\ToolStripSplitButton.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
|
||||
3
mRemoteV1/mRemoteV1.csproj.DotSettings
Normal file
3
mRemoteV1/mRemoteV1.csproj.DotSettings
Normal file
@@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tree_005Cclickhandlers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ui_005Ccontrols_005Cconnectiontree/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
Reference in New Issue
Block a user