- 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
{
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;
/// <summary>
/// <param name="culture">The culture to use in the converter.</param>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- IEnumerable<Preset> presets = value as IEnumerable<Preset>;
+ IEnumerable<IPresetObject> presets = value as IEnumerable<IPresetObject>;
if (presets == null)
{
}
Dictionary<string, MenuItem> groupedMenu = new Dictionary<string, MenuItem>();
- 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);
}
}
{
throw new NotImplementedException();
}
+
+ private void ProcessPreset(Dictionary<string, MenuItem> 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<string, MenuItem> groupedMenu, PresetDisplayCategory category)
+ {
+ foreach (Preset preset in category.Presets)
+ {
+ this.ProcessPreset(groupedMenu, preset);
+ }
+ }
}
}
<Compile Include="EventArgs\SettingChangedEventArgs.cs" />\r
<Compile Include="Exceptions\GeneralApplicationException.cs" />\r
<Compile Include="Extensions\StringExtensions.cs" />\r
+ <Compile Include="Helpers\TreeViewHelper.cs" />\r
<Compile Include="Helpers\LogManager.cs" />\r
<Compile Include="Helpers\MP4Helper.cs" />\r
<Compile Include="Helpers\TimeSpanHelper.cs" />\r
<Compile Include="Services\Encode\Model\Models\Video\VideoProfile.cs" />\r
<Compile Include="Services\Encode\Model\Models\Video\VideoTune.cs" />\r
<Compile Include="Services\Presets\Factories\JsonPresetFactory.cs" />\r
+ <Compile Include="Services\Presets\Interfaces\IPresetObject.cs" />\r
+ <Compile Include="Services\Presets\Model\PresetDisplayCategory.cs" />\r
<Compile Include="Services\Queue\Interfaces\IQueueProcessor.cs" />\r
<Compile Include="Helpers\FileHelper.cs" />\r
<Compile Include="Services\Presets\Model\Preset.cs" />\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="TreeViewHelper.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Helper functions for handling <see cref="TimeSpan" /> 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
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+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<object> 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
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="IPresetObject.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// The Preset Service Interface
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Presets.Interfaces
+{
+ public interface IPresetObject
+ {
+ bool IsSelected { get; set; }
+ string Category { get; }
+ }
+}
\ No newline at end of file
/// <summary>\r
/// Gets a Collection of presets.\r
/// </summary>\r
- ObservableCollection<Preset> Presets { get; }\r
+ ObservableCollection<IPresetObject> Presets { get; }\r
\r
/// <summary>\r
/// Gets DefaultPreset.\r
/// </summary>\r
void Load();\r
\r
+ /// <summary>\r
+ /// Save the state of the Preset Treview\r
+ /// </summary>\r
+ void SaveCategoryStates();\r
+\r
+ /// <summary>\r
+ /// Load the state of the Preset Treeview.\r
+ /// </summary>\r
+ void LoadCategoryStates();\r
+\r
/// <summary>\r
/// Add a new preset to the system\r
/// </summary>\r
/// <param name="preset">\r
/// The Preset to remove\r
/// </param>\r
- void Remove(Preset preset);\r
+ /// <returns>\r
+ /// True if it was removed successfully, false otherwise.\r
+ /// </returns>\r
+ bool Remove(Preset preset);\r
\r
/// <summary>\r
/// Remove a group of presets by category\r
/// The replacement.\r
/// </param>\r
void Replace(Preset existing, Preset replacement);\r
+\r
+ /// <summary>\r
+ /// Set the selected preset\r
+ /// </summary>\r
+ /// <param name="selectedPreset">The preset we want to select.</param>\r
+ void SetSelected(Preset selectedPreset);\r
}\r
}
\ No newline at end of file
{\r
using HandBrakeWPF.Model.Audio;\r
using HandBrakeWPF.Model.Subtitles;\r
+ using HandBrakeWPF.Services.Presets.Interfaces;\r
using HandBrakeWPF.Utilities;\r
\r
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;\r
/// https://github.com/Caliburn-Micro/Caliburn.Micro/issues/89\r
/// https://github.com/Caliburn-Micro/Caliburn.Micro/issues/96\r
/// </remarks>\r
- public class Preset : PropertyChangedBase // Delibery not \r
+ public class Preset : PropertyChangedBase, IPresetObject // Delibery not \r
{\r
#region Constants and Fields\r
\r
/// </summary>\r
private bool isDefault;\r
\r
+ private bool isSelected;\r
+\r
#endregion\r
\r
/// <summary>\r
/// </summary>\r
public string Description { get; set; }\r
\r
+ /// <summary>\r
+ /// Reflects the visual state of this preset.\r
+ /// </summary>\r
+ public bool IsExpanded { get; set; }\r
+\r
+ public bool IsSelected\r
+ {\r
+ get\r
+ {\r
+ return this.isSelected;\r
+ }\r
+ set\r
+ {\r
+ this.isSelected = value;\r
+ this.NotifyOfPropertyChange(() => this.IsSelected);\r
+ }\r
+ }\r
+\r
/// <summary>\r
/// Gets or sets a value indicating whether this is a built in preset\r
/// </summary>\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="PresetDisplayCategory.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// A Preset Category encoding with.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+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<Preset> presets)
+ {
+ this.Category = category;
+ this.Presets = presets;
+ }
+
+ public string Category { get; private set; }
+ public BindingList<Preset> 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);
+ }
+ }
+}
using System;\r
using System.Collections.Generic;\r
using System.Collections.ObjectModel;\r
+ using System.Collections.Specialized;\r
+ using System.ComponentModel;\r
using System.Diagnostics;\r
using System.IO;\r
using System.Linq;\r
public const int ForcePresetReset = 3;\r
public static string UserPresetCatgoryName = "User Presets";\r
private readonly string presetFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()), "presets.json");\r
- private readonly ObservableCollection<Preset> presets = new ObservableCollection<Preset>();\r
+ private readonly ObservableCollection<IPresetObject> presets = new ObservableCollection<IPresetObject>(); // Can store Presets and PresetDisplayCategory objects.\r
+ private readonly Dictionary<string, Preset> flatPresetList = new Dictionary<string, Preset>();\r
private readonly IErrorService errorService;\r
private readonly IUserSettingService userSettingService;\r
\r
/// <summary>\r
/// Gets a Collection of presets.\r
/// </summary>\r
- public ObservableCollection<Preset> Presets\r
+ public ObservableCollection<IPresetObject> Presets\r
{\r
get\r
{\r
{\r
get\r
{\r
- return this.presets.FirstOrDefault(p => p.IsDefault);\r
+ return this.flatPresetList.Values.FirstOrDefault(p => p.IsDefault);\r
}\r
}\r
\r
if (!File.Exists(this.presetFile))\r
{\r
this.UpdateBuiltInPresets();\r
+ return;\r
}\r
\r
// Load the presets from file\r
this.LoadPresets();\r
}\r
\r
+ public bool Add(Preset preset)\r
+ {\r
+ return this.Add(preset, false);\r
+ }\r
+\r
/// <summary>\r
/// Add a new preset to the system.\r
/// Performs an Update if it already exists\r
/// <param name="preset">\r
/// A Preset to add\r
/// </param>\r
+ /// <param name="isLoading">\r
+ /// Prevents Saving of presets.\r
+ /// </param>\r
/// <returns>\r
/// True if added,\r
/// False if name already exists\r
/// </returns>\r
- public bool Add(Preset preset)\r
+ public bool Add(Preset preset, bool isLoading)\r
{\r
if (!this.CheckIfPresetExists(preset.Name))\r
{\r
- this.presets.Add(preset);\r
+ // Check to see if the category already exists.\r
+ PresetDisplayCategory category = this.presets.FirstOrDefault(a => a.Category == preset.Category) as PresetDisplayCategory; // TODO build Dict for this.\r
+ if (category != null)\r
+ {\r
+ category.Presets.Add(preset);\r
+ }\r
+ else if (!string.IsNullOrEmpty(preset.Category))\r
+ {\r
+ // Otherwise, if we have category but it doesn't exist, create it.\r
+ this.presets.Add(new PresetDisplayCategory(preset.Category, new BindingList<Preset> { preset }));\r
+ }\r
+ else\r
+ {\r
+ // Preset has no category. \r
+ this.presets.Add(preset);\r
+ }\r
+\r
+ this.flatPresetList.Add(preset.Name, preset);\r
\r
// Update the presets file\r
- this.SavePresetFiles();\r
+ if (!isLoading)\r
+ {\r
+ this.SavePresetFiles();\r
+ }\r
return true;\r
}\r
\r
- this.Update(preset);\r
- return true;\r
+ return false;\r
}\r
\r
/// <summary>\r
try\r
{\r
preset = JsonPresetFactory.ImportPreset(hbPreset);\r
- preset.Category = UserPresetCatgoryName;\r
+ preset.Category = UserPresetCatgoryName; // TODO can we get this from the preset?\r
\r
// IF we are using Source Max, Set the Max Width / Height values.\r
if (preset.PictureSettingsMode == PresetPictureSettingsMode.SourceMaximum)\r
}\r
else\r
{\r
- this.Add(preset);\r
+ this.Add(preset, false);\r
}\r
}\r
}\r
-\r
- // Category Handling.\r
- // TODO maybe for a future release.\r
}\r
}\r
\r
/// </param>\r
public void Update(Preset update)\r
{\r
- // TODO - Change this to be a lookup\r
- foreach (Preset preset in this.presets)\r
+ Preset preset;\r
+ if (this.flatPresetList.TryGetValue(update.Name, out preset))\r
{\r
- if (preset.Name == update.Name)\r
- {\r
- preset.Task = update.Task;\r
- preset.PictureSettingsMode = update.PictureSettingsMode;\r
- preset.Category = update.Category;\r
- preset.Description = update.Description;\r
- preset.AudioTrackBehaviours = update.AudioTrackBehaviours;\r
- preset.SubtitleTrackBehaviours = update.SubtitleTrackBehaviours;\r
-\r
- // Update the presets file\r
- this.SavePresetFiles();\r
- break;\r
- }\r
+ preset.Task = update.Task;\r
+ preset.PictureSettingsMode = update.PictureSettingsMode;\r
+ preset.Category = update.Category;\r
+ preset.Description = update.Description;\r
+ preset.AudioTrackBehaviours = update.AudioTrackBehaviours;\r
+ preset.SubtitleTrackBehaviours = update.SubtitleTrackBehaviours;\r
+\r
+ // Update the presets file\r
+ this.SavePresetFiles();\r
}\r
}\r
\r
public void Replace(Preset existing, Preset replacement)\r
{\r
this.Remove(existing);\r
- this.Add(replacement);\r
+ this.Add(replacement, false);\r
}\r
\r
/// <summary>\r
/// <param name="preset">\r
/// The Preset to remove\r
/// </param>\r
- public void Remove(Preset preset)\r
+ /// <returns>True if successfully removed, false otherwise.</returns>\r
+ public bool Remove(Preset preset)\r
{\r
if (preset == null || preset.IsDefault)\r
{\r
- return;\r
+ return false;\r
+ }\r
+\r
+ PresetDisplayCategory cateogry = this.presets.FirstOrDefault(p => p.Category == preset.Category) as PresetDisplayCategory;\r
+ if (cateogry != null)\r
+ {\r
+ // Remove the preset, and cleanup the category if it's not got any presets in it.\r
+ cateogry.Presets.Remove(preset);\r
+ this.flatPresetList.Remove(preset.Name);\r
+ if (cateogry.Presets.Count == 0)\r
+ {\r
+ this.presets.Remove(cateogry);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ this.presets.Remove(preset);\r
+ this.flatPresetList.Remove(preset.Name);\r
}\r
\r
- this.presets.Remove(preset);\r
this.SavePresetFiles();\r
+\r
+ return true;\r
}\r
\r
/// <summary>\r
/// Remove a group of presets by category\r
/// </summary>\r
- /// <param name="category">\r
+ /// <param name="categoryName">\r
/// The Category to remove\r
/// </param>\r
- public void RemoveGroup(string category)\r
+ public void RemoveGroup(string categoryName)\r
{\r
- List<Preset> removeList = this.presets.Where(p => p.Category == category).ToList();\r
- foreach (Preset preset in removeList)\r
+ PresetDisplayCategory category = this.presets.FirstOrDefault(p => p.Category == categoryName) as PresetDisplayCategory;\r
+ if (category != null)\r
{\r
- if (preset.IsDefault)\r
+ foreach (Preset preset in category.Presets)\r
{\r
- // Skip default preset\r
- continue;\r
+ if (preset.IsDefault)\r
+ {\r
+ // Skip default preset\r
+ continue;\r
+ }\r
+\r
+ this.presets.Remove(preset);\r
+ this.flatPresetList.Remove(preset.Name);\r
}\r
\r
- this.presets.Remove(preset);\r
- }\r
+ // Cleanup the category if we can.\r
+ if (category.Presets.Count == 0)\r
+ {\r
+ this.presets.Remove(category);\r
+ }\r
\r
- this.SavePresetFiles();\r
+ this.SavePresetFiles();\r
+ }\r
}\r
\r
/// <summary>\r
/// Set Default Preset\r
/// </summary>\r
- /// <param name="name">\r
+ /// <param name="preset">\r
/// The name.\r
/// </param>\r
- public void SetDefault(Preset name)\r
+ public void SetDefault(Preset preset)\r
{\r
- foreach (Preset preset in this.presets)\r
+ // Set IsDefault false for everything.\r
+ foreach (Preset item in this.flatPresetList.Values)\r
{\r
- preset.IsDefault = false;\r
+ item.IsDefault = false;\r
}\r
\r
- name.IsDefault = true;\r
+ // Set the new preset to default.\r
+ preset.IsDefault = true;\r
+\r
this.SavePresetFiles();\r
}\r
\r
/// </returns>\r
public Preset GetPreset(string name)\r
{\r
- return this.presets.FirstOrDefault(item => item.Name == name);\r
+ Preset preset;\r
+ if (this.flatPresetList.TryGetValue(name, out preset))\r
+ {\r
+ return preset;\r
+ }\r
+\r
+ return null;\r
}\r
\r
/// <summary>\r
/// </summary>\r
public void ClearBuiltIn()\r
{\r
- List<Preset> remove = this.presets.Where(p => p.IsBuildIn).ToList();\r
- foreach (Preset preset in remove)\r
+ List<IPresetObject> topLevel = new List<IPresetObject>();\r
+ foreach (IPresetObject item in this.presets)\r
{\r
- this.presets.Remove(preset);\r
+ // We either have a Preset\r
+ Preset foundPreset = item as Preset;\r
+ if (foundPreset != null && foundPreset.IsBuildIn)\r
+ {\r
+ topLevel.Add(item);\r
+ }\r
+\r
+ // Or a Category.\r
+ PresetDisplayCategory foundCategory = item as PresetDisplayCategory;\r
+ if (foundCategory != null)\r
+ {\r
+ // Find all the presets in this category to remove\r
+ List<Preset> presetsToRemove = new List<Preset>();\r
+ foreach (Preset categoryPreset in foundCategory.Presets)\r
+ {\r
+ if (categoryPreset.IsBuildIn)\r
+ {\r
+ presetsToRemove.Add(categoryPreset);\r
+ }\r
+ }\r
+\r
+ // Then remove them.\r
+ foreach (Preset toRemove in presetsToRemove)\r
+ {\r
+ foundCategory.Presets.Remove(toRemove);\r
+ this.flatPresetList.Remove(toRemove.Name);\r
+ }\r
+\r
+ // Check if we can remove this category.\r
+ if (foundCategory.Presets.Count == 0)\r
+ {\r
+ topLevel.Add(foundCategory);\r
+ }\r
+ }\r
+ }\r
+\r
+ // Remove any top level items we need to remove.\r
+ foreach (var item in topLevel)\r
+ {\r
+ this.presets.Remove(item);\r
+\r
+ if (item.GetType() == typeof(Preset))\r
+ {\r
+ this.flatPresetList.Remove(((Preset)item).Name);\r
+ }\r
}\r
}\r
\r
public void ClearAll()\r
{\r
this.presets.Clear();\r
+ this.flatPresetList.Clear();\r
}\r
\r
/// <summary>\r
Preset preset = JsonPresetFactory.ImportPreset(hbpreset);\r
preset.IsBuildIn = true; \r
preset.Category = category.PresetName;\r
-\r
- if (preset.Name == "iPod")\r
- {\r
- preset.Task.KeepDisplayAspect = true;\r
- }\r
-\r
preset.Task.AllowedPassthruOptions = new AllowedPassthru(true); // We don't want to override the built-in preset\r
\r
- this.presets.Add(preset);\r
+ this.Add(preset, true);\r
}\r
}\r
\r
/// </returns>\r
public bool CheckIfPresetExists(string name)\r
{\r
- return name == string.Empty || this.presets.Any(item => item.Name == name);\r
+ if (this.flatPresetList.ContainsKey(name))\r
+ {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
}\r
\r
/// <summary>\r
/// </returns>\r
public bool CanUpdatePreset(string name)\r
{\r
- return this.presets.Where(preset => preset.Name == name).Any(preset => preset.IsBuildIn == false);\r
+ Preset preset;\r
+ if (this.flatPresetList.TryGetValue(name, out preset))\r
+ {\r
+ return !preset.IsBuildIn;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Set the selected preset\r
+ /// </summary>\r
+ /// <param name="selectedPreset">The preset we want to select.</param>\r
+ public void SetSelected(Preset selectedPreset)\r
+ {\r
+ foreach (var item in this.flatPresetList.Values)\r
+ {\r
+ item.IsSelected = false;\r
+ }\r
+\r
+ selectedPreset.IsSelected = true;\r
+ }\r
+\r
+ public void SaveCategoryStates()\r
+ {\r
+ StringCollection expandedPresets = new StringCollection();\r
+ foreach (IPresetObject presetObject in this.presets)\r
+ {\r
+ PresetDisplayCategory category = presetObject as PresetDisplayCategory;\r
+ if (category != null && category.IsExpanded)\r
+ {\r
+ expandedPresets.Add(category.Category);\r
+ }\r
+ }\r
+\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.PresetExpandedStateList, expandedPresets);\r
+ }\r
+\r
+ public void LoadCategoryStates()\r
+ {\r
+ StringCollection expandedPresets = this.userSettingService.GetUserSetting<StringCollection>(UserSettingConstants.PresetExpandedStateList);\r
+ if (expandedPresets == null || expandedPresets.Count == 0)\r
+ {\r
+ return;\r
+ }\r
+\r
+ foreach (IPresetObject presetObject in this.presets)\r
+ {\r
+ PresetDisplayCategory category = presetObject as PresetDisplayCategory;\r
+ if (category != null && expandedPresets.Contains(category.Category))\r
+ {\r
+ category.IsExpanded = true;\r
+ }\r
+ }\r
}\r
\r
#endregion\r
preset.Task.MaxHeight = preset.Task.Width;\r
}\r
\r
- this.presets.Add(preset);\r
+ this.Add(preset, true);\r
}\r
}\r
\r
preset.Task.MaxHeight = preset.Task.Width;\r
}\r
\r
- this.presets.Add(preset);\r
+ this.Add(preset, true);\r
}\r
}\r
}\r
// Orgamise the Presets list into Json Equivilent objects.\r
Dictionary<string, PresetCategory> presetCategories = new Dictionary<string, PresetCategory>();\r
List<HBPreset> uncategorisedPresets = new List<HBPreset>(); \r
- foreach (Preset item in this.presets)\r
+ foreach (Preset item in this.flatPresetList.Values.OrderBy(o => o.IsBuildIn)) // Handle User Presets first.\r
{\r
if (string.IsNullOrEmpty(item.Category))\r
{\r
/// </summary>\r
public const string ForcePresetReset = "ForcePresetReset";\r
\r
+ /// <summary>\r
+ /// Setting to record the expansion state of preset categories. \r
+ /// </summary>\r
+ public const string PresetExpandedStateList = "PresetExpandedStateList";\r
+\r
#endregion\r
}\r
}
\ No newline at end of file
{\r
using System.Windows;\r
\r
- using HandBrakeWPF.Services.Presets.Model;\r
-\r
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;\r
\r
/// <summary>\r
/// </summary>\r
public interface IMainViewModel\r
{\r
- /// <summary>\r
- /// Sets SelectedPreset.\r
- /// </summary>\r
- Preset SelectedPreset { set; }\r
-\r
/// <summary>\r
/// The preset select.\r
/// </summary>\r
using System.Linq;\r
using System.Threading;\r
using System.Windows;\r
+ using System.Windows.Data;\r
using System.Windows.Input;\r
\r
using Caliburn.Micro;\r
this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeStatusChanged;\r
this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged;\r
\r
- this.Presets = this.presetService.Presets;\r
+ this.Presets = new BindingList<IPresetObject>();\r
this.Drives = new BindingList<SourceMenuItem>();\r
\r
// Set Process Priority\r
/// <summary>\r
/// Gets or sets Presets.\r
/// </summary>\r
- public IEnumerable<Preset> Presets { get; set; }\r
+ public IEnumerable<IPresetObject> Presets { get; set; }\r
\r
/// <summary>\r
/// Gets or sets SelectedPreset.\r
/// </summary>\r
- public Preset SelectedPreset\r
+ public object SelectedPreset\r
{\r
get\r
{\r
return this.selectedPreset;\r
}\r
+\r
set\r
{\r
- this.selectedPreset = value;\r
+ if (value == null || value.GetType() != typeof(Preset))\r
+ {\r
+ return;\r
+ }\r
+\r
+ this.selectedPreset = (Preset)value;\r
\r
- if (this.SelectedPreset != null)\r
+ this.presetService.SetSelected(selectedPreset);\r
+ \r
+ if (this.selectedPreset != null)\r
{\r
// Main Window Settings\r
this.OptimizeMP4 = selectedPreset.Task.OptimizeMP4;\r
this.SelectedOutputFormat = selectedPreset.Task.OutputFormat;\r
\r
// Tab Settings\r
- this.PictureSettingsViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.VideoViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.FiltersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.AudioViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.SubtitleViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.ChaptersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.AdvancedViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
- this.MetaDataViewModel.SetPreset(this.SelectedPreset, this.CurrentTask);\r
+ this.PictureSettingsViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.VideoViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.FiltersViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.AudioViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.SubtitleViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.ChaptersViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.AdvancedViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
+ this.MetaDataViewModel.SetPreset(this.selectedPreset, this.CurrentTask);\r
\r
// Do this again to force an update for m4v/mp4 selection\r
this.SelectedOutputFormat = selectedPreset.Task.OutputFormat;\r
}\r
}\r
\r
+ public void TrickPresetDisplayUpdate()\r
+ {\r
+ this.NotifyOfPropertyChange(() => this.SelectedPreset);\r
+ this.selectedPreset.IsSelected = true;\r
+ }\r
+\r
/// <summary>\r
/// Optimise MP4 Checkbox\r
/// </summary>\r
{\r
if (this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null)\r
{\r
- this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset);\r
+ this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset);\r
}\r
}\r
this.NotifyOfPropertyChange(() => this.CurrentTask);\r
if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
{\r
- this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset);\r
+ this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset);\r
}\r
}\r
\r
if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
{\r
- this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset);\r
+ this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.selectedPreset);\r
}\r
\r
if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters)\r
\r
// Setup the presets.\r
this.presetService.Load();\r
+ this.Presets = this.presetService.Presets;\r
this.NotifyOfPropertyChange(() => this.Presets);\r
+ this.presetService.LoadCategoryStates();\r
\r
// Queue Recovery\r
bool queueRecovered = QueueRecoveryHelper.RecoverQueue(this.queueProcessor, this.errorService, StartupOptions.AutoRestartQueue);\r
{\r
// Shutdown Service\r
this.encodeService.Stop();\r
+ this.presetService.SaveCategoryStates();\r
\r
// Unsubscribe from Events.\r
this.scanService.ScanStarted -= this.ScanStared;\r
/// </summary>\r
public void PresetAdd()\r
{\r
+ // TODO select the new preset.\r
IAddPresetViewModel presetViewModel = IoC.Get<IAddPresetViewModel>();\r
presetViewModel.Setup(this.CurrentTask, this.SelectedTitle, this.AudioViewModel.AudioBehaviours, this.SubtitleViewModel.SubtitleBehaviours);\r
- this.windowManager.ShowWindow(presetViewModel);\r
+ this.windowManager.ShowDialog(presetViewModel);\r
+ this.NotifyOfPropertyChange(() => this.Presets);\r
}\r
\r
/// <summary>\r
return;\r
}\r
\r
- if (this.SelectedPreset.IsBuildIn)\r
+ if (this.selectedPreset.IsBuildIn)\r
{\r
this.errorService.ShowMessageBox(\r
Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning);\r
\r
if (this.errorService.ShowMessageBox(Resources.Main_PresetUpdateConfrimation, Resources.AreYouSure, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)\r
{\r
- this.SelectedPreset.Update(new EncodeTask(this.CurrentTask), new AudioBehaviours(this.AudioViewModel.AudioBehaviours), new SubtitleBehaviours(this.SubtitleViewModel.SubtitleBehaviours));\r
- this.presetService.Update(this.SelectedPreset);\r
+ this.selectedPreset.Update(new EncodeTask(this.CurrentTask), new AudioBehaviours(this.AudioViewModel.AudioBehaviours), new SubtitleBehaviours(this.SubtitleViewModel.SubtitleBehaviours));\r
+ this.presetService.Update(this.selectedPreset);\r
\r
this.errorService.ShowMessageBox(\r
Resources.Main_PresetUpdated, Resources.Updated, MessageBoxButton.OK, MessageBoxImage.Information);\r
return;\r
}\r
\r
- if (this.SelectedPreset.IsBuildIn)\r
+ if (this.selectedPreset.IsBuildIn)\r
{\r
this.errorService.ShowMessageBox(\r
Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning);\r
}\r
\r
IManagePresetViewModel presetViewModel = IoC.Get<IManagePresetViewModel>();\r
- presetViewModel.Setup(this.SelectedPreset);\r
+ presetViewModel.Setup(this.selectedPreset);\r
this.windowManager.ShowDialog(presetViewModel);\r
Preset preset = presetViewModel.Preset;\r
\r
}\r
\r
this.presetService.Remove(this.selectedPreset);\r
+ this.NotifyOfPropertyChange(() => this.Presets);\r
}\r
else\r
{\r
if (this.selectedPreset != null)\r
{\r
this.presetService.SetDefault(this.selectedPreset);\r
- this.NotifyOfPropertyChange(() => this.Presets);\r
MessageBox.Show(string.Format(Resources.Main_NewDefaultPreset, this.selectedPreset.Name), Resources.Main_Presets, MessageBoxButton.OK, MessageBoxImage.Information);\r
}\r
else\r
// Setup the Tabs\r
if (this.selectedTitle != null)\r
{\r
- this.PictureSettingsViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.VideoViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.FiltersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.AudioViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.SubtitleViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.ChaptersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.AdvancedViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
- this.MetaDataViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask);\r
+ this.PictureSettingsViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.VideoViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.FiltersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.AudioViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.SubtitleViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.ChaptersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.AdvancedViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
+ this.MetaDataViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.selectedPreset, this.CurrentTask);\r
}\r
}\r
\r
xmlns:commands="clr-namespace:HandBrakeWPF.Commands"\r
xmlns:Properties="clr-namespace:HandBrakeWPF.Properties"\r
xmlns:cal="http://www.caliburnproject.org"\r
- xmlns:attachedProperties="clr-namespace:HandBrakeWPF.AttachedProperties"\r
xmlns:menu="clr-namespace:HandBrakeWPF.Commands.Menu"\r
+ xmlns:loc="clr-namespace:HandBrakeWPF.Services.Presets.Model"\r
+ xmlns:helpers="clr-namespace:HandBrakeWPF.Helpers"\r
AllowDrop="True"\r
FontSize="11"\r
cal:Message.Attach="[Event Loaded] = [Action Load]"\r
<Converters:EnumComboConverter x:Key="enumComboConverter" />\r
<Converters:PresetsMenuConverter x:Key="presetsMenuConverter"/>\r
\r
-\r
<Style TargetType="Button">\r
-\r
<Setter Property="Padding" Value="8,2" />\r
<Setter Property="FontSize" Value="11.5" />\r
<Setter Property="VerticalAlignment" Value="Center" />\r
<Setter Property="Padding" Value="5,5" />\r
</Style>\r
\r
- <CollectionViewSource x:Key="presetsCvs" Source="{Binding Presets}">\r
- <CollectionViewSource.GroupDescriptions>\r
- <PropertyGroupDescription PropertyName="Category" />\r
- </CollectionViewSource.GroupDescriptions>\r
- </CollectionViewSource>\r
-\r
- <Style x:Key="ContainerStyle" TargetType="{x:Type GroupItem}">\r
- <Setter Property="Template">\r
- <Setter.Value>\r
- <ControlTemplate>\r
- <Expander Header="{Binding Name}" IsExpanded="True">\r
- <ItemsPresenter />\r
- </Expander>\r
- </ControlTemplate>\r
- </Setter.Value>\r
- </Setter>\r
- </Style>\r
-\r
<Converters:BooleanToVisibilityConverter x:Key="boolToVisConverter" />\r
\r
</UserControl.Resources>\r
Margin="0,0,5,5"\r
IsEnabled="{Binding HasSource, Converter={StaticResource booleanConverter}, ConverterParameter=false}"\r
Visibility="{Binding IsPresetPanelShowing, Converter={StaticResource boolToVisConverter}}">\r
+ \r
\r
<Grid>\r
<Grid.RowDefinitions>\r
<RowDefinition Height="*" />\r
<RowDefinition Height="Auto" />\r
</Grid.RowDefinitions>\r
-\r
- <ListBox HorizontalAlignment="Stretch" AutomationProperties.Name="Presets List" ToolTip="{x:Static Properties:ResourcesTooltips.MainView_Presets}"\r
- VerticalAlignment="Stretch" ItemsSource="{Binding Source={StaticResource presetsCvs}}"\r
- SelectedItem="{Binding SelectedPreset, Mode=TwoWay}" BorderThickness="0,0,0,1"\r
- BorderBrush="LightGray"\r
- >\r
- <ListBox.Resources>\r
-\r
- <Style TargetType="ToolTip">\r
- <Style.Resources>\r
- <Style TargetType="ContentPresenter">\r
- <Style.Resources>\r
- <Style TargetType="TextBlock">\r
- <Setter Property="TextWrapping" Value="Wrap" />\r
- </Style>\r
- </Style.Resources>\r
+ \r
+ <Grid.Resources>\r
+\r
+ <HierarchicalDataTemplate DataType="{x:Type loc:Preset}">\r
+ <StackPanel Orientation="Horizontal" >\r
+ <StackPanel.Resources>\r
+ <Style TargetType="TextBlock">\r
+ <Style.Triggers>\r
+ <DataTrigger Binding="{Binding IsDefault}" Value="True" >\r
+ <Setter Property="FontStyle" Value="Italic" />\r
+ </DataTrigger>\r
+ <DataTrigger Binding="{Binding IsDefault}" Value="False" >\r
+ <Setter Property="FontStyle" Value="Normal" />\r
+ </DataTrigger>\r
+ <DataTrigger Binding="{Binding IsSelected}" Value="True">\r
+ <Setter Property="FontWeight" Value="Bold"/>\r
+ </DataTrigger>\r
+ </Style.Triggers>\r
</Style>\r
- </Style.Resources>\r
- <Setter Property="MaxWidth" Value="300" />\r
- </Style>\r
+ </StackPanel.Resources>\r
+ <TextBlock Text="{Binding Name}"/>\r
+ </StackPanel>\r
+ </HierarchicalDataTemplate>\r
\r
- <Style TargetType="ListBoxItem">\r
- <Setter Property="Padding" Value="0,2,0,2" />\r
+ <HierarchicalDataTemplate DataType="{x:Type loc:PresetDisplayCategory}" ItemsSource="{Binding Presets}">\r
+ <StackPanel Orientation="Horizontal" >\r
+ <TextBlock Text="{Binding Category}" FontSize="14" />\r
+ </StackPanel>\r
+ </HierarchicalDataTemplate>\r
+ </Grid.Resources>\r
+ \r
+ <TreeView x:Name="presetListTree" HorizontalAlignment="Stretch" AutomationProperties.Name="Presets List" ToolTip="{x:Static Properties:ResourcesTooltips.MainView_Presets}"\r
+ VerticalAlignment="Stretch" BorderThickness="0,0,0,1" BorderBrush="LightGray"\r
+ ItemsSource="{Binding Presets}"\r
+ helpers:TreeViewHelper.TreeViewSelectedItem="{Binding Path=SelectedPreset, Mode=TwoWay}"\r
+ PreviewMouseRightButtonDown="PresetListTree_OnPreviewMouseRightButtonDown">\r
+\r
+ <TreeView.ItemContainerStyle>\r
+ <Style BasedOn="{StaticResource {x:Type TreeViewItem}}" TargetType="TreeViewItem">\r
+ <Setter Property="HorizontalAlignment" Value="Stretch" />\r
+ <Setter Property="Padding" Value="4" />\r
<Setter Property="ToolTip" Value="{Binding Description}" />\r
<Setter Property="ToolTipService.InitialShowDelay" Value="1500"/>\r
+ <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />\r
+ <EventSetter Event="TreeViewItem.Collapsed" Handler="PresetTreeviewItemCollasped" />\r
<Style.Triggers>\r
- <Trigger Property="IsSelected" Value="True">\r
- <Setter Property="FontWeight" Value="Bold"/>\r
- <Setter Property="Background" Value="Transparent"/>\r
+ <Trigger Property="HasItems" Value="True">\r
+ <Setter Property="Focusable" Value="false" />\r
</Trigger>\r
- <DataTrigger Binding="{Binding IsDefault}" Value="True" >\r
- <Setter Property="FontStyle" Value="Italic" />\r
- </DataTrigger>\r
- <DataTrigger Binding="{Binding IsDefault}" Value="False" >\r
- <Setter Property="FontStyle" Value="Normal" />\r
- </DataTrigger>\r
+ \r
</Style.Triggers>\r
</Style>\r
- </ListBox.Resources>\r
+ </TreeView.ItemContainerStyle>\r
\r
- <ListBox.ContextMenu>\r
+ <TreeView.ContextMenu>\r
<ContextMenu AutomationProperties.Name="Presets List Context Menu">\r
<MenuItem Header="{x:Static Properties:ResourcesUI.MainView_SetDefault}" cal:Message.Attach="[Event Click] = [Action PresetSetDefault]" />\r
<Separator />\r
<MenuItem Header="{x:Static Properties:ResourcesUI.MainView_ResetBuiltInPresets}" cal:Message.Attach="[Event Click] = [Action PresetReset]" />\r
</ContextMenu>\r
\r
- </ListBox.ContextMenu>\r
- \r
+ </TreeView.ContextMenu>\r
+ \r
<i:Interaction.Triggers>\r
<commands:InputBindingTrigger>\r
<commands:InputBindingTrigger.InputBinding>\r
</commands:InputBindingTrigger>\r
</i:Interaction.Triggers>\r
\r
- <ListBox.GroupStyle>\r
- <GroupStyle ContainerStyle="{StaticResource ContainerStyle}"/>\r
- </ListBox.GroupStyle>\r
-\r
- <ListBox.ItemTemplate>\r
- <DataTemplate>\r
- <TextBlock Text="{Binding Name}" Margin="24,0,0,0" Padding="8,1" />\r
- </DataTemplate>\r
- </ListBox.ItemTemplate>\r
-\r
- </ListBox>\r
+ </TreeView>\r
\r
<ToolBar Name="presetsToolBar"\r
Grid.Row="1"\r
Background="Transparent"\r
ToolBarTray.IsLocked="True"\r
Loaded="ToolBarLoaded"\r
- KeyboardNavigation.TabNavigation="Continue"\r
- >\r
+ KeyboardNavigation.TabNavigation="Continue" >\r
\r
<ToolBar.Resources>\r
<Style TargetType="{x:Type ToolBarPanel}">\r
</StatusBar>\r
</Grid>\r
</UserControl>\r
+\r
\r
namespace HandBrakeWPF.Views\r
{\r
- using System;\r
using System.Windows;\r
using System.Windows.Controls;\r
using System.Windows.Input;\r
// Otherwise assume it's a main area click and add to queue.\r
((IMainViewModel)this.DataContext).AddToQueue();\r
}\r
+\r
+ private void PresetTreeviewItemCollasped(object sender, RoutedEventArgs e)\r
+ {\r
+ if (e.Source.GetType() == typeof(TreeViewItem))\r
+ {\r
+ TreeViewItem item = e.Source as TreeViewItem;\r
+ if (item != null) item.IsSelected = false;\r
+ }\r
+ }\r
+\r
+ private void PresetListTree_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)\r
+ {\r
+ TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);\r
+\r
+ if (treeViewItem != null)\r
+ {\r
+ treeViewItem.Focus();\r
+ e.Handled = true;\r
+ }\r
+ }\r
+\r
+ private static TreeViewItem VisualUpwardSearch(DependencyObject source)\r
+ {\r
+ while (source != null && !(source is TreeViewItem))\r
+ source = VisualTreeHelper.GetParent(source);\r
+\r
+ return source as TreeViewItem;\r
+ }\r
}\r
}\r