mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[GUI] Restart with a simpler main window.
This commit is contained in:
@@ -84,9 +84,9 @@ public sealed class App : Application
|
|||||||
{
|
{
|
||||||
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
||||||
{
|
{
|
||||||
MainWindow: MainWindow
|
MainWindow: OldMainWindow
|
||||||
{
|
{
|
||||||
DataContext: MainWindowViewModel mainWindowViewModel
|
DataContext: OldMainWindowViewModel mainWindowViewModel
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
@@ -98,9 +98,9 @@ public sealed class App : Application
|
|||||||
{
|
{
|
||||||
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
||||||
{
|
{
|
||||||
MainWindow: MainWindow
|
MainWindow: OldMainWindow
|
||||||
{
|
{
|
||||||
DataContext: MainWindowViewModel mainWindowViewModel
|
DataContext: OldMainWindowViewModel mainWindowViewModel
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
@@ -112,9 +112,9 @@ public sealed class App : Application
|
|||||||
{
|
{
|
||||||
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime
|
||||||
{
|
{
|
||||||
MainWindow: MainWindow
|
MainWindow: OldMainWindow
|
||||||
{
|
{
|
||||||
DataContext: MainWindowViewModel mainWindowViewModel
|
DataContext: OldMainWindowViewModel mainWindowViewModel
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,175 +1,77 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// Aaru Data Preservation Suite
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : MainWindowViewModel.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// 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 <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2025 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Aaru.CommonTypes;
|
|
||||||
using Aaru.CommonTypes.Enums;
|
|
||||||
using Aaru.CommonTypes.Interfaces;
|
|
||||||
using Aaru.CommonTypes.Interop;
|
using Aaru.CommonTypes.Interop;
|
||||||
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
|
||||||
using Aaru.Core;
|
|
||||||
using Aaru.Core.Media.Info;
|
|
||||||
using Aaru.Database;
|
using Aaru.Database;
|
||||||
using Aaru.Devices;
|
|
||||||
using Aaru.Gui.Models;
|
using Aaru.Gui.Models;
|
||||||
using Aaru.Gui.ViewModels.Dialogs;
|
using Aaru.Gui.ViewModels.Dialogs;
|
||||||
using Aaru.Gui.ViewModels.Panels;
|
|
||||||
using Aaru.Gui.Views.Dialogs;
|
using Aaru.Gui.Views.Dialogs;
|
||||||
using Aaru.Gui.Views.Panels;
|
|
||||||
using Aaru.Gui.Views.Windows;
|
|
||||||
using Aaru.Localization;
|
using Aaru.Localization;
|
||||||
using Aaru.Logging;
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Media.Imaging;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Avalonia.Platform;
|
|
||||||
using Avalonia.Platform.Storage;
|
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using MsBox.Avalonia;
|
using MsBox.Avalonia;
|
||||||
using MsBox.Avalonia.Enums;
|
|
||||||
using Spectre.Console;
|
|
||||||
using Console = Aaru.Gui.Views.Dialogs.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;
|
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
|
||||||
|
|
||||||
namespace Aaru.Gui.ViewModels.Windows;
|
namespace Aaru.Gui.ViewModels.Windows;
|
||||||
|
|
||||||
public sealed class MainWindowViewModel : ViewModelBase
|
public partial class MainWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
const string MODULE_NAME = "Main Window ViewModel";
|
readonly Window _view;
|
||||||
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;
|
Console _console;
|
||||||
|
[ObservableProperty]
|
||||||
object _contentPanel;
|
object _contentPanel;
|
||||||
|
[ObservableProperty]
|
||||||
bool _devicesSupported;
|
bool _devicesSupported;
|
||||||
|
[ObservableProperty]
|
||||||
|
ObservableCollection<RootModel> _treeRoot;
|
||||||
object _treeViewSelectedItem;
|
object _treeViewSelectedItem;
|
||||||
|
|
||||||
public MainWindowViewModel(MainWindow view)
|
|
||||||
|
public MainWindowViewModel(Window view)
|
||||||
{
|
{
|
||||||
AboutCommand = new RelayCommand(About);
|
AboutCommand = new AsyncRelayCommand(AboutAsync);
|
||||||
EncodingsCommand = new RelayCommand(Encodings);
|
EncodingsCommand = new AsyncRelayCommand(EncodingsAsync);
|
||||||
PluginsCommand = new RelayCommand(Plugins);
|
PluginsCommand = new AsyncRelayCommand(PluginsAsync);
|
||||||
StatisticsCommand = new RelayCommand(Statistics);
|
StatisticsCommand = new AsyncRelayCommand(StatisticsAsync);
|
||||||
ExitCommand = new RelayCommand(Exit);
|
ExitCommand = new RelayCommand(Exit);
|
||||||
SettingsCommand = new AsyncRelayCommand(SettingsAsync);
|
SettingsCommand = new AsyncRelayCommand(SettingsAsync);
|
||||||
ConsoleCommand = new RelayCommand(Console);
|
ConsoleCommand = new RelayCommand(Console);
|
||||||
OpenCommand = new AsyncRelayCommand(OpenAsync);
|
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())
|
switch(DetectOS.GetRealPlatformID())
|
||||||
{
|
{
|
||||||
case PlatformID.Win32NT:
|
case PlatformID.Win32NT:
|
||||||
case PlatformID.Linux:
|
case PlatformID.Linux:
|
||||||
case PlatformID.FreeBSD:
|
case PlatformID.FreeBSD:
|
||||||
_devicesRoot = new DevicesRootModel
|
|
||||||
{
|
|
||||||
Name = UI.Title_Devices
|
|
||||||
};
|
|
||||||
|
|
||||||
TreeRoot.Add(_devicesRoot);
|
|
||||||
DevicesSupported = true;
|
DevicesSupported = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_genericHddIcon =
|
TreeRoot =
|
||||||
new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-harddisk.png")));
|
[
|
||||||
|
new RootModel
|
||||||
_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;
|
Name = "Nothing opened."
|
||||||
set => SetProperty(ref _devicesSupported, value);
|
|
||||||
}
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
_view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
public bool NativeMenuSupported
|
||||||
{
|
{
|
||||||
@@ -182,291 +84,44 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NotNull]
|
|
||||||
public string Greeting => UI.Welcome_to_Aaru;
|
|
||||||
|
|
||||||
public ObservableCollection<RootModel> 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
|
public object TreeViewSelectedItem
|
||||||
{
|
{
|
||||||
get => _treeViewSelectedItem;
|
get => _treeViewSelectedItem;
|
||||||
set
|
set => SetProperty(ref _treeViewSelectedItem, value);
|
||||||
{
|
|
||||||
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)
|
Task OpenAsync() =>
|
||||||
{
|
|
||||||
ContentPanel = string.Format(UI.Error_0_opening_device, dev.LastError);
|
|
||||||
|
|
||||||
return;
|
// TODO
|
||||||
}
|
null;
|
||||||
|
|
||||||
var devInfo = new DeviceInfo(dev);
|
Task AboutAsync()
|
||||||
|
|
||||||
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();
|
var dialog = new About();
|
||||||
dialog.DataContext = new AboutViewModel(dialog);
|
dialog.DataContext = new AboutViewModel(dialog);
|
||||||
dialog.ShowDialog(_view);
|
|
||||||
|
return dialog.ShowDialog(_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Encodings()
|
Task EncodingsAsync()
|
||||||
{
|
{
|
||||||
var dialog = new Encodings();
|
var dialog = new Encodings();
|
||||||
dialog.DataContext = new EncodingsViewModel(dialog);
|
dialog.DataContext = new EncodingsViewModel(dialog);
|
||||||
dialog.ShowDialog(_view);
|
|
||||||
|
return dialog.ShowDialog(_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plugins()
|
Task PluginsAsync()
|
||||||
{
|
{
|
||||||
var dialog = new PluginsDialog();
|
var dialog = new PluginsDialog();
|
||||||
dialog.DataContext = new PluginsViewModel(dialog);
|
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() &&
|
if(!ctx.Commands.Any() &&
|
||||||
!ctx.Filesystems.Any() &&
|
!ctx.Filesystems.Any() &&
|
||||||
@@ -476,7 +131,7 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
!ctx.Partitions.Any() &&
|
!ctx.Partitions.Any() &&
|
||||||
!ctx.SeenDevices.Any())
|
!ctx.SeenDevices.Any())
|
||||||
{
|
{
|
||||||
MessageBoxManager.GetMessageBoxStandard(UI.Title_Warning, UI.There_are_no_statistics)
|
await MessageBoxManager.GetMessageBoxStandard(UI.Title_Warning, UI.There_are_no_statistics)
|
||||||
.ShowWindowDialogAsync(_view);
|
.ShowWindowDialogAsync(_view);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -484,18 +139,18 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
var dialog = new StatisticsDialog();
|
var dialog = new StatisticsDialog();
|
||||||
dialog.DataContext = new StatisticsViewModel(dialog);
|
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);
|
await dialog.ShowDialog(_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Exit() =>
|
Task SettingsAsync()
|
||||||
(Application.Current?.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
|
{
|
||||||
|
var dialog = new SettingsDialog();
|
||||||
|
dialog.DataContext = new SettingsViewModel(dialog, false);
|
||||||
|
|
||||||
|
return dialog.ShowDialog(_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exit() => (Application.Current?.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
|
||||||
|
|
||||||
void Console()
|
void Console()
|
||||||
{
|
{
|
||||||
@@ -507,367 +162,4 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
_console.Show();
|
_console.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task OpenAsync()
|
|
||||||
{
|
|
||||||
// TODO: Extensions
|
|
||||||
IReadOnlyList<IStorageFile> result = await _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
|
||||||
{
|
|
||||||
Title = UI.Dialog_Choose_image_to_open,
|
|
||||||
AllowMultiple = false,
|
|
||||||
FileTypeFilter = new List<FilePickerFileType>
|
|
||||||
{
|
|
||||||
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<CommonTypes.Partition> partitions = Core.Partitions.GetAll(imageFormat);
|
|
||||||
Core.Partitions.AddSchemesToStats(partitions);
|
|
||||||
|
|
||||||
var checkRaw = false;
|
|
||||||
List<string> 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<string, string>(),
|
|
||||||
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<string, string>(),
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
873
Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs
Normal file
873
Aaru.Gui/ViewModels/Windows/OldMainWindowViewModel.cs
Normal file
@@ -0,0 +1,873 @@
|
|||||||
|
// /***************************************************************************
|
||||||
|
// Aaru Data Preservation Suite
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Filename : MainWindowViewModel.cs
|
||||||
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// 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<RootModel> 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<IStorageFile> result = await _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
|
{
|
||||||
|
Title = UI.Dialog_Choose_image_to_open,
|
||||||
|
AllowMultiple = false,
|
||||||
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
|
{
|
||||||
|
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<CommonTypes.Partition> partitions = Core.Partitions.GetAll(imageFormat);
|
||||||
|
Core.Partitions.AddSchemesToStats(partitions);
|
||||||
|
|
||||||
|
var checkRaw = false;
|
||||||
|
List<string> 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<string, string>(),
|
||||||
|
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<string, string>(),
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
Aaru.Gui/Views/Windows/MainWindow.axaml
Normal file
80
Aaru.Gui/Views/Windows/MainWindow.axaml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:windows="clr-namespace:Aaru.Gui.ViewModels.Windows"
|
||||||
|
xmlns:models="clr-namespace:Aaru.Gui.Models"
|
||||||
|
xmlns:localization="clr-namespace:Aaru.Localization;assembly=Aaru.Localization"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
x:Class="Aaru.Gui.Views.Windows.MainWindow"
|
||||||
|
Icon="/Assets/aaru-logo.png"
|
||||||
|
Title="Aaru">
|
||||||
|
<Design.DataContext>
|
||||||
|
<windows:MainWindowViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<DockPanel>
|
||||||
|
<Menu DockPanel.Dock="Top">
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_File}">
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Open}"
|
||||||
|
Command="{Binding OpenCommand, Mode=OneWay}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Settings}"
|
||||||
|
IsVisible="{Binding !NativeMenuSupported, Mode=OneWay}"
|
||||||
|
Command="{Binding SettingsCommand, Mode=OneWay}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Exit}"
|
||||||
|
IsVisible="{Binding !NativeMenuSupported, Mode=OneWay}"
|
||||||
|
Command="{Binding ExitCommand, Mode=OneWay}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Devices}"
|
||||||
|
IsVisible="{Binding DevicesSupported, Mode=OneWay}">
|
||||||
|
<MenuItem Header="TODO" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Window}">
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Console}"
|
||||||
|
Command="{Binding ConsoleCommand, Mode=OneWay}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Help}">
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Encodings}"
|
||||||
|
Command="{Binding EncodingsCommand, Mode=OneWay}" />
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Plugins}"
|
||||||
|
Command="{Binding PluginsCommand, Mode=OneWay}" />
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_Statistics}"
|
||||||
|
Command="{Binding StatisticsCommand, Mode=OneWay}" />
|
||||||
|
<Separator IsVisible="{Binding !NativeMenuSupported, Mode=OneWay}" />
|
||||||
|
<MenuItem Header="{x:Static localization:UI.Menu_About}"
|
||||||
|
Name="AboutMenuItem"
|
||||||
|
IsVisible="{Binding !NativeMenuSupported, Mode=OneWay}"
|
||||||
|
Command="{Binding AboutCommand, Mode=OneWay}" />
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
<Grid ColumnDefinitions="*,5,6*">
|
||||||
|
<TreeView ItemsSource="{Binding TreeRoot, Mode=OneWay}"
|
||||||
|
SelectedItem="{Binding TreeViewSelectedItem, Mode=OneWay}"
|
||||||
|
BorderBrush="LightGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="4">
|
||||||
|
<TreeView.DataTemplates>
|
||||||
|
<DataTemplate DataType="models:RootModel">
|
||||||
|
<TextBlock Text="{Binding Name, Mode=OneWay}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</TreeView.DataTemplates>
|
||||||
|
</TreeView>
|
||||||
|
<GridSplitter Grid.Column="1"
|
||||||
|
Width="5"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Background="#555555" />
|
||||||
|
<ContentControl Grid.Column="2"
|
||||||
|
Content="{Binding ContentPanel, Mode=OneWay}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
BorderBrush="LightGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="4" />
|
||||||
|
</Grid>
|
||||||
|
</DockPanel>
|
||||||
|
</Window>
|
||||||
11
Aaru.Gui/Views/Windows/MainWindow.axaml.cs
Normal file
11
Aaru.Gui/Views/Windows/MainWindow.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Aaru.Gui.Views.Windows;
|
||||||
|
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,11 +41,11 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
x:Class="Aaru.Gui.Views.Windows.MainWindow"
|
x:Class="Aaru.Gui.Views.Windows.OldMainWindow"
|
||||||
Icon="/Assets/aaru-logo.png"
|
Icon="/Assets/aaru-logo.png"
|
||||||
Title="Aaru.Gui">
|
Title="Aaru.Gui">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<windows:MainWindowViewModel />
|
<windows:OldMainWindowViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Menu DockPanel.Dock="Top">
|
<Menu DockPanel.Dock="Top">
|
||||||
@@ -38,9 +38,9 @@ using Avalonia.Markup.Xaml;
|
|||||||
|
|
||||||
namespace Aaru.Gui.Views.Windows;
|
namespace Aaru.Gui.Views.Windows;
|
||||||
|
|
||||||
public sealed class MainWindow : Window
|
public sealed class OldMainWindow : Window
|
||||||
{
|
{
|
||||||
public MainWindow()
|
public OldMainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -54,6 +54,6 @@ public sealed class MainWindow : Window
|
|||||||
{
|
{
|
||||||
base.OnOpened(e);
|
base.OnOpened(e);
|
||||||
|
|
||||||
(DataContext as MainWindowViewModel)?.LoadComplete();
|
(DataContext as OldMainWindowViewModel)?.LoadComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user