diff --git a/DICUI/Windows/MainWindow.xaml b/DICUI/Windows/MainWindow.xaml index 9ee90947..86152588 100644 --- a/DICUI/Windows/MainWindow.xaml +++ b/DICUI/Windows/MainWindow.xaml @@ -30,7 +30,7 @@ - + - + diff --git a/DICUI/Windows/MainWindow.xaml.cs b/DICUI/Windows/MainWindow.xaml.cs index 4c4516b6..668f9851 100644 --- a/DICUI/Windows/MainWindow.xaml.cs +++ b/DICUI/Windows/MainWindow.xaml.cs @@ -15,44 +15,84 @@ namespace DICUI.Windows { public partial class MainWindow : Window { - // Private UI-related variables - private List _drives; - private MediaType? _currentMediaType; - private List _systems; - private List _mediaTypes; - private bool _alreadyShown; + #region Fields - private DumpEnvironment _env; + /// + /// Currently selected or detected media type + /// + public MediaType? CurrentMediaType { get; private set; } - // Option related - private UIOptions _uiOptions; - private OptionsWindow _optionsWindow; + /// + /// Current list of drives + /// + public List Drives { get; private set; } - // User input related - private DiscInformationWindow _discInformationWindow; + /// + /// Current dumping environment + /// + public DumpEnvironment Env { get; private set; } - private LogWindow _logWindow; + /// + /// Current list of supported media types + /// + public List MediaTypes { get; private set; } = new List(); + + /// + /// Current list of supported system profiles + /// + public List Systems { get; private set; } + + /// + /// Current UI options + /// + public UIOptions UIOptions { get; private set; } = new UIOptions(); + + #endregion + + #region Private Instance Variables + + /// + /// Determines if the window is already shown or not + /// + private bool alreadyShown; + + /// + /// Current attached DiscInformationWindow + /// + private DiscInformationWindow discInformationWindow; + + /// + /// Current attached LogWindow + /// + private LogWindow logWindow; + + /// + /// Currently attached OptionsWindow + /// + private OptionsWindow optionsWindow; + + #endregion public MainWindow() { InitializeComponent(); - // Initializes and load Options object - _uiOptions = new UIOptions(); - ViewModels.OptionsViewModel = new OptionsViewModel(_uiOptions); + // Load the options + ViewModels.OptionsViewModel = new OptionsViewModel(UIOptions); - _logWindow = new LogWindow(this); - ViewModels.LoggerViewModel.SetWindow(_logWindow); + // Load the log window + logWindow = new LogWindow(this); + ViewModels.LoggerViewModel.SetWindow(logWindow); // Disable buttons until we load fully StartStopButton.IsEnabled = false; - DiskScanButton.IsEnabled = false; + MediaScanButton.IsEnabled = false; CopyProtectScanButton.IsEnabled = false; - if (_uiOptions.OpenLogWindowAtStartup) + if (UIOptions.OpenLogWindowAtStartup) { this.WindowStartupLocation = WindowStartupLocation.Manual; - double combinedHeight = this.Height + _logWindow.Height + Constants.LogWindowMarginFromMainWindow; + double combinedHeight = this.Height + logWindow.Height + Constants.LogWindowMarginFromMainWindow; Rectangle bounds = GetScaledCoordinates(WinForms.Screen.PrimaryScreen.WorkingArea); this.Left = bounds.Left + (bounds.Width - this.Width) / 2; @@ -60,229 +100,193 @@ namespace DICUI.Windows } } - #region Events + #region Helpers - protected override void OnContentRendered(EventArgs e) + /// + /// Browse for an output folder + /// + private void BrowseFolder() { - base.OnContentRendered(e); + WinForms.FolderBrowserDialog folderDialog = new WinForms.FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory }; + WinForms.DialogResult result = folderDialog.ShowDialog(); - if (_alreadyShown) - return; - - _alreadyShown = true; - - if (_uiOptions.OpenLogWindowAtStartup) + if (result == WinForms.DialogResult.OK) { - //TODO: this should be bound directly to WindowVisible property in two way fashion - // we need to study how to properly do it in XAML - ShowLogMenuItem.IsChecked = true; - ViewModels.LoggerViewModel.WindowVisible = true; + OutputDirectoryTextBox.Text = folderDialog.SelectedPath; } - - // Populate the list of systems - StatusLabel.Content = "Creating system list, please wait!"; - PopulateSystems(); - - // Populate the list of drives - StatusLabel.Content = "Creating drive list, please wait!"; - PopulateDrives(); } - private void StartStopButtonClick(object sender, RoutedEventArgs e) + /// + /// Cache the current disc type to internal variable + /// + private void CacheCurrentDiscType() { - // Dump or stop the dump - if ((string)StartStopButton.Content == Constants.StartDumping) + // Get the drive letter from the selected item + var drive = DriveLetterComboBox.SelectedItem as Drive; + if (drive == null) + return; + + // Get the current media type + if (!UIOptions.SkipMediaTypeDetection) { - StartDumping(); + ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter); + CurrentMediaType = Validators.GetMediaType(drive); + ViewModels.LoggerViewModel.VerboseLogLn(CurrentMediaType == null ? "unable to detect." : ("detected " + CurrentMediaType.LongName() + ".")); } - else if ((string)StartStopButton.Content == Constants.StopDumping) + } + + /// + /// Create a DumpEnvironment with all current settings + /// + /// Filled DumpEnvironment instance + private DumpEnvironment DetermineEnvironment() + { + // Populate the new environment + var env = new DumpEnvironment(UIOptions.Options, + OutputDirectoryTextBox.Text, + OutputFilenameTextBox.Text, + DriveLetterComboBox.SelectedItem as Drive, + SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem, + MediaTypeComboBox.SelectedItem as MediaType?, + ParametersTextBox.Text); + + // Disable automatic reprocessing of the textboxes until we're done + OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged; + OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged; + + OutputDirectoryTextBox.Text = env.OutputDirectory; + OutputFilenameTextBox.Text = env.OutputFilename; + + OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged; + OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged; + + return env; + } + + /// + /// Ensure information is consistent with the currently selected disc type + /// + private void EnsureDiscInformation() + { + // Get the current environment information + Env = DetermineEnvironment(); + + // Take care of null cases + if (Env.System == null) + Env.System = KnownSystem.NONE; + if (Env.Type == null) + Env.Type = MediaType.NONE; + + // Get the status to write out + Result result = Validators.GetSupportStatus(Env.System, Env.Type); + StatusLabel.Content = result.Message; + + // Set the index for the current disc type + SetCurrentDiscType(); + + StartStopButton.IsEnabled = result && (Drives != null && Drives.Count > 0 ? true : false); + + // If we're in a type that doesn't support drive speeds + DriveSpeedComboBox.IsEnabled = Env.Type.DoesSupportDriveSpeed(); + + // If input params are not enabled, generate the full parameters from the environment + if (!ParametersTextBox.IsEnabled) { - ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process..."); - _env.CancelDumping(); + string generated = Env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem); + if (generated != null) + ParametersTextBox.Text = generated; + } + } + + /// + /// Get the default output directory name from the currently selected drive + /// + /// Force an updated name if the drive letter changes + private void GetOutputNames(bool driveChanged) + { + Drive drive = DriveLetterComboBox.SelectedItem as Drive; + KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem; + MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?; + + // Set the output directory, if we changed drives or it's not already + if (driveChanged || string.IsNullOrEmpty(OutputDirectoryTextBox.Text)) + OutputDirectoryTextBox.Text = Path.Combine(UIOptions.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty); + + // Get the extension for the file for the next two statements + string extension = Env.GetExtension(mediaType); + + // Set the output filename, if we changed drives or it's not already + if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text)) + OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? systemType.LongName()) + (extension ?? ".bin"); + + // If the extension for the file changed, update that automatically + else if (Path.GetExtension(OutputFilenameTextBox.Text) != extension) + OutputFilenameTextBox.Text = Path.GetFileNameWithoutExtension(OutputFilenameTextBox.Text) + (extension ?? ".bin"); + } + + /// + /// Get a complete list of active disc drives and fill the combo box + /// + /// TODO: Find a way for this to periodically run, or have it hook to a "drive change" event + private void PopulateDrives() + { + ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives.."); + + // Always enable the media scan + MediaScanButton.IsEnabled = true; + + // Populate the list of drives and add it to the combo box + Drives = Validators.CreateListOfDrives(UIOptions.IgnoreFixedDrives); + DriveLetterComboBox.ItemsSource = Drives; + + if (DriveLetterComboBox.Items.Count > 0) + { + // Check for active optical drives first + int index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical); + + // Then we check for floppy drives + if (index == -1) + index = Drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy); + + // Then we try all other drive types + if (index == -1) + index = Drives.FindIndex(d => d.MarkedActive); + + // Set the selected index + DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0); + StatusLabel.Content = "Valid drive found! Choose your Media Type"; CopyProtectScanButton.IsEnabled = true; - if (EjectWhenDoneCheckBox.IsChecked == true) + // Get the current media type + if (!UIOptions.SkipSystemDetection && index != -1) { - ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}"); - _env.EjectDisc(); + ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", Drives[index].Letter); + var currentSystem = Validators.GetKnownSystem(Drives[index]); + ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + ".")); + + if (currentSystem != null && currentSystem != KnownSystem.NONE) + { + int sysIndex = Systems.FindIndex(s => s == currentSystem); + SystemTypeComboBox.SelectedIndex = sysIndex; + } } - if (_uiOptions.ResetDriveAfterDump) - { - ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {_env.Drive.Letter}"); - _env.ResetDrive(); - } + // Only enable the start/stop if we don't have the default selected + StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE; + + ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", Drives.Count, string.Join(", ", Drives.Select(d => d.Letter))); } - } - - private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e) - { - BrowseFolder(); - EnsureDiscInformation(); - } - - private void DiskScanButtonClick(object sender, RoutedEventArgs e) - { - PopulateDrives(); - } - - private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e) - { - ScanAndShowProtection(); - } - - private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) - { - // If we're on a separator, go to the next item and return - if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader()) - { - SystemTypeComboBox.SelectedIndex++; - return; - } - - ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name); - PopulateMediaType(); - GetOutputNames(false); - EnsureDiscInformation(); - } - - private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) - { - // Only change the media type if the selection and not the list has changed - if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1) - { - _currentMediaType = MediaTypeComboBox.SelectedItem as MediaType?; - SetSupportedDriveSpeed(); - } - - GetOutputNames(false); - EnsureDiscInformation(); - } - - private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) - { - CacheCurrentDiscType(); - SetCurrentDiscType(); - GetOutputNames(true); - SetSupportedDriveSpeed(); - } - - private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) - { - EnsureDiscInformation(); - } - - private void OutputFilenameTextBoxTextChanged(object sender, TextChangedEventArgs e) - { - EnsureDiscInformation(); - } - - private void OutputDirectoryTextBoxTextChanged(object sender, TextChangedEventArgs e) - { - EnsureDiscInformation(); - } - - private void ProgressUpdated(object sender, Result value) - { - StatusLabel.Content = value.Message; - ViewModels.LoggerViewModel.VerboseLogLn(value.Message); - } - - private void ProgressUpdated(object sender, FileProtection value) - { - string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}"; - StatusLabel.Content = message; - ViewModels.LoggerViewModel.VerboseLogLn(message); - } - - private void MainWindowLocationChanged(object sender, EventArgs e) - { - if (_logWindow.IsVisible) - _logWindow.AdjustPositionToMainWindow(); - } - - private void MainWindowActivated(object sender, EventArgs e) - { - if (_logWindow.IsVisible && !this.Topmost) - { - _logWindow.Topmost = true; - _logWindow.Topmost = false; - } - } - - private void MainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e) - { - if (_logWindow.IsVisible) - _logWindow.Close(); - } - - private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e) - { - if (EnableParametersCheckBox.IsChecked == true) - ParametersTextBox.IsEnabled = true; else { - ParametersTextBox.IsEnabled = false; - ProcessCustomParameters(); + DriveLetterComboBox.SelectedIndex = -1; + StatusLabel.Content = "No valid drive found!"; + StartStopButton.IsEnabled = false; + CopyProtectScanButton.IsEnabled = false; + + ViewModels.LoggerViewModel.VerboseLogLn("Found no drives"); } } - // Toolbar Events - - private void AppExitClick(object sender, RoutedEventArgs e) - { - Application.Current.Shutdown(); - } - - private void AboutClick(object sender, RoutedEventArgs e) - { - MessageBox.Show($"darksabre76 - Project Lead / Backend Design" - + $"{Environment.NewLine}ReignStumble - Former Project Lead / UI Design" - + $"{Environment.NewLine}Jakz - Primary Feature Contributor" - + $"{Environment.NewLine}NHellFire - Feature Contributor", "About", MessageBoxButton.OK, MessageBoxImage.Information); - } - - private void OptionsClick(object sender, RoutedEventArgs e) - { - // lazy initialization - if (_optionsWindow == null) - { - _optionsWindow = new OptionsWindow(this, _uiOptions); - _optionsWindow.Closed += delegate - { - _optionsWindow = null; - }; - } - - _optionsWindow.Owner = this; - _optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; - _optionsWindow.Refresh(); - _optionsWindow.Show(); - } - - private void CheckForUpdatesClick(object sender, RoutedEventArgs e) - { - (bool different, string message, string url) = Tools.CheckForNewVersion(); - - // If we have a new version, put it in the clipboard - if (different) - Clipboard.SetText(url); - - MessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information); - } - - public void OnOptionsUpdated() - { - PopulateDrives(); - GetOutputNames(false); - SetSupportedDriveSpeed(); - EnsureDiscInformation(); - } - - #endregion - - #region Helpers - /// /// Populate media type according to system type /// @@ -292,11 +296,11 @@ namespace DICUI.Windows if (currentSystem != null) { - _mediaTypes = Validators.GetValidMediaTypes(currentSystem); - MediaTypeComboBox.ItemsSource = _mediaTypes; + MediaTypes = Validators.GetValidMediaTypes(currentSystem); + MediaTypeComboBox.ItemsSource = MediaTypes; - MediaTypeComboBox.IsEnabled = _mediaTypes.Count > 1; - MediaTypeComboBox.SelectedIndex = (_mediaTypes.IndexOf(_currentMediaType) >= 0 ? _mediaTypes.IndexOf(_currentMediaType) : 0); + MediaTypeComboBox.IsEnabled = MediaTypes.Count > 1; + MediaTypeComboBox.SelectedIndex = (MediaTypes.IndexOf(CurrentMediaType) >= 0 ? MediaTypes.IndexOf(CurrentMediaType) : 0); } else { @@ -324,124 +328,131 @@ namespace DICUI.Windows .ToList() ); - _systems = new List(); - _systems.Add(new KnownSystemComboBoxItem(KnownSystem.NONE)); + Systems = new List() + { + new KnownSystemComboBoxItem(KnownSystem.NONE), + }; foreach (var group in mapping) { - _systems.Add(new KnownSystemComboBoxItem(group.Key)); - group.Value.ForEach(system => _systems.Add(new KnownSystemComboBoxItem(system))); + Systems.Add(new KnownSystemComboBoxItem(group.Key)); + group.Value.ForEach(system => Systems.Add(new KnownSystemComboBoxItem(system))); } - SystemTypeComboBox.ItemsSource = _systems; + SystemTypeComboBox.ItemsSource = Systems; SystemTypeComboBox.SelectedIndex = 0; StartStopButton.IsEnabled = false; } /// - /// Get a complete list of active disc drives and fill the combo box + /// Process the current custom parameters back into UI values /// - /// TODO: Find a way for this to periodically run, or have it hook to a "drive change" event - private void PopulateDrives() + private void ProcessCustomParameters() { - ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives.."); + Env.SetParameters(ParametersTextBox.Text); + if (Env.Parameters == null) + return; - // Always enable the disk scan - DiskScanButton.IsEnabled = true; + int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(Env.Parameters.InputPath()[0]); + if (driveIndex > -1) + DriveLetterComboBox.SelectedIndex = driveIndex; - // Populate the list of drives and add it to the combo box - _drives = Validators.CreateListOfDrives(_uiOptions.IgnoreFixedDrives); - DriveLetterComboBox.ItemsSource = _drives; - - if (DriveLetterComboBox.Items.Count > 0) - { - // Check for active optical drives first - int index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical); - - // Then we check for floppy drives - if (index == -1) - index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy); - - // Then we try all other drive types - if (index == -1) - index = _drives.FindIndex(d => d.MarkedActive); - - // Set the selected index - DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0); - StatusLabel.Content = "Valid drive found! Choose your Media Type"; - CopyProtectScanButton.IsEnabled = true; - - // Get the current media type - if (!_uiOptions.SkipSystemDetection && index != -1) - { - ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", _drives[index].Letter); - var currentSystem = Validators.GetKnownSystem(_drives[index]); - ViewModels.LoggerViewModel.VerboseLogLn(currentSystem == null || currentSystem == KnownSystem.NONE ? "unable to detect." : ("detected " + currentSystem.LongName() + ".")); - - if (currentSystem != null && currentSystem != KnownSystem.NONE) - { - int sysIndex = _systems.FindIndex(s => s == currentSystem); - SystemTypeComboBox.SelectedIndex = sysIndex; - } - } - - // Only enable the start/stop if we don't have the default selected - StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE; - - ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, string.Join(", ", _drives.Select(d => d.Letter))); - } + int driveSpeed = Env.Parameters.GetSpeed() ?? -1; + if (driveSpeed > 0) + DriveSpeedComboBox.SelectedValue = driveSpeed; else + Env.Parameters.SetSpeed((int?)DriveSpeedComboBox.SelectedValue); + + string trimmedPath = Env.Parameters.OutputPath()?.Trim('"') ?? string.Empty; + string outputDirectory = Path.GetDirectoryName(trimmedPath); + string outputFilename = Path.GetFileName(trimmedPath); + if (!string.IsNullOrWhiteSpace(outputDirectory)) + OutputDirectoryTextBox.Text = outputDirectory; + else + outputDirectory = OutputDirectoryTextBox.Text; + if (!string.IsNullOrWhiteSpace(outputFilename)) + OutputFilenameTextBox.Text = outputFilename; + else + outputFilename = OutputFilenameTextBox.Text; + + MediaType? mediaType = Env.Parameters.GetMediaType(); + int mediaTypeIndex = MediaTypes.IndexOf(mediaType); + if (mediaTypeIndex > -1) + MediaTypeComboBox.SelectedIndex = mediaTypeIndex; + } + + /// + /// Scan and show copy protection for the current disc + /// + private async void ScanAndShowProtection() + { + if (Env == null) + Env = DetermineEnvironment(); + + if (Env.Drive.Letter != default(char)) { - DriveLetterComboBox.SelectedIndex = -1; - StatusLabel.Content = "No valid drive found!"; + ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", Env.Drive.Letter); + + var tempContent = StatusLabel.Content; + StatusLabel.Content = "Scanning for copy protection... this might take a while!"; StartStopButton.IsEnabled = false; + MediaScanButton.IsEnabled = false; CopyProtectScanButton.IsEnabled = false; - ViewModels.LoggerViewModel.VerboseLogLn("Found no drives"); + var progress = new Progress(); + progress.ProgressChanged += ProgressUpdated; + string protections = await Validators.RunProtectionScanOnPath(Env.Drive.Letter + ":\\", progress); + + // If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only + if (Env.InternalProgram == InternalProgram.DiscImageCreator && protections.Contains("SmartE")) + { + ((DiscImageCreator.Parameters)Env.Parameters)[DiscImageCreator.Flag.ScanFileProtect] = false; + ViewModels.LoggerViewModel.VerboseLogLn($"SmartE detected, removing {DiscImageCreator.FlagStrings.ScanFileProtect} from parameters"); + } + + if (!ViewModels.LoggerViewModel.WindowVisible) + MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information); + ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", Env.Drive.Letter, protections); + + StatusLabel.Content = tempContent; + StartStopButton.IsEnabled = true; + MediaScanButton.IsEnabled = true; + CopyProtectScanButton.IsEnabled = true; } } /// - /// Browse for an output folder + /// Set the current disc type in the combo box /// - private void BrowseFolder() + private void SetCurrentDiscType() { - WinForms.FolderBrowserDialog folderDialog = new WinForms.FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory }; - WinForms.DialogResult result = folderDialog.ShowDialog(); + // If we have an invalid current type, we don't care and return + if (CurrentMediaType == null || CurrentMediaType == MediaType.NONE) + return; - if (result == WinForms.DialogResult.OK) - { - OutputDirectoryTextBox.Text = folderDialog.SelectedPath; - } + // Now set the selected item, if possible + int index = MediaTypes.FindIndex(kvp => kvp.Value == CurrentMediaType); + if (index != -1) + MediaTypeComboBox.SelectedIndex = index; + else + StatusLabel.Content = $"Disc of type '{Converters.LongName(CurrentMediaType)}' found, but the current system does not support it!"; } /// - /// Create a DumpEnvironment with all current settings + /// Set the drive speed based on reported maximum and user-defined option /// - /// Filled DumpEnvironment instance - private DumpEnvironment DetermineEnvironment() + private void SetSupportedDriveSpeed() { - // Populate the new environment - var env = new DumpEnvironment(_uiOptions.Options, - OutputDirectoryTextBox.Text, - OutputFilenameTextBox.Text, - DriveLetterComboBox.SelectedItem as Drive, - SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem, - MediaTypeComboBox.SelectedItem as MediaType?, - ParametersTextBox.Text); + // Set the drive speed list that's appropriate + var values = Constants.GetSpeedsForMediaType(CurrentMediaType); + DriveSpeedComboBox.ItemsSource = values; + ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values)); - // Disable automatic reprocessing of the textboxes until we're done - OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged; - OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged; - - OutputDirectoryTextBox.Text = env.OutputDirectory; - OutputFilenameTextBox.Text = env.OutputFilename; - - OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged; - OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged; - - return env; + // Set the selected speed + int speed = UIOptions.GetPreferredDumpSpeedForMediaType(CurrentMediaType); + ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", speed); + DriveSpeedComboBox.SelectedValue = speed; } /// @@ -450,7 +461,7 @@ namespace DICUI.Windows private async void StartDumping() { // One last check to determine environment, just in case - _env = DetermineEnvironment(); + Env = DetermineEnvironment(); // If still in custom parameter mode, check that users meant to continue or not if (EnableParametersCheckBox.IsChecked == true) @@ -468,12 +479,12 @@ namespace DICUI.Windows } // Fix the output paths - _env.FixOutputPaths(); + Env.FixOutputPaths(); try { // Validate that the user explicitly wants an inactive drive to be considered for dumping - if (!_env.Drive.MarkedActive) + if (!Env.Drive.MarkedActive) { MessageBoxResult mbresult = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None) @@ -484,7 +495,7 @@ namespace DICUI.Windows } // If a complete dump already exists - if (_env.FoundAllFiles()) + if (Env.FoundAllFiles()) { MessageBoxResult mbresult = MessageBox.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) @@ -506,10 +517,10 @@ namespace DICUI.Windows protectionProgress.ProgressChanged += ProgressUpdated; // Run the program with the parameters - Result result = await _env.Run(resultProgress); + Result result = await Env.Run(resultProgress); // If we didn't execute a dumping command we cannot get submission output - if (!_env.Parameters.IsDumpingCommand()) + if (!Env.Parameters.IsDumpingCommand()) { ViewModels.LoggerViewModel.VerboseLogLn("No dumping command was run, submission information will not be gathered."); StatusLabel.Content = "Execution complete!"; @@ -521,26 +532,26 @@ namespace DICUI.Windows if (result) { // Verify dump output and save it - result = await _env.VerifyAndSaveDumpOutput(resultProgress, + result = await Env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, EjectWhenDoneCheckBox.IsChecked, - _uiOptions.ResetDriveAfterDump, + UIOptions.ResetDriveAfterDump, (si) => { // lazy initialization - if (_discInformationWindow == null) + if (discInformationWindow == null) { - _discInformationWindow = new DiscInformationWindow(si); - _discInformationWindow.Closed += delegate + discInformationWindow = new DiscInformationWindow(si); + discInformationWindow.Closed += delegate { - _discInformationWindow = null; + discInformationWindow = null; }; } - _discInformationWindow.Owner = this; - _discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; - _discInformationWindow.Load(); - return _discInformationWindow.ShowDialog(); + discInformationWindow.Owner = this; + discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; + discInformationWindow.Load(); + return discInformationWindow.ShowDialog(); } ); } @@ -556,194 +567,291 @@ namespace DICUI.Windows } } + #endregion + + #region Event Handlers + /// - /// Ensure information is consistent with the currently selected disc type + /// Handler for AboutMenuItem Click event /// - private void EnsureDiscInformation() + private void AboutClick(object sender, RoutedEventArgs e) { - // Get the current environment information - _env = DetermineEnvironment(); + MessageBox.Show($"darksabre76 - Project Lead / Backend Design" + + $"{Environment.NewLine}ReignStumble - Former Project Lead / UI Design" + + $"{Environment.NewLine}Jakz - Primary Feature Contributor" + + $"{Environment.NewLine}NHellFire - Feature Contributor", "About", MessageBoxButton.OK, MessageBoxImage.Information); + } - // Take care of null cases - if (_env.System == null) - _env.System = KnownSystem.NONE; - if (_env.Type == null) - _env.Type = MediaType.NONE; + /// + /// Handler for AppExitMenuItem Click event + /// + private void AppExitClick(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + } - // Get the status to write out - Result result = Validators.GetSupportStatus(_env.System, _env.Type); - StatusLabel.Content = result.Message; + /// + /// Handler for CheckForUpdatesMenuItem Click event + /// + private void CheckForUpdatesClick(object sender, RoutedEventArgs e) + { + (bool different, string message, string url) = Tools.CheckForNewVersion(); - // Set the index for the current disc type + // If we have a new version, put it in the clipboard + if (different) + Clipboard.SetText(url); + + MessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information); + } + + /// + /// Handler for CopyProtectScanButton Click event + /// + private void CopyProtectScanButtonClick(object sender, RoutedEventArgs e) + { + ScanAndShowProtection(); + } + + /// + /// Handler for DriveLetterComboBox SelectionChanged event + /// + private void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) + { + CacheCurrentDiscType(); SetCurrentDiscType(); + GetOutputNames(true); + SetSupportedDriveSpeed(); + } - StartStopButton.IsEnabled = result && (_drives != null && _drives.Count > 0 ? true : false); + /// + /// Handler for DriveSpeedComboBox SelectionChanged event + /// + private void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) + { + EnsureDiscInformation(); + } - // If we're in a type that doesn't support drive speeds - DriveSpeedComboBox.IsEnabled = _env.Type.DoesSupportDriveSpeed(); - - // If input params are not enabled, generate the full parameters from the environment - if (!ParametersTextBox.IsEnabled) + /// + /// Handler for EnableParametersCheckBox Click event + /// + private void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e) + { + if (EnableParametersCheckBox.IsChecked == true) + ParametersTextBox.IsEnabled = true; + else { - string generated = _env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem); - if (generated != null) - ParametersTextBox.Text = generated; + ParametersTextBox.IsEnabled = false; + ProcessCustomParameters(); } } /// - /// Get the default output directory name from the currently selected drive + /// Handler for MediaTypeComboBox SelectionChanged event /// - /// Force an updated name if the drive letter changes - private void GetOutputNames(bool driveChanged) + private void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { - Drive drive = DriveLetterComboBox.SelectedItem as Drive; - KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem; - MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?; + // Only change the media type if the selection and not the list has changed + if (e.RemovedItems.Count == 1 && e.AddedItems.Count == 1) + { + CurrentMediaType = MediaTypeComboBox.SelectedItem as MediaType?; + SetSupportedDriveSpeed(); + } - // Set the output directory, if we changed drives or it's not already - if (driveChanged || string.IsNullOrEmpty(OutputDirectoryTextBox.Text)) - OutputDirectoryTextBox.Text = Path.Combine(_uiOptions.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty); - - // Get the extension for the file for the next two statements - string extension = _env.GetExtension(mediaType); - - // Set the output filename, if we changed drives or it's not already - if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text)) - OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? systemType.LongName()) + (extension ?? ".bin"); - - // If the extension for the file changed, update that automatically - else if (Path.GetExtension(OutputFilenameTextBox.Text) != extension) - OutputFilenameTextBox.Text = Path.GetFileNameWithoutExtension(OutputFilenameTextBox.Text) + (extension ?? ".bin"); + GetOutputNames(false); + EnsureDiscInformation(); } /// - /// Scan and show copy protection for the current disc + /// Handler for MediaScanButton Click event /// - private async void ScanAndShowProtection() + private void MediaScanButtonClick(object sender, RoutedEventArgs e) { - if (_env == null) - _env = DetermineEnvironment(); + PopulateDrives(); + } - if (_env.Drive.Letter != default(char)) + /// + /// Handler for MainWindow Activated event + /// + private void MainWindowActivated(object sender, EventArgs e) + { + if (logWindow.IsVisible && !this.Topmost) { - ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", _env.Drive.Letter); + logWindow.Topmost = true; + logWindow.Topmost = false; + } + } - var tempContent = StatusLabel.Content; - StatusLabel.Content = "Scanning for copy protection... this might take a while!"; - StartStopButton.IsEnabled = false; - DiskScanButton.IsEnabled = false; - CopyProtectScanButton.IsEnabled = false; + /// + /// Handler for MainWindow Closing event + /// + private void MainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e) + { + if (logWindow.IsVisible) + logWindow.Close(); + } - var progress = new Progress(); - progress.ProgressChanged += ProgressUpdated; - string protections = await Validators.RunProtectionScanOnPath(_env.Drive.Letter + ":\\", progress); + /// + /// Handler for MainWindow PositionChanged event + /// + private void MainWindowLocationChanged(object sender, EventArgs e) + { + if (logWindow.IsVisible) + logWindow.AdjustPositionToMainWindow(); + } - // If SmartE is detected on the current disc, remove `/sf` from the flags for DIC only - if (_env.InternalProgram == InternalProgram.DiscImageCreator && protections.Contains("SmartE")) + /// + /// Handler for MainWindow OnContentRendered event + /// + /// + protected override void OnContentRendered(EventArgs e) + { + base.OnContentRendered(e); + + if (alreadyShown) + return; + + alreadyShown = true; + + if (UIOptions.OpenLogWindowAtStartup) + { + //TODO: this should be bound directly to WindowVisible property in two way fashion + // we need to study how to properly do it in XAML + ShowLogMenuItem.IsChecked = true; + ViewModels.LoggerViewModel.WindowVisible = true; + } + + // Populate the list of systems + StatusLabel.Content = "Creating system list, please wait!"; + PopulateSystems(); + + // Populate the list of drives + StatusLabel.Content = "Creating drive list, please wait!"; + PopulateDrives(); + } + + /// + /// Handler for OptionsWindow OnUpdated event + /// + public void OnOptionsUpdated() + { + PopulateDrives(); + GetOutputNames(false); + SetSupportedDriveSpeed(); + EnsureDiscInformation(); + } + + /// + /// Handler for OptionsMenuItem Click event + /// + /// TODO: Re-evaluate this based on Avalonia code + private void OptionsMenuItemClick(object sender, RoutedEventArgs e) + { + // lazy initialization + if (optionsWindow == null) + { + optionsWindow = new OptionsWindow(this, UIOptions); + optionsWindow.Closed += delegate { - ((DiscImageCreator.Parameters)_env.Parameters)[DiscImageCreator.Flag.ScanFileProtect] = false; - ViewModels.LoggerViewModel.VerboseLogLn($"SmartE detected, removing {DiscImageCreator.FlagStrings.ScanFileProtect} from parameters"); + optionsWindow = null; + }; + } + + optionsWindow.Owner = this; + optionsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; + optionsWindow.Refresh(); + optionsWindow.Show(); + } + + /// + /// Handler for OutputDirectoryBrowseButton Click event + /// + private void OutputDirectoryBrowseButtonClick(object sender, RoutedEventArgs e) + { + BrowseFolder(); + EnsureDiscInformation(); + } + + /// + /// Handler for OutputFilenameTextBox TextInput event + /// + private void OutputDirectoryTextBoxTextChanged(object sender, TextChangedEventArgs e) + { + EnsureDiscInformation(); + } + + /// + /// Handler for OutputFilenameTextBox TextInput event + /// + private void OutputFilenameTextBoxTextChanged(object sender, TextChangedEventArgs e) + { + EnsureDiscInformation(); + } + + /// + /// Handler for Result ProgressChanged event + /// + private void ProgressUpdated(object sender, Result value) + { + StatusLabel.Content = value.Message; + ViewModels.LoggerViewModel.VerboseLogLn(value.Message); + } + + /// + /// Handler for FileProtection ProgressChanged event + /// + private void ProgressUpdated(object sender, FileProtection value) + { + string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}"; + StatusLabel.Content = message; + ViewModels.LoggerViewModel.VerboseLogLn(message); + } + + /// + /// Handler for StartStopButton Click event + /// + private void StartStopButtonClick(object sender, RoutedEventArgs e) + { + // Dump or stop the dump + if ((string)StartStopButton.Content == Constants.StartDumping) + { + StartDumping(); + } + else if ((string)StartStopButton.Content == Constants.StopDumping) + { + ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process..."); + Env.CancelDumping(); + CopyProtectScanButton.IsEnabled = true; + + if (EjectWhenDoneCheckBox.IsChecked == true) + { + ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {Env.Drive.Letter}"); + Env.EjectDisc(); } - if (!ViewModels.LoggerViewModel.WindowVisible) - MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information); - ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", _env.Drive.Letter, protections); - - StatusLabel.Content = tempContent; - StartStopButton.IsEnabled = true; - DiskScanButton.IsEnabled = true; - CopyProtectScanButton.IsEnabled = true; + if (UIOptions.ResetDriveAfterDump) + { + ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {Env.Drive.Letter}"); + Env.ResetDrive(); + } } } /// - /// Set the drive speed based on reported maximum and user-defined option + /// Handler for SystemTypeComboBox SelectionChanged event /// - private void SetSupportedDriveSpeed() + private void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { - // Set the drive speed list that's appropriate - var values = Constants.GetSpeedsForMediaType(_currentMediaType); - DriveSpeedComboBox.ItemsSource = values; - ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values)); - - // Set the selected speed - int speed = _uiOptions.GetPreferredDumpSpeedForMediaType(_currentMediaType); - ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", speed); - DriveSpeedComboBox.SelectedValue = speed; - } - - /// - /// Cache the current disc type to internal variable - /// - private void CacheCurrentDiscType() - { - // Get the drive letter from the selected item - var drive = DriveLetterComboBox.SelectedItem as Drive; - if (drive == null) - return; - - // Get the current media type - if (!_uiOptions.SkipMediaTypeDetection) + // If we're on a separator, go to the next item and return + if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader()) { - ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter); - _currentMediaType = Validators.GetMediaType(drive); - ViewModels.LoggerViewModel.VerboseLogLn(_currentMediaType == null ? "unable to detect." : ("detected " + _currentMediaType.LongName() + ".")); + SystemTypeComboBox.SelectedIndex++; + return; } - } - /// - /// Set the current disc type in the combo box - /// - 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 (index != -1) - MediaTypeComboBox.SelectedIndex = index; - else - StatusLabel.Content = $"Disc of type '{Converters.LongName(_currentMediaType)}' found, but the current system does not support it!"; - } - - /// - /// Process the current custom parameters back into UI values - /// - private void ProcessCustomParameters() - { - _env.SetParameters(ParametersTextBox.Text); - if (_env.Parameters == null) - return; - - int driveIndex = _drives.Select(d => d.Letter).ToList().IndexOf(_env.Parameters.InputPath()[0]); - if (driveIndex > -1) - DriveLetterComboBox.SelectedIndex = driveIndex; - - int driveSpeed = _env.Parameters.GetSpeed() ?? -1; - if (driveSpeed > 0) - DriveSpeedComboBox.SelectedValue = driveSpeed; - else - _env.Parameters.SetSpeed((int?)DriveSpeedComboBox.SelectedValue); - - string trimmedPath = _env.Parameters.OutputPath()?.Trim('"') ?? string.Empty; - string outputDirectory = Path.GetDirectoryName(trimmedPath); - string outputFilename = Path.GetFileName(trimmedPath); - if (!string.IsNullOrWhiteSpace(outputDirectory)) - OutputDirectoryTextBox.Text = outputDirectory; - else - outputDirectory = OutputDirectoryTextBox.Text; - if (!string.IsNullOrWhiteSpace(outputFilename)) - OutputFilenameTextBox.Text = outputFilename; - else - outputFilename = OutputFilenameTextBox.Text; - - MediaType? mediaType = _env.Parameters.GetMediaType(); - int mediaTypeIndex = _mediaTypes.IndexOf(mediaType); - if (mediaTypeIndex > -1) - MediaTypeComboBox.SelectedIndex = mediaTypeIndex; + ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name); + PopulateMediaType(); + GetOutputNames(false); + EnsureDiscInformation(); } #endregion