From 8bffe8c323ec9a98fad7de0aec3b4931d900251b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 25 Oct 2025 14:38:04 +0100 Subject: [PATCH] [GUI] Restart with a simpler main window. --- Aaru.Gui/App.xaml.cs | 12 +- .../ViewModels/Windows/MainWindowViewModel.cs | 834 ++--------------- .../Windows/OldMainWindowViewModel.cs | 873 ++++++++++++++++++ Aaru.Gui/Views/Windows/MainWindow.axaml | 80 ++ Aaru.Gui/Views/Windows/MainWindow.axaml.cs | 11 + .../{MainWindow.xaml => OldMainWindow.xaml} | 4 +- ...inWindow.xaml.cs => OldMainWindow.xaml.cs} | 6 +- 7 files changed, 1038 insertions(+), 782 deletions(-) create mode 100644 Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs create mode 100644 Aaru.Gui/Views/Windows/MainWindow.axaml create mode 100644 Aaru.Gui/Views/Windows/MainWindow.axaml.cs rename Aaru.Gui/Views/Windows/{MainWindow.xaml => OldMainWindow.xaml} (99%) rename Aaru.Gui/Views/Windows/{MainWindow.xaml.cs => OldMainWindow.xaml.cs} (93%) diff --git a/Aaru.Gui/App.xaml.cs b/Aaru.Gui/App.xaml.cs index 1c115e0ab..12efceed1 100644 --- a/Aaru.Gui/App.xaml.cs +++ b/Aaru.Gui/App.xaml.cs @@ -84,9 +84,9 @@ public sealed class App : Application { if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime { - MainWindow: MainWindow + MainWindow: OldMainWindow { - DataContext: MainWindowViewModel mainWindowViewModel + DataContext: OldMainWindowViewModel mainWindowViewModel } }) return; @@ -98,9 +98,9 @@ public sealed class App : Application { if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime { - MainWindow: MainWindow + MainWindow: OldMainWindow { - DataContext: MainWindowViewModel mainWindowViewModel + DataContext: OldMainWindowViewModel mainWindowViewModel } }) return; @@ -112,9 +112,9 @@ public sealed class App : Application { if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime { - MainWindow: MainWindow + MainWindow: OldMainWindow { - DataContext: MainWindowViewModel mainWindowViewModel + DataContext: OldMainWindowViewModel mainWindowViewModel } }) return; diff --git a/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs b/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs index f2fd3674e..8d18e6856 100644 --- a/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs @@ -1,175 +1,77 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : MainWindowViewModel.cs -// Author(s) : Natalia Portillo -// -// Component : GUI view models. -// -// --[ Description ] ---------------------------------------------------------- -// -// View model and code for the main window. -// -// --[ License ] -------------------------------------------------------------- -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General public License for more details. -// -// You should have received a copy of the GNU General public License -// along with this program. If not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2025 Natalia Portillo -// ****************************************************************************/ - -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Interop; -using Aaru.CommonTypes.Structs.Devices.SCSI; -using Aaru.Core; -using Aaru.Core.Media.Info; using Aaru.Database; -using Aaru.Devices; using Aaru.Gui.Models; using Aaru.Gui.ViewModels.Dialogs; -using Aaru.Gui.ViewModels.Panels; using Aaru.Gui.Views.Dialogs; -using Aaru.Gui.Views.Panels; -using Aaru.Gui.Views.Windows; using Aaru.Localization; -using Aaru.Logging; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using JetBrains.Annotations; using MsBox.Avalonia; -using MsBox.Avalonia.Enums; -using Spectre.Console; using Console = Aaru.Gui.Views.Dialogs.Console; -using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo; -using ImageInfo = Aaru.Gui.Views.Panels.ImageInfo; -using Partition = Aaru.Gui.Views.Panels.Partition; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; namespace Aaru.Gui.ViewModels.Windows; -public sealed class MainWindowViewModel : ViewModelBase +public partial class MainWindowViewModel : ViewModelBase { - const string MODULE_NAME = "Main Window ViewModel"; - readonly DevicesRootModel _devicesRoot; - readonly Bitmap _ejectIcon; - readonly Bitmap _genericFolderIcon; - readonly Bitmap _genericHddIcon; - readonly Bitmap _genericOpticalIcon; - readonly Bitmap _genericTapeIcon; - readonly ImagesRootModel _imagesRoot; - readonly Bitmap _removableIcon; - readonly Bitmap _sdIcon; - readonly Bitmap _usbIcon; - readonly MainWindow _view; - Console _console; - object _contentPanel; - bool _devicesSupported; - object _treeViewSelectedItem; + readonly Window _view; + Console _console; + [ObservableProperty] + object _contentPanel; + [ObservableProperty] + bool _devicesSupported; + [ObservableProperty] + ObservableCollection _treeRoot; + object _treeViewSelectedItem; - public MainWindowViewModel(MainWindow view) + + public MainWindowViewModel(Window view) { - AboutCommand = new RelayCommand(About); - EncodingsCommand = new RelayCommand(Encodings); - PluginsCommand = new RelayCommand(Plugins); - StatisticsCommand = new RelayCommand(Statistics); - ExitCommand = new RelayCommand(Exit); - SettingsCommand = new AsyncRelayCommand(SettingsAsync); - ConsoleCommand = new RelayCommand(Console); - OpenCommand = new AsyncRelayCommand(OpenAsync); - CalculateEntropyCommand = new RelayCommand(CalculateEntropy); - VerifyImageCommand = new RelayCommand(VerifyImage); - ChecksumImageCommand = new RelayCommand(ChecksumImage); - ConvertImageCommand = new RelayCommand(ConvertImage); - CreateSidecarCommand = new RelayCommand(CreateSidecar); - ViewImageSectorsCommand = new RelayCommand(ViewImageSectors); - DecodeImageMediaTagsCommand = new RelayCommand(DecodeImageMediaTags); - RefreshDevicesCommand = new RelayCommand(RefreshDevices); - _view = view; - TreeRoot = []; - ContentPanel = Greeting; - - _imagesRoot = new ImagesRootModel - { - Name = UI.Title_Images - }; - - TreeRoot.Add(_imagesRoot); + AboutCommand = new AsyncRelayCommand(AboutAsync); + EncodingsCommand = new AsyncRelayCommand(EncodingsAsync); + PluginsCommand = new AsyncRelayCommand(PluginsAsync); + StatisticsCommand = new AsyncRelayCommand(StatisticsAsync); + ExitCommand = new RelayCommand(Exit); + SettingsCommand = new AsyncRelayCommand(SettingsAsync); + ConsoleCommand = new RelayCommand(Console); + OpenCommand = new AsyncRelayCommand(OpenAsync); switch(DetectOS.GetRealPlatformID()) { case PlatformID.Win32NT: case PlatformID.Linux: case PlatformID.FreeBSD: - _devicesRoot = new DevicesRootModel - { - Name = UI.Title_Devices - }; - - TreeRoot.Add(_devicesRoot); DevicesSupported = true; break; } - _genericHddIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-harddisk.png"))); + TreeRoot = + [ + new RootModel + { + Name = "Nothing opened." + } + ]; - _genericOpticalIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-optical.png"))); - - _genericTapeIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-tape.png"))); - - _genericFolderIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/inode-directory.png"))); - - _usbIcon = - new - Bitmap(AssetLoader.Open(new - Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media-usb.png"))); - - _removableIcon = - new - Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media.png"))); - - _sdIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-flash-sd-mmc.png"))); - - _ejectIcon = - new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-eject.png"))); + _view = view; } - public bool DevicesSupported - { - get => _devicesSupported; - set => SetProperty(ref _devicesSupported, value); - } + public ICommand OpenCommand { get; } + public ICommand SettingsCommand { get; } + public ICommand ExitCommand { get; } + public ICommand ConsoleCommand { get; } + public ICommand EncodingsCommand { get; } + public ICommand PluginsCommand { get; } + public ICommand StatisticsCommand { get; } + public ICommand AboutCommand { get; } public bool NativeMenuSupported { @@ -182,291 +84,44 @@ public sealed class MainWindowViewModel : ViewModelBase } } - [NotNull] - public string Greeting => UI.Welcome_to_Aaru; - - public ObservableCollection TreeRoot { get; } - public ICommand AboutCommand { get; } - public ICommand ConsoleCommand { get; } - public ICommand EncodingsCommand { get; } - public ICommand PluginsCommand { get; } - public ICommand StatisticsCommand { get; } - public ICommand ExitCommand { get; } - public ICommand SettingsCommand { get; } - public ICommand OpenCommand { get; } - public ICommand CalculateEntropyCommand { get; } - public ICommand VerifyImageCommand { get; } - public ICommand ChecksumImageCommand { get; } - public ICommand ConvertImageCommand { get; } - public ICommand CreateSidecarCommand { get; } - public ICommand ViewImageSectorsCommand { get; } - public ICommand DecodeImageMediaTagsCommand { get; } - public ICommand RefreshDevicesCommand { get; } - - public object ContentPanel - { - get => _contentPanel; - set => SetProperty(ref _contentPanel, value); - } - public object TreeViewSelectedItem { get => _treeViewSelectedItem; - set - { - if(value == _treeViewSelectedItem) return; - - SetProperty(ref _treeViewSelectedItem, value); - - ContentPanel = null; - - switch(value) - { - case ImageModel imageModel: - ContentPanel = new ImageInfo - { - DataContext = imageModel.ViewModel - }; - - break; - case PartitionModel partitionModel: - ContentPanel = new Partition - { - DataContext = partitionModel.ViewModel - }; - - break; - case FileSystemModel fileSystemModel: - ContentPanel = new FileSystem - { - DataContext = fileSystemModel.ViewModel - }; - - break; - case SubdirectoryModel subdirectoryModel: - ContentPanel = new Subdirectory - { - DataContext = new SubdirectoryViewModel(subdirectoryModel, _view) - }; - - break; - case DeviceModel deviceModel: - { - if(deviceModel.ViewModel is null) - { - var dev = Device.Create(deviceModel.Path, out ErrorNumber devErrno); - - switch(dev) - { - case null: - ContentPanel = string.Format(UI.Error_0_opening_device, devErrno); - - return; - case Devices.Remote.Device remoteDev: - Core.Statistics.AddRemote(remoteDev.RemoteApplication, - remoteDev.RemoteVersion, - remoteDev.RemoteOperatingSystem, - remoteDev.RemoteOperatingSystemVersion, - remoteDev.RemoteArchitecture); - - break; - } - - if(dev.Error) - { - ContentPanel = string.Format(UI.Error_0_opening_device, dev.LastError); - - return; - } - - var devInfo = new DeviceInfo(dev); - - deviceModel.ViewModel = new DeviceInfoViewModel(devInfo, _view); - - if(!dev.IsRemovable) - { - deviceModel.Media.Add(new MediaModel - { - NonRemovable = true, - Name = UI.Non_removable_device_commands_not_yet_implemented - }); - } - else - { - // TODO: Removable non-SCSI? - var scsiInfo = new ScsiInfo(dev); - - if(!scsiInfo.MediaInserted) - { - deviceModel.Media.Add(new MediaModel - { - NoMediaInserted = true, - Icon = _ejectIcon, - Name = UI.No_media_inserted - }); - } - else - { - var mediaResource = - new Uri($"avares://Aaru.Gui/Assets/Logos/Media/{scsiInfo.MediaType}.png"); - - deviceModel.Media.Add(new MediaModel - { - DevicePath = deviceModel.Path, - Icon = AssetLoader.Exists(mediaResource) - ? new Bitmap(AssetLoader.Open(mediaResource)) - : null, - Name = $"{scsiInfo.MediaType}", - ViewModel = new MediaInfoViewModel(scsiInfo, deviceModel.Path, _view) - }); - } - } - - dev.Close(); - } - - ContentPanel = new Views.Panels.DeviceInfo - { - DataContext = deviceModel.ViewModel - }; - - break; - } - case MediaModel { NonRemovable: true }: - ContentPanel = UI.Non_removable_device_commands_not_yet_implemented; - - break; - case MediaModel { NoMediaInserted: true }: - ContentPanel = UI.No_media_inserted; - - break; - case MediaModel mediaModel: - { - if(mediaModel.ViewModel != null) - { - ContentPanel = new MediaInfo - { - DataContext = mediaModel.ViewModel - }; - } - - break; - } - } - } + set => SetProperty(ref _treeViewSelectedItem, value); } - void CalculateEntropy() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; + Task OpenAsync() => - var imageEntropyWindow = new ImageEntropy(); - imageEntropyWindow.DataContext = new ImageEntropyViewModel(imageModel.Image, imageEntropyWindow); + // TODO + null; - imageEntropyWindow.Closed += (_, _) => imageEntropyWindow = null; - - imageEntropyWindow.Show(); - } - - void VerifyImage() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - var imageVerifyWindow = new ImageVerify(); - imageVerifyWindow.DataContext = new ImageVerifyViewModel(imageModel.Image, imageVerifyWindow); - - imageVerifyWindow.Closed += (_, _) => imageVerifyWindow = null; - - imageVerifyWindow.Show(); - } - - void ChecksumImage() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - var imageChecksumWindow = new ImageChecksum(); - imageChecksumWindow.DataContext = new ImageChecksumViewModel(imageModel.Image, imageChecksumWindow); - - imageChecksumWindow.Closed += (_, _) => imageChecksumWindow = null; - - imageChecksumWindow.Show(); - } - - void ConvertImage() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - var imageConvertWindow = new ImageConvert(); - - imageConvertWindow.DataContext = - new ImageConvertViewModel(imageModel.Image, imageModel.Path, imageConvertWindow); - - imageConvertWindow.Closed += (_, _) => imageConvertWindow = null; - - imageConvertWindow.Show(); - } - - void CreateSidecar() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - var imageSidecarWindow = new ImageSidecar(); - - // TODO: Pass thru chosen default encoding - imageSidecarWindow.DataContext = - new ImageSidecarViewModel(imageModel.Image, - imageModel.Path, - imageModel.Filter.Id, - null, - imageSidecarWindow); - - imageSidecarWindow.Show(); - } - - void ViewImageSectors() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - new ViewSector - { - DataContext = new ViewSectorViewModel(imageModel.Image) - }.Show(); - } - - void DecodeImageMediaTags() - { - if(TreeViewSelectedItem is not ImageModel imageModel) return; - - new DecodeMediaTags - { - DataContext = new DecodeMediaTagsViewModel(imageModel.Image) - }.Show(); - } - - internal void About() + Task AboutAsync() { var dialog = new About(); dialog.DataContext = new AboutViewModel(dialog); - dialog.ShowDialog(_view); + + return dialog.ShowDialog(_view); } - void Encodings() + Task EncodingsAsync() { var dialog = new Encodings(); dialog.DataContext = new EncodingsViewModel(dialog); - dialog.ShowDialog(_view); + + return dialog.ShowDialog(_view); } - void Plugins() + Task PluginsAsync() { var dialog = new PluginsDialog(); dialog.DataContext = new PluginsViewModel(dialog); - dialog.ShowDialog(_view); + + return dialog.ShowDialog(_view); } - void Statistics() + async Task StatisticsAsync() { - using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); + await using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); if(!ctx.Commands.Any() && !ctx.Filesystems.Any() && @@ -476,26 +131,26 @@ public sealed class MainWindowViewModel : ViewModelBase !ctx.Partitions.Any() && !ctx.SeenDevices.Any()) { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Warning, UI.There_are_no_statistics) - .ShowWindowDialogAsync(_view); + await MessageBoxManager.GetMessageBoxStandard(UI.Title_Warning, UI.There_are_no_statistics) + .ShowWindowDialogAsync(_view); return; } var dialog = new StatisticsDialog(); dialog.DataContext = new StatisticsViewModel(dialog); - dialog.ShowDialog(_view); - } - - internal async Task SettingsAsync() - { - var dialog = new SettingsDialog(); - dialog.DataContext = new SettingsViewModel(dialog, false); await dialog.ShowDialog(_view); } - internal void Exit() => - (Application.Current?.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown(); + Task SettingsAsync() + { + var dialog = new SettingsDialog(); + dialog.DataContext = new SettingsViewModel(dialog, false); + + return dialog.ShowDialog(_view); + } + + void Exit() => (Application.Current?.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown(); void Console() { @@ -507,367 +162,4 @@ public sealed class MainWindowViewModel : ViewModelBase _console.Show(); } - - async Task OpenAsync() - { - // TODO: Extensions - IReadOnlyList result = await _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - Title = UI.Dialog_Choose_image_to_open, - AllowMultiple = false, - FileTypeFilter = new List - { - FilePickerFileTypes.All - } - }); - - if(result.Count != 1) return; - - IFilter inputFilter = PluginRegister.Singleton.GetFilter(result[0].Path.AbsolutePath); - - if(inputFilter == null) - { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, - UI.Cannot_open_specified_file, - ButtonEnum.Ok, - Icon.Error); - - return; - } - - try - { - if(ImageFormat.Detect(inputFilter) is not IMediaImage imageFormat) - { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, - UI.Image_format_not_identified, - ButtonEnum.Ok, - Icon.Error); - - return; - } - - AaruLogging.WriteLine(UI.Image_format_identified_by_0_1, Markup.Escape(imageFormat.Name), imageFormat.Id); - - try - { - ErrorNumber opened = imageFormat.Open(inputFilter); - - if(opened != ErrorNumber.NoError) - { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, - string.Format(UI.Error_0_opening_image_format, opened), - ButtonEnum.Ok, - Icon.Error); - - AaruLogging.Error(UI.Unable_to_open_image_format); - AaruLogging.Error(UI.No_error_given); - - return; - } - - var mediaResource = new Uri($"avares://Aaru.Gui/Assets/Logos/Media/{imageFormat.Info.MediaType}.png"); - - var imageModel = new ImageModel - { - Path = result[0].Path.AbsolutePath, - Icon = AssetLoader.Exists(mediaResource) - ? new Bitmap(AssetLoader.Open(mediaResource)) - : imageFormat.Info.MetadataMediaType == MetadataMediaType.BlockMedia - ? _genericHddIcon - : imageFormat.Info.MetadataMediaType == MetadataMediaType.OpticalDisc - ? _genericOpticalIcon - : _genericFolderIcon, - FileName = Path.GetFileName(result[0].Path.AbsolutePath), - Image = imageFormat, - ViewModel = new ImageInfoViewModel(result[0].Path.AbsolutePath, inputFilter, imageFormat, _view), - Filter = inputFilter - }; - - List partitions = Core.Partitions.GetAll(imageFormat); - Core.Partitions.AddSchemesToStats(partitions); - - var checkRaw = false; - List idPlugins; - PluginRegister plugins = PluginRegister.Singleton; - - if(partitions.Count == 0) - { - AaruLogging.Debug(MODULE_NAME, UI.No_partitions_found); - - checkRaw = true; - } - else - { - AaruLogging.WriteLine(UI._0_partitions_found, partitions.Count); - - foreach(string scheme in partitions.Select(p => p.Scheme).Distinct().OrderBy(s => s)) - { - // TODO: Add icons to partition schemes - var schemeModel = new PartitionSchemeModel - { - Name = scheme - }; - - foreach(CommonTypes.Partition partition in partitions.Where(p => p.Scheme == scheme) - .OrderBy(p => p.Start)) - { - var partitionModel = new PartitionModel - { - // TODO: Add icons to partition types - Name = $"{partition.Name} ({partition.Type})", - Partition = partition, - ViewModel = new PartitionViewModel(partition) - }; - - AaruLogging.WriteLine(UI.Identifying_filesystems_on_partition); - - Core.Filesystems.Identify(imageFormat, out idPlugins, partition); - - if(idPlugins.Count == 0) - AaruLogging.WriteLine(UI.Filesystem_not_identified); - else - { - AaruLogging.WriteLine(string.Format(UI.Identified_by_0_plugins, idPlugins.Count)); - - foreach(string pluginName in idPlugins) - { - if(!plugins.Filesystems.TryGetValue(pluginName, out IFilesystem fs)) continue; - if(fs is null) continue; - - fs.GetInformation(imageFormat, - partition, - null, - out string information, - out CommonTypes.AaruMetadata.FileSystem fsMetadata); - - var rofs = fs as IReadOnlyFilesystem; - - if(rofs != null) - { - ErrorNumber error = rofs.Mount(imageFormat, - partition, - null, - new Dictionary(), - null); - - if(error != ErrorNumber.NoError) rofs = null; - } - - var filesystemModel = new FileSystemModel - { - VolumeName = rofs?.Metadata.VolumeName is null - ? fsMetadata.VolumeName is null - ? $"{fsMetadata.Type}" - : $"{fsMetadata.VolumeName} ({fsMetadata.Type})" - : $"{rofs.Metadata.VolumeName} ({rofs.Metadata.Type})", - Filesystem = fs, - ReadOnlyFilesystem = rofs, - ViewModel = new FileSystemViewModel(rofs?.Metadata ?? fsMetadata, information) - }; - - // TODO: Trap expanding item - if(rofs != null) - { - filesystemModel.Roots.Add(new SubdirectoryModel - { - Name = "/", - Path = "", - Plugin = rofs - }); - - Core.Statistics.AddCommand("ls"); - } - - Core.Statistics.AddFilesystem(rofs?.Metadata.Type ?? fsMetadata.Type); - partitionModel.FileSystems.Add(filesystemModel); - } - } - - schemeModel.Partitions.Add(partitionModel); - } - - imageModel.PartitionSchemesOrFileSystems.Add(schemeModel); - } - } - - if(checkRaw) - { - var wholePart = new CommonTypes.Partition - { - Name = Localization.Core.Whole_device, - Length = imageFormat.Info.Sectors, - Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize - }; - - Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); - - if(idPlugins.Count == 0) - AaruLogging.WriteLine(UI.Filesystem_not_identified); - else - { - AaruLogging.WriteLine(string.Format(UI.Identified_by_0_plugins, idPlugins.Count)); - - foreach(string pluginName in idPlugins) - { - if(!plugins.Filesystems.TryGetValue(pluginName, out IFilesystem fs)) continue; - if(fs is null) continue; - - fs.GetInformation(imageFormat, - wholePart, - null, - out string information, - out CommonTypes.AaruMetadata.FileSystem fsMetadata); - - var rofs = fs as IReadOnlyFilesystem; - - if(rofs != null) - { - ErrorNumber error = rofs.Mount(imageFormat, - wholePart, - null, - new Dictionary(), - null); - - if(error != ErrorNumber.NoError) rofs = null; - } - - var filesystemModel = new FileSystemModel - { - VolumeName = rofs?.Metadata.VolumeName is null - ? fsMetadata.VolumeName is null - ? $"{fsMetadata.Type}" - : $"{fsMetadata.VolumeName} ({fsMetadata.Type})" - : $"{rofs.Metadata.VolumeName} ({rofs.Metadata.Type})", - Filesystem = fs, - ReadOnlyFilesystem = rofs, - ViewModel = new FileSystemViewModel(rofs?.Metadata ?? fsMetadata, information) - }; - - // TODO: Trap expanding item - if(rofs != null) - { - filesystemModel.Roots.Add(new SubdirectoryModel - { - Name = "/", - Path = "", - Plugin = rofs - }); - - Core.Statistics.AddCommand("ls"); - } - - Core.Statistics.AddFilesystem(rofs?.Metadata.Type ?? fsMetadata.Type); - imageModel.PartitionSchemesOrFileSystems.Add(filesystemModel); - } - } - } - - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); - - _imagesRoot.Images.Add(imageModel); - } - catch(Exception ex) - { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, - UI.Unable_to_open_image_format, - ButtonEnum.Ok, - Icon.Error); - - AaruLogging.Error(UI.Unable_to_open_image_format); - AaruLogging.Error(Localization.Core.Error_0, ex.Message); - AaruLogging.Exception(ex, Localization.Core.Error_0, ex.Message); - } - } - catch(Exception ex) - { - MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, - UI.Exception_reading_file, - ButtonEnum.Ok, - Icon.Error); - - AaruLogging.Error(string.Format(UI.Error_reading_file_0, ex.Message)); - AaruLogging.Exception(ex, UI.Error_reading_file_0, ex.Message); - } - - Core.Statistics.AddCommand("image-info"); - } - - internal void LoadComplete() => RefreshDevices(); - - void RefreshDevices() - { - if(!DevicesSupported) return; - - try - { - AaruLogging.WriteLine(UI.Refreshing_devices); - _devicesRoot.Devices.Clear(); - - foreach(Devices.DeviceInfo device in Device.ListDevices() - .Where(d => d.Supported) - .OrderBy(d => d.Vendor) - .ThenBy(d => d.Model)) - { - AaruLogging.Debug(MODULE_NAME, - UI.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 - }; - - var dev = Device.Create(device.Path, out _); - - if(dev != null) - { - if(dev is Devices.Remote.Device remoteDev) - { - Core.Statistics.AddRemote(remoteDev.RemoteApplication, - remoteDev.RemoteVersion, - remoteDev.RemoteOperatingSystem, - remoteDev.RemoteOperatingSystemVersion, - remoteDev.RemoteArchitecture); - } - - deviceModel.Icon = dev.Type switch - { - DeviceType.ATAPI or DeviceType.SCSI => dev.ScsiType switch - { - PeripheralDeviceTypes.DirectAccess - or PeripheralDeviceTypes.SCSIZonedBlockDevice - or PeripheralDeviceTypes.SimplifiedDevice => dev.IsRemovable - ? dev.IsUsb ? _usbIcon : _removableIcon - : _genericHddIcon, - PeripheralDeviceTypes.SequentialAccess => _genericTapeIcon, - PeripheralDeviceTypes.OpticalDevice - or PeripheralDeviceTypes.WriteOnceDevice - or PeripheralDeviceTypes.OCRWDevice => _removableIcon, - PeripheralDeviceTypes.MultiMediaDevice => _genericOpticalIcon, - _ => deviceModel.Icon - }, - DeviceType.SecureDigital or DeviceType.MMC => _sdIcon, - DeviceType.NVMe => null, - _ => deviceModel.Icon - }; - - dev.Close(); - } - - _devicesRoot.Devices.Add(deviceModel); - } - } - catch(InvalidOperationException ex) - { - AaruLogging.Exception(ex, "Unhandled exception refreshing devices"); - } - } } \ No newline at end of file diff --git a/Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs b/Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs new file mode 100644 index 000000000..3f376e909 --- /dev/null +++ b/Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs @@ -0,0 +1,873 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MainWindowViewModel.cs +// Author(s) : Natalia Portillo +// +// Component : GUI view models. +// +// --[ Description ] ---------------------------------------------------------- +// +// View model and code for the main window. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General public License for more details. +// +// You should have received a copy of the GNU General public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2025 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Input; +using Aaru.CommonTypes; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Interop; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Core; +using Aaru.Core.Media.Info; +using Aaru.Database; +using Aaru.Devices; +using Aaru.Gui.Models; +using Aaru.Gui.ViewModels.Dialogs; +using Aaru.Gui.ViewModels.Panels; +using Aaru.Gui.Views.Dialogs; +using Aaru.Gui.Views.Panels; +using Aaru.Gui.Views.Windows; +using Aaru.Localization; +using Aaru.Logging; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using MsBox.Avalonia; +using MsBox.Avalonia.Enums; +using Spectre.Console; +using Console = Aaru.Gui.Views.Dialogs.Console; +using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo; +using ImageInfo = Aaru.Gui.Views.Panels.ImageInfo; +using Partition = Aaru.Gui.Views.Panels.Partition; +using PlatformID = Aaru.CommonTypes.Interop.PlatformID; + +namespace Aaru.Gui.ViewModels.Windows; + +public sealed class OldMainWindowViewModel : ViewModelBase +{ + const string MODULE_NAME = "Main Window ViewModel"; + readonly DevicesRootModel _devicesRoot; + readonly Bitmap _ejectIcon; + readonly Bitmap _genericFolderIcon; + readonly Bitmap _genericHddIcon; + readonly Bitmap _genericOpticalIcon; + readonly Bitmap _genericTapeIcon; + readonly ImagesRootModel _imagesRoot; + readonly Bitmap _removableIcon; + readonly Bitmap _sdIcon; + readonly Bitmap _usbIcon; + readonly OldMainWindow _view; + Console _console; + object _contentPanel; + bool _devicesSupported; + object _treeViewSelectedItem; + + public OldMainWindowViewModel(OldMainWindow view) + { + AboutCommand = new RelayCommand(About); + EncodingsCommand = new RelayCommand(Encodings); + PluginsCommand = new RelayCommand(Plugins); + StatisticsCommand = new RelayCommand(Statistics); + ExitCommand = new RelayCommand(Exit); + SettingsCommand = new AsyncRelayCommand(SettingsAsync); + ConsoleCommand = new RelayCommand(Console); + OpenCommand = new AsyncRelayCommand(OpenAsync); + CalculateEntropyCommand = new RelayCommand(CalculateEntropy); + VerifyImageCommand = new RelayCommand(VerifyImage); + ChecksumImageCommand = new RelayCommand(ChecksumImage); + ConvertImageCommand = new RelayCommand(ConvertImage); + CreateSidecarCommand = new RelayCommand(CreateSidecar); + ViewImageSectorsCommand = new RelayCommand(ViewImageSectors); + DecodeImageMediaTagsCommand = new RelayCommand(DecodeImageMediaTags); + RefreshDevicesCommand = new RelayCommand(RefreshDevices); + _view = view; + TreeRoot = []; + ContentPanel = Greeting; + + _imagesRoot = new ImagesRootModel + { + Name = UI.Title_Images + }; + + TreeRoot.Add(_imagesRoot); + + switch(DetectOS.GetRealPlatformID()) + { + case PlatformID.Win32NT: + case PlatformID.Linux: + case PlatformID.FreeBSD: + _devicesRoot = new DevicesRootModel + { + Name = UI.Title_Devices + }; + + TreeRoot.Add(_devicesRoot); + DevicesSupported = true; + + break; + } + + _genericHddIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-harddisk.png"))); + + _genericOpticalIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-optical.png"))); + + _genericTapeIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-tape.png"))); + + _genericFolderIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/inode-directory.png"))); + + _usbIcon = + new + Bitmap(AssetLoader.Open(new + Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media-usb.png"))); + + _removableIcon = + new + Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-removable-media.png"))); + + _sdIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-flash-sd-mmc.png"))); + + _ejectIcon = + new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/media-eject.png"))); + } + + public bool DevicesSupported + { + get => _devicesSupported; + set => SetProperty(ref _devicesSupported, value); + } + + public bool NativeMenuSupported + { + get + { + Window mainWindow = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime) + ?.MainWindow; + + return mainWindow is not null && NativeMenu.GetIsNativeMenuExported(mainWindow); + } + } + + [NotNull] + public string Greeting => UI.Welcome_to_Aaru; + + public ObservableCollection TreeRoot { get; } + public ICommand AboutCommand { get; } + public ICommand ConsoleCommand { get; } + public ICommand EncodingsCommand { get; } + public ICommand PluginsCommand { get; } + public ICommand StatisticsCommand { get; } + public ICommand ExitCommand { get; } + public ICommand SettingsCommand { get; } + public ICommand OpenCommand { get; } + public ICommand CalculateEntropyCommand { get; } + public ICommand VerifyImageCommand { get; } + public ICommand ChecksumImageCommand { get; } + public ICommand ConvertImageCommand { get; } + public ICommand CreateSidecarCommand { get; } + public ICommand ViewImageSectorsCommand { get; } + public ICommand DecodeImageMediaTagsCommand { get; } + public ICommand RefreshDevicesCommand { get; } + + public object ContentPanel + { + get => _contentPanel; + set => SetProperty(ref _contentPanel, value); + } + + public object TreeViewSelectedItem + { + get => _treeViewSelectedItem; + set + { + if(value == _treeViewSelectedItem) return; + + SetProperty(ref _treeViewSelectedItem, value); + + ContentPanel = null; + + switch(value) + { + case ImageModel imageModel: + ContentPanel = new ImageInfo + { + DataContext = imageModel.ViewModel + }; + + break; + case PartitionModel partitionModel: + ContentPanel = new Partition + { + DataContext = partitionModel.ViewModel + }; + + break; + case FileSystemModel fileSystemModel: + ContentPanel = new FileSystem + { + DataContext = fileSystemModel.ViewModel + }; + + break; + case SubdirectoryModel subdirectoryModel: + ContentPanel = new Subdirectory + { + DataContext = new SubdirectoryViewModel(subdirectoryModel, _view) + }; + + break; + case DeviceModel deviceModel: + { + if(deviceModel.ViewModel is null) + { + var dev = Device.Create(deviceModel.Path, out ErrorNumber devErrno); + + switch(dev) + { + case null: + ContentPanel = string.Format(UI.Error_0_opening_device, devErrno); + + return; + case Devices.Remote.Device remoteDev: + Core.Statistics.AddRemote(remoteDev.RemoteApplication, + remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, + remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); + + break; + } + + if(dev.Error) + { + ContentPanel = string.Format(UI.Error_0_opening_device, dev.LastError); + + return; + } + + var devInfo = new DeviceInfo(dev); + + deviceModel.ViewModel = new DeviceInfoViewModel(devInfo, _view); + + if(!dev.IsRemovable) + { + deviceModel.Media.Add(new MediaModel + { + NonRemovable = true, + Name = UI.Non_removable_device_commands_not_yet_implemented + }); + } + else + { + // TODO: Removable non-SCSI? + var scsiInfo = new ScsiInfo(dev); + + if(!scsiInfo.MediaInserted) + { + deviceModel.Media.Add(new MediaModel + { + NoMediaInserted = true, + Icon = _ejectIcon, + Name = UI.No_media_inserted + }); + } + else + { + var mediaResource = + new Uri($"avares://Aaru.Gui/Assets/Logos/Media/{scsiInfo.MediaType}.png"); + + deviceModel.Media.Add(new MediaModel + { + DevicePath = deviceModel.Path, + Icon = AssetLoader.Exists(mediaResource) + ? new Bitmap(AssetLoader.Open(mediaResource)) + : null, + Name = $"{scsiInfo.MediaType}", + ViewModel = new MediaInfoViewModel(scsiInfo, deviceModel.Path, _view) + }); + } + } + + dev.Close(); + } + + ContentPanel = new Views.Panels.DeviceInfo + { + DataContext = deviceModel.ViewModel + }; + + break; + } + case MediaModel { NonRemovable: true }: + ContentPanel = UI.Non_removable_device_commands_not_yet_implemented; + + break; + case MediaModel { NoMediaInserted: true }: + ContentPanel = UI.No_media_inserted; + + break; + case MediaModel mediaModel: + { + if(mediaModel.ViewModel != null) + { + ContentPanel = new MediaInfo + { + DataContext = mediaModel.ViewModel + }; + } + + break; + } + } + } + } + + void CalculateEntropy() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + var imageEntropyWindow = new ImageEntropy(); + imageEntropyWindow.DataContext = new ImageEntropyViewModel(imageModel.Image, imageEntropyWindow); + + imageEntropyWindow.Closed += (_, _) => imageEntropyWindow = null; + + imageEntropyWindow.Show(); + } + + void VerifyImage() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + var imageVerifyWindow = new ImageVerify(); + imageVerifyWindow.DataContext = new ImageVerifyViewModel(imageModel.Image, imageVerifyWindow); + + imageVerifyWindow.Closed += (_, _) => imageVerifyWindow = null; + + imageVerifyWindow.Show(); + } + + void ChecksumImage() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + var imageChecksumWindow = new ImageChecksum(); + imageChecksumWindow.DataContext = new ImageChecksumViewModel(imageModel.Image, imageChecksumWindow); + + imageChecksumWindow.Closed += (_, _) => imageChecksumWindow = null; + + imageChecksumWindow.Show(); + } + + void ConvertImage() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + var imageConvertWindow = new ImageConvert(); + + imageConvertWindow.DataContext = + new ImageConvertViewModel(imageModel.Image, imageModel.Path, imageConvertWindow); + + imageConvertWindow.Closed += (_, _) => imageConvertWindow = null; + + imageConvertWindow.Show(); + } + + void CreateSidecar() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + var imageSidecarWindow = new ImageSidecar(); + + // TODO: Pass thru chosen default encoding + imageSidecarWindow.DataContext = + new ImageSidecarViewModel(imageModel.Image, + imageModel.Path, + imageModel.Filter.Id, + null, + imageSidecarWindow); + + imageSidecarWindow.Show(); + } + + void ViewImageSectors() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + new ViewSector + { + DataContext = new ViewSectorViewModel(imageModel.Image) + }.Show(); + } + + void DecodeImageMediaTags() + { + if(TreeViewSelectedItem is not ImageModel imageModel) return; + + new DecodeMediaTags + { + DataContext = new DecodeMediaTagsViewModel(imageModel.Image) + }.Show(); + } + + internal void About() + { + var dialog = new About(); + dialog.DataContext = new AboutViewModel(dialog); + dialog.ShowDialog(_view); + } + + void Encodings() + { + var dialog = new Encodings(); + dialog.DataContext = new EncodingsViewModel(dialog); + dialog.ShowDialog(_view); + } + + void Plugins() + { + var dialog = new PluginsDialog(); + dialog.DataContext = new PluginsViewModel(dialog); + dialog.ShowDialog(_view); + } + + void Statistics() + { + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); + + if(!ctx.Commands.Any() && + !ctx.Filesystems.Any() && + !ctx.Filters.Any() && + !ctx.MediaFormats.Any() && + !ctx.Medias.Any() && + !ctx.Partitions.Any() && + !ctx.SeenDevices.Any()) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Warning, UI.There_are_no_statistics) + .ShowWindowDialogAsync(_view); + + return; + } + + var dialog = new StatisticsDialog(); + dialog.DataContext = new StatisticsViewModel(dialog); + dialog.ShowDialog(_view); + } + + internal async Task SettingsAsync() + { + var dialog = new SettingsDialog(); + dialog.DataContext = new SettingsViewModel(dialog, false); + await dialog.ShowDialog(_view); + } + + internal void Exit() => + (Application.Current?.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown(); + + void Console() + { + if(_console is null) + { + _console = new Console(); + _console.DataContext = new ConsoleViewModel(_console); + } + + _console.Show(); + } + + async Task OpenAsync() + { + // TODO: Extensions + IReadOnlyList result = await _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + Title = UI.Dialog_Choose_image_to_open, + AllowMultiple = false, + FileTypeFilter = new List + { + FilePickerFileTypes.All + } + }); + + if(result.Count != 1) return; + + IFilter inputFilter = PluginRegister.Singleton.GetFilter(result[0].Path.AbsolutePath); + + if(inputFilter == null) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, + UI.Cannot_open_specified_file, + ButtonEnum.Ok, + Icon.Error); + + return; + } + + try + { + if(ImageFormat.Detect(inputFilter) is not IMediaImage imageFormat) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, + UI.Image_format_not_identified, + ButtonEnum.Ok, + Icon.Error); + + return; + } + + AaruLogging.WriteLine(UI.Image_format_identified_by_0_1, Markup.Escape(imageFormat.Name), imageFormat.Id); + + try + { + ErrorNumber opened = imageFormat.Open(inputFilter); + + if(opened != ErrorNumber.NoError) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, + string.Format(UI.Error_0_opening_image_format, opened), + ButtonEnum.Ok, + Icon.Error); + + AaruLogging.Error(UI.Unable_to_open_image_format); + AaruLogging.Error(UI.No_error_given); + + return; + } + + var mediaResource = new Uri($"avares://Aaru.Gui/Assets/Logos/Media/{imageFormat.Info.MediaType}.png"); + + var imageModel = new ImageModel + { + Path = result[0].Path.AbsolutePath, + Icon = AssetLoader.Exists(mediaResource) + ? new Bitmap(AssetLoader.Open(mediaResource)) + : imageFormat.Info.MetadataMediaType == MetadataMediaType.BlockMedia + ? _genericHddIcon + : imageFormat.Info.MetadataMediaType == MetadataMediaType.OpticalDisc + ? _genericOpticalIcon + : _genericFolderIcon, + FileName = Path.GetFileName(result[0].Path.AbsolutePath), + Image = imageFormat, + ViewModel = new ImageInfoViewModel(result[0].Path.AbsolutePath, inputFilter, imageFormat, _view), + Filter = inputFilter + }; + + List partitions = Core.Partitions.GetAll(imageFormat); + Core.Partitions.AddSchemesToStats(partitions); + + var checkRaw = false; + List idPlugins; + PluginRegister plugins = PluginRegister.Singleton; + + if(partitions.Count == 0) + { + AaruLogging.Debug(MODULE_NAME, UI.No_partitions_found); + + checkRaw = true; + } + else + { + AaruLogging.WriteLine(UI._0_partitions_found, partitions.Count); + + foreach(string scheme in partitions.Select(p => p.Scheme).Distinct().OrderBy(s => s)) + { + // TODO: Add icons to partition schemes + var schemeModel = new PartitionSchemeModel + { + Name = scheme + }; + + foreach(CommonTypes.Partition partition in partitions.Where(p => p.Scheme == scheme) + .OrderBy(p => p.Start)) + { + var partitionModel = new PartitionModel + { + // TODO: Add icons to partition types + Name = $"{partition.Name} ({partition.Type})", + Partition = partition, + ViewModel = new PartitionViewModel(partition) + }; + + AaruLogging.WriteLine(UI.Identifying_filesystems_on_partition); + + Core.Filesystems.Identify(imageFormat, out idPlugins, partition); + + if(idPlugins.Count == 0) + AaruLogging.WriteLine(UI.Filesystem_not_identified); + else + { + AaruLogging.WriteLine(string.Format(UI.Identified_by_0_plugins, idPlugins.Count)); + + foreach(string pluginName in idPlugins) + { + if(!plugins.Filesystems.TryGetValue(pluginName, out IFilesystem fs)) continue; + if(fs is null) continue; + + fs.GetInformation(imageFormat, + partition, + null, + out string information, + out CommonTypes.AaruMetadata.FileSystem fsMetadata); + + var rofs = fs as IReadOnlyFilesystem; + + if(rofs != null) + { + ErrorNumber error = rofs.Mount(imageFormat, + partition, + null, + new Dictionary(), + null); + + if(error != ErrorNumber.NoError) rofs = null; + } + + var filesystemModel = new FileSystemModel + { + VolumeName = rofs?.Metadata.VolumeName is null + ? fsMetadata.VolumeName is null + ? $"{fsMetadata.Type}" + : $"{fsMetadata.VolumeName} ({fsMetadata.Type})" + : $"{rofs.Metadata.VolumeName} ({rofs.Metadata.Type})", + Filesystem = fs, + ReadOnlyFilesystem = rofs, + ViewModel = new FileSystemViewModel(rofs?.Metadata ?? fsMetadata, information) + }; + + // TODO: Trap expanding item + if(rofs != null) + { + filesystemModel.Roots.Add(new SubdirectoryModel + { + Name = "/", + Path = "", + Plugin = rofs + }); + + Core.Statistics.AddCommand("ls"); + } + + Core.Statistics.AddFilesystem(rofs?.Metadata.Type ?? fsMetadata.Type); + partitionModel.FileSystems.Add(filesystemModel); + } + } + + schemeModel.Partitions.Add(partitionModel); + } + + imageModel.PartitionSchemesOrFileSystems.Add(schemeModel); + } + } + + if(checkRaw) + { + var wholePart = new CommonTypes.Partition + { + Name = Localization.Core.Whole_device, + Length = imageFormat.Info.Sectors, + Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize + }; + + Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); + + if(idPlugins.Count == 0) + AaruLogging.WriteLine(UI.Filesystem_not_identified); + else + { + AaruLogging.WriteLine(string.Format(UI.Identified_by_0_plugins, idPlugins.Count)); + + foreach(string pluginName in idPlugins) + { + if(!plugins.Filesystems.TryGetValue(pluginName, out IFilesystem fs)) continue; + if(fs is null) continue; + + fs.GetInformation(imageFormat, + wholePart, + null, + out string information, + out CommonTypes.AaruMetadata.FileSystem fsMetadata); + + var rofs = fs as IReadOnlyFilesystem; + + if(rofs != null) + { + ErrorNumber error = rofs.Mount(imageFormat, + wholePart, + null, + new Dictionary(), + null); + + if(error != ErrorNumber.NoError) rofs = null; + } + + var filesystemModel = new FileSystemModel + { + VolumeName = rofs?.Metadata.VolumeName is null + ? fsMetadata.VolumeName is null + ? $"{fsMetadata.Type}" + : $"{fsMetadata.VolumeName} ({fsMetadata.Type})" + : $"{rofs.Metadata.VolumeName} ({rofs.Metadata.Type})", + Filesystem = fs, + ReadOnlyFilesystem = rofs, + ViewModel = new FileSystemViewModel(rofs?.Metadata ?? fsMetadata, information) + }; + + // TODO: Trap expanding item + if(rofs != null) + { + filesystemModel.Roots.Add(new SubdirectoryModel + { + Name = "/", + Path = "", + Plugin = rofs + }); + + Core.Statistics.AddCommand("ls"); + } + + Core.Statistics.AddFilesystem(rofs?.Metadata.Type ?? fsMetadata.Type); + imageModel.PartitionSchemesOrFileSystems.Add(filesystemModel); + } + } + } + + Core.Statistics.AddMediaFormat(imageFormat.Format); + Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); + Core.Statistics.AddFilter(inputFilter.Name); + + _imagesRoot.Images.Add(imageModel); + } + catch(Exception ex) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, + UI.Unable_to_open_image_format, + ButtonEnum.Ok, + Icon.Error); + + AaruLogging.Error(UI.Unable_to_open_image_format); + AaruLogging.Error(Localization.Core.Error_0, ex.Message); + AaruLogging.Exception(ex, Localization.Core.Error_0, ex.Message); + } + } + catch(Exception ex) + { + MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, + UI.Exception_reading_file, + ButtonEnum.Ok, + Icon.Error); + + AaruLogging.Error(string.Format(UI.Error_reading_file_0, ex.Message)); + AaruLogging.Exception(ex, UI.Error_reading_file_0, ex.Message); + } + + Core.Statistics.AddCommand("image-info"); + } + + internal void LoadComplete() => RefreshDevices(); + + void RefreshDevices() + { + if(!DevicesSupported) return; + + try + { + AaruLogging.WriteLine(UI.Refreshing_devices); + _devicesRoot.Devices.Clear(); + + foreach(Devices.DeviceInfo device in Device.ListDevices() + .Where(d => d.Supported) + .OrderBy(d => d.Vendor) + .ThenBy(d => d.Model)) + { + AaruLogging.Debug(MODULE_NAME, + UI.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 + }; + + var dev = Device.Create(device.Path, out _); + + if(dev != null) + { + if(dev is Devices.Remote.Device remoteDev) + { + Core.Statistics.AddRemote(remoteDev.RemoteApplication, + remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, + remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); + } + + deviceModel.Icon = dev.Type switch + { + DeviceType.ATAPI or DeviceType.SCSI => dev.ScsiType switch + { + PeripheralDeviceTypes.DirectAccess + or PeripheralDeviceTypes.SCSIZonedBlockDevice + or PeripheralDeviceTypes.SimplifiedDevice => dev.IsRemovable + ? dev.IsUsb ? _usbIcon : _removableIcon + : _genericHddIcon, + PeripheralDeviceTypes.SequentialAccess => _genericTapeIcon, + PeripheralDeviceTypes.OpticalDevice + or PeripheralDeviceTypes.WriteOnceDevice + or PeripheralDeviceTypes.OCRWDevice => _removableIcon, + PeripheralDeviceTypes.MultiMediaDevice => _genericOpticalIcon, + _ => deviceModel.Icon + }, + DeviceType.SecureDigital or DeviceType.MMC => _sdIcon, + DeviceType.NVMe => null, + _ => deviceModel.Icon + }; + + dev.Close(); + } + + _devicesRoot.Devices.Add(deviceModel); + } + } + catch(InvalidOperationException ex) + { + AaruLogging.Exception(ex, "Unhandled exception refreshing devices"); + } + } +} \ No newline at end of file diff --git a/Aaru.Gui/Views/Windows/MainWindow.axaml b/Aaru.Gui/Views/Windows/MainWindow.axaml new file mode 100644 index 000000000..4db4d78b5 --- /dev/null +++ b/Aaru.Gui/Views/Windows/MainWindow.axaml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Views/Windows/MainWindow.axaml.cs b/Aaru.Gui/Views/Windows/MainWindow.axaml.cs new file mode 100644 index 000000000..60a065b63 --- /dev/null +++ b/Aaru.Gui/Views/Windows/MainWindow.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace Aaru.Gui.Views.Windows; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Aaru.Gui/Views/Windows/MainWindow.xaml b/Aaru.Gui/Views/Windows/OldMainWindow.xaml similarity index 99% rename from Aaru.Gui/Views/Windows/MainWindow.xaml rename to Aaru.Gui/Views/Windows/OldMainWindow.xaml index 6095d2b34..87d82f486 100644 --- a/Aaru.Gui/Views/Windows/MainWindow.xaml +++ b/Aaru.Gui/Views/Windows/OldMainWindow.xaml @@ -41,11 +41,11 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Aaru.Gui.Views.Windows.MainWindow" + x:Class="Aaru.Gui.Views.Windows.OldMainWindow" Icon="/Assets/aaru-logo.png" Title="Aaru.Gui"> - + diff --git a/Aaru.Gui/Views/Windows/MainWindow.xaml.cs b/Aaru.Gui/Views/Windows/OldMainWindow.xaml.cs similarity index 93% rename from Aaru.Gui/Views/Windows/MainWindow.xaml.cs rename to Aaru.Gui/Views/Windows/OldMainWindow.xaml.cs index 7ad6693c2..d24eaa748 100644 --- a/Aaru.Gui/Views/Windows/MainWindow.xaml.cs +++ b/Aaru.Gui/Views/Windows/OldMainWindow.xaml.cs @@ -38,9 +38,9 @@ using Avalonia.Markup.Xaml; namespace Aaru.Gui.Views.Windows; -public sealed class MainWindow : Window +public sealed class OldMainWindow : Window { - public MainWindow() + public OldMainWindow() { InitializeComponent(); #if DEBUG @@ -54,6 +54,6 @@ public sealed class MainWindow : Window { base.OnOpened(e); - (DataContext as MainWindowViewModel)?.LoadComplete(); + (DataContext as OldMainWindowViewModel)?.LoadComplete(); } } \ No newline at end of file