Skip to content

Commit b8352f5

Browse files
authored
PuTTY with tabs added
PuTTY with tabs added
1 parent 105ca12 commit b8352f5

50 files changed

Lines changed: 2059 additions & 95 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Source/NETworkManager.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,25 @@ EndProject
88
Global
99
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1010
Debug|Any CPU = Debug|Any CPU
11+
Debug|x64 = Debug|x64
1112
Release|Any CPU = Release|Any CPU
13+
Release|x64 = Release|x64
1214
EndGlobalSection
1315
GlobalSection(ProjectConfigurationPlatforms) = postSolution
1416
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1517
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Debug|x64.ActiveCfg = Debug|x64
19+
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Debug|x64.Build.0 = Debug|x64
1620
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Release|Any CPU.ActiveCfg = Release|Any CPU
1721
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Release|Any CPU.Build.0 = Release|Any CPU
1822
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Release|Any CPU.Deploy.0 = Release|Any CPU
23+
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Release|x64.ActiveCfg = Release|x64
24+
{E825EC30-AFA2-476A-AC2C-7537630A645B}.Release|x64.Build.0 = Release|x64
1925
EndGlobalSection
2026
GlobalSection(SolutionProperties) = preSolution
2127
HideSolutionNode = FALSE
2228
EndGlobalSection
29+
GlobalSection(ExtensibilityGlobals) = postSolution
30+
SolutionGuid = {0D35FFD6-8915-433B-9899-258AEAE2AEFF}
31+
EndGlobalSection
2332
EndGlobal

Source/NETworkManager/App.xaml.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ private void Application_Exit(object sender, ExitEventArgs e)
114114

115115
if (RemoteDesktopSessionManager.SessionsChanged)
116116
RemoteDesktopSessionManager.Save();
117+
118+
if (PuTTYSessionManager.SessionsChanged)
119+
PuTTYSessionManager.Save();
117120
}
118121
}
119122
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Dragablz;
2+
using System.Windows;
3+
4+
namespace NETworkManager.Controls
5+
{
6+
public class DragablzPuTTYInterTabClient : IInterTabClient
7+
{
8+
public INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source)
9+
{
10+
DragablzPuTTYTabHostWindow dragablzPuTTYTabHostWindow = new DragablzPuTTYTabHostWindow();
11+
return new NewTabHost<DragablzPuTTYTabHostWindow>(dragablzPuTTYTabHostWindow, dragablzPuTTYTabHostWindow.TabsContainer);
12+
}
13+
14+
public TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)
15+
{
16+
return TabEmptiedResponse.DoNothing;
17+
}
18+
}
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Controls:MetroWindow x:Class="NETworkManager.Controls.DragablzPuTTYTabHostWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
7+
xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz"
8+
xmlns:IconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
9+
mc:Ignorable="d"
10+
Title="{DynamicResource String_ProductName}" Style="{DynamicResource DefaultWindow}" MinWidth="650" MinHeight="500" Height="650" Width="1000" TitleAlignment="Left">
11+
<Controls:MetroWindow.WindowButtonCommands>
12+
<Controls:WindowButtonCommands Template="{DynamicResource MahApps.Metro.Templates.WindowButtonCommands.Win10}" />
13+
</Controls:MetroWindow.WindowButtonCommands>
14+
<Grid>
15+
<dragablz:TabablzControl Name="TabsContainer" ClosingItemCallback="{Binding CloseItemCommand}">
16+
<dragablz:TabablzControl.InterTabController>
17+
<dragablz:InterTabController Partition="70BF46A6-B55D-4DC2-B8BD-6B61EFC95883" />
18+
</dragablz:TabablzControl.InterTabController>
19+
<dragablz:TabablzControl.Style>
20+
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource DefaultTabablzControl}">
21+
<!-- If not null, the header suffix will be removed in the main window -->
22+
<Setter Property="HeaderSuffixContent" Value="{x:Null}" />
23+
<Setter Property="ContentTemplate">
24+
<Setter.Value>
25+
<DataTemplate>
26+
<ContentPresenter Content="{Binding View}" />
27+
</DataTemplate>
28+
</Setter.Value>
29+
</Setter>
30+
</Style>
31+
</dragablz:TabablzControl.Style>
32+
</dragablz:TabablzControl>
33+
</Grid>
34+
</Controls:MetroWindow>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Dragablz;
2+
using MahApps.Metro.Controls;
3+
4+
namespace NETworkManager.Controls
5+
{
6+
/// <summary>
7+
/// Interaktionslogik für Settings.xaml
8+
/// </summary>
9+
public partial class DragablzPuTTYTabHostWindow : MetroWindow
10+
{
11+
public DragablzPuTTYTabHostWindow()
12+
{
13+
InitializeComponent();
14+
DataContext = this;
15+
}
16+
17+
#region ICommand & Actions
18+
public ItemActionCallback CloseItemCommand
19+
{
20+
get { return CloseItemAction; }
21+
}
22+
23+
private void CloseItemAction(ItemActionCallbackArgs<TabablzControl> args)
24+
{
25+
((args.DragablzItem.Content as DragablzPuTTYTabItem).View as PuTTYControl).CloseTab();
26+
}
27+
#endregion
28+
}
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using NETworkManager.Models.PuTTY;
2+
using NETworkManager.ViewModels;
3+
using System;
4+
using System.Diagnostics;
5+
6+
namespace NETworkManager.Controls
7+
{
8+
public class DragablzPuTTYTabItem : ViewModelBase
9+
{
10+
public string Header { get; set; }
11+
public PuTTYControl View { get; set; }
12+
13+
public DragablzPuTTYTabItem(string header, PuTTYControl view)
14+
{
15+
Header = header;
16+
View = view;
17+
}
18+
}
19+
}

Source/NETworkManager/Controls/DragablzRemoteDesktopTabHostWindow.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<dragablz:InterTabController Partition="3D21565B-3E97-42F1-B0B9-CCA7DA63EFB2" />
1717
</dragablz:TabablzControl.InterTabController>
1818
<dragablz:TabablzControl.Style>
19-
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource DefaultTabablzControl}">
19+
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource DefaultTabablzControl}">
2020
<!-- If not null, the header suffix will be removed in the main window -->
2121
<Setter Property="HeaderSuffixContent" Value="{x:Null}" />
2222
<Setter Property="ContentTemplate">
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<UserControl x:Class="NETworkManager.Controls.PuTTYControl"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:Converter="clr-namespace:NETworkManager.Converters"
7+
xmlns:WindowsForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
8+
mc:Ignorable="d" Loaded="UserControl_Loaded">
9+
<UserControl.Resources>
10+
<Converter:BooleanReverseToVisibilityConverter x:Key="BooleanReverseToVisibilityConverter" />
11+
<Converter:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
12+
</UserControl.Resources>
13+
<Grid x:Name="puTTYGrid" SizeChanged="PuTTYGrid_SizeChanged" Margin="10">
14+
<WindowsFormsHost>
15+
<WindowsForms:Panel x:Name="puTTYHost" />
16+
</WindowsFormsHost>
17+
</Grid>
18+
</UserControl>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Contains code from: https://stackoverflow.com/questions/5028598/hosting-external-app-in-wpf-window
2+
3+
using System.ComponentModel;
4+
using System.Runtime.CompilerServices;
5+
using System.Windows;
6+
using System.Windows.Controls;
7+
using System;
8+
using System.Windows.Threading;
9+
using System.Diagnostics;
10+
using NETworkManager.Utils;
11+
using NETworkManager.Models.PuTTY;
12+
13+
namespace NETworkManager.Controls
14+
{
15+
public partial class PuTTYControl : UserControl, INotifyPropertyChanged
16+
{
17+
#region PropertyChangedEventHandler
18+
public event PropertyChangedEventHandler PropertyChanged;
19+
20+
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
21+
{
22+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
23+
}
24+
#endregion
25+
26+
#region Variables
27+
private bool _initialized = false;
28+
29+
private PuTTYSessionInfo _puTTYSessionInfo;
30+
31+
Process PuTTYProcess = null;
32+
IntPtr AppWin;
33+
34+
DispatcherTimer resizeTimer = new DispatcherTimer();
35+
#endregion
36+
37+
#region Constructor, load
38+
public PuTTYControl(PuTTYSessionInfo info)
39+
{
40+
InitializeComponent();
41+
DataContext = this;
42+
43+
_puTTYSessionInfo = info;
44+
45+
resizeTimer.Tick += ResizeTimer_Tick;
46+
resizeTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
47+
48+
Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
49+
}
50+
51+
private void UserControl_Loaded(object sender, RoutedEventArgs e)
52+
{
53+
// Connect after the control is drawn and only on the first init
54+
if (!_initialized)
55+
{
56+
Connect();
57+
_initialized = true;
58+
}
59+
}
60+
61+
private void Dispatcher_ShutdownStarted(object sender, EventArgs e)
62+
{
63+
OnClose();
64+
}
65+
#endregion
66+
67+
#region ICommands & Actions
68+
69+
70+
71+
#endregion
72+
73+
#region Methods
74+
private void Connect()
75+
{
76+
ProcessStartInfo info = new ProcessStartInfo
77+
{
78+
FileName = _puTTYSessionInfo.PuTTYLocation,
79+
Arguments = string.Format("{0}", _puTTYSessionInfo.Host)
80+
};
81+
82+
PuTTYProcess = Process.Start(info);
83+
84+
PuTTYProcess.WaitForInputIdle();
85+
86+
AppWin = PuTTYProcess.MainWindowHandle;
87+
88+
NativeMethods.SetParent(AppWin, puTTYHost.Handle);
89+
90+
// Show window before set style and resize
91+
NativeMethods.ShowWindow(AppWin, NativeMethods.WindowShowStyle.Maximize);
92+
93+
// Remove border etc.
94+
int style = (int)NativeMethods.GetWindowLong(AppWin, NativeMethods.GWL_STYLE);
95+
style &= ~(NativeMethods.WS_BORDER | NativeMethods.WS_THICKFRAME);
96+
NativeMethods.SetWindowLongPtr(AppWin, NativeMethods.GWL_STYLE, new IntPtr(style));
97+
98+
// Resize embedded application & refresh
99+
if (PuTTYProcess != null)
100+
ResizeEmbeddedPuTTY();
101+
}
102+
103+
public void Disconnect()
104+
{
105+
if (PuTTYProcess != null && !PuTTYProcess.HasExited)
106+
PuTTYProcess.Kill();
107+
}
108+
109+
private void ResizeEmbeddedPuTTY()
110+
{
111+
try
112+
{
113+
NativeMethods.SetWindowPos(PuTTYProcess.MainWindowHandle, IntPtr.Zero, 0, 0, puTTYHost.ClientSize.Width, puTTYHost.ClientSize.Height, NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOACTIVATE);
114+
}
115+
catch(Exception ex)
116+
{
117+
MessageBox.Show(ex.Message);
118+
}
119+
}
120+
121+
public void CloseTab()
122+
{
123+
Disconnect();
124+
}
125+
126+
private void OnClose()
127+
{
128+
Disconnect();
129+
}
130+
#endregion
131+
132+
#region Events
133+
private void PuTTYGrid_SizeChanged(object sender, SizeChangedEventArgs e)
134+
{
135+
if (PuTTYProcess != null)
136+
ResizeEmbeddedPuTTY();
137+
}
138+
139+
private void ResizeTimer_Tick(object sender, EventArgs e)
140+
{
141+
resizeTimer.Stop();
142+
143+
ResizeEmbeddedPuTTY();
144+
}
145+
#endregion
146+
}
147+
}

Source/NETworkManager/Converters/ValidateSettingsExportConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public sealed class ValidateSettingsExportConverter : IMultiValueConverter
88
{
99
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
1010
{
11-
return (!(bool)values[0] && (bool)values[1] || (bool)values[2] || (bool)values[3] || (bool)values[4] || (bool)values[5] || (bool)values[6]);
11+
return (!(bool)values[0] && (bool)values[1] || (bool)values[2] || (bool)values[3] || (bool)values[4] || (bool)values[5] || (bool)values[6] || (bool)values[7]);
1212
}
1313

1414
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)

0 commit comments

Comments
 (0)