Release 17 updates

This commit is contained in:
Brett Hewitson 2020-07-15 17:29:43 +10:00
parent 38dededb14
commit 4a54288072
11 changed files with 306 additions and 19 deletions

View file

@ -198,6 +198,18 @@ namespace ServerManagerTool.Plugin.Common
Plugins.Add(new PluginItem { Plugin = plugin, PluginFile = pluginFile, PluginType = nameof(IAlertPlugin) });
}
}
else if (type.GetInterface(typeof(IPlugin).Name) != null)
{
var plugin = assembly.CreateInstance(type.FullName) as IPlugin;
if (plugin != null && plugin.Enabled)
{
if (type.GetInterface(typeof(IBeta).Name) != null)
((IBeta)plugin).BetaEnabled = BetaEnabled;
plugin.Initialize();
Plugins.Add(new PluginItem { Plugin = plugin, PluginFile = pluginFile, PluginType = nameof(IPlugin) });
}
}
}
catch (Exception ex)
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View file

@ -96,6 +96,17 @@ namespace ServerManagerTool.Plugin.Discord
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
public void Move(int oldIndex, int newIndex)
{
var item = _listObject.ElementAt(oldIndex);
if (item != null)
{
_listObject.Remove(item);
_listObject.Insert(newIndex, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex));
}
}
public bool Remove(T item)
{
int index = _listObject.IndexOf(item);

View file

@ -26,6 +26,7 @@
<None Remove="Art\ChangeNotes.ico" />
<None Remove="Art\Delete.ico" />
<None Remove="Art\Download.ico" />
<None Remove="Art\Drag.ico" />
<None Remove="Art\Edit.ico" />
<None Remove="Art\favicon.ico" />
<None Remove="Globalization\en-US\en-US.xaml" />
@ -53,6 +54,7 @@
<Resource Include="Art\ChangeNotes.ico" />
<Resource Include="Art\Delete.ico" />
<Resource Include="Art\Download.ico" />
<Resource Include="Art\Drag.ico" />
<Resource Include="Art\Edit.ico" />
<Resource Include="Art\favicon.ico" />
<Resource Include="Globalization\en-US\en-US.xaml" />

View file

@ -30,5 +30,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.17.1")]
[assembly: AssemblyFileVersion("1.0.17.1")]
[assembly: AssemblyVersion("1.0.17.2")]
[assembly: AssemblyFileVersion("1.0.17.2")]

View file

@ -0,0 +1,122 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace ServerManagerTool.Plugin.Discord
{
public static class WindowUtils
{
public static void RemoveDefaultResourceDictionary(Window window, string defaultDictionary)
{
if (window == null)
return;
var dictToRemove = window.Resources.MergedDictionaries.FirstOrDefault(d => d.Source.OriginalString.Contains(defaultDictionary));
if (dictToRemove != null)
{
window.Resources.MergedDictionaries.Remove(dictToRemove);
}
}
public static void RemoveDefaultResourceDictionary(UserControl control, string defaultDictionary)
{
if (control == null)
return;
var dictToRemove = control.Resources.MergedDictionaries.FirstOrDefault(d => d.Source.OriginalString.Contains(defaultDictionary));
if (dictToRemove != null)
{
control.Resources.MergedDictionaries.Remove(dictToRemove);
}
}
/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the queried item.</param>
/// <returns>The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned.</returns>
public static T TryFindParent<T>(DependencyObject child)
where T : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
//use recursion to proceed with next level
return TryFindParent<T>(parentObject);
}
/// <summary>
/// This method is an alternative to WPF's <see cref="VisualTreeHelper.GetParent"/> method, which also supports content elements.
/// Do note, that for content element, this method falls back to the logical tree of the element.
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise null.</returns>
public static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
var contentElement = child as ContentElement;
if (contentElement != null)
{
var parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
var fce = contentElement as FrameworkContentElement;
return fce?.Parent;
}
//if it's not a ContentElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
/// <summary>
/// Recursively processes a given dependency object and all its children, and updates sources of all objects that use a binding expression on a given property.
/// </summary>
/// <param name="obj">The dependency object that marks a starting point. This could be a dialog window or a panel control that hosts bound controls.</param>
/// <param name="properties">The properties to be updated if
/// <paramref name="obj"/> or one of its childs provide it along with a binding expression.</param>
public static void UpdateBindingSources(DependencyObject obj, params DependencyProperty[] properties)
{
foreach (var depProperty in properties)
{
//check whether the submitted object provides a bound property that matches the property parameters
var be = BindingOperations.GetBindingExpression(obj, depProperty);
be?.UpdateSource();
}
int count = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < count; i++)
{
//process child items recursively
var childObject = VisualTreeHelper.GetChild(obj, i);
UpdateBindingSources(childObject, properties);
}
}
/// <summary>
/// Tries to locate a given item within the visual tree, starting with the dependency object at a given position.
/// </summary>
/// <typeparam name="T">The type of the element to be found on the visual tree of the element at the given location.</typeparam>
/// <param name="reference">The main element which is used to perform hit testing.</param>
/// <param name="point">The position to be evaluated on the origin.</param>
public static T TryFindFromPoint<T>(UIElement reference, Point point)
where T : DependencyObject
{
var element = reference.InputHitTest(point) as DependencyObject;
if (element == null) return null;
if (element is T) return (T)element;
return TryFindParent<T>(element);
}
}
}

View file

@ -9,8 +9,8 @@
<entry>
<id>urn:uuid:D8974ABF-8444-4D40-A594-D4443921B3B8</id>
<title>1.0.17 (1.0.17.1)</title>
<summary>1.0.17.1</summary>
<title>1.0.17 (1.0.17.2)</title>
<summary>1.0.17.2</summary>
<link href="" />
<updated>2020-07-13T00:00:00Z</updated>
<content type="xhtml">
@ -20,6 +20,7 @@
<br/>
<ul>
<li>Profile name has been converted to a droplist and is now populated with the Server Manager Profile Names for selection.</li>
<li>Added drag/drop feature to the config window.</li>
</ul>
</p>
</div>

View file

@ -5,14 +5,37 @@
<title>Discord Plugin Version Feed</title>
<subtitle>This is the Discord Plugin beta version feed.</subtitle>
<link href="" />
<updated>2020-07-13T00:00:00Z</updated>
<updated>2020-07-12T02:00:00Z</updated>
<entry>
<id>urn:uuid:4750D17C-2C8F-4D8C-AA17-B3512F002170</id>
<title>1.0.17 (1.0.17.2)</title>
<summary>1.0.17.2</summary>
<link href="" />
<updated>2020-07-12T02:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Added drag/drop feature to the config window.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:D8974ABF-8444-4D40-A594-D4443921B3B8</id>
<title>1.0.17 (1.0.17.1)</title>
<summary>1.0.17.1</summary>
<link href="" />
<updated>2020-07-13T00:00:00Z</updated>
<updated>2020-07-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>

View file

@ -132,7 +132,7 @@
</StackPanel>
</GroupBox.Header>
<DataGrid ItemsSource="{Binding Profile.ProfileNames}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
<DataGrid ItemsSource="{Binding Profile.ProfileNames}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
@ -150,7 +150,7 @@
</DataGrid.VerticalGridLinesBrush>
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" CanUserSort="True" SortMemberPath="DisplayName">
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.Header>
<TextBlock Text="{DynamicResource ConfigProfileWindow_ProfileNameColumnLabel}" />
</DataGridTemplateColumn.Header>
@ -161,7 +161,7 @@
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn Width="30" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="DeleteProfileName_Click" ToolTip="{DynamicResource ConfigProfileWindow_DeleteProfileNameTooltip}">
@ -188,7 +188,7 @@
</GroupBox.Header>
<DataGrid ItemsSource="{Binding Profile.AlertTypes}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
<DataGrid ItemsSource="{Binding Profile.AlertTypes}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
@ -206,7 +206,7 @@
</DataGrid.VerticalGridLinesBrush>
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.Header>
<TextBlock Text="{DynamicResource ConfigProfileWindow_AlertTypeColumnLabel}"/>
</DataGridTemplateColumn.Header>
@ -217,7 +217,7 @@
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn Width="30" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="DeleteAlertType_Click" ToolTip="{DynamicResource ConfigProfileWindow_DeleteAlertTypeTooltip}">

View file

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pc="clr-namespace:ServerManagerTool.Plugin.Common;assembly=ServerManager.Plugin.Common"
Title="{DynamicResource ConfigWindow_Title}"
Name="ConfigUI" Title="{DynamicResource ConfigWindow_Title}"
Icon="/ServerManager.Plugin.Discord;component/Art/favicon.ico"
Width="640" Height="480" MinWidth="640" MinHeight="480" ResizeMode="CanResizeWithGrip" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" Closing="ConfigWindow_Closing" Loaded="ConfigWindow_Loaded">
<Window.Resources>
@ -24,8 +24,8 @@
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid Background="{StaticResource BeigeGradient}">
<Grid Background="{StaticResource BeigeGradient}" MouseLeftButtonUp="OnMouseLeftButtonUp" MouseMove="OnMouseMove">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
@ -64,7 +64,7 @@
</StackPanel>
</GroupBox.Header>
<DataGrid ItemsSource="{Binding PluginConfig.ConfigProfiles}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25">
<DataGrid Name="ConfigsGrid" ItemsSource="{Binding PluginConfig.ConfigProfiles}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25" PreviewMouseLeftButtonDown="OnMouseLeftButtonDown">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
@ -93,7 +93,7 @@
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding Name}" IsReadOnly="True">
<DataGridTextColumn Width="*" IsReadOnly="True" Binding="{Binding Name}">
<DataGridTextColumn.Header>
<TextBlock Text="{DynamicResource ConfigWindow_NameColumnLabel}"/>
</DataGridTextColumn.Header>
@ -107,7 +107,7 @@
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn Width="30" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="EditConfigProfile_Click" ToolTip="{DynamicResource ConfigWindow_EditConfigProfileTooltip}">
@ -116,7 +116,7 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn Width="30" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="DeleteConfigProfile_Click" ToolTip="{DynamicResource ConfigWindow_DeleteConfigProfileTooltip}">
@ -133,5 +133,15 @@
<Button Content="{DynamicResource Global_SaveButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" Click="Save_Click"/>
<Button Content="{DynamicResource Global_CloseButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" IsCancel="True"/>
</StackPanel>
<!-- Drag and Drop Popup -->
<Popup x:Name="popup" IsHitTestVisible="False" Placement="RelativePoint" PlacementTarget="{Binding ElementName=ConfigUI}" AllowsTransparency="True">
<Border BorderBrush="LightSteelBlue" BorderThickness="2" Background="White" Opacity="0.75">
<StackPanel Orientation="Horizontal" Margin="4,3,8,3">
<Image Source="{pc:Icon Path=/ServerManager.Plugin.Discord;component/Art/Drag.ico,Size=32}" Width="16" Height="16"/>
<TextBlock FontSize="14" VerticalAlignment="Center" Text="{Binding DraggedItem.Name, ElementName=ConfigUI}" Margin="8,0,0,0" />
</StackPanel>
</Border>
</Popup>
</Grid>
</Window>

View file

@ -267,5 +267,111 @@ namespace ServerManagerTool.Plugin.Discord.Windows
JsonUtils.SerializeToFile(PluginConfig, configFile);
PluginConfig?.CommitChanges();
}
#region Drag and Drop
private static readonly DependencyProperty DraggedItemProperty = DependencyProperty.Register(nameof(DraggedItem), typeof(ConfigProfile), typeof(ConfigWindow), new PropertyMetadata(null));
private ConfigProfile DraggedItem
{
get { return GetValue(DraggedItemProperty) as ConfigProfile; }
set { SetValue(DraggedItemProperty, value); }
}
private 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(ConfigsGrid));
if (cell != null) return;
// check if we have a valid row
var row = WindowUtils.TryFindFromPoint<DataGridRow>((UIElement)sender, e.GetPosition(ConfigsGrid));
if (row == null) return;
// set flag that indicates we're capturing mouse movements
IsDragging = true;
DraggedItem = (ConfigProfile)row.Item;
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!IsDragging)
{
if (popup.IsOpen)
popup.IsOpen = false;
return;
}
//get the target item
var targetItem = (ConfigProfile)ConfigsGrid.SelectedItem;
if (targetItem == null || !ReferenceEquals(DraggedItem, targetItem))
{
//get target index
var targetIndex = PluginConfig.ConfigProfiles.IndexOf(targetItem);
//move source at the target's location
Move(DraggedItem, targetIndex);
//select the dropped item
ConfigsGrid.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
ConfigsGrid.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(ConfigsGrid);
var row = WindowUtils.TryFindFromPoint<DataGridRow>(ConfigsGrid, position);
if (row != null) ConfigsGrid.SelectedItem = row.Item;
}
private void Move(ConfigProfile draggedItem, int newIndex)
{
if (draggedItem == null)
return;
var index = PluginConfig.ConfigProfiles.IndexOf(draggedItem);
if (index < 0)
return;
PluginConfig.ConfigProfiles.Move(index, newIndex);
}
private void ResetDragDrop()
{
IsDragging = false;
popup.IsOpen = false;
ConfigsGrid.IsReadOnly = false;
}
#endregion
}
}