mirror of
https://github.com/rmcrackan/Libation.git
synced 2025-12-23 22:17:52 -05:00
Improve EditReplacementChars dialog usability
This commit is contained in:
25
Source/LibationAvalonia/Controls/DataGridTextColumnExt.cs
Normal file
25
Source/LibationAvalonia/Controls/DataGridTextColumnExt.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace LibationAvalonia.Controls;
|
||||
internal class DataGridTextColumnExt : DataGridTextColumn
|
||||
{
|
||||
public static readonly StyledProperty<int> MaxLengthProperty =
|
||||
AvaloniaProperty.Register<DataGridTextColumnExt, int>(nameof(MaxLength));
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get => GetValue(MaxLengthProperty);
|
||||
set => SetValue(MaxLengthProperty, value);
|
||||
}
|
||||
|
||||
protected override object PrepareCellForEdit(Control editingElement, RoutedEventArgs editingEventArgs)
|
||||
{
|
||||
if (editingElement is TextBox textBox)
|
||||
{
|
||||
textBox.MaxLength = MaxLength;
|
||||
}
|
||||
return base.PrepareCellForEdit(editingElement, editingEventArgs);
|
||||
}
|
||||
}
|
||||
@@ -2,92 +2,80 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
MinWidth="500" MinHeight="450"
|
||||
Width="500" Height="450"
|
||||
mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="450"
|
||||
MinWidth="450" MinHeight="450"
|
||||
Width="450" Height="450"
|
||||
x:Class="LibationAvalonia.Dialogs.EditReplacementChars"
|
||||
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
|
||||
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||
x:DataType="dialogs:EditReplacementChars"
|
||||
Title="Illegal Character Replacement">
|
||||
|
||||
<Grid
|
||||
RowDefinitions="*,Auto"
|
||||
ColumnDefinitions="*,Auto">
|
||||
x:CompileBindings="True"
|
||||
Title="File Path Character Replacement">
|
||||
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<DataGrid
|
||||
Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
GridLinesVisibility="All"
|
||||
Margin="5"
|
||||
Name="replacementGrid"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="False"
|
||||
BeginningEdit="ReplacementGrid_BeginningEdit"
|
||||
CellEditEnding="ReplacementGrid_CellEditEnding"
|
||||
KeyDown="ReplacementGrid_KeyDown"
|
||||
ItemsSource="{CompiledBinding replacements}">
|
||||
|
||||
GridLinesVisibility="All"
|
||||
CanUserSortColumns="False"
|
||||
AutoGenerateColumns="False"
|
||||
ItemsSource="{Binding Replacements}"
|
||||
KeyDown="replacementGrid_KeyDown"
|
||||
BeginningEdit="replacementGrid_BeginningEdit"
|
||||
CellEditEnded="replacementGrid_CellEditEnded"
|
||||
CellEditEnding="replacementGrid_CellEditEnding">
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTemplateColumn Header="Char to
Replace">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="dialogs:EditReplacementChars+ReplacementsExt">
|
||||
<TextBox IsReadOnly="{CompiledBinding Mandatory}" Text="{CompiledBinding CharacterToReplace, Mode=TwoWay}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTemplateColumn Header="Replacement
Text">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="dialogs:EditReplacementChars+ReplacementsExt">
|
||||
<TextBox Text="{CompiledBinding ReplacementText, Mode=TwoWay}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<controls:DataGridTextColumnExt
|
||||
x:DataType="dialogs:EditReplacementChars+ReplacementsExt"
|
||||
MaxLength="1"
|
||||
Header="Char to
Replace"
|
||||
Binding="{Binding CharacterToReplace, Mode=TwoWay}"/>
|
||||
|
||||
<DataGridTemplateColumn Width="*" Header="Description">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="dialogs:EditReplacementChars+ReplacementsExt">
|
||||
<TextBox IsReadOnly="{CompiledBinding Mandatory}" Text="{CompiledBinding Description, Mode=TwoWay}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn
|
||||
x:DataType="dialogs:EditReplacementChars+ReplacementsExt"
|
||||
Header="Replacement
Text"
|
||||
Binding="{Binding ReplacementText, Mode=TwoWay}"/>
|
||||
|
||||
<DataGridTextColumn
|
||||
x:DataType="dialogs:EditReplacementChars+ReplacementsExt"
|
||||
Header="Description"
|
||||
Binding="{Binding Description, Mode=TwoWay}"/>
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
RowDefinitions="Auto,Auto"
|
||||
Margin="5"
|
||||
ColumnDefinitions="Auto,Auto,Auto,Auto">
|
||||
ColumnDefinitions="Auto,Auto,Auto,*,Auto,Auto"
|
||||
Margin="5">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Padding" Value="6"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
</Style>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
|
||||
<TextBlock IsVisible="{CompiledBinding !EnvironmentIsWindows}" Text="This System:" Margin="0,0,10,0" VerticalAlignment="Center" />
|
||||
<TextBlock IsVisible="{CompiledBinding !EnvironmentIsWindows}" Grid.Row="1" Text="NTFS:" Margin="0,0,10,0" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="0" Text="This
System:" IsVisible="{Binding !EnvironmentIsWindows}" />
|
||||
<TextBlock Grid.Row="1" Text="NTFS:" IsVisible="{Binding !EnvironmentIsWindows}" />
|
||||
|
||||
<Button Grid.Column="1" Margin="0,0,10,0" Command="{CompiledBinding Defaults}" CommandParameter="{CompiledBinding EnvironmentIsWindows}" Content="Defaults" />
|
||||
<Button Grid.Column="2" Margin="0,0,10,0" Command="{CompiledBinding LoFiDefaults}" CommandParameter="{CompiledBinding EnvironmentIsWindows}" Content="LoFi Defaults" />
|
||||
<Button Grid.Column="3" Command="{CompiledBinding Barebones}" CommandParameter="{CompiledBinding EnvironmentIsWindows}" Content="Barebones" />
|
||||
<Button Grid.Column="1" Command="{Binding Defaults}" CommandParameter="{Binding EnvironmentIsWindows}" Content="Defaults" />
|
||||
<Button Grid.Column="2" Command="{Binding LoFiDefaults}" CommandParameter="{Binding EnvironmentIsWindows}" Content="LoFi Defaults" />
|
||||
<Button Grid.Column="3" Command="{Binding Barebones}" CommandParameter="{Binding EnvironmentIsWindows}" Content="Barebones" />
|
||||
|
||||
<Button IsVisible="{CompiledBinding !EnvironmentIsWindows}" Grid.Row="1" Grid.Column="1" Margin="0,10,10,0" Command="{CompiledBinding Defaults}" CommandParameter="True" Content="Defaults" />
|
||||
<Button IsVisible="{CompiledBinding !EnvironmentIsWindows}" Grid.Row="1" Grid.Column="2" Margin="0,10,10,0" Command="{CompiledBinding LoFiDefaults}" CommandParameter="True" Content="LoFi Defaults" />
|
||||
<Button IsVisible="{CompiledBinding !EnvironmentIsWindows}" Grid.Row="1" Grid.Column="3" Margin="0,10,0,0" Command="{CompiledBinding Barebones}" CommandParameter="True" Content="Barebones" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="5"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<Button Margin="0,0,10,0" Command="{Binding Close}" Content="Cancel" />
|
||||
<Button Padding="20,5,20,6" Command="{Binding SaveAndClose}" Content="Save" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
<Button Grid.Row="1" Grid.Column="1" IsVisible="{Binding !EnvironmentIsWindows}" Command="{Binding Defaults}" CommandParameter="True" Content="Defaults" />
|
||||
<Button Grid.Row="1" Grid.Column="2" IsVisible="{Binding !EnvironmentIsWindows}" Command="{Binding LoFiDefaults}" CommandParameter="True" Content="LoFi Defaults" />
|
||||
<Button Grid.Row="1" Grid.Column="3" IsVisible="{Binding !EnvironmentIsWindows}" Command="{Binding Barebones}" CommandParameter="True" Content="Barebones" />
|
||||
|
||||
<Button Grid.RowSpan="2" Grid.Column="4" Command="{Binding Close}" Content="Cancel" />
|
||||
<Button Grid.RowSpan="2" Grid.Column="5" Padding="20,6" Command="{Binding SaveAndClose}" Content="Save" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using FileManager;
|
||||
using LibationFileManager;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
#nullable enable
|
||||
namespace LibationAvalonia.Dialogs
|
||||
{
|
||||
public partial class EditReplacementChars : DialogWindow
|
||||
{
|
||||
Configuration config;
|
||||
private Configuration? Config { get; }
|
||||
|
||||
public bool EnvironmentIsWindows => Configuration.IsWindows;
|
||||
|
||||
private readonly List<ReplacementsExt> SOURCE = new();
|
||||
public DataGridCollectionView replacements { get; }
|
||||
private readonly AvaloniaList<ReplacementsExt> SOURCE = new();
|
||||
public DataGridCollectionView Replacements { get; }
|
||||
public EditReplacementChars()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
replacements = new(SOURCE);
|
||||
Replacements = new(SOURCE);
|
||||
|
||||
if (Design.IsDesignMode)
|
||||
{
|
||||
@@ -33,7 +33,7 @@ namespace LibationAvalonia.Dialogs
|
||||
|
||||
public EditReplacementChars(Configuration config) : this()
|
||||
{
|
||||
this.config = config;
|
||||
Config = config;
|
||||
LoadTable(config.ReplacementCharacters.Replacements);
|
||||
}
|
||||
|
||||
@@ -44,15 +44,14 @@ namespace LibationAvalonia.Dialogs
|
||||
public void Barebones(bool isNtfs)
|
||||
=> LoadTable(ReplacementCharacters.Barebones(isNtfs).Replacements);
|
||||
|
||||
protected override void SaveAndClose()
|
||||
public new void Close() => base.Close();
|
||||
public new void SaveAndClose()
|
||||
{
|
||||
var replacements = SOURCE
|
||||
.Where(r => !r.IsDefault)
|
||||
.Select(r => new Replacement(r.Character, r.ReplacementText, r.Description) { Mandatory = r.Mandatory })
|
||||
.ToList();
|
||||
|
||||
if (config is not null)
|
||||
config.ReplacementCharacters = new ReplacementCharacters { Replacements = replacements };
|
||||
if (Config is not null)
|
||||
{
|
||||
var replacements = SOURCE.Where(r => !r.IsDefault).Select(r => r.ToReplacement()).ToArray();
|
||||
Config.ReplacementCharacters = new ReplacementCharacters { Replacements = replacements };
|
||||
}
|
||||
base.SaveAndClose();
|
||||
}
|
||||
|
||||
@@ -61,59 +60,64 @@ namespace LibationAvalonia.Dialogs
|
||||
SOURCE.Clear();
|
||||
SOURCE.AddRange(replacements.Select(r => new ReplacementsExt(r)));
|
||||
SOURCE.Add(new ReplacementsExt());
|
||||
this.replacements.Refresh();
|
||||
}
|
||||
|
||||
public void ReplacementGrid_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
|
||||
private bool ColumnIsCharacter(DataGridColumn column)
|
||||
=> column.DisplayIndex is 0;
|
||||
|
||||
private bool ColumnIsReplacement(DataGridColumn column)
|
||||
=> column.DisplayIndex is 1;
|
||||
|
||||
private bool RowIsReadOnly(DataGridRow row)
|
||||
=> row.DataContext is ReplacementsExt rep && rep.Mandatory;
|
||||
|
||||
private bool CanDeleteSelectedItem(ReplacementsExt selectedItem)
|
||||
=> !selectedItem.Mandatory && (!selectedItem.IsDefault || SOURCE[^1] != selectedItem);
|
||||
|
||||
private void replacementGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
|
||||
{
|
||||
if (e.Key == Avalonia.Input.Key.Delete
|
||||
&& ((DataGrid)sender).SelectedItem is ReplacementsExt repl
|
||||
&& !repl.Mandatory
|
||||
&& !repl.IsDefault)
|
||||
{
|
||||
replacements.Remove(repl);
|
||||
}
|
||||
e.Cancel = RowIsReadOnly(e.Row) && !ColumnIsReplacement(e.Column);
|
||||
}
|
||||
|
||||
public void ReplacementGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
|
||||
private void replacementGrid_CellEditEnding(object? sender, DataGridCellEditEndingEventArgs e)
|
||||
{
|
||||
var replacement = e.Row.DataContext as ReplacementsExt;
|
||||
var colBinding = columnBindingPath(e.Column);
|
||||
|
||||
//Prevent duplicate CharacterToReplace
|
||||
if (e.EditingElement is TextBox tbox
|
||||
&& colBinding == nameof(replacement.CharacterToReplace)
|
||||
&& SOURCE.Any(r => r != replacement && r.CharacterToReplace == tbox.Text))
|
||||
//Disallow duplicates of CharacterToReplace
|
||||
if (ColumnIsCharacter(e.Column) && e.Row.DataContext is ReplacementsExt r && r.CharacterToReplace.Length > 0 && SOURCE.Count(rep => rep.CharacterToReplace == r.CharacterToReplace) > 1)
|
||||
{
|
||||
tbox.Text = replacement.CharacterToReplace;
|
||||
}
|
||||
|
||||
//Add new blank row
|
||||
void Replacement_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!SOURCE.Any(r => r.IsDefault))
|
||||
{
|
||||
var rewRepl = new ReplacementsExt();
|
||||
SOURCE.Add(rewRepl);
|
||||
}
|
||||
replacement.PropertyChanged -= Replacement_PropertyChanged;
|
||||
}
|
||||
|
||||
replacement.PropertyChanged += Replacement_PropertyChanged;
|
||||
}
|
||||
|
||||
public void ReplacementGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
|
||||
{
|
||||
var replacement = e.Row.DataContext as ReplacementsExt;
|
||||
|
||||
//Disallow editing of Mandatory CharacterToReplace and Descriptions
|
||||
if (replacement.Mandatory
|
||||
&& columnBindingPath(e.Column) != nameof(replacement.ReplacementText))
|
||||
r.CharacterToReplace = "";
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static string columnBindingPath(DataGridColumn column)
|
||||
=> ((Binding)((DataGridBoundColumn)column).Binding).Path;
|
||||
private void replacementGrid_CellEditEnded(object? sender, DataGridCellEditEndedEventArgs e)
|
||||
{
|
||||
if (ColumnIsCharacter(e.Column) && e.Row.DataContext is ReplacementsExt r && r.CharacterToReplace.Length > 0 && !SOURCE[^1].IsDefault)
|
||||
{
|
||||
Replacements.AddNew();
|
||||
}
|
||||
}
|
||||
|
||||
private void replacementGrid_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Avalonia.Input.Key.Delete && (sender as DataGrid)?.SelectedItem is ReplacementsExt r && CanDeleteSelectedItem(r))
|
||||
{
|
||||
if (Replacements.IsEditingItem)
|
||||
{
|
||||
if (Replacements.CanCancelEdit)
|
||||
Replacements.CancelEdit();
|
||||
else
|
||||
Replacements.CommitEdit();
|
||||
}
|
||||
if (Replacements.IsAddingNew)
|
||||
{
|
||||
Replacements.CancelNew();
|
||||
}
|
||||
if (Replacements.CanRemove)
|
||||
{
|
||||
Replacements.Remove(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ReplacementsExt : ViewModels.ViewModelBase
|
||||
{
|
||||
@@ -122,7 +126,6 @@ namespace LibationAvalonia.Dialogs
|
||||
_replacementText = string.Empty;
|
||||
_description = string.Empty;
|
||||
_characterToReplace = string.Empty;
|
||||
IsDefault = true;
|
||||
}
|
||||
public ReplacementsExt(Replacement replacement)
|
||||
{
|
||||
@@ -131,41 +134,19 @@ namespace LibationAvalonia.Dialogs
|
||||
_description = replacement.Description;
|
||||
Mandatory = replacement.Mandatory;
|
||||
}
|
||||
|
||||
private string _replacementText;
|
||||
private string _description;
|
||||
private string _characterToReplace;
|
||||
public bool Mandatory { get; }
|
||||
public string ReplacementText
|
||||
{
|
||||
get => _replacementText;
|
||||
set
|
||||
{
|
||||
if (ReplacementCharacters.ContainsInvalidFilenameChar(value))
|
||||
this.RaisePropertyChanged(nameof(ReplacementText));
|
||||
else
|
||||
this.RaiseAndSetIfChanged(ref _replacementText, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string ReplacementText { get => _replacementText; set => this.RaiseAndSetIfChanged(ref _replacementText, value); }
|
||||
public string Description { get => _description; set => this.RaiseAndSetIfChanged(ref _description, value); }
|
||||
|
||||
public string CharacterToReplace
|
||||
{
|
||||
get => _characterToReplace;
|
||||
|
||||
set
|
||||
{
|
||||
if (value?.Length != 1)
|
||||
this.RaisePropertyChanged(nameof(CharacterToReplace));
|
||||
else
|
||||
{
|
||||
IsDefault = false;
|
||||
this.RaiseAndSetIfChanged(ref _characterToReplace, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public string CharacterToReplace { get => _characterToReplace; set => this.RaiseAndSetIfChanged(ref _characterToReplace, value); }
|
||||
public char Character => string.IsNullOrEmpty(_characterToReplace) ? default : _characterToReplace[0];
|
||||
public bool IsDefault { get; private set; }
|
||||
public bool IsDefault => !Mandatory && string.IsNullOrEmpty(CharacterToReplace);
|
||||
public bool Mandatory { get; }
|
||||
|
||||
public Replacement ToReplacement()
|
||||
=> new(Character, ReplacementText, Description) { Mandatory = Mandatory };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user