using System; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Collections.Generic; using System.Text.RegularExpressions; using Avalonia; using Avalonia.Controls; using Avalonia.VisualTree; using Avalonia.Markup.Xaml; using Avalonia.LogicalTree; using BFR.Helpers; using BFR.DataModels; using Avalonia.Input; namespace BFR { public partial class MainWindow : Window { public readonly AvaloniaProperty[] HandledProperties = new AvaloniaProperty[] { TextBox.TextProperty, ComboBox.SelectedItemProperty, NumericUpDown.ValueProperty, CheckBox.IsCheckedProperty }; private bool HandleEvents = false; public async Task OpenDirectoryButtonClick() => OpenDirectory(await new OpenFolderDialog() { Directory = WorkingDirectory }.ShowAsync(this)); public void OpenDirectory(string directory) { WorkingDirectory = directory.Replace('\\', '/'); AllFiles.ReplaceAll(Directory.GetFiles(WorkingDirectory).Select(x => new FileModel(x.Replace('\\', '/')))); Filter(); } public void FilterChanged(object sender, AvaloniaPropertyChangedEventArgs e) { if(HandledProperties.Contains(e.Property) && HandleEvents) 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.OldExtension == FilterExtension) && (FilterFullName ? x.OldFullName : x.OldName).RegexContains(FilterRegex ? FilterPattern : Regex.Escape(FilterPattern)))); Preview(); } public void PreviewChanged(object sender, AvaloniaPropertyChangedEventArgs e) { if (HandledProperties.Contains(e.Property) && HandleEvents) Preview(); // Bind to PropertyChanged } public void Preview() { // Reset all files to how they currently exist foreach (var file in Files) file.Path = file.OldPath; // Apply operations foreach (var operation in Operations) operation.ApplyTo(Files); // Validate that there are any changes, and that the new file names are all unique. IsCommitButtonEnabled = Files.Any(x => x.Path != x.OldPath) // Check for changes && Files.GroupBy(x => x.Path).All(g => g.Count() == 1) // Check for duplicates && !Files.Any(x => x.FullName == "") // Check for empty file names && !Files.Any(x => "?%*:<>|/\\\"".Any(y => x.FullName.Contains(y))); // Check for invalid characters // Refresh the file list to guarantee that changes are displayed. TODO: Find a better way to do this. Files.ReplaceAll(new List(Files)); } public void AddOperation() { HandleEvents = false; if (Operations.Count >= 1) Operations.Insert( SelectedOperation >= 0 ? SelectedOperation + 1 : Operations.Count, OperationTypes[SelectedOperationType].Create()); else Operations.Add(OperationTypes[SelectedOperationType].Create()); HandleEvents = true; Preview(); } private ListBox OperationsListBox; private ListBoxItem DragItem; public void DeleteOperation(object sender, PointerReleasedEventArgs e) { var hoveredItem = (ListBoxItem)OperationsListBox.GetLogicalChildren().FirstOrDefault(x => this.GetVisualsAt(e.GetPosition(this)).Contains(((IVisual)x).GetVisualChildren().First())); if(hoveredItem != null) Operations.RemoveAt(OperationsListBox.GetLogicalChildren().ToList().IndexOf(hoveredItem)); Preview(); } public void StartMoveOperation(object sender, PointerPressedEventArgs e) => DragItem = OperationsListBox.GetLogicalChildren().Cast().Single(x => x.IsPointerOver); public void EndMoveOperation(object sender, PointerReleasedEventArgs e) { var hoveredItem = (ListBoxItem)OperationsListBox.GetLogicalChildren().FirstOrDefault(x => this.GetVisualsAt(e.GetPosition(this)).Contains(((IVisual)x).GetVisualChildren().First())); if (DragItem == null || hoveredItem == null || DragItem == hoveredItem) return; Operations.Move( OperationsListBox.GetLogicalChildren().ToList().IndexOf(DragItem), OperationsListBox.GetLogicalChildren().ToList().IndexOf(hoveredItem)); DragItem = null; Preview(); } public void Commit() { foreach (var file in Files) if (file.OldPath != file.Path) File.Move(file.OldPath, file.Path); UndoStack.Push(new List(Files)); UndoCount = UndoStack.Count; OpenDirectory(WorkingDirectory); } public void Undo() { foreach (var file in UndoStack.Pop()) File.Move(file.Path, file.OldPath); UndoCount = UndoStack.Count; OpenDirectory(WorkingDirectory); } public MainWindow() => InitializeComponent(); private void InitializeComponent() { AvaloniaXamlLoader.Load(this); DataContext = this; OpenDirectory(Environment.OSVersion.Platform == PlatformID.Win32NT ? @"C:/Users/" : @"/home/"); HandleEvents = true; OperationsListBox = this.Find("OperationsListBox"); } } }