Fully implemented Operations UI with one example

- You can now add, remove, modify and move operations
- FilterChangedAny was renamed to FilterChanged, the new event for the preview follows the same naming scheme with PreviewChanged
- Operations now actually verify that they're enabled (This was originally supposed to be done in the loop in Preview(), but this way seems nicer since it also removes the error label when the operation is disabled)
- The foundation has been laid to make it very easy to add more operations
This commit is contained in:
adroslice 2019-11-17 02:22:13 +01:00
parent c51f848a31
commit 5d8327f071
4 changed files with 91 additions and 14 deletions

View File

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ops="clr-namespace:BFR.Operations;assembly=BFR"
mc:Ignorable="d" MinWidth="720" MinHeight="480" mc:Ignorable="d" MinWidth="720" MinHeight="480"
x:Class="BFR.MainWindow" x:Class="BFR.MainWindow"
Title="BFR"> Title="BFR">
@ -16,13 +17,13 @@
<!-- Filters --> <!-- Filters -->
<Grid Grid.Row="1" Grid.ColumnSpan="3" ColumnDefinitions="auto,*,auto,*,auto,auto,auto,auto" IsVisible="{Binding #FilterExpander.IsExpanded}"> <Grid Grid.Row="1" Grid.ColumnSpan="3" ColumnDefinitions="auto,*,auto,*,auto,auto,auto,auto" IsVisible="{Binding #FilterExpander.IsExpanded}">
<TextBlock Grid.Column="0" Text="Extension:"/> <TextBlock Grid.Column="0" Text="Extension:"/>
<TextBox Grid.Column="1" Text="{Binding FilterExtension}" KeyUp="FilterChangedAny"/> <TextBox Grid.Column="1" Text="{Binding FilterExtension}" KeyUp="FilterChanged"/>
<TextBlock Grid.Column="2" Text="Name:"/> <TextBlock Grid.Column="2" Text="Name:"/>
<TextBox Grid.Column="3" Text="{Binding FilterPattern}" KeyUp="FilterChangedAny"/> <TextBox Grid.Column="3" Text="{Binding FilterPattern}" KeyUp="FilterChanged"/>
<TextBlock Grid.Column="4" Text="Full Name:"/> <TextBlock Grid.Column="4" Text="Full Name:"/>
<CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" Click="FilterChangedAny"/> <CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" Click="FilterChanged"/>
<TextBlock Grid.Column="6" Text="Regex:"/> <TextBlock Grid.Column="6" Text="Regex:"/>
<CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" Click="FilterChangedAny" Margin="4,4,5,4"/> <CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" Click="FilterChanged" Margin="4,4,5,4"/>
</Grid> </Grid>
</Grid> </Grid>
</Border> </Border>
@ -51,16 +52,16 @@
<!-- Middle Section (Operations, Controls) --> <!-- Middle Section (Operations, Controls) -->
<Grid Grid.Row="2" Grid.Column="1" RowDefinitions="*,auto,auto" Classes="StyleBorders"> <Grid Grid.Row="2" Grid.Column="1" RowDefinitions="*,auto,auto" Classes="StyleBorders">
<!-- Operations ListBox --> <!-- Operations ListBox -->
<ListBox Grid.Row="0"/> <ListBox Grid.Row="0" Items="{Binding Operations}" Name="OperationsListBox" SelectedIndex="{Binding SelectedOperation}"/>
<!-- Operations Controls --> <!-- Operations Controls -->
<Border Grid.Row="1" Classes="ConnectUp"> <Border Grid.Row="1" Classes="ConnectUp">
<Grid ColumnDefinitions="auto,*,auto,auto,auto"> <Grid ColumnDefinitions="auto,*,auto,auto,auto">
<TextBlock Grid.Column="0" Text="New:"/> <TextBlock Grid.Column="0" Text="New:"/>
<ComboBox Grid.Column="1"/> <ComboBox Grid.Column="1" Items="{Binding OperationTypes}" SelectedIndex="{Binding SelectedOperationType}"/>
<Button Grid.Column="2" Content=" + "/> <Button Grid.Column="2" Content=" + " Command="{Binding AddOperation}"/>
<Button Grid.Column="3" Content=" - "/> <Button Grid.Column="3" Content=" - " Command="{Binding RemoveOperation}"/>
<ButtonSpinner Grid.Column="4"/> <ButtonSpinner Grid.Column="4" Spin="MoveOperation"/>
</Grid> </Grid>
</Border> </Border>
@ -75,6 +76,7 @@
</Grid> </Grid>
<Window.Styles> <Window.Styles>
<!-- General Styling-->
<Style Selector="Grid > Expander"> <Style Selector="Grid > Expander">
<Setter Property="Margin" Value="4"/> <Setter Property="Margin" Value="4"/>
</Style> </Style>
@ -120,5 +122,41 @@
<Style Selector="Border.ConnectUp"> <Style Selector="Border.ConnectUp">
<Setter Property="Margin" Value="4,-5,4,4"/> <Setter Property="Margin" Value="4,-5,4,4"/>
</Style> </Style>
<!-- Operation Styles -->
<Style Selector="Expander.OperationExpander">
<Setter Property="Header">
<Template>
<Grid ColumnDefinitions="auto,*,auto">
<CheckBox Grid.Column="0" Margin="0,0,8,0" IsChecked="{Binding IsEnabled}" Command="{Binding $parent[6].DataContext.Preview}"/>
<TextBlock Grid.Column="1" Margin="0,0,8,0" Text="{Binding Name}"/>
<Grid Grid.Column="2" ToolTip.Tip="{Binding Error}" IsVisible="{Binding !!Error.Length}">
<Ellipse Width="18" Height="18" Margin="0" Stroke="DarkRed" StrokeThickness="2"/>
<TextBlock Width="18" Height="18" Margin="0" Foreground="DarkRed" Text="!" FontWeight="Black" TextAlignment="Center"/>
</Grid>
</Grid>
</Template>
</Setter>
</Style>
</Window.Styles> </Window.Styles>
<Window.DataTemplates>
<!-- Operation Type (For the selector) -->
<DataTemplate DataType="{x:Type ops:OperationType}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<!-- Operations -->
<DataTemplate DataType="{x:Type ops:Overwrite}">
<Expander Classes="OperationExpander">
<Grid ColumnDefinitions="auto,*" RowDefinitions="*,*">
<TextBlock Grid.Row="0" Text="Replacement:"/>
<TextBox Grid.Row="0" Text="{Binding Replacement}" KeyUp="PreviewChanged"/>
<TextBlock Grid.Row="1" Text="Full Name:"/>
<CheckBox Grid.Row="1" IsChecked="{Binding FullName}" Click="PreviewChanged"/>
</Grid>
</Expander>
</DataTemplate>
</Window.DataTemplates>
</Window> </Window>

View File

@ -25,8 +25,8 @@ namespace BFR
Filter(); Filter();
} }
public void FilterChangedAny(object sender, KeyEventArgs e) => Filter(); public void FilterChanged(object sender, KeyEventArgs e) => Filter();
public void FilterChangedAny(object sender, RoutedEventArgs e) => Filter(); public void FilterChanged(object sender, RoutedEventArgs e) => Filter();
public void Filter() public void Filter()
{ {
// Filter all files in the directory for those satisfying the given filters // Filter all files in the directory for those satisfying the given filters
@ -37,6 +37,10 @@ namespace BFR
Preview(); Preview();
} }
public void PreviewChanged(object sender, KeyEventArgs e) => Preview(); // TextBox.KeyUp
public void PreviewChanged(object sender, RoutedEventArgs e) => Preview(); // CheckBox.Click
public void PreviewChanged(object sender, SelectionChangedEventArgs e) => Preview(); // ComboBox.SelectionChanged
public void PreviewChanged(object sender, NumericUpDownValueChangedEventArgs e) => Preview(); // NumericUpDown.ValueChanged
public void Preview() public void Preview()
{ {
// Reset all files to how they currently exist // Reset all files to how they currently exist
@ -51,6 +55,32 @@ namespace BFR
Files.ReplaceAll(new List<FileModel>(Files)); Files.ReplaceAll(new List<FileModel>(Files));
} }
public void AddOperation()
{
Operations.Insert(
SelectedOperation >= 0 ? SelectedOperation + 1 : Operations.Count,
OperationTypes[SelectedOperationType].Create());
Preview();
}
public void RemoveOperation()
{
if (SelectedOperation >= 0)
Operations.RemoveAt(SelectedOperation);
else Operations.RemoveAt(0);
Preview();
}
public void MoveOperation(object sender, SpinEventArgs e)
{
if (Operations.Count > 1)
if (e.Direction == SpinDirection.Increase && SelectedOperation > 0)
Operations.Move(SelectedOperation, SelectedOperation - 1);
else if (e.Direction == SpinDirection.Decrease && SelectedOperation < Operations.Count - 1)
Operations.Move(SelectedOperation, SelectedOperation + 1);
Preview();
}
public MainWindow() => InitializeComponent(); public MainWindow() => InitializeComponent();
private void InitializeComponent() private void InitializeComponent()
{ {

View File

@ -16,6 +16,13 @@ namespace BFR
public AvaloniaList<FileModel> AllFiles { get; } = new AvaloniaList<FileModel>(); public AvaloniaList<FileModel> AllFiles { get; } = new AvaloniaList<FileModel>();
public AvaloniaList<FileModel> Files { get; } = new AvaloniaList<FileModel>(); public AvaloniaList<FileModel> Files { get; } = new AvaloniaList<FileModel>();
public AvaloniaList<Operation> Operations { get; } = new AvaloniaList<Operation>(); public AvaloniaList<Operation> Operations { get; } = new AvaloniaList<Operation>();
public int SelectedOperation { get; set; }
public int SelectedOperationType { get; set; } = 0;
public OperationType[] OperationTypes { get; } = new[]
{
OperationType.Make<Overwrite>()
};
// Filters // Filters
public string FilterExtension { get; set; } = ""; public string FilterExtension { get; set; } = "";

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Collections.Generic;
using Avalonia; using Avalonia;
using BFR.DataModels; using BFR.DataModels;
@ -24,8 +25,9 @@ namespace BFR.Operations
var backup = files.Select(file => file.Path).ToList(); var backup = files.Select(file => file.Path).ToList();
try try
{ {
ApplyToInternal(files); // Try to apply operation if(IsEnabled)
Error = ""; // If successul, remove any previous error ApplyToInternal(files); // Try to apply operation
Error = ""; // If successul, remove any previous error
} }
catch (OperationException e) { Error = e.Message; } // If expected, show user a concise and descriptive message catch (OperationException e) { Error = e.Message; } // If expected, show user a concise and descriptive message
catch (Exception e) { Error = $"Unexpected {e}"; } // If not, hint with the exception thrown that this is unexpected behaviour catch (Exception e) { Error = $"Unexpected {e}"; } // If not, hint with the exception thrown that this is unexpected behaviour