Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 45 additions & 33 deletions src/ui/Features/Tools/ChangeCasing/FixNamesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Nikse.SubtitleEdit.Features.Tools.ChangeCasing;

Expand All @@ -37,56 +38,27 @@ public partial class FixNamesViewModel : ObservableObject, IClosingCleanup
private const string SuffixChars = " ,.!?:;…')]<-\"\r\n";
private static readonly string[] CommonWords = ["US", "Lane", "Bill", "Rose"];
private readonly HashSet<string> _usedNames;
private string _oldNames;
private readonly System.Timers.Timer _previewTimer;
private bool _loading;
private readonly Lock _lock = new();

public FixNamesViewModel()
{
Names = new ObservableCollection<FixNameItem>();
Hits = new ObservableCollection<FixNameHitItem>();

_loading = true;
_nameListInclMulti = new List<string>();
_language = "en_US";
_subtitleBefore = new Subtitle();
_subtitle = new Subtitle();
_usedNames = new HashSet<string>();
ExtraNames = string.Empty;
_oldNames = string.Empty;
Info = string.Empty;
Subtitle = new Subtitle();

_previewTimer = new System.Timers.Timer(500);
_previewTimer.Elapsed += PreviewTimerElapsed;
}

private void PreviewTimerElapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
var namesString = string.Join(' ', Names.Where(p => p.IsChecked).Select(p => p.Name));
if (namesString != _oldNames && !_loading)
{
lock (_lock)
{
GeneratePreview();
_oldNames = namesString;
}
}
}

public void OnClosingCleanup()
{
_previewTimer.StopAndDispose(PreviewTimerElapsed);
}

internal void Initialize(Subtitle subtitle)
{
subtitle.Renumber();
_subtitle = new Subtitle(subtitle);
_subtitleBefore = subtitle;
_oldNames = string.Empty;

_language = LanguageAutoDetect.AutoDetectGoogleLanguage(_subtitle);
if (string.IsNullOrEmpty(_language))
{
Expand Down Expand Up @@ -161,6 +133,44 @@ private static bool IsWordBoundary(string text, int startIndex, string name)
&& (afterNameIndex == text.Length || SuffixChars.Contains(text[afterNameIndex]));
}

private CancellationTokenSource? _cancellationTokenSource;

[RelayCommand]
private void FixNameItemChanged(FixNameItem item)
{
RequestPreview();
}

internal void RequestPreview()
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = new CancellationTokenSource();
_ = DebouncedPreviewAsync(_cancellationTokenSource.Token);
}

private async Task DebouncedPreviewAsync(CancellationToken token)
{
try
{
await Task.Delay(500, token).ConfigureAwait(false);
GeneratePreview();
}
catch (OperationCanceledException)
{
// Superseded by a newer request, or the window closed.
}
}

public void OnClosingCleanup()
{
// Null out so a repeated Closed callback (or a late RequestPreview) never
// touches the disposed source.
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}

private void GeneratePreview()
{
var hits = new List<FixNameHitItem>();
Expand Down Expand Up @@ -214,6 +224,8 @@ public void NamesSelectAll()
{
name.IsChecked = true;
}

GeneratePreview();
}

[RelayCommand]
Expand All @@ -223,6 +235,8 @@ public void NamesInvertSelection()
{
name.IsChecked = !name.IsChecked;
}

GeneratePreview();
}

[RelayCommand]
Expand Down Expand Up @@ -266,6 +280,7 @@ private void Ok()
noOfLinesChanged++;
}
}

Info = $"Change casing - lines changed: {noOfLinesChanged}";

OkPressed = true;
Expand All @@ -281,9 +296,8 @@ public void Cancel()
[RelayCommand]
public void AddExtraName()
{
_loading = true;
FindAllNames();
_loading = false;
GeneratePreview();
}

internal void OnKeyDown(KeyEventArgs e)
Expand Down Expand Up @@ -313,7 +327,5 @@ internal async void OnLoaded(RoutedEventArgs e)
ExtraNames = Se.Settings.Tools.ChangeCasing.ExtraNames;
FindAllNames();
GeneratePreview();
_previewTimer.Start();
_loading = false;
}
}
22 changes: 13 additions & 9 deletions src/ui/Features/Tools/ChangeCasing/FixNamesWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using Nikse.SubtitleEdit.Logic;
using Nikse.SubtitleEdit.Logic.Config;
using System;
using System.Linq;

namespace Nikse.SubtitleEdit.Features.Tools.ChangeCasing;

Expand Down Expand Up @@ -132,15 +128,20 @@ private static Border MakeNamesView(FixNamesViewModel vm)
Header = Se.Language.General.Enabled,
CellTheme = UiUtil.TableViewNoPaddingCellTheme,
HeaderTheme = UiUtil.TableViewColumnHeaderTheme,
CellTemplate = new FuncDataTemplate<FixNameItem>(static (item, _) =>
new Border
CellTemplate = new FuncDataTemplate<FixNameItem>((item, _) => new Border
{
Background = Brushes.Transparent, // Prevents highlighting
Padding = new Thickness(4),
Child = new CheckBox
{
Focusable = false,
[!ToggleButton.IsCheckedProperty] = new Binding(nameof(FixNameItem.IsChecked)),
[!ToggleButton.IsCheckedProperty] = new Binding(nameof(FixNameItem.IsChecked))
{
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
},
Command = vm.FixNameItemChangedCommand,
CommandParameter = item,
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
}
}),
Expand All @@ -157,8 +158,11 @@ private static Border MakeNamesView(FixNamesViewModel vm)
HeaderTheme = UiUtil.TableViewColumnHeaderTheme,
});

TableViewExtras.AddSpaceToggle<FixNameItem>(dataGrid,
item => item.IsChecked, (item, v) => item.IsChecked = v);
TableViewExtras.AddSpaceToggle<FixNameItem>(dataGrid, item => item.IsChecked, (item, v) =>
{
item.IsChecked = v;
vm.RequestPreview();
});

var flyout = new MenuFlyout();
flyout.Items.Add(new MenuItem { Header = Se.Language.General.SelectAll, Command = vm.NamesSelectAllCommand });
Expand Down
6 changes: 3 additions & 3 deletions src/ui/Logic/TableViewExtras.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,10 @@ e.KeyModifiers is not (KeyModifiers.None or KeyModifiers.Control) ||
/// CheckboxMultiSelect helper that TableView does not provide natively (extended
/// selection itself is native ListBox behavior).
/// </summary>
public static void AddSpaceToggle<TItem>(TableView tableView, Func<TItem, bool> getChecked, Action<TItem, bool> setChecked)
public static void AddSpaceToggle<TItem>(TableView tableView, Func<TItem, bool> checkStatus, Action<TItem, bool> setChecked)
where TItem : class
{
tableView.AddHandler(InputElement.KeyDownEvent, (object? _, KeyEventArgs e) =>
tableView.AddHandler(InputElement.KeyDownEvent, (_, e) =>
{
if (e.Key != Key.Space)
{
Expand All @@ -427,7 +427,7 @@ public static void AddSpaceToggle<TItem>(TableView tableView, Func<TItem, bool>
return;
}

var newValue = !selected.All(getChecked);
var newValue = !selected.All(checkStatus);
foreach (var item in selected)
{
setChecked(item, newValue);
Expand Down
Loading