using FileTime.Core.Components; using FileTime.Core.Extensions; using FileTime.Core.Interactions; using FileTime.Core.Models; using FileTime.Providers.Local; using FileTime.Avalonia.Application; using FileTime.Avalonia.Command; using FileTime.Avalonia.Misc; using FileTime.Avalonia.Models; using FileTime.Avalonia.Services; using MvvmGen; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using Avalonia.Input; using FileTime.App.Core.Clipboard; using Microsoft.Extensions.DependencyInjection; using FileTime.Core.Command; using FileTime.Core.Timeline; using FileTime.Core.Providers; using Syroot.Windows.IO; using FileTime.Avalonia.IconProviders; using Avalonia.Threading; namespace FileTime.Avalonia.ViewModels { [ViewModel] [Inject(typeof(LocalContentProvider))] [Inject(typeof(AppState), PropertyAccessModifier = AccessModifier.Public)] [Inject(typeof(ItemNameConverterService))] public partial class MainPageViewModel { const string RAPIDTRAVEL = "rapidTravel"; private readonly List _previousKeys = new List(); private readonly List _keysToSkip = new List(); private List _commandBindings = new(); private List _universalCommandBindings = new(); private IClipboard _clipboard; private TimeRunner _timeRunner; private IEnumerable _contentProviders; private IIconProvider _iconProvider; private Func? _inputHandler; [Property] private string _text; [Property] private bool _noCommandFound; [Property] private List _possibleCommands = new(); [Property] private List _inputs; [Property] private List _rootDriveInfos; [Property] private List _places; [Property] private string _messageBoxText; [Property] private ObservableCollection _popupTexts = new ObservableCollection(); public ObservableCollection TimelineCommands { get; } = new(); async partial void OnInitialize() { _clipboard = App.ServiceProvider.GetService()!; _timeRunner = App.ServiceProvider.GetService()!; _contentProviders = App.ServiceProvider.GetService>()!; _iconProvider = App.ServiceProvider.GetService()!; var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService()!; inputInterface.InputHandler = ReadInputs; App.ServiceProvider.GetService(); _timeRunner.CommandsChanged += UpdateParalellCommands; InitCommandBindings(); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Up) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Down) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Tab) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.PageDown) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.PageUp) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.F4, alt: true) }); var tab = new Tab(); await tab.Init(LocalContentProvider); var tabContainer = new TabContainer(tab, LocalContentProvider, ItemNameConverterService); await tabContainer.Init(1); tabContainer.IsSelected = true; AppState.Tabs.Add(tabContainer); var driveInfos = new List(); foreach (var drive in DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Fixed)) { var container = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? await GetContainerForWindowsDrive(drive) : await GetContainerForLinuxDrive(drive); if (container != null) { var driveInfo = new RootDriveInfo(drive, container); driveInfos.Add(driveInfo); } } RootDriveInfos = driveInfos.OrderBy(d => d.Name).ToList(); var places = new List(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var placesFolders = new List() { KnownFolders.Profile, KnownFolders.Desktop, KnownFolders.DocumentsLocalized, KnownFolders.DownloadsLocalized, KnownFolders.Music, KnownFolders.Pictures, KnownFolders.Videos, }; foreach (var placesFolder in placesFolders) { var possibleContainer = await LocalContentProvider.GetByPath(placesFolder.Path); if (possibleContainer is IContainer container) { var name = container.Name; if (await container.GetByPath("desktop.ini") is LocalFile element) { var lines = File.ReadAllLines(element.File.FullName); if (Array.Find(lines, l => l.StartsWith("localizedresourcename", StringComparison.OrdinalIgnoreCase)) is string nameLine) { var nameLineValue = string.Join('=', nameLine.Split('=')[1..]); var environemntVariables = Environment.GetEnvironmentVariables(); foreach (var keyo in environemntVariables.Keys) { if (keyo is string key && environemntVariables[key] is string value) { nameLineValue = nameLineValue.Replace($"%{key}%", value); } } if (nameLineValue.StartsWith("@")) { var parts = nameLineValue[1..].Split(','); if (parts.Length >= 2 && long.TryParse(parts[^1], out var parsedResourceId)) { if (parsedResourceId < 0) parsedResourceId *= -1; name = NativeMethodHelpers.GetStringResource(string.Join(',', parts[..^1]), (uint)parsedResourceId); } } else { name = nameLineValue; } } } places.Add(new PlaceInfo(name, container)); } } } else { throw new Exception("TODO linux places"); } Places = places; } private void UpdateParalellCommands(object? sender, EventArgs e) { foreach (var parallelCommand in _timeRunner.ParallelCommands) { if (!TimelineCommands.Any(c => c.Id == parallelCommand.Id)) { TimelineCommands.Add(new ParallelCommandsViewModel(parallelCommand)); } } var itemsToRemove = new List(); foreach (var parallelCommandVm in TimelineCommands) { if (!_timeRunner.ParallelCommands.Any(c => c.Id == parallelCommandVm.Id)) { itemsToRemove.Add(parallelCommandVm); } } for (var i = 0; i < itemsToRemove.Count; i++) { itemsToRemove[i].Dispose(); TimelineCommands.Remove(itemsToRemove[i]); } } private async Task GetContainerForWindowsDrive(DriveInfo drive) { return (await LocalContentProvider.GetRootContainers()).FirstOrDefault(d => d.Name == drive.Name.TrimEnd(Path.DirectorySeparatorChar)); } private async Task GetContainerForLinuxDrive(DriveInfo drive) { return await LocalContentProvider.GetByPath(drive.Name) as IContainer; } public async Task OpenContainer() { AppState.RapidTravelText = ""; await AppState.SelectedTab.Open(); } public async Task OpenContainer(IContainer container) { AppState.RapidTravelText = ""; await AppState.SelectedTab.OpenContainer(container); } public async Task OpenOrRun() { if (AppState.SelectedTab.SelectedItem is ContainerViewModel) { await OpenContainer(); } else if (AppState.SelectedTab.SelectedItem is ElementViewModel elementViewModel && elementViewModel.Element is LocalFile localFile) { Process.Start(new ProcessStartInfo(localFile.File.FullName) { UseShellExecute = true }); if (AppState.ViewMode == ViewMode.RapidTravel) { await ExitRapidTravelMode(); } } } public async Task GoUp() { await AppState.SelectedTab.GoUp(); } public async Task MoveCursorUp() { await AppState.SelectedTab.MoveCursorUp(); } public async Task MoveCursorDown() { await AppState.SelectedTab.MoveCursorDown(); } public async Task MoveCursorUpPage() { await AppState.SelectedTab.MoveCursorUpPage(); } public async Task MoveCursorDownPage() { await AppState.SelectedTab.MoveCursorDownPage(); } public async Task MoveToFirst() { await AppState.SelectedTab.MoveCursorToFirst(); } public async Task MoveToLast() { await AppState.SelectedTab.MoveCursorToLast(); } public async Task GotToProvider() { await AppState.SelectedTab.GotToProvider(); } public async Task GotToRoot() { await AppState.SelectedTab.GotToRoot(); } public async Task GotToHome() { await AppState.SelectedTab.GotToHome(); } public Task EnterRapidTravelMode() { AppState.ViewMode = ViewMode.RapidTravel; _previousKeys.Clear(); PossibleCommands = new(); return Task.CompletedTask; } public async Task ExitRapidTravelMode() { AppState.ViewMode = ViewMode.Default; _previousKeys.Clear(); PossibleCommands = new(); AppState.RapidTravelText = ""; await AppState.SelectedTab.OpenContainer(await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL)); } public async Task SwitchToTab(int number) { var tabContainer = AppState.Tabs.FirstOrDefault(t => t.TabNumber == number); if (number == -1) { var greatestNumber = AppState.Tabs.Select(t => t.TabNumber).Max(); tabContainer = AppState.Tabs.FirstOrDefault(t => t.TabNumber == greatestNumber); } else if (tabContainer == null) { var newContainer = await AppState.SelectedTab.CurrentLocation.Container.Clone(); var newTab = new Tab(); await newTab.Init(newContainer); tabContainer = new TabContainer(newTab, LocalContentProvider, ItemNameConverterService); await tabContainer.Init(number); var i = 0; for (i = 0; i < AppState.Tabs.Count; i++) { if (AppState.Tabs[i].TabNumber > number) break; } AppState.Tabs.Insert(i, tabContainer); } if (AppState.ViewMode == ViewMode.RapidTravel) { await ExitRapidTravelMode(); } AppState.SelectedTab = tabContainer; foreach (var tab2 in AppState.Tabs) { tab2.IsSelected = tab2.TabNumber == tabContainer!.TabNumber; } } public async Task CloseTab() { var tabs = AppState.Tabs; if (tabs.Count > 1) { var currentTab = tabs.FirstOrDefault(t => t == AppState.SelectedTab); if (currentTab != null) { tabs.Remove(currentTab); var tabNumber = tabs[0].TabNumber; for (var i = 0; i < tabs.Count; i++) { tabNumber = tabs[i].TabNumber; if (tabs[i].TabNumber > currentTab.TabNumber) break; } await SwitchToTab(tabNumber); } } } public Task CreateContainer() { var handler = async () => { if (Inputs != null) { var container = AppState.SelectedTab.CurrentLocation.Container; var createContainerCommand = new CreateContainerCommand(new Core.Models.AbsolutePath(container), Inputs[0].Value); await _timeRunner.AddCommand(createContainerCommand); Inputs = null; } }; ReadInputs(new List() { new Core.Interactions.InputElement("Container name", InputType.Text) }, handler); return Task.CompletedTask; } public Task CreateElement() { var handler = async () => { if (Inputs != null) { var container = AppState.SelectedTab.CurrentLocation.Container; var createElementCommand = new CreateElementCommand(new Core.Models.AbsolutePath(container), Inputs[0].Value); await _timeRunner.AddCommand(createElementCommand); Inputs = null; } }; ReadInputs(new List() { new Core.Interactions.InputElement("Element name", InputType.Text) }, handler); return Task.CompletedTask; } public async Task MarkCurrentItem() { await AppState.SelectedTab.MarkCurrentItem(); } public async Task Copy() { _clipboard.Clear(); _clipboard.SetCommand(); var currentSelectedItems = await AppState.SelectedTab.TabState.GetCurrentMarkedItems(); if (currentSelectedItems.Count > 0) { foreach (var selectedItem in currentSelectedItems) { _clipboard.AddContent(selectedItem); } } else { var currentSelectedItem = AppState.SelectedTab.SelectedItem?.Item; if (currentSelectedItem != null) { _clipboard.AddContent(new AbsolutePath(currentSelectedItem)); } } } public Task Cut() { _clipboard.Clear(); _clipboard.SetCommand(); return Task.CompletedTask; } public async Task Delete() { IList? itemsToDelete = null; var askForDelete = false; var questionText = ""; var shouldDelete = false; var currentSelectedItems = await AppState.SelectedTab.TabState.GetCurrentMarkedItems(); var currentSelectedItem = AppState.SelectedTab.SelectedItem?.Item; if (currentSelectedItems.Count > 0) { itemsToDelete = currentSelectedItems.Cast().ToList(); //FIXME: check 'is Container' if (currentSelectedItems.Count == 1) { if ((await currentSelectedItems[0].Resolve()) is IContainer container && (await container.GetItems())?.Count > 0) { askForDelete = true; questionText = $"The container '{container.Name}' is not empty. Proceed with delete?"; } else { shouldDelete = true; } } else { askForDelete = true; questionText = $"Are you sure you want to delete {itemsToDelete.Count} item?"; } } else if (currentSelectedItem != null) { itemsToDelete = new List() { new Core.Models.AbsolutePath(currentSelectedItem) }; if (currentSelectedItem is IContainer container && (await container.GetItems())?.Count > 0) { askForDelete = true; questionText = $"The container '{container.Name}' is not empty. Proceed with delete?"; } else { shouldDelete = true; } } if (itemsToDelete?.Count > 0) { if (askForDelete) { ShowMessageBox(questionText, HandleDelete); } else if (shouldDelete) { await HandleDelete(); } } async Task HandleDelete() { var deleteCommand = new DeleteCommand(); foreach (var itemToDelete in itemsToDelete!) { deleteCommand.ItemsToDelete.Add(itemToDelete); } await _timeRunner.AddCommand(deleteCommand); _clipboard.Clear(); } } public async Task PasteMerge() { await Paste(TransportMode.Merge); } public async Task PasteOverwrite() { await Paste(TransportMode.Overwrite); } public async Task PasteSkip() { await Paste(TransportMode.Skip); } private async Task Paste(TransportMode transportMode) { if (_clipboard.CommandType != null) { var command = (ITransportationCommand)Activator.CreateInstance(_clipboard.CommandType!)!; command.TransportMode = transportMode; command.Sources.Clear(); foreach (var item in _clipboard.Content) { command.Sources.Add(item); } var currentLocation = AppState.SelectedTab.CurrentLocation.Container; command.Target = currentLocation is VirtualContainer virtualContainer ? virtualContainer.BaseContainer : currentLocation; await _timeRunner.AddCommand(command); _clipboard.Clear(); } } private Task Rename() { var selectedItem = AppState.SelectedTab.SelectedItem?.Item; if (selectedItem != null) { var handler = async () => { if (Inputs != null) { var renameCommand = new RenameCommand(new Core.Models.AbsolutePath(selectedItem), Inputs[0].Value); await _timeRunner.AddCommand(renameCommand); } }; ReadInputs(new List() { new Core.Interactions.InputElement("New name", InputType.Text, selectedItem.Name) }, handler); } return Task.CompletedTask; } private async Task RefreshCurrentLocation() { await AppState.SelectedTab.CurrentLocation.Container.Refresh(); await AppState.SelectedTab.UpdateCurrentSelectedItem(); } private Task PauseTimeline() { _timeRunner.EnableRunning = false; return Task.CompletedTask; } private async Task ContinueTimeline() { _timeRunner.EnableRunning = true; await _timeRunner.TryStartCommandRunner(); } private async Task RefreshTimeline() { await _timeRunner.Refresh(); } private Task GoToContainer() { var handler = async () => { if (Inputs != null) { var path = Inputs[0].Value; foreach (var contentProvider in _contentProviders) { if (contentProvider.CanHandlePath(path)) { var possibleContainer = await contentProvider.GetByPath(path); if (possibleContainer is IContainer container) { AppState.SelectedTab.OpenContainer(container).Wait(); } //TODO: multiple possible content provider handler return; } } } }; ReadInputs(new List() { new Core.Interactions.InputElement("Path", InputType.Text) }, handler); return Task.CompletedTask; } private Task ToggleAdvancedIcons() { _iconProvider.EnableAdvancedIcons = !_iconProvider.EnableAdvancedIcons; var text = "Advanced icons are: " + (_iconProvider.EnableAdvancedIcons ? "ON" : "OFF"); _popupTexts.Add(text); Task.Run(async () => { await Task.Delay(5000); await Dispatcher.UIThread.InvokeAsync(() => _popupTexts.Remove(text)); }); return Task.CompletedTask; } [Command] public async void ProcessInputs() { if (_inputHandler != null) { await _inputHandler.Invoke(); } Inputs = null; _inputHandler = null; } [Command] public void CancelInputs() { Inputs = null; _inputHandler = null; } [Command] public void ProcessMessageBoxCommand() { _inputHandler?.Invoke(); MessageBoxText = null; _inputHandler = null; } [Command] public void CancelMessageBoxCommand() { MessageBoxText = null; _inputHandler = null; } public async Task ProcessKeyDown(Key key, KeyModifiers keyModifiers) { if (key == Key.LeftAlt || key == Key.RightAlt || key == Key.LeftShift || key == Key.RightShift || key == Key.LeftCtrl || key == Key.RightCtrl) return false; NoCommandFound = false; var isAltPressed = (keyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt; var isShiftPressed = (keyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift; var isCtrlPressed = (keyModifiers & KeyModifiers.Control) == KeyModifiers.Control; if (AppState.ViewMode == ViewMode.Default) { var keyWithModifiers = new KeyWithModifiers(key, isAltPressed, isShiftPressed, isCtrlPressed); _previousKeys.Add(keyWithModifiers); var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys)); selectedCommandBinding ??= _commandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys)); if (key == Key.Escape) { _previousKeys.Clear(); PossibleCommands = new(); } else if (selectedCommandBinding != null) { await selectedCommandBinding.InvokeAsync(); _previousKeys.Clear(); PossibleCommands = new(); } else if (_keysToSkip.Any(k => AreKeysEqual(k, _previousKeys))) { _previousKeys.Clear(); PossibleCommands = new(); return false; } else if (_previousKeys.Count == 2) { NoCommandFound = true; _previousKeys.Clear(); PossibleCommands = new(); } else { var possibleCommands = _universalCommandBindings.Concat(_commandBindings).Where(c => AreKeysEqual(c.Keys[0], keyWithModifiers)).ToList(); if (possibleCommands.Count == 0) { NoCommandFound = true; _previousKeys.Clear(); } else { PossibleCommands = possibleCommands; } } } else { var keyString = key.ToString(); var updateRapidTravelFilter = false; if (key == Key.Escape) { await ExitRapidTravelMode(); } else if (key == Key.Back) { if (AppState.RapidTravelText.Length > 0) { AppState.RapidTravelText = AppState.RapidTravelText.Substring(0, AppState.RapidTravelText.Length - 1); updateRapidTravelFilter = true; } } else if (keyString.Length == 1) { AppState.RapidTravelText += keyString.ToString().ToLower(); updateRapidTravelFilter = true; } else { var currentKeyAsList = new List() { new KeyWithModifiers(key) }; var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, currentKeyAsList)); if (selectedCommandBinding != null) { await selectedCommandBinding.InvokeAsync(); return true; } else { return false; } } if (updateRapidTravelFilter) { var currentLocation = await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL); var newLocation = new VirtualContainer( currentLocation, new List, IEnumerable>>() { container => container.Where(c => c.Name.ToLower().Contains(AppState.RapidTravelText)) }, new List, IEnumerable>>() { element => element.Where(e => e.Name.ToLower().Contains(AppState.RapidTravelText)) }, virtualContainerName: RAPIDTRAVEL ); await newLocation.Init(); await AppState.SelectedTab.OpenContainer(newLocation); var selectedItemName = AppState.SelectedTab.SelectedItem?.Item.Name; var currentLocationItems = await AppState.SelectedTab.CurrentLocation.GetItems(); if (currentLocationItems.FirstOrDefault(i => i.Item.Name.ToLower() == AppState.RapidTravelText.ToLower()) is IItemViewModel matchItem) { await AppState.SelectedTab.SetCurrentSelectedItem(matchItem.Item); } else if (!currentLocationItems.Select(i => i.Item.Name).Any(n => n == selectedItemName)) { await AppState.SelectedTab.MoveCursorToFirst(); } } } return true; } public Task ProcessKeyUp(Key key, KeyModifiers keyModifiers) { return Task.FromResult(false); } private void ReadInputs(List inputs, Action inputHandler) { ReadInputs(inputs, () => { inputHandler(); return Task.CompletedTask; }); } private void ReadInputs(List inputs, Func inputHandler) { Inputs = inputs.Select(i => new InputElementWrapper(i, i.DefaultValue)).ToList(); _inputHandler = inputHandler; } public async Task ReadInputs(IEnumerable fields) { var waiting = true; var result = new string[0]; ReadInputs(fields.ToList(), () => { if (Inputs != null) { result = Inputs.Select(i => i.Value).ToArray(); } waiting = false; }); while (waiting) await Task.Delay(100); return result; } private void ShowMessageBox(string text, Func inputHandler) { MessageBoxText = text; _inputHandler = inputHandler; } private static bool AreKeysEqual(IReadOnlyList collection1, IReadOnlyList collection2) { if (collection1.Count != collection2.Count) return false; for (var i = 0; i < collection1.Count; i++) { if (!AreKeysEqual(collection1[i], collection2[i])) return false; } return true; } private static bool AreKeysEqual(KeyWithModifiers key1, KeyWithModifiers key2) => key1.Key == key2.Key && key1.Alt == key2.Alt && key1.Shift == key2.Shift && key1.Ctrl == key1.Ctrl; private void InitCommandBindings() { var commandBindings = new List() { new CommandBinding( "enter rapid travel mode", FileTime.App.Core.Command.Commands.EnterRapidTravel, new KeyWithModifiers[]{new KeyWithModifiers(Key.OemComma, shift: true)}, EnterRapidTravelMode), new CommandBinding( "create container", FileTime.App.Core.Command.Commands.CreateContainer, new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.C)}, CreateContainer), new CommandBinding( "create element", FileTime.App.Core.Command.Commands.CreateElement, new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.E)}, CreateElement), new CommandBinding( "move to first", FileTime.App.Core.Command.Commands.MoveToTop, new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.G)}, MoveToFirst), new CommandBinding( "move to last", FileTime.App.Core.Command.Commands.MoveToBottom, new KeyWithModifiers[]{new KeyWithModifiers(Key.G, shift: true)}, MoveToLast), new CommandBinding( "go to provider", FileTime.App.Core.Command.Commands.GoToProvider, new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.T)}, GotToProvider), new CommandBinding( "go to root", FileTime.App.Core.Command.Commands.GoToRoot, new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.R)}, GotToRoot), new CommandBinding( "go to home", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.H)}, GotToHome), new CommandBinding( "switch to tab 1", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D1)}, async() => await SwitchToTab(1)), new CommandBinding( "switch to tab 2", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D2)}, async() => await SwitchToTab(2)), new CommandBinding( "switch to tab 3", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D3)}, async() => await SwitchToTab(3)), new CommandBinding( "switch to tab 4", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D4)}, async() => await SwitchToTab(4)), new CommandBinding( "switch to tab 5", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D5)}, async() => await SwitchToTab(5)), new CommandBinding( "switch to tab 6", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D6)}, async() => await SwitchToTab(6)), new CommandBinding( "switch to tab 7", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D7)}, async() => await SwitchToTab(7)), new CommandBinding( "switch to tab 8", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D8)}, async() => await SwitchToTab(8)), new CommandBinding( "switch to last tab", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.D9)}, async() => await SwitchToTab(-1)), new CommandBinding( "close tab", FileTime.App.Core.Command.Commands.GoToHome, new KeyWithModifiers[]{new KeyWithModifiers(Key.Q)}, CloseTab), new CommandBinding( "select", FileTime.App.Core.Command.Commands.Select, new KeyWithModifiers[]{new KeyWithModifiers(Key.Space)}, MarkCurrentItem), new CommandBinding( "copy", FileTime.App.Core.Command.Commands.Copy, new KeyWithModifiers[]{new KeyWithModifiers(Key.Y),new KeyWithModifiers(Key.Y)}, Copy), new CommandBinding( "cut", FileTime.App.Core.Command.Commands.Cut, new KeyWithModifiers[]{new KeyWithModifiers(Key.D),new KeyWithModifiers(Key.D)}, Cut), new CommandBinding( "delete", FileTime.App.Core.Command.Commands.Delete, new KeyWithModifiers[]{new KeyWithModifiers(Key.D),new KeyWithModifiers(Key.D, shift: true)}, Delete), new CommandBinding( "paste merge", FileTime.App.Core.Command.Commands.PasteMerge, new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.P)}, PasteMerge), new CommandBinding( "paste (overwrite)", FileTime.App.Core.Command.Commands.PasteOverwrite, new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.O)}, PasteOverwrite), new CommandBinding( "paste (skip)", FileTime.App.Core.Command.Commands.PasteSkip, new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.S)}, PasteSkip), new CommandBinding( "rename", FileTime.App.Core.Command.Commands.Rename, new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.W)}, Rename), new CommandBinding( "timeline pause", FileTime.App.Core.Command.Commands.Dummy, new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.P)}, PauseTimeline), new CommandBinding( "timeline start", FileTime.App.Core.Command.Commands.Dummy, new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.S)}, ContinueTimeline), new CommandBinding( "refresh timeline", FileTime.App.Core.Command.Commands.Dummy, new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.R)}, RefreshTimeline), new CommandBinding( "refresh", FileTime.App.Core.Command.Commands.Refresh, new KeyWithModifiers[]{new KeyWithModifiers(Key.R)}, RefreshCurrentLocation), new CommandBinding( "go to", FileTime.App.Core.Command.Commands.Dummy, new KeyWithModifiers[]{new KeyWithModifiers(Key.L, ctrl: true)}, GoToContainer), new CommandBinding( "toggle advanced icons", FileTime.App.Core.Command.Commands.Dummy, new KeyWithModifiers[]{new KeyWithModifiers(Key.Z),new KeyWithModifiers(Key.I)}, ToggleAdvancedIcons), }; var universalCommandBindings = new List() { new CommandBinding("go up", FileTime.App.Core.Command.Commands.GoUp, new KeyWithModifiers[]{new KeyWithModifiers(Key.Left)}, GoUp), new CommandBinding("open", FileTime.App.Core.Command.Commands.Open, new KeyWithModifiers[]{new KeyWithModifiers(Key.Right)}, OpenContainer), new CommandBinding("open or run", FileTime.App.Core.Command.Commands.OpenOrRun, new KeyWithModifiers[]{new KeyWithModifiers(Key.Enter)}, OpenOrRun), new CommandBinding("cursor up", FileTime.App.Core.Command.Commands.MoveCursorUp, new KeyWithModifiers[]{new KeyWithModifiers(Key.Up)}, MoveCursorUp), new CommandBinding("cursor down", FileTime.App.Core.Command.Commands.MoveCursorDown, new KeyWithModifiers[]{new KeyWithModifiers(Key.Down)}, MoveCursorDown), new CommandBinding("cursor page up", FileTime.App.Core.Command.Commands.MoveCursorUpPage, new KeyWithModifiers[]{new KeyWithModifiers(Key.PageUp)}, MoveCursorUpPage), new CommandBinding("cursor page down", FileTime.App.Core.Command.Commands.MoveCursorDownPage, new KeyWithModifiers[]{new KeyWithModifiers(Key.PageDown)}, MoveCursorDownPage), }; _commandBindings.AddRange(commandBindings); _universalCommandBindings.AddRange(universalCommandBindings); } } }