#if !(NET20 || NET35 || NET40) using System; #endif using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Threading.Tasks; using BinaryObjectScanner; using MPF.Frontend.ComboBoxItems; using MPF.Frontend.Tools; using SabreTools.RedumpLib.Data; namespace MPF.Frontend.ViewModels { /// /// Constructor /// public class CheckDumpViewModel : INotifyPropertyChanged { #region Fields /// /// Access to the current options /// public Options Options { get => _options; } private readonly Options _options; /// /// Indicates if SelectionChanged events can be executed /// public bool CanExecuteSelectionChanged { get; private set; } = false; /// public event PropertyChangedEventHandler? PropertyChanged; #endregion #region Properties /// /// Currently selected system value /// public RedumpSystem? CurrentSystem { get => _currentSystem; set { _currentSystem = value; TriggerPropertyChanged(nameof(CurrentSystem)); } } private RedumpSystem? _currentSystem; /// /// Indicates the status of the system type combo box /// public bool SystemTypeComboBoxEnabled { get => _systemTypeComboBoxEnabled; set { _systemTypeComboBoxEnabled = value; TriggerPropertyChanged(nameof(SystemTypeComboBoxEnabled)); } } private bool _systemTypeComboBoxEnabled; /// /// Currently provided input path /// public string? InputPath { get => _inputPath; set { _inputPath = value; TriggerPropertyChanged(nameof(InputPath)); } } private string? _inputPath; /// /// Indicates the status of the input path text box /// public bool InputPathTextBoxEnabled { get => _inputPathTextBoxEnabled; set { _inputPathTextBoxEnabled = value; TriggerPropertyChanged(nameof(InputPathTextBoxEnabled)); } } private bool _inputPathTextBoxEnabled; /// /// Indicates the status of the input path browse button /// public bool InputPathBrowseButtonEnabled { get => _inputPathBrowseButtonEnabled; set { _inputPathBrowseButtonEnabled = value; TriggerPropertyChanged(nameof(InputPathBrowseButtonEnabled)); } } private bool _inputPathBrowseButtonEnabled; /// /// Currently selected dumping program /// public InternalProgram CurrentProgram { get => _currentProgram; set { _currentProgram = value; TriggerPropertyChanged(nameof(CurrentProgram)); } } private InternalProgram _currentProgram; /// /// Indicates the status of the dumping program combo box /// public bool DumpingProgramComboBoxEnabled { get => _dumpingProgramComboBoxEnabled; set { _dumpingProgramComboBoxEnabled = value; TriggerPropertyChanged(nameof(DumpingProgramComboBoxEnabled)); } } private bool _dumpingProgramComboBoxEnabled; /// /// Currently displayed status /// public string Status { get => _status; set { _status = value; TriggerPropertyChanged(nameof(Status)); TriggerPropertyChanged(nameof(StatusFirstLine)); } } private string _status; /// /// Currently displayed status trimmed to one line /// public string StatusFirstLine { get { if (string.IsNullOrEmpty(Status)) return string.Empty; var statusLines = Status.Split('\n'); if (statusLines.Length > 1) return statusLines[0] + " (...)"; return statusLines[0]; } } /// /// Indicates the status of the check dump button /// public bool CheckDumpButtonEnabled { get => _checkDumpButtonEnabled; set { _checkDumpButtonEnabled = value; TriggerPropertyChanged(nameof(CheckDumpButtonEnabled)); } } private bool _checkDumpButtonEnabled; /// /// Indicates the status of the cancel button /// public bool CancelButtonEnabled { get => _cancelButtonEnabled; set { _cancelButtonEnabled = value; TriggerPropertyChanged(nameof(CancelButtonEnabled)); } } private bool _cancelButtonEnabled; #endregion #region List Properties /// /// Current list of supported system profiles /// public List Systems { get => _systems; set { _systems = value; TriggerPropertyChanged(nameof(Systems)); } } private List _systems; /// /// List of available internal programs /// public List> InternalPrograms { get => _internalPrograms; set { _internalPrograms = value; TriggerPropertyChanged(nameof(InternalPrograms)); } } private List> _internalPrograms; #endregion /// /// Constructor for pure view model /// public CheckDumpViewModel() { _options = OptionsLoader.LoadFromConfig(); _internalPrograms = []; _inputPath = string.Empty; _systems = []; _status = string.Empty; SystemTypeComboBoxEnabled = true; InputPathTextBoxEnabled = true; InputPathBrowseButtonEnabled = true; DumpingProgramComboBoxEnabled = true; CheckDumpButtonEnabled = false; CancelButtonEnabled = true; Systems = RedumpSystemComboBoxItem.GenerateElements(); InternalPrograms = []; PopulateInternalPrograms(); EnableEventHandlers(); } #region Property Updates /// /// Trigger a property changed event /// private void TriggerPropertyChanged(string propertyName) { // Disable event handlers temporarily bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // If the property change event is initialized PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); // Reenable event handlers, if necessary if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); } #endregion #region UI Commands /// /// Change the currently selected system /// public void ChangeSystem() { CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } /// /// Change the currently selected dumping program /// public void ChangeDumpingProgram() { CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } /// /// Change the currently selected input path /// public void ChangeInputPath() { CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } #endregion #region UI Control /// /// Enables all UI elements that should be enabled /// private void EnableUIElements() { SystemTypeComboBoxEnabled = true; InputPathTextBoxEnabled = true; InputPathBrowseButtonEnabled = true; DumpingProgramComboBoxEnabled = true; CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); CancelButtonEnabled = true; } /// /// Disables all UI elements /// private void DisableUIElements() { SystemTypeComboBoxEnabled = false; InputPathTextBoxEnabled = false; InputPathBrowseButtonEnabled = false; DumpingProgramComboBoxEnabled = false; CheckDumpButtonEnabled = false; CancelButtonEnabled = false; } #endregion #region Population /// /// Populate media type according to system type /// private void PopulateInternalPrograms() { // Disable other UI updates bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // Get the current internal program InternalProgram internalProgram = Options.InternalProgram; // Create a static list of supported Check programs, not everything var internalPrograms = new List { InternalProgram.Redumper, InternalProgram.Aaru, InternalProgram.DiscImageCreator, // InternalProgram.Dreamdump, InternalProgram.CleanRip, InternalProgram.PS3CFW, InternalProgram.UmdImageCreator, InternalProgram.XboxBackupCreator }; InternalPrograms = internalPrograms.ConvertAll(ip => new Element(ip)); // Select the current default dumping program int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram); CurrentProgram = currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value; // Reenable event handlers, if necessary if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); } #endregion #region UI Functionality private bool ShouldEnableCheckDumpButton() { return CurrentSystem is not null && !string.IsNullOrEmpty(InputPath); } /// /// Enable all textbox and combobox event handlers /// private void EnableEventHandlers() { CanExecuteSelectionChanged = true; } /// /// Disable all textbox and combobox event handlers /// private void DisableEventHandlers() { CanExecuteSelectionChanged = false; } #endregion #region MPF.Check /// /// Performs MPF.Check functionality /// /// An error message if failed, otherwise string.Empty/null public async Task CheckDump(ProcessUserInfoDelegate processUserInfo) { if (string.IsNullOrEmpty(InputPath)) return ResultEventArgs.Failure("Invalid Input path"); if (!File.Exists(InputPath!.Trim('"'))) return ResultEventArgs.Failure("Input Path is not a valid file"); // Disable UI while Check is running DisableUIElements(); bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // Get progress indicators var resultProgress = new Progress(); resultProgress.ProgressChanged += ProgressUpdated; var protectionProgress = new Progress(); protectionProgress.ProgressChanged += ProgressUpdated; // Populate an environment var env = new DumpEnvironment(Options, Path.GetFullPath(InputPath.Trim('"')), null, CurrentSystem, CurrentProgram); env.SetProcessor(); // Finally, attempt to do the output dance var result = await env.VerifyAndSaveDumpOutput( resultProgress: resultProgress, protectionProgress: protectionProgress, processUserInfo: processUserInfo); // Reenable UI and event handlers, if necessary EnableUIElements(); if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); return result; } /// /// Handler for Result ProgressChanged event /// private void ProgressUpdated(object? sender, ResultEventArgs value) { Status = value?.Message ?? string.Empty; } /// /// Handler for ProtectionProgress ProgressChanged event /// private void ProgressUpdated(object? sender, ProtectionProgress value) { string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}"; Status = message; } #endregion } }