mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 15:17:34 +00:00
source code checkin
This commit is contained in:
parent
5f8fb2c825
commit
7e57b72e35
675 changed files with 168433 additions and 0 deletions
31
src/ConanServerManager/Windows/AddUserWindow.xaml
Normal file
31
src/ConanServerManager/Windows/AddUserWindow.xaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<Window x:Class="ServerManagerTool.AddUserWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
MinHeight="200" Width="300" Height="200" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResize"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource AddUser_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Users, Mode=TwoWay}" Margin="5,5,5,0" TextWrapping="NoWrap" VerticalScrollBarVisibility="Auto" AcceptsReturn="true"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,0" Text="{DynamicResource AddUser_InstructionLabel}" VerticalAlignment="Center" TextWrapping="Wrap" />
|
||||
<Button Grid.Row="2" Grid.Column="0" Content="{DynamicResource AddUser_ProcessButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" Click="Process_Click"/>
|
||||
<Button Grid.Row="2" Grid.Column="1" Content="{DynamicResource AddUser_CancelButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
33
src/ConanServerManager/Windows/AddUserWindow.xaml.cs
Normal file
33
src/ConanServerManager/Windows/AddUserWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using ServerManagerTool.Common.Utils;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AddUserWindow.xaml
|
||||
/// </summary>
|
||||
public partial class AddUserWindow : Window
|
||||
{
|
||||
public AddUserWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UsersProperty = DependencyProperty.Register(nameof(Users), typeof(string), typeof(AddUserWindow), new PropertyMetadata(string.Empty));
|
||||
public string Users
|
||||
{
|
||||
get { return (string)GetValue(UsersProperty); }
|
||||
set { SetValue(UsersProperty, value); }
|
||||
}
|
||||
|
||||
private void Process_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/ConanServerManager/Windows/AutoUpdateWindow.xaml
Normal file
23
src/ConanServerManager/Windows/AutoUpdateWindow.xaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<Window x:Class="ServerManagerTool.AutoUpdateWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Width="380" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" SizeToContent="Height"
|
||||
Loaded="Window_Loaded" Closing="Window_Closing"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource AutoUpdater_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<StackPanel HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch" Width="Auto">
|
||||
<ProgressBar x:Name="CompletionProgress" Height="10"/>
|
||||
<Label x:Name="StatusLabel" Content="{DynamicResource AutoUpdater_Status}" HorizontalContentAlignment="Center"/>
|
||||
<Button Content="{DynamicResource AutoUpdater_CancelButtonLabel}" Width="75" HorizontalAlignment="Center" IsCancel="True" Click="Button_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
65
src/ConanServerManager/Windows/AutoUpdateWindow.xaml.cs
Normal file
65
src/ConanServerManager/Windows/AutoUpdateWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AutoUpdateWindow.xaml
|
||||
/// </summary>
|
||||
public partial class AutoUpdateWindow : Window
|
||||
{
|
||||
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
private SteamCmdUpdater updater = new SteamCmdUpdater();
|
||||
private CancellationTokenSource cancelSource;
|
||||
|
||||
public AutoUpdateWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
cancelSource = new CancellationTokenSource();
|
||||
updater.UpdateSteamCmdAsync(Config.Default.DataPath, new Progress<SteamCmdUpdater.Update>(async u =>
|
||||
{
|
||||
var message = string.IsNullOrWhiteSpace(u.StatusKey) ? string.Empty : _globalizer.GetResourceString(u.StatusKey) ?? u.StatusKey;
|
||||
this.StatusLabel.Content = message;
|
||||
this.CompletionProgress.Value = u.CompletionPercent;
|
||||
|
||||
if(u.FailureText != null)
|
||||
{
|
||||
// TODO: Report error through UI
|
||||
throw new Exception(u.FailureText);
|
||||
}
|
||||
|
||||
if (u.CompletionPercent >= 100 || u.Cancelled)
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var mainWindow = new MainWindow();
|
||||
mainWindow.Show();
|
||||
this.Close();
|
||||
});
|
||||
}
|
||||
}), cancelSource.Token);
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (cancelSource != null)
|
||||
cancelSource.Cancel();
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (cancelSource != null)
|
||||
cancelSource.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/ConanServerManager/Windows/CommandLineWindow.xaml
Normal file
24
src/ConanServerManager/Windows/CommandLineWindow.xaml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<Window x:Class="ServerManagerTool.CommandLineWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
MinWidth="500" MinHeight="200" Width="500" Height="200" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResize"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource CommandLine_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Name="OutputTextBox" Grid.Row="0" Text="{Binding Mode=OneWay}" Margin="5,5,5,0" IsReadOnly="True" IsReadOnlyCaretVisible="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/>
|
||||
<Button Grid.Row="1" Content="{DynamicResource CommandLine_CopyButtonLabel}" Margin="5" HorizontalAlignment="Center" Click="CopyToClipboard_Click"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
41
src/ConanServerManager/Windows/CommandLineWindow.xaml.cs
Normal file
41
src/ConanServerManager/Windows/CommandLineWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using ServerManagerTool.Common.Utils;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CommandLineWindow.xaml
|
||||
/// </summary>
|
||||
public partial class CommandLineWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public CommandLineWindow(string commandLine)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.DataContext = commandLine;
|
||||
}
|
||||
|
||||
public TextWrapping OutputTextWrapping
|
||||
{
|
||||
get { return OutputTextBox.TextWrapping; }
|
||||
set { OutputTextBox.TextWrapping = value; }
|
||||
}
|
||||
|
||||
private void CopyToClipboard_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Clipboard.SetText(this.DataContext as string);
|
||||
MessageBox.Show(_globalizer.GetResourceString("CommandLine_CopyButton_ConfirmLabel"), _globalizer.GetResourceString("CommandLine_CopyButton_ConfirmTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("CommandLine_CopyButton_ErrorLabel"), _globalizer.GetResourceString("CommandLine_CopyButton_ErrorTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/ConanServerManager/Windows/GameDataWindow.xaml
Normal file
128
src/ConanServerManager/Windows/GameDataWindow.xaml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
<Window x:Class="ServerManagerTool.GameDataWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
MinWidth="640" MinHeight="480" Width="800" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Loaded="Window_Loaded"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource GameDataWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Row="0" HorizontalAlignment="Stretch" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||
<Button Width="22" Height="22" Click="AddGameData_Click" ToolTip="{DynamicResource GameDataWindow_AddGameDataTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Add.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="ClearGameData_Click" Margin="10,0,0,0" ToolTip="{DynamicResource GameDataWindow_ClearGameDataTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="ReloadGameData_Click" Margin="10,0,0,0" ToolTip="{DynamicResource GameDataWindow_ReloadGameDataTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Reload.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="ValidateGameData_Click" Margin="10,0,0,0" ToolTip="{DynamicResource GameDataWindow_ValidateGameDataTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Validate.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="OpenGameDataFolder_Click" Margin="10,0,0,0" ToolTip="{DynamicResource GameDataWindow_OpenGameDataFolderTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/FolderOpen.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="GameDataForum_Click" Margin="20,0,0,0" ToolTip="{DynamicResource GameDataWindow_GameDataForumTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Help.ico,Size=32}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</GroupBox.Header>
|
||||
|
||||
<DataGrid ItemsSource="{Binding GameDataFiles}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsUserData}" Value="False">
|
||||
<Setter Property="Foreground" Value="Blue" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding HasError}" Value="True">
|
||||
<Setter Property="Foreground" Value="Red" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Width="4*" Binding="{Binding FileName, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource GameDataWindow_NameColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="Auto" MinWidth="80" Binding="{Binding Version, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource GameDataWindow_VersionColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="130" Binding="{Binding CreatedDate, Mode=OneWay}" Header="{DynamicResource GameDataWindow_DateColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="RemoveGameData_Click" ToolTip="{DynamicResource GameDataWindow_RemoveGameDataTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsUserData}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Window>
|
||||
371
src/ConanServerManager/Windows/GameDataWindow.xaml.cs
Normal file
371
src/ConanServerManager/Windows/GameDataWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for GameDataWindow.xaml
|
||||
/// </summary>
|
||||
public partial class GameDataWindow : Window
|
||||
{
|
||||
public class GameDataFileList : SortableObservableCollection<GameDataFile>
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(GameDataFile)} - {Count}";
|
||||
}
|
||||
}
|
||||
|
||||
public class GameDataFile : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty CreatedDateProperty = DependencyProperty.Register(nameof(CreatedDate), typeof(DateTime), typeof(GameDataFile), new PropertyMetadata(DateTime.MinValue));
|
||||
public static readonly DependencyProperty FileProperty = DependencyProperty.Register(nameof(File), typeof(string), typeof(GameDataFile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register(nameof(FileName), typeof(string), typeof(GameDataFile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IsUserDataProperty = DependencyProperty.Register(nameof(IsUserData), typeof(bool), typeof(GameDataFile), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty VersionProperty = DependencyProperty.Register(nameof(Version), typeof(string), typeof(GameDataFile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty HasErrorProperty = DependencyProperty.Register(nameof(HasError), typeof(bool), typeof(GameDataFile), new PropertyMetadata(false));
|
||||
|
||||
public DateTime CreatedDate
|
||||
{
|
||||
get { return (DateTime)GetValue(CreatedDateProperty); }
|
||||
set { SetValue(CreatedDateProperty, value); }
|
||||
}
|
||||
|
||||
public string File
|
||||
{
|
||||
get { return (string)GetValue(FileProperty); }
|
||||
set { SetValue(FileProperty, value); }
|
||||
}
|
||||
|
||||
public string FileName
|
||||
{
|
||||
get { return (string)GetValue(FileNameProperty); }
|
||||
set { SetValue(FileNameProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsUserData
|
||||
{
|
||||
get { return (bool)GetValue(IsUserDataProperty); }
|
||||
set { SetValue(IsUserDataProperty, value); }
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get { return (string)GetValue(VersionProperty); }
|
||||
set { SetValue(VersionProperty, value); }
|
||||
}
|
||||
|
||||
public bool HasError
|
||||
{
|
||||
get { return (bool)GetValue(HasErrorProperty); }
|
||||
set { SetValue(HasErrorProperty, value); }
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty GameDataFilesProperty = DependencyProperty.Register(nameof(GameDataFiles), typeof(GameDataFileList), typeof(GameDataWindow), new PropertyMetadata(null));
|
||||
|
||||
public GameDataWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.GameDataFiles = new GameDataFileList();
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public GameDataFileList GameDataFiles
|
||||
{
|
||||
get { return GetValue(GameDataFilesProperty) as GameDataFileList; }
|
||||
set { SetValue(GameDataFilesProperty, value); }
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReloadGameDataFiles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_LoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog();
|
||||
dialog.Title = GlobalizedApplication.Instance.GetResourceString("GameDataWindow_AddDialogTitle");
|
||||
dialog.DefaultExtension = GlobalizedApplication.Instance.GetResourceString("GameDataWindow_GameDataDefaultExtension");
|
||||
dialog.Filters.Add(new CommonFileDialogFilter(GlobalizedApplication.Instance.GetResourceString("GameDataWindow_AddFilterLabel"), GlobalizedApplication.Instance.GetResourceString("GameDataWindow_AddFilterExtension")));
|
||||
if (dialog == null || dialog.ShowDialog(this) != CommonFileDialogResult.Ok)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
AddGameDataFile(GameData.UserDataFolder, dialog.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_AddErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearGameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("GameDataWindow_ClearLabel"), _globalizer.GetResourceString("GameDataWindow_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (!GameData.UserDataFolder.Equals(GameData.MainDataFolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
DeleteAllGameDataFiles(GameData.UserDataFolder);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_ClearErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenGameDataFolder_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(GameData.UserDataFolder))
|
||||
Directory.CreateDirectory(GameData.UserDataFolder);
|
||||
Process.Start("explorer.exe", GameData.UserDataFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_OpenErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void GameDataForum_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.GameDataUrl);
|
||||
}
|
||||
|
||||
private void ReloadGameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReloadGameDataFiles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_LoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveGameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("GameDataWindow_DeleteLabel"), _globalizer.GetResourceString("GameDataWindow_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var gameDataItem = ((GameDataFile)((Button)e.Source).DataContext);
|
||||
DeleteGameDataFile(gameDataItem.File, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_DeleteErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateGameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
ValidateAllGameDataFiles(GameData.UserDataFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("GameDataWindow_ClearErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGameDataFile(string folder, string gameDataFile)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(folder))
|
||||
return;
|
||||
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
var newGameDataFile = Path.Combine(folder, $"{Path.GetFileName(gameDataFile)}");
|
||||
if (File.Exists(newGameDataFile))
|
||||
throw new Exception(_globalizer.GetResourceString("GameDataWindow_ExistingFileErrorLabel"));
|
||||
|
||||
ValidateGameDataFile(gameDataFile);
|
||||
|
||||
File.Copy(gameDataFile, newGameDataFile, true);
|
||||
|
||||
LoadGameDataFile(newGameDataFile, true);
|
||||
}
|
||||
|
||||
private void DeleteAllGameDataFiles(string folder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(folder) || !Directory.Exists(folder))
|
||||
return;
|
||||
|
||||
var fileList = Directory.GetFiles(folder, $"*.{GlobalizedApplication.Instance.GetResourceString("GameDataWindow_GameDataDefaultExtension")}");
|
||||
foreach (var file in fileList)
|
||||
{
|
||||
DeleteGameDataFile(file, false);
|
||||
}
|
||||
|
||||
LoadGameDataFiles(GameData.UserDataFolder, true, true);
|
||||
LoadGameDataFiles(GameData.MainDataFolder, false, false);
|
||||
}
|
||||
|
||||
private void DeleteGameDataFile(string file, bool updateList)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
|
||||
return;
|
||||
|
||||
File.Delete(file);
|
||||
|
||||
if (updateList)
|
||||
{
|
||||
var gameDataFiles = GameDataFiles.Where(f => f.File == file).ToList();
|
||||
foreach (var gameDataFile in gameDataFiles)
|
||||
{
|
||||
GameDataFiles.Remove(gameDataFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadGameDataFile(string file, bool isUserData)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
|
||||
return;
|
||||
|
||||
BaseGameData baseGameData = null;
|
||||
|
||||
try
|
||||
{
|
||||
baseGameData = BaseGameData.Load(file);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// do nothing, just swallow the error
|
||||
}
|
||||
|
||||
var gameDataFile = new GameDataFile
|
||||
{
|
||||
CreatedDate = baseGameData?.Created ?? DateTime.MinValue,
|
||||
File = file,
|
||||
FileName = string.IsNullOrWhiteSpace(file) ? string.Empty : Path.GetFileNameWithoutExtension(file),
|
||||
IsUserData = isUserData,
|
||||
Version = baseGameData?.Version ?? "0.0.0",
|
||||
HasError = baseGameData == null,
|
||||
};
|
||||
GameDataFiles.Add(gameDataFile);
|
||||
}
|
||||
|
||||
private void LoadGameDataFiles(string folder, bool isUserData, bool ClearExisting)
|
||||
{
|
||||
if (ClearExisting)
|
||||
GameDataFiles.Clear();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(folder) || !Directory.Exists(folder))
|
||||
return;
|
||||
|
||||
var files = Directory.GetFiles(folder, $"*.{GlobalizedApplication.Instance.GetResourceString("GameDataWindow_GameDataDefaultExtension")}");
|
||||
foreach (var file in files)
|
||||
{
|
||||
LoadGameDataFile(file, isUserData);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReloadGameDataFiles()
|
||||
{
|
||||
if (!GameData.UserDataFolder.Equals(GameData.MainDataFolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
LoadGameDataFiles(GameData.UserDataFolder, true, true);
|
||||
}
|
||||
LoadGameDataFiles(GameData.MainDataFolder, false, false);
|
||||
}
|
||||
|
||||
private void ValidateAllGameDataFiles(string folder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(folder) || !Directory.Exists(folder))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GameDataWindow_ValidateSuccessLabel"), _globalizer.GetResourceString("GameDataWindow_ValidateSuccessTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
var fileList = Directory.GetFiles(folder, $"*.{GlobalizedApplication.Instance.GetResourceString("GameDataWindow_GameDataDefaultExtension")}");
|
||||
var errorList = new List<string>();
|
||||
|
||||
foreach (var file in fileList)
|
||||
{
|
||||
try
|
||||
{
|
||||
ValidateGameDataFile(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorList.Add($"{Path.GetFileNameWithoutExtension(file)} - {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (errorList.Count > 0)
|
||||
{
|
||||
var message = $"{_globalizer.GetResourceString("GameDataWindow_ValidateErrorLabel")}{Environment.NewLine}{string.Join(Environment.NewLine, errorList)}";
|
||||
var window = new CommandLineWindow(message);
|
||||
window.OutputTextWrapping = TextWrapping.NoWrap;
|
||||
window.Height = 300;
|
||||
window.Width = 600;
|
||||
window.Title = _globalizer.GetResourceString("GameDataWindow_ValidateErrorTitle");
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GameDataWindow_ValidateSuccessLabel"), _globalizer.GetResourceString("GameDataWindow_ValidateSuccessTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateGameDataFile(string file)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
|
||||
return;
|
||||
|
||||
MainGameData gameData = null;
|
||||
|
||||
try
|
||||
{
|
||||
gameData = MainGameData.Load(file, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = _globalizer.GetResourceString("GameDataWindow_ValidateErrorMessage");
|
||||
throw new Exception(message, ex);
|
||||
}
|
||||
|
||||
if (gameData == null)
|
||||
{
|
||||
var message = _globalizer.GetResourceString("GameDataWindow_ValidateErrorMessage");
|
||||
throw new Exception(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
692
src/ConanServerManager/Windows/GlobalSettingsControl.xaml
Normal file
692
src/ConanServerManager/Windows/GlobalSettingsControl.xaml
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
<UserControl x:Class="ServerManagerTool.GlobalSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:cctl="clr-namespace:ServerManagerTool.Common.Controls;assembly=ServerManager.Common"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:gctl="clr-namespace:WPFSharp.Globalizer.Controls;assembly=WPFSharp.Globalizer"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:InvertBooleanConverter x:Key="InvertBooleanConverter"/>
|
||||
<cc:MinutesToTimeValueConverter x:Key="MinutesToTimeValueConverter"/>
|
||||
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
</Style>
|
||||
<Style x:Key="HiddenTextBoxStyle" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Background" Value="Wheat"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
</Style>
|
||||
|
||||
<ContentControl x:Key="SaveManagerPasswordButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SaveManagerPasswordButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="CreateManagerUserButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_CreateManagerUserButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DeleteManagerUserButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_DeleteManagerUserButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DataDirectoryButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SetLocationButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="BackupDirectoryButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SetLocationButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="ClearButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_ClearButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="SteamFileButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SetSteamFileButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="SteamAPIKeyButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SteamAPIKeyButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="SteamAPIKeyHelpButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_SteamAPIKeyHelpButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="CacheDirectoryButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_CacheDirectoryButtonLabel}" VerticalAlignment="Center" Margin="0,-3,0,-3"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Margin="3">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<DockPanel Grid.Row="0" Grid.ColumnSpan="4" LastChildFill="False">
|
||||
<Label DockPanel.Dock="Left" Content="{DynamicResource GlobalSettings_Title}" FontSize="20" VerticalAlignment="Center" />
|
||||
<Button DockPanel.Dock="Right" Margin="10,0,0,0" Padding="5,2,5,2" Content="{DynamicResource GlobalSettings_ResetButtonLabel}" Click="ResetSettings_Click" VerticalAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ResetButtonTooltip}"/>
|
||||
<Label DockPanel.Dock="Right" Content="{Binding Version}" FontSize="15" VerticalAlignment="Center"/>
|
||||
<Label DockPanel.Dock="Right" Content="{DynamicResource GlobalSettings_VersionLabel}" FontSize="15" VerticalAlignment="Center" />
|
||||
</DockPanel>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_RunAsAdministratorLabel}" IsChecked="{Binding Config.RunAsAdministratorPrompt, Mode=TwoWay}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_MinimizeToTrayLabel}" IsChecked="{Binding Config.MainWindow_MinimizeToTray, Mode=TwoWay}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManageFirewallLabel}" IsChecked="{Binding Config.ManageFirewallAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManagePublicIPLabel}" IsChecked="{Binding CurrentConfig.ManagePublicIPAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_DataDirectoryLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding Config.DataPath, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" />
|
||||
<Button Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,1,0,1" VerticalAlignment="Center" HorizontalAlignment="Left" Content="{DynamicResource DataDirectoryButtonContent}" Click="SetDataDir_Click"/>
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_BackupDirectoryLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding Config.BackupPath, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" />
|
||||
<StackPanel Grid.Row="5" Grid.Column="3" Orientation="Horizontal">
|
||||
<Button Margin="5,1,0,1" VerticalAlignment="Center" Content="{DynamicResource BackupDirectoryButtonContent}" Click="SetBackupDir_Click"/>
|
||||
<Button Margin="5,1,0,1" VerticalAlignment="Center" Content="{DynamicResource ClearButtonContent}" Click="ClearBackupDir_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
<GroupBox Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_LanguageSelectionLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<gctl:LanguageSelectionComboBox Grid.Row="0" Grid.Column="0" Margin="0,0,5,0" SelectionChanged="LanguageSelectionComboBox_SelectionChanged"/>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Margin="5,0,0,0" Orientation="Horizontal">
|
||||
<StackPanel.Style>
|
||||
<Style TargetType="{x:Type StackPanel}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ElementName=TranslatedByLabel, Path=Content}" Value="unknown">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</StackPanel.Style>
|
||||
|
||||
<Label Content="{DynamicResource Generic_TranslatedByLabel}" VerticalAlignment="Center"/>
|
||||
<Label Name="TranslatedByLabel" Content="{DynamicResource Generic_TranslatedBy}" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_SteamSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" IsChecked="{Binding Config.SteamCmd_UseAnonymousCredentials}" Content="{DynamicResource GlobalSettings_SteamCmdCredentialsLabel}" VerticalAlignment="Bottom" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdCredentialsTooltip}" HorizontalAlignment="Left">
|
||||
<CheckBox.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type CheckBox}}" TargetType="{x:Type CheckBox}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</CheckBox.Style>
|
||||
</CheckBox>
|
||||
<CheckBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="4" Margin="5" Content="{DynamicResource GlobalSettings_SteamCmdRedirectOutputLabel}" IsChecked="{Binding Config.SteamCmdRedirectOutput, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRedirectOutputTooltip}" HorizontalAlignment="Left" Visibility="Collapsed"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="9" Content="{DynamicResource GlobalSettings_SteamCMDAuthentication_DisabledTooltip}" VerticalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="false">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="4" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_SteamCmdUsernameLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding Config.SteamCmd_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdUsernameTooltip}">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
<Label Grid.Row="4" Grid.Column="3" Margin="1" Content="{DynamicResource GlobalSettings_SteamCmdPasswordLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="4" Margin="1" Name="HideSteamPasswordTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource HiddenTextBoxStyle}" TargetType="{x:Type TextBox}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
<TextBox Grid.Row="4" Grid.Column="4" Margin="1" Name="SteamPasswordTextBox" Text="{Binding Config.SteamCmd_Password, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
<Button Grid.Row="4" Grid.Column="6" Margin="1" Content="{DynamicResource GlobalSettings_SteamCMDAuthenticateButtonLabel}" Click="SteamCMDAuthenticate_Click">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
|
||||
<Setter Property="IsEnabled" Value="false"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_SteamAPIKeyLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="4" Margin="1" Name="HideSteamAPIKeyTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="4" Margin="1" Name="SteamAPIKeyTextBox" Text="{Binding CommonConfig.SteamAPIKey, Mode=TwoWay}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed"/>
|
||||
<Button Grid.Row="5" Grid.Column="6" Margin="1" Content="{DynamicResource SteamAPIKeyButtonContent}" Click="ApplySteamAPIKey_Click"/>
|
||||
<Button Grid.Row="5" Grid.Column="7" Margin="1" Content="{DynamicResource SteamAPIKeyHelpButtonContent}" Click="SteamAPIKeyHelp_Click" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_ServerStatusLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EnableServerStatusActionsLabel}" IsChecked="{Binding Config.ServerStatus_EnableActions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableServerStatusActionsTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationLabel}" IsChecked="{Binding Config.ServerStatus_ShowActionConfirmation, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationTooltip}" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_ServerStartupLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_ValidateProfileOnServerStartLabel}" IsChecked="{Binding Config.ValidateProfileOnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateProfileOnServerStartTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ServerUpdateOnServerStartLabel}" IsChecked="{Binding Config.ServerUpdate_OnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ServerUpdateOnServerStartTooltip}" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_UpdateModSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="5,0,0,5" IsChecked="{Binding Config.ServerUpdate_UpdateModsWhenUpdatingServer, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_UpdateModWithServerLabel}" ToolTip="{DynamicResource GlobalSettings_UpdateModWithServerTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="3" Margin="0,0,0,5" IsChecked="{Binding Config.ServerUpdate_ForceUpdateMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="6" Margin="0,0,0,5" IsChecked="{Binding Config.ServerUpdate_ForceCopyMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceCopyModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceCopyModsTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="6" Margin="5,0,0,0" IsChecked="{Binding Config.ServerUpdate_ForceUpdateModsIfNoSteamInfo, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" Margin="0,0,5,0" Label="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursLabel}" Value="{Binding Config.WorkshopCache_ExpiredHours}" Minimum="0" Maximum="1000" SmallChange="1" LargeChange="12" TickFrequency="24" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Hours}" ToolTip="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="14" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}" IsEnabled="{Binding IsAdministrator}">
|
||||
<GroupBox.Header>
|
||||
<CheckBox IsChecked="{Binding Config.AutoBackup_EnableBackup}" Content="{DynamicResource GlobalSettings_AutoBackupLabel}" VerticalAlignment="Center"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid IsEnabled="{Binding Config.AutoBackup_EnableBackup}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_BackupIntervalLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_BackupIntervalTooltip}">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Config.AutoBackup_BackupPeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_DeleteOldFilesLabel}" IsChecked="{Binding Config.AutoBackup_DeleteOldFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,0,5,0" Label="{DynamicResource GlobalSettings_DeleteIntervalLabel}" Value="{Binding Config.AutoBackup_DeleteInterval}" Minimum="1" Maximum="1000" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Days}" ToolTip="{DynamicResource GlobalSettings_DeleteIntervalTooltip}" IsEnabled="{Binding Config.AutoBackup_DeleteOldFiles}"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_BackupWorldSaveLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="4" Margin="1" Text="{Binding Config.ServerBackup_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_BackupWorldSaveTooltip}"/>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="15" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}" IsEnabled="{Binding IsAdministrator}">
|
||||
<GroupBox.Header>
|
||||
<CheckBox IsChecked="{Binding Config.AutoUpdate_EnableUpdate}" Content="{DynamicResource GlobalSettings_AutoUpdateLabel}" VerticalAlignment="Center"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid IsEnabled="{Binding Config.AutoUpdate_EnableUpdate}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_CacheDirectoryLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Grid.ColumnSpan="4" Text="{Binding Config.AutoUpdate_CacheDir}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_CacheDirectoryTooltip}"/>
|
||||
<Button Grid.Row="0" Grid.Column="5" Margin="5,1,0,1" Content="{StaticResource CacheDirectoryButtonContent}" VerticalAlignment="Center" Click="SetCacheDir_Click"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_UpdateIntervalLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UpdateIntervalTooltip}">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Config.AutoUpdate_UpdatePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_ValidateServerFilesLabel}" IsChecked="{Binding Config.AutoUpdate_ValidateServerFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateServerFilesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="3" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_UseSmartCopyLabel}" IsChecked="{Binding Config.AutoUpdate_UseSmartCopy, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="4" Margin="5,0,0,0" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_RetryOnFailLabel}" IsChecked="{Binding Config.AutoUpdate_RetryOnFail, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_RetryOnFailTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_OverrideServerStartupLabel}" IsChecked="{Binding Config.AutoUpdate_OverrideServerStartup, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_OverrideServerStartupTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="3" Content="{DynamicResource GlobalSettings_ParallelUpdateLabel}" IsChecked="{Binding Config.AutoUpdate_ParallelUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ParallelUpdateTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<cctl:AnnotatedSlider Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="4" Margin="0,2,0,2" Label="{DynamicResource GlobalSettings_SequencialDelayPeriodLabel}" Value="{Binding Config.AutoUpdate_SequencialDelayPeriod}" Minimum="0" Maximum="1200" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_SequencialDelayPeriodTooltip}" IsEnabled="{Binding Config.AutoUpdate_ParallelUpdate, Converter={StaticResource InvertBooleanConverter}}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShowUpdateReasonLabel}" IsChecked="{Binding Config.AutoUpdate_ShowUpdateReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowUpdateReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<Label Grid.Row="4" Grid.Column="2" Margin="0,2,0,2" Content="{DynamicResource GlobalSettings_UpdateReasonPrefixLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="3" Margin="1" Grid.ColumnSpan="2" IsEnabled="{Binding Config.AutoUpdate_ShowUpdateReason}" Text="{Binding Config.AutoUpdate_UpdateReasonPrefix}" MaxLength="50" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UpdateReasonPrefixTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="16" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_AutoRestartLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Text="{DynamicResource GlobalSettings_RestartGraceIntervalInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_EnableRestartGraceIntervalLabel}" IsChecked="{Binding Config.AutoRestart_EnabledGracePeriod, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableRestartGraceIntervalTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_RestartGraceIntervalLabel}" ToolTip="{DynamicResource GlobalSettings_RestartGraceIntervalTooltip}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" IsEnabled="{Binding Config.AutoRestart_EnabledGracePeriod}" ToolTip="{DynamicResource GlobalSettings_RestartGraceIntervalTooltip}">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Config.AutoRestart_GracePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="17" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_ShutdownLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" Text="{DynamicResource GlobalSettings_ShutdownMessageInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_CheckForOnlinePlayersLabel}" IsChecked="{Binding Config.ServerShutdown_CheckForOnlinePlayers, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CheckForOnlinePlayersTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_SendShutdownMessagesLabel}" IsChecked="{Binding Config.ServerShutdown_SendShutdownMessages, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SendShutdownMessagesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
|
||||
<cctl:AnnotatedSlider Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="1" Label="{DynamicResource GlobalSettings_ShutdownGraceIntervalLabel}" Value="{Binding Config.ServerShutdown_GracePeriod}" Minimum="0" Maximum="60" SmallChange="1" LargeChange="5" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Minutes}" ToolTip="{DynamicResource GlobalSettings_ShutdownGraceIntervalTooltip}"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage1Label}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage1}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage1Tooltip}"/>
|
||||
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage2Label}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage2}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage2Tooltip}"/>
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage3Label}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage3}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage3Tooltip}"/>
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownWorldSaveLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownWorldSaveTooltip}"/>
|
||||
|
||||
<Label Grid.Row="8" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownCancelLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_CancelMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownCancelTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="9" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonLabel}" IsChecked="{Binding Config.ServerShutdown_AllMessagesShowReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="18" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_AlertsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStopMessageLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStopMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStopMessageTooltip}"/>
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerShutdownMessageLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerShutdownMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerShutdownMessageTooltip}"/>
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStartedMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageTooltip}"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortLabel}" IsChecked="{Binding Config.Alert_ServerStartedMessageIncludeIPandPort, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_BackupProcessErrorLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_BackupProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_BackupProcessErrorTooltip}"/>
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ShutdownProcessErrorLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ShutdownProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ShutdownProcessErrorTooltip}"/>
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_RestartProcessErrorLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_RestartProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_RestartProcessErrorTooltip}"/>
|
||||
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_UpdateProcessErrorLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="7" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_UpdateProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateProcessErrorTooltip}"/>
|
||||
<Label Grid.Row="8" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_UpdateResultsLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_UpdateResults}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateResultsTooltip}"/>
|
||||
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerUpdateLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="9" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerUpdate}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerUpdateTooltip}"/>
|
||||
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStatusChangeLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="10" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStatusChange}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStatusChangeTooltip}"/>
|
||||
<Label Grid.Row="11" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ModUpdateDetectedLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="11" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ModUpdateDetected}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ModUpdateDetectedTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="19" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_EmailHostLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding Config.Email_Host}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailHostTooltip}"/>
|
||||
<Label Grid.Row="0" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailPortLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="4" Margin="1" Text="{Binding Config.Email_Port}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailPortTooltip}"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="7" Content="{DynamicResource GlobalSettings_EmailUseSSLLabel}" IsChecked="{Binding Config.Email_UseSSL}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseSSLTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1" Content="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsLabel}" IsChecked="{Binding Config.Email_UseDetaultCredentials}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsTooltip}" HorizontalAlignment="Left"/>
|
||||
<Label Grid.Row="1" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailUsernameLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="4" Margin="1" Text="{Binding Config.Email_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUsernameTooltip}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}"/>
|
||||
<Label Grid.Row="1" Grid.Column="6" Content="{DynamicResource GlobalSettings_EmailPasswordLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="HideEmailPasswordTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="EmailPasswordTextBox" Text="{Binding Config.Email_Password, Mode=TwoWay}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource GlobalSettings_EmailPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_EmailFromLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding Config.Email_From}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailFromTooltip}"/>
|
||||
<Label Grid.Row="2" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailToLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.Email_To}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailToTooltip}"/>
|
||||
<Button Grid.Row="2" Grid.Column="7" Margin="1" Padding="5,2,5,0" Content="{DynamicResource GlobalSettings_EmailTestButtonLabel}" Click="SendTestEmail_Click" HorizontalAlignment="Right"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="20" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailNotifySettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoBackupLabel}" IsChecked="{Binding Config.EmailNotify_AutoBackup}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoBackupTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateLabel}" IsChecked="{Binding Config.EmailNotify_AutoUpdate}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoRestartLabel}" IsChecked="{Binding Config.EmailNotify_AutoRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoRestartTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="3" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartLabel}" IsChecked="{Binding Config.EmailNotify_ShutdownRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartTooltip}" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="21" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_AdvancedSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Text="{DynamicResource GlobalSettings_AdvancedSettingsInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UseShutdownCommandLabel}" IsChecked="{Binding Config.ServerShutdown_UseShutdownCommand}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UseShutdownCommandTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_BackupWorldFileLabel}" IsChecked="{Binding Config.BackupWorldFile, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_BackupWorldFileTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedLabel}" IsChecked="{Binding Config.CloseShutdownWindowWhenFinished, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_VerifyServerAfterUpdateLabel}" IsChecked="{Binding Config.AutoUpdate_VerifyServerAfterUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_VerifyServerAfterUpdateTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_SteamCmdRemoveQuitLabel}" IsChecked="{Binding CommonConfig.SteamCmdRemoveQuit, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRemoveQuitTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsLabel}" IsChecked="{Binding Config.UpdateDirectoryPermissions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Margin="1" Label="{DynamicResource GlobalSettings_WorldSaveDelayLabel}" Value="{Binding Config.ServerShutdown_WorldSaveDelay, Converter={cc:IntRangeValueConverter 10, 300}}" Minimum="10" Maximum="300" SmallChange="10" LargeChange="50" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_WorldSaveDelayTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
375
src/ConanServerManager/Windows/GlobalSettingsControl.xaml.cs
Normal file
375
src/ConanServerManager/Windows/GlobalSettingsControl.xaml.cs
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Xml;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for GlobalSettingsControl.xaml
|
||||
/// </summary>
|
||||
public partial class GlobalSettingsControl : UserControl
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(GlobalSettingsControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IsAdministratorProperty = DependencyProperty.Register(nameof(IsAdministrator), typeof(bool), typeof(GlobalSettingsControl), new PropertyMetadata(false));
|
||||
|
||||
public GlobalSettingsControl()
|
||||
{
|
||||
this.AppInstance = App.Instance;
|
||||
this.Config = Config.Default;
|
||||
this.CommonConfig = CommonConfig.Default;
|
||||
this.IsAdministrator = SecurityUtils.IsAdministrator();
|
||||
this.Version = GetDeployedVersion();
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public App AppInstance
|
||||
{
|
||||
get { return GetValue(AppInstanceProperty) as App; }
|
||||
set { SetValue(AppInstanceProperty, value); }
|
||||
}
|
||||
|
||||
public Config Config
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public CommonConfig CommonConfig
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsAdministrator
|
||||
{
|
||||
get { return (bool)GetValue(IsAdministratorProperty); }
|
||||
set { SetValue(IsAdministratorProperty, value); }
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private string GetDeployedVersion()
|
||||
{
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
Assembly asmCurrent = System.Reflection.Assembly.GetEntryAssembly();
|
||||
string executePath = new Uri(asmCurrent.GetName().CodeBase).LocalPath;
|
||||
|
||||
xmlDoc.Load(executePath + ".manifest");
|
||||
XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
|
||||
ns.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1");
|
||||
string xPath = "/asmv1:assembly/asmv1:assemblyIdentity/@version";
|
||||
XmlNode node = xmlDoc.SelectSingleNode(xPath, ns);
|
||||
string version = node.Value;
|
||||
return version;
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
Window.GetWindow(this)?.Activate();
|
||||
}
|
||||
|
||||
private void ApplySteamAPIKey_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(CommonConfig.Default.SteamAPIKeyUrl);
|
||||
}
|
||||
|
||||
private async void SendTestEmail_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var email = new EmailUtil()
|
||||
{
|
||||
EnableSsl = Config.Default.Email_UseSSL,
|
||||
MailServer = Config.Default.Email_Host,
|
||||
Port = Config.Default.Email_Port,
|
||||
UseDefaultCredentials = Config.Default.Email_UseDetaultCredentials,
|
||||
Credentials = Config.Default.Email_UseDetaultCredentials ? null : new System.Net.NetworkCredential(Config.Default.Email_Username, Config.Default.Email_Password),
|
||||
};
|
||||
|
||||
email.SendEmail(Config.Default.Email_From, Config.Default.Email_To?.Split(','), "Server Manager Test Email", "This is a test email sent from the server manager settings window.", true);
|
||||
|
||||
});
|
||||
MessageBox.Show("Test email sent.", "Send Email Confirmation", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = ex.Message;
|
||||
if (ex.InnerException != null)
|
||||
message += $"\r\n{ex.InnerException.Message}";
|
||||
MessageBox.Show(message, "Send Email Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDataDir_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var optionResult = MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_DataDirectoryChange_ConfirmLabel"), _globalizer.GetResourceString("GlobalSettings_DataDirectoryChange_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (optionResult == MessageBoxResult.Yes)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog();
|
||||
dialog.IsFolderPicker = true;
|
||||
dialog.Title = _globalizer.GetResourceString("Application_DataDirectoryTitle");
|
||||
dialog.InitialDirectory = Config.Default.DataPath;
|
||||
var result = dialog.ShowDialog(Window.GetWindow(this));
|
||||
|
||||
if (result == CommonFileDialogResult.Ok)
|
||||
{
|
||||
if (!String.Equals(dialog.FileName, Config.Default.DataPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set up the destination directories
|
||||
string newConfigDirectory = Path.Combine(dialog.FileName, Config.Default.ProfilesRelativePath);
|
||||
string oldSteamDirectory = Path.Combine(Config.Default.DataPath, CommonConfig.Default.SteamCmdRelativePath);
|
||||
string newSteamDirectory = Path.Combine(dialog.FileName, CommonConfig.Default.SteamCmdRelativePath);
|
||||
|
||||
Directory.CreateDirectory(newConfigDirectory);
|
||||
Directory.CreateDirectory(newSteamDirectory);
|
||||
|
||||
// Copy the Profiles
|
||||
foreach (var file in Directory.EnumerateFiles(Config.Default.ConfigPath, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
string sourceWithoutRoot = file.Substring(Config.Default.ConfigPath.Length + 1);
|
||||
string destination = Path.Combine(newConfigDirectory, sourceWithoutRoot);
|
||||
if (!File.Exists(destination))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destination));
|
||||
File.Copy(file, destination);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the SteamCMD files
|
||||
foreach (var file in Directory.EnumerateFiles(oldSteamDirectory, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
string sourceWithoutRoot = file.Substring(oldSteamDirectory.Length + 1);
|
||||
string destination = Path.Combine(newSteamDirectory, sourceWithoutRoot);
|
||||
if (!File.Exists(destination))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destination));
|
||||
File.Copy(file, destination);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the old directories
|
||||
Directory.Delete(Config.Default.ConfigPath, true);
|
||||
Directory.Delete(oldSteamDirectory, true);
|
||||
|
||||
// Update the config
|
||||
Config.Default.DataPath = dialog.FileName;
|
||||
Config.Default.ConfigPath = newConfigDirectory;
|
||||
App.ReconfigureLogging();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("GlobalSettings_DataDirectoryChange_FailedLabel"), ex.Message), _globalizer.GetResourceString("GlobalSettings_DataDirectoryChange_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBackupDir_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog();
|
||||
dialog.IsFolderPicker = true;
|
||||
dialog.Title = _globalizer.GetResourceString("GlobalSettings_DataDirectoryTitle");
|
||||
dialog.InitialDirectory = Config.Default.BackupPath;
|
||||
var result = dialog.ShowDialog(Window.GetWindow(this));
|
||||
|
||||
if (result == CommonFileDialogResult.Ok)
|
||||
{
|
||||
if (!String.Equals(dialog.FileName, Config.Default.BackupPath))
|
||||
{
|
||||
Config.Default.BackupPath = dialog.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearBackupDir_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Config.Default.BackupPath = string.Empty;
|
||||
}
|
||||
|
||||
private void SetCacheDir_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog();
|
||||
dialog.IsFolderPicker = true;
|
||||
dialog.Title = _globalizer.GetResourceString("GlobalSettings_CacheDirectoryTitle");
|
||||
dialog.InitialDirectory = Config.Default.DataPath;
|
||||
var result = dialog.ShowDialog(Window.GetWindow(this));
|
||||
|
||||
if (result == CommonFileDialogResult.Ok)
|
||||
{
|
||||
if (!String.Equals(dialog.FileName, Config.Default.AutoUpdate_CacheDir))
|
||||
{
|
||||
Config.Default.AutoUpdate_CacheDir = dialog.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SteamAPIKeyHelp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.SteamWebAPIKeyHelpUrl);
|
||||
}
|
||||
|
||||
private async void SteamCMDAuthenticate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.SteamCmd_Username))
|
||||
{
|
||||
MessageBox.Show("A steam username has not be entered.", "SteamCMD Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var steamCmdFile = SteamCmdUpdater.GetSteamCmdFile(Config.Default.DataPath);
|
||||
if (string.IsNullOrWhiteSpace(steamCmdFile) || !File.Exists(steamCmdFile))
|
||||
{
|
||||
MessageBox.Show("Could not locate the SteamCMD executable. Try reinstalling SteamCMD.", "SteamCMD Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
var steamCmdArgs = SteamUtils.BuildSteamCmdArguments(CommonConfig.Default.SteamCmdRemoveQuit, CommonConfig.Default.SteamCmdAuthenticateArgs, Config.Default.SteamCmd_Username, Config.Default.SteamCmd_Password);
|
||||
var workingDirectory = Config.Default.DataPath;
|
||||
|
||||
var result = await ProcessUtils.RunProcessAsync(steamCmdFile, steamCmdArgs, string.Empty, workingDirectory, null, null, null, CancellationToken.None);
|
||||
if (result)
|
||||
MessageBox.Show("The authentication was completed.", "SteamCMD Authentication", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
else
|
||||
MessageBox.Show("An error occurred while trying to authenticate with steam. Please try again.", "SteamCMD Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "SteamCMD Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void LanguageSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Config.CultureName = AvailableLanguages.Instance.SelectedLanguage;
|
||||
}
|
||||
|
||||
private void StyleSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Config.StyleName = AvailableStyles.Instance.SelectedStyle;
|
||||
}
|
||||
|
||||
private void HiddenField_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is TextBox hideTextBox)
|
||||
{
|
||||
TextBox textBox = null;
|
||||
if (Equals(hideTextBox, HideSteamPasswordTextBox))
|
||||
textBox = SteamPasswordTextBox;
|
||||
if (Equals(hideTextBox, HideSteamAPIKeyTextBox))
|
||||
textBox = SteamAPIKeyTextBox;
|
||||
if (Equals(hideTextBox, HideEmailPasswordTextBox))
|
||||
textBox = EmailPasswordTextBox;
|
||||
|
||||
if (textBox != null)
|
||||
{
|
||||
textBox.Visibility = System.Windows.Visibility.Visible;
|
||||
hideTextBox.Visibility = System.Windows.Visibility.Collapsed;
|
||||
textBox.Focus();
|
||||
}
|
||||
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void HiddenField_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is TextBox textBox)
|
||||
{
|
||||
TextBox hideTextBox = null;
|
||||
if (textBox == SteamPasswordTextBox)
|
||||
hideTextBox = HideSteamPasswordTextBox;
|
||||
if (textBox == SteamAPIKeyTextBox)
|
||||
hideTextBox = HideSteamAPIKeyTextBox;
|
||||
if (textBox == EmailPasswordTextBox)
|
||||
hideTextBox = HideEmailPasswordTextBox;
|
||||
|
||||
if (hideTextBox != null)
|
||||
{
|
||||
hideTextBox.Visibility = System.Windows.Visibility.Visible;
|
||||
textBox.Visibility = System.Windows.Visibility.Collapsed;
|
||||
}
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetSettings_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_ResetSettings_ConfirmLabel"), _globalizer.GetResourceString("GlobalSettings_ResetSettings_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
Config.Default.Reset();
|
||||
Config.Default.UpgradeConfig = false;
|
||||
Config.Default.Save();
|
||||
Config.Default.Reload();
|
||||
|
||||
CommonConfig.Default.Reset();
|
||||
CommonConfig.Default.UpgradeConfig = false;
|
||||
CommonConfig.Default.Save();
|
||||
CommonConfig.Default.Reload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Exception while resettiing the settings: {0}\n{1}", ex.Message, ex.StackTrace);
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_ResetSettings_FailedLabel"), _globalizer.GetResourceString("GlobalSettings_ResetSettings_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
exitCode = 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
App.Current.Shutdown(exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
src/ConanServerManager/Windows/GuildProfileWindow.xaml
Normal file
100
src/ConanServerManager/Windows/GuildProfileWindow.xaml
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<Window x:Class="ServerManagerTool.GuildProfileWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
Width="600" ResizeMode="NoResize" SizeToContent="Height" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Icon="../Art/favicon.ico" Title="{Binding WindowTitle}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:UnixTimeToDateTimeConverter x:Key="UnixTimeToDateTimeConverter"/>
|
||||
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
</Style>
|
||||
<Style x:Key="OnlineListViewItemStyle" TargetType="{x:Type ListViewItem}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOnline}" Value="True">
|
||||
<Setter Property="Foreground" Value="Green"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Margin="3" CanVerticallyScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Profile_NameLabel}" VerticalAlignment="Center"/>
|
||||
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Player.GuildName}" VerticalAlignment="Center" FontWeight="Bold" FontSize="13.333"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox HorizontalAlignment="Stretch" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{DynamicResource Profile_TribeSectionLabel}" VerticalAlignment="Center" FontWeight="Bold" FontSize="13.333"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Profile_IdLabel}"/>
|
||||
<Label Grid.Row="0" Grid.Column="1" Content="{Binding GuildData.GuildId}"/>
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Profile_TribeOwnerLabel}"/>
|
||||
<Label Grid.Row="1" Grid.Column="1" Content="{Binding GuildOwner}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox HorizontalAlignment="Stretch" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{DynamicResource Profile_TribeMembersSectionLabel}" VerticalAlignment="Center" FontWeight="Bold" FontSize="13.333"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<ListView x:Name="GuildMembersListView" ItemsSource="{Binding GuildPlayers}" Height="200" HorizontalContentAlignment="Stretch" ItemContainerStyle="{DynamicResource OnlineListViewItemStyle}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{DynamicResource Profile_CharacterNameColumnLabel}" Width="Auto" DisplayMemberBinding="{Binding PlayerData.CharacterName}"/>
|
||||
<GridViewColumn Header="{DynamicResource Profile_LevelColumnLabel}" Width="Auto" DisplayMemberBinding="{Binding PlayerData.Level}"/>
|
||||
<GridViewColumn Header="{DynamicResource Profile_OnlineColumnLabel}" Width="Auto" DisplayMemberBinding="{Binding IsOnline}"/>
|
||||
<GridViewColumn Header="{DynamicResource Profile_LastOnlineColumnLabel}" Width="Auto" DisplayMemberBinding="{Binding LastOnline, Converter={StaticResource UnixTimeToDateTimeConverter}}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
91
src/ConanServerManager/Windows/GuildProfileWindow.xaml.cs
Normal file
91
src/ConanServerManager/Windows/GuildProfileWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
using ConanData;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for GuildProfileWindow.xaml
|
||||
/// </summary>
|
||||
public partial class GuildProfileWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public GuildProfileWindow(PlayerInfo player, ICollection<PlayerInfo> players, String serverFolder)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.Player = player;
|
||||
this.Players = players;
|
||||
this.ServerFolder = serverFolder;
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public PlayerInfo Player
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ICollection<PlayerInfo> Players
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public String ServerFolder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public PlayerData PlayerData => Player?.PlayerData;
|
||||
|
||||
public GuildData GuildData => Player?.PlayerData?.Guild;
|
||||
|
||||
public String GuildOwner => GuildData != null && GuildData.Owner != null ? $"{GuildData.Owner.CharacterName}" : null;
|
||||
|
||||
public ICollection<PlayerInfo> GuildPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GuildData == null) return null;
|
||||
|
||||
ICollection<PlayerInfo> players = new List<PlayerInfo>();
|
||||
foreach (var guildPlayer in GuildData.Players)
|
||||
{
|
||||
var player = Players.FirstOrDefault(p => p.PlayerId.ToString() == guildPlayer.PlayerId);
|
||||
if (player != null)
|
||||
players.Add(player);
|
||||
}
|
||||
return players;
|
||||
}
|
||||
}
|
||||
|
||||
public String WindowTitle => String.Format(_globalizer.GetResourceString("Profile_WindowTitle_Tribe"), Player.GuildName);
|
||||
|
||||
public ICommand ExplorerLinkCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<String>(
|
||||
execute: (action) =>
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(action)) return;
|
||||
Process.Start("explorer.exe", action);
|
||||
},
|
||||
canExecute: (action) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
521
src/ConanServerManager/Windows/MainWindow.xaml
Normal file
521
src/ConanServerManager/Windows/MainWindow.xaml
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
<Window x:Class="ServerManagerTool.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:eo="http://schemas.essentialobjects.com/wpf/"
|
||||
xmlns:sm="clr-namespace:ServerManagerTool"
|
||||
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:cvr="clr-namespace:ServerManagerTool.Common.ValidationRules;assembly=ServerManager.Common"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:tsk="clr-namespace:Microsoft.Win32.TaskScheduler;assembly=Microsoft.Win32.TaskScheduler"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50"
|
||||
Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged"
|
||||
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
|
||||
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<cc:HasStringValueConverter x:Key="HasStringValueConverter"/>
|
||||
|
||||
<Style x:Key="ButtonStyle1" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Background" Value="#00ffffff"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Width" Value="22"/>
|
||||
<Setter Property="Height" Value="22"/>
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
<Style x:Key="ButtonStyle2" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Width" Value="22"/>
|
||||
<Setter Property="Height" Value="22"/>
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
<Style x:Key="ButtonStyle3" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Background" Value="#00ffffff"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Height" Value="22"/>
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
<Style x:Key="ButtonStyle5" TargetType="Button" BasedOn="{StaticResource ButtonStyle1}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border CornerRadius="15" Background="{TemplateBinding Background}" BorderThickness="1">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="Red"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<DockPanel x:Name="dockPanel">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel Grid.Row="0" LastChildFill="False">
|
||||
<DockPanel.Style>
|
||||
<Style TargetType="{x:Type DockPanel}">
|
||||
<Setter Property="Background" Value="#4F4F4F"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AppInstance.BetaVersion}" Value="True">
|
||||
<Setter Property="Background" Value="#378CFB"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DockPanel.Style>
|
||||
|
||||
<Grid DockPanel.Dock="Left">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0" Background="Transparent" Foreground="White" FontSize="20" FontWeight="Bold" Margin="5,0,5,0" Content="{DynamicResource MainWindow_Label}" BorderThickness="0"/>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal">
|
||||
<Label Margin="5,0,0,0" Background="Transparent" Foreground="White" FontSize="12" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_VersionLabel}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AppInstance.BetaVersion}" Value="True">
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_BetaVersionLabel}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
<Label Margin="5,0,0,0" Background="Transparent" Foreground="White" FontSize="12" Content="{Binding Source={x:Static sm:App.Instance}, Path=Version}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
|
||||
<Button Margin="5" Click="PatchNotes_Click" ToolTip="{DynamicResource ServerSettings_PatchNotesTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/ChangeNotes.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Margin="5,0,0,0" Background="#00AA00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" ContentStringFormat="{DynamicResource MainWindow_UpdateToLabelFormat}" Content="{Binding LatestServerManagerVersion}" Click="Upgrade_Click" VerticalAlignment="Center" >
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding NewServerManagerAvailable}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding NewServerManagerAvailable}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid DockPanel.Dock="Right" VerticalAlignment="Top" Margin="5" MinWidth="130">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MinHeight="22"/>
|
||||
<RowDefinition MinHeight="22"/>
|
||||
<RowDefinition MinHeight="22"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
<ColumnDefinition MinWidth="25"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="4" Margin="5,2,0,0" Grid.ColumnSpan="3" Click="Donate_Click" ToolTip="{DynamicResource MainWindow_DonateTooltip}" Style="{StaticResource ButtonStyle3}">
|
||||
<Image Source="../Art/Donate.png"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="2" Grid.Column="0" Margin="5,0,0,0" Click="ServerMonitor_Click" ToolTip="{DynamicResource MainWindow_OpenServerMonitorTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Servers.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="1" Margin="5,0,0,0" HorizontalAlignment="Right" Click="GameData_Click" ToolTip="{DynamicResource MainWindow_OpenGameDataTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Document.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="2" Margin="5,0,0,0" Click="Plugins_Click" ToolTip="{DynamicResource MainWindow_OpenPluginsTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Plugin.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="3" Margin="5,0,0,0" Click="OpenLogFolder_Click" ToolTip="{DynamicResource MainWindow_OpenLogFolderTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Logs.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="4" Margin="5,0,0,0" Click="SteamCMD_Click" ToolTip="{DynamicResource MainWindow_SteamCMDTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Steam.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="5" Margin="5,0,0,0" Click="Settings_Click" ToolTip="{DynamicResource MainWindow_OpenSettingsTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Settings.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Grid.Row="2" Grid.Column="6" Margin="5,0,0,0" Click="Help_Click" ToolTip="{DynamicResource MainWindow_OpenHelpTooltip}" Style="{StaticResource ButtonStyle1}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Help.ico,Size=32}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid DockPanel.Dock="Right" VerticalAlignment="Top" Margin="10,0,10,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Margin="0,-2,0,-3" Background="Transparent" Foreground="White" FontSize="11" Content="{DynamicResource MainWindow_TaskStatusLabel}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="5,0,0,0">
|
||||
<Label Margin="0" Background="Transparent" Foreground="White" FontSize="10" Content="{DynamicResource MainWindow_AutoBackupTaskLabel}" VerticalAlignment="Center" HorizontalAlignment="Left" ToolTip="{Binding AutoBackupNextRunTime}" ToolTipService.IsEnabled="{Binding AutoBackupNextRunTime, Converter={StaticResource HasStringValueConverter}}"/>
|
||||
<Label Margin="0" Background="Transparent" FontSize="10" Content="{Binding AutoBackupStateString}" VerticalAlignment="Center" HorizontalAlignment="Left" ToolTip="{Binding AutoBackupNextRunTime}" ToolTipService.IsEnabled="{Binding AutoBackupNextRunTime, Converter={StaticResource HasStringValueConverter}}">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Disabled}">
|
||||
<Setter Property="Foreground" Value="DarkRed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Ready}">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Running}">
|
||||
<Setter Property="Foreground" Value="LightGreen"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
<Button Margin="5,0,0,0" Background="#00AA00" Foreground="White" Padding="1" Content="{DynamicResource MainWindow_AutoBackupTaskRunLabel}" BorderThickness="1" BorderBrush="White" Click="AutoBackupTaskRun_Click" VerticalAlignment="Center" ToolTip="{DynamicResource MainWindow_AutoBackupTaskRunTooltip}">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Ready}">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Margin="5,0,0,0" Background="#AA8A00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" Click="AutoBackupTaskState_Click" VerticalAlignment="Center">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoBackupTaskEnableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoBackupTaskEnableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Disabled}"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoBackupTaskEnableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoBackupTaskEnableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding AutoBackupState}" Value="{x:Static tsk:TaskState.Ready}"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoBackupTaskDisableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoBackupTaskDisableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Center" Margin="5,0,0,0">
|
||||
<Label Margin="0" Background="Transparent" Foreground="White" FontSize="10" Content="{DynamicResource MainWindow_AutoUpdateTaskLabel}" VerticalAlignment="Center" HorizontalAlignment="Left" ToolTip="{Binding AutoUpdateNextRunTime}" ToolTipService.IsEnabled="{Binding AutoUpdateNextRunTime, Converter={StaticResource HasStringValueConverter}}"/>
|
||||
<Label Margin="0" Background="Transparent" FontSize="10" Content="{Binding AutoUpdateStateString}" VerticalAlignment="Center" HorizontalAlignment="Left" ToolTip="{Binding AutoUpdateNextRunTime}" ToolTipService.IsEnabled="{Binding AutoUpdateNextRunTime, Converter={StaticResource HasStringValueConverter}}">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Disabled}">
|
||||
<Setter Property="Foreground" Value="DarkRed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Ready}">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Running}">
|
||||
<Setter Property="Foreground" Value="LightGreen"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
<Button Margin="5,0,0,0" Background="#00AA00" Foreground="White" Padding="1" Content="{DynamicResource MainWindow_AutoUpdateTaskRunLabel}" BorderThickness="1" BorderBrush="White" Click="AutoUpdateTaskRun_Click" VerticalAlignment="Center" ToolTip="{DynamicResource MainWindow_AutoUpdateTaskRunTooltip}">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Ready}">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Margin="5,0,0,0" Background="#AA8A00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" Click="AutoUpdateTaskState_Click" VerticalAlignment="Center">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoUpdateTaskEnableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoUpdateTaskEnableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Disabled}"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoUpdateTaskEnableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoUpdateTaskEnableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding AutoUpdateState}" Value="{x:Static tsk:TaskState.Ready}"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Content" Value="{DynamicResource MainWindow_AutoUpdateTaskDisableLabel}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_AutoUpdateTaskDisableTooltip}"/>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid DockPanel.Dock="Top" VerticalAlignment="Top" Margin="10,0,10,0" HorizontalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0" Margin="0" Background="Transparent" Foreground="White" FontSize="11" Content="{DynamicResource MainWindow_MyIpLabel}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="5,0,0,0">
|
||||
<TextBox FontSize="12" Height="22" Width="120" VerticalAlignment="Bottom" Margin="0" VerticalContentAlignment="Center" ToolTip="{DynamicResource MainWindow_MyIpTooltip}">
|
||||
<Validation.ErrorTemplate>
|
||||
<ControlTemplate>
|
||||
<StackPanel>
|
||||
<!-- Placeholder for the TextBox itself -->
|
||||
<AdornedElementPlaceholder x:Name="textBox"/>
|
||||
<TextBlock Text="{DynamicResource MainWindow_MyIpError}" Background="Red" Foreground="White"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Validation.ErrorTemplate>
|
||||
<TextBox.Text>
|
||||
<Binding Path="Config.MachinePublicIP" ElementName="Main">
|
||||
<Binding.ValidationRules>
|
||||
<cvr:IpValidationRule ValidatesOnTargetUpdated="true" />
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
<Button Grid.Row="1" Margin="5,0,0,0" Click="RefreshPublicIP_Click" ToolTip="{DynamicResource MainWindow_RefreshMyIpTooltip}" Style="{StaticResource ButtonStyle2}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Reload.ico,Size=32}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
|
||||
<eo:TabControl Name="Tabs" Grid.Row ="1" Margin="0,5,0,0" ShowCloseTabButton="True" ShowNewTabButton="True" NewItemRequested="Servers_AddNew" PreviewItemClose="Servers_Remove" ItemsSource="{Binding ServerManager.Servers}">
|
||||
<eo:TabControl.HeaderTemplate>
|
||||
<DataTemplate >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Grid.Row="0" Grid.Column="4" Margin="5,0,0,0" Command="{Binding StatusButtonCommand, ElementName=Main}" CommandParameter="{Binding}">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource ButtonStyle5}" TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUnknownLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusInitializingLabel}"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}"/>
|
||||
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusRunningLabel}"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}"/>
|
||||
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusRunningLabel}"/>
|
||||
</MultiDataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppingLabel}"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}"/>
|
||||
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppedLabel}"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}"/>
|
||||
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppedLabel}"/>
|
||||
</MultiDataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUnknownLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUpdatingLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUninstalledLabel}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image Margin="0,2" VerticalAlignment="Center" Width="16" Height="16">
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusUnknown.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUnknownLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusStarting.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusInitializingLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusOn.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusRunningLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusOn.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppingLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusOff.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppedLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusUnknown.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUnknownLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUpdatingLabel}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/StatusUnknown.ico,Size=32}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusUninstalledLabel}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
</Button>
|
||||
<TextBlock Margin="2" VerticalAlignment="Center" Text="{Binding Profile.ProfileName}" ToolTip="{Binding Profile.ProfileToolTip}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</eo:TabControl.HeaderTemplate>
|
||||
<eo:TabControl.NewTabButtonStyle>
|
||||
<Style TargetType="eo:BareButton">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Border BorderBrush="#8C8E94" BorderThickness="1,1,1,0" Padding="3,0">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<LinearGradientBrush.GradientStops>
|
||||
<GradientStop Offset="0" Color="#F3F3F3" />
|
||||
<GradientStop Offset="0.5" Color="#EBEBEB" />
|
||||
<GradientStop Offset="0.5" Color="#DDDDDD" />
|
||||
<GradientStop Offset="1" Color="#CDCDCD" />
|
||||
</LinearGradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
<Image Margin="0,2" VerticalAlignment="Center" Source="{com:Icon Path=/ConanServerManager;component/Art/Add.ico,Size=32}" Width="16" Height="16" ToolTip="{DynamicResource MainWindow_NewProfileTooltip}"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</eo:TabControl.NewTabButtonStyle>
|
||||
<eo:TabControl.CloseTabButtonStyle>
|
||||
<Style TargetType="eo:BareButton">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Image Margin="0,2" VerticalAlignment="Center" Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}" Width="16" Height="16" ToolTip="{DynamicResource MainWindow_CloseProfileTooltip}"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</eo:TabControl.CloseTabButtonStyle>
|
||||
<eo:TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<sm:ServerSettingsControl Server="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</eo:TabControl.ContentTemplate>
|
||||
</eo:TabControl>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
|
||||
<!-- It's important that this is in the end of the XAML as it needs to be on top of everything else! -->
|
||||
<Grid x:Name="OverlayGrid" Visibility="Collapsed" DockPanel.Dock="Top" >
|
||||
<Grid Background="Black" Opacity="0.5"/>
|
||||
<Border MinWidth="250" Background="Orange" BorderBrush="Black" BorderThickness="1" CornerRadius="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel>
|
||||
<Label x:Name="OverlayMessage" Margin="5" FontWeight="Bold" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<tb:TaskbarIcon
|
||||
Visibility="Visible"
|
||||
ToolTipText="{Binding Title}"
|
||||
IconSource="../Art/favicon.ico"
|
||||
LeftClickCommand="{Binding ShowWindowCommand, ElementName=Main}"
|
||||
MenuActivation="RightClick">
|
||||
|
||||
<tb:TaskbarIcon.Resources>
|
||||
<clib:BindingProxy x:Key="proxy" Data="{Binding ElementName=Main}"/>
|
||||
</tb:TaskbarIcon.Resources>
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{DynamicResource Application_NotifyIcon_ShowMainWindow}" Command="{Binding Source={StaticResource proxy}, Path=Data.ShowWindowCommand}" />
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
|
||||
</tb:TaskbarIcon>
|
||||
</Grid>
|
||||
</Window>
|
||||
763
src/ConanServerManager/Windows/MainWindow.xaml.cs
Normal file
763
src/ConanServerManager/Windows/MainWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
using EO.Wpf;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly ActionQueue versionChecker;
|
||||
private readonly ActionQueue scheduledTaskChecker;
|
||||
|
||||
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(MainWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(MainWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ServerManagerProperty = DependencyProperty.Register(nameof(ServerManager), typeof(ServerManager), typeof(MainWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty AutoBackupStateProperty = DependencyProperty.Register(nameof(AutoBackupState), typeof(Microsoft.Win32.TaskScheduler.TaskState), typeof(MainWindow), new PropertyMetadata(Microsoft.Win32.TaskScheduler.TaskState.Unknown));
|
||||
public static readonly DependencyProperty AutoBackupStateStringProperty = DependencyProperty.Register(nameof(AutoBackupStateString), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty AutoBackupNextRunTimeProperty = DependencyProperty.Register(nameof(AutoBackupNextRunTime), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty AutoUpdateStateProperty = DependencyProperty.Register(nameof(AutoUpdateState), typeof(Microsoft.Win32.TaskScheduler.TaskState), typeof(MainWindow), new PropertyMetadata(Microsoft.Win32.TaskScheduler.TaskState.Unknown));
|
||||
public static readonly DependencyProperty AutoUpdateStateStringProperty = DependencyProperty.Register(nameof(AutoUpdateStateString), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty AutoUpdateNextRunTimeProperty = DependencyProperty.Register(nameof(AutoUpdateNextRunTime), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IsIpValidProperty = DependencyProperty.Register(nameof(IsIpValid), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty LatestServerManagerVersionProperty = DependencyProperty.Register(nameof(LatestServerManagerVersion), typeof(Version), typeof(MainWindow), new PropertyMetadata(new Version()));
|
||||
public static readonly DependencyProperty NewServerManagerAvailableProperty = DependencyProperty.Register(nameof(NewServerManagerAvailable), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
|
||||
|
||||
public App AppInstance
|
||||
{
|
||||
get { return GetValue(AppInstanceProperty) as App; }
|
||||
set { SetValue(AppInstanceProperty, value); }
|
||||
}
|
||||
|
||||
public Config Config
|
||||
{
|
||||
get { return GetValue(ConfigProperty) as Config; }
|
||||
set { SetValue(ConfigProperty, value); }
|
||||
}
|
||||
|
||||
public ServerManager ServerManager
|
||||
{
|
||||
get { return (ServerManager)GetValue(ServerManagerProperty); }
|
||||
set { SetValue(ServerManagerProperty, value); }
|
||||
}
|
||||
|
||||
public Microsoft.Win32.TaskScheduler.TaskState AutoBackupState
|
||||
{
|
||||
get { return (Microsoft.Win32.TaskScheduler.TaskState)GetValue(AutoBackupStateProperty); }
|
||||
set { SetValue(AutoBackupStateProperty, value); }
|
||||
}
|
||||
|
||||
public string AutoBackupStateString
|
||||
{
|
||||
get { return (string)GetValue(AutoBackupStateStringProperty); }
|
||||
set { SetValue(AutoBackupStateStringProperty, value); }
|
||||
}
|
||||
|
||||
public string AutoBackupNextRunTime
|
||||
{
|
||||
get { return (string)GetValue(AutoBackupNextRunTimeProperty); }
|
||||
set { SetValue(AutoBackupNextRunTimeProperty, value); }
|
||||
}
|
||||
|
||||
public Microsoft.Win32.TaskScheduler.TaskState AutoUpdateState
|
||||
{
|
||||
get { return (Microsoft.Win32.TaskScheduler.TaskState)GetValue(AutoUpdateStateProperty); }
|
||||
set { SetValue(AutoUpdateStateProperty, value); }
|
||||
}
|
||||
|
||||
public string AutoUpdateStateString
|
||||
{
|
||||
get { return (string)GetValue(AutoUpdateStateStringProperty); }
|
||||
set { SetValue(AutoUpdateStateStringProperty, value); }
|
||||
}
|
||||
|
||||
public string AutoUpdateNextRunTime
|
||||
{
|
||||
get { return (string)GetValue(AutoUpdateNextRunTimeProperty); }
|
||||
set { SetValue(AutoUpdateNextRunTimeProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsAdministrator
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsIpValid
|
||||
{
|
||||
get { return (bool)GetValue(IsIpValidProperty); }
|
||||
set { SetValue(IsIpValidProperty, value); }
|
||||
}
|
||||
|
||||
public Version LatestServerManagerVersion
|
||||
{
|
||||
get { return (Version)GetValue(LatestServerManagerVersionProperty); }
|
||||
set { SetValue(LatestServerManagerVersionProperty, value); }
|
||||
}
|
||||
|
||||
public bool NewServerManagerAvailable
|
||||
{
|
||||
get { return (bool)GetValue(NewServerManagerAvailableProperty); }
|
||||
set { SetValue(NewServerManagerAvailableProperty, value); }
|
||||
}
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
this.AppInstance = App.Instance;
|
||||
this.Config = Config.Default;
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.ServerManager = ServerManager.Instance;
|
||||
|
||||
this.DataContext = this;
|
||||
this.versionChecker = new ActionQueue();
|
||||
this.scheduledTaskChecker = new ActionQueue();
|
||||
|
||||
IsAdministrator = SecurityUtils.IsAdministrator();
|
||||
if (!string.IsNullOrWhiteSpace(App.Instance.Title))
|
||||
{
|
||||
this.Title = App.Instance.Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsAdministrator)
|
||||
{
|
||||
this.Title = _globalizer.GetResourceString("MainWindow_TitleWithAdmin");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Title = _globalizer.GetResourceString("MainWindow_Title");
|
||||
}
|
||||
}
|
||||
|
||||
this.Height = Config.Default.MainWindow_Height;
|
||||
this.Width = Config.Default.MainWindow_Width;
|
||||
|
||||
// hook into the language change event
|
||||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//
|
||||
// Kick off the initialization.
|
||||
//
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
// We need to load the set of existing servers, or create a blank one if we don't have any...
|
||||
foreach (var profile in Directory.EnumerateFiles(Config.Default.ConfigPath, "*" + Config.Default.ProfileExtension))
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerManager.Instance.AddFromPath(profile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_ProfileLoad_FailedLabel"), profile, ex.Message, ex.StackTrace), _globalizer.GetResourceString("MainWindow_ProfileLoad_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
}
|
||||
}
|
||||
|
||||
ServerManager.Instance.SortServers();
|
||||
ServerManager.Instance.CheckProfiles();
|
||||
|
||||
Tabs.SelectedIndex = 0;
|
||||
}).DoNotWait();
|
||||
|
||||
this.versionChecker.PostAction(CheckForUpdates).DoNotWait();
|
||||
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
window.Closed -= Window_Closed;
|
||||
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState != WindowState.Minimized)
|
||||
{
|
||||
Config.Default.MainWindow_Height = e.NewSize.Height;
|
||||
Config.Default.MainWindow_Width = e.NewSize.Width;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
base.OnClosing(e);
|
||||
RconWindow.CloseAllWindows();
|
||||
PlayerListWindow.CloseAllWindows();
|
||||
ServerMonitorWindow.CloseAllWindows();
|
||||
this.versionChecker.DisposeAsync().DoNotWait();
|
||||
|
||||
var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
var backupFolder = IOUtils.NormalizePath(string.IsNullOrWhiteSpace(Config.Default.BackupPath)
|
||||
? Path.Combine(Config.Default.DataPath, Config.Default.BackupRelativePath)
|
||||
: Path.Combine(Config.Default.BackupPath));
|
||||
SettingsUtils.BackupUserConfigSettings(Config.Default, "userconfig.json", installFolder, backupFolder);
|
||||
SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder);
|
||||
}
|
||||
|
||||
private void ResourceDictionaryChangedEvent(object source, ResourceDictionaryChangedEventArgs e)
|
||||
{
|
||||
if (IsAdministrator)
|
||||
this.Title = _globalizer.GetResourceString("MainWindow_TitleWithAdmin");
|
||||
else
|
||||
this.Title = _globalizer.GetResourceString("MainWindow_Title");
|
||||
|
||||
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
|
||||
}
|
||||
|
||||
private void PatchNotes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var url = string.Empty;
|
||||
if (AppInstance.BetaVersion)
|
||||
url = Config.Default.ServerManagerVersionBetaFeedUrl;
|
||||
else
|
||||
url = Config.Default.ServerManagerVersionFeedUrl;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
var window = new VersionFeedWindow(url);
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppInstance.BetaVersion)
|
||||
url = Config.Default.LatestServerManagerBetaPatchNotesUrl;
|
||||
else
|
||||
url = Config.Default.LatestServerManagerPatchNotesUrl;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return;
|
||||
|
||||
Process.Start(url);
|
||||
}
|
||||
}
|
||||
|
||||
private void Donate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.DonationUrl))
|
||||
return;
|
||||
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_Donate_Label"), _globalizer.GetResourceString("MainWindow_Donate_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
Process.Start(Config.DonationUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private void Help_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.HelpUrl))
|
||||
return;
|
||||
|
||||
Process.Start(Config.Default.HelpUrl);
|
||||
}
|
||||
|
||||
private void OpenLogFolder_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var logFolder = App.GetLogFolder();
|
||||
if (!Directory.Exists(logFolder))
|
||||
logFolder = Config.Default.DataPath;
|
||||
Process.Start("explorer.exe", logFolder);
|
||||
}
|
||||
|
||||
private async void RefreshPublicIP_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
await App.DiscoverMachinePublicIPAsync(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Refresh Public IP Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Settings_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var window = new SettingsWindow();
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void GameData_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = new GameDataWindow();
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void Plugins_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = new PluginsWindow();
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void ServerMonitor_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = ServerMonitorWindow.GetWindow(ServerManager);
|
||||
window.Closed += Window_Closed;
|
||||
window.Show();
|
||||
if (window.WindowState == WindowState.Minimized)
|
||||
{
|
||||
window.WindowState = WindowState.Normal;
|
||||
}
|
||||
window.Focus();
|
||||
}
|
||||
|
||||
private async void SteamCMD_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_SteamCmd_Label"), _globalizer.GetResourceString("MainWindow_SteamCmd_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
ProgressWindow window = null;
|
||||
|
||||
try
|
||||
{
|
||||
var updater = new SteamCmdUpdater();
|
||||
var cancelSource = new CancellationTokenSource();
|
||||
|
||||
window = new ProgressWindow(_globalizer.GetResourceString("Progress_ReinstallSteamCmd_WindowTitle"));
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.Show();
|
||||
|
||||
await Task.Delay(1000);
|
||||
await updater.ReinstallSteamCmdAsync(Config.Default.DataPath, new Progress<SteamCmdUpdater.Update>(u =>
|
||||
{
|
||||
var resourceString = string.IsNullOrWhiteSpace(u.StatusKey) ? null : _globalizer.GetResourceString(u.StatusKey);
|
||||
var message = resourceString != null ? $"{SteamCmdUpdater.OUTPUT_PREFIX} {resourceString}" : u.StatusKey;
|
||||
window?.AddMessage(message);
|
||||
|
||||
if (u.FailureText != null)
|
||||
{
|
||||
message = string.Format(_globalizer.GetResourceString("MainWindow_SteamCmd_FailedLabel"), u.FailureText);
|
||||
window?.AddMessage(message);
|
||||
MessageBox.Show(message, _globalizer.GetResourceString("MainWindow_SteamCmd_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}), cancelSource.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = string.Format(_globalizer.GetResourceString("MainWindow_SteamCmd_FailedLabel"), ex.Message);
|
||||
window?.AddMessage(message);
|
||||
MessageBox.Show(message, _globalizer.GetResourceString("MainWindow_SteamCmd_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (window != null)
|
||||
window.CloseWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void Upgrade_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_Label"), this.LatestServerManagerVersion), _globalizer.GetResourceString("MainWindow_Upgrade_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if(result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
OverlayMessage.Content = _globalizer.GetResourceString("MainWindow_OverlayMessage_UpgradeLabel");
|
||||
OverlayGrid.Visibility = Visibility.Visible;
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var process = Process.GetCurrentProcess();
|
||||
if (process == null || process.HasExited)
|
||||
throw new Exception("Application process could not be found or does not exist.");
|
||||
|
||||
var assemblyLocation = Assembly.GetEntryAssembly().Location;
|
||||
var updaterFile = Path.Combine(Path.GetDirectoryName(assemblyLocation), Config.Default.UpdaterFile);
|
||||
var newUpdaterFile = Path.Combine(Path.GetDirectoryName(assemblyLocation), $"New{Config.Default.UpdaterFile}");
|
||||
|
||||
// check if there is a new version of the updater file
|
||||
if (System.IO.File.Exists(newUpdaterFile))
|
||||
{
|
||||
// file exists, rename the file, so that we use the new updater instead
|
||||
try
|
||||
{
|
||||
File.Copy(newUpdaterFile, updaterFile, true);
|
||||
await Task.Delay(1000);
|
||||
File.Delete(newUpdaterFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if error, then do nothing
|
||||
Logger.Debug($"An error occurred trying to update the server manager updater. {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!File.Exists(updaterFile))
|
||||
throw new FileNotFoundException("The updater application could not be found or does not exist.");
|
||||
|
||||
var arguments = new string[]
|
||||
{
|
||||
process.Id.ToString().AsQuoted(),
|
||||
App.Instance.BetaVersion ? Config.Default.LatestServerManagerBetaDownloadUrl.AsQuoted() : Config.Default.LatestServerManagerDownloadUrl.AsQuoted(),
|
||||
Config.Default.UpdaterPrefix.AsQuoted(),
|
||||
};
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo()
|
||||
{
|
||||
FileName = updaterFile.AsQuoted(),
|
||||
Arguments = string.Join(" ", arguments),
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
var updaterProcess = Process.Start(info);
|
||||
if (updaterProcess == null)
|
||||
throw new Exception("Could not restart application.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_FailedLabel"), ex.Message, ex.StackTrace), _globalizer.GetResourceString("MainWindow_Upgrade_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
OverlayGrid.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Servers_AddNew(object sender, NewItemRequestedEventArgs e)
|
||||
{
|
||||
var index = this.ServerManager.AddNew();
|
||||
((EO.Wpf.TabControl)e.Source).SelectedIndex = index;
|
||||
}
|
||||
|
||||
public void Servers_Remove(object sender, TabItemCloseEventArgs args)
|
||||
{
|
||||
args.Canceled = true;
|
||||
var server = ServerManager.Instance.Servers[args.ItemIndex];
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_ProfileDelete_Label"), String.Format(_globalizer.GetResourceString("MainWindow_ProfileDelete_Title"), server.Profile.ProfileName), MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if(result == MessageBoxResult.Yes)
|
||||
{
|
||||
ServerManager.Instance.Remove(server, deleteProfile: true);
|
||||
args.Canceled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoBackupTaskRun_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
try
|
||||
{
|
||||
TaskSchedulerUtils.RunAutoBackup(taskKey, null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoBackupTaskState_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsAdministrator)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("MainWindow_TaskAdminErrorLabel"), _globalizer.GetResourceString("MainWindow_TaskAdminErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
try
|
||||
{
|
||||
TaskSchedulerUtils.SetAutoBackupState(taskKey, null, null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoUpdateTaskRun_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
try
|
||||
{
|
||||
TaskSchedulerUtils.RunAutoUpdate(taskKey, null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoUpdateTaskState_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsAdministrator)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("MainWindow_TaskAdminErrorLabel"), _globalizer.GetResourceString("MainWindow_TaskAdminErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
try
|
||||
{
|
||||
TaskSchedulerUtils.SetAutoUpdateState(taskKey, null, null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ShowWindowCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (parameter) =>
|
||||
{
|
||||
this.Show();
|
||||
this.WindowState = WindowState.Normal;
|
||||
this.Activate();
|
||||
},
|
||||
canExecute: (parameter) =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand StatusButtonCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<Server>(
|
||||
execute: (server) =>
|
||||
{
|
||||
Debug.WriteLine($"{server.Profile.ProfileName}: {server.Runtime.Status}");
|
||||
if (!Config.Default.ServerStatus_EnableActions)
|
||||
return;
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Stopped:
|
||||
if (Config.Default.ServerStatus_ShowActionConfirmation && MessageBox.Show(_globalizer.GetResourceString("MainWindow_ServerStatus_StartServerActionLabel"), _globalizer.GetResourceString("MainWindow_ServerStatus_StartServerActionTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
StartServerAsync(server).DoNotWait();
|
||||
break;
|
||||
|
||||
case ServerStatus.Running:
|
||||
if (Config.Default.ServerStatus_ShowActionConfirmation && MessageBox.Show(_globalizer.GetResourceString("MainWindow_ServerStatus_ShutdownServerActionLabel"), _globalizer.GetResourceString("MainWindow_ServerStatus_ShutdownServerActionTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
ShutdownServerAsync(server).DoNotWait();
|
||||
break;
|
||||
}
|
||||
},
|
||||
canExecute: (server) => server != null && server.Profile != null && server.Runtime != null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckForUpdates()
|
||||
{
|
||||
string url = App.Instance.BetaVersion ? Config.Default.LatestServerManagerBetaVersionUrl : Config.Default.LatestServerManagerVersionUrl;
|
||||
var newVersion = await NetworkUtils.GetLatestServerManagerVersion(url);
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var appVersion = new Version();
|
||||
Version.TryParse(App.Instance.Version, out appVersion);
|
||||
|
||||
this.LatestServerManagerVersion = newVersion;
|
||||
this.NewServerManagerAvailable = appVersion < newVersion;
|
||||
|
||||
Logger.Info($"{nameof(CheckForUpdates)} performed.");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}).DoNotWait();
|
||||
|
||||
await Task.Delay(Config.Default.UpdateCheckTime * 60 * 1000);
|
||||
this.versionChecker.PostAction(CheckForUpdates).DoNotWait();
|
||||
}
|
||||
|
||||
private async Task CheckForScheduledTasks()
|
||||
{
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var backupState = TaskSchedulerUtils.TaskStateAutoBackup(taskKey, null, out DateTime backupnextRunTime);
|
||||
var updateState = TaskSchedulerUtils.TaskStateAutoUpdate(taskKey, null, out DateTime updatenextRunTime);
|
||||
|
||||
this.AutoBackupState = backupState;
|
||||
this.AutoUpdateState = updateState;
|
||||
|
||||
this.AutoBackupStateString = GetTaskStateString(AutoBackupState);
|
||||
this.AutoUpdateStateString = GetTaskStateString(AutoUpdateState);
|
||||
|
||||
this.AutoBackupNextRunTime = backupnextRunTime == DateTime.MinValue ? string.Empty : $"{_globalizer.GetResourceString("MainWindow_TaskRunTimeLabel")} {backupnextRunTime:G}";
|
||||
this.AutoUpdateNextRunTime = updatenextRunTime == DateTime.MinValue ? string.Empty : $"{_globalizer.GetResourceString("MainWindow_TaskRunTimeLabel")} {updatenextRunTime:G}";
|
||||
|
||||
Logger.Info($"{nameof(CheckForScheduledTasks)} performed");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}).DoNotWait();
|
||||
|
||||
await Task.Delay(Config.Default.ScheduledTasksCheckTime * 1 * 1000);
|
||||
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
|
||||
}
|
||||
|
||||
private string GetTaskStateString(Microsoft.Win32.TaskScheduler.TaskState taskState)
|
||||
{
|
||||
switch (taskState)
|
||||
{
|
||||
case Microsoft.Win32.TaskScheduler.TaskState.Disabled:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateDisabledLabel");
|
||||
case Microsoft.Win32.TaskScheduler.TaskState.Queued:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateQueuedLabel");
|
||||
case Microsoft.Win32.TaskScheduler.TaskState.Ready:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateReadyLabel");
|
||||
case Microsoft.Win32.TaskScheduler.TaskState.Running:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateRunningLabel");
|
||||
case Microsoft.Win32.TaskScheduler.TaskState.Unknown:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateUnknownLabel");
|
||||
default:
|
||||
return _globalizer.GetResourceString("MainWindow_TaskStateUnknownLabel");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartServerAsync(Server server)
|
||||
{
|
||||
if (server == null || server.Profile == null || server.Runtime == null || server.Runtime.Status != ServerStatus.Stopped)
|
||||
return;
|
||||
|
||||
Mutex mutex = null;
|
||||
bool createdNew = false;
|
||||
|
||||
try
|
||||
{
|
||||
// try to establish a mutex for the profile.
|
||||
mutex = new Mutex(true, ServerApp.GetMutexName(server.Profile.InstallDirectory), out createdNew);
|
||||
|
||||
// check if the mutex was established
|
||||
if (createdNew)
|
||||
{
|
||||
server.Profile.Save(false, false, null);
|
||||
|
||||
if (!server.Profile.Validate(false, out string validateMessage))
|
||||
{
|
||||
var outputMessage = _globalizer.GetResourceString("ProfileValidation_WarningLabel").Replace("{validateMessage}", validateMessage);
|
||||
if (MessageBox.Show(outputMessage, _globalizer.GetResourceString("ProfileValidation_Title"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
await server.StartAsync();
|
||||
|
||||
var startupMessage = Config.Default.Alert_ServerStartedMessage;
|
||||
if (Config.Default.Alert_ServerStartedMessageIncludeIPandPort)
|
||||
startupMessage += $" {Config.Default.MachinePublicIP}:{server.Profile.QueryPort}";
|
||||
PluginHelper.Instance.ProcessAlert(AlertType.Startup, server.Profile.ProfileName, startupMessage);
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// display an error message and exit
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_StartServer_MutexFailedLabel"), _globalizer.GetResourceString("ServerSettings_StartServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_StartServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (mutex != null)
|
||||
{
|
||||
if (createdNew)
|
||||
{
|
||||
mutex.ReleaseMutex();
|
||||
mutex.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ShutdownServerAsync(Server server)
|
||||
{
|
||||
if (server == null || server.Profile == null || server.Runtime == null || server.Runtime.Status != ServerStatus.Running)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var shutdownWindow = ShutdownWindow.OpenShutdownWindow(server);
|
||||
if (shutdownWindow == null)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_ShutdownServer_AlreadyOpenLabel"), _globalizer.GetResourceString("ServerSettings_ShutdownServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
server.Runtime.UpdateServerStatus(ServerStatus.Stopping, AvailabilityStatus.Unavailable, false);
|
||||
|
||||
shutdownWindow.CloseShutdownWindowWhenFinished = true;
|
||||
shutdownWindow.Owner = this;
|
||||
shutdownWindow.Closed += Window_Closed;
|
||||
shutdownWindow.Show();
|
||||
await shutdownWindow.StartShutdownAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ShutdownServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
275
src/ConanServerManager/Windows/ModDetailsWindow.xaml
Normal file
275
src/ConanServerManager/Windows/ModDetailsWindow.xaml
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
<Window x:Class="ServerManagerTool.ModDetailsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
MinWidth="600" MinHeight="480" Width="900" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Loaded="Window_Loaded" Closing="Window_Closing"
|
||||
Name="ModDetailsUI" Icon="../Art/favicon.ico" Title="{DynamicResource ModDetails_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:IsNullOrWhiteSpaceValueConverter x:Key="IsNullOrWhiteSpaceValueConverter"/>
|
||||
<cc:InvertBooleanConverter x:Key="InvertBooleanConverter"/>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}" MouseLeftButtonUp="OnMouseLeftButtonUp" MouseMove="OnMouseMove">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="10*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" Width="22" Height="22" Margin="5,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="SaveMods_Click" ToolTip="{DynamicResource ModDetails_SaveModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Save.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="1" Width="22" Height="22" Margin="10,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="AddMods_Click" ToolTip="{DynamicResource ModDetails_AddModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Add.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="2" Width="22" Height="22" Margin="0,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="RemoveAllMods_Click" ToolTip="{DynamicResource ModDetails_RemoveAllModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="3" Width="22" Height="22" Margin="10,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="RefreshMods_Click" ToolTip="{DynamicResource ModDetails_RefreshModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Refresh.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="4" Width="22" Height="22" Margin="0,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="ReloadMods_Click" ToolTip="{DynamicResource ModDetails_ReloadModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Reload.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="5" Width="22" Height="22" Margin="0,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="LoadMods_Click" ToolTip="{DynamicResource ModDetails_LoadModsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/FolderOpen.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="6" Width="22" Height="22" Margin="10,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="PurgeModsFolder_Click" IsEnabled="{Binding Path=ModDetailsChanged, ElementName=ModDetailsUI, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ModDetails_PurgeModsFolderTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/FolderDelete.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="7" Width="22" Height="22" Margin="10,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="SaveModDetails_Click" ToolTip="{DynamicResource ModDetails_SaveModDetailsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Copy.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="8" Orientation="Horizontal">
|
||||
<TextBlock Margin="30,5,5,0" Text="{DynamicResource ModDetails_TotalCountLabel}" VerticalAlignment="Center" />
|
||||
<TextBlock Margin="5,5,5,0" Text="{Binding ModDetails.Count}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" Margin="0,5,0,0" Orientation="Horizontal" Height="30" DataContext="{Binding}">
|
||||
<TextBlock Margin="5,0,5,0" Text="{DynamicResource General_FilterLabel}" VerticalAlignment="Center" />
|
||||
<TextBox Margin="5,0,5,0" Text="{Binding ModDetailsFilterString, Mode=TwoWay}" Width="200" Padding="2" VerticalAlignment="Center"/>
|
||||
<Button Margin="5,0,5,0" Width="22" Height="22" HorizontalAlignment="Left" VerticalAlignment="Center" Click="FilterMods_Click" ToolTip="{DynamicResource General_FilterButtonTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Filter.ico,Size=32}"/>
|
||||
</Button>
|
||||
<TextBlock Margin="5,0,5,0" Text="{Binding ModDetailsStatusMessage}" VerticalAlignment="Center" Foreground="SteelBlue" />
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="9" Name="ModDetailsGrid" ItemsSource="{Binding ModDetails}" Margin="5" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" CanUserSortColumns="True" RowHeaderWidth="0" SelectionMode="Single" PreviewMouseLeftButtonDown="OnMouseLeftButtonDown">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsValid}" Value="False">
|
||||
<Setter Property="Background" Value="#FFB8E7F5" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding UpToDate}" Value="False">
|
||||
<Setter Property="Background" Value="#FFF5DFB8" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Width="Auto" Binding="{Binding Index, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ModDetails_IndexColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="100" CanUserSort="True" SortMemberPath="ModId">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ModDetails_ModIdColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock>
|
||||
<Hyperlink NavigateUri="{Binding ModUrl}" RequestNavigate="Mod_RequestNavigate">
|
||||
<TextBlock Text="{Binding ModId, Mode=OneWay}"/>
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Width="1*" Binding="{Binding Title, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ModDetails_TitleColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="Auto" MinWidth="80" Binding="{Binding ModTypeString, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ModDetails_TypeColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="Auto" MinWidth="130" Binding="{Binding LastWriteTimeString, Mode=OneWay}" Header="{DynamicResource ModDetails_LastUpdatedColumnLabel}" SortMemberPath="LastWriteTimeSortString">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="Auto" MinWidth="130" Binding="{Binding TimeUpdatedString, Mode=OneWay}" Header="{DynamicResource ModDetails_TimeUpdatedColumnLabel}" SortMemberPath="TimeUpdatedSortString">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="Auto" MinWidth="80" Binding="{Binding TimeUpdated, Mode=OneWay}" Header="{DynamicResource ModDetails_TimestampColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="85" Binding="{Binding FolderSizeString, Mode=OneWay}" Header="{DynamicResource ModDetails_FolderSizeColumnLabel}" SortMemberPath="FolderSize">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="MoveModUp_Click" ToolTip="{DynamicResource ModDetails_MoveModUpTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Up.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="{x:Type DataGridCell}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsFirst}" Value="True">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ModDetailsFilterString, ElementName=ModDetailsUI, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="MoveModDown_Click" ToolTip="{DynamicResource ModDetails_MoveModDownTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Down.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="{x:Type DataGridCell}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsLast}" Value="True">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ModDetailsFilterString, ElementName=ModDetailsUI, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="RemoveMod_Click" ToolTip="{DynamicResource ModDetails_RemoveModTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="WriteTimestampMod_Click" ToolTip="{DynamicResource ModDetails_WriteTimestampModTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Edit.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="{x:Type DataGridCell}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsValid}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<!-- Drag and Drop Popup -->
|
||||
<Popup Grid.Row="0" Grid.Column="0" x:Name="popup" IsHitTestVisible="False" Placement="RelativePoint" PlacementTarget="{Binding ElementName=ModDetailsUI}" AllowsTransparency="True">
|
||||
<Border BorderBrush="LightSteelBlue" BorderThickness="2" Background="White" Opacity="0.75">
|
||||
<StackPanel Orientation="Horizontal" Margin="4,3,8,3">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Drag.ico,Size=32}"/>
|
||||
<TextBlock FontSize="14" VerticalAlignment="Center" Text="{Binding DraggedItem, ElementName=ModDetailsUI}" Margin="8,0,0,0" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
</Window>
|
||||
647
src/ConanServerManager/Windows/ModDetailsWindow.xaml.cs
Normal file
647
src/ConanServerManager/Windows/ModDetailsWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
using NLog;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Navigation;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ModDetailsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ModDetailsWindow : Window
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public EventHandler<ProfileEventArgs> SavePerformed;
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly ServerProfile _profile = null;
|
||||
|
||||
private WorkshopFilesWindow _workshopFilesWindow = null;
|
||||
|
||||
public static readonly DependencyProperty ModDetailsProperty = DependencyProperty.Register(nameof(ModDetails), typeof(ModDetailList), typeof(ModDetailsWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ModDetailsChangedProperty = DependencyProperty.Register(nameof(ModDetailsChanged), typeof(bool), typeof(ModDetailsWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty ModDetailsViewProperty = DependencyProperty.Register(nameof(ModDetailsView), typeof(ICollectionView), typeof(ModDetailsWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ModDetailsFilterStringProperty = DependencyProperty.Register(nameof(ModDetailsFilterString), typeof(string), typeof(ModDetailsWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty ModDetailsStatusMessageProperty = DependencyProperty.Register(nameof(ModDetailsStatusMessage), typeof(string), typeof(ModDetailsWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty WorkshopFilesProperty = DependencyProperty.Register(nameof(WorkshopFiles), typeof(WorkshopFileList), typeof(ModDetailsWindow), new PropertyMetadata(null));
|
||||
|
||||
public ModDetailsWindow(ServerProfile profile)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
_profile = profile;
|
||||
this.Title = string.Format(_globalizer.GetResourceString("ModDetails_ProfileTitle"), _profile?.ProfileName);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public ModDetailList ModDetails
|
||||
{
|
||||
get { return GetValue(ModDetailsProperty) as ModDetailList; }
|
||||
set
|
||||
{
|
||||
SetValue(ModDetailsProperty, value);
|
||||
|
||||
ModDetailsView = CollectionViewSource.GetDefaultView(ModDetails);
|
||||
ModDetailsView.Filter = new Predicate<object>(Filter);
|
||||
|
||||
if (_workshopFilesWindow != null)
|
||||
_workshopFilesWindow.UpdateModDetailsList(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ModDetailsChanged
|
||||
{
|
||||
get { return (bool)GetValue(ModDetailsChangedProperty); }
|
||||
set { SetValue(ModDetailsChangedProperty, value); }
|
||||
}
|
||||
|
||||
public ICollectionView ModDetailsView
|
||||
{
|
||||
get { return GetValue(ModDetailsViewProperty) as ICollectionView; }
|
||||
set { SetValue(ModDetailsViewProperty, value); }
|
||||
}
|
||||
|
||||
public string ModDetailsFilterString
|
||||
{
|
||||
get { return (string)GetValue(ModDetailsFilterStringProperty); }
|
||||
set { SetValue(ModDetailsFilterStringProperty, value); }
|
||||
}
|
||||
|
||||
public string ModDetailsStatusMessage
|
||||
{
|
||||
get { return (string)GetValue(ModDetailsStatusMessageProperty); }
|
||||
set { SetValue(ModDetailsStatusMessageProperty, value); }
|
||||
}
|
||||
|
||||
public WorkshopFileList WorkshopFiles
|
||||
{
|
||||
get { return GetValue(WorkshopFilesProperty) as WorkshopFileList; }
|
||||
set { SetValue(WorkshopFilesProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
WorkshopFiles = await LoadWorkshopItemsAsync();
|
||||
await LoadModsFromProfile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (ModDetailsChanged)
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("ModDetails_Unsaved_Label"), _globalizer.GetResourceString("ModDetails_Unsaved_Title"), MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.No)
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void ModDetails_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
ModDetailsChanged = true;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadModsFromList();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Refresh_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async void WorkshopFilesWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
_workshopFilesWindow = null;
|
||||
this.Activate();
|
||||
|
||||
try
|
||||
{
|
||||
WorkshopFiles = await LoadWorkshopItemsAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Mod_RequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
var mod = ((ModDetail)((Hyperlink)e.Source).DataContext);
|
||||
|
||||
Process.Start(new ProcessStartInfo(mod.ModUrl));
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void AddMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_workshopFilesWindow != null)
|
||||
return;
|
||||
|
||||
_workshopFilesWindow = new WorkshopFilesWindow(this, _profile);
|
||||
_workshopFilesWindow.Owner = this;
|
||||
_workshopFilesWindow.Closed += WorkshopFilesWindow_Closed;
|
||||
_workshopFilesWindow.Show();
|
||||
}
|
||||
|
||||
private async void LoadMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_profile == null)
|
||||
return;
|
||||
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadModsFromServerFolder();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveModDown_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mod = ((ModDetail)((Button)e.Source).DataContext);
|
||||
ModDetails.MoveDown(mod);
|
||||
}
|
||||
|
||||
private void MoveModUp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mod = ((ModDetail)((Button)e.Source).DataContext);
|
||||
ModDetails.MoveUp(mod);
|
||||
}
|
||||
|
||||
private async void PurgeModsFolder_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_profile == null)
|
||||
return;
|
||||
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ModDetails_Purge_Label"), _globalizer.GetResourceString("ModDetails_Purge_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
int folderCount;
|
||||
int fileCount;
|
||||
|
||||
PurgeModsFromServerFolder(out folderCount, out fileCount);
|
||||
|
||||
var message = _globalizer.GetResourceString("ModDetails_Purge_SuccessLabel");
|
||||
message = message.Replace("{folderCount}", folderCount.ToString());
|
||||
message = message.Replace("{fileCount}", fileCount.ToString());
|
||||
MessageBox.Show(message, _globalizer.GetResourceString("ModDetails_Purge_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Purge_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async void RefreshMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadModsFromList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Refresh_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ReloadMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadModsFromProfile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Reload_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveMod_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mod = ((ModDetail)((Button)e.Source).DataContext);
|
||||
ModDetails.Remove(mod);
|
||||
}
|
||||
|
||||
private void RemoveAllMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ModDetails.Clear();
|
||||
}
|
||||
|
||||
private async void SaveMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
string mapString;
|
||||
string modIdString;
|
||||
|
||||
// check if there are any unknown mod types.
|
||||
if (ModDetails.AnyUnknownModTypes)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ModDetails_Save_UnknownLabel"), _globalizer.GetResourceString("ModDetails_Save_UnknownTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ModDetails.GetModStrings(out mapString, out modIdString))
|
||||
{
|
||||
if (mapString != null)
|
||||
_profile.ServerMap = mapString;
|
||||
_profile.ServerModIds = modIdString ?? string.Empty;
|
||||
}
|
||||
|
||||
await LoadModsFromProfile();
|
||||
OnSavePerformed();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_Save_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveModDetails_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var modDetails = string.Empty;
|
||||
var delimiter = string.Empty;
|
||||
foreach (var modDetail in ModDetails)
|
||||
{
|
||||
modDetails += $"{delimiter}{modDetail.Title} ({modDetail.ModId}){Environment.NewLine}{modDetail.ModUrl}";
|
||||
delimiter = Environment.NewLine;
|
||||
}
|
||||
|
||||
var window = new CommandLineWindow(modDetails);
|
||||
window.OutputTextWrapping = TextWrapping.NoWrap;
|
||||
window.Height = 500;
|
||||
window.Title = _globalizer.GetResourceString("ModDetails_Clipboard_SaveTitle");
|
||||
window.Owner = Window.GetWindow(this);
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private async void WriteTimestampMod_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mod = ((ModDetail)((Button)e.Source).DataContext);
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ModDetails_WriteTimestamp_ConfirmLabel"), _globalizer.GetResourceString("ModDetails_WriteTimestamp_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
var file = ModUtils.GetLatestModTimeFile(_profile?.InstallDirectory, mod.ModId);
|
||||
var steamLastUpdated = mod?.TimeUpdated.ToString() ?? string.Empty;
|
||||
File.WriteAllText(file, steamLastUpdated);
|
||||
|
||||
mod.PopulateExtended(Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath));
|
||||
ModDetailsView?.Refresh();
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("ModDetails_WriteTimestamp_FailedLabel"), _globalizer.GetResourceString("ModDetails_WriteTimestamp_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ModDetails_WriteTimestamp_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnSavePerformed()
|
||||
{
|
||||
SavePerformed?.Invoke(this, new ProfileEventArgs(_profile));
|
||||
}
|
||||
|
||||
public int SelectedRowIndex()
|
||||
{
|
||||
return ModDetailsGrid.SelectedIndex;
|
||||
}
|
||||
|
||||
private async Task LoadModsFromList()
|
||||
{
|
||||
// build a list of mods to be processed
|
||||
var modIdList = new List<string>();
|
||||
|
||||
modIdList.AddRange(ModDetails.Select(m => m.ModId));
|
||||
modIdList = ModUtils.ValidateModList(modIdList);
|
||||
|
||||
var response = await Task.Run(() => SteamUtils.GetSteamModDetails(modIdList));
|
||||
var workshopFiles = WorkshopFiles;
|
||||
var modsRootFolder = Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath);
|
||||
var modDetails = ModDetailList.GetModDetails(modIdList, modsRootFolder, workshopFiles, response);
|
||||
|
||||
UpdateModDetailsList(modDetails);
|
||||
|
||||
ModDetailsStatusMessage = modDetails.Count > 0 && response?.publishedfiledetails == null ? _globalizer.GetResourceString("ModDetails_ModDetailFetchFailed_Label") : string.Empty;
|
||||
ModDetailsChanged = true;
|
||||
}
|
||||
|
||||
private async Task LoadModsFromProfile()
|
||||
{
|
||||
// build a list of mods to be processed
|
||||
var modIdList = new List<string>();
|
||||
|
||||
modIdList.AddRange(ModUtils.GetModIdList(_profile.ServerModIds));
|
||||
modIdList = ModUtils.ValidateModList(modIdList);
|
||||
|
||||
var response = await Task.Run(() => SteamUtils.GetSteamModDetails(modIdList));
|
||||
var workshopFiles = WorkshopFiles;
|
||||
var modsRootFolder = Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath);
|
||||
var modDetails = ModDetailList.GetModDetails(modIdList, modsRootFolder, workshopFiles, response);
|
||||
|
||||
UpdateModDetailsList(modDetails);
|
||||
|
||||
ModDetailsStatusMessage = modDetails.Count > 0 && response?.publishedfiledetails == null ? _globalizer.GetResourceString("ModDetails_ModDetailFetchFailed_Label") : string.Empty;
|
||||
ModDetailsChanged = false;
|
||||
}
|
||||
|
||||
private async Task LoadModsFromServerFolder()
|
||||
{
|
||||
// build a list of mods to be processed
|
||||
var modIdList = new List<string>();
|
||||
|
||||
var modDirectory = new DirectoryInfo(Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath));
|
||||
foreach (var file in modDirectory.GetFiles("*.pak"))
|
||||
{
|
||||
var modId = Path.GetFileNameWithoutExtension(file.Name);
|
||||
if (ModUtils.IsOfficialMod(modId))
|
||||
continue;
|
||||
|
||||
modIdList.Add(modId);
|
||||
}
|
||||
modIdList = ModUtils.ValidateModList(modIdList);
|
||||
|
||||
var response = await Task.Run(() => SteamUtils.GetSteamModDetails(modIdList));
|
||||
var workshopFiles = WorkshopFiles;
|
||||
var modsRootFolder = Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath);
|
||||
var modDetails = ModDetailList.GetModDetails(modIdList, modsRootFolder, workshopFiles, response);
|
||||
|
||||
UpdateModDetailsList(modDetails);
|
||||
|
||||
ModDetailsStatusMessage = modDetails.Count > 0 && response?.publishedfiledetails == null ? _globalizer.GetResourceString("ModDetails_ModDetailFetchFailed_Label") : string.Empty;
|
||||
ModDetailsChanged = true;
|
||||
}
|
||||
|
||||
private async Task<WorkshopFileList> LoadWorkshopItemsAsync()
|
||||
{
|
||||
WorkshopFileDetailResponse localCache = null;
|
||||
|
||||
await Task.Run(() => {
|
||||
var file = Path.Combine(Config.Default.DataPath, Config.Default.WorkshopCacheFile);
|
||||
|
||||
// try to load the cache file.
|
||||
localCache = WorkshopFileDetailResponse.Load(file);
|
||||
});
|
||||
|
||||
return WorkshopFileList.GetList(localCache);
|
||||
}
|
||||
|
||||
private void PurgeModsFromServerFolder(out int folderCount, out int fileCount)
|
||||
{
|
||||
folderCount = 0;
|
||||
fileCount = 0;
|
||||
|
||||
// build a list of mods to be processed
|
||||
var modIdList = ModDetails.Select(m => m.ModId).ToList();
|
||||
|
||||
var modDirectory = new DirectoryInfo(Path.Combine(_profile.InstallDirectory, Config.Default.ServerModsRelativePath));
|
||||
if (Directory.Exists(modDirectory.FullName))
|
||||
{
|
||||
foreach (var file in modDirectory.GetFiles("*.pak"))
|
||||
{
|
||||
var modId = Path.GetFileNameWithoutExtension(file.Name);
|
||||
if (ModUtils.IsOfficialMod(modId))
|
||||
continue;
|
||||
|
||||
if (modIdList.Contains(modId))
|
||||
continue;
|
||||
|
||||
file.Delete();
|
||||
fileCount++;
|
||||
|
||||
var timeFile = Path.ChangeExtension(file.FullName, ".txt");
|
||||
if (File.Exists(timeFile))
|
||||
File.Delete(timeFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateModDetailsList(ModDetailList modDetails)
|
||||
{
|
||||
if (ModDetails != null)
|
||||
ModDetails.CollectionChanged -= ModDetails_CollectionChanged;
|
||||
|
||||
ModDetails = modDetails ?? new ModDetailList();
|
||||
if (ModDetails != null)
|
||||
ModDetails.CollectionChanged += ModDetails_CollectionChanged;
|
||||
|
||||
ModDetailsView?.Refresh();
|
||||
}
|
||||
|
||||
#region Drag and Drop
|
||||
|
||||
public static readonly DependencyProperty DraggedItemProperty = DependencyProperty.Register(nameof(DraggedItem), typeof(ModDetail), typeof(ModDetailsWindow), new PropertyMetadata(null));
|
||||
|
||||
public ModDetail DraggedItem
|
||||
{
|
||||
get { return (ModDetail)GetValue(DraggedItemProperty); }
|
||||
set { SetValue(DraggedItemProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsDragging { get; set; }
|
||||
|
||||
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// check fi the column is a template column (no drag-n-drop for those column types)
|
||||
var cell = WindowUtils.TryFindFromPoint<DataGridCell>((UIElement)sender, e.GetPosition(ModDetailsGrid));
|
||||
if (cell == null || cell.Column is DataGridTemplateColumn) return;
|
||||
|
||||
// check if we have a valid row
|
||||
var row = WindowUtils.TryFindFromPoint<DataGridRow>((UIElement)sender, e.GetPosition(ModDetailsGrid));
|
||||
if (row == null) return;
|
||||
|
||||
// set flag that indicates we're capturing mouse movements
|
||||
IsDragging = true;
|
||||
DraggedItem = (ModDetail)row.Item;
|
||||
}
|
||||
|
||||
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!IsDragging)
|
||||
{
|
||||
if (popup.IsOpen)
|
||||
popup.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//get the target item
|
||||
var targetItem = (ModDetail)ModDetailsGrid.SelectedItem;
|
||||
|
||||
if (targetItem == null || !ReferenceEquals(DraggedItem, targetItem))
|
||||
{
|
||||
//get target index
|
||||
var targetIndex = ModDetails.IndexOf(targetItem);
|
||||
|
||||
//move source at the target's location
|
||||
ModDetails.Move(DraggedItem, targetIndex);
|
||||
|
||||
//select the dropped item
|
||||
ModDetailsGrid.SelectedItem = DraggedItem;
|
||||
}
|
||||
|
||||
//reset
|
||||
ResetDragDrop();
|
||||
}
|
||||
|
||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!IsDragging || e.LeftButton != MouseButtonState.Pressed)
|
||||
{
|
||||
if (popup.IsOpen)
|
||||
popup.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// display the popup if it hasn't been opened yet
|
||||
if (!popup.IsOpen)
|
||||
{
|
||||
// switch to read-only mode
|
||||
ModDetailsGrid.IsReadOnly = true;
|
||||
|
||||
// make sure the popup is visible
|
||||
popup.IsOpen = true;
|
||||
}
|
||||
|
||||
var popupSize = new Size(popup.ActualWidth, popup.ActualHeight);
|
||||
popup.PlacementRectangle = new Rect(e.GetPosition(this), popupSize);
|
||||
|
||||
// make sure the row under the grid is being selected
|
||||
var position = e.GetPosition(ModDetailsGrid);
|
||||
var row = WindowUtils.TryFindFromPoint<DataGridRow>(ModDetailsGrid, position);
|
||||
if (row != null) ModDetailsGrid.SelectedItem = row.Item;
|
||||
}
|
||||
|
||||
private void ResetDragDrop()
|
||||
{
|
||||
IsDragging = false;
|
||||
popup.IsOpen = false;
|
||||
ModDetailsGrid.IsReadOnly = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filter
|
||||
private void FilterMods_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ModDetailsView?.Refresh();
|
||||
}
|
||||
|
||||
public bool Filter(object obj)
|
||||
{
|
||||
var data = obj as ModDetail;
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
var filterString = ModDetailsFilterString.ToLower();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filterString))
|
||||
return true;
|
||||
|
||||
return data.ModId.Contains(filterString) || data.TitleFilterString.Contains(filterString);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
177
src/ConanServerManager/Windows/PlayerListWindow.xaml
Normal file
177
src/ConanServerManager/Windows/PlayerListWindow.xaml
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
<Window x:Class="ServerManagerTool.PlayerListWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:en="clr-namespace:ServerManagerTool.Enums"
|
||||
xmlns:vm="clr-namespace:ServerManagerTool.Lib.ViewModel"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
MinWidth="300" MinHeight="200" Width="300" Height="500" ResizeMode="CanResizeWithGrip" WindowStyle="ToolWindow"
|
||||
SizeChanged="Window_SizeChanged" LocationChanged="Window_LocationChanged"
|
||||
Name="PlayerList" Icon="../Art/favicon.ico" Title="{Binding PlayerListParameters.WindowTitle}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:EnumConverter x:Key="EnumConverter"/>
|
||||
<cc:EnumFlagsConverter x:Key="EnumFlagsConverter"/>
|
||||
<cc:IsNullOrWhiteSpaceValueConverter x:Key="IsNullOrWhiteSpaceValueConverter"/>
|
||||
<cc:IsNullValueConverter x:Key="IsNullValueConverter"/>
|
||||
<cc:NullValueConverter x:Key="NullValueConverter"/>
|
||||
|
||||
<SolidColorBrush x:Key="HeaderBrush" Color="#FFF0F0F0"/>
|
||||
|
||||
<Style x:Key="PlayerStatus" TargetType="Border">
|
||||
<Setter Property="BorderBrush" Value="Gray"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOnline}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="LightGreen"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsOnline}" Value="False" />
|
||||
<Condition Binding="{Binding IsValid}" Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="BorderBrush" Value="Orange"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsOnline}" Value="False" />
|
||||
<Condition Binding="{Binding IsWhitelisted}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="BorderBrush" Value="#0066CC"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="GuildName" TargetType="Label">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding GuildName, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="True">
|
||||
<Setter Property="Content" Value="No clan"/>
|
||||
<Setter Property="FontStyle" Value="Italic"/>
|
||||
<Setter Property="Foreground" Value="LightGray"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding GuildName, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="False">
|
||||
<Setter Property="Content" Value="{Binding PlayerData.Guild.GuildName}"/>
|
||||
<Setter Property="FontStyle" Value="Normal"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<DockPanel x:Name="dockPanel">
|
||||
<Border DockPanel.Dock="Top" BorderThickness="1" BorderBrush="LightGray" Margin="2" Background="{StaticResource HeaderBrush}">
|
||||
<DockPanel Margin="2,2,2,1" LastChildFill="False">
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Left">
|
||||
<Menu VerticalAlignment="Center" Margin="1" Background="{StaticResource HeaderBrush}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Players}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Sort}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortOnline}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Online}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Online}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortName}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Name}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Name}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortTribe}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Tribe}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Tribe}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortLastOnline}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.LastOnline}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=LastOnline}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Filter}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterOnline}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Online}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Online, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterOffline}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Offline}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Offline, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterWhitelisted}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Whitelisted}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Whitelisted, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterInvalid}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Invalid}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Invalid, Mode=OneWay}"/>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
|
||||
<Label Content="{DynamicResource RCON_PlayersLabel}" Margin="5,0,0,0"/>
|
||||
<Label Content="{Binding ServerPlayers.CountOnlinePlayers, FallbackValue=0}"/>
|
||||
<Label Content="{DynamicResource RCON_PlayersSeparatorLabel}" Name="PlayerCountSeparator"/>
|
||||
<Label Content="{Binding PlayerListParameters.MaxPlayers, FallbackValue=0}" Name="MaxPlayerLabel"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<DockPanel DockPanel.Dock="Right" MinWidth="200" Margin="1,1,2,1" DataContext="{Binding}">
|
||||
<DockPanel DockPanel.Dock="Top">
|
||||
<Label DockPanel.Dock="Left" Content="{DynamicResource General_FilterLabel}" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<Button DockPanel.Dock="Right" Margin="5,0,5,0" Width="22" Height="22" HorizontalAlignment="Right" VerticalAlignment="Center" Click="FilterPlayerList_Click" ToolTip="{DynamicResource General_FilterButtonTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Filter.ico,Size=32}"/>
|
||||
</Button>
|
||||
<TextBox DockPanel.Dock="Left" Text="{Binding PlayerListFilterString, Mode=TwoWay}" BorderBrush="LightGray" VerticalAlignment="Center" VerticalContentAlignment="Center" IsTabStop="True" Margin="0" Padding="2"/>
|
||||
</DockPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource PlayerList_ProfileCountLabel}" HorizontalAlignment="Center"/>
|
||||
<Label Content="{Binding ServerPlayers.Players.Count, FallbackValue=0}" HorizontalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource PlayerList_ProfileInvalidCountLabel}" HorizontalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ServerPlayers.CountInvalidPlayers, FallbackValue=0, Converter={cc:GreaterThanIntValueConverter 0}}" Value="true">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
<Label Content="{Binding ServerPlayers.CountInvalidPlayers, FallbackValue=0}" HorizontalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ServerPlayers.CountInvalidPlayers, FallbackValue=0, Converter={cc:GreaterThanIntValueConverter 0}}" Value="true">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
</StackPanel>
|
||||
|
||||
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding ServerPlayers.Players}" BorderBrush="LightGray" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||
<ListBox.Resources>
|
||||
<clib:BindingProxy x:Key="proxy" Data="{Binding ElementName=PlayerList}"/>
|
||||
</ListBox.Resources>
|
||||
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="ContextMenu">
|
||||
<Setter.Value>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{DynamicResource PlayerList_Menu_ViewProfile}" Command="{Binding Source={StaticResource proxy}, Path=Data.ViewPlayerProfileCommand}" CommandParameter="{Binding}" />
|
||||
<MenuItem Header="{DynamicResource PlayerList_Menu_ViewTribe}" Command="{Binding Source={StaticResource proxy}, Path=Data.ViewPlayerTribeCommand}" CommandParameter="{Binding}"/>
|
||||
</ContextMenu>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:PlayerInfo}">
|
||||
<Border BorderThickness="2" Padding="1" Style="{DynamicResource PlayerStatus}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch">
|
||||
<StackPanel Orientation="Horizontal" Margin="0" ToolTip="{Binding PlayerId}">
|
||||
<Label Content="{Binding CharacterName}" Padding="0,-1,0,-1"/>
|
||||
<TextBlock Text="{Binding PlayerData.Level, StringFormat=({0})}" Margin="5,0,0,0" Padding="0,-1,0,-1" />
|
||||
</StackPanel>
|
||||
<Label Padding="0,-1,0,-1" Style="{DynamicResource GuildName}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
389
src/ConanServerManager/Windows/PlayerListWindow.xaml.cs
Normal file
389
src/ConanServerManager/Windows/PlayerListWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PlayerListWindow.xaml
|
||||
/// </summary>
|
||||
public partial class PlayerListWindow : Window
|
||||
{
|
||||
private static Dictionary<Server, PlayerListWindow> Windows = new Dictionary<Server, PlayerListWindow>();
|
||||
|
||||
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(PlayerListWindow), new PropertyMetadata(Config.Default));
|
||||
public static readonly DependencyProperty PlayerFilteringProperty = DependencyProperty.Register(nameof(PlayerFiltering), typeof(PlayerFilterType), typeof(PlayerListWindow), new PropertyMetadata(PlayerFilterType.Online | PlayerFilterType.Offline));
|
||||
public static readonly DependencyProperty PlayerListParametersProperty = DependencyProperty.Register(nameof(PlayerListParameters), typeof(PlayerListParameters), typeof(PlayerListWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty PlayerListFilterStringProperty = DependencyProperty.Register(nameof(PlayerListFilterString), typeof(string), typeof(PlayerListWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty PlayerListViewProperty = DependencyProperty.Register(nameof(PlayerListView), typeof(ICollectionView), typeof(PlayerListWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty PlayerSortingProperty = DependencyProperty.Register(nameof(PlayerSorting), typeof(PlayerSortType), typeof(PlayerListWindow), new PropertyMetadata(PlayerSortType.Name));
|
||||
public static readonly DependencyProperty ServerPlayersProperty = DependencyProperty.Register(nameof(ServerPlayers), typeof(ServerPlayers), typeof(PlayerListWindow), new PropertyMetadata(null));
|
||||
|
||||
public PlayerListWindow(PlayerListParameters parameters)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.PlayerFiltering = (PlayerFilterType)Config.Default.PlayerListFilter;
|
||||
this.PlayerSorting = (PlayerSortType)Config.Default.PlayerListSort;
|
||||
|
||||
this.PlayerListParameters = parameters;
|
||||
this.ServerPlayers = new ServerPlayers(parameters);
|
||||
this.ServerPlayers.Players.CollectionChanged += Players_CollectionChanged;
|
||||
this.ServerPlayers.PlayersCollectionUpdated += Players_CollectionUpdated;
|
||||
|
||||
this.PlayerListView = CollectionViewSource.GetDefaultView(this.ServerPlayers.Players);
|
||||
this.PlayerListView.Filter = new Predicate<object>(PlayerListFilter);
|
||||
|
||||
if (this.PlayerListParameters?.Server?.Runtime != null)
|
||||
{
|
||||
this.PlayerListParameters.Server.Runtime.StatusUpdate += Runtime_StatusUpdate;
|
||||
}
|
||||
|
||||
this.DataContext = this;
|
||||
|
||||
if (this.PlayerListParameters.WindowExtents.Width > 50 && this.PlayerListParameters.WindowExtents.Height > 50)
|
||||
{
|
||||
this.Left = this.PlayerListParameters.WindowExtents.Left;
|
||||
this.Top = this.PlayerListParameters.WindowExtents.Top;
|
||||
this.Width = this.PlayerListParameters.WindowExtents.Width;
|
||||
this.Height = this.PlayerListParameters.WindowExtents.Height;
|
||||
|
||||
// Fix issues where the window was saved while offscreen.
|
||||
if (this.Left == -32000)
|
||||
{
|
||||
this.Left = 0;
|
||||
}
|
||||
|
||||
if (this.Top == -32000)
|
||||
{
|
||||
this.Top = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Config Config
|
||||
{
|
||||
get { return (Config)GetValue(ConfigProperty); }
|
||||
set { SetValue(ConfigProperty, value); }
|
||||
}
|
||||
|
||||
public PlayerListParameters PlayerListParameters
|
||||
{
|
||||
get { return (PlayerListParameters)GetValue(PlayerListParametersProperty); }
|
||||
set { SetValue(PlayerListParametersProperty, value); }
|
||||
}
|
||||
|
||||
public PlayerFilterType PlayerFiltering
|
||||
{
|
||||
get { return (PlayerFilterType)GetValue(PlayerFilteringProperty); }
|
||||
set { SetValue(PlayerFilteringProperty, value); }
|
||||
}
|
||||
|
||||
public string PlayerListFilterString
|
||||
{
|
||||
get { return (string)GetValue(PlayerListFilterStringProperty); }
|
||||
set { SetValue(PlayerListFilterStringProperty, value); }
|
||||
}
|
||||
|
||||
public ICollectionView PlayerListView
|
||||
{
|
||||
get { return (ICollectionView)GetValue(PlayerListViewProperty); }
|
||||
set { SetValue(PlayerListViewProperty, value); }
|
||||
}
|
||||
|
||||
public PlayerSortType PlayerSorting
|
||||
{
|
||||
get { return (PlayerSortType)GetValue(PlayerSortingProperty); }
|
||||
set { SetValue(PlayerSortingProperty, value); }
|
||||
}
|
||||
|
||||
public ServerPlayers ServerPlayers
|
||||
{
|
||||
get { return (ServerPlayers)GetValue(ServerPlayersProperty); }
|
||||
set { SetValue(ServerPlayersProperty, value); }
|
||||
}
|
||||
|
||||
public ICommand CopyIDCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Clipboard.SetText(player.PlayerId.ToString());
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyIdLabel")} {player.PlayerName}", _globalizer.GetResourceString("RCON_CopyIdTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON_ClipboardErrorTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
},
|
||||
canExecute: (player) => player != null
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand CopyPlayerIDCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
if (player.PlayerData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Clipboard.SetText(player.PlayerData.CharacterId.ToString());
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyPlayerIdLabel")} {player.PlayerName}", _globalizer.GetResourceString("RCON_CopyPlayerIdTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON__ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON__ClipboardErrorTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
}
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null && player.IsValid
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand FilterPlayersCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerFilterType>(
|
||||
execute: (filter) =>
|
||||
{
|
||||
this.PlayerFiltering ^= filter;
|
||||
Config.Default.PlayerListFilter = (int)this.PlayerFiltering;
|
||||
this.PlayerListView.Refresh();
|
||||
},
|
||||
canExecute: (filter) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand SortPlayersCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerSortType>(
|
||||
execute: (sort) =>
|
||||
{
|
||||
Config.Default.PlayerListSort = (int)this.PlayerSorting;
|
||||
SortPlayers();
|
||||
},
|
||||
canExecute: (sort) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ViewPlayerProfileCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) => {
|
||||
var savedFilesPath = ServerProfile.GetProfileSavePath(this.PlayerListParameters.InstallDirectory);
|
||||
var window = new PlayerProfileWindow(player, savedFilesPath)
|
||||
{
|
||||
Owner = this
|
||||
};
|
||||
window.ShowDialog();
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ViewPlayerTribeCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) => {
|
||||
var savedFilesPath = ServerProfile.GetProfileSavePath(this.PlayerListParameters.InstallDirectory);
|
||||
var window = new GuildProfileWindow(player, this.ServerPlayers.Players, savedFilesPath)
|
||||
{
|
||||
Owner = this
|
||||
};
|
||||
window.ShowDialog();
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null && !string.IsNullOrWhiteSpace(player.GuildName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void Players_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
PlayerListView?.Refresh();
|
||||
}
|
||||
|
||||
private void Players_CollectionUpdated(object sender, EventArgs e)
|
||||
{
|
||||
this.PlayerListView = CollectionViewSource.GetDefaultView(this.ServerPlayers.Players);
|
||||
this.PlayerListView.Filter = new Predicate<object>(PlayerListFilter);
|
||||
|
||||
SortPlayers();
|
||||
PlayerListView?.Refresh();
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState != WindowState.Minimized)
|
||||
{
|
||||
var savedRect = this.PlayerListParameters.WindowExtents;
|
||||
this.PlayerListParameters.WindowExtents = new Rect(savedRect.Location, e.NewSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_LocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (this.WindowState != WindowState.Minimized && this.Left != -32000 && this.Top != -32000)
|
||||
{
|
||||
var savedRect = this.PlayerListParameters.WindowExtents;
|
||||
this.PlayerListParameters.WindowExtents = new Rect(new Point(this.Left, this.Top), savedRect.Size);
|
||||
if (this.PlayerListParameters.Server != null)
|
||||
{
|
||||
this.PlayerListParameters.Server.Profile.PlayerListWindowExtents = this.PlayerListParameters.WindowExtents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Runtime_StatusUpdate(object sender, EventArgs eventArgs)
|
||||
{
|
||||
this.PlayerListParameters.ProfileName = this.PlayerListParameters?.Server?.Runtime?.ProfileSnapshot.ProfileName ?? "<unknown>";
|
||||
this.PlayerListParameters.MaxPlayers = this.PlayerListParameters?.Server?.Runtime?.MaxPlayers ?? 0;
|
||||
}
|
||||
|
||||
public static void CloseAllWindows()
|
||||
{
|
||||
var windows = Windows.Values.ToList();
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.IsLoaded)
|
||||
window.Close();
|
||||
}
|
||||
windows.Clear();
|
||||
}
|
||||
|
||||
public static PlayerListWindow GetWindowForServer(Server server)
|
||||
{
|
||||
if (!Windows.TryGetValue(server, out PlayerListWindow window) || !window.IsLoaded)
|
||||
{
|
||||
window = new PlayerListWindow(new PlayerListParameters()
|
||||
{
|
||||
WindowTitle = String.Format(GlobalizedApplication.Instance.GetResourceString("PlayerList_TitleLabel"), server.Runtime.ProfileSnapshot.ProfileName),
|
||||
WindowExtents = server.Profile.PlayerListWindowExtents,
|
||||
|
||||
Server = server,
|
||||
InstallDirectory = server.Runtime.ProfileSnapshot.InstallDirectory,
|
||||
GameFile = server.Runtime.ProfileSnapshot.GameFile,
|
||||
ProfileName = server.Runtime.ProfileSnapshot.ProfileName,
|
||||
ProfileId = server.Runtime.ProfileSnapshot.ProfileId,
|
||||
MaxPlayers = server.Runtime.MaxPlayers,
|
||||
});
|
||||
Windows[server] = window;
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
this.ServerPlayers.PlayersCollectionUpdated -= Players_CollectionUpdated;
|
||||
this.ServerPlayers.Players.CollectionChanged -= Players_CollectionChanged;
|
||||
this.ServerPlayers.Dispose();
|
||||
|
||||
if (this.PlayerListParameters?.Server != null)
|
||||
{
|
||||
Windows.TryGetValue(this.PlayerListParameters.Server, out PlayerListWindow window);
|
||||
if (window != null)
|
||||
{
|
||||
Windows.Remove(this.PlayerListParameters.Server);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
public void SortPlayers()
|
||||
{
|
||||
this.PlayerListView.SortDescriptions.Clear();
|
||||
|
||||
switch (this.PlayerSorting)
|
||||
{
|
||||
case PlayerSortType.Name:
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.Online:
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.IsOnline), ListSortDirection.Descending));
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.Tribe:
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.GuildName), ListSortDirection.Ascending));
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.LastOnline:
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.LastOnline), ListSortDirection.Descending));
|
||||
this.PlayerListView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region Filtering
|
||||
private void FilterPlayerList_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PlayerListView?.Refresh();
|
||||
}
|
||||
|
||||
public bool PlayerListFilter(object obj)
|
||||
{
|
||||
var player = obj as PlayerInfo;
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
var result = (this.PlayerFiltering.HasFlag(PlayerFilterType.Online) && player.IsOnline) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Offline) && !player.IsOnline) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Admin) && player.IsAdmin) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Whitelisted) && player.IsWhitelisted) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Invalid) && !player.IsValid);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
var filterString = PlayerListFilterString.ToLower();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filterString))
|
||||
return true;
|
||||
|
||||
result = player.PlatformNameFilterString != null && player.PlatformNameFilterString.Contains(filterString) ||
|
||||
player.GuildNameFilterString != null && player.GuildNameFilterString.Contains(filterString) ||
|
||||
player.CharacterNameFilterString != null && player.CharacterNameFilterString.Contains(filterString);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
173
src/ConanServerManager/Windows/PlayerProfileWindow.xaml
Normal file
173
src/ConanServerManager/Windows/PlayerProfileWindow.xaml
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<Window x:Class="ServerManagerTool.PlayerProfileWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
Width="500" ResizeMode="NoResize" SizeToContent="Height" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Icon="../Art/favicon.ico" Title="{Binding WindowTitle}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:NullValueConverter x:Key="NullValueConverter"/>
|
||||
<cc:UnixTimeToDateTimeConverter x:Key="UnixTimeToDateTimeConverter"/>
|
||||
|
||||
<BitmapImage x:Key="NoAvatar" UriSource="../Art/NoAvatar.png" />
|
||||
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
</Style>
|
||||
<Style x:Key="Online" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Player.IsOnline}" Value="True">
|
||||
<Setter Property="Foreground" Value="Green"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Player.IsOnline}" Value="False">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="CommunityBanned" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PlayerData.CommunityBanned}" Value="False">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding PlayerData.CommunityBanned}" Value="True">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="VACBanned" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PlayerData.VACBanned}" Value="False">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding PlayerData.VACBanned}" Value="True">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="Banned" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Player.IsBanned}" Value="False">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Player.IsBanned}" Value="True">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="Whitelisted" TargetType="{x:Type Label}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Player.IsWhitelisted}" Value="True">
|
||||
<Setter Property="Foreground" Value="Blue"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Player.IsWhitelisted}" Value="False">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<StackPanel Margin="3" CanVerticallyScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Profile_OnlineLabel}"/>
|
||||
<Label Grid.Row="1" Grid.Column="1" Content="{Binding Player.IsOnline}" Style="{DynamicResource Online}"/>
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Profile_LastOnlineLabel}"/>
|
||||
<Label Grid.Row="2" Grid.Column="1" Content="{Binding Player.LastOnline, Converter={StaticResource UnixTimeToDateTimeConverter}}"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox HorizontalAlignment="Stretch" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{DynamicResource Profile_PlayerSectionLabel}" VerticalAlignment="Center" FontWeight="Bold" FontSize="13.333"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="{DynamicResource Profile_IdLabel}"/>
|
||||
<Label Grid.Row="0" Grid.Column="1" Content="{Binding PlayerData.CharacterId}"/>
|
||||
<Label Grid.Row="1" Content="{DynamicResource Profile_NameLabel}"/>
|
||||
<Label Grid.Row="1" Grid.Column="1" Content="{Binding PlayerData.CharacterName}"/>
|
||||
<Label Grid.Row="2" Content="{DynamicResource Profile_LevelLabel}"/>
|
||||
<Label Grid.Row="2" Grid.Column="1" Content="{Binding PlayerData.Level}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox HorizontalAlignment="Stretch">
|
||||
<GroupBox.Header>
|
||||
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{DynamicResource Profile_TribeSectionLabel}" VerticalAlignment="Center" FontWeight="Bold" FontSize="13.333"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<GroupBox.Style>
|
||||
<Style BasedOn="{StaticResource GroupBoxStyle}" TargetType="{x:Type GroupBox}">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PlayerData.GuildId}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</GroupBox.Style>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="{DynamicResource Profile_IdLabel}"/>
|
||||
<Label Grid.Row="0" Grid.Column="1" Content="{Binding GuildData.GuildId}"/>
|
||||
<Label Grid.Row="1" Content="{DynamicResource Profile_NameLabel}"/>
|
||||
<Label Grid.Row="1" Grid.Column="1" Content="{Binding GuildData.GuildName}"/>
|
||||
<Label Grid.Row="2" Content="{DynamicResource Profile_TribeOwnerLabel}"/>
|
||||
<Label Grid.Row="2" Grid.Column="1" Content="{Binding GuildOwner}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
67
src/ConanServerManager/Windows/PlayerProfileWindow.xaml.cs
Normal file
67
src/ConanServerManager/Windows/PlayerProfileWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
using ConanData;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PlayerProfileWindow.xaml
|
||||
/// </summary>
|
||||
public partial class PlayerProfileWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public PlayerProfileWindow(PlayerInfo player, String serverFolder)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.Player = player;
|
||||
this.ServerFolder = serverFolder;
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public PlayerInfo Player
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public String ServerFolder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public PlayerData PlayerData => Player?.PlayerData;
|
||||
|
||||
public GuildData GuildData => Player?.PlayerData?.Guild;
|
||||
|
||||
public Boolean IsGuildOwner => PlayerData != null && GuildData != null && GuildData.OwnerId == PlayerData.CharacterId;
|
||||
|
||||
public String GuildOwner => GuildData != null && GuildData.Owner != null ? $"{GuildData.Owner.CharacterName}" : null;
|
||||
|
||||
public String WindowTitle => String.Format(_globalizer.GetResourceString("Profile_WindowTitle_Player"), Player.PlayerName);
|
||||
|
||||
public ICommand ExplorerLinkCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<String>(
|
||||
execute: (action) =>
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(action)) return;
|
||||
Process.Start("explorer.exe", action);
|
||||
},
|
||||
canExecute: (action) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
src/ConanServerManager/Windows/PluginsWindow.xaml
Normal file
115
src/ConanServerManager/Windows/PluginsWindow.xaml
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<Window x:Class="ServerManagerTool.PluginsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
MinWidth="640" MinHeight="480" Width="640" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource PluginsWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Row="0" HorizontalAlignment="Stretch" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||
<Button Width="22" Height="22" Click="AddPlugin_Click" ToolTip="{DynamicResource PluginsWindow_AddPluginTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Add.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="ClearPlugins_Click" Margin="10,0,0,0" ToolTip="{DynamicResource PluginsWindow_ClearPluginsTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="OpenPluginsFolder_Click" Margin="10,0,0,0" ToolTip="{DynamicResource PluginsWindow_OpenPluginsFolderTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/FolderOpen.ico,Size=32}"/>
|
||||
</Button>
|
||||
<Button Width="22" Height="22" Click="PluginsForum_Click" Margin="20,0,0,0" ToolTip="{DynamicResource PluginsWindow_PluginsForumTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Help.ico,Size=32}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</GroupBox.Header>
|
||||
|
||||
<DataGrid ItemsSource="{Binding PluginHelperInstance.Plugins}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Width="4*" Binding="{Binding Plugin.PluginName}" IsReadOnly="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource PluginsWindow_NameColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="2*" Binding="{Binding PluginType}" IsReadOnly="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource PluginsWindow_TypeColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="1*" Binding="{Binding Plugin.PluginVersion}" IsReadOnly="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource PluginsWindow_VersionColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="ConfigPlugin_Click" ToolTip="{DynamicResource PluginsWindow_ConfigPluginTooltip}">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Plugin.HasConfigForm}" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Settings.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="RemovePlugin_Click" ToolTip="{DynamicResource PluginsWindow_RemovePluginTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Window>
|
||||
124
src/ConanServerManager/Windows/PluginsWindow.xaml.cs
Normal file
124
src/ConanServerManager/Windows/PluginsWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PluginsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class PluginsWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty PluginHelperInstanceProperty = DependencyProperty.Register(nameof(PluginHelperInstance), typeof(PluginHelper), typeof(PluginsWindow));
|
||||
|
||||
public PluginsWindow()
|
||||
{
|
||||
this.PluginHelperInstance = PluginHelper.Instance;
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public PluginHelper PluginHelperInstance
|
||||
{
|
||||
get { return GetValue(PluginHelperInstanceProperty) as PluginHelper; }
|
||||
set { SetValue(PluginHelperInstanceProperty, value); }
|
||||
}
|
||||
|
||||
private void AddPlugin_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog();
|
||||
dialog.Title = GlobalizedApplication.Instance.GetResourceString("PluginsWindow_AddDialogTitle");
|
||||
dialog.DefaultExtension = GlobalizedApplication.Instance.GetResourceString("PluginsWindow_PluginDefaultExtension");
|
||||
dialog.Filters.Add(new CommonFileDialogFilter(GlobalizedApplication.Instance.GetResourceString("PluginsWindow_AddFilterLabel"), GlobalizedApplication.Instance.GetResourceString("PluginsWindow_AddFilterExtension")));
|
||||
if (dialog == null || dialog.ShowDialog(this) != CommonFileDialogResult.Ok)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var installPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
PluginHelperInstance.AddPlugin(installPath, dialog.FileName);
|
||||
}
|
||||
catch (PluginException ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("PluginsWindow_AddErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("PluginsWindow_AddErrorLabel"), _globalizer.GetResourceString("PluginsWindow_AddErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearPlugins_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("PluginsWindow_ClearLabel"), _globalizer.GetResourceString("PluginsWindow_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
PluginHelperInstance.DeleteAllPlugins();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("PluginsWindow_ClearErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigPlugin_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pluginItem = ((PluginItem)((Button)e.Source).DataContext);
|
||||
PluginHelperInstance.OpenConfigForm(pluginItem.Plugin, this);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("PluginsWindow_ConfigErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenPluginsFolder_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start("explorer.exe", PluginHelper.PluginFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("PluginsWindow_OpenErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void PluginsForum_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.ServerManagerPluginUrl);
|
||||
}
|
||||
|
||||
private void RemovePlugin_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("PluginsWindow_DeleteLabel"), _globalizer.GetResourceString("PluginsWindow_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var pluginItem = ((PluginItem)((Button)e.Source).DataContext);
|
||||
PluginHelperInstance.DeletePlugin(pluginItem.PluginFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("PluginsWindow_DeleteErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/ConanServerManager/Windows/ProcessorAffinityWindow.xaml
Normal file
76
src/ConanServerManager/Windows/ProcessorAffinityWindow.xaml
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<Window x:Class="ServerManagerTool.ProcessorAffinityWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:cctl="clr-namespace:ServerManagerTool.Common.Controls;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:cvr="clr-namespace:ServerManagerTool.Common.ValidationRules;assembly=ServerManager.Common"
|
||||
MinWidth="300" MinHeight="200" Width="300" Height="300" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResize"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource ProcessorAffinity_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:InvertBooleanConverter x:Key="InvertBooleanConverter"/>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" Margin="5,5,5,0" Text="{DynamicResource ProcessorAffinity_InstructionLabel}" VerticalAlignment="Center" TextWrapping="Wrap" />
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="5,5,5,0" VerticalAlignment="Center" HorizontalAlignment="Left" Content="{DynamicResource ProcessorAffinity_AllCpuLabel}" IsChecked="{Binding ProcessorAffinityList.AllProcessors, Mode=TwoWay}" ToolTip="{DynamicResource ProcessorAffinity_AllCpuTooltip}"/>
|
||||
|
||||
<DataGrid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" Name="ModDetailsGrid" ItemsSource="{Binding ProcessorAffinityList}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" RowHeaderWidth="0" SelectionMode="Single" IsEnabled="{Binding ProcessorAffinityList.AllProcessors, Converter={StaticResource InvertBooleanConverter}}">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Width="Auto" Binding="{Binding Selected, Mode=TwoWay}">
|
||||
<DataGridCheckBoxColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ProcessorAffinity_SelectedColumnLabel}" />
|
||||
</DataGridCheckBoxColumn.Header>
|
||||
</DataGridCheckBoxColumn>
|
||||
<DataGridTextColumn Width="*" Binding="{Binding Description, Mode=OneWay}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ProcessorAffinity_DescriptionColumnLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Button Grid.Row="3" Grid.Column="0" Content="{DynamicResource ProcessorAffinity_SelectAllButtonLabel}" Margin="5" MinWidth="40" HorizontalAlignment="Right" Click="SelectAll_Click" IsEnabled="{Binding ProcessorAffinityList.AllProcessors, Converter={StaticResource InvertBooleanConverter}}"/>
|
||||
<Button Grid.Row="3" Grid.Column="1" Content="{DynamicResource ProcessorAffinity_UnselectAllButtonLabel}" Margin="5" MinWidth="40" HorizontalAlignment="Right" Click="UnselectAll_Click" IsEnabled="{Binding ProcessorAffinityList.AllProcessors, Converter={StaticResource InvertBooleanConverter}}"/>
|
||||
<Button Grid.Row="3" Grid.Column="2" Content="{DynamicResource ProcessorAffinity_ProcessButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" Click="Process_Click"/>
|
||||
<Button Grid.Row="3" Grid.Column="3" Content="{DynamicResource ProcessorAffinity_CancelButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System.Numerics;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ProcessorAffinityWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ProcessorAffinityWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty ProcessorAffinityListProperty = DependencyProperty.Register(nameof(ProcessorAffinityList), typeof(ProcessorAffinityList), typeof(ProcessorAffinityWindow), new PropertyMetadata(null));
|
||||
public ProcessorAffinityList ProcessorAffinityList
|
||||
{
|
||||
get { return (ProcessorAffinityList)GetValue(ProcessorAffinityListProperty); }
|
||||
set { SetValue(ProcessorAffinityListProperty, value); }
|
||||
}
|
||||
|
||||
public ProcessorAffinityWindow(string profileName, BigInteger affinityValue)
|
||||
{
|
||||
AffinityValue = affinityValue;
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.Title = string.Format(_globalizer.GetResourceString("ProcessorAffinity_ProfileTitle"), profileName);
|
||||
this.ProcessorAffinityList = new ProcessorAffinityList(affinityValue);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public BigInteger AffinityValue
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private void Process_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AffinityValue = this.ProcessorAffinityList.AffinityValue;
|
||||
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SelectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var item in ProcessorAffinityList)
|
||||
{
|
||||
item.Selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnselectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var item in ProcessorAffinityList)
|
||||
{
|
||||
item.Selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/ConanServerManager/Windows/ProfileSyncWindow.xaml
Normal file
124
src/ConanServerManager/Windows/ProfileSyncWindow.xaml
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<Window x:Class="ServerManagerTool.ProfileSyncWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
MinWidth="400" MinHeight="640" Width="640" Height="500" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResize"
|
||||
Loaded="Window_Loaded"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource ProfileSyncWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,0" Text="{DynamicResource ProfileSyncWindow_SyncInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold"/>
|
||||
|
||||
<ListView Grid.Row="2" Grid.Column="0" Margin="5,5,5,0" ItemsSource="{Binding SyncSections}" HorizontalContentAlignment="Stretch">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Width="Auto">
|
||||
<GridViewColumnHeader>
|
||||
<TextBlock Text="{DynamicResource ProfileSyncWindow_SelectedColumnLabel}" />
|
||||
</GridViewColumnHeader>
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding Selected}" HorizontalAlignment="Center"/>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Width="330" DisplayMemberBinding="{Binding SectionName}">
|
||||
<GridViewColumnHeader HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Padding="5,0,0,0">
|
||||
<TextBlock Text="{DynamicResource ProfileSyncWindow_SectionNameColumnLabel}" />
|
||||
</GridViewColumnHeader>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ListViewItem}" >
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Background" Value="White" />
|
||||
<Setter Property="Height" Value="20" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
</ListView>
|
||||
|
||||
<ListView Grid.Row="2" Grid.Column="1" Margin="5,5,5,0" ItemsSource="{Binding SyncProfiles}" HorizontalContentAlignment="Stretch">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Width="Auto">
|
||||
<GridViewColumnHeader>
|
||||
<TextBlock Text="{DynamicResource ProfileSyncWindow_SelectedColumnLabel}" />
|
||||
</GridViewColumnHeader>
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding Selected}" HorizontalAlignment="Center"/>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Width="330" DisplayMemberBinding="{Binding ProfileName}">
|
||||
<GridViewColumnHeader HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Padding="5,0,0,0">
|
||||
<TextBlock Text="{DynamicResource ProfileSyncWindow_ProfileNameColumnLabel}" />
|
||||
</GridViewColumnHeader>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ListViewItem}" >
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Background" Value="White" />
|
||||
<Setter Property="Height" Value="20" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
</ListView>
|
||||
|
||||
<DockPanel Grid.Row="3" Grid.Column="0">
|
||||
<Button DockPanel.Dock="Left" Content="{DynamicResource ProfileSyncWindow_SelectAllButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" Click="SectionSelectAll_Click"/>
|
||||
<Button DockPanel.Dock="Left" Content="{DynamicResource ProfileSyncWindow_UnselectAllButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" Click="SectionUnselectAll_Click"/>
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Grid.Row="3" Grid.Column="1">
|
||||
<Button DockPanel.Dock="Left" Content="{DynamicResource ProfileSyncWindow_SelectAllButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" Click="ProfileSelectAll_Click"/>
|
||||
<Button DockPanel.Dock="Left" Content="{DynamicResource ProfileSyncWindow_UnselectAllButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" Click="ProfileUnselectAll_Click"/>
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2">
|
||||
<Button DockPanel.Dock="Right" Content="{DynamicResource ProfileSyncWindow_CloseButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" IsCancel="True"/>
|
||||
<Button DockPanel.Dock="Right" Content="{DynamicResource ProfileSyncWindow_ProcessButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" Click="Process_Click"/>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- It's important that this is in the end of the XAML as it needs to be on top of everything else! -->
|
||||
<Grid x:Name="OverlayGrid" Visibility="Collapsed" DockPanel.Dock="Top" >
|
||||
<Grid Background="Black" Opacity="0.5"/>
|
||||
<Border MinWidth="250" Background="Orange" BorderBrush="Black" BorderThickness="1" CornerRadius="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label x:Name="OverlayProfile" Grid.Row="0" Margin="5,0,5,1" FontWeight="Bold" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" />
|
||||
<Label x:Name="OverlaySection" Grid.Row="1" Margin="5,1,5,0" FontWeight="Bold" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
250
src/ConanServerManager/Windows/ProfileSyncWindow.xaml.cs
Normal file
250
src/ConanServerManager/Windows/ProfileSyncWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ProfileSyncWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ProfileSyncWindow : Window
|
||||
{
|
||||
public class SyncProfile : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(nameof(Selected), typeof(bool), typeof(SyncProfile), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty ProfileNameProperty = DependencyProperty.Register(nameof(ProfileName), typeof(string), typeof(SyncProfile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty ProfileProperty = DependencyProperty.Register(nameof(Profile), typeof(ServerProfile), typeof(SyncProfile), new PropertyMetadata(null));
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get { return (bool)GetValue(SelectedProperty); }
|
||||
set { SetValue(SelectedProperty, value); }
|
||||
}
|
||||
public string ProfileName
|
||||
{
|
||||
get { return (string)GetValue(ProfileNameProperty); }
|
||||
set { SetValue(ProfileNameProperty, value); }
|
||||
}
|
||||
public ServerProfile Profile
|
||||
{
|
||||
get { return (ServerProfile)GetValue(ProfileProperty); }
|
||||
set { SetValue(ProfileProperty, value); }
|
||||
}
|
||||
}
|
||||
|
||||
public class SyncSection : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(nameof(Selected), typeof(bool), typeof(SyncSection), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty SectionNameProperty = DependencyProperty.Register(nameof(SectionName), typeof(string), typeof(SyncSection), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty CategoryProperty = DependencyProperty.Register(nameof(Category), typeof(ServerProfileCategory), typeof(SyncSection));
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get { return (bool)GetValue(SelectedProperty); }
|
||||
set { SetValue(SelectedProperty, value); }
|
||||
}
|
||||
public string SectionName
|
||||
{
|
||||
get { return (string)GetValue(SectionNameProperty); }
|
||||
set { SetValue(SectionNameProperty, value); }
|
||||
}
|
||||
public ServerProfileCategory Category
|
||||
{
|
||||
get { return (ServerProfileCategory)GetValue(CategoryProperty); }
|
||||
set { SetValue(CategoryProperty, value); }
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty SyncProfilesProperty = DependencyProperty.Register(nameof(SyncProfiles), typeof(ObservableCollection<SyncProfile>), typeof(ProfileSyncWindow), new PropertyMetadata(new ObservableCollection<SyncProfile>()));
|
||||
public static readonly DependencyProperty SyncSectionsProperty = DependencyProperty.Register(nameof(SyncSections), typeof(ObservableCollection<SyncSection>), typeof(ProfileSyncWindow), new PropertyMetadata(new ObservableCollection<SyncSection>()));
|
||||
|
||||
public ProfileSyncWindow(ServerManager serverManager, ServerProfile serverProfile)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
OverlayGrid.Visibility = Visibility.Collapsed;
|
||||
|
||||
this.Title = string.Format(_globalizer.GetResourceString("ProfileSyncWindow_ProfileTitle"), serverProfile?.ProfileName);
|
||||
|
||||
this.ServerManager = serverManager;
|
||||
this.ServerProfile = serverProfile;
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public ServerManager ServerManager
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ServerProfile ServerProfile
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ObservableCollection<SyncProfile> SyncProfiles
|
||||
{
|
||||
get { return (ObservableCollection<SyncProfile>)GetValue(SyncProfilesProperty); }
|
||||
set { SetValue(SyncProfilesProperty, value); }
|
||||
}
|
||||
|
||||
public ObservableCollection<SyncSection> SyncSections
|
||||
{
|
||||
get { return (ObservableCollection<SyncSection>)GetValue(SyncSectionsProperty); }
|
||||
set { SetValue(SyncSectionsProperty, value); }
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
CreateSyncProfileList();
|
||||
CreateSyncSectionList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ProfileSyncWindow_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Process_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
if (!SyncProfiles.Any(s => s.Selected))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("ProfileSyncWindow_Process_NoProfilesSelectedLabel"), _globalizer.GetResourceString("ProfileSyncWindow_Process_Title"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SyncSections.Any(s => s.Selected))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("ProfileSyncWindow_Process_NoSectionsSelectedLabel"), _globalizer.GetResourceString("ProfileSyncWindow_Process_Title"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ProfileSyncWindow_Process_ConfirmLabel"), _globalizer.GetResourceString("ProfileSyncWindow_Process_Title"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
|
||||
OverlayProfile.Content = string.Empty;
|
||||
OverlaySection.Content = string.Empty;
|
||||
OverlayGrid.Visibility = Visibility.Visible;
|
||||
await Task.Delay(100);
|
||||
|
||||
await PerformProfileSync();
|
||||
|
||||
MessageBox.Show(_globalizer.GetResourceString("ProfileSyncWindow_Process_SuccessLabel"), _globalizer.GetResourceString("ProfileSyncWindow_Process_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ProfileSyncWindow_Process_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
OverlayGrid.Visibility = Visibility.Collapsed;
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileSelectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var profile in SyncProfiles)
|
||||
{
|
||||
profile.Selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileUnselectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var profile in SyncProfiles)
|
||||
{
|
||||
profile.Selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SectionSelectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var section in SyncSections)
|
||||
{
|
||||
section.Selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SectionUnselectAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var section in SyncSections)
|
||||
{
|
||||
section.Selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSyncProfileList()
|
||||
{
|
||||
SyncProfiles.Clear();
|
||||
|
||||
if (this.ServerManager == null || this.ServerManager.Servers == null)
|
||||
return;
|
||||
|
||||
foreach (var server in this.ServerManager.Servers)
|
||||
{
|
||||
if (server.Profile == ServerProfile)
|
||||
continue;
|
||||
|
||||
SyncProfiles.Add(new SyncProfile() { Selected = false, Profile = server.Profile, ProfileName = server.Profile.ProfileName });
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSyncSectionList()
|
||||
{
|
||||
SyncSections.Clear();
|
||||
|
||||
SyncSections.Add(new SyncSection() { Selected = false, Category = ServerProfileCategory.Administration, SectionName = _globalizer.GetResourceString("ServerSettings_AdministrationSectionLabel") });
|
||||
SyncSections.Add(new SyncSection() { Selected = false, Category = ServerProfileCategory.AutomaticManagement, SectionName = _globalizer.GetResourceString("ServerSettings_AutomaticManagementLabel") });
|
||||
SyncSections.Add(new SyncSection() { Selected = false, Category = ServerProfileCategory.ServerFiles, SectionName = _globalizer.GetResourceString("ServerSettings_ServerFilesLabel") });
|
||||
}
|
||||
|
||||
private async Task PerformProfileSync()
|
||||
{
|
||||
foreach (var syncProfile in SyncProfiles)
|
||||
{
|
||||
if (!syncProfile.Selected)
|
||||
continue;
|
||||
|
||||
OverlayProfile.Content = syncProfile.ProfileName ?? string.Empty;
|
||||
|
||||
bool updateSchedules = false;
|
||||
|
||||
foreach (var syncSection in SyncSections)
|
||||
{
|
||||
if (!syncSection.Selected)
|
||||
continue;
|
||||
|
||||
OverlaySection.Content = syncSection.SectionName;
|
||||
await Task.Delay(100);
|
||||
|
||||
syncProfile.Profile?.SyncSettings(syncSection.Category, ServerProfile);
|
||||
|
||||
if (syncSection.Category == ServerProfileCategory.AutomaticManagement)
|
||||
updateSchedules = true;
|
||||
}
|
||||
|
||||
syncProfile.Profile?.Save(false, updateSchedules, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/ConanServerManager/Windows/ProgressWindow.xaml
Normal file
28
src/ConanServerManager/Windows/ProgressWindow.xaml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<Window x:Class="ServerManagerTool.ProgressWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Width="640" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Closing="Window_Closing"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource Progress_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="400*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Name="MessageOutput" Grid.Row="0" HorizontalAlignment="Stretch" IsReadOnly="True" IsReadOnlyCaretVisible="True" TextWrapping="NoWrap" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="5"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
53
src/ConanServerManager/Windows/ProgressWindow.xaml.cs
Normal file
53
src/ConanServerManager/Windows/ProgressWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ProgressWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ProgressWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private bool _allowClose = false;
|
||||
|
||||
public ProgressWindow(string windowTitle)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(windowTitle))
|
||||
Title = windowTitle;
|
||||
Application.Current.Dispatcher.Invoke(() => MessageOutput.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
|
||||
_allowClose = false;
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public void AddMessage(string message, bool includeNewLine = true)
|
||||
{
|
||||
MessageOutput.AppendText(message);
|
||||
if (includeNewLine)
|
||||
MessageOutput.AppendText(Environment.NewLine);
|
||||
MessageOutput.ScrollToEnd();
|
||||
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
public void CloseWindow()
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => MessageOutput.Cursor = null);
|
||||
|
||||
_allowClose = true;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (!_allowClose)
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
284
src/ConanServerManager/Windows/RconWindow.xaml
Normal file
284
src/ConanServerManager/Windows/RconWindow.xaml
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
<Window x:Class="ServerManagerTool.RconWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:sm="clr-namespace:ServerManagerTool"
|
||||
xmlns:en="clr-namespace:ServerManagerTool.Enums"
|
||||
xmlns:vm="clr-namespace:ServerManagerTool.Lib.ViewModel"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
Width="1024" Height="768" MinWidth="640" MinHeight="480" ResizeMode="CanResizeWithGrip"
|
||||
SizeChanged="RCON_SizeChanged" LocationChanged="RCON_LocationChanged"
|
||||
Name="RCON" Icon="../Art/favicon.ico" Title="{Binding RconParameters.WindowTitle}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<sm:ScrollToBottomAction x:Key="ScrollToBottomAction" />
|
||||
<cc:EnumConverter x:Key="EnumConverter"/>
|
||||
<cc:EnumFlagsConverter x:Key="EnumFlagsConverter"/>
|
||||
<cc:IsNullOrWhiteSpaceValueConverter x:Key="IsNullOrWhiteSpaceValueConverter"/>
|
||||
<cc:IsNullValueConverter x:Key="IsNullValueConverter"/>
|
||||
<cc:NullValueConverter x:Key="NullValueConverter"/>
|
||||
|
||||
<SolidColorBrush x:Key="HeaderBrush" Color="#FFF0F0F0"/>
|
||||
|
||||
<Style x:Key="PlayerStatus" TargetType="Border">
|
||||
<Setter Property="BorderBrush" Value="Gray"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsOnline}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="LightGreen"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsOnline}" Value="False" />
|
||||
<Condition Binding="{Binding IsValid}" Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="BorderBrush" Value="Orange"/>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsOnline}" Value="False" />
|
||||
<Condition Binding="{Binding IsWhitelisted}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="BorderBrush" Value="#0066CC"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="GuildName" TargetType="Label">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding GuildName, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="True">
|
||||
<Setter Property="Content" Value="No clan"/>
|
||||
<Setter Property="FontStyle" Value="Italic"/>
|
||||
<Setter Property="Foreground" Value="LightGray"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding GuildName, Converter={StaticResource IsNullOrWhiteSpaceValueConverter}}" Value="False">
|
||||
<Setter Property="Content" Value="{Binding PlayerData.Guild.GuildName}"/>
|
||||
<Setter Property="FontStyle" Value="Normal"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<ObjectDataProvider MethodName="GetValues"
|
||||
ObjectType="{x:Type sys:Enum}"
|
||||
x:Key="InputModes">
|
||||
<ObjectDataProvider.MethodParameters>
|
||||
<x:Type TypeName="sm:InputMode" />
|
||||
</ObjectDataProvider.MethodParameters>
|
||||
</ObjectDataProvider>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid x:Name="dockPanel">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MinWidth="200" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="200" MinWidth="200" x:Name="playerListColumn" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" BorderThickness="1" BorderBrush="LightGray" Margin="2" Background="{StaticResource HeaderBrush}">
|
||||
<DockPanel Margin="2,2,2,1" LastChildFill="False">
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Left">
|
||||
<Menu VerticalAlignment="Center" Margin="1" Background="{StaticResource HeaderBrush}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_File}" VerticalAlignment="Stretch">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_ViewLogs}" Command="{Binding ViewLogsCommand}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_ClearLogs}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Confirm}" Command="{Binding ClearLogsCommand}"/>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Menu VerticalAlignment="Center" Margin="1" Background="{StaticResource HeaderBrush}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Console}" VerticalAlignment="Stretch">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_AutoScroll}" IsCheckable="True" IsChecked="{Binding ScrollOnNewInput}"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Menu VerticalAlignment="Center" Margin="1" Background="{StaticResource HeaderBrush}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Players}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Sort}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortOnline}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Online}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Online}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortName}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Name}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Name}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortTribe}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.Tribe}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=Tribe}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_SortLastOnline}" IsCheckable="True" Command="{Binding SortPlayersCommand}" CommandParameter="{x:Static en:PlayerSortType.LastOnline}" IsChecked="{Binding PlayerSorting, Converter={StaticResource EnumConverter}, ConverterParameter=LastOnline}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_Filter}">
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterOnline}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Online}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Online, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterOffline}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Offline}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Offline, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterWhitelisted}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Whitelisted}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Whitelisted, Mode=OneWay}"/>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_FilterInvalid}" IsCheckable="True" Command="{Binding FilterPlayersCommand}" CommandParameter="{x:Static en:PlayerFilterType.Invalid}" IsChecked="{Binding PlayerFiltering, Converter={StaticResource EnumFlagsConverter}, ConverterParameter=Invalid, Mode=OneWay}"/>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
|
||||
<Label Content="{DynamicResource RCON_PlayersLabel}" Margin="5,0,0,0"/>
|
||||
<Label Content="{Binding ServerRcon.CountOnlinePlayers, FallbackValue=0}"/>
|
||||
<Label Content="{DynamicResource RCON_PlayersSeparatorLabel}" Name="PlayerCountSeparator"/>
|
||||
<Label Content="{Binding RconParameters.MaxPlayers, FallbackValue=0}" Name="MaxPlayerLabel"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<RichTextBox Grid.Row="1" Grid.Column="0" BorderBrush="LightGray" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Visible" Margin="2,1,0,1" HorizontalScrollBarVisibility="Auto" IsReadOnlyCaretVisible="True" IsReadOnly="True" IsTabStop="False">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="TextChanged" >
|
||||
<sm:ScrollToBottomAction IsEnabled="{Binding ScrollOnNewInput}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<RichTextBox.Resources>
|
||||
<Style TargetType="{x:Type Paragraph}">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_Command}">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_NoResponse}">
|
||||
<Setter Property="FontStyle" Value="Italic"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_CommandOutput}">
|
||||
<Setter Property="FontStyle" Value="Normal"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_CommandTime}">
|
||||
<Setter Property="FontStyle" Value="Normal"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_ConnectionChanged}">
|
||||
<Setter Property="FontStyle" Value="Italic"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_Broadcast}">
|
||||
<Setter Property="FontStyle" Value="Normal"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type sm:RconOutput_Comment}">
|
||||
<Setter Property="FontStyle" Value="Italic"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
</Style>
|
||||
</RichTextBox.Resources>
|
||||
<FlowDocument Name="ConsoleContent"/>
|
||||
</RichTextBox>
|
||||
|
||||
<GridSplitter Grid.Row="1" Grid.Column="1" Width="5" ShowsPreview="True" HorizontalAlignment="Center" VerticalAlignment="Stretch" Opacity="0"/>
|
||||
|
||||
<DockPanel x:Name="playerListPanel" Grid.Row="1" Grid.Column="2" Margin="0,1,2,1" DataContext="{Binding}" SizeChanged="PlayerList_SizeChanged">
|
||||
<DockPanel DockPanel.Dock="Top">
|
||||
<Label DockPanel.Dock="Left" Content="{DynamicResource General_FilterLabel}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Button DockPanel.Dock="Right" Margin="5,0,5,0" Width="22" Height="22" HorizontalAlignment="Right" VerticalAlignment="Center" Click="FilterPlayerList_Click" ToolTip="{DynamicResource General_FilterButtonTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Filter.ico,Size=32}"/>
|
||||
</Button>
|
||||
<TextBox DockPanel.Dock="Left" Text="{Binding PlayerFilterString, Mode=TwoWay}" BorderBrush="LightGray" VerticalAlignment="Center" VerticalContentAlignment="Center" IsTabStop="True" Margin="0" Padding="2"/>
|
||||
</DockPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource RCON_ProfileCountLabel}" HorizontalAlignment="Center"/>
|
||||
<Label Content="{Binding ServerRcon.CountPlayers, FallbackValue=0}" HorizontalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource RCON_ProfileInvalidCountLabel}" HorizontalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ServerRcon.CountInvalidPlayers, FallbackValue=0, Converter={cc:GreaterThanIntValueConverter 0}}" Value="true">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
<Label Content="{Binding ServerRcon.CountInvalidPlayers, FallbackValue=0}" HorizontalAlignment="Center">
|
||||
<Label.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ServerRcon.CountInvalidPlayers, FallbackValue=0, Converter={cc:GreaterThanIntValueConverter 0}}" Value="true">
|
||||
<Setter Property="Foreground" Value="Red"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Label.Style>
|
||||
</Label>
|
||||
</StackPanel>
|
||||
|
||||
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding ServerRcon.Players}" BorderBrush="LightGray" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||
<ListBox.Resources>
|
||||
<clib:BindingProxy x:Key="proxy" Data="{Binding ElementName=RCON}"/>
|
||||
</ListBox.Resources>
|
||||
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="ContextMenu">
|
||||
<Setter.Value>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_ViewProfile}" Command="{Binding Source={StaticResource proxy}, Path=Data.ViewPlayerProfileCommand}" CommandParameter="{Binding}" />
|
||||
<MenuItem Header="{DynamicResource RCON_Menu_ViewTribe}" Command="{Binding Source={StaticResource proxy}, Path=Data.ViewPlayerTribeCommand}" CommandParameter="{Binding}"/>
|
||||
</ContextMenu>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:PlayerInfo}">
|
||||
<Border BorderThickness="2" Padding="1" Style="{DynamicResource PlayerStatus}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch" ToolTip="{Binding PlayerId}">
|
||||
<StackPanel Orientation="Horizontal" Margin="0" >
|
||||
<Label Content="{Binding CharacterName}" Padding="0,-1,0,-1"/>
|
||||
<TextBlock Text="{Binding PlayerData.Level, StringFormat=({0})}" Margin="5,0,0,0" Padding="0,-1,0,-1" />
|
||||
</StackPanel>
|
||||
<Label Padding="0,-1,0,-1" Style="{DynamicResource GuildName}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Margin="2,1,2,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Content="{DynamicResource RCON_ModeLabel}"/>
|
||||
<ComboBox Name="InputModesComboBox" Grid.Column="1" ItemsSource="{Binding Source={StaticResource InputModes}}" SelectedItem="{Binding CurrentInputMode, Mode=TwoWay}" Margin="0,0,2,0"/>
|
||||
<TextBox Name="ConsoleInput" TabIndex="0" Grid.Column="2" KeyUp="ConsoleInput_KeyUp" BorderBrush="LightGray" VerticalContentAlignment="Center" IsTabStop="True"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- It's important that this is in the end of the XAML as it needs to be on top of everything else! -->
|
||||
<Grid x:Name="inputBox" Visibility="Collapsed" DockPanel.Dock="Top" >
|
||||
<Grid Background="Black" Opacity="0.5"/>
|
||||
<Border MinWidth="250" Background="Orange" BorderBrush="Black" BorderThickness="1" CornerRadius="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="inputTitle" Margin="5" FontWeight="Bold" />
|
||||
<TextBox x:Name="inputTextBox" MinWidth="150" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,0,5,0" MaxLength="200"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button x:Name="button1" Margin="5" Content="{DynamicResource RCON_Button_OK}" Background="{x:Null}" Command="{Binding Button1Command}" CommandParameter="{Binding}"/>
|
||||
<Button x:Name="button2" Margin="5" Content="{DynamicResource RCON_Button_Cancel}" Background="{x:Null}" Command="{Binding Button2Command}" CommandParameter="{Binding}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
896
src/ConanServerManager/Windows/RconWindow.xaml.cs
Normal file
896
src/ConanServerManager/Windows/RconWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,896 @@
|
|||
using ServerManagerTool.Common.Enums;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interactivity;
|
||||
using System.Windows.Media;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
|
||||
public enum InputMode
|
||||
{
|
||||
Command,
|
||||
//Global,
|
||||
Broadcast,
|
||||
}
|
||||
|
||||
public enum InputWindowMode
|
||||
{
|
||||
None,
|
||||
ServerChatTo,
|
||||
RenamePlayer,
|
||||
RenameTribe,
|
||||
}
|
||||
|
||||
public class ScrollToBottomAction : TriggerAction<RichTextBox>
|
||||
{
|
||||
protected override void Invoke(object parameter)
|
||||
{
|
||||
AssociatedObject.ScrollToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_CommandTime : Run
|
||||
{
|
||||
public RconOutput_CommandTime()
|
||||
: this(DateTime.Now)
|
||||
{
|
||||
}
|
||||
|
||||
public RconOutput_CommandTime(DateTime time)
|
||||
: base($"[{time.ToString("g")}] ")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_TimedCommand : Span
|
||||
{
|
||||
protected RconOutput_TimedCommand()
|
||||
: base()
|
||||
{
|
||||
base.Inlines.Add(new RconOutput_CommandTime());
|
||||
}
|
||||
|
||||
public RconOutput_TimedCommand(Inline output)
|
||||
: this()
|
||||
{
|
||||
base.Inlines.Add(output);
|
||||
}
|
||||
|
||||
public RconOutput_TimedCommand(string output)
|
||||
: this(new Run(output))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_Comment : Run
|
||||
{
|
||||
public RconOutput_Comment(string value)
|
||||
: base(value)
|
||||
{
|
||||
Foreground = Brushes.Green;
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_ChatSend : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_ChatSend(string target, string output)
|
||||
: base($"[{target}] {output}")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_Broadcast : RconOutput_ChatSend
|
||||
{
|
||||
public RconOutput_Broadcast(string output)
|
||||
: base("ALL", output)
|
||||
{
|
||||
Foreground = Brushes.Orange;
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_ConnectionChanged : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_ConnectionChanged(bool isConnected)
|
||||
: base(isConnected ? GlobalizedApplication.Instance.GetResourceString("RCON_ConnectionEstablishedLabel") : GlobalizedApplication.Instance.GetResourceString("RCON_ConnectionLostLabel"))
|
||||
{
|
||||
Foreground = Brushes.Orange;
|
||||
}
|
||||
}
|
||||
|
||||
public class RconOutput_Command : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_Command(string text)
|
||||
: base(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public class RconOutput_NoResponse : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_NoResponse()
|
||||
: base(GlobalizedApplication.Instance.GetResourceString("RCON_NoCommandResponseLabel"))
|
||||
{
|
||||
Foreground = Brushes.LightGray;
|
||||
}
|
||||
};
|
||||
|
||||
public class RconOutput_CommandOutput : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_CommandOutput(string text)
|
||||
: base(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public class RconOutput_PlayerJoined : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_PlayerJoined(string text)
|
||||
: base(text)
|
||||
{
|
||||
Foreground = new SolidColorBrush(Color.FromArgb(255, 85, 142, 181));
|
||||
}
|
||||
};
|
||||
|
||||
public class RconOutput_PlayerLeft : RconOutput_TimedCommand
|
||||
{
|
||||
public RconOutput_PlayerLeft(string text)
|
||||
: base(text)
|
||||
{
|
||||
Foreground = new SolidColorBrush(Color.FromArgb(255, 62, 104, 132));
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for RconWindow.xaml
|
||||
/// </summary>
|
||||
public partial class RconWindow : Window
|
||||
{
|
||||
private static Dictionary<Server, RconWindow> RconWindows = new Dictionary<Server, RconWindow>();
|
||||
|
||||
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(RconWindow), new PropertyMetadata(Config.Default));
|
||||
public static readonly DependencyProperty CurrentInputModeProperty = DependencyProperty.Register(nameof(CurrentInputMode), typeof(InputMode), typeof(RconWindow), new PropertyMetadata(InputMode.Command));
|
||||
public static readonly DependencyProperty PlayerFilteringProperty = DependencyProperty.Register(nameof(PlayerFiltering), typeof(PlayerFilterType), typeof(RconWindow), new PropertyMetadata(PlayerFilterType.Online | PlayerFilterType.Offline));
|
||||
public static readonly DependencyProperty PlayerFilterStringProperty = DependencyProperty.Register(nameof(PlayerFilterString), typeof(string), typeof(RconWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty PlayerSortingProperty = DependencyProperty.Register(nameof(PlayerSorting), typeof(PlayerSortType), typeof(RconWindow), new PropertyMetadata(PlayerSortType.Online));
|
||||
public static readonly DependencyProperty PlayersViewProperty = DependencyProperty.Register(nameof(PlayersView), typeof(ICollectionView), typeof(RconWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty RconParametersProperty = DependencyProperty.Register(nameof(RconParameters), typeof(RconParameters), typeof(RconWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ScrollOnNewInputProperty = DependencyProperty.Register(nameof(ScrollOnNewInput), typeof(bool), typeof(RconWindow), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty ServerRconProperty = DependencyProperty.Register(nameof(ServerRcon), typeof(ServerRcon), typeof(RconWindow), new PropertyMetadata(null));
|
||||
|
||||
public RconWindow(RconParameters parameters)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.CurrentInputWindowMode = InputWindowMode.None;
|
||||
this.PlayerFiltering = (PlayerFilterType)Config.Default.RCON_PlayerListFilter;
|
||||
this.PlayerSorting = (PlayerSortType)Config.Default.RCON_PlayerListSort;
|
||||
this.RconParameters = parameters;
|
||||
this.ServerRcon = new ServerRcon(parameters);
|
||||
this.ServerRcon.RegisterCommandListener(RenderRCONCommandOutput);
|
||||
this.ServerRcon.Players.CollectionChanged += Players_CollectionChanged;
|
||||
this.ServerRcon.PlayersCollectionUpdated += Players_CollectionUpdated;
|
||||
|
||||
this.PlayersView = CollectionViewSource.GetDefaultView(this.ServerRcon.Players);
|
||||
this.PlayersView.Filter = new Predicate<object>(PlayerFilter);
|
||||
|
||||
if (this.RconParameters?.Server?.Runtime != null)
|
||||
{
|
||||
this.RconParameters.Server.Runtime.StatusUpdate += Runtime_StatusUpdate;
|
||||
}
|
||||
|
||||
if (this.RconParameters?.Server == null)
|
||||
{
|
||||
this.PlayerCountSeparator.Visibility = Visibility.Collapsed;
|
||||
this.MaxPlayerLabel.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
this.DataContext = this;
|
||||
|
||||
RenderCommentsBlock(
|
||||
_globalizer.GetResourceString("RCON_Comments_Line1"),
|
||||
_globalizer.GetResourceString("RCON_Comments_Line2"),
|
||||
_globalizer.GetResourceString("RCON_Comments_Line3"),
|
||||
_globalizer.GetResourceString("RCON_Comments_Line4"),
|
||||
_globalizer.GetResourceString("RCON_Comments_Line5"),
|
||||
String.Format(_globalizer.GetResourceString("RCON_Comments_Line6"), _globalizer.GetResourceString("RCON_Help_Keyword"))
|
||||
);
|
||||
|
||||
if (this.RconParameters.WindowExtents.Width > 50 && this.RconParameters.WindowExtents.Height > 50)
|
||||
{
|
||||
this.Left = this.RconParameters.WindowExtents.Left;
|
||||
this.Top = this.RconParameters.WindowExtents.Top;
|
||||
this.Width = this.RconParameters.WindowExtents.Width;
|
||||
this.Height = this.RconParameters.WindowExtents.Height;
|
||||
|
||||
//
|
||||
// Fix issues where the console was saved while offscreen.
|
||||
if(this.Left == -32000)
|
||||
{
|
||||
this.Left = 0;
|
||||
}
|
||||
|
||||
if(this.Top == -32000)
|
||||
{
|
||||
this.Top = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SetPlayerListWidth(this.RconParameters.PlayerListWidth);
|
||||
|
||||
this.ConsoleInput.Focus();
|
||||
|
||||
// hook into the language change event
|
||||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public Config Config
|
||||
{
|
||||
get { return (Config)GetValue(ConfigProperty); }
|
||||
set { SetValue(ConfigProperty, value); }
|
||||
}
|
||||
|
||||
public InputMode CurrentInputMode
|
||||
{
|
||||
get { return (InputMode)GetValue(CurrentInputModeProperty); }
|
||||
set { SetValue(CurrentInputModeProperty, value); }
|
||||
}
|
||||
|
||||
public PlayerFilterType PlayerFiltering
|
||||
{
|
||||
get { return (PlayerFilterType)GetValue(PlayerFilteringProperty); }
|
||||
set { SetValue(PlayerFilteringProperty, value); }
|
||||
}
|
||||
|
||||
public string PlayerFilterString
|
||||
{
|
||||
get { return (string)GetValue(PlayerFilterStringProperty); }
|
||||
set { SetValue(PlayerFilterStringProperty, value); }
|
||||
}
|
||||
|
||||
public PlayerSortType PlayerSorting
|
||||
{
|
||||
get { return (PlayerSortType)GetValue(PlayerSortingProperty); }
|
||||
set { SetValue(PlayerSortingProperty, value); }
|
||||
}
|
||||
|
||||
public ICollectionView PlayersView
|
||||
{
|
||||
get { return (ICollectionView)GetValue(PlayersViewProperty); }
|
||||
set { SetValue(PlayersViewProperty, value); }
|
||||
}
|
||||
|
||||
public RconParameters RconParameters
|
||||
{
|
||||
get { return (RconParameters)GetValue(RconParametersProperty); }
|
||||
set { SetValue(RconParametersProperty, value); }
|
||||
}
|
||||
|
||||
public bool ScrollOnNewInput
|
||||
{
|
||||
get { return (bool)GetValue(ScrollOnNewInputProperty); }
|
||||
set { SetValue(ScrollOnNewInputProperty, value); }
|
||||
}
|
||||
|
||||
public ServerRcon ServerRcon
|
||||
{
|
||||
get { return (ServerRcon)GetValue(ServerRconProperty); }
|
||||
set { SetValue(ServerRconProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
private InputWindowMode CurrentInputWindowMode
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public ICommand Button1Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (_) =>
|
||||
{
|
||||
inputBox.Visibility = Visibility.Collapsed;
|
||||
dockPanel.IsEnabled = true;
|
||||
|
||||
PlayerInfo player;
|
||||
var inputText = inputTextBox.Text;
|
||||
|
||||
switch (this.CurrentInputWindowMode)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear InputBox.
|
||||
inputTextBox.Text = String.Empty;
|
||||
this.CurrentInputWindowMode = InputWindowMode.None;
|
||||
},
|
||||
canExecute: (_) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Button2Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (_) =>
|
||||
{
|
||||
inputBox.Visibility = Visibility.Collapsed;
|
||||
dockPanel.IsEnabled = true;
|
||||
|
||||
switch (this.CurrentInputWindowMode)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear InputBox.
|
||||
inputTextBox.Text = String.Empty;
|
||||
this.CurrentInputWindowMode = InputWindowMode.None;
|
||||
},
|
||||
canExecute: (_) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ClearLogsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (_) =>
|
||||
{
|
||||
string logsDir = String.Empty;
|
||||
try
|
||||
{
|
||||
logsDir = App.GetProfileLogFolder(this.RconParameters.ProfileId);
|
||||
Directory.Delete(logsDir, true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore any failures here, best effort only.
|
||||
}
|
||||
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("RCON_ClearLogs_Label"), logsDir), _globalizer.GetResourceString("RCON_ClearLogs_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
},
|
||||
canExecute: (_) => this.RconParameters.Server != null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ViewLogsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (_) =>
|
||||
{
|
||||
string logsDir = String.Empty;
|
||||
try
|
||||
{
|
||||
logsDir = App.GetProfileLogFolder(this.RconParameters.ProfileId);
|
||||
Process.Start(logsDir);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("RCON_ViewLogs_ErrorLabel"), logsDir, ex.Message), _globalizer.GetResourceString("RCON_ViewLogs_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
},
|
||||
canExecute: (_) => this.RconParameters.Server != null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand SortPlayersCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerSortType>(
|
||||
execute: (sort) =>
|
||||
{
|
||||
Config.Default.RCON_PlayerListSort = (int)this.PlayerSorting;
|
||||
SortPlayers();
|
||||
},
|
||||
canExecute: (sort) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand FilterPlayersCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerFilterType>(
|
||||
execute: (filter) =>
|
||||
{
|
||||
this.PlayerFiltering ^= filter;
|
||||
Config.Default.RCON_PlayerListFilter = (int)this.PlayerFiltering;
|
||||
this.PlayersView.Refresh();
|
||||
},
|
||||
canExecute: (filter) => true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ViewPlayerProfileCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
var savedFilesPath = ServerProfile.GetProfileSavePath(this.RconParameters.InstallDirectory);
|
||||
var window = new PlayerProfileWindow(player, savedFilesPath)
|
||||
{
|
||||
Owner = this
|
||||
};
|
||||
window.ShowDialog();
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ViewPlayerTribeCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
var savedFilesPath = ServerProfile.GetProfileSavePath(this.RconParameters.InstallDirectory);
|
||||
var window = new GuildProfileWindow(player, this.ServerRcon.Players, savedFilesPath)
|
||||
{
|
||||
Owner = this
|
||||
};
|
||||
window.ShowDialog();
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null && !string.IsNullOrWhiteSpace(player.GuildName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand CopyIDCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Clipboard.SetText(player.PlayerId.ToString());
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyIdLabel")} {player.PlayerName}", _globalizer.GetResourceString("RCON_CopyIdTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON_ClipboardErrorTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
},
|
||||
canExecute: (player) => player != null
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand CopyPlayerIDCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<PlayerInfo>(
|
||||
execute: (player) =>
|
||||
{
|
||||
if (player.PlayerData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Clipboard.SetText(player.PlayerData.CharacterId.ToString());
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_CopyPlayerIdLabel")} {player.CharacterName}", _globalizer.GetResourceString("RCON_CopyPlayerIdTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"{_globalizer.GetResourceString("RCON_ClipboardErrorLabel")}", _globalizer.GetResourceString("RCON_ClipboardErrorTitle"), MessageBoxButton.OK);
|
||||
}
|
||||
}
|
||||
},
|
||||
canExecute: (player) => player?.PlayerData != null && player.IsValid
|
||||
);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public static RconWindow GetRconForServer(Server server)
|
||||
{
|
||||
if (!RconWindows.TryGetValue(server, out RconWindow window) || !window.IsLoaded)
|
||||
{
|
||||
window = new RconWindow(new RconParameters()
|
||||
{
|
||||
WindowTitle = String.Format(GlobalizedApplication.Instance.GetResourceString("RCON_TitleLabel"), server.Runtime.ProfileSnapshot.ProfileName),
|
||||
WindowExtents = server.Profile.RconWindowExtents,
|
||||
PlayerListWidth = server.Profile.RconPlayerListWidth,
|
||||
|
||||
Server = server,
|
||||
InstallDirectory = server.Runtime.ProfileSnapshot.InstallDirectory,
|
||||
GameFile = server.Runtime.ProfileSnapshot.GameFile,
|
||||
ProfileId = server.Runtime.ProfileSnapshot.ProfileId,
|
||||
ProfileName = server.Runtime.ProfileSnapshot.ProfileName,
|
||||
MaxPlayers = server.Runtime.MaxPlayers,
|
||||
RconHost = server.Runtime.ProfileSnapshot.ServerIP,
|
||||
RconPort = server.Runtime.ProfileSnapshot.RconPort,
|
||||
RconPassword = server.Runtime.ProfileSnapshot.RconPassword,
|
||||
});
|
||||
RconWindows[server] = window;
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
private void ResourceDictionaryChangedEvent(object source, ResourceDictionaryChangedEventArgs e)
|
||||
{
|
||||
// refresh the InputModes combobox list
|
||||
this.InputModesComboBox.Items.Refresh();
|
||||
|
||||
// refresh the InputModes combobox value
|
||||
var currentInputMode = CurrentInputMode;
|
||||
this.InputModesComboBox.SelectedItem = null;
|
||||
this.InputModesComboBox.SelectedItem = currentInputMode;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent -= ResourceDictionaryChangedEvent;
|
||||
|
||||
if (this.RconParameters?.Server?.Runtime != null)
|
||||
{
|
||||
this.RconParameters.Server.Runtime.StatusUpdate -= Runtime_StatusUpdate;
|
||||
}
|
||||
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
this.ServerRcon.PlayersCollectionUpdated -= Players_CollectionUpdated;
|
||||
this.ServerRcon.Players.CollectionChanged -= Players_CollectionChanged;
|
||||
this.ServerRcon.DisposeAsync().DoNotWait();
|
||||
|
||||
if (this.RconParameters?.Server != null)
|
||||
{
|
||||
RconWindows.TryGetValue(this.RconParameters.Server, out RconWindow window);
|
||||
if (window != null)
|
||||
RconWindows.Remove(this.RconParameters.Server);
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void RCON_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
Rect savedRect = this.RconParameters.WindowExtents;
|
||||
this.RconParameters.WindowExtents = new Rect(savedRect.Location, e.NewSize);
|
||||
if (this.RconParameters.Server != null)
|
||||
{
|
||||
this.RconParameters.Server.Profile.RconWindowExtents = this.RconParameters.WindowExtents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RCON_LocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (this.WindowState != WindowState.Minimized && this.Left != -32000 && this.Top != -32000)
|
||||
{
|
||||
Rect savedRect = this.RconParameters.WindowExtents;
|
||||
this.RconParameters.WindowExtents = new Rect(new Point(this.Left, this.Top), savedRect.Size);
|
||||
if (this.RconParameters.Server != null)
|
||||
{
|
||||
this.RconParameters.Server.Profile.RconWindowExtents = this.RconParameters.WindowExtents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConsoleInput_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if(e.Key == Key.Enter)
|
||||
{
|
||||
var textBox = (TextBox)sender;
|
||||
var effectiveMode = this.CurrentInputMode;
|
||||
var commandText = textBox.Text.Trim();
|
||||
|
||||
if (commandText.StartsWith("/"))
|
||||
{
|
||||
effectiveMode = InputMode.Command;
|
||||
commandText = commandText.Substring(1);
|
||||
}
|
||||
|
||||
switch (effectiveMode)
|
||||
{
|
||||
case InputMode.Broadcast:
|
||||
this.ServerRcon.IssueCommand($"{ServerRcon.RCON_COMMAND_BROADCAST} {commandText}");
|
||||
break;
|
||||
|
||||
case InputMode.Command:
|
||||
this.ServerRcon.IssueCommand(commandText);
|
||||
break;
|
||||
}
|
||||
|
||||
textBox.Text = String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void Players_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
SortPlayers();
|
||||
PlayersView?.Refresh();
|
||||
}
|
||||
|
||||
private void Players_CollectionUpdated(object sender, EventArgs e)
|
||||
{
|
||||
this.PlayersView = CollectionViewSource.GetDefaultView(this.ServerRcon.Players);
|
||||
this.PlayersView.Filter = new Predicate<object>(PlayerFilter);
|
||||
|
||||
SortPlayers();
|
||||
PlayersView?.Refresh();
|
||||
}
|
||||
|
||||
private void PlayerList_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
this.RconParameters.PlayerListWidth = this.playerListColumn.Width.Value;
|
||||
if (this.RconParameters.Server != null)
|
||||
{
|
||||
this.RconParameters.Server.Profile.RconPlayerListWidth = this.RconParameters.PlayerListWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private void Runtime_StatusUpdate(object sender, EventArgs eventArgs)
|
||||
{
|
||||
this.RconParameters.ProfileName = this.RconParameters?.Server?.Runtime?.ProfileSnapshot.ProfileName ?? "<unknown>";
|
||||
this.RconParameters.MaxPlayers = this.RconParameters?.Server?.Runtime?.MaxPlayers ?? 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
public static void CloseAllWindows()
|
||||
{
|
||||
var windows = RconWindows.Values.ToList();
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.IsLoaded)
|
||||
window.Close();
|
||||
}
|
||||
windows.Clear();
|
||||
}
|
||||
|
||||
private void SetPlayerListWidth(double value)
|
||||
{
|
||||
if (value < this.playerListColumn.MinWidth)
|
||||
this.playerListColumn.Width = new GridLength(this.playerListColumn.MinWidth, GridUnitType.Pixel);
|
||||
else
|
||||
this.playerListColumn.Width = new GridLength(value, GridUnitType.Pixel);
|
||||
}
|
||||
|
||||
public void SortPlayers()
|
||||
{
|
||||
this.PlayersView.SortDescriptions.Clear();
|
||||
|
||||
switch (this.PlayerSorting)
|
||||
{
|
||||
case PlayerSortType.Name:
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.Online:
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.IsOnline), ListSortDirection.Descending));
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.Tribe:
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.GuildName), ListSortDirection.Ascending));
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
|
||||
case PlayerSortType.LastOnline:
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.LastOnline), ListSortDirection.Descending));
|
||||
this.PlayersView.SortDescriptions.Add(new SortDescription(nameof(PlayerInfo.PlayerName), ListSortDirection.Ascending));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Command Methods
|
||||
private void AddBlockContent(Block b)
|
||||
{
|
||||
ConsoleContent.Blocks.Add(b);
|
||||
}
|
||||
|
||||
private IEnumerable<Inline> FormatCommandInput(ConsoleCommand command)
|
||||
{
|
||||
if (command.command.Equals(ServerRcon.RCON_COMMAND_BROADCAST, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
yield return new RconOutput_Broadcast(command.args);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new RconOutput_Command($"> {command.rawCommand}");
|
||||
}
|
||||
|
||||
if (!command.suppressOutput && command.lines.Count() > 0)
|
||||
{
|
||||
yield return new LineBreak();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Inline> FormatCommandOutput(ConsoleCommand command)
|
||||
{
|
||||
bool firstLine = true;
|
||||
|
||||
if (command.command.Equals(ServerRcon.RCON_COMMAND_LISTPLAYERS, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var output in command.lines)
|
||||
{
|
||||
var trimmed = output.TrimEnd();
|
||||
|
||||
if (!firstLine)
|
||||
{
|
||||
yield return new LineBreak();
|
||||
}
|
||||
firstLine = false;
|
||||
|
||||
if (trimmed == ServerRcon.NoResponseOutput)
|
||||
{
|
||||
yield return new RconOutput_NoResponse();
|
||||
}
|
||||
else if (trimmed.EndsWith("joined the game."))
|
||||
{
|
||||
yield return new RconOutput_PlayerJoined(trimmed);
|
||||
}
|
||||
else if (trimmed.EndsWith("left the game."))
|
||||
{
|
||||
yield return new RconOutput_PlayerLeft(trimmed);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new RconOutput_CommandOutput(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in command.lines)
|
||||
{
|
||||
var trimmed = output.TrimEnd();
|
||||
|
||||
if (!firstLine)
|
||||
{
|
||||
yield return new LineBreak();
|
||||
}
|
||||
firstLine = false;
|
||||
|
||||
if (trimmed == ServerRcon.NoResponseOutput)
|
||||
{
|
||||
yield return new RconOutput_NoResponse();
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new RconOutput_CommandOutput(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderCommentsBlock(params string[] lines)
|
||||
{
|
||||
var p = new Paragraph();
|
||||
bool firstLine = true;
|
||||
|
||||
foreach (var output in lines)
|
||||
{
|
||||
var trimmed = output.TrimEnd();
|
||||
|
||||
if (!firstLine)
|
||||
{
|
||||
p.Inlines.Add(new LineBreak());
|
||||
}
|
||||
firstLine = false;
|
||||
|
||||
p.Inlines.Add(new RconOutput_Comment(trimmed));
|
||||
}
|
||||
|
||||
AddBlockContent(p);
|
||||
}
|
||||
|
||||
private void RenderRCONCommandOutput(ConsoleCommand command)
|
||||
{
|
||||
//
|
||||
// Format output
|
||||
//
|
||||
var p = new Paragraph();
|
||||
|
||||
if (!command.suppressCommand)
|
||||
{
|
||||
foreach (var element in FormatCommandInput(command))
|
||||
{
|
||||
p.Inlines.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!command.suppressOutput)
|
||||
{
|
||||
foreach (var element in FormatCommandOutput(command))
|
||||
{
|
||||
p.Inlines.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(command.suppressCommand && command.suppressOutput))
|
||||
{
|
||||
if (p.Inlines.Count > 0)
|
||||
{
|
||||
AddBlockContent(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Filtering
|
||||
private void FilterPlayerList_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PlayersView?.Refresh();
|
||||
}
|
||||
|
||||
public bool PlayerFilter(object obj)
|
||||
{
|
||||
var player = obj as PlayerInfo;
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
var result = (this.PlayerFiltering.HasFlag(PlayerFilterType.Online) && player.IsOnline) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Offline) && !player.IsOnline) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Admin) && player.IsAdmin) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Whitelisted) && player.IsWhitelisted) ||
|
||||
(this.PlayerFiltering.HasFlag(PlayerFilterType.Invalid) && !player.IsValid);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
var filterString = PlayerFilterString.ToLower();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filterString))
|
||||
return true;
|
||||
|
||||
result = player.PlatformNameFilterString != null && player.PlatformNameFilterString.Contains(filterString) ||
|
||||
player.GuildNameFilterString != null && player.GuildNameFilterString.Contains(filterString) ||
|
||||
player.CharacterNameFilterString != null && player.CharacterNameFilterString.Contains(filterString);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
583
src/ConanServerManager/Windows/ServerMonitorWindow.xaml
Normal file
583
src/ConanServerManager/Windows/ServerMonitorWindow.xaml
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
<Window x:Class="ServerManagerTool.Windows.ServerMonitorWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
|
||||
xmlns:vm="clr-namespace:ServerManagerTool.Lib.ViewModel"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="600" MinHeight="500" Width="900" Height="500" Left="50" Top="50" ResizeMode="CanResize"
|
||||
Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged"
|
||||
Name="ServerMonitorUI" Icon="../Art/favicon.ico" Title="{DynamicResource ServerMonitor_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<cc:CommaDelimitedStringCountConverter x:Key="CommaDelimitedStringCountConverter"/>
|
||||
<cc:InstalledVersionConverter x:Key="InstalledVersionConverter"/>
|
||||
<vm:MapNameValueConverter x:Key="MapNameValueConverter"/>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}" MouseLeftButtonUp="OnMouseLeftButtonUp" MouseMove="OnMouseMove">
|
||||
<DockPanel x:Name="dockPanel">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="10*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" Width="22" Height="22" Margin="5,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="CreateShortcut_Click" ToolTip="{DynamicResource ServerMonitor_CreateShortcutButtonTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Shortcut.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock Margin="30,5,5,0" Text="{DynamicResource ServerMonitor_TotalCountLabel}" VerticalAlignment="Center" />
|
||||
<TextBlock Margin="5,5,5,0" Text="{Binding ServerManager.Servers.Count}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="2" Height="22" Margin="5,5,5,0" Background="#00AA00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" ContentStringFormat="{DynamicResource MainWindow_UpdateToLabelFormat}" Content="{Binding LatestServerManagerVersion}" Click="UpgradeApplication_Click" VerticalAlignment="Center" >
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ShowUpdateButton}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ShowUpdateButton}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="3" Width="22" Height="22" Margin="5,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="PatchNotes_Click" ToolTip="{DynamicResource ServerSettings_PatchNotesTooltip}">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsStandAloneWindow}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsStandAloneWindow}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/ChangeNotes.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" Name="ServersGrid" ItemsSource="{Binding ServerManager.Servers}" GridLinesVisibility="Horizontal" HeadersVisibility="All" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" CanUserResizeRows="False" RowHeaderWidth="25" SelectionMode="Single" PreviewMouseLeftButtonDown="OnMouseLeftButtonDown">
|
||||
<DataGrid.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="{x:Type DataGridCell}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Setter Property="Background" Value="White" />
|
||||
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="Black"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
|
||||
</Style.Resources>
|
||||
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Background" Value="#26FF0000" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="Background" Value="#26FFA500" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="Background" Value="#26008000" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="Background" Value="#26FFA500" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="Background" Value="White" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Background" Value="#26FF0000" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="Background" Value="#260000FF" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Background" Value="#260000FF" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_ServerColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Profile.ProfileName}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="150">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_MapColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Profile.ServerMap, Converter={StaticResource MapNameValueConverter}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="50">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_ModsColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Profile.ServerModIds, Converter={StaticResource CommaDelimitedStringCountConverter}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="80">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_VersionColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Profile.LastInstalledVersion, Converter={StaticResource InstalledVersionConverter}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="80">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_PlayersColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Label Content="{Binding Runtime.Players}" />
|
||||
<Label Content="/" />
|
||||
<Label Content="{Binding Runtime.MaxPlayers}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="100">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{DynamicResource ServerMonitor_StatusColumnLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Runtime.StatusString}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="30" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="StartStopServer_Click">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_StopServerTooltip}" />
|
||||
<Setter Property="Visibility" Value="Hidden"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_StopServerTooltip}" />
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_StopServerTooltip}" />
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_StartServerTooltip}" />
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Visibility" Value="Hidden"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Visibility" Value="Hidden"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image>
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Start.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="30" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="UpdateServer_Click">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Hidden"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_UpgradeButtonTooltip}" />
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Visibility" Value="Hidden"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_InstallButtonTooltip}" />
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image>
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="30" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OpenPlayerList_Click">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Profile.RconEnabled}" Value="False">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_PlayerListButtonTooltip}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Profile.RconEnabled}" Value="True">
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerMonitor_RCONButtonTooltip}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image>
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Profile.RconEnabled}" Value="False">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Players.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Profile.RconEnabled}" Value="True">
|
||||
<Setter Property="Source" Value="{com:Icon Path=/ConanServerManager;component/Art/Command.ico,Size=32}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="30" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="BackupServer_Click" ToolTip="{DynamicResource ServerSettings_SaveBackupButtonTooltip}">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Null}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Initializing}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopping}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}">
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Unknown}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Updating}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Uninstalled}">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Save.ico,Size=32}" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Width="30" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OpenServerFolder_Click" ToolTip="{DynamicResource ServerSettings_OpenServerFolderTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/FolderOpen.ico,Size=32}" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
|
||||
<!-- Drag and Drop Popup -->
|
||||
<Popup Grid.Row="0" Grid.Column="0" x:Name="popup" IsHitTestVisible="False" Placement="RelativePoint" PlacementTarget="{Binding ElementName=ServerMonitorUI}" AllowsTransparency="True">
|
||||
<Border BorderBrush="LightSteelBlue" BorderThickness="2" Background="White" Opacity="0.75">
|
||||
<StackPanel Orientation="Horizontal" Margin="4,3,8,3">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Drag.ico,Size=32}" Width="16" Height="16"/>
|
||||
<TextBlock FontSize="14" VerticalAlignment="Center" Text="{Binding DraggedItem.Profile.ProfileName, ElementName=ServerMonitorUI}" Margin="8,0,0,0" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
|
||||
<!-- It's important that this is in the end of the XAML as it needs to be on top of everything else! -->
|
||||
<Grid x:Name="OverlayGrid" Visibility="Collapsed" DockPanel.Dock="Top" >
|
||||
<Grid Background="Black" Opacity="0.5"/>
|
||||
<Border MinWidth="250" Background="Orange" BorderBrush="Black" BorderThickness="1" CornerRadius="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel>
|
||||
<Label x:Name="OverlayMessage" Margin="5" FontWeight="Bold" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<tb:TaskbarIcon
|
||||
Visibility="{Binding IsStandAloneWindow, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
ToolTipText="{Binding Title}"
|
||||
IconSource="../Art/favicon.ico"
|
||||
LeftClickCommand="{Binding ShowWindowCommand, ElementName=ServerMonitorUI}">
|
||||
|
||||
<tb:TaskbarIcon.Resources>
|
||||
<clib:BindingProxy x:Key="proxy" Data="{Binding ElementName=ServerMonitorUI}"/>
|
||||
</tb:TaskbarIcon.Resources>
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{DynamicResource Application_NotifyIcon_ShowServerMonitorWindow}" Command="{Binding Source={StaticResource proxy}, Path=Data.ShowWindowCommand}" />
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
|
||||
</tb:TaskbarIcon>
|
||||
</Grid>
|
||||
</Window>
|
||||
800
src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
Normal file
800
src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,800 @@
|
|||
using IWshRuntimeLibrary;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ServerMonitorWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ServerMonitorWindow : Window
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
private static readonly List<ServerMonitorWindow> Windows = new List<ServerMonitorWindow>();
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private CancellationTokenSource _upgradeCancellationSource = null;
|
||||
private ActionQueue _versionChecker;
|
||||
|
||||
public static readonly DependencyProperty ServerManagerProperty = DependencyProperty.Register(nameof(ServerManager), typeof(ServerManager), typeof(ServerMonitorWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty LatestServerManagerVersionProperty = DependencyProperty.Register(nameof(LatestServerManagerVersion), typeof(Version), typeof(ServerMonitorWindow), new PropertyMetadata(new Version()));
|
||||
public static readonly DependencyProperty ShowUpdateButtonProperty = DependencyProperty.Register(nameof(ShowUpdateButton), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsStandAloneWindowProperty = DependencyProperty.Register(nameof(IsStandAloneWindow), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false));
|
||||
|
||||
public ServerMonitorWindow() : this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public ServerMonitorWindow(ServerManager serverManager)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.ServerManager = serverManager;
|
||||
this.IsStandAloneWindow = serverManager == null;
|
||||
this.DataContext = this;
|
||||
|
||||
SetWindowTitle();
|
||||
|
||||
this.Height = Config.Default.ServerMonitorWindow_Height;
|
||||
this.Width = Config.Default.ServerMonitorWindow_Width;
|
||||
|
||||
// hook into the language change event
|
||||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
||||
|
||||
Windows.Add(this);
|
||||
}
|
||||
|
||||
public ServerManager ServerManager
|
||||
{
|
||||
get { return (ServerManager)GetValue(ServerManagerProperty); }
|
||||
set { SetValue(ServerManagerProperty, value); }
|
||||
}
|
||||
|
||||
public Version LatestServerManagerVersion
|
||||
{
|
||||
get { return (Version)GetValue(LatestServerManagerVersionProperty); }
|
||||
set { SetValue(LatestServerManagerVersionProperty, value); }
|
||||
}
|
||||
|
||||
public bool ShowUpdateButton
|
||||
{
|
||||
get { return (bool)GetValue(ShowUpdateButtonProperty); }
|
||||
set { SetValue(ShowUpdateButtonProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsStandAloneWindow
|
||||
{
|
||||
get { return (bool)GetValue(IsStandAloneWindowProperty); }
|
||||
set { SetValue(IsStandAloneWindowProperty, value); }
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ServerManager == null)
|
||||
{
|
||||
ServerManager = ServerManager.Instance;
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
// We need to load the set of existing servers, or create a blank one if we don't have any...
|
||||
foreach (var profile in Directory.EnumerateFiles(Config.Default.ConfigPath, "*" + Config.Default.ProfileExtension))
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerManager.Instance.AddFromPath(profile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_ProfileLoad_FailedLabel"), profile, ex.Message, ex.StackTrace), _globalizer.GetResourceString("MainWindow_ProfileLoad_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
}
|
||||
}
|
||||
|
||||
ServerManager.Instance.SortServers();
|
||||
ServerManager.Instance.CheckProfiles();
|
||||
|
||||
}).DoNotWait();
|
||||
}
|
||||
|
||||
if (IsStandAloneWindow)
|
||||
{
|
||||
_versionChecker = new ActionQueue();
|
||||
_versionChecker.PostAction(CheckForUpdates).DoNotWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState != WindowState.Minimized)
|
||||
{
|
||||
Config.Default.ServerMonitorWindow_Height = e.NewSize.Height;
|
||||
Config.Default.ServerMonitorWindow_Width = e.NewSize.Width;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (IsStandAloneWindow && Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
if (this.OwnedWindows.OfType<ProgressWindow>().Any())
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes)
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Windows.Remove(this);
|
||||
_versionChecker?.DisposeAsync().DoNotWait();
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void ResourceDictionaryChangedEvent(object source, ResourceDictionaryChangedEventArgs e)
|
||||
{
|
||||
SetWindowTitle();
|
||||
}
|
||||
|
||||
private async void BackupServer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var server = ((Server)((Button)e.Source).DataContext);
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !Config.Default.AutoBackup_EnableBackup,
|
||||
SendEmails = false,
|
||||
OutputLogs = false,
|
||||
ServerProcess = ServerProcessType.Backup,
|
||||
};
|
||||
|
||||
var profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
{
|
||||
throw new ApplicationException($"An error occured during the backup process - ExitCode: {exitCode}");
|
||||
}
|
||||
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_BackupServer_SuccessfulLabel"), _globalizer.GetResourceString("ServerSettings_BackupServer_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_BackupServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateShortcut_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars().ToList();
|
||||
|
||||
var name = $"{_globalizer.GetResourceString("MainWindow_Title")} - {_globalizer.GetResourceString("ServerMonitor_Title")}";
|
||||
invalidChars.ForEach(c => name = name.Replace(c.ToString(), ""));
|
||||
|
||||
var desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
|
||||
var shortcutLocation = Path.Combine(desktopPath, name + ".lnk");
|
||||
var applicationFile = Assembly.GetExecutingAssembly().Location;
|
||||
|
||||
WshShell shell = new WshShell();
|
||||
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation);
|
||||
|
||||
shortcut.Description = name;
|
||||
shortcut.Arguments = "-sm";
|
||||
shortcut.IconLocation = applicationFile;
|
||||
shortcut.TargetPath = applicationFile;
|
||||
shortcut.WorkingDirectory = Path.GetDirectoryName(applicationFile);
|
||||
shortcut.Save();
|
||||
}
|
||||
|
||||
private void OpenPlayerList_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var server = ((Server)((Button)e.Source).DataContext);
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
Window window = null;
|
||||
|
||||
if (server.Profile.RconEnabled)
|
||||
{
|
||||
window = RconWindow.GetRconForServer(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
window = PlayerListWindow.GetWindowForServer(server);
|
||||
}
|
||||
|
||||
window.Closed += Window_Closed;
|
||||
window.Show();
|
||||
if (window.WindowState == WindowState.Minimized)
|
||||
{
|
||||
window.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
window.Focus();
|
||||
}
|
||||
|
||||
private void OpenServerFolder_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var server = ((Server)((Button)e.Source).DataContext);
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
Process.Start("explorer.exe", server.Profile.InstallDirectory);
|
||||
}
|
||||
|
||||
private void PatchNotes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var url = string.Empty;
|
||||
if (App.Instance.BetaVersion)
|
||||
url = Config.Default.ServerManagerVersionBetaFeedUrl;
|
||||
else
|
||||
url = Config.Default.ServerManagerVersionFeedUrl;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
var window = new VersionFeedWindow(url);
|
||||
window.Closed += Window_Closed;
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (App.Instance.BetaVersion)
|
||||
url = Config.Default.LatestServerManagerBetaPatchNotesUrl;
|
||||
else
|
||||
url = Config.Default.LatestServerManagerPatchNotesUrl;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return;
|
||||
|
||||
Process.Start(url);
|
||||
}
|
||||
}
|
||||
|
||||
private async void StartStopServer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var server = ((Server)((Button)e.Source).DataContext);
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
await StartStopServerAsync(server);
|
||||
}
|
||||
|
||||
private async void UpdateServer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var server = ((Server)((Button)e.Source).DataContext);
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
break;
|
||||
|
||||
case ServerStatus.Running:
|
||||
case ServerStatus.Initializing:
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("ServerSettings_UpgradeServer_RunningLabel"), _globalizer.GetResourceString("ServerSettings_UpgradeServer_RunningTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.No)
|
||||
return;
|
||||
|
||||
break;
|
||||
|
||||
case ServerStatus.Updating:
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
server.Profile.Save(false, false, null);
|
||||
await UpdateServerAsync(server, true, true, Config.Default.ServerUpdate_UpdateModsWhenUpdatingServer, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_UpdateServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void UpgradeApplication_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_Label"), this.LatestServerManagerVersion), _globalizer.GetResourceString("MainWindow_Upgrade_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
OverlayMessage.Content = _globalizer.GetResourceString("MainWindow_OverlayMessage_UpgradeLabel");
|
||||
OverlayGrid.Visibility = Visibility.Visible;
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
var process = Process.GetCurrentProcess();
|
||||
if (process == null || process.HasExited)
|
||||
throw new Exception("Application process could not be found or does not exist.");
|
||||
|
||||
var assemblyLocation = Assembly.GetEntryAssembly().Location;
|
||||
var updaterFile = Path.Combine(Path.GetDirectoryName(assemblyLocation), Config.Default.UpdaterFile);
|
||||
var newUpdaterFile = Path.Combine(Path.GetDirectoryName(assemblyLocation), $"New{Config.Default.UpdaterFile}");
|
||||
|
||||
// check if there is a new version of the updater file
|
||||
if (System.IO.File.Exists(newUpdaterFile))
|
||||
{
|
||||
// file exists, rename the file, so that we use the new updater instead
|
||||
try
|
||||
{
|
||||
System.IO.File.Copy(newUpdaterFile, updaterFile, true);
|
||||
await Task.Delay(1000);
|
||||
System.IO.File.Delete(newUpdaterFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if error, then do nothing
|
||||
Logger.Debug($"An error occurred trying to update the server manager updater. {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(updaterFile))
|
||||
throw new FileNotFoundException("The updater application could not be found or does not exist.");
|
||||
|
||||
var arguments = new string[]
|
||||
{
|
||||
process.Id.ToString().AsQuoted(),
|
||||
App.Instance.BetaVersion ? Config.Default.LatestServerManagerBetaDownloadUrl.AsQuoted() : Config.Default.LatestServerManagerDownloadUrl.AsQuoted(),
|
||||
Config.Default.UpdaterPrefix.AsQuoted(),
|
||||
};
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo()
|
||||
{
|
||||
FileName = updaterFile.AsQuoted(),
|
||||
Arguments = string.Join(" ", arguments),
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
var updaterProcess = Process.Start(info);
|
||||
if (updaterProcess == null)
|
||||
throw new Exception("Could not restart application.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_FailedLabel"), ex.Message, ex.StackTrace), _globalizer.GetResourceString("MainWindow_Upgrade_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
OverlayGrid.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckForUpdates()
|
||||
{
|
||||
string url = App.Instance.BetaVersion ? Config.Default.LatestServerManagerBetaVersionUrl : Config.Default.LatestServerManagerVersionUrl;
|
||||
var newVersion = await NetworkUtils.GetLatestServerManagerVersion(url);
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var appVersion = new Version();
|
||||
Version.TryParse(App.Instance.Version, out appVersion);
|
||||
|
||||
this.LatestServerManagerVersion = newVersion;
|
||||
this.ShowUpdateButton = appVersion < newVersion;
|
||||
|
||||
Logger.Info($"{nameof(CheckForUpdates)} performed.");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore.
|
||||
}
|
||||
}).DoNotWait();
|
||||
|
||||
await Task.Delay(Config.Default.UpdateCheckTime * 60 * 1000);
|
||||
_versionChecker?.PostAction(CheckForUpdates).DoNotWait();
|
||||
}
|
||||
|
||||
public static void CloseAllWindows()
|
||||
{
|
||||
var windows = Windows.ToArray();
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.IsLoaded)
|
||||
window.Close();
|
||||
}
|
||||
Windows.Clear();
|
||||
}
|
||||
|
||||
public static ServerMonitorWindow GetWindow(ServerManager serverManager)
|
||||
{
|
||||
if (Windows.Count > 0)
|
||||
return Windows[0];
|
||||
|
||||
return new ServerMonitorWindow(serverManager);
|
||||
}
|
||||
|
||||
private void SetWindowTitle()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(App.Instance.Title))
|
||||
{
|
||||
this.Title = App.Instance.Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Title = _globalizer.GetResourceString("MainWindow_Title");
|
||||
}
|
||||
|
||||
this.Title += $" - {_globalizer.GetResourceString("ServerMonitor_Title")}";
|
||||
|
||||
if (IsStandAloneWindow)
|
||||
{
|
||||
this.Title += $" - {App.Instance.Version}";
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartStopServerAsync(Server server)
|
||||
{
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
var serverRuntime = server.Runtime;
|
||||
var serverProfile = server.Profile;
|
||||
MessageBoxResult result = MessageBoxResult.None;
|
||||
|
||||
switch (serverRuntime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Running:
|
||||
// check if the server is initialising.
|
||||
if (serverRuntime.Status == ServerStatus.Initializing)
|
||||
{
|
||||
result = MessageBox.Show(_globalizer.GetResourceString("ServerSettings_StartServer_StartingLabel"), _globalizer.GetResourceString("ServerSettings_StartServer_StartingTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.No)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
PluginHelper.Instance.ProcessAlert(AlertType.Shutdown, serverProfile.ProfileName, Config.Default.Alert_ServerStopMessage);
|
||||
await Task.Delay(2000);
|
||||
|
||||
await server.StopAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_StopServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var shutdownWindow = ShutdownWindow.OpenShutdownWindow(server);
|
||||
if (shutdownWindow == null)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_ShutdownServer_AlreadyOpenLabel"), _globalizer.GetResourceString("ServerSettings_ShutdownServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
shutdownWindow.Owner = Window.GetWindow(this);
|
||||
shutdownWindow.Closed += Window_Closed;
|
||||
shutdownWindow.Show();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ShutdownServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ServerStatus.Stopped:
|
||||
Mutex mutex = null;
|
||||
bool createdNew = false;
|
||||
|
||||
try
|
||||
{
|
||||
// try to establish a mutex for the profile.
|
||||
mutex = new Mutex(true, ServerApp.GetMutexName(serverProfile.InstallDirectory), out createdNew);
|
||||
|
||||
// check if the mutex was established
|
||||
if (createdNew)
|
||||
{
|
||||
serverProfile.Save(false, false, null);
|
||||
|
||||
if (Config.Default.ServerUpdate_OnServerStart)
|
||||
{
|
||||
if (!await UpdateServerAsync(server, false, true, Config.Default.ServerUpdate_UpdateModsWhenUpdatingServer, true))
|
||||
{
|
||||
if (MessageBox.Show(_globalizer.GetResourceString("ServerUpdate_WarningLabel"), _globalizer.GetResourceString("ServerUpdate_Title"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!serverProfile.Validate(false, out string validateMessage))
|
||||
{
|
||||
var outputMessage = _globalizer.GetResourceString("ProfileValidation_WarningLabel").Replace("{validateMessage}", validateMessage);
|
||||
if (MessageBox.Show(outputMessage, _globalizer.GetResourceString("ProfileValidation_Title"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
await server.StartAsync();
|
||||
|
||||
var startupMessage = Config.Default.Alert_ServerStartedMessage;
|
||||
if (Config.Default.Alert_ServerStartedMessageIncludeIPandPort)
|
||||
startupMessage += $" {Config.Default.MachinePublicIP}:{serverProfile.QueryPort}";
|
||||
PluginHelper.Instance.ProcessAlert(AlertType.Startup, serverProfile.ProfileName, startupMessage);
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// display an error message and exit
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_StartServer_MutexFailedLabel"), _globalizer.GetResourceString("ServerSettings_StartServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_StartServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (mutex != null)
|
||||
{
|
||||
if (createdNew)
|
||||
{
|
||||
mutex.ReleaseMutex();
|
||||
mutex.Dispose();
|
||||
}
|
||||
mutex = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateServerAsync(Server server, bool establishLock, bool updateServer, bool updateMods, bool closeProgressWindow)
|
||||
{
|
||||
if (server == null)
|
||||
return false;
|
||||
|
||||
if (_upgradeCancellationSource != null)
|
||||
{
|
||||
// display an error message and exit
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_UpgradeServer_FailedLabel"), _globalizer.GetResourceString("ServerMonitor_UpgradeServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return false;
|
||||
}
|
||||
|
||||
ProgressWindow window = null;
|
||||
Mutex mutex = null;
|
||||
bool createdNew = !establishLock;
|
||||
var serverProfile = server.Profile;
|
||||
|
||||
try
|
||||
{
|
||||
if (establishLock)
|
||||
{
|
||||
// try to establish a mutex for the profile.
|
||||
mutex = new Mutex(true, ServerApp.GetMutexName(serverProfile.InstallDirectory), out createdNew);
|
||||
}
|
||||
|
||||
// check if the mutex was established
|
||||
if (createdNew)
|
||||
{
|
||||
_upgradeCancellationSource = new CancellationTokenSource();
|
||||
|
||||
window = new ProgressWindow(string.Format(_globalizer.GetResourceString("Progress_UpgradeServer_WindowTitle"), serverProfile.ProfileName))
|
||||
{
|
||||
Owner = Window.GetWindow(this)
|
||||
};
|
||||
window.Closed += Window_Closed;
|
||||
window.Show();
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var branch = new BranchSnapshot() { BranchName = serverProfile.BranchName, BranchPassword = serverProfile.BranchPassword };
|
||||
return await server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
// display an error message and exit
|
||||
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_UpgradeServer_MutexFailedLabel"), _globalizer.GetResourceString("ServerSettings_UpgradeServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (window != null)
|
||||
{
|
||||
window.AddMessage(ex.Message);
|
||||
window.AddMessage(ex.StackTrace);
|
||||
}
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_UpgradeServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_upgradeCancellationSource = null;
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
window.CloseWindow();
|
||||
if (closeProgressWindow)
|
||||
window.Close();
|
||||
}
|
||||
|
||||
if (mutex != null)
|
||||
{
|
||||
if (createdNew)
|
||||
{
|
||||
mutex.ReleaseMutex();
|
||||
mutex.Dispose();
|
||||
}
|
||||
mutex = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ShowWindowCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand<object>(
|
||||
execute: (parameter) =>
|
||||
{
|
||||
this.Show();
|
||||
this.WindowState = WindowState.Normal;
|
||||
this.Activate();
|
||||
},
|
||||
canExecute: (parameter) =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#region Drag and Drop
|
||||
|
||||
public static readonly DependencyProperty DraggedItemProperty = DependencyProperty.Register(nameof(DraggedItem), typeof(Server), typeof(ServerMonitorWindow), new PropertyMetadata(null));
|
||||
|
||||
public Server DraggedItem
|
||||
{
|
||||
get { return (Server)GetValue(DraggedItemProperty); }
|
||||
set { SetValue(DraggedItemProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsDragging { get; set; }
|
||||
|
||||
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ResetDragDrop();
|
||||
|
||||
// check fi the column is a template column (no drag-n-drop for those column types)
|
||||
var cell = WindowUtils.TryFindFromPoint<DataGridCell>((UIElement)sender, e.GetPosition(ServersGrid));
|
||||
if (cell != null) return;
|
||||
|
||||
// check if we have a valid row
|
||||
var row = WindowUtils.TryFindFromPoint<DataGridRow>((UIElement)sender, e.GetPosition(ServersGrid));
|
||||
if (row == null) return;
|
||||
|
||||
// set flag that indicates we're capturing mouse movements
|
||||
IsDragging = true;
|
||||
DraggedItem = (Server)row.Item;
|
||||
}
|
||||
|
||||
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!IsDragging)
|
||||
{
|
||||
if (popup.IsOpen)
|
||||
popup.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//get the target item
|
||||
var targetItem = (Server)ServersGrid.SelectedItem;
|
||||
|
||||
if (targetItem == null || !ReferenceEquals(DraggedItem, targetItem))
|
||||
{
|
||||
//get target index
|
||||
var targetIndex = ServerManager.Servers.IndexOf(targetItem);
|
||||
|
||||
//move source at the target's location
|
||||
Move(DraggedItem, targetIndex);
|
||||
|
||||
//select the dropped item
|
||||
ServersGrid.SelectedItem = DraggedItem;
|
||||
}
|
||||
|
||||
//reset
|
||||
ResetDragDrop();
|
||||
}
|
||||
|
||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!IsDragging || e.LeftButton != MouseButtonState.Pressed)
|
||||
{
|
||||
if (popup.IsOpen)
|
||||
popup.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// display the popup if it hasn't been opened yet
|
||||
if (!popup.IsOpen)
|
||||
{
|
||||
// switch to read-only mode
|
||||
ServersGrid.IsReadOnly = true;
|
||||
|
||||
// make sure the popup is visible
|
||||
popup.IsOpen = true;
|
||||
}
|
||||
|
||||
var popupSize = new Size(popup.ActualWidth, popup.ActualHeight);
|
||||
popup.PlacementRectangle = new Rect(e.GetPosition(this), popupSize);
|
||||
|
||||
// make sure the row under the grid is being selected
|
||||
var position = e.GetPosition(ServersGrid);
|
||||
var row = WindowUtils.TryFindFromPoint<DataGridRow>(ServersGrid, position);
|
||||
if (row != null) ServersGrid.SelectedItem = row.Item;
|
||||
}
|
||||
|
||||
public void Move(Server draggedItem, int newIndex)
|
||||
{
|
||||
if (draggedItem == null)
|
||||
return;
|
||||
|
||||
var index = ServerManager.Servers.IndexOf(draggedItem);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
ServerManager.Servers.Move(index, newIndex);
|
||||
UpdateSequence();
|
||||
}
|
||||
|
||||
private void ResetDragDrop()
|
||||
{
|
||||
IsDragging = false;
|
||||
popup.IsOpen = false;
|
||||
ServersGrid.IsReadOnly = false;
|
||||
}
|
||||
|
||||
public void UpdateSequence()
|
||||
{
|
||||
foreach (var server in ServerManager.Servers)
|
||||
{
|
||||
server.Profile.Sequence = ServerManager.Servers.IndexOf(server) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1641
src/ConanServerManager/Windows/ServerSettingsControl.xaml
Normal file
1641
src/ConanServerManager/Windows/ServerSettingsControl.xaml
Normal file
File diff suppressed because it is too large
Load diff
1509
src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs
Normal file
1509
src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs
Normal file
File diff suppressed because it is too large
Load diff
28
src/ConanServerManager/Windows/SettingsWindow.xaml
Normal file
28
src/ConanServerManager/Windows/SettingsWindow.xaml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<Window x:Class="ServerManagerTool.SettingsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sm="clr-namespace:ServerManagerTool"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="800" MinHeight="600" Width="800" Height="700" ResizeMode="CanResizeWithGrip" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Closing="SettingsWindow_Closing"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource Settings_Title}" >
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<sm:GlobalSettingsControl x:Name="globalSettingsControl" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch" Background="{StaticResource BeigeGradient}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
113
src/ConanServerManager/Windows/SettingsWindow.xaml.cs
Normal file
113
src/ConanServerManager/Windows/SettingsWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SettingsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsWindow : Window
|
||||
{
|
||||
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(SettingsWindow), new PropertyMetadata(null));
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public SettingsWindow()
|
||||
{
|
||||
this.AppInstance = App.Instance;
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
}
|
||||
|
||||
public App AppInstance
|
||||
{
|
||||
get { return GetValue(AppInstanceProperty) as App; }
|
||||
set { SetValue(AppInstanceProperty, value); }
|
||||
}
|
||||
|
||||
private void SettingsWindow_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (!globalSettingsControl.IsEnabled)
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
if (SecurityUtils.IsAdministrator())
|
||||
{
|
||||
// check if the Auto Update has been enabled.
|
||||
if (Config.Default.AutoUpdate_EnableUpdate)
|
||||
{
|
||||
// check if an update period has been set.
|
||||
if (Config.Default.AutoUpdate_UpdatePeriod <= 0)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_CacheUpdate_DisabledLabel"), _globalizer.GetResourceString("GlobalSettings_CacheUpdate_DisabledTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
// check if the cache directory has been set and it exists.
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir) || !Directory.Exists(Config.Default.AutoUpdate_CacheDir))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_CacheDirectory_ErrorLabel"), _globalizer.GetResourceString("GlobalSettings_CacheDirectory_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var taskKey = TaskSchedulerUtils.ComputeKey(Config.Default.DataPath);
|
||||
|
||||
var command = Assembly.GetEntryAssembly().Location;
|
||||
if (!TaskSchedulerUtils.ScheduleAutoUpdate(taskKey, null, command, Config.Default.AutoUpdate_EnableUpdate ? Config.Default.AutoUpdate_UpdatePeriod : 0))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_CacheTaskUpdate_ErrorLabel"), _globalizer.GetResourceString("GlobalSettings_CacheTaskUpdate_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Config.Default.AutoUpdate_EnableUpdate && Config.Default.AutoUpdate_UpdatePeriod > 0)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("GlobalSettings_CacheUpdate_EnabledLabel"), Config.Default.AutoUpdate_UpdatePeriod), _globalizer.GetResourceString("GlobalSettings_CacheUpdate_EnabledTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_CacheUpdate_DisabledLabel"), _globalizer.GetResourceString("GlobalSettings_CacheUpdate_DisabledTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
|
||||
if (!TaskSchedulerUtils.ScheduleAutoBackup(taskKey, null, command, Config.Default.AutoBackup_EnableBackup ? Config.Default.AutoBackup_BackupPeriod : 0))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_ErrorLabel"), _globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Config.Default.AutoBackup_EnableBackup && Config.Default.AutoBackup_BackupPeriod > 0)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_EnabledLabel"), Config.Default.AutoBackup_BackupPeriod), _globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_EnabledTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_DisabledLabel"), _globalizer.GetResourceString("GlobalSettings_BackupTaskUpdate_DisabledTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.Default.SteamCmdRedirectOutput && !Config.Default.SteamCmd_UseAnonymousCredentials)
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("GlobalSettings_SteamCMDAuthentication_DisabledLabel"), _globalizer.GetResourceString("GlobalSettings_SteamCMDAuthentication_DisabledTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Config.Default.SteamCmd_UseAnonymousCredentials = true;
|
||||
}
|
||||
|
||||
Config.Default.Save();
|
||||
CommonConfig.Default.Save();
|
||||
|
||||
Config.Default.Reload();
|
||||
CommonConfig.Default.Reload();
|
||||
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
254
src/ConanServerManager/Windows/ShutdownWindow.xaml
Normal file
254
src/ConanServerManager/Windows/ShutdownWindow.xaml
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
<Window x:Class="ServerManagerTool.ShutdownWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cctl="clr-namespace:ServerManagerTool.Common.Controls;assembly=ServerManager.Common"
|
||||
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters;assembly=ServerManager.Common"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
|
||||
Width="600" ResizeMode="CanMinimize" SizeToContent="Height" WindowStyle="SingleBorderWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="True"
|
||||
Closing="Window_Closing" Closed="Window_Closed"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource ShutdownWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<cc:InvertBooleanConverter x:Key="InvertBooleanConverter"/>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
<SolidColorBrush x:Key="BeigeLabel" Color="#FFE6DFD8"/>
|
||||
<SolidColorBrush x:Key="BeigeBorder" Color="#FFD8CCBC"/>
|
||||
|
||||
<Style x:Key="GroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource BeigeBorder}"/>
|
||||
</Style>
|
||||
|
||||
<ContentControl x:Key="ShutdownButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Width="16" Height="16" Margin="5,0,5,0" Source="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}" VerticalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource ShutdownWindow_ShutdownButtonLabel}" VerticalAlignment="Center" Padding="5,0"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="RestartButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Width="16" Height="16" Margin="5,0,5,0" Source="{com:Icon Path=/ConanServerManager;component/Art/Start.ico,Size=32}" VerticalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource ShutdownWindow_RestartButtonLabel}" VerticalAlignment="Center" Padding="5,0"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="CancelShutdownButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Width="16" Height="16" Margin="5,0,5,0" Source="{com:Icon Path=/ConanServerManager;component/Art/Cancel.ico,Size=32}" VerticalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource ShutdownWindow_CancelShutdownButtonLabel}" VerticalAlignment="Center" Padding="5,0"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="StopButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Width="16" Height="16" Margin="5,0,5,0" Source="{com:Icon Path=/ConanServerManager;component/Art/Stop.ico,Size=32}" VerticalAlignment="Center"/>
|
||||
<Label Content="{DynamicResource ShutdownWindow_StopButtonLabel}" VerticalAlignment="Center" Padding="5,0"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="CancelButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource ShutdownWindow_CloseButtonLabel}" VerticalAlignment="Center" Padding="5,0"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" DataContext="{Binding Server.Runtime}" Margin="2,0,2,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Column="0" Margin="0,2,0,2" Background="{DynamicResource BeigeLabel}" ToolTip="{DynamicResource ServerSettings_StatusTooltip}">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Label FontSize="15" Content="{DynamicResource ServerSettings_StatusLabel}"/>
|
||||
<Label FontSize="15" Content="{Binding StatusString}" MinWidth="100"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Grid.Column="1" Margin="2,2,0,2" Background="{DynamicResource BeigeLabel}" ToolTip="{DynamicResource ServerSettings_PlayersTooltip}">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Label FontSize="15" Content="{DynamicResource ServerSettings_PlayersLabel}"/>
|
||||
<Label FontSize="15" Content="{Binding Players}"/>
|
||||
<Label FontSize="15" Content="/" Width="20"/>
|
||||
<Label FontSize="15" Content="{Binding MaxPlayers}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<GroupBox Grid.Row="1" Style="{StaticResource GroupBoxStyle}" Margin="2,0,2,2">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource ShutdownWindow_ShutdownRestartOptionsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5" Content="{DynamicResource ShutdownWindow_CheckForOnlinePlayersLabel}" IsChecked="{Binding CheckForOnlinePlayers}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_CheckForOnlinePlayersTooltip}" HorizontalAlignment="Left"/>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5" Content="{DynamicResource ShutdownWindow_SendShutdownMessagesLabel}" IsChecked="{Binding SendShutdownMessages}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_SendShutdownMessagesTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<cctl:AnnotatedSlider Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="1" Label="{DynamicResource ShutdownWindow_ShutdownIntervalLabel}" Value="{Binding ShutdownInterval}" Minimum="0" Maximum="60" SmallChange="1" LargeChange="5" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Minutes}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_ShutdownIntervalTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5" Content="{DynamicResource ShutdownWindow_BackupWorldFileLabel}" IsChecked="{Binding BackupWorldFile}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_BackupWorldFileTooltip}" HorizontalAlignment="Left">
|
||||
<CheckBox.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type CheckBox}}" TargetType="{x:Type CheckBox}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Server.Profile.SOTF_Enabled}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Server.Profile.SOTF_Enabled}" Value="False">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</CheckBox.Style>
|
||||
</CheckBox>
|
||||
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5" Content="{DynamicResource ShutdownWindow_UpdateServerLabel}" IsChecked="{Binding UpdateServer}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_UpdateServerTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="0" Margin="5" Content="{DynamicResource ShutdownWindow_RestartServerLabel}" IsChecked="{Binding RestartServer}" IsEnabled="{Binding ShutdownStarted, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ShutdownWindow_RestartServerTooltip}" HorizontalAlignment="Left"/>
|
||||
|
||||
<Grid Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Content="{DynamicResource ShutdownWindow_ShutdownReasonLabel}" ToolTip="{DynamicResource ShutdownWindow_ShutdownReasonTooltip}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ShutdownReason}" ToolTip="{DynamicResource ShutdownWindow_ShutdownReasonTooltip}"/>
|
||||
</Grid>
|
||||
|
||||
<TextBox Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" Name="MessageOutput" Margin="1" Height="200" HorizontalAlignment="Stretch" IsReadOnly="True" IsReadOnlyCaretVisible="True" TextWrapping="NoWrap" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Server.Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ShutdownType}" Value="1">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ShutdownType}" Value="2">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="2" Margin="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MinWidth="75" Width="Auto"/>
|
||||
<ColumnDefinition MinWidth="75" Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition MinWidth="75" Width="Auto"/>
|
||||
<ColumnDefinition MinWidth="75" Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" Margin="0" Padding="5" VerticalAlignment="Center" Click="Shutdown_Click">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="IsEnabled" Value="False" />
|
||||
<Setter Property="Content" Value="{StaticResource ShutdownButtonContent}" />
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ShutdownWindow_ShutdownButtonTooltip}" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Server.Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}" />
|
||||
<Condition Binding="{Binding ShutdownStarted}" Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</MultiDataTrigger>
|
||||
<DataTrigger Binding="{Binding RestartServer}" Value="True">
|
||||
<Setter Property="Content" Value="{StaticResource RestartButtonContent}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ShutdownWindow_RestartButtonTooltip}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Grid.Row="0" Grid.Column="1" Margin="5,0,0,0" Padding="5" VerticalAlignment="Center" Name="CancelShutdownButton" Click="CancelShutdown_Click">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="Content" Value="{StaticResource CancelShutdownButtonContent}" />
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ShutdownWindow_CancelShutdownButtonTooltip}" />
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Server.Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}" />
|
||||
<Condition Binding="{Binding ShutdownStarted}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Grid.Row="0" Grid.Column="3" Margin="5,0,0,0" Padding="5" VerticalAlignment="Center" Click="Stop_Click">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="IsEnabled" Value="False" />
|
||||
<Setter Property="Content" Value="{StaticResource StopButtonContent}" />
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ShutdownWindow_StopButtonTooltip}" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding Server.Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}" />
|
||||
<Condition Binding="{Binding ShutdownStarted}" Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="IsEnabled" Value="True"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Grid.Row="0" Grid.Column="4" Margin="5,0,0,0" Padding="5" VerticalAlignment="Center" Click="Cancel_Click">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="IsEnabled" Value="True" />
|
||||
<Setter Property="Content" Value="{StaticResource CancelButtonContent}" />
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ShutdownWindow_CloseButtonTooltip}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ShutdownStarted}" Value="True">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
276
src/ConanServerManager/Windows/ShutdownWindow.xaml.cs
Normal file
276
src/ConanServerManager/Windows/ShutdownWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
using static ServerManagerTool.Lib.ServerApp;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ShutdownWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ShutdownWindow : Window
|
||||
{
|
||||
private static readonly List<Server> Instances = new List<Server>();
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private CancellationTokenSource _shutdownCancellationSource = null;
|
||||
|
||||
public static readonly DependencyProperty CheckForOnlinePlayersProperty = DependencyProperty.Register(nameof(CheckForOnlinePlayers), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(Config.Default.ServerShutdown_CheckForOnlinePlayers));
|
||||
public static readonly DependencyProperty SendShutdownMessagesProperty = DependencyProperty.Register(nameof(SendShutdownMessages), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(Config.Default.ServerShutdown_SendShutdownMessages));
|
||||
public static readonly DependencyProperty BackupWorldFileProperty = DependencyProperty.Register(nameof(BackupWorldFile), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(Config.Default.BackupWorldFile));
|
||||
public static readonly DependencyProperty RestartServerProperty = DependencyProperty.Register(nameof(RestartServer), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty ShowMessageOutputProperty = DependencyProperty.Register(nameof(ShowMessageOutput), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty ShutdownIntervalProperty = DependencyProperty.Register(nameof(ShutdownInterval), typeof(int), typeof(ShutdownWindow), new PropertyMetadata(Config.Default.ServerShutdown_GracePeriod));
|
||||
public static readonly DependencyProperty ShutdownStartedProperty = DependencyProperty.Register(nameof(ShutdownStarted), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty ShutdownTypeProperty = DependencyProperty.Register(nameof(ShutdownType), typeof(int), typeof(ShutdownWindow), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty ServerProperty = DependencyProperty.Register(nameof(Server), typeof(Server), typeof(ShutdownWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ShutdownReasonProperty = DependencyProperty.Register(nameof(ShutdownReason), typeof(string), typeof(ShutdownWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty UpdateServerProperty = DependencyProperty.Register(nameof(UpdateServer), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty CloseShutdownWindowWhenFinishedProperty = DependencyProperty.Register(nameof(CloseShutdownWindowWhenFinished), typeof(bool), typeof(ShutdownWindow), new PropertyMetadata(false));
|
||||
|
||||
protected ShutdownWindow(Server server)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
Server = server;
|
||||
BackupWorldFile = Config.Default.BackupWorldFile;
|
||||
this.Title = string.Format(_globalizer.GetResourceString("ShutdownWindow_ProfileTitle"), server?.Profile?.ProfileName);
|
||||
this.CloseShutdownWindowWhenFinished = Config.Default.CloseShutdownWindowWhenFinished;
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public bool CheckForOnlinePlayers
|
||||
{
|
||||
get { return (bool)GetValue(CheckForOnlinePlayersProperty); }
|
||||
set { SetValue(CheckForOnlinePlayersProperty, value); }
|
||||
}
|
||||
public bool SendShutdownMessages
|
||||
{
|
||||
get { return (bool)GetValue(SendShutdownMessagesProperty); }
|
||||
set { SetValue(SendShutdownMessagesProperty, value); }
|
||||
}
|
||||
public bool BackupWorldFile
|
||||
{
|
||||
get { return (bool)GetValue(BackupWorldFileProperty); }
|
||||
set { SetValue(BackupWorldFileProperty, value); }
|
||||
}
|
||||
public bool RestartServer
|
||||
{
|
||||
get { return (bool)GetValue(RestartServerProperty); }
|
||||
set { SetValue(RestartServerProperty, value); }
|
||||
}
|
||||
public bool ShowMessageOutput
|
||||
{
|
||||
get { return (bool)GetValue(ShowMessageOutputProperty); }
|
||||
set { SetValue(ShowMessageOutputProperty, value); }
|
||||
}
|
||||
public int ShutdownInterval
|
||||
{
|
||||
get { return (int)GetValue(ShutdownIntervalProperty); }
|
||||
set { SetValue(ShutdownIntervalProperty, value); }
|
||||
}
|
||||
public bool ShutdownStarted
|
||||
{
|
||||
get { return (bool)GetValue(ShutdownStartedProperty); }
|
||||
set { SetValue(ShutdownStartedProperty, value); }
|
||||
}
|
||||
public int ShutdownType
|
||||
{
|
||||
get { return (int)GetValue(ShutdownTypeProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(ShutdownTypeProperty, value);
|
||||
ShowMessageOutput = value == 1;
|
||||
ShutdownStarted = value > 0;
|
||||
}
|
||||
}
|
||||
public Server Server
|
||||
{
|
||||
get { return (Server)GetValue(ServerProperty); }
|
||||
set { SetValue(ServerProperty, value); }
|
||||
}
|
||||
public string ShutdownReason
|
||||
{
|
||||
get { return (string)GetValue(ShutdownReasonProperty); }
|
||||
set { SetValue(ShutdownReasonProperty, value); }
|
||||
}
|
||||
public bool UpdateServer
|
||||
{
|
||||
get { return (bool)GetValue(UpdateServerProperty); }
|
||||
set { SetValue(UpdateServerProperty, value); }
|
||||
}
|
||||
public bool CloseShutdownWindowWhenFinished
|
||||
{
|
||||
get { return (bool)GetValue(CloseShutdownWindowWhenFinishedProperty); }
|
||||
set { SetValue(CloseShutdownWindowWhenFinishedProperty, value); }
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (ShutdownStarted)
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
Instances.Remove(Server);
|
||||
Server = null;
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ShutdownStarted)
|
||||
return;
|
||||
|
||||
// close the form.
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void CancelShutdown_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_shutdownCancellationSource == null || _shutdownCancellationSource.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_shutdownCancellationSource.Cancel();
|
||||
}
|
||||
|
||||
private async void Shutdown_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await StartShutdownAsync();
|
||||
}
|
||||
|
||||
private async void Stop_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ShutdownStarted)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
ShutdownType = 2;
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
|
||||
PluginHelper.Instance.ProcessAlert(AlertType.Shutdown, Server.Profile.ProfileName, Config.Default.Alert_ServerStopMessage);
|
||||
await Task.Delay(2000);
|
||||
|
||||
await this.Server.StopAsync();
|
||||
|
||||
ShutdownType = 0;
|
||||
this.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_StopServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
ShutdownType = 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = null);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMessage(string message, bool includeNewLine = true)
|
||||
{
|
||||
MessageOutput.AppendText(message);
|
||||
if (includeNewLine)
|
||||
MessageOutput.AppendText(Environment.NewLine);
|
||||
MessageOutput.ScrollToEnd();
|
||||
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
public static bool HasInstance(Server server)
|
||||
{
|
||||
return Instances.Contains(server);
|
||||
}
|
||||
|
||||
public static ShutdownWindow OpenShutdownWindow(Server server)
|
||||
{
|
||||
if (HasInstance(server))
|
||||
return null;
|
||||
|
||||
Instances.Add(server);
|
||||
return new ShutdownWindow(server);
|
||||
}
|
||||
|
||||
public async Task StartShutdownAsync()
|
||||
{
|
||||
if (ShutdownStarted)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
MessageOutput.Clear();
|
||||
|
||||
ShutdownType = 1;
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
Application.Current.Dispatcher.Invoke(() => this.CancelShutdownButton.Cursor = System.Windows.Input.Cursors.Arrow);
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
CheckForOnlinePlayers = this.CheckForOnlinePlayers,
|
||||
SendMessages = this.SendShutdownMessages,
|
||||
BackupWorldFile = this.BackupWorldFile,
|
||||
ShutdownInterval = this.ShutdownInterval,
|
||||
ShutdownReason = this.ShutdownReason,
|
||||
OutputLogs = false,
|
||||
SendAlerts = true,
|
||||
ServerProcess = RestartServer ? ServerProcessType.Restart : ServerProcessType.Shutdown,
|
||||
ProgressCallback = (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { this.AddMessage(m, n); }).DoNotWait(); },
|
||||
};
|
||||
|
||||
// if restarting the serverm, then check and update the public IP address
|
||||
if (RestartServer && Config.Default.ManagePublicIPAutomatically)
|
||||
{
|
||||
await App.DiscoverMachinePublicIPAsync(false);
|
||||
}
|
||||
|
||||
var profile = ServerProfileSnapshot.Create(Server.Profile);
|
||||
var restartServer = RestartServer;
|
||||
var updateServer = UpdateServer;
|
||||
|
||||
_shutdownCancellationSource = new CancellationTokenSource();
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileShutdown(profile, restartServer, updateServer, false, CommonConfig.Default.SteamCmdRemoveQuit, _shutdownCancellationSource.Token));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
throw new ApplicationException($"An error occured during the shutdown process - ExitCode: {exitCode}");
|
||||
|
||||
if (restartServer)
|
||||
{
|
||||
profile.Update(Server.Profile);
|
||||
Server.Profile.SaveProfile();
|
||||
}
|
||||
|
||||
ShutdownType = 0;
|
||||
// if restarting or updating the server after the shutdown, delay the form closing
|
||||
if (restartServer || updateServer)
|
||||
await Task.Delay(5000);
|
||||
|
||||
if (this.CloseShutdownWindowWhenFinished)
|
||||
this.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ShutdownServer_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
ShutdownType = 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_shutdownCancellationSource = null;
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = null);
|
||||
Application.Current.Dispatcher.Invoke(() => this.CancelShutdownButton.Cursor = null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/ConanServerManager/Windows/VersionFeedWindow.xaml
Normal file
65
src/ConanServerManager/Windows/VersionFeedWindow.xaml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<Window x:Class="ServerManagerTool.VersionFeedWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common"
|
||||
xmlns:cmod="clr-namespace:ServerManagerTool.Common.Model;assembly=ServerManager.Common"
|
||||
MinWidth="400" MinHeight="400" Width="640" Height="480" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResizeWithGrip"
|
||||
Loaded="Window_Loaded"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource VersionFeedWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="Version" TargetType="Label">
|
||||
<Setter Property="Content" Value="{Binding Title}"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Foreground" Value="#0066CC"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Margin="5,5,0,0" Content="{DynamicResource VersionFeedWindow_VersionFilterLabel}"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="5,5,5,0" ItemsSource="{Binding FeedEntries}" SelectedValue="{Binding SelectedFeedEntry}" ToolTip="{DynamicResource VersionFeedWindow_VersionFilterTooltip}">
|
||||
<ComboBox.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type ComboBoxItem}" >
|
||||
<Setter Property="Height" Value="20" />
|
||||
</Style>
|
||||
</ComboBox.ItemContainerStyle>
|
||||
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type cmod:VersionFeedEntry}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<Label Padding="0,-1,0,-1" VerticalAlignment="Center" Style="{DynamicResource Version}"/>
|
||||
<TextBlock Text="{Binding Updated, StringFormat= - {0:G}}" Margin="5,0,0,0" Padding="0,-1,0,-1" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<Button Grid.Row="0" Grid.Column="2" Width="22" Height="22" Margin="5,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="PatchNotes_Click" ToolTip="{DynamicResource ServerSettings_PatchNotesTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Website.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<WebBrowser Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Margin="5" clib:BrowserBehavior.Html="{Binding SelectedFeedEntry.Content}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
106
src/ConanServerManager/Windows/VersionFeedWindow.xaml.cs
Normal file
106
src/ConanServerManager/Windows/VersionFeedWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for VersionFeedWindow.xaml
|
||||
/// </summary>
|
||||
public partial class VersionFeedWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(VersionFeedWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty FeedEntriesProperty = DependencyProperty.Register(nameof(FeedEntries), typeof(ObservableCollection<VersionFeedEntry>), typeof(VersionFeedWindow), new PropertyMetadata(new ObservableCollection<VersionFeedEntry>()));
|
||||
public static readonly DependencyProperty SelectedFeedEntryProperty = DependencyProperty.Register(nameof(SelectedFeedEntry), typeof(VersionFeedEntry), typeof(VersionFeedWindow), new PropertyMetadata(null));
|
||||
|
||||
private string feedUri = string.Empty;
|
||||
|
||||
public VersionFeedWindow(string feedUri)
|
||||
{
|
||||
this.AppInstance = App.Instance;
|
||||
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
this.feedUri = feedUri;
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public App AppInstance
|
||||
{
|
||||
get { return GetValue(AppInstanceProperty) as App; }
|
||||
set { SetValue(AppInstanceProperty, value); }
|
||||
}
|
||||
|
||||
public ObservableCollection<VersionFeedEntry> FeedEntries
|
||||
{
|
||||
get { return (ObservableCollection<VersionFeedEntry>)GetValue(FeedEntriesProperty); }
|
||||
set { SetValue(FeedEntriesProperty, value); }
|
||||
}
|
||||
|
||||
public VersionFeedEntry SelectedFeedEntry
|
||||
{
|
||||
get { return (VersionFeedEntry)GetValue(SelectedFeedEntryProperty); }
|
||||
set { SetValue(SelectedFeedEntryProperty, value); }
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadFeed();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("VersionFeedWindow_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchNotes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var url = string.Empty;
|
||||
if (AppInstance.BetaVersion)
|
||||
url = Config.Default.LatestServerManagerBetaPatchNotesUrl;
|
||||
else
|
||||
url = Config.Default.LatestServerManagerPatchNotesUrl;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return;
|
||||
|
||||
Process.Start(url);
|
||||
}
|
||||
|
||||
private void LoadFeed()
|
||||
{
|
||||
FeedEntries.Clear();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(this.feedUri))
|
||||
return;
|
||||
|
||||
var versionFeed = VersionFeedUtils.LoadVersionFeed(this.feedUri, AppInstance.Version);
|
||||
if (versionFeed == null)
|
||||
return;
|
||||
|
||||
foreach (var entry in versionFeed.Entries)
|
||||
{
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
FeedEntries.Add(entry);
|
||||
}
|
||||
|
||||
SelectedFeedEntry = FeedEntries.OrderByDescending(e => e.Updated).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
147
src/ConanServerManager/Windows/WorkshopFilesWindow.xaml
Normal file
147
src/ConanServerManager/Windows/WorkshopFilesWindow.xaml
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<Window x:Class="ServerManagerTool.WorkshopFilesWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
MinWidth="700" MinHeight="480" Width="800" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Loaded="Window_Loaded"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource WorkshopFiles_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="10*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" Width="22" Height="22" Margin="5,5,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Reload_Click" ToolTip="{DynamicResource WorkshopFiles_ReloadTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Reload.ico,Size=32}"/>
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock Margin="10,5,5,0" Text="{DynamicResource WorkshopFiles_TotalCountLabel}" VerticalAlignment="Center" />
|
||||
<TextBlock Margin="5,5,5,0" Text="{Binding WorkshopFiles.Count}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal">
|
||||
<TextBlock Margin="30,5,5,0" Text="{DynamicResource WorkshopFiles_LastRefreshedLabel}" VerticalAlignment="Center" />
|
||||
<TextBlock Margin="5,5,5,0" Text="{Binding WorkshopFiles.CachedTimeFormatted}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Margin="0,5,0,0" Orientation="Horizontal" Height="30" DataContext="{Binding}">
|
||||
<TextBlock Margin="5,0,5,0" Text="{DynamicResource General_FilterLabel}" VerticalAlignment="Center" />
|
||||
<TextBox Margin="5,0,5,0" Text="{Binding WorkshopFilterString, Mode=TwoWay}" Width="200" Padding="2" VerticalAlignment="Center"/>
|
||||
<Button Margin="5,0,5,0" Width="22" Height="22" HorizontalAlignment="Left" VerticalAlignment="Center" Click="FilterWorkshopFiles_Click" ToolTip="{DynamicResource General_FilterButtonTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Filter.ico,Size=32}"/>
|
||||
</Button>
|
||||
<CheckBox Margin="5,0,5,0" IsChecked="{Binding WorkshopFilterExisting, Mode=TwoWay}" Content="{DynamicResource WorkshopFiles_FilterExistingLabel}" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding WorkshopFilesView}" Margin="5" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" CanUserSortColumns="True" RowHeaderWidth="0" SelectionMode="Single">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Add_Click" ToolTip="{DynamicResource WorkshopFiles_AddTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Add.ico,Size=32}"/>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="Auto" MinWidth="100" CanUserSort="True" SortMemberPath="WorkshopId" Header="{DynamicResource WorkshopFiles_ModIdColumnLabel}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock>
|
||||
<Hyperlink NavigateUri="{Binding WorkshopUrl}" RequestNavigate="RequestNavigate_Click">
|
||||
<TextBlock Text="{Binding WorkshopId}"/>
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Width="1*" Binding="{Binding Title, Mode=OneWay}" Header="{DynamicResource WorkshopFiles_TitleColumnLabel}"/>
|
||||
<DataGridTextColumn Width="130" Binding="{Binding CreatedDate, Mode=OneWay}" Header="{DynamicResource WorkshopFiles_CreatedDateColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="130" Binding="{Binding UpdatedDate, Mode=OneWay}" Header="{DynamicResource WorkshopFiles_UpdatedDateColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="80" Binding="{Binding Subscriptions, Mode=OneWay}" Header="{DynamicResource WorkshopFiles_SubscriptionsColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="80" Binding="{Binding FileSize, Mode=OneWay}" Header="{DynamicResource WorkshopFiles_FileSizeColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</Window>
|
||||
237
src/ConanServerManager/Windows/WorkshopFilesWindow.xaml.cs
Normal file
237
src/ConanServerManager/Windows/WorkshopFilesWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Navigation;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WorkshopFilesWindow.xaml
|
||||
/// </summary>
|
||||
public partial class WorkshopFilesWindow : Window
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly ServerProfile _profile = null;
|
||||
private ModDetailList _modDetails = null;
|
||||
|
||||
private readonly ModDetailsWindow _window = null;
|
||||
|
||||
public static readonly DependencyProperty WorkshopFilesProperty = DependencyProperty.Register(nameof(WorkshopFiles), typeof(WorkshopFileList), typeof(WorkshopFilesWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty WorkshopFilesViewProperty = DependencyProperty.Register(nameof(WorkshopFilesView), typeof(ICollectionView), typeof(WorkshopFilesWindow), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty WorkshopFilterStringProperty = DependencyProperty.Register(nameof(WorkshopFilterString), typeof(string), typeof(WorkshopFilesWindow), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty WorkshopFilterExistingProperty = DependencyProperty.Register(nameof(WorkshopFilterExisting), typeof(bool), typeof(WorkshopFilesWindow), new PropertyMetadata(false));
|
||||
|
||||
public WorkshopFilesWindow(ModDetailList modDetails, ServerProfile profile)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
_profile = profile;
|
||||
this.Title = string.Format(_globalizer.GetResourceString("WorkshopFiles_ProfileTitle"), _profile?.ProfileName);
|
||||
|
||||
UpdateModDetailsList(modDetails);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public WorkshopFilesWindow(ModDetailsWindow window, ServerProfile profile)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
_window = window;
|
||||
_profile = profile;
|
||||
this.Title = string.Format(_globalizer.GetResourceString("WorkshopFiles_ProfileTitle"), _profile?.ProfileName);
|
||||
|
||||
UpdateModDetailsList(window?.ModDetails);
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public WorkshopFileList WorkshopFiles
|
||||
{
|
||||
get { return GetValue(WorkshopFilesProperty) as WorkshopFileList; }
|
||||
set
|
||||
{
|
||||
SetValue(WorkshopFilesProperty, value);
|
||||
|
||||
WorkshopFilesView = CollectionViewSource.GetDefaultView(WorkshopFiles);
|
||||
WorkshopFilesView.Filter = new Predicate<object>(Filter);
|
||||
}
|
||||
}
|
||||
|
||||
public ICollectionView WorkshopFilesView
|
||||
{
|
||||
get { return GetValue(WorkshopFilesViewProperty) as ICollectionView; }
|
||||
set { SetValue(WorkshopFilesViewProperty, value); }
|
||||
}
|
||||
|
||||
public string WorkshopFilterString
|
||||
{
|
||||
get { return (string)GetValue(WorkshopFilterStringProperty); }
|
||||
set { SetValue(WorkshopFilterStringProperty, value); }
|
||||
}
|
||||
|
||||
public bool WorkshopFilterExisting
|
||||
{
|
||||
get { return (bool)GetValue(WorkshopFilterExistingProperty); }
|
||||
set { SetValue(WorkshopFilterExistingProperty, value); }
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadWorkshopItems(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("WorkshopFiles_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ModDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
WorkshopFilesView?.Refresh();
|
||||
}
|
||||
|
||||
private void Add_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = ((WorkshopFileItem)((Button)e.Source).DataContext);
|
||||
|
||||
var mod = ModDetail.GetModDetail(item);
|
||||
|
||||
var selectedIndex = _window?.SelectedRowIndex() ?? -1;
|
||||
if (selectedIndex >= 0)
|
||||
_modDetails.Insert(selectedIndex, mod);
|
||||
else
|
||||
_modDetails.Add(mod);
|
||||
}
|
||||
|
||||
private async void Reload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadWorkshopItems(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("WorkshopFiles_Refresh_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestNavigate_Click(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
var item = ((WorkshopFileItem)((Hyperlink)e.Source).DataContext);
|
||||
|
||||
Process.Start(new ProcessStartInfo(item.WorkshopUrl));
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async Task LoadWorkshopItems(bool loadFromCacheFile)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
WorkshopFileDetailResponse localCache = null;
|
||||
WorkshopFileDetailResponse steamCache = null;
|
||||
|
||||
await Task.Run( () => {
|
||||
var file = Path.Combine(Config.Default.DataPath, Config.Default.WorkshopCacheFile);
|
||||
|
||||
// try to load the cache file.
|
||||
localCache = WorkshopFileDetailResponse.Load(file);
|
||||
|
||||
if (loadFromCacheFile)
|
||||
{
|
||||
steamCache = localCache;
|
||||
|
||||
// check if the cache is old
|
||||
if (localCache != null && Config.Default.WorkshopCache_ExpiredHours > 0 && localCache.cached.AddHours(Config.Default.WorkshopCache_ExpiredHours) < DateTime.UtcNow)
|
||||
// cache is considered old, clear cache variable so it will reload from internet
|
||||
steamCache = null;
|
||||
}
|
||||
|
||||
// check if the cache exists
|
||||
if (steamCache == null)
|
||||
{
|
||||
steamCache = SteamUtils.GetSteamModDetails(Config.Default.AppId);
|
||||
if (steamCache != null)
|
||||
steamCache.Save(file);
|
||||
else
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("WorkshopFiles_Refresh_FailedLabel"), _globalizer.GetResourceString("WorkshopFiles_Refresh_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
steamCache = localCache;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
WorkshopFiles = WorkshopFileList.GetList(steamCache);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateModDetailsList(ModDetailList modDetails)
|
||||
{
|
||||
if (_modDetails != null)
|
||||
_modDetails.CollectionChanged -= ModDetails_CollectionChanged;
|
||||
|
||||
_modDetails = modDetails ?? new ModDetailList();
|
||||
if (_modDetails != null)
|
||||
_modDetails.CollectionChanged += ModDetails_CollectionChanged;
|
||||
|
||||
WorkshopFilesView?.Refresh();
|
||||
}
|
||||
|
||||
#region Filtering
|
||||
private void FilterWorkshopFiles_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WorkshopFilesView?.Refresh();
|
||||
}
|
||||
|
||||
public bool Filter(object obj)
|
||||
{
|
||||
var data = obj as WorkshopFileItem;
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
if (WorkshopFilterExisting && _modDetails.Any(m => m.ModId.Equals(data.WorkshopId)))
|
||||
return false;
|
||||
|
||||
var filterString = WorkshopFilterString.ToLower();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filterString))
|
||||
return true;
|
||||
|
||||
return data.WorkshopId.Contains(filterString) || data.TitleFilterString.Contains(filterString);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
127
src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml
Normal file
127
src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<Window x:Class="ServerManagerTool.WorldSaveRestoreWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
MinWidth="700" MinHeight="480" Width="800" Height="480" ResizeMode="CanResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Loaded="Window_Loaded"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource WorldSaveRestore_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<LinearGradientBrush x:Key="BeigeGradient" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource BeigeGradient}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Reload_Click" Margin="5,5,5,0" Width="22" Height="22" ToolTip="{DynamicResource WorldSaveRestore_ReloadTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Reload.ico,Size=32}" />
|
||||
</Button>
|
||||
|
||||
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding WorldSaveFiles}" Margin="5" AutoGenerateColumns="False" CanUserAddRows="False" CanUserReorderColumns="False" CanUserSortColumns="True" RowHeaderWidth="0" SelectionMode="Single">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</Style.Resources>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsActiveFile}" Value="True">
|
||||
<Setter Property="Background" Value="#FFF5DFB8" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsArchiveFile}" Value="True">
|
||||
<Setter Property="Foreground" Value="Blue" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.HorizontalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.HorizontalGridLinesBrush>
|
||||
<DataGrid.VerticalGridLinesBrush>
|
||||
<SolidColorBrush Color="#FFB4B4B4"/>
|
||||
</DataGrid.VerticalGridLinesBrush>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Width="1*" Binding="{Binding FileName, Mode=OneWay}" Header="{DynamicResource WorldSaveRestore_NameColumnLabel}"/>
|
||||
<DataGridTextColumn Width="130" Binding="{Binding CreatedDate, Mode=OneWay}" Header="{DynamicResource WorldSaveRestore_CreatedDateColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="130" Binding="{Binding UpdatedDate, Mode=OneWay}" Header="{DynamicResource WorldSaveRestore_UpdatedDateColumnLabel}">
|
||||
<DataGridTextColumn.HeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.HeaderStyle>
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Restore_Click" ToolTip="{DynamicResource WorldSaveRestore_RestoreTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Download.ico,Size=32}" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsActiveFile}" Value="True">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="30" CanUserReorder="False" CanUserResize="False">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Width="22" Height="22" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Delete_Click" ToolTip="{DynamicResource WorldSaveRestore_DeleteTooltip}">
|
||||
<Image Source="{com:Icon Path=/ConanServerManager;component/Art/Delete.ico,Size=32}" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellStyle>
|
||||
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsActiveFile}" Value="True">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</Window>
|
||||
295
src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs
Normal file
295
src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Lib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WorldSaveRestoreWindow.xaml
|
||||
/// </summary>
|
||||
public partial class WorldSaveRestoreWindow : Window
|
||||
{
|
||||
public class WorldSaveFileList : SortableObservableCollection<WorldSaveFile>
|
||||
{
|
||||
public new void Add(WorldSaveFile item)
|
||||
{
|
||||
if (item == null || this.Any(m => m.FileName.Equals(item.FileName)))
|
||||
return;
|
||||
|
||||
base.Add(item);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(WorldSaveFile)} - {Count}";
|
||||
}
|
||||
}
|
||||
|
||||
public class WorldSaveFile : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty CreatedDateProperty = DependencyProperty.Register(nameof(CreatedDate), typeof(DateTime), typeof(WorldSaveFile), new PropertyMetadata(DateTime.MinValue));
|
||||
public static readonly DependencyProperty FileProperty = DependencyProperty.Register(nameof(File), typeof(string), typeof(WorldSaveFile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register(nameof(FileName), typeof(string), typeof(WorldSaveFile), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty UpdatedDateProperty = DependencyProperty.Register(nameof(UpdatedDate), typeof(DateTime), typeof(WorldSaveFile), new PropertyMetadata(DateTime.MinValue));
|
||||
public static readonly DependencyProperty IsActiveFileProperty = DependencyProperty.Register(nameof(IsActiveFile), typeof(bool), typeof(WorldSaveFile), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsArchiveFileProperty = DependencyProperty.Register(nameof(IsArchiveFile), typeof(bool), typeof(WorldSaveFile), new PropertyMetadata(false));
|
||||
|
||||
public DateTime CreatedDate
|
||||
{
|
||||
get { return (DateTime)GetValue(CreatedDateProperty); }
|
||||
set { SetValue(CreatedDateProperty, value); }
|
||||
}
|
||||
|
||||
public string File
|
||||
{
|
||||
get { return (string)GetValue(FileProperty); }
|
||||
set { SetValue(FileProperty, value); }
|
||||
}
|
||||
|
||||
public string FileName
|
||||
{
|
||||
get { return (string)GetValue(FileNameProperty); }
|
||||
set { SetValue(FileNameProperty, value); }
|
||||
}
|
||||
|
||||
public DateTime UpdatedDate
|
||||
{
|
||||
get { return (DateTime)GetValue(UpdatedDateProperty); }
|
||||
set { SetValue(UpdatedDateProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsActiveFile
|
||||
{
|
||||
get { return (bool)GetValue(IsActiveFileProperty); }
|
||||
set { SetValue(IsActiveFileProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsArchiveFile
|
||||
{
|
||||
get { return (bool)GetValue(IsArchiveFileProperty); }
|
||||
set { SetValue(IsArchiveFileProperty, value); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return FileName;
|
||||
}
|
||||
}
|
||||
|
||||
public class WorldSaveFileComparer : IComparer<WorldSaveFile>
|
||||
{
|
||||
public int Compare(WorldSaveFile x, WorldSaveFile y)
|
||||
{
|
||||
if (x == null && y == null)
|
||||
return 0;
|
||||
if (x == null)
|
||||
return 1;
|
||||
if (y == null)
|
||||
return -1;
|
||||
|
||||
if (x.IsActiveFile && y.IsActiveFile)
|
||||
{
|
||||
if (x.UpdatedDate == y.UpdatedDate)
|
||||
return 0;
|
||||
return x.UpdatedDate < y.UpdatedDate ? 1 : -1;
|
||||
}
|
||||
if (x.IsActiveFile)
|
||||
return -1;
|
||||
if (y.IsActiveFile)
|
||||
return 1;
|
||||
|
||||
if (x.UpdatedDate == y.UpdatedDate)
|
||||
return 0;
|
||||
return x.UpdatedDate < y.UpdatedDate ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly ServerProfile _profile = null;
|
||||
|
||||
public static readonly DependencyProperty WorldSaveFilesProperty = DependencyProperty.Register(nameof(WorldSaveFiles), typeof(WorldSaveFileList), typeof(WorldSaveRestoreWindow), new PropertyMetadata(null));
|
||||
|
||||
public WorldSaveRestoreWindow(ServerProfile profile)
|
||||
{
|
||||
InitializeComponent();
|
||||
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
|
||||
|
||||
_profile = profile;
|
||||
this.Title = string.Format(_globalizer.GetResourceString("WorldSaveRestore_ProfileTitle"), _profile?.ProfileName);
|
||||
|
||||
WorldSaveFiles = new WorldSaveFileList();
|
||||
|
||||
this.DataContext = this;
|
||||
}
|
||||
|
||||
public WorldSaveFileList WorldSaveFiles
|
||||
{
|
||||
get { return GetValue(WorldSaveFilesProperty) as WorldSaveFileList; }
|
||||
set { SetValue(WorldSaveFilesProperty, value); }
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadWorldSaveFiles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("WorldSaveRestore_Load_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Delete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = ((WorldSaveFile)((Button)e.Source).DataContext);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
var deleteMessage = _globalizer.GetResourceString("WorldSaveRestore_DeleteConfirmationLabel");
|
||||
deleteMessage = deleteMessage.Replace("{fileName}", item.FileName);
|
||||
if (MessageBox.Show(this, deleteMessage, _globalizer.GetResourceString("WorldSaveRestore_DeleteConfirmationTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
File.Delete(item.File);
|
||||
|
||||
MessageBox.Show(this, _globalizer.GetResourceString("WorldSaveRestore_DeleteSuccessLabel"), _globalizer.GetResourceString("WorldSaveRestore_DeleteSuccessTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(this, ex.Message, _globalizer.GetResourceString("WorldSaveRestore_DeleteErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await LoadWorldSaveFiles();
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Reload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
await LoadWorldSaveFiles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, _globalizer.GetResourceString("WorldSaveRestore_Refresh_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Restore_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = ((WorldSaveFile)((Button)e.Source).DataContext);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
var confirmationMessage = _globalizer.GetResourceString("WorldSaveRestore_RestoreConfirmationLabel");
|
||||
confirmationMessage = confirmationMessage.Replace("{fileName}", item.FileName);
|
||||
if (MessageBox.Show(this, confirmationMessage, _globalizer.GetResourceString("WorldSaveRestore_RestoreConfirmationTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
var restoredFileCount = _profile.RestoreSaveFiles(item.File, item.IsArchiveFile);
|
||||
|
||||
var successMessage = _globalizer.GetResourceString("WorldSaveRestore_RestoreSuccessLabel");
|
||||
successMessage = successMessage.Replace("{fileCount}", restoredFileCount.ToString());
|
||||
MessageBox.Show(this, successMessage, _globalizer.GetResourceString("WorldSaveRestore_RestoreSuccessTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(this, ex.Message, _globalizer.GetResourceString("WorldSaveRestore_RestoreErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await LoadWorldSaveFiles();
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadWorldSaveFiles()
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
||||
try
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait);
|
||||
await Task.Delay(500);
|
||||
|
||||
WorldSaveFiles.Clear();
|
||||
|
||||
var saveFolder = ServerProfile.GetProfileSavePath(_profile);
|
||||
if (!Directory.Exists(saveFolder))
|
||||
return;
|
||||
|
||||
var saveFolderInfo = new DirectoryInfo(saveFolder);
|
||||
var mapFileName = _profile.ServerMapSaveFileName;
|
||||
var mapName = Path.GetFileNameWithoutExtension(mapFileName);
|
||||
var mapExtension = Path.GetExtension(mapFileName);
|
||||
|
||||
var searchPattern = $"{mapName}{mapExtension}";
|
||||
var saveFiles = saveFolderInfo.GetFiles(searchPattern);
|
||||
foreach (var file in saveFiles)
|
||||
{
|
||||
WorldSaveFiles.Add(new WorldSaveFile { File = file.FullName, FileName = file.Name, CreatedDate = file.CreationTime, UpdatedDate = file.LastWriteTime, IsArchiveFile = false, IsActiveFile = file.Name.Equals(mapFileName, StringComparison.OrdinalIgnoreCase) });
|
||||
}
|
||||
|
||||
searchPattern = $"{mapName}_backup_*{mapExtension}";
|
||||
saveFiles = saveFolderInfo.GetFiles(searchPattern);
|
||||
foreach (var file in saveFiles)
|
||||
{
|
||||
WorldSaveFiles.Add(new WorldSaveFile { File = file.FullName, FileName = file.Name, CreatedDate = file.CreationTime, UpdatedDate = file.LastWriteTime, IsArchiveFile = false, IsActiveFile = file.Name.Equals(mapFileName, StringComparison.OrdinalIgnoreCase) });
|
||||
}
|
||||
|
||||
var backupFolder = ServerApp.GetServerBackupFolder(_profile);
|
||||
if (Directory.Exists(backupFolder))
|
||||
{
|
||||
var backupFolderInfo = new DirectoryInfo(backupFolder);
|
||||
searchPattern = $"{mapName}*{Config.Default.BackupExtension}";
|
||||
|
||||
var backupFiles = backupFolderInfo.GetFiles(searchPattern);
|
||||
foreach (var file in backupFiles)
|
||||
{
|
||||
WorldSaveFiles.Add(new WorldSaveFile { File = file.FullName, FileName = file.Name, CreatedDate = file.CreationTime, UpdatedDate = file.LastWriteTime, IsArchiveFile = true, IsActiveFile = false });
|
||||
}
|
||||
}
|
||||
|
||||
WorldSaveFiles.Sort(f => f, new WorldSaveFileComparer());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => this.Cursor = cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue