Files
MPF/MPF.UI.Core/ViewModels/MainViewModel.cs

1762 lines
64 KiB
C#
Raw Normal View History

2022-04-11 10:32:03 -07:00
using System;
using System.Collections.Generic;
2023-10-08 20:52:29 -04:00
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
2022-04-11 10:32:03 -07:00
using BurnOutSharp;
2023-10-06 20:39:59 -04:00
using MPF.Core;
2023-10-08 20:52:29 -04:00
using MPF.Core.Converters;
2022-04-11 10:32:03 -07:00
using MPF.Core.Data;
using MPF.Core.Utilities;
2023-10-07 01:30:11 -04:00
using MPF.Core.UI.ComboBoxItems;
2023-09-05 00:08:09 -04:00
using SabreTools.RedumpLib.Data;
using WPFCustomMessageBox;
2023-09-25 21:39:28 -04:00
namespace MPF.UI.Core.ViewModels
{
2023-10-08 20:52:29 -04:00
public class MainViewModel : INotifyPropertyChanged
{
#region Fields
2023-09-25 21:29:55 -04:00
/// <summary>
/// Access to the current options
/// </summary>
public MPF.Core.Data.Options Options
{
get => _options;
set
{
_options = value;
OptionsLoader.SaveToConfig(_options);
}
}
2023-10-08 23:06:17 -04:00
private MPF.Core.Data.Options _options;
2023-09-25 21:29:55 -04:00
/// <summary>
2023-10-08 23:06:17 -04:00
/// Indicates if SelectionChanged events can be executed
/// </summary>
2023-10-08 23:06:17 -04:00
public bool CanExecuteSelectionChanged { get; private set; } = false;
/// <inheritdoc/>
public event PropertyChangedEventHandler PropertyChanged;
2023-09-25 21:29:55 -04:00
/// <summary>
/// Action to process logging statements
2023-09-25 21:29:55 -04:00
/// </summary>
private Action<LogLevel, string> _logger;
2023-09-25 21:29:55 -04:00
2023-10-08 23:06:17 -04:00
/// <summary>
/// Current dumping environment
/// </summary>
private DumpEnvironment _environment;
2023-10-08 20:52:29 -04:00
2023-10-08 23:15:24 -04:00
/// <summary>
/// Function to process user information
/// </summary>
private Func<SubmissionInfo, (bool?, SubmissionInfo)> _processUserInfo;
#endregion
2023-10-08 20:52:29 -04:00
#region Properties
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the options menu item
/// </summary>
public bool OptionsMenuItemEnabled
{
get => _optionsMenuItemEnabled;
set
{
_optionsMenuItemEnabled = value;
TriggerPropertyChanged("OptionsMenuItemEnabled");
}
}
private bool _optionsMenuItemEnabled;
/// <summary>
2023-10-08 20:52:29 -04:00
/// Currently selected system value
/// </summary>
2023-10-08 20:52:29 -04:00
public RedumpSystem? CurrentSystem
{
get => _currentSystem;
set
{
_currentSystem = value;
TriggerPropertyChanged("CurrentSystem");
}
}
private RedumpSystem? _currentSystem;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the system type combo box
/// </summary>
public bool SystemTypeComboBoxEnabled
{
get => _systemTypeComboBoxEnabled;
set
{
_systemTypeComboBoxEnabled = value;
TriggerPropertyChanged("SystemTypeComboBoxEnabled");
}
}
private bool _systemTypeComboBoxEnabled;
/// <summary>
2023-10-08 20:52:29 -04:00
/// Currently selected media type value
/// </summary>
2023-10-08 20:52:29 -04:00
public MediaType? CurrentMediaType
{
get => _currentMediaType;
set
{
_currentMediaType = value;
TriggerPropertyChanged("CurrentMediaType");
}
}
private MediaType? _currentMediaType;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the media type combo box
/// </summary>
public bool MediaTypeComboBoxEnabled
{
get => _mediaTypeComboBoxEnabled;
set
{
_mediaTypeComboBoxEnabled = value;
TriggerPropertyChanged("MediaTypeComboBoxEnabled");
}
}
private bool _mediaTypeComboBoxEnabled;
/// <summary>
2023-10-08 20:52:29 -04:00
/// Currently provided output path
/// </summary>
public string OutputPath
{
get => _outputPath;
set
{
_outputPath = value;
TriggerPropertyChanged("OutputPath");
}
}
private string _outputPath;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the output path text box
/// </summary>
public bool OutputPathTextBoxEnabled
{
get => _outputPathTextBoxEnabled;
set
{
_outputPathTextBoxEnabled = value;
TriggerPropertyChanged("OutputPathTextBoxEnabled");
}
}
private bool _outputPathTextBoxEnabled;
/// <summary>
/// Indicates the status of the output path browse button
/// </summary>
public bool OutputPathBrowseButtonEnabled
{
get => _outputPathBrowseButtonEnabled;
set
{
_outputPathBrowseButtonEnabled = value;
TriggerPropertyChanged("OutputPathBrowseButtonEnabled");
}
}
private bool _outputPathBrowseButtonEnabled;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Currently selected drive value
/// </summary>
2023-10-08 20:52:29 -04:00
public Drive CurrentDrive
{
get => _currentDrive;
set
{
_currentDrive = value;
TriggerPropertyChanged("CurrentDrive");
}
}
private Drive _currentDrive;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the drive combo box
/// </summary>
public bool DriveLetterComboBoxEnabled
{
get => _driveLetterComboBoxEnabled;
set
{
_driveLetterComboBoxEnabled = value;
TriggerPropertyChanged("DriveLetterComboBoxEnabled");
}
}
private bool _driveLetterComboBoxEnabled;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Currently selected drive speed value
/// </summary>
public int DriveSpeed
{
get => _driveSpeed;
set
{
_driveSpeed = value;
TriggerPropertyChanged("DriveSpeed");
}
}
private int _driveSpeed;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the drive speed combo box
/// </summary>
public bool DriveSpeedComboBoxEnabled
{
get => _driveSpeedComboBoxEnabled;
set
{
_driveSpeedComboBoxEnabled = value;
TriggerPropertyChanged("DriveSpeedComboBoxEnabled");
}
}
private bool _driveSpeedComboBoxEnabled;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Currently selected dumping program
/// </summary>
public InternalProgram CurrentProgram
{
get => _currentProgram;
set
{
_currentProgram = value;
TriggerPropertyChanged("CurrentProgram");
}
}
private InternalProgram _currentProgram;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the dumping program combo box
/// </summary>
public bool DumpingProgramComboBoxEnabled
{
get => _dumpingProgramComboBoxEnabled;
set
{
_dumpingProgramComboBoxEnabled = value;
TriggerPropertyChanged("DumpingProgramComboBoxEnabled");
}
}
private bool _dumpingProgramComboBoxEnabled;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Currently provided parameters
/// </summary>
public string Parameters
{
get => _parameters;
set
{
_parameters = value;
TriggerPropertyChanged("Parameters");
}
}
private string _parameters;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the parameters text box
/// </summary>
public bool ParametersCheckBoxEnabled
{
get => _parametersCheckBoxEnabled;
set
{
_parametersCheckBoxEnabled = value;
TriggerPropertyChanged("ParametersCheckBoxEnabled");
}
}
private bool _parametersCheckBoxEnabled;
/// <summary>
/// Indicates the status of the parameters check box
/// </summary>
public bool EnableParametersCheckBoxEnabled
{
get => _enableParametersCheckBoxEnabled;
set
{
_enableParametersCheckBoxEnabled = value;
TriggerPropertyChanged("EnableParametersCheckBoxEnabled");
}
}
private bool _enableParametersCheckBoxEnabled;
/// <summary>
/// Indicates the status of the start/stop button
/// </summary>
public bool StartStopButtonEnabled
{
get => _startStopButtonEnabled;
set
{
_startStopButtonEnabled = value;
TriggerPropertyChanged("StartStopButtonEnabled");
}
}
private bool _startStopButtonEnabled;
/// <summary>
/// Current value for the start/stop dumping button
/// </summary>
public object StartStopButtonText
{
get => _startStopButtonText;
set
{
_startStopButtonText = value as string;
TriggerPropertyChanged("StartStopButtonText");
}
}
private string _startStopButtonText;
/// <summary>
/// Indicates the status of the media scan button
/// </summary>
public bool MediaScanButtonEnabled
{
get => _mediaScanButtonEnabled;
set
{
_mediaScanButtonEnabled = value;
TriggerPropertyChanged("MediaScanButtonEnabled");
}
}
private bool _mediaScanButtonEnabled;
/// <summary>
/// Indicates the status of the update volume label button
/// </summary>
public bool UpdateVolumeLabelEnabled
{
get => _updateVolumeLabelEnabled;
set
{
_updateVolumeLabelEnabled = value;
TriggerPropertyChanged("UpdateVolumeLabelEnabled");
}
}
private bool _updateVolumeLabelEnabled;
/// <summary>
/// Indicates the status of the copy protect scan button
/// </summary>
public bool CopyProtectScanButtonEnabled
{
get => _copyProtectScanButtonEnabled;
set
{
_copyProtectScanButtonEnabled = value;
TriggerPropertyChanged("CopyProtectScanButtonEnabled");
}
}
private bool _copyProtectScanButtonEnabled;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Currently displayed status
/// </summary>
public string Status
{
get => _status;
set
{
_status = value;
TriggerPropertyChanged("Status");
}
}
private string _status;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Indicates the status of the log panel
/// </summary>
public bool LogPanelExpanded
{
get => _logPanelExpanded;
set
{
_logPanelExpanded = value;
TriggerPropertyChanged("LogPanelExpanded");
}
}
private bool _logPanelExpanded;
#endregion
2023-10-08 20:52:29 -04:00
#region List Properties
/// <summary>
2023-10-08 20:52:29 -04:00
/// Current list of drives
/// </summary>
2023-10-08 20:52:29 -04:00
public List<Drive> Drives
{
get => _drives;
set
{
_drives = value;
TriggerPropertyChanged("Drives");
}
}
private List<Drive> _drives;
2023-10-08 22:49:46 -04:00
/// <summary>
/// Current list of drive speeds
/// </summary>
public List<int> DriveSpeeds
{
get => _driveSpeeds;
set
{
_driveSpeeds = value;
TriggerPropertyChanged("DriveSpeeds");
}
}
private List<int> _driveSpeeds;
2023-10-08 20:52:29 -04:00
/// <summary>
/// Current list of supported media types
/// </summary>
public List<Element<MediaType>> MediaTypes
{
get => _mediaTypes;
set
{
_mediaTypes = value;
TriggerPropertyChanged("MediaTypes");
}
}
private List<Element<MediaType>> _mediaTypes;
/// <summary>
/// Current list of supported system profiles
/// </summary>
public List<RedumpSystemComboBoxItem> Systems
{
get => _systems;
set
{
_systems = value;
TriggerPropertyChanged("Systems");
}
}
private List<RedumpSystemComboBoxItem> _systems;
/// <summary>
/// List of available internal programs
/// </summary>
public List<Element<InternalProgram>> InternalPrograms
{
get => _internalPrograms;
set
{
_internalPrograms = value;
TriggerPropertyChanged("InternalPrograms");
}
}
private List<Element<InternalProgram>> _internalPrograms;
#endregion
2023-09-25 21:29:55 -04:00
/// <summary>
/// Generic constructor
/// </summary>
public MainViewModel()
{
_options = OptionsLoader.LoadFromConfig();
2023-10-08 22:49:46 -04:00
OptionsMenuItemEnabled = true;
SystemTypeComboBoxEnabled = true;
MediaTypeComboBoxEnabled = true;
DriveLetterComboBoxEnabled = true;
DumpingProgramComboBoxEnabled = true;
StartStopButtonEnabled = true;
StartStopButtonText = Interface.StartDumping;
MediaScanButtonEnabled = true;
LogPanelExpanded = _options.OpenLogWindowAtStartup;
2023-10-08 20:52:29 -04:00
MediaTypes = new List<Element<MediaType>>();
Systems = RedumpSystemComboBoxItem.GenerateElements().ToList();
InternalPrograms = new List<Element<InternalProgram>>();
2023-09-25 21:29:55 -04:00
}
/// <summary>
/// Initialize the main window after loading
/// </summary>
public void Init(Action<LogLevel, string> loggerAction, Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo)
{
// Set the callbacks
_logger = loggerAction;
2023-10-08 23:15:24 -04:00
_processUserInfo = processUserInfo;
// Finish initializing the rest of the values
2023-09-25 21:29:55 -04:00
InitializeUIValues(removeEventHandlers: false, rescanDrives: true);
// Check for updates, if necessary
2023-10-08 23:15:24 -04:00
if (Options.CheckForUpdatesOnStartup)
2023-09-25 21:21:51 -04:00
CheckForUpdates(showIfSame: false);
}
2023-10-08 20:52:29 -04:00
#region Property Updates
/// <summary>
/// Trigger a property changed event
/// </summary>
private void TriggerPropertyChanged(string propertyName)
{
// Disable event handlers temporarily
CanExecuteSelectionChanged = false;
// If the property change event is initialized
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
// Reenable event handlers
CanExecuteSelectionChanged = true;
}
#endregion
#region Population
/// <summary>
/// Get a complete list of active disc drives and fill the combo box
/// </summary>
/// <remarks>TODO: Find a way for this to periodically run, or have it hook to a "drive change" event</remarks>
2023-09-25 21:29:55 -04:00
private void PopulateDrives()
{
2023-10-08 20:52:29 -04:00
// Disable other UI updates
CanExecuteSelectionChanged = false;
VerboseLogLn("Scanning for drives..");
// Always enable the media scan
2023-10-08 22:49:46 -04:00
this.MediaScanButtonEnabled = true;
this.UpdateVolumeLabelEnabled = true;
// If we have a selected drive, keep track of it
2023-10-08 20:52:29 -04:00
char? lastSelectedDrive = this.CurrentDrive?.Letter;
// Populate the list of drives and add it to the combo box
2023-09-25 21:29:55 -04:00
Drives = Drive.CreateListOfDrives(this.Options.IgnoreFixedDrives);
2023-10-08 20:52:29 -04:00
if (Drives.Count > 0)
{
VerboseLogLn($"Found {Drives.Count} drives: {string.Join(", ", Drives.Select(d => d.Letter))}");
// Check for the last selected drive, if possible
int index = -1;
if (lastSelectedDrive != null)
index = Drives.FindIndex(d => d.MarkedActive && d.Letter == lastSelectedDrive);
// Check for active optical drives
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical);
// Check for active floppy drives
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy);
// Check for any active drives
if (index == -1)
index = Drives.FindIndex(d => d.MarkedActive);
// Set the selected index
2023-10-08 20:52:29 -04:00
CurrentDrive = (index != -1 ? Drives[index] : Drives[0]);
this.Status = "Valid drive found! Choose your Media Type";
2023-10-08 22:49:46 -04:00
this.CopyProtectScanButtonEnabled = true;
// Get the current system type
if (index != -1)
2023-09-25 21:29:55 -04:00
DetermineSystemType();
// Only enable the start/stop if we don't have the default selected
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = ShouldEnableDumpingButton();
}
else
{
VerboseLogLn("Found no drives");
2023-10-08 20:52:29 -04:00
this.CurrentDrive = null;
this.Status = "No valid drive found!";
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = false;
this.CopyProtectScanButtonEnabled = false;
}
2023-10-08 20:52:29 -04:00
// Reenable UI updates
CanExecuteSelectionChanged = true;
}
/// <summary>
/// Populate media type according to system type
/// </summary>
2023-09-25 21:16:43 -04:00
private void PopulateMediaType()
{
2023-10-08 20:52:29 -04:00
// Disable other UI updates
CanExecuteSelectionChanged = false;
2023-10-08 20:52:29 -04:00
if (this.CurrentSystem != null)
{
2023-10-08 20:52:29 -04:00
var mediaTypeValues = this.CurrentSystem.MediaTypes();
int index = mediaTypeValues.FindIndex(m => m == this.CurrentMediaType);
if (this.CurrentMediaType != null && index == -1)
VerboseLogLn($"Disc of type '{CurrentMediaType.LongName()}' found, but the current system does not support it!");
2023-10-08 20:52:29 -04:00
MediaTypes = Element<MediaType>.GenerateElements().Where(m => mediaTypeValues.Contains(m.Value)).ToList();
2023-10-08 22:49:46 -04:00
this.MediaTypeComboBoxEnabled = MediaTypes.Count > 1;
2023-10-08 20:52:29 -04:00
this.CurrentMediaType = (index > -1 ? MediaTypes[index] : MediaTypes[0]);
}
else
{
2023-10-08 22:49:46 -04:00
this.MediaTypeComboBoxEnabled = false;
this.MediaTypes = null;
this.CurrentMediaType = null;
}
2023-10-08 20:52:29 -04:00
// Reenable UI updates
CanExecuteSelectionChanged = true;
2023-10-08 22:49:46 -04:00
// Force an update of the media type
2023-10-08 20:52:29 -04:00
this.ChangeMediaType(null);
}
/// <summary>
/// Populate media type according to system type
/// </summary>
2023-09-25 21:29:55 -04:00
private void PopulateInternalPrograms()
{
2023-10-08 20:52:29 -04:00
// Disable other UI updates
CanExecuteSelectionChanged = false;
// Get the current internal program
2023-09-25 21:29:55 -04:00
InternalProgram internalProgram = this.Options.InternalProgram;
// Create a static list of supported programs, not everything
2023-09-07 10:36:33 -04:00
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.Redumper };
InternalPrograms = internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
// Select the current default dumping program
int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram);
2023-10-08 20:52:29 -04:00
this.CurrentProgram = (currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value);
// Reenable UI updates
CanExecuteSelectionChanged = true;
}
#endregion
#region UI Commands
/// <summary>
/// Change the currently selected dumping program
/// </summary>
2023-09-25 21:29:55 -04:00
public void ChangeDumpingProgram()
{
VerboseLogLn($"Changed dumping program to: {((InternalProgram?)this.CurrentProgram).LongName()}");
2023-09-25 21:29:55 -04:00
EnsureDiscInformation();
GetOutputNames(false);
}
/// <summary>
/// Change the currently selected media type
/// </summary>
2023-09-25 21:29:55 -04:00
public void ChangeMediaType(SelectionChangedEventArgs e)
{
// Only change the media type if the selection and not the list has changed
2023-10-08 20:52:29 -04:00
if (e == null || (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1))
{
2023-09-25 21:29:55 -04:00
SetSupportedDriveSpeed();
}
2023-09-25 21:29:55 -04:00
GetOutputNames(false);
EnsureDiscInformation();
}
/// <summary>
/// Change the currently selected system
/// </summary>
2023-09-25 21:29:55 -04:00
public void ChangeSystem()
{
VerboseLogLn($"Changed system to: {this.CurrentSystem.LongName()}");
2023-09-25 21:16:43 -04:00
PopulateMediaType();
2023-09-25 21:29:55 -04:00
GetOutputNames(false);
EnsureDiscInformation();
}
/// <summary>
/// Check for available updates
/// </summary>
2021-12-30 21:00:01 -08:00
/// <param name="showIfSame">True to show the box even if it's the same, false to only show if it's different</param>
2023-09-25 21:21:51 -04:00
public void CheckForUpdates(bool showIfSame)
{
(bool different, string message, string url) = Tools.CheckForNewVersion();
// If we have a new version, put it in the clipboard
if (different)
Clipboard.SetText(url);
SecretLogLn(message);
2021-09-28 11:46:37 -07:00
if (url == null)
message = "An exception occurred while checking for versions, please try again later. See the log window for more details.";
2021-12-30 21:00:01 -08:00
if (showIfSame || different)
2023-09-25 21:16:43 -04:00
CustomMessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information);
}
/// <summary>
/// Build a dummy SubmissionInfo and display it for testing
/// </summary>
2023-10-08 23:06:17 -04:00
public SubmissionInfo CreateDebugSubmissionInfo()
{
2023-10-08 23:06:17 -04:00
return new SubmissionInfo()
{
SchemaVersion = 1,
FullyMatchedID = 3,
PartiallyMatchedIDs = new List<int> { 0, 1, 2, 3 },
Added = DateTime.UtcNow,
LastModified = DateTime.UtcNow,
CommonDiscInfo = new CommonDiscInfoSection()
{
2023-10-08 20:52:29 -04:00
System = SabreTools.RedumpLib.Data.RedumpSystem.IBMPCcompatible,
Media = DiscType.BD128,
Title = "Game Title",
ForeignTitleNonLatin = "Foreign Game Title",
DiscNumberLetter = "1",
DiscTitle = "Install Disc",
Category = DiscCategory.Games,
Region = Region.World,
Languages = new Language?[] { Language.English, Language.Spanish, Language.French },
LanguageSelection = new LanguageSelection?[] { LanguageSelection.BiosSettings },
Serial = "Disc Serial",
Layer0MasteringRing = "L0 Mastering Ring",
Layer0MasteringSID = "L0 Mastering SID",
Layer0ToolstampMasteringCode = "L0 Toolstamp",
Layer0MouldSID = "L0 Mould SID",
Layer0AdditionalMould = "L0 Additional Mould",
Layer1MasteringRing = "L1 Mastering Ring",
Layer1MasteringSID = "L1 Mastering SID",
Layer1ToolstampMasteringCode = "L1 Toolstamp",
Layer1MouldSID = "L1 Mould SID",
Layer1AdditionalMould = "L1 Additional Mould",
Layer2MasteringRing = "L2 Mastering Ring",
Layer2MasteringSID = "L2 Mastering SID",
Layer2ToolstampMasteringCode = "L2 Toolstamp",
Layer3MasteringRing = "L3 Mastering Ring",
Layer3MasteringSID = "L3 Mastering SID",
Layer3ToolstampMasteringCode = "L3 Toolstamp",
RingWriteOffset = "+12",
Barcode = "UPC Barcode",
EXEDateBuildDate = "19xx-xx-xx",
ErrorsCount = "0",
Comments = "Comment data line 1\r\nComment data line 2",
2023-09-05 00:08:09 -04:00
#if NET48
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
2023-09-05 00:08:09 -04:00
#else
CommentsSpecialFields = new Dictionary<SiteCode, string>()
#endif
{
[SiteCode.ISBN] = "ISBN",
},
Contents = "Special contents 1\r\nSpecial contents 2",
2023-09-05 00:08:09 -04:00
#if NET48
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
2023-09-05 00:08:09 -04:00
#else
ContentsSpecialFields = new Dictionary<SiteCode, string>()
#endif
{
[SiteCode.PlayableDemos] = "Game Demo 1",
},
},
VersionAndEditions = new VersionAndEditionsSection()
{
Version = "Original",
VersionDatfile = "Alt",
CommonEditions = new string[] { "Taikenban" },
OtherEditions = "Rerelease",
},
EDC = new EDCSection()
{
EDC = YesNo.Yes,
},
ParentCloneRelationship = new ParentCloneRelationshipSection()
{
ParentID = "12345",
RegionalParent = false,
},
Extras = new ExtrasSection()
{
PVD = "PVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\nPVD with a stupidly long line and nothing else but a little more\n",
DiscKey = "Disc key",
DiscID = "Disc ID",
PIC = "PIC",
Header = "Header",
BCA = "BCA",
SecuritySectorRanges = "SSv1 Ranges",
},
CopyProtection = new CopyProtectionSection()
{
AntiModchip = YesNo.Yes,
LibCrypt = YesNo.No,
LibCryptData = "LibCrypt data",
Protection = "List of protections",
SecuROMData = "SecuROM data",
},
DumpersAndStatus = new DumpersAndStatusSection()
{
Status = DumpStatus.TwoOrMoreGreen,
Dumpers = new string[] { "Dumper1", "Dumper2" },
OtherDumpers = "Dumper3",
},
TracksAndWriteOffsets = new TracksAndWriteOffsetsSection()
{
ClrMameProData = "Datfile",
Cuesheet = "Cuesheet",
CommonWriteOffsets = new int[] { 0, 12, -12 },
OtherWriteOffsets = "-2",
},
SizeAndChecksums = new SizeAndChecksumsSection()
{
Layerbreak = 0,
Layerbreak2 = 1,
Layerbreak3 = 2,
Size = 12345,
CRC32 = "CRC32",
MD5 = "MD5",
SHA1 = "SHA1",
},
DumpingInfo = new DumpingInfoSection()
{
DumpingProgram = "DiscImageCreator 20500101",
DumpingDate = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"),
Manufacturer = "ATAPI",
Model = "Optical Drive",
Firmware = "1.23",
2022-10-19 12:34:40 -07:00
ReportedDiscType = "CD-R",
},
Artifacts = new Dictionary<string, string>()
{
["Sample Artifact"] = "Sample Data",
},
};
2023-10-08 23:06:17 -04:00
}
2023-10-08 23:06:17 -04:00
/// <summary>
/// Shutdown the current application
/// </summary>
public static void ExitApplication() => Application.Current.Shutdown();
/// <summary>
/// Show the About text popup
/// </summary>
public void ShowAboutText()
{
string aboutText = $"Media Preservation Frontend (MPF)"
+ $"{Environment.NewLine}"
+ $"{Environment.NewLine}A community preservation frontend developed in C#."
+ $"{Environment.NewLine}Supports Redumper, Aaru, and DiscImageCreator."
+ $"{Environment.NewLine}Originally created to help the Redump project."
+ $"{Environment.NewLine}"
+ $"{Environment.NewLine}Thanks to everyone who has supported this project!"
+ $"{Environment.NewLine}"
+ $"{Environment.NewLine}Version {Tools.GetCurrentVersion()}";
SecretLogLn(aboutText);
2023-10-08 23:06:17 -04:00
CustomMessageBox.Show(aboutText, "About", MessageBoxButton.OK, MessageBoxImage.Information);
}
/// <summary>
/// Toggle the Start/Stop button
/// </summary>
2023-09-25 21:29:55 -04:00
public async void ToggleStartStop()
{
// Dump or stop the dump
2023-10-08 22:49:46 -04:00
if (this.StartStopButtonText as string == Interface.StartDumping)
{
2023-09-25 21:29:55 -04:00
StartDumping();
}
2023-10-08 22:49:46 -04:00
else if (this.StartStopButtonText as string == Interface.StopDumping)
{
VerboseLogLn("Canceling dumping process...");
2023-10-08 23:06:17 -04:00
_environment.CancelDumping();
2023-10-08 22:49:46 -04:00
this.CopyProtectScanButtonEnabled = true;
2023-10-08 23:06:17 -04:00
if (_environment.Options.EjectAfterDump == true)
{
VerboseLogLn($"Ejecting disc in drive {_environment.Drive.Letter}");
2023-10-08 23:06:17 -04:00
await _environment.EjectDisc();
}
2023-09-25 21:29:55 -04:00
if (this.Options.DICResetDriveAfterDump)
{
VerboseLogLn($"Resetting drive {_environment.Drive.Letter}");
2023-10-08 23:06:17 -04:00
await _environment.ResetDrive();
}
}
}
/// <summary>
/// Update the internal options from a closed OptionsWindow
/// </summary>
/// <param name="savedSettings">Indicates if the settings were saved or not</param>
/// <param name="newOptions">Options representing the new, saved values</param>
public void UpdateOptions(bool savedSettings, MPF.Core.Data.Options newOptions)
{
if (savedSettings)
{
this.Options = new MPF.Core.Data.Options(newOptions);
2023-09-25 21:29:55 -04:00
InitializeUIValues(removeEventHandlers: true, rescanDrives: true);
}
}
#endregion
#region UI Functionality
/// <summary>
/// Performs UI value setup end to end
/// </summary>
/// <param name="removeEventHandlers">Whether event handlers need to be removed first</param>
/// <param name="rescanDrives">Whether drives should be rescanned or not</param>
2023-10-08 23:06:17 -04:00
public void InitializeUIValues(bool removeEventHandlers, bool rescanDrives)
{
// Disable the dumping button
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = false;
// Safely uncheck the parameters box, just in case
2023-10-08 22:49:46 -04:00
if (this.ParametersCheckBoxEnabled == true)
{
2023-10-08 22:49:46 -04:00
this.CanExecuteSelectionChanged = false;
this.ParametersCheckBoxEnabled = false;
this.CanExecuteSelectionChanged = true;
}
// Set the UI color scheme according to the options
2023-09-25 21:29:55 -04:00
if (this.Options.EnableDarkMode)
EnableDarkMode();
else
EnableLightMode();
// Remove event handlers to ensure ordering
if (removeEventHandlers)
DisableEventHandlers();
// Populate the list of drives and determine the system
if (rescanDrives)
{
2023-10-08 20:52:29 -04:00
this.Status = "Creating drive list, please wait!";
2023-10-08 22:49:46 -04:00
PopulateDrives();
}
else
{
2023-10-08 22:49:46 -04:00
DetermineSystemType();
}
// Determine current media type, if possible
2023-10-08 22:49:46 -04:00
PopulateMediaType();
2023-09-25 21:29:55 -04:00
CacheCurrentDiscType();
2023-09-25 21:16:43 -04:00
SetCurrentDiscType();
// Set the dumping program
2023-10-08 22:49:46 -04:00
PopulateInternalPrograms();
// Set the initial environment and UI values
2023-09-25 21:29:55 -04:00
SetSupportedDriveSpeed();
2023-10-08 23:06:17 -04:00
_environment = DetermineEnvironment();
2023-09-25 21:29:55 -04:00
GetOutputNames(true);
EnsureDiscInformation();
// Enable event handlers
EnableEventHandlers();
// Enable the dumping button, if necessary
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = ShouldEnableDumpingButton();
}
/// <summary>
/// Performs a fast update of the output path while skipping disc checks
/// </summary>
/// <param name="removeEventHandlers">Whether event handlers need to be removed first</param>
2023-10-08 20:52:29 -04:00
public void FastUpdateLabel(bool removeEventHandlers)
{
// Disable the dumping button
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = false;
// Safely uncheck the parameters box, just in case
2023-10-08 22:49:46 -04:00
if (this.ParametersCheckBoxEnabled == true)
{
2023-10-08 22:49:46 -04:00
this.CanExecuteSelectionChanged = false;
this.ParametersCheckBoxEnabled = false;
this.CanExecuteSelectionChanged = true;
}
// Remove event handlers to ensure ordering
if (removeEventHandlers)
DisableEventHandlers();
// Refresh the drive info
2023-10-08 20:52:29 -04:00
this.CurrentDrive?.RefreshDrive();
// Set the initial environment and UI values
2023-10-08 23:06:17 -04:00
_environment = DetermineEnvironment();
2023-09-25 21:29:55 -04:00
GetOutputNames(true);
EnsureDiscInformation();
// Enable event handlers
EnableEventHandlers();
// Enable the dumping button, if necessary
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = ShouldEnableDumpingButton();
}
/// <summary>
/// Enable all textbox and combobox event handlers
/// </summary>
private void EnableEventHandlers()
{
2023-10-08 20:52:29 -04:00
CanExecuteSelectionChanged = true;
}
/// <summary>
/// Disable all textbox and combobox event handlers
/// </summary>
private void DisableEventHandlers()
{
2023-10-08 20:52:29 -04:00
CanExecuteSelectionChanged = false;
}
/// <summary>
/// Recolor all UI elements for light mode
/// </summary>
2023-09-25 21:39:28 -04:00
private static void EnableLightMode()
{
var theme = new LightModeTheme();
theme.Apply();
}
/// <summary>
/// Recolor all UI elements for dark mode
/// </summary>
2023-09-25 21:39:28 -04:00
private static void EnableDarkMode()
{
var theme = new DarkModeTheme();
theme.Apply();
}
#endregion
#region Logging
/// <summary>
/// Enqueue text to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void Log(string text) => _logger(LogLevel.USER, text);
/// <summary>
/// Enqueue text with a newline to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void LogLn(string text) => Log(text + "\n");
/// <summary>
/// Enqueue error text to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void ErrorLog(string text) => _logger(LogLevel.ERROR, text);
/// <summary>
/// Enqueue error text with a newline to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void ErrorLogLn(string text) => ErrorLog(text + "\n");
/// <summary>
/// Enqueue secret text to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void SecretLog(string text) => _logger(LogLevel.SECRET, text);
/// <summary>
/// Enqueue secret text with a newline to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void SecretLogLn(string text) => SecretLog(text + "\n");
/// <summary>
/// Enqueue verbose text to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void VerboseLog(string text)
{
if (Options.VerboseLogging)
_logger(LogLevel.VERBOSE, text);
}
/// <summary>
/// Enqueue verbose text with a newline to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void VerboseLogLn(string text)
{
if (Options.VerboseLogging)
VerboseLog(text + "\n");
}
#endregion
#region Helpers
/// <summary>
/// Cache the current disc type to internal variable
/// </summary>
2023-09-25 21:29:55 -04:00
private void CacheCurrentDiscType()
{
// If the selected item is invalid, we just skip
2023-10-08 20:52:29 -04:00
if (this.CurrentDrive == null)
return;
// Get reasonable default values based on the current system
2023-10-08 20:52:29 -04:00
MediaType? defaultMediaType = this.CurrentSystem.MediaTypes().FirstOrDefault() ?? MediaType.CDROM;
if (defaultMediaType == MediaType.NONE)
defaultMediaType = MediaType.CDROM;
// If we're skipping detection, set the default value
2023-09-25 21:29:55 -04:00
if (this.Options.SkipMediaTypeDetection)
{
VerboseLogLn($"Media type detection disabled, defaulting to {defaultMediaType.LongName()}.");
CurrentMediaType = defaultMediaType;
}
// If the drive is marked active, try to read from it
2023-10-08 20:52:29 -04:00
else if (this.CurrentDrive.MarkedActive)
{
VerboseLog($"Trying to detect media type for drive {this.CurrentDrive.Letter} [{this.CurrentDrive.DriveFormat}] using size and filesystem.. ");
2023-10-08 20:52:29 -04:00
(MediaType? detectedMediaType, string errorMessage) = this.CurrentDrive.GetMediaType(this.CurrentSystem);
// If we got an error message, post it to the log
if (errorMessage != null)
VerboseLogLn($"Message from detecting media type: {errorMessage}");
// If we got either an error or no media, default to the current System default
if (detectedMediaType == null)
{
VerboseLogLn($"Unable to detect, defaulting to {defaultMediaType.LongName()}.");
CurrentMediaType = defaultMediaType;
}
else
{
VerboseLogLn($"Detected {detectedMediaType.LongName()}.");
CurrentMediaType = detectedMediaType;
}
}
// All other cases, just use the default
else
{
VerboseLogLn($"Drive marked as empty, defaulting to {defaultMediaType.LongName()}.");
CurrentMediaType = defaultMediaType;
}
}
/// <summary>
/// Create a DumpEnvironment with all current settings
/// </summary>
2023-09-25 21:16:43 -04:00
/// <returns>Filled DumpEnvironment this.Parent</returns>
2023-09-25 21:29:55 -04:00
private DumpEnvironment DetermineEnvironment()
{
2023-10-08 20:52:29 -04:00
return new DumpEnvironment(
this.Options,
this.OutputPath,
this.CurrentDrive,
this.CurrentSystem,
this.CurrentMediaType,
this.CurrentProgram,
this.Parameters);
}
/// <summary>
/// Determine and set the current system type, if allowed
/// </summary>
2023-09-25 21:29:55 -04:00
private void DetermineSystemType()
{
2023-10-08 20:52:29 -04:00
if (Drives == null || Drives.Count == 0 || this.CurrentDrive == null)
{
VerboseLogLn("Skipping system type detection because no valid drives found!");
}
2023-10-08 20:52:29 -04:00
else if (this.CurrentDrive?.MarkedActive != true)
{
VerboseLogLn("Skipping system type detection because drive not marked as active!");
}
2023-09-25 21:29:55 -04:00
else if (!this.Options.SkipSystemDetection)
{
VerboseLog($"Trying to detect system for drive {this.CurrentDrive.Letter}.. ");
2023-10-08 20:52:29 -04:00
var currentSystem = this.CurrentDrive?.GetRedumpSystem(this.Options.DefaultSystem) ?? this.Options.DefaultSystem;
VerboseLogLn(currentSystem == null ? "unable to detect." : ($"detected {currentSystem.LongName()}."));
2021-08-18 22:13:38 -07:00
if (currentSystem != null)
{
int sysIndex = Systems.FindIndex(s => s == currentSystem);
2023-10-08 22:49:46 -04:00
this.CurrentSystem = Systems[sysIndex];
}
}
2023-09-25 21:29:55 -04:00
else if (this.Options.SkipSystemDetection && this.Options.DefaultSystem != null)
{
2023-09-25 21:29:55 -04:00
var currentSystem = this.Options.DefaultSystem;
VerboseLogLn($"System detection disabled, setting to default of {currentSystem.LongName()}.");
int sysIndex = Systems.FindIndex(s => s == currentSystem);
2023-10-08 22:49:46 -04:00
this.CurrentSystem = Systems[sysIndex];
}
2023-10-08 22:49:46 -04:00
}
/// <summary>
/// Disable all UI elements during dumping
/// </summary>
public void DisableAllUIElements()
{
OptionsMenuItemEnabled = false;
SystemTypeComboBoxEnabled = false;
MediaTypeComboBoxEnabled = false;
OutputPathTextBoxEnabled = false;
OutputPathBrowseButtonEnabled = false;
DriveLetterComboBoxEnabled = false;
DriveSpeedComboBoxEnabled = false;
DumpingProgramComboBoxEnabled = false;
EnableParametersCheckBoxEnabled = false;
StartStopButtonText = Interface.StopDumping;
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
CopyProtectScanButtonEnabled = false;
}
2023-10-08 22:49:46 -04:00
/// <summary>
/// Enable all UI elements after dumping
/// </summary>
public void EnableAllUIElements()
{
OptionsMenuItemEnabled = true;
SystemTypeComboBoxEnabled = true;
MediaTypeComboBoxEnabled = true;
OutputPathTextBoxEnabled = true;
OutputPathBrowseButtonEnabled = true;
DriveLetterComboBoxEnabled = true;
DriveSpeedComboBoxEnabled = true;
DumpingProgramComboBoxEnabled = true;
EnableParametersCheckBoxEnabled = true;
StartStopButtonText = Interface.StartDumping;
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
}
/// <summary>
/// Ensure information is consistent with the currently selected disc type
/// </summary>
2023-09-25 21:29:55 -04:00
public void EnsureDiscInformation()
{
// Get the current environment information
2023-10-08 23:06:17 -04:00
_environment = DetermineEnvironment();
// Get the status to write out
2023-10-08 23:06:17 -04:00
Result result = Tools.GetSupportStatus(_environment.System, _environment.Type);
2023-10-08 20:52:29 -04:00
this.Status = result.Message;
// Set the index for the current disc type
2023-09-25 21:16:43 -04:00
SetCurrentDiscType();
// Enable or disable the button
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = result && ShouldEnableDumpingButton();
// If we're in a type that doesn't support drive speeds
2023-10-08 23:06:17 -04:00
this.DriveSpeedComboBoxEnabled = _environment.Type.DoesSupportDriveSpeed();
// If input params are not enabled, generate the full parameters from the environment
2023-10-08 22:49:46 -04:00
if (!this.ParametersCheckBoxEnabled)
{
2023-10-08 23:06:17 -04:00
string generated = _environment.GetFullParameters(this.DriveSpeed);
if (generated != null)
2023-10-08 20:52:29 -04:00
this.Parameters = generated;
}
}
/// <summary>
/// Get the default output directory name from the currently selected drive
/// </summary>
/// <param name="driveChanged">Force an updated name if the drive letter changes</param>
2023-09-25 21:29:55 -04:00
public void GetOutputNames(bool driveChanged)
{
2023-10-08 20:52:29 -04:00
if (Drives == null || Drives.Count == 0 || this.CurrentDrive == null)
{
VerboseLog("Skipping output name building because no valid drives found!");
return;
}
// Get the extension for the file for the next two statements
2023-10-08 23:06:17 -04:00
string extension = _environment?.Parameters?.GetDefaultExtension(this.CurrentMediaType);
// Set the output filename, if it's not already
2023-10-08 20:52:29 -04:00
if (string.IsNullOrEmpty(this.OutputPath))
{
2023-10-08 20:52:29 -04:00
string label = this.CurrentDrive?.FormattedVolumeLabel ?? this.CurrentSystem.LongName();
2023-09-25 21:29:55 -04:00
string directory = this.Options.DefaultOutputPath;
string filename = $"{label}{extension ?? ".bin"}";
// If the path ends with the label already
if (directory.EndsWith(label, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
2023-10-08 20:52:29 -04:00
this.OutputPath = Path.Combine(directory, label, filename);
}
// Set the output filename, if we changed drives
else if (driveChanged)
{
2023-10-08 20:52:29 -04:00
string label = this.CurrentDrive?.FormattedVolumeLabel ?? this.CurrentSystem.LongName();
string oldPath = InfoTool.NormalizeOutputPaths(this.OutputPath, false);
string oldFilename = Path.GetFileNameWithoutExtension(oldPath);
string directory = Path.GetDirectoryName(oldPath);
string filename = $"{label}{extension ?? ".bin"}";
// If the previous path included the label
if (directory.EndsWith(oldFilename, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
// If the path ends with the label already
if (directory.EndsWith(label, StringComparison.OrdinalIgnoreCase))
directory = Path.GetDirectoryName(directory);
2023-10-08 20:52:29 -04:00
this.OutputPath = Path.Combine(directory, label, filename);
}
2023-08-28 11:24:58 -04:00
// Otherwise, reset the extension of the currently set path
else
{
2023-10-08 20:52:29 -04:00
string oldPath = InfoTool.NormalizeOutputPaths(this.OutputPath, false);
string filename = Path.GetFileNameWithoutExtension(oldPath);
string directory = Path.GetDirectoryName(oldPath);
2023-08-28 11:24:58 -04:00
filename = $"{filename}{extension ?? ".bin"}";
2023-10-08 20:52:29 -04:00
this.OutputPath = Path.Combine(directory, filename);
2023-08-28 11:24:58 -04:00
}
}
/// <summary>
/// Process the current custom parameters back into UI values
/// </summary>
2023-09-25 21:16:43 -04:00
public void ProcessCustomParameters()
{
2023-10-08 23:06:17 -04:00
_environment.SetParameters(this.Parameters);
if (_environment.Parameters == null)
return;
2022-01-13 10:25:57 -08:00
// Catch this in case there's an input path issue
try
{
2023-10-08 23:06:17 -04:00
int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(_environment.Parameters.InputPath[0]);
2023-10-08 20:52:29 -04:00
this.CurrentDrive = (driveIndex != -1 ? Drives[driveIndex] : Drives[0]);
2022-01-13 10:25:57 -08:00
}
catch { }
2023-10-08 23:06:17 -04:00
int driveSpeed = _environment.Parameters.Speed ?? -1;
if (driveSpeed > 0)
2023-10-08 20:52:29 -04:00
this.DriveSpeed = driveSpeed;
else
2023-10-08 23:06:17 -04:00
_environment.Parameters.Speed = this.DriveSpeed;
// Disable change handling
DisableEventHandlers();
2023-10-08 23:06:17 -04:00
this.OutputPath = InfoTool.NormalizeOutputPaths(_environment.Parameters.OutputPath, true);
2023-10-08 23:06:17 -04:00
MediaType? mediaType = _environment.Parameters.GetMediaType();
int mediaTypeIndex = MediaTypes.FindIndex(m => m == mediaType);
2023-10-08 20:52:29 -04:00
this.CurrentMediaType = (mediaTypeIndex > -1 ? MediaTypes[mediaTypeIndex] : MediaTypes[0]);
// Reenable change handling
EnableEventHandlers();
}
/// <summary>
/// Scan and show copy protection for the current disc
/// </summary>
2023-09-25 21:29:55 -04:00
public async void ScanAndShowProtection()
{
// Determine current environment, just in case
2023-10-08 23:06:17 -04:00
if (_environment == null)
_environment = DetermineEnvironment();
// Pull the drive letter from the UI directly, just in case
2023-10-08 20:52:29 -04:00
if (this.CurrentDrive != null && this.CurrentDrive.Letter != default(char))
{
VerboseLogLn($"Scanning for copy protection in {this.CurrentDrive.Letter}");
2023-10-08 20:52:29 -04:00
var tempContent = this.Status;
this.Status = "Scanning for copy protection... this might take a while!";
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = false;
this.MediaScanButtonEnabled = false;
this.UpdateVolumeLabelEnabled = false;
this.CopyProtectScanButtonEnabled = false;
var progress = new Progress<ProtectionProgress>();
progress.ProgressChanged += ProgressUpdated;
2023-10-08 20:52:29 -04:00
(var protections, string error) = await Protection.RunProtectionScanOnPath(this.CurrentDrive.Letter + ":\\", this.Options, progress);
string output = Protection.FormatProtections(protections);
// If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only -- Disabled until further notice
//if (Env.InternalProgram == InternalProgram.DiscImageCreator && output.Contains("SmartE"))
//{
// ((Modules.DiscImageCreator.Parameters)Env.Parameters)[Modules.DiscImageCreator.FlagStrings.ScanFileProtect] = false;
2023-09-25 21:29:55 -04:00
// if (this.Options.VerboseLogging)
2023-09-25 21:21:51 -04:00
// this.Logger.VerboseLogLn($"SmartE detected, removing {Modules.DiscImageCreator.FlagStrings.ScanFileProtect} from parameters");
//}
2023-10-08 22:49:46 -04:00
if (!this.LogPanelExpanded)
{
if (string.IsNullOrEmpty(error))
CustomMessageBox.Show(output, "Detected Protection(s)", MessageBoxButton.OK, MessageBoxImage.Information);
else
CustomMessageBox.Show("An exception occurred, see the log for details", "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
}
if (string.IsNullOrEmpty(error))
LogLn($"Detected the following protections in {this.CurrentDrive.Letter}:\r\n\r\n{output}");
else
ErrorLogLn($"Path could not be scanned! Exception information:\r\n\r\n{error}");
2023-10-08 20:52:29 -04:00
this.Status = tempContent;
2023-10-08 22:49:46 -04:00
this.StartStopButtonEnabled = ShouldEnableDumpingButton();
this.MediaScanButtonEnabled = true;
this.UpdateVolumeLabelEnabled = true;
this.CopyProtectScanButtonEnabled = true;
}
}
/// <summary>
/// Set the current disc type in the combo box
/// </summary>
2023-09-25 21:16:43 -04:00
private void SetCurrentDiscType()
{
// If we have an invalid current type, we don't care and return
if (CurrentMediaType == null || CurrentMediaType == MediaType.NONE)
return;
// Now set the selected item, if possible
int index = MediaTypes.FindIndex(kvp => kvp.Value == CurrentMediaType);
if (this.CurrentMediaType != null && index == -1)
VerboseLogLn($"Disc of type '{CurrentMediaType.LongName()}' found, but the current system does not support it!");
2023-10-08 20:52:29 -04:00
this.CurrentMediaType = (index > -1 ? MediaTypes[index] : MediaTypes[0]);
}
/// <summary>
/// Set the drive speed based on reported maximum and user-defined option
/// </summary>
2023-09-25 21:29:55 -04:00
public void SetSupportedDriveSpeed()
{
// Set the drive speed list that's appropriate
2023-10-08 22:49:46 -04:00
this.DriveSpeeds = (List<int>)Interface.GetSpeedsForMediaType(CurrentMediaType);
VerboseLogLn($"Supported media speeds: {string.Join(", ", this.DriveSpeeds)}");
// Set the selected speed
int speed;
2023-10-08 20:52:29 -04:00
switch (this.CurrentMediaType)
{
case MediaType.CDROM:
case MediaType.GDROM:
2023-09-25 21:29:55 -04:00
speed = this.Options.PreferredDumpSpeedCD;
break;
case MediaType.DVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
2023-09-25 21:29:55 -04:00
speed = this.Options.PreferredDumpSpeedDVD;
break;
case MediaType.HDDVD:
2023-09-25 21:29:55 -04:00
speed = this.Options.PreferredDumpSpeedHDDVD;
break;
case MediaType.BluRay:
2023-09-25 21:29:55 -04:00
speed = this.Options.PreferredDumpSpeedBD;
break;
default:
2023-09-25 21:29:55 -04:00
speed = this.Options.PreferredDumpSpeedCD;
break;
}
VerboseLogLn($"Setting drive speed to: {speed}");
2023-10-08 20:52:29 -04:00
this.DriveSpeed = speed;
}
/// <summary>
/// Determine if the dumping button should be enabled
/// </summary>
2023-09-25 21:16:43 -04:00
private bool ShouldEnableDumpingButton()
{
2023-02-23 16:55:27 -05:00
return Drives != null
&& Drives.Count > 0
2023-10-08 20:52:29 -04:00
&& this.CurrentSystem != null
&& !string.IsNullOrEmpty(this.Parameters);
}
/// <summary>
/// Begin the dumping process using the given inputs
/// </summary>
2023-09-25 21:29:55 -04:00
public async void StartDumping()
{
// One last check to determine environment, just in case
2023-10-08 23:06:17 -04:00
_environment = DetermineEnvironment();
2022-03-01 16:41:54 -08:00
// Force an internal drive refresh in case the user entered things manually
2023-10-08 23:06:17 -04:00
_environment.Drive.RefreshDrive();
2022-03-01 16:41:54 -08:00
// If still in custom parameter mode, check that users meant to continue or not
2023-10-08 22:49:46 -04:00
if (this.ParametersCheckBoxEnabled == true)
{
MessageBoxResult result = CustomMessageBox.Show("It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
2023-10-08 22:49:46 -04:00
this.ParametersCheckBoxEnabled = false;
2023-09-25 21:16:43 -04:00
ProcessCustomParameters();
}
else if (result == MessageBoxResult.Cancel)
2023-09-25 16:58:14 -04:00
{
return;
2023-09-25 16:58:14 -04:00
}
// If "No", then we continue with the current known environment
}
2023-04-13 12:33:14 -04:00
// Run path adjustments for DiscImageCreator -- Disabled until further notice
//Env.AdjustPathsForDiscImageCreator();
try
{
// Run pre-dumping validation checks
2023-09-25 21:21:51 -04:00
if (!ValidateBeforeDumping())
return;
// Disable all UI elements apart from dumping button
2023-10-08 22:49:46 -04:00
DisableAllUIElements();
// Refresh the drive, if it wasn't null
2023-10-08 23:06:17 -04:00
_environment.Drive?.RefreshDrive();
// Output to the label and log
2023-10-08 20:52:29 -04:00
this.Status = "Starting dumping process... Please wait!";
LogLn("Starting dumping process... Please wait!");
2023-09-25 21:29:55 -04:00
if (this.Options.ToolsInSeparateWindow)
LogLn("Look for the separate command window for more details");
else
LogLn("Program outputs may be slow to populate in the log window");
// Get progress indicators
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ProgressUpdated;
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ProgressUpdated;
2023-10-08 23:06:17 -04:00
_environment.ReportStatus += ProgressUpdated;
// Run the program with the parameters
2023-10-08 23:06:17 -04:00
Result result = await _environment.Run(resultProgress);
// If we didn't execute a dumping command we cannot get submission output
2023-10-08 23:06:17 -04:00
if (!_environment.Parameters.IsDumpingCommand())
{
LogLn("No dumping command was run, submission information will not be gathered.");
2023-10-08 20:52:29 -04:00
this.Status = "Execution complete!";
// Reset all UI elements
2023-10-08 22:49:46 -04:00
EnableAllUIElements();
return;
}
// Verify dump output and save it
if (result)
{
2023-10-08 23:15:24 -04:00
result = await _environment.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, _processUserInfo);
}
else
{
ErrorLogLn(result.Message);
2023-10-08 20:52:29 -04:00
this.Status = "Execution failed!";
}
}
catch (Exception ex)
{
ErrorLogLn(ex.ToString());
2023-10-08 20:52:29 -04:00
this.Status = "An exception occurred!";
}
finally
{
// Reset all UI elements
2023-10-08 22:49:46 -04:00
EnableAllUIElements();
}
}
/// <summary>
/// Toggle the parameters input box
/// </summary>
public void ToggleParameters()
{
if (ParametersCheckBoxEnabled == true)
{
SystemTypeComboBoxEnabled = false;
MediaTypeComboBoxEnabled = false;
OutputPathTextBoxEnabled = false;
OutputPathBrowseButtonEnabled = false;
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
CopyProtectScanButtonEnabled = false;
}
else
{
ProcessCustomParameters();
SystemTypeComboBoxEnabled = true;
MediaTypeComboBoxEnabled = true;
OutputPathTextBoxEnabled = true;
OutputPathBrowseButtonEnabled = true;
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
}
}
/// <summary>
/// Perform validation, including user input, before attempting to start dumping
/// </summary>
/// <returns>True if dumping should start, false otherwise</returns>
2023-09-25 21:21:51 -04:00
private bool ValidateBeforeDumping()
{
// Validate that we have an output path of any sort
2023-10-08 23:06:17 -04:00
if (string.IsNullOrWhiteSpace(_environment.OutputPath))
{
2023-09-25 21:39:28 -04:00
_ = CustomMessageBox.Show("No output path was provided so dumping cannot continue.", "Missing Path", MessageBoxButton.OK, MessageBoxImage.Exclamation);
LogLn("Dumping aborted!");
return false;
}
// Validate that the user explicitly wants an inactive drive to be considered for dumping
2023-10-08 23:06:17 -04:00
if (!_environment.Drive.MarkedActive)
{
string message = "The currently selected drive does not appear to contain a disc! "
2023-10-08 23:06:17 -04:00
+ (!_environment.System.DetectedByWindows() ? $"This is normal for {_environment.System.LongName()} as the discs may not be readable on Windows. " : string.Empty)
+ "Do you want to continue?";
MessageBoxResult mbresult = CustomMessageBox.Show(message, "No Disc Detected", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
{
LogLn("Dumping aborted!");
return false;
}
}
// Pre-split the output path
2023-10-08 23:06:17 -04:00
string outputDirectory = Path.GetDirectoryName(_environment.OutputPath);
string outputFilename = Path.GetFileName(_environment.OutputPath);
// If a complete dump already exists
2023-10-08 23:06:17 -04:00
(bool foundFiles, List<string> _) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, _environment.Parameters, true);
if (foundFiles)
{
MessageBoxResult mbresult = CustomMessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
{
LogLn("Dumping aborted!");
return false;
}
}
// Validate that at least some space exists
// TODO: Tie this to the size of the disc, type of disc, etc.
string fullPath = Path.GetFullPath(outputDirectory);
var driveInfo = new DriveInfo(Path.GetPathRoot(fullPath));
if (driveInfo.AvailableFreeSpace < Math.Pow(2, 30))
{
MessageBoxResult mbresult = CustomMessageBox.Show("There is less than 1gb of space left on the target drive. Are you sure you want to continue?", "Low Space", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None)
{
LogLn("Dumping aborted!");
return false;
}
}
// If nothing above fails, we want to continue
return true;
}
#endregion
#region Progress Reporting
/// <summary>
/// Handler for Result ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, string value)
{
try
{
value = value ?? string.Empty;
LogLn(value);
}
catch { }
}
/// <summary>
/// Handler for Result ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, Result value)
{
string message = value?.Message;
// Update the label with only the first line of output
if (message.Contains("\n"))
2023-10-08 20:52:29 -04:00
this.Status = value.Message.Split('\n')[0] + " (See log output)";
else
2023-10-08 20:52:29 -04:00
this.Status = value.Message;
// Log based on success or failure
if (value)
VerboseLogLn(message);
else if (!value)
ErrorLogLn(message);
}
/// <summary>
/// Handler for ProtectionProgress ProgressChanged event
/// </summary>
private void ProgressUpdated(object sender, ProtectionProgress value)
{
string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}";
2023-10-08 20:52:29 -04:00
this.Status = message;
VerboseLogLn(message);
}
#endregion
}
}