Added Replace-Operation, structuring and reworked event bindings
- Added Replace-Operation + UI - Added OperationMode to make it easier to give operations different modes - Replaced all specific-control-event-handlers with one general PropertyChanged-event-handler for each preview and filter - TODO: Add Remove-Operation as a subclass of Replace
This commit is contained in:
parent
2aa1fa6529
commit
c519147302
|
@ -6,6 +6,7 @@
|
|||
mc:Ignorable="d" MinWidth="720" MinHeight="480"
|
||||
x:Class="BFR.MainWindow"
|
||||
Title="BFR">
|
||||
|
||||
<Grid RowDefinitions="auto,auto,*" ColumnDefinitions="*,*,*" Classes="StyleBorders">
|
||||
<!-- Directory Selection + Filters -->
|
||||
<Border Grid.Row="0" Grid.ColumnSpan="3">
|
||||
|
@ -17,13 +18,13 @@
|
|||
<!-- Filters -->
|
||||
<Grid Grid.Row="1" Grid.ColumnSpan="3" ColumnDefinitions="auto,*,auto,*,auto,auto,auto,auto" IsVisible="{Binding #FilterExpander.IsExpanded}">
|
||||
<TextBlock Grid.Column="0" Text="Extension:"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding FilterExtension}" KeyUp="FilterChanged"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding FilterExtension}" PropertyChanged="FilterChanged"/>
|
||||
<TextBlock Grid.Column="2" Text="Name:"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding FilterPattern}" KeyUp="FilterChanged"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding FilterPattern}" PropertyChanged="FilterChanged"/>
|
||||
<TextBlock Grid.Column="4" Text="Full Name:"/>
|
||||
<CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" Click="FilterChanged"/>
|
||||
<CheckBox Grid.Column="5" IsChecked="{Binding FilterFullName}" PropertyChanged="FilterChanged"/>
|
||||
<TextBlock Grid.Column="6" Text="Regex:"/>
|
||||
<CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" Click="FilterChanged" Margin="4,4,5,4"/>
|
||||
<CheckBox Grid.Column="7" IsChecked="{Binding FilterRegex}" PropertyChanged="FilterChanged" Margin="4,4,5,4"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
@ -99,6 +100,10 @@
|
|||
<Setter Property="Margin" Value="4"/>
|
||||
<Setter Property="Grid.Column" Value="1"/>
|
||||
</Style>
|
||||
<Style Selector="Grid > NumericUpDown">
|
||||
<Setter Property="Margin" Value="4"/>
|
||||
<Setter Property="Grid.Column" Value="1"/>
|
||||
</Style>
|
||||
<Style Selector="Grid > CheckBox">
|
||||
<Setter Property="Margin" Value="4"/>
|
||||
<Setter Property="Grid.Column" Value="1"/>
|
||||
|
@ -151,12 +156,45 @@
|
|||
<Expander Classes="OperationExpander">
|
||||
<Grid ColumnDefinitions="auto,*" RowDefinitions="*,*">
|
||||
<TextBlock Grid.Row="0" Text="Replacement:"/>
|
||||
<TextBox Grid.Row="0" Text="{Binding Replacement}" KeyUp="PreviewChanged"/>
|
||||
<TextBox Grid.Row="0" Text="{Binding Replacement}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="1" Text="Full Name:"/>
|
||||
<CheckBox Grid.Row="1" IsChecked="{Binding FullName}" Click="PreviewChanged"/>
|
||||
<CheckBox Grid.Row="1" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type ops:Replace}">
|
||||
<Expander Classes="OperationExpander">
|
||||
<Grid ColumnDefinitions="auto,*" RowDefinitions="auto,auto,auto,auto,auto,auto,auto,auto,auto,auto,auto">
|
||||
<TextBlock Grid.Row="0" Text="Mode:"/>
|
||||
<ComboBox Grid.Row="0" Items="{Binding Modes}" SelectedItem="{Binding Mode}" PropertyChanged="PreviewChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Grid.Row="1" Text="Pattern:" IsVisible="{Binding Mode.IsPatternMode}"/>
|
||||
<TextBox Grid.Row="1" Text="{Binding Pattern}" IsVisible="{Binding Mode.IsPatternMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="2" Text="Characters:" IsVisible="{Binding Mode.IsCharactersMode}"/>
|
||||
<TextBox Grid.Row="2" Text="{Binding Characters}" IsVisible="{Binding Mode.IsCharactersMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="3" Text="From N:" IsVisible="{Binding Mode.IsFromNToNMode}"/>
|
||||
<NumericUpDown Grid.Row="3" Value="{Binding FromN}" IsVisible="{Binding Mode.IsFromNToNMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="4" Text="To N:" IsVisible="{Binding Mode.IsFromNToNMode}"/>
|
||||
<NumericUpDown Grid.Row="4" Value="{Binding ToN}" IsVisible="{Binding Mode.IsFromNToNMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="5" Text="First N:" IsVisible="{Binding Mode.IsFirstNMode}"/>
|
||||
<NumericUpDown Grid.Row="5" Value="{Binding FirstN}" IsVisible="{Binding Mode.IsFirstNMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="6" Text="Last N:" IsVisible="{Binding Mode.IsLastNMode}"/>
|
||||
<NumericUpDown Grid.Row="6" Value="{Binding LastN}" IsVisible="{Binding Mode.IsLastNMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="7" Text="Replacement:"/>
|
||||
<TextBox Grid.Row="7" Text="{Binding Replacement}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="8" Text="Regex:" IsVisible="{Binding Mode.IsPatternMode}"/>
|
||||
<CheckBox Grid.Row="8" IsChecked="{Binding UseRegex}" IsVisible="{Binding Mode.IsPatternMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="9" Text="Replace Regex:" IsVisible="{Binding Mode.IsPatternMode}"/>
|
||||
<CheckBox Grid.Row="9" IsChecked="{Binding UseRegexReplace}" IsVisible="{Binding Mode.IsPatternMode}" PropertyChanged="PreviewChanged"/>
|
||||
<TextBlock Grid.Row="10" Text="Full Name:"/>
|
||||
<CheckBox Grid.Row="10" IsChecked="{Binding FullName}" PropertyChanged="PreviewChanged"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
</Window.DataTemplates>
|
||||
|
||||
</Window>
|
||||
|
|
|
@ -5,10 +5,9 @@ using System.Threading.Tasks;
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Avalonia.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
using BFR.Helpers;
|
||||
using BFR.DataModels;
|
||||
|
@ -25,22 +24,18 @@ namespace BFR
|
|||
Filter();
|
||||
}
|
||||
|
||||
public void FilterChanged(object sender, KeyEventArgs e) => Filter();
|
||||
public void FilterChanged(object sender, RoutedEventArgs e) => Filter();
|
||||
public void FilterChanged(object sender, AvaloniaPropertyChangedEventArgs e) => Filter(); // Bind to PropertyChanged
|
||||
public void Filter()
|
||||
{
|
||||
// Filter all files in the directory for those satisfying the given filters
|
||||
Files.ReplaceAll(AllFiles.Where(x =>
|
||||
(FilterExtension == "" || x.Extension == FilterExtension)
|
||||
(FilterExtension == "" || x.OldExtension == FilterExtension)
|
||||
&& (FilterFullName ? x.OldFullName : x.OldName).RegexContains(FilterRegex ? FilterPattern : Regex.Escape(FilterPattern))));
|
||||
|
||||
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 PreviewChanged(object sender, AvaloniaPropertyChangedEventArgs e) => Preview(); // Bind to PropertyChanged
|
||||
public void Preview()
|
||||
{
|
||||
// Reset all files to how they currently exist
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using Avalonia;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
|
||||
using BFR.DataModels;
|
||||
using BFR.Operations;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BFR
|
||||
{
|
||||
|
@ -22,7 +23,8 @@ namespace BFR
|
|||
public int SelectedOperationType { get; set; } = 0;
|
||||
public OperationType[] OperationTypes { get; } = new[]
|
||||
{
|
||||
OperationType.Make<Overwrite>()
|
||||
OperationType.Make<Overwrite>(),
|
||||
OperationType.Make<Replace>()
|
||||
};
|
||||
|
||||
public readonly AvaloniaProperty<bool> isCommitButtonEnabled =
|
||||
|
|
11
BFR/Operations/OperationMode.cs
Normal file
11
BFR/Operations/OperationMode.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace BFR.Operations
|
||||
{
|
||||
public class OperationMode
|
||||
{
|
||||
public int Index { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public OperationMode(int index, string name) =>
|
||||
(Index, Name) = (index, name);
|
||||
}
|
||||
}
|
85
BFR/Operations/Replace.cs
Normal file
85
BFR/Operations/Replace.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Avalonia;
|
||||
|
||||
using BFR.Helpers;
|
||||
using BFR.DataModels;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BFR.Operations
|
||||
{
|
||||
public class Replace : Operation
|
||||
{
|
||||
private static readonly ReplaceMode DefaultMode = new ReplaceMode(0, "Pattern");
|
||||
|
||||
public override string Name => "Replace";
|
||||
public override string Description => "Replaces the selected part of the file name.";
|
||||
|
||||
public AvaloniaProperty<ReplaceMode> modeProperty =
|
||||
AvaloniaProperty.Register<MainWindow, ReplaceMode>(nameof(Mode), defaultValue: DefaultMode);
|
||||
public ReplaceMode Mode { get => GetValue(modeProperty); set => SetValue(modeProperty, value); }
|
||||
public ReplaceMode[] Modes { get; } = new ReplaceMode[]
|
||||
{
|
||||
DefaultMode,
|
||||
new ReplaceMode(1, "Characters"),
|
||||
new ReplaceMode(2, "FromNToN"),
|
||||
new ReplaceMode(3, "FirstN"),
|
||||
new ReplaceMode(4, "LastN"),
|
||||
};
|
||||
|
||||
public string Replacement { get; set; } = "";
|
||||
public bool FullName { get; set; } = false;
|
||||
public string Pattern { get; set; } = "";
|
||||
public bool UseRegex { get; set; } = false;
|
||||
public bool UseRegexReplace { get; set; } = false;
|
||||
public string Characters { get; set; } = "";
|
||||
public int FirstN { get; set; } = 0;
|
||||
public int LastN { get; set; } = 0;
|
||||
public int FromN { get; set; } = 0;
|
||||
public int ToN { get; set; } = 0;
|
||||
|
||||
protected override void ApplyToInternal(IList<FileModel> files)
|
||||
{
|
||||
// Fail conditions: Various out-of-bounds
|
||||
var shortestLength = files.Min(x => FullName ? x.FullName.Length : x.Name.Length);
|
||||
if (FirstN > shortestLength) throw new OperationException($"First N can't be greater than the shortest file name length ({shortestLength}).");
|
||||
if (LastN > shortestLength) throw new OperationException($"Last N can't be greater than the shortest file name length ({shortestLength}).");
|
||||
if (FromN > shortestLength) throw new OperationException($"From N can't be greater than the shortest file name length ({shortestLength}).");
|
||||
if (ToN > shortestLength) throw new OperationException($"To N can't be greater than the shortest file name length ({shortestLength}).");
|
||||
if (FromN > ToN) throw new OperationException("From N can't be greater than To N.");
|
||||
|
||||
// Regex Failure
|
||||
if(Mode.IsPatternMode && UseRegex)
|
||||
try { "".Replace(Pattern, Replacement, true, false); }
|
||||
catch(Exception) { throw new OperationException("Invalid Regex Pattern."); }
|
||||
|
||||
// Apply operation
|
||||
foreach(var file in files)
|
||||
{
|
||||
var newName = FullName ? file.FullName : file.Name;
|
||||
|
||||
newName = Mode.Index switch
|
||||
{
|
||||
0 => newName.Replace(Pattern, Replacement, UseRegex, UseRegexReplace),
|
||||
1 => Characters.Length > 0 ? Regex.Replace(newName, $"[{Characters}]", Replacement.Replace("$", "$$")) : newName,
|
||||
2 => Regex.Replace(newName, $"^(.{{{FromN}}}).+(.{{{newName.Length - ToN - 1}}})$", $"$1{Replacement.Replace("$", "$$")}$2"),
|
||||
3 => Regex.Replace(newName, $"^.{{{FirstN}}}", Replacement.Replace("$", "$$")),
|
||||
4 => Regex.Replace(newName, $".{{{LastN}}}$", Replacement.Replace("$", "$$")),
|
||||
_ => newName
|
||||
};
|
||||
|
||||
if (FullName) file.FullName = newName;
|
||||
else file.Name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
private string ReplaceAllCharacters(string input, string characters, string replacement)
|
||||
{
|
||||
foreach (var character in characters)
|
||||
input = input.Replace(character.ToString(), replacement);
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
14
BFR/Operations/ReplaceMode.cs
Normal file
14
BFR/Operations/ReplaceMode.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace BFR.Operations
|
||||
{
|
||||
public class ReplaceMode : OperationMode
|
||||
{
|
||||
public bool IsPatternMode => Index == 0;
|
||||
public bool IsCharactersMode => Index == 1;
|
||||
public bool IsFromNToNMode => Index == 2;
|
||||
public bool IsFirstNMode => Index == 3;
|
||||
public bool IsLastNMode => Index == 4;
|
||||
|
||||
public ReplaceMode(int index, string name) :
|
||||
base(index, name) { }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user