From: sr55 Date: Sat, 4 Mar 2017 17:22:26 +0000 (+0000) Subject: WinGui: Rework of the preset system X-Git-Tag: 1.1.0~666 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=45eb6a58ae7fd4e0f84d9e64eb78def0eebfe274;p=handbrake WinGui: Rework of the preset system - Better support for categories. - Switched from a List to Treeview Control. - Remember the expansion state of each group - Put User Presets on top after next save. Closes #445 --- diff --git a/win/CS/HandBrakeWPF/Converters/PresetsMenuConverter.cs b/win/CS/HandBrakeWPF/Converters/PresetsMenuConverter.cs index 098d9e952..bbcfd891d 100644 --- a/win/CS/HandBrakeWPF/Converters/PresetsMenuConverter.cs +++ b/win/CS/HandBrakeWPF/Converters/PresetsMenuConverter.cs @@ -11,13 +11,13 @@ namespace HandBrakeWPF.Converters { using System; using System.Collections.Generic; - using System.Linq; using System.Globalization; + using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; - using HandBrakeWPF.Commands; + using HandBrakeWPF.Services.Presets.Interfaces; using HandBrakeWPF.Services.Presets.Model; /// @@ -33,7 +33,7 @@ namespace HandBrakeWPF.Converters /// The culture to use in the converter. public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - IEnumerable presets = value as IEnumerable; + IEnumerable presets = value as IEnumerable; if (presets == null) { @@ -41,31 +41,19 @@ namespace HandBrakeWPF.Converters } Dictionary groupedMenu = new Dictionary(); - foreach (Preset item in presets) + foreach (IPresetObject item in presets) { - if (groupedMenu.ContainsKey(item.Category)) + PresetDisplayCategory category = item as PresetDisplayCategory; + if (category != null) { - MenuItem newMeuItem = new MenuItem { Header = item.Name, Tag = item, Command = new PresetMenuSelectCommand(item) }; - if (item.IsDefault) - { - newMeuItem.FontStyle = FontStyles.Italic; - } - - groupedMenu[item.Category].Items.Add(newMeuItem); + ProcessCategory(groupedMenu, category); + continue; } - else - { - MenuItem group = new MenuItem(); - group.Header = item.Category; - - MenuItem newMeuItem = new MenuItem { Header = item.Name, Tag = item, Command = new PresetMenuSelectCommand(item) }; - if (item.IsDefault) - { - newMeuItem.FontStyle = FontStyles.Italic; - } - group.Items.Add(newMeuItem); - groupedMenu[item.Category] = group; + Preset preset = item as Preset; + if (preset != null) + { + ProcessPreset(groupedMenu, preset); } } @@ -82,5 +70,41 @@ namespace HandBrakeWPF.Converters { throw new NotImplementedException(); } + + private void ProcessPreset(Dictionary groupedMenu, Preset preset) + { + if (groupedMenu.ContainsKey(preset.Category)) + { + MenuItem newMeuItem = new MenuItem { Header = preset.Name, Tag = preset, Command = new PresetMenuSelectCommand(preset) }; + if (preset.IsDefault) + { + newMeuItem.FontStyle = FontStyles.Italic; + } + + groupedMenu[preset.Category].Items.Add(newMeuItem); + } + else + { + MenuItem group = new MenuItem(); + group.Header = preset.Category; + + MenuItem newMeuItem = new MenuItem { Header = preset.Name, Tag = preset, Command = new PresetMenuSelectCommand(preset) }; + if (preset.IsDefault) + { + newMeuItem.FontStyle = FontStyles.Italic; + } + + group.Items.Add(newMeuItem); + groupedMenu[preset.Category] = group; + } + } + + private void ProcessCategory(Dictionary groupedMenu, PresetDisplayCategory category) + { + foreach (Preset preset in category.Presets) + { + this.ProcessPreset(groupedMenu, preset); + } + } } } diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index e28bec1dd..d37f10acd 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -171,6 +171,7 @@ + @@ -224,6 +225,8 @@ + + diff --git a/win/CS/HandBrakeWPF/Helpers/TreeViewHelper.cs b/win/CS/HandBrakeWPF/Helpers/TreeViewHelper.cs new file mode 100644 index 000000000..99b458859 --- /dev/null +++ b/win/CS/HandBrakeWPF/Helpers/TreeViewHelper.cs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// Helper functions for handling structures +// Based of https://social.technet.microsoft.com/wiki/contents/articles/18188.wpf-treeview-selecteditem-twoway-mvvm-plus-expand-to-selected-and-close-all-others.aspx +// +// -------------------------------------------------------------------------------------------------------------------- +namespace HandBrakeWPF.Helpers +{ + using System.Windows; + using System.Windows.Controls; + + public class TreeViewHelper + { + public static object GetTreeViewSelectedItem(DependencyObject obj) + { + return (object)obj.GetValue(TreeViewSelectedItemProperty); + } + + public static void SetTreeViewSelectedItem(DependencyObject obj, object value) + { + obj.SetValue(TreeViewSelectedItemProperty, value); + } + + public static readonly DependencyProperty TreeViewSelectedItemProperty = + DependencyProperty.RegisterAttached("TreeViewSelectedItem", typeof(object), typeof(TreeViewHelper), new PropertyMetadata(new object(), TreeViewSelectedItemChanged)); + + private static void TreeViewSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + TreeView treeView = sender as TreeView; + if (treeView == null) + { + return; + } + + treeView.SelectedItemChanged -= TreeView_SelectedItemChanged; + treeView.SelectedItemChanged += TreeView_SelectedItemChanged; + + TreeViewItem thisItem = treeView.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem; + if (thisItem != null) + { + thisItem.IsSelected = true; + return; + } + + for (int i = 0; i < treeView.Items.Count; i++) + { + if (SelectItem(e.NewValue, treeView.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem)) + { + return; // Break out the loop. We've found the item and expanded it's parent if necessary. + } + } + } + + private static void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + TreeView treeView = sender as TreeView; + SetTreeViewSelectedItem(treeView, e.NewValue); + } + + private static bool SelectItem(object o, TreeViewItem parentItem) + { + bool found = false; + foreach (var item in parentItem.Items) + { + if (item.Equals(o)) + { + found = true; + break; + } + } + + if (found) + { + bool isExpanded = parentItem.IsExpanded; + if (!isExpanded) + { + parentItem.IsExpanded = true; + parentItem.UpdateLayout(); + } + } + + return found; + } + } +} \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetObject.cs b/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetObject.cs new file mode 100644 index 000000000..07c3d4d1b --- /dev/null +++ b/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetObject.cs @@ -0,0 +1,17 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// The Preset Service Interface +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Services.Presets.Interfaces +{ + public interface IPresetObject + { + bool IsSelected { get; set; } + string Category { get; } + } +} \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetService.cs b/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetService.cs index fb46b932f..f75c054c5 100644 --- a/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetService.cs +++ b/win/CS/HandBrakeWPF/Services/Presets/Interfaces/IPresetService.cs @@ -23,7 +23,7 @@ namespace HandBrakeWPF.Services.Presets.Interfaces /// /// Gets a Collection of presets. /// - ObservableCollection Presets { get; } + ObservableCollection Presets { get; } /// /// Gets DefaultPreset. @@ -35,6 +35,16 @@ namespace HandBrakeWPF.Services.Presets.Interfaces /// void Load(); + /// + /// Save the state of the Preset Treview + /// + void SaveCategoryStates(); + + /// + /// Load the state of the Preset Treeview. + /// + void LoadCategoryStates(); + /// /// Add a new preset to the system /// @@ -83,7 +93,10 @@ namespace HandBrakeWPF.Services.Presets.Interfaces /// /// The Preset to remove /// - void Remove(Preset preset); + /// + /// True if it was removed successfully, false otherwise. + /// + bool Remove(Preset preset); /// /// Remove a group of presets by category @@ -155,5 +168,11 @@ namespace HandBrakeWPF.Services.Presets.Interfaces /// The replacement. /// void Replace(Preset existing, Preset replacement); + + /// + /// Set the selected preset + /// + /// The preset we want to select. + void SetSelected(Preset selectedPreset); } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/Presets/Model/Preset.cs b/win/CS/HandBrakeWPF/Services/Presets/Model/Preset.cs index 8b6aee917..5f179f67e 100644 --- a/win/CS/HandBrakeWPF/Services/Presets/Model/Preset.cs +++ b/win/CS/HandBrakeWPF/Services/Presets/Model/Preset.cs @@ -11,6 +11,7 @@ namespace HandBrakeWPF.Services.Presets.Model { using HandBrakeWPF.Model.Audio; using HandBrakeWPF.Model.Subtitles; + using HandBrakeWPF.Services.Presets.Interfaces; using HandBrakeWPF.Utilities; using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask; @@ -24,7 +25,7 @@ namespace HandBrakeWPF.Services.Presets.Model /// https://github.com/Caliburn-Micro/Caliburn.Micro/issues/89 /// https://github.com/Caliburn-Micro/Caliburn.Micro/issues/96 /// - public class Preset : PropertyChangedBase // Delibery not + public class Preset : PropertyChangedBase, IPresetObject // Delibery not { #region Constants and Fields @@ -33,6 +34,8 @@ namespace HandBrakeWPF.Services.Presets.Model /// private bool isDefault; + private bool isSelected; + #endregion /// @@ -72,6 +75,24 @@ namespace HandBrakeWPF.Services.Presets.Model /// public string Description { get; set; } + /// + /// Reflects the visual state of this preset. + /// + public bool IsExpanded { get; set; } + + public bool IsSelected + { + get + { + return this.isSelected; + } + set + { + this.isSelected = value; + this.NotifyOfPropertyChange(() => this.IsSelected); + } + } + /// /// Gets or sets a value indicating whether this is a built in preset /// diff --git a/win/CS/HandBrakeWPF/Services/Presets/Model/PresetDisplayCategory.cs b/win/CS/HandBrakeWPF/Services/Presets/Model/PresetDisplayCategory.cs new file mode 100644 index 000000000..95d2213fb --- /dev/null +++ b/win/CS/HandBrakeWPF/Services/Presets/Model/PresetDisplayCategory.cs @@ -0,0 +1,78 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// A Preset Category encoding with. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Services.Presets.Model +{ + using System.ComponentModel; + using Caliburn.Micro; + using HandBrakeWPF.Services.Presets.Interfaces; + + public class PresetDisplayCategory : PropertyChangedBase, IPresetObject + { + private bool isSelected; + private bool isExpanded; + + public PresetDisplayCategory(string category, BindingList presets) + { + this.Category = category; + this.Presets = presets; + } + + public string Category { get; private set; } + public BindingList Presets { get; private set; } + + public string Description => this.Category; + + public bool IsExpanded + { + get + { + return this.isExpanded; + } + set + { + if (value == this.isExpanded) return; + this.isExpanded = value; + this.NotifyOfPropertyChange(() => this.IsExpanded); + } + } + + public bool IsSelected + { + get + { + return this.isSelected; + } + set + { + if (value == this.isSelected) return; + this.isSelected = value; + this.NotifyOfPropertyChange(() => this.IsSelected); + } + } + + protected bool Equals(PresetDisplayCategory other) + { + return string.Equals(this.Category, other.Category); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((PresetDisplayCategory)obj); + } + + public override int GetHashCode() + { + return (this.Category != null ? this.Category.GetHashCode() : 0); + } + } +} diff --git a/win/CS/HandBrakeWPF/Services/Presets/PresetService.cs b/win/CS/HandBrakeWPF/Services/Presets/PresetService.cs index 78387e54e..a90bf1543 100644 --- a/win/CS/HandBrakeWPF/Services/Presets/PresetService.cs +++ b/win/CS/HandBrakeWPF/Services/Presets/PresetService.cs @@ -12,6 +12,8 @@ namespace HandBrakeWPF.Services.Presets using System; using System.Collections.Generic; using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -46,7 +48,8 @@ namespace HandBrakeWPF.Services.Presets public const int ForcePresetReset = 3; public static string UserPresetCatgoryName = "User Presets"; private readonly string presetFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()), "presets.json"); - private readonly ObservableCollection presets = new ObservableCollection(); + private readonly ObservableCollection presets = new ObservableCollection(); // Can store Presets and PresetDisplayCategory objects. + private readonly Dictionary flatPresetList = new Dictionary(); private readonly IErrorService errorService; private readonly IUserSettingService userSettingService; @@ -70,7 +73,7 @@ namespace HandBrakeWPF.Services.Presets /// /// Gets a Collection of presets. /// - public ObservableCollection Presets + public ObservableCollection Presets { get { @@ -85,7 +88,7 @@ namespace HandBrakeWPF.Services.Presets { get { - return this.presets.FirstOrDefault(p => p.IsDefault); + return this.flatPresetList.Values.FirstOrDefault(p => p.IsDefault); } } @@ -100,12 +103,18 @@ namespace HandBrakeWPF.Services.Presets if (!File.Exists(this.presetFile)) { this.UpdateBuiltInPresets(); + return; } // Load the presets from file this.LoadPresets(); } + public bool Add(Preset preset) + { + return this.Add(preset, false); + } + /// /// Add a new preset to the system. /// Performs an Update if it already exists @@ -113,23 +122,45 @@ namespace HandBrakeWPF.Services.Presets /// /// A Preset to add /// + /// + /// Prevents Saving of presets. + /// /// /// True if added, /// False if name already exists /// - public bool Add(Preset preset) + public bool Add(Preset preset, bool isLoading) { if (!this.CheckIfPresetExists(preset.Name)) { - this.presets.Add(preset); + // Check to see if the category already exists. + PresetDisplayCategory category = this.presets.FirstOrDefault(a => a.Category == preset.Category) as PresetDisplayCategory; // TODO build Dict for this. + if (category != null) + { + category.Presets.Add(preset); + } + else if (!string.IsNullOrEmpty(preset.Category)) + { + // Otherwise, if we have category but it doesn't exist, create it. + this.presets.Add(new PresetDisplayCategory(preset.Category, new BindingList { preset })); + } + else + { + // Preset has no category. + this.presets.Add(preset); + } + + this.flatPresetList.Add(preset.Name, preset); // Update the presets file - this.SavePresetFiles(); + if (!isLoading) + { + this.SavePresetFiles(); + } return true; } - this.Update(preset); - return true; + return false; } /// @@ -170,7 +201,7 @@ namespace HandBrakeWPF.Services.Presets try { preset = JsonPresetFactory.ImportPreset(hbPreset); - preset.Category = UserPresetCatgoryName; + preset.Category = UserPresetCatgoryName; // TODO can we get this from the preset? // IF we are using Source Max, Set the Max Width / Height values. if (preset.PictureSettingsMode == PresetPictureSettingsMode.SourceMaximum) @@ -206,13 +237,10 @@ namespace HandBrakeWPF.Services.Presets } else { - this.Add(preset); + this.Add(preset, false); } } } - - // Category Handling. - // TODO maybe for a future release. } } @@ -243,22 +271,18 @@ namespace HandBrakeWPF.Services.Presets /// public void Update(Preset update) { - // TODO - Change this to be a lookup - foreach (Preset preset in this.presets) + Preset preset; + if (this.flatPresetList.TryGetValue(update.Name, out preset)) { - if (preset.Name == update.Name) - { - preset.Task = update.Task; - preset.PictureSettingsMode = update.PictureSettingsMode; - preset.Category = update.Category; - preset.Description = update.Description; - preset.AudioTrackBehaviours = update.AudioTrackBehaviours; - preset.SubtitleTrackBehaviours = update.SubtitleTrackBehaviours; - - // Update the presets file - this.SavePresetFiles(); - break; - } + preset.Task = update.Task; + preset.PictureSettingsMode = update.PictureSettingsMode; + preset.Category = update.Category; + preset.Description = update.Description; + preset.AudioTrackBehaviours = update.AudioTrackBehaviours; + preset.SubtitleTrackBehaviours = update.SubtitleTrackBehaviours; + + // Update the presets file + this.SavePresetFiles(); } } @@ -274,7 +298,7 @@ namespace HandBrakeWPF.Services.Presets public void Replace(Preset existing, Preset replacement) { this.Remove(existing); - this.Add(replacement); + this.Add(replacement, false); } /// @@ -283,54 +307,86 @@ namespace HandBrakeWPF.Services.Presets /// /// The Preset to remove /// - public void Remove(Preset preset) + /// True if successfully removed, false otherwise. + public bool Remove(Preset preset) { if (preset == null || preset.IsDefault) { - return; + return false; + } + + PresetDisplayCategory cateogry = this.presets.FirstOrDefault(p => p.Category == preset.Category) as PresetDisplayCategory; + if (cateogry != null) + { + // Remove the preset, and cleanup the category if it's not got any presets in it. + cateogry.Presets.Remove(preset); + this.flatPresetList.Remove(preset.Name); + if (cateogry.Presets.Count == 0) + { + this.presets.Remove(cateogry); + } + } + else + { + this.presets.Remove(preset); + this.flatPresetList.Remove(preset.Name); } - this.presets.Remove(preset); this.SavePresetFiles(); + + return true; } /// /// Remove a group of presets by category /// - /// + /// /// The Category to remove /// - public void RemoveGroup(string category) + public void RemoveGroup(string categoryName) { - List removeList = this.presets.Where(p => p.Category == category).ToList(); - foreach (Preset preset in removeList) + PresetDisplayCategory category = this.presets.FirstOrDefault(p => p.Category == categoryName) as PresetDisplayCategory; + if (category != null) { - if (preset.IsDefault) + foreach (Preset preset in category.Presets) { - // Skip default preset - continue; + if (preset.IsDefault) + { + // Skip default preset + continue; + } + + this.presets.Remove(preset); + this.flatPresetList.Remove(preset.Name); } - this.presets.Remove(preset); - } + // Cleanup the category if we can. + if (category.Presets.Count == 0) + { + this.presets.Remove(category); + } - this.SavePresetFiles(); + this.SavePresetFiles(); + } } /// /// Set Default Preset /// - /// + /// /// The name. /// - public void SetDefault(Preset name) + public void SetDefault(Preset preset) { - foreach (Preset preset in this.presets) + // Set IsDefault false for everything. + foreach (Preset item in this.flatPresetList.Values) { - preset.IsDefault = false; + item.IsDefault = false; } - name.IsDefault = true; + // Set the new preset to default. + preset.IsDefault = true; + this.SavePresetFiles(); } @@ -345,7 +401,13 @@ namespace HandBrakeWPF.Services.Presets /// public Preset GetPreset(string name) { - return this.presets.FirstOrDefault(item => item.Name == name); + Preset preset; + if (this.flatPresetList.TryGetValue(name, out preset)) + { + return preset; + } + + return null; } /// @@ -353,10 +415,54 @@ namespace HandBrakeWPF.Services.Presets /// public void ClearBuiltIn() { - List remove = this.presets.Where(p => p.IsBuildIn).ToList(); - foreach (Preset preset in remove) + List topLevel = new List(); + foreach (IPresetObject item in this.presets) { - this.presets.Remove(preset); + // We either have a Preset + Preset foundPreset = item as Preset; + if (foundPreset != null && foundPreset.IsBuildIn) + { + topLevel.Add(item); + } + + // Or a Category. + PresetDisplayCategory foundCategory = item as PresetDisplayCategory; + if (foundCategory != null) + { + // Find all the presets in this category to remove + List presetsToRemove = new List(); + foreach (Preset categoryPreset in foundCategory.Presets) + { + if (categoryPreset.IsBuildIn) + { + presetsToRemove.Add(categoryPreset); + } + } + + // Then remove them. + foreach (Preset toRemove in presetsToRemove) + { + foundCategory.Presets.Remove(toRemove); + this.flatPresetList.Remove(toRemove.Name); + } + + // Check if we can remove this category. + if (foundCategory.Presets.Count == 0) + { + topLevel.Add(foundCategory); + } + } + } + + // Remove any top level items we need to remove. + foreach (var item in topLevel) + { + this.presets.Remove(item); + + if (item.GetType() == typeof(Preset)) + { + this.flatPresetList.Remove(((Preset)item).Name); + } } } @@ -366,6 +472,7 @@ namespace HandBrakeWPF.Services.Presets public void ClearAll() { this.presets.Clear(); + this.flatPresetList.Clear(); } /// @@ -385,15 +492,9 @@ namespace HandBrakeWPF.Services.Presets Preset preset = JsonPresetFactory.ImportPreset(hbpreset); preset.IsBuildIn = true; preset.Category = category.PresetName; - - if (preset.Name == "iPod") - { - preset.Task.KeepDisplayAspect = true; - } - preset.Task.AllowedPassthruOptions = new AllowedPassthru(true); // We don't want to override the built-in preset - this.presets.Add(preset); + this.Add(preset, true); } } @@ -418,7 +519,12 @@ namespace HandBrakeWPF.Services.Presets /// public bool CheckIfPresetExists(string name) { - return name == string.Empty || this.presets.Any(item => item.Name == name); + if (this.flatPresetList.ContainsKey(name)) + { + return true; + } + + return false; } /// @@ -432,7 +538,60 @@ namespace HandBrakeWPF.Services.Presets /// public bool CanUpdatePreset(string name) { - return this.presets.Where(preset => preset.Name == name).Any(preset => preset.IsBuildIn == false); + Preset preset; + if (this.flatPresetList.TryGetValue(name, out preset)) + { + return !preset.IsBuildIn; + } + + return true; + } + + /// + /// Set the selected preset + /// + /// The preset we want to select. + public void SetSelected(Preset selectedPreset) + { + foreach (var item in this.flatPresetList.Values) + { + item.IsSelected = false; + } + + selectedPreset.IsSelected = true; + } + + public void SaveCategoryStates() + { + StringCollection expandedPresets = new StringCollection(); + foreach (IPresetObject presetObject in this.presets) + { + PresetDisplayCategory category = presetObject as PresetDisplayCategory; + if (category != null && category.IsExpanded) + { + expandedPresets.Add(category.Category); + } + } + + this.userSettingService.SetUserSetting(UserSettingConstants.PresetExpandedStateList, expandedPresets); + } + + public void LoadCategoryStates() + { + StringCollection expandedPresets = this.userSettingService.GetUserSetting(UserSettingConstants.PresetExpandedStateList); + if (expandedPresets == null || expandedPresets.Count == 0) + { + return; + } + + foreach (IPresetObject presetObject in this.presets) + { + PresetDisplayCategory category = presetObject as PresetDisplayCategory; + if (category != null && expandedPresets.Contains(category.Category)) + { + category.IsExpanded = true; + } + } } #endregion @@ -609,7 +768,7 @@ namespace HandBrakeWPF.Services.Presets preset.Task.MaxHeight = preset.Task.Width; } - this.presets.Add(preset); + this.Add(preset, true); } } @@ -629,7 +788,7 @@ namespace HandBrakeWPF.Services.Presets preset.Task.MaxHeight = preset.Task.Width; } - this.presets.Add(preset); + this.Add(preset, true); } } } @@ -658,7 +817,7 @@ namespace HandBrakeWPF.Services.Presets // Orgamise the Presets list into Json Equivilent objects. Dictionary presetCategories = new Dictionary(); List uncategorisedPresets = new List(); - foreach (Preset item in this.presets) + foreach (Preset item in this.flatPresetList.Values.OrderBy(o => o.IsBuildIn)) // Handle User Presets first. { if (string.IsNullOrEmpty(item.Category)) { diff --git a/win/CS/HandBrakeWPF/UserSettingConstants.cs b/win/CS/HandBrakeWPF/UserSettingConstants.cs index 80b740b90..a5ba0c7ff 100644 --- a/win/CS/HandBrakeWPF/UserSettingConstants.cs +++ b/win/CS/HandBrakeWPF/UserSettingConstants.cs @@ -226,6 +226,11 @@ namespace HandBrakeWPF /// public const string ForcePresetReset = "ForcePresetReset"; + /// + /// Setting to record the expansion state of preset categories. + /// + public const string PresetExpandedStateList = "PresetExpandedStateList"; + #endregion } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/ViewModels/Interfaces/IMainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/Interfaces/IMainViewModel.cs index 17f460123..bcc72b9dd 100644 --- a/win/CS/HandBrakeWPF/ViewModels/Interfaces/IMainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/Interfaces/IMainViewModel.cs @@ -11,8 +11,6 @@ namespace HandBrakeWPF.ViewModels.Interfaces { using System.Windows; - using HandBrakeWPF.Services.Presets.Model; - using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask; /// @@ -20,11 +18,6 @@ namespace HandBrakeWPF.ViewModels.Interfaces /// public interface IMainViewModel { - /// - /// Sets SelectedPreset. - /// - Preset SelectedPreset { set; } - /// /// The preset select. /// diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index db7c608ff..f48902aec 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -18,6 +18,7 @@ namespace HandBrakeWPF.ViewModels using System.Linq; using System.Threading; using System.Windows; + using System.Windows.Data; using System.Windows.Input; using Caliburn.Micro; @@ -206,7 +207,7 @@ namespace HandBrakeWPF.ViewModels this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeStatusChanged; this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged; - this.Presets = this.presetService.Presets; + this.Presets = new BindingList(); this.Drives = new BindingList(); // Set Process Priority @@ -359,22 +360,30 @@ namespace HandBrakeWPF.ViewModels /// /// Gets or sets Presets. /// - public IEnumerable Presets { get; set; } + public IEnumerable Presets { get; set; } /// /// Gets or sets SelectedPreset. /// - public Preset SelectedPreset + public object SelectedPreset { get { return this.selectedPreset; } + set { - this.selectedPreset = value; + if (value == null || value.GetType() != typeof(Preset)) + { + return; + } + + this.selectedPreset = (Preset)value; - if (this.SelectedPreset != null) + this.presetService.SetSelected(selectedPreset); + + if (this.selectedPreset != null) { // Main Window Settings this.OptimizeMP4 = selectedPreset.Task.OptimizeMP4; @@ -382,14 +391,14 @@ namespace HandBrakeWPF.ViewModels this.SelectedOutputFormat = selectedPreset.Task.OutputFormat; // Tab Settings - this.PictureSettingsViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.VideoViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.FiltersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.AudioViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.SubtitleViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.ChaptersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.AdvancedViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); - this.MetaDataViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); + this.PictureSettingsViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.VideoViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.FiltersViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.AudioViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.SubtitleViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.ChaptersViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.AdvancedViewModel.SetPreset(this.selectedPreset, this.CurrentTask); + this.MetaDataViewModel.SetPreset(this.selectedPreset, this.CurrentTask); // Do this again to force an update for m4v/mp4 selection this.SelectedOutputFormat = selectedPreset.Task.OutputFormat; @@ -399,6 +408,12 @@ namespace HandBrakeWPF.ViewModels } } + public void TrickPresetDisplayUpdate() + { + this.NotifyOfPropertyChange(() => this.SelectedPreset); + this.selectedPreset.IsSelected = true; + } + /// /// Optimise MP4 Checkbox /// @@ -787,7 +802,7 @@ namespace HandBrakeWPF.ViewModels { if (this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null) { - this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); + this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset); } } this.NotifyOfPropertyChange(() => this.CurrentTask); @@ -842,7 +857,7 @@ namespace HandBrakeWPF.ViewModels if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters)) { - this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); + this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset); } } @@ -871,7 +886,7 @@ namespace HandBrakeWPF.ViewModels if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters)) { - this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); + this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset); } if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters) @@ -1243,7 +1258,9 @@ namespace HandBrakeWPF.ViewModels // Setup the presets. this.presetService.Load(); + this.Presets = this.presetService.Presets; this.NotifyOfPropertyChange(() => this.Presets); + this.presetService.LoadCategoryStates(); // Queue Recovery bool queueRecovered = QueueRecoveryHelper.RecoverQueue(this.queueProcessor, this.errorService, StartupOptions.AutoRestartQueue); @@ -1287,6 +1304,7 @@ namespace HandBrakeWPF.ViewModels { // Shutdown Service this.encodeService.Stop(); + this.presetService.SaveCategoryStates(); // Unsubscribe from Events. this.scanService.ScanStarted -= this.ScanStared; @@ -1876,9 +1894,11 @@ namespace HandBrakeWPF.ViewModels /// public void PresetAdd() { + // TODO select the new preset. IAddPresetViewModel presetViewModel = IoC.Get(); presetViewModel.Setup(this.CurrentTask, this.SelectedTitle, this.AudioViewModel.AudioBehaviours, this.SubtitleViewModel.SubtitleBehaviours); - this.windowManager.ShowWindow(presetViewModel); + this.windowManager.ShowDialog(presetViewModel); + this.NotifyOfPropertyChange(() => this.Presets); } /// @@ -1894,7 +1914,7 @@ namespace HandBrakeWPF.ViewModels return; } - if (this.SelectedPreset.IsBuildIn) + if (this.selectedPreset.IsBuildIn) { this.errorService.ShowMessageBox( Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); @@ -1903,8 +1923,8 @@ namespace HandBrakeWPF.ViewModels if (this.errorService.ShowMessageBox(Resources.Main_PresetUpdateConfrimation, Resources.AreYouSure, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { - this.SelectedPreset.Update(new EncodeTask(this.CurrentTask), new AudioBehaviours(this.AudioViewModel.AudioBehaviours), new SubtitleBehaviours(this.SubtitleViewModel.SubtitleBehaviours)); - this.presetService.Update(this.SelectedPreset); + this.selectedPreset.Update(new EncodeTask(this.CurrentTask), new AudioBehaviours(this.AudioViewModel.AudioBehaviours), new SubtitleBehaviours(this.SubtitleViewModel.SubtitleBehaviours)); + this.presetService.Update(this.selectedPreset); this.errorService.ShowMessageBox( Resources.Main_PresetUpdated, Resources.Updated, MessageBoxButton.OK, MessageBoxImage.Information); @@ -1924,7 +1944,7 @@ namespace HandBrakeWPF.ViewModels return; } - if (this.SelectedPreset.IsBuildIn) + if (this.selectedPreset.IsBuildIn) { this.errorService.ShowMessageBox( Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); @@ -1932,7 +1952,7 @@ namespace HandBrakeWPF.ViewModels } IManagePresetViewModel presetViewModel = IoC.Get(); - presetViewModel.Setup(this.SelectedPreset); + presetViewModel.Setup(this.selectedPreset); this.windowManager.ShowDialog(presetViewModel); Preset preset = presetViewModel.Preset; @@ -1970,6 +1990,7 @@ namespace HandBrakeWPF.ViewModels } this.presetService.Remove(this.selectedPreset); + this.NotifyOfPropertyChange(() => this.Presets); } else { @@ -1985,7 +2006,6 @@ namespace HandBrakeWPF.ViewModels if (this.selectedPreset != null) { this.presetService.SetDefault(this.selectedPreset); - this.NotifyOfPropertyChange(() => this.Presets); MessageBox.Show(string.Format(Resources.Main_NewDefaultPreset, this.selectedPreset.Name), Resources.Main_Presets, MessageBoxButton.OK, MessageBoxImage.Information); } else @@ -2195,14 +2215,14 @@ namespace HandBrakeWPF.ViewModels // Setup the Tabs if (this.selectedTitle != null) { - this.PictureSettingsViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.VideoViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.FiltersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.AudioViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.SubtitleViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.ChaptersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.AdvancedViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); - this.MetaDataViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); + this.PictureSettingsViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.VideoViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.FiltersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.AudioViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.SubtitleViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.ChaptersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.AdvancedViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); + this.MetaDataViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask); } } diff --git a/win/CS/HandBrakeWPF/Views/MainView.xaml b/win/CS/HandBrakeWPF/Views/MainView.xaml index 7d7556c85..507ceb41d 100644 --- a/win/CS/HandBrakeWPF/Views/MainView.xaml +++ b/win/CS/HandBrakeWPF/Views/MainView.xaml @@ -7,8 +7,9 @@ xmlns:commands="clr-namespace:HandBrakeWPF.Commands" xmlns:Properties="clr-namespace:HandBrakeWPF.Properties" xmlns:cal="http://www.caliburnproject.org" - xmlns:attachedProperties="clr-namespace:HandBrakeWPF.AttachedProperties" xmlns:menu="clr-namespace:HandBrakeWPF.Commands.Menu" + xmlns:loc="clr-namespace:HandBrakeWPF.Services.Presets.Model" + xmlns:helpers="clr-namespace:HandBrakeWPF.Helpers" AllowDrop="True" FontSize="11" cal:Message.Attach="[Event Loaded] = [Action Load]" @@ -21,9 +22,7 @@ - - - - - - - - - @@ -507,53 +488,68 @@ Margin="0,0,5,5" IsEnabled="{Binding HasSource, Converter={StaticResource booleanConverter}, ConverterParameter=false}" Visibility="{Binding IsPresetPanelShowing, Converter={StaticResource boolToVisConverter}}"> + - - - - - - + + + + + + + - - - + + + + - - + - + @@ -566,8 +562,8 @@ - - + + @@ -577,17 +573,7 @@ - - - - - - - - - - - + + KeyboardNavigation.TabNavigation="Continue" >