From a4953807eb1633274623a7d85259b8a9fb32755e Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 14 Apr 2020 22:32:47 +0100 Subject: [PATCH] Implement listing devices in main window. --- Aaru.Gui/Forms/frmMain.xeto.cs | 222 +-------------------- Aaru.Gui/Models/DeviceModel.cs | 9 +- Aaru.Gui/ViewModels/MainWindowViewModel.cs | 144 +++++++++++-- Aaru.Gui/Views/MainWindow.xaml | 48 +++-- Aaru.Gui/Views/MainWindow.xaml.cs | 18 +- 5 files changed, 178 insertions(+), 263 deletions(-) diff --git a/Aaru.Gui/Forms/frmMain.xeto.cs b/Aaru.Gui/Forms/frmMain.xeto.cs index 38260a644..9983dd423 100644 --- a/Aaru.Gui/Forms/frmMain.xeto.cs +++ b/Aaru.Gui/Forms/frmMain.xeto.cs @@ -31,14 +31,8 @@ // ****************************************************************************/ using System; -using System.Collections.Generic; using System.ComponentModel; using System.IO; -using System.Linq; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; -using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; using Aaru.Core; using Aaru.Core.Media.Info; @@ -47,7 +41,7 @@ using Aaru.Gui.Panels; using Eto.Drawing; using Eto.Forms; using Eto.Serialization.Xaml; -using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo; namespace Aaru.Gui.Forms { @@ -180,7 +174,7 @@ namespace Aaru.Gui.Forms Text = "Refresh devices" }; - menuItem.Click += OnDeviceRefresh; + // menuItem.Click += OnDeviceRefresh; treeImagesMenu.Items.Add(menuItem); if(!(treeImages.SelectedItem is TreeGridItem selectedItem)) @@ -203,106 +197,6 @@ namespace Aaru.Gui.Forms Application.Instance.Quit(); } - protected void OnDeviceRefresh(object sender, EventArgs e) => RefreshDevices(); - - protected override void OnLoadComplete(EventArgs e) - { - base.OnLoadComplete(e); - - RefreshDevices(); - } - - void RefreshDevices() - { - try - { - AaruConsole.WriteLine("Refreshing devices"); - devicesRoot.Children.Clear(); - - foreach(DeviceInfo device in Device.ListDevices().Where(d => d.Supported).OrderBy(d => d.Vendor). - ThenBy(d => d.Model)) - { - AaruConsole.DebugWriteLine("Main window", - "Found supported device model {0} by manufacturer {1} on bus {2} and path {3}", - device.Model, device.Vendor, device.Bus, device.Path); - - var devItem = new TreeGridItem - { - Values = new object[] - { - hardDiskIcon, $"{device.Vendor} {device.Model} ({device.Bus})", device.Path, null - } - }; - - try - { - var dev = new Device(device.Path); - - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); - - switch(dev.Type) - { - case DeviceType.ATAPI: - case DeviceType.SCSI: - switch(dev.ScsiType) - { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.SCSIZonedBlockDevice: - case PeripheralDeviceTypes.SimplifiedDevice: - devItem.Values[0] = dev.IsRemovable ? dev.IsUsb - ? usbIcon - : removableIcon : hardDiskIcon; - - break; - case PeripheralDeviceTypes.SequentialAccess: - devItem.Values[0] = tapeIcon; - - break; - case PeripheralDeviceTypes.OpticalDevice: - case PeripheralDeviceTypes.WriteOnceDevice: - case PeripheralDeviceTypes.OCRWDevice: - devItem.Values[0] = removableIcon; - - break; - case PeripheralDeviceTypes.MultiMediaDevice: - devItem.Values[0] = opticalIcon; - - break; - } - - break; - case DeviceType.SecureDigital: - case DeviceType.MMC: - devItem.Values[0] = sdIcon; - - break; - case DeviceType.NVMe: - devItem.Values[0] = nullImage; - - break; - } - - dev.Close(); - } - catch - { - // ignored - } - - devItem.Children.Add(placeholderItem); - devicesRoot.Children.Add(devItem); - } - - treeImages.ReloadData(); - } - catch(InvalidOperationException ex) - { - AaruConsole.ErrorWriteLine(ex.Message); - } - } - protected void OnTreeImagesSelectedItemChanged(object sender, EventArgs e) { if(!(sender is TreeGridView tree)) @@ -342,7 +236,7 @@ namespace Aaru.Gui.Forms return; } - var devInfo = new Core.Devices.Info.DeviceInfo(dev); + var devInfo = new DeviceInfo(dev); selectedItem.Values[3] = new pnlDeviceInfo(devInfo); splMain.Panel2 = (Panel)selectedItem.Values[3]; @@ -449,116 +343,6 @@ namespace Aaru.Gui.Forms dev.Close(); } - else if(((TreeGridItem)e.Item).Values[2] is IReadOnlyFilesystem fsPlugin) - { - var fsItem = (TreeGridItem)e.Item; - - fsItem.Children.Clear(); - - if(fsItem.Values.Length == 5 && - fsItem.Values[4] is string dirPath) - { - Errno errno = fsPlugin.ReadDir(dirPath, out List dirents); - - if(errno != Errno.NoError) - { - Eto.Forms.MessageBox.Show($"Error {errno} trying to read \"{dirPath}\" of chosen filesystem", - MessageBoxType.Error); - - return; - } - - List directories = new List(); - - foreach(string dirent in dirents) - { - errno = fsPlugin.Stat(dirPath + "/" + dirent, out FileEntryInfo stat); - - if(errno != Errno.NoError) - { - AaruConsole. - ErrorWriteLine($"Error {errno} trying to get information about filesystem entry named {dirent}"); - - continue; - } - - if(stat.Attributes.HasFlag(FileAttributes.Directory)) - directories.Add(dirent); - } - - foreach(string directory in directories) - { - var dirItem = new TreeGridItem - { - Values = new object[] - { - imagesIcon, directory, fsPlugin, null, dirPath + "/" + directory - } - }; - - dirItem.Children.Add(placeholderItem); - fsItem.Children.Add(dirItem); - } - } - else - { - Errno errno = fsPlugin.ReadDir("/", out List dirents); - - if(errno != Errno.NoError) - { - Eto.Forms.MessageBox.Show($"Error {errno} trying to read root directory of chosen filesystem", - MessageBoxType.Error); - - return; - } - - Dictionary files = new Dictionary(); - List directories = new List(); - - foreach(string dirent in dirents) - { - errno = fsPlugin.Stat("/" + dirent, out FileEntryInfo stat); - - if(errno != Errno.NoError) - { - AaruConsole. - ErrorWriteLine($"Error {errno} trying to get information about filesystem entry named {dirent}"); - - continue; - } - - if(stat.Attributes.HasFlag(FileAttributes.Directory)) - directories.Add(dirent); - else - files.Add(dirent, stat); - } - - var rootDirectoryItem = new TreeGridItem - { - Values = new object[] - { - nullImage, // TODO: Get icon from volume - "/", fsPlugin, files - } - }; - - foreach(string directory in directories) - { - var dirItem = new TreeGridItem - { - Values = new object[] - { - imagesIcon, directory, fsPlugin, null, "/" + directory - } - }; - - dirItem.Children.Add(placeholderItem); - rootDirectoryItem.Children.Add(dirItem); - } - - fsItem.Children.Add(rootDirectoryItem); - } - } } #region XAML IDs diff --git a/Aaru.Gui/Models/DeviceModel.cs b/Aaru.Gui/Models/DeviceModel.cs index f4539dae4..599ee5ec7 100644 --- a/Aaru.Gui/Models/DeviceModel.cs +++ b/Aaru.Gui/Models/DeviceModel.cs @@ -1,4 +1,11 @@ +using Avalonia.Media.Imaging; + namespace Aaru.Gui.Models { - public class DeviceModel {} + public class DeviceModel + { + public Bitmap Icon { get; set; } + public string Name { get; set; } + public string Path { get; set; } + } } \ No newline at end of file diff --git a/Aaru.Gui/ViewModels/MainWindowViewModel.cs b/Aaru.Gui/ViewModels/MainWindowViewModel.cs index 5ebbf7431..dff37b270 100644 --- a/Aaru.Gui/ViewModels/MainWindowViewModel.cs +++ b/Aaru.Gui/ViewModels/MainWindowViewModel.cs @@ -9,9 +9,11 @@ using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Structs; +using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; using Aaru.Core; using Aaru.Database; +using Aaru.Devices; using Aaru.Gui.Models; using Aaru.Gui.Panels; using Aaru.Gui.Views; @@ -31,16 +33,21 @@ namespace Aaru.Gui.ViewModels { readonly IAssetLoader _assets; readonly DevicesRootModel _devicesRoot; + readonly Bitmap _ejectIcon; readonly Bitmap _genericFolderIcon; readonly Bitmap _genericHddIcon; readonly Bitmap _genericOpticalIcon; readonly Bitmap _genericTapeIcon; readonly ImagesRootModel _imagesRoot; - readonly MainWindow _view; - ConsoleWindow _consoleWindow; - public object _contentPanel; - bool _devicesSupported; - public object _treeViewSelectedItem; + readonly Bitmap _removableIcon; + readonly Bitmap _sdIcon; + + readonly Bitmap _usbIcon; + readonly MainWindow _view; + ConsoleWindow _consoleWindow; + object _contentPanel; + bool _devicesSupported; + object _treeViewSelectedItem; public MainWindowViewModel(MainWindow view) { @@ -59,6 +66,7 @@ namespace Aaru.Gui.ViewModels CreateSidecarCommand = ReactiveCommand.Create(ExecuteCreateSidecarCommand); ViewImageSectorsCommand = ReactiveCommand.Create(ExecuteViewImageSectorsCommand); DecodeImageMediaTagsCommand = ReactiveCommand.Create(ExecuteDecodeImageMediaTagsCommand); + RefreshDevicesCommand = ReactiveCommand.Create(ExecuteRefreshDevicesCommand); _view = view; TreeRoot = new ObservableCollection(); _assets = AvaloniaLocator.Current.GetService(); @@ -98,6 +106,21 @@ namespace Aaru.Gui.ViewModels _genericFolderIcon = new Bitmap(_assets.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/inode-directory.png"))); + + _usbIcon = + new + Bitmap(_assets.Open(new + Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media-usb.png"))); + + _removableIcon = + new + Bitmap(_assets.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media.png"))); + + _sdIcon = + new Bitmap(_assets.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-flash-sd-mmc.png"))); + + _ejectIcon = + new Bitmap(_assets.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-eject.png"))); } public bool DevicesSupported @@ -127,6 +150,7 @@ namespace Aaru.Gui.ViewModels public ReactiveCommand CreateSidecarCommand { get; } public ReactiveCommand ViewImageSectorsCommand { get; } public ReactiveCommand DecodeImageMediaTagsCommand { get; } + public ReactiveCommand RefreshDevicesCommand { get; } public object ContentPanel { @@ -282,21 +306,21 @@ namespace Aaru.Gui.ViewModels dialog.ShowDialog(_view); } - internal void ExecuteEncodingsCommand() + void ExecuteEncodingsCommand() { var dialog = new EncodingsDialog(); dialog.DataContext = new EncodingsDialogViewModel(dialog); dialog.ShowDialog(_view); } - internal void ExecutePluginsCommand() + void ExecutePluginsCommand() { var dialog = new PluginsDialog(); dialog.DataContext = new PluginsDialogViewModel(dialog); dialog.ShowDialog(_view); } - internal void ExecuteStatisticsCommand() + void ExecuteStatisticsCommand() { using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); @@ -328,7 +352,7 @@ namespace Aaru.Gui.ViewModels internal void ExecuteExitCommand() => (Application.Current.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown(); - internal void ExecuteConsoleCommand() + void ExecuteConsoleCommand() { if(_consoleWindow is null) { @@ -407,12 +431,10 @@ namespace Aaru.Gui.ViewModels Filter = inputFilter }; - // TODO: pnlImageInfo - List partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); - bool checkraw = false; + bool checkRaw = false; List idPlugins; IFilesystem plugin; PluginBase plugins = GetPluginBase.Instance; @@ -421,7 +443,7 @@ namespace Aaru.Gui.ViewModels { AaruConsole.DebugWriteLine("Analyze command", "No partitions found"); - checkraw = true; + checkRaw = true; } else { @@ -438,7 +460,6 @@ namespace Aaru.Gui.ViewModels foreach(Partition partition in partitions. Where(p => p.Scheme == scheme).OrderBy(p => p.Start)) { - // TODO: pnlPartition var partitionModel = new PartitionModel { // TODO: Add icons to partition types @@ -505,7 +526,7 @@ namespace Aaru.Gui.ViewModels } } - if(checkraw) + if(checkRaw) { var wholePart = new Partition { @@ -589,5 +610,98 @@ namespace Aaru.Gui.ViewModels Statistics.AddCommand("image-info"); } + + internal void LoadComplete() => RefreshDevices(); + + void ExecuteRefreshDevicesCommand() => RefreshDevices(); + + void RefreshDevices() + { + if(!DevicesSupported) + return; + + try + { + AaruConsole.WriteLine("Refreshing devices"); + _devicesRoot.Devices.Clear(); + + foreach(DeviceInfo device in Device.ListDevices().Where(d => d.Supported).OrderBy(d => d.Vendor). + ThenBy(d => d.Model)) + { + AaruConsole.DebugWriteLine("Main window", + "Found supported device model {0} by manufacturer {1} on bus {2} and path {3}", + device.Model, device.Vendor, device.Bus, device.Path); + + var deviceModel = new DeviceModel + { + Icon = _genericHddIcon, Name = $"{device.Vendor} {device.Model} ({device.Bus})", + Path = device.Path + }; + + try + { + var dev = new Device(device.Path); + + if(dev.IsRemote) + Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, + dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + + switch(dev.Type) + { + case DeviceType.ATAPI: + case DeviceType.SCSI: + switch(dev.ScsiType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.SCSIZonedBlockDevice: + case PeripheralDeviceTypes.SimplifiedDevice: + deviceModel.Icon = dev.IsRemovable ? dev.IsUsb + ? _usbIcon + : _removableIcon : _genericHddIcon; + + break; + case PeripheralDeviceTypes.SequentialAccess: + deviceModel.Icon = _genericTapeIcon; + + break; + case PeripheralDeviceTypes.OpticalDevice: + case PeripheralDeviceTypes.WriteOnceDevice: + case PeripheralDeviceTypes.OCRWDevice: + deviceModel.Icon = _removableIcon; + + break; + case PeripheralDeviceTypes.MultiMediaDevice: + deviceModel.Icon = _genericOpticalIcon; + + break; + } + + break; + case DeviceType.SecureDigital: + case DeviceType.MMC: + deviceModel.Icon = _sdIcon; + + break; + case DeviceType.NVMe: + deviceModel.Icon = null; + + break; + } + + dev.Close(); + } + catch + { + // ignored + } + + _devicesRoot.Devices.Add(deviceModel); + } + } + catch(InvalidOperationException ex) + { + AaruConsole.ErrorWriteLine(ex.Message); + } + } } } \ No newline at end of file diff --git a/Aaru.Gui/Views/MainWindow.xaml b/Aaru.Gui/Views/MainWindow.xaml index 0d858d4fe..1a410fc56 100644 --- a/Aaru.Gui/Views/MainWindow.xaml +++ b/Aaru.Gui/Views/MainWindow.xaml @@ -17,7 +17,7 @@ - + @@ -39,12 +39,22 @@ + + + + + + + + + + @@ -54,27 +64,15 @@ - - - - - - - + + + + + + + @@ -105,6 +103,12 @@ + + + + + + diff --git a/Aaru.Gui/Views/MainWindow.xaml.cs b/Aaru.Gui/Views/MainWindow.xaml.cs index d2a805eeb..75dd4bf9a 100644 --- a/Aaru.Gui/Views/MainWindow.xaml.cs +++ b/Aaru.Gui/Views/MainWindow.xaml.cs @@ -1,4 +1,6 @@ -using Avalonia; +using System; +using Aaru.Gui.ViewModels; +using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -9,14 +11,18 @@ namespace Aaru.Gui.Views public MainWindow() { InitializeComponent(); -#if DEBUG + #if DEBUG this.AttachDevTools(); -#endif + #endif } - private void InitializeComponent() + void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + protected override void OnOpened(EventArgs e) { - AvaloniaXamlLoader.Load(this); + base.OnOpened(e); + + (DataContext as MainWindowViewModel)?.LoadComplete(); } } -} +} \ No newline at end of file