/Application/GUI/Utilities.cs
http://yet-another-music-application.googlecode.com/ · C# · 792 lines · 416 code · 129 blank · 247 comment · 96 complexity · 5adac6eafb4d56feb561359897f2415f MD5 · raw file
- /**
- * Utilities.cs
- *
- * An extension of the Utilities class in Core that provides
- * various GUI related utilities for the Windows 7 GUI.
- *
- * * * * * * * * *
- *
- * This code is part of the Stoffi Music Player Project.
- * Visit our website at: stoffiplayer.com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 3 of the License, or (at your option) any later version.
- *
- * See stoffiplayer.com/license for more information.
- **/
-
- using System;
- using System.Collections.Generic;
- using System.Windows.Controls;
- using System.Diagnostics;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using System.Runtime.InteropServices;
- using System.Runtime.CompilerServices;
- using System.Windows;
- using System.Windows.Data;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Media;
-
- namespace Stoffi
- {
- /// <summary>
- /// A utilities class with helper method for GUI related stuff
- /// </summary>
- static partial class Utilities
- {
- /// <summary>
- /// Extracts a specific image from an ico
- /// file given it's size.
- /// If no exact size is matched, the largest
- /// image will be returned.
- /// </summary>
- /// <param name="path">The path to the ico</param>
- /// <param name="width">The prefered width</param>
- /// <param name="height">The prefered height</param>
- /// <returns>An image from inside the ico file</returns>
- public static BitmapFrame GetIcoImage(string path, int width, int height)
- {
- var iconUri = new Uri(path, UriKind.RelativeOrAbsolute);
- try
- {
-
- var iconDecoder = new IconBitmapDecoder(iconUri,
- BitmapCreateOptions.None, BitmapCacheOption.Default);
-
- // no image found
- if (iconDecoder.Frames.Count == 0) return null;
-
- BitmapFrame largest = iconDecoder.Frames[0];
- foreach (BitmapFrame frame in iconDecoder.Frames)
- {
- if (frame.PixelHeight == height &&
- frame.PixelWidth == width)
- {
- return frame;
- }
-
- if (frame.PixelWidth * frame.PixelHeight >
- largest.PixelWidth * frame.PixelHeight)
- largest = frame;
- }
-
- return largest;
- }
- catch (Exception)
- {
- return null;
- }
- }
-
- /// <summary>Finds a parent of a given item on the visual tree.</summary>
- /// <typeparam name="T">The type of the queried item.</typeparam>
- /// <param name="iChild">A direct or indirect child of the queried item.</param>
- /// <returns>The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned.</returns>
- public static T TryFindParent<T>(this DependencyObject iChild)
- where T : DependencyObject
- {
- // Get parent item.
- DependencyObject parentObject = GetParentObject(iChild);
-
- // We've reached the end of the tree.
- if (parentObject == null)
- return null;
-
- // Check if the parent matches the type we're looking for.
- // Else use recursion to proceed with next level.
- T parent = parentObject as T;
- return parent ?? TryFindParent<T>(parentObject);
- }
-
- /// <summary>
- /// This method is an alternative to WPF's <see cref="VisualTreeHelper.GetParent"/> method, which also
- /// supports content elements. Keep in mind that for content element, this method falls back to the logical tree of the element!
- /// </summary>
- /// <param name="iChild">The item to be processed.</param>
- /// <returns>The submitted item's parent, if available. Otherwise null.</returns>
- public static DependencyObject GetParentObject(this DependencyObject iChild)
- {
- if (iChild == null)
- {
- return null;
- }
-
- // Handle content elements separately.
- ContentElement contentElement = iChild as ContentElement;
- if (contentElement != null)
- {
- DependencyObject parent = ContentOperations.GetParent(contentElement);
- if (parent != null) return parent;
-
- FrameworkContentElement frameworkContentElement = contentElement as FrameworkContentElement;
- return frameworkContentElement != null ? frameworkContentElement.Parent : null;
- }
-
- // Also try searching for parent in framework elements (such as DockPanel, etc).
- FrameworkElement frameworkElement = iChild as FrameworkElement;
- if (frameworkElement != null)
- {
- DependencyObject parent = frameworkElement.Parent;
- if (parent != null) return parent;
- }
-
- // If it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper.
- return VisualTreeHelper.GetParent(iChild);
- }
-
- /// <summary>Tries to locate a given item within the visual tree, starting with the dependency object at a given position.</summary>
- /// <typeparam name="T">The type of the element to be found on the visual tree of the element at the given location.</typeparam>
- /// <param name="iReference">The main element which is used to perform hit testing.</param>
- /// <param name="iPoint">The position to be evaluated on the origin.</param>
- public static T TryFindFromPoint<T>(this UIElement iReference, Point iPoint) where T : DependencyObject
- {
- DependencyObject element = iReference.InputHitTest(iPoint) as DependencyObject;
- if (element == null)
- {
- return null;
- }
- else if (element is T)
- return (T)element;
- else
- return TryFindParent<T>(element);
- }
-
- /// <summary>
- /// Tries to locate a child of a given item within the visual tree
- /// </summary>
- /// <typeparam name="T">The type of the element to be found on the visual tree of the parent to the element</typeparam>
- /// <param name="referenceVisual">A direct or indirect parent of the element to be found</param>
- /// <returns>The first child item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned.</returns>
- public static T GetVisualChild<T>(Visual referenceVisual) where T : Visual
- {
- Visual child = null;
- for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
- {
- child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
- if (child != null && (child.GetType() == typeof(T)))
- {
- break;
- }
- else if (child != null)
- {
- child = GetVisualChild<T>(child);
- if (child != null && (child.GetType() == typeof(T)))
- {
- break;
- }
- }
- }
- return child as T;
- }
- }
-
- #region Description converters
-
- /// <summary>
- ///
- /// </summary>
- class OpenFileAddDescriptionConverter : IValueConverter
- {
- private string OpenFile_NoAdd = U.T("GeneralAddPolicyDont", "Content");
- private string OpenFile_Add2Lib = U.T("GeneralAddPolicyLibrary", "Content");
- private string OpenFile_Add2Pl = U.T("GeneralAddPolicyBoth", "Content");
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- OpenAddPolicy source = (OpenAddPolicy)Enum.Parse(typeof(OpenAddPolicy), value.ToString());
- string target;
-
- switch (source)
- {
- case OpenAddPolicy.DoNotAdd:
- target = OpenFile_NoAdd;
- break;
-
- case OpenAddPolicy.Library:
- default:
- target = OpenFile_Add2Lib;
- break;
-
- case OpenAddPolicy.LibraryAndPlaylist:
- target = OpenFile_Add2Pl;
- break;
- }
-
- return target;
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- string source = value.ToString();
-
- if (source == OpenFile_NoAdd)
- return OpenAddPolicy.DoNotAdd;
-
- else if (source == OpenFile_Add2Pl)
- return OpenAddPolicy.LibraryAndPlaylist;
-
- else
- return OpenAddPolicy.Library;
- }
- }
-
- /// <summary>
- ///
- /// </summary>
- class OpenFilePlayDescriptionConverter : IValueConverter
- {
- private string OpenFile_Play = U.T("GeneralPlayPolicyPlay", "Content");
- private string OpenFile_DoNotPlay = U.T("GeneralPlayPolicyDont", "Content");
- private string OpenFile_BackOfQueue = U.T("GeneralPlayPolicyBack", "Content");
- private string OpenFile_FrontOfQueue = U.T("GeneralPlayPolicyFront", "Content");
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- OpenPlayPolicy source = (OpenPlayPolicy)Enum.Parse(typeof(OpenPlayPolicy), value.ToString());
- string target;
-
- switch (source)
- {
- case OpenPlayPolicy.BackOfQueue:
- default:
- target = OpenFile_BackOfQueue;
- break;
-
- case OpenPlayPolicy.FrontOfQueue:
- target = OpenFile_FrontOfQueue;
- break;
-
- case OpenPlayPolicy.DoNotPlay:
- target = OpenFile_DoNotPlay;
- break;
-
- case OpenPlayPolicy.Play:
- target = OpenFile_Play;
- break;
- }
-
- return target;
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- string source = value.ToString();
-
- if (source == OpenFile_Play)
- return OpenPlayPolicy.Play;
-
- else if (source == OpenFile_FrontOfQueue)
- return OpenPlayPolicy.FrontOfQueue;
-
- else if (source == OpenFile_DoNotPlay)
- return OpenPlayPolicy.DoNotPlay;
-
- else
- return OpenPlayPolicy.BackOfQueue;
- }
- }
-
- /// <summary>
- ///
- /// </summary>
- class UpgradePolicyDescriptionConverter : IValueConverter
- {
- private string UpgradePolicy_Automatic = U.T("GeneralUpgradePolicyAuto", "Content");
- private string UpgradePolicy_Notify = U.T("GeneralUpgradePolicyNotify", "Content");
- private string UpgradePolicy_Manual = U.T("GeneralUpgradePolicyManual", "Content");
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- UpgradePolicy source = (UpgradePolicy)Enum.Parse(typeof(UpgradePolicy), value.ToString());
- string target;
-
- switch (source)
- {
- case UpgradePolicy.Automatic:
- default:
- target = UpgradePolicy_Automatic;
- break;
-
- case UpgradePolicy.Notify:
- target = UpgradePolicy_Notify;
- break;
-
- case UpgradePolicy.Manual:
- target = UpgradePolicy_Manual;
- break;
- }
-
- return target;
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- string source = value.ToString();
-
- if (source == UpgradePolicy_Notify)
- return UpgradePolicy.Notify;
-
- else if (source == UpgradePolicy_Manual)
- return UpgradePolicy.Manual;
-
- else
- return UpgradePolicy.Automatic;
- }
- }
-
- /// <summary>
- ///
- /// </summary>
- class SearchPolicyDescriptionConverter : IValueConverter
- {
- private string SearchPolicy_Global = U.T("GeneralSearchPolicyGlobal", "Content");
- private string SearchPolicy_Partial = U.T("GeneralSearchPolicyPartial", "Content");
- private string SearchPolicy_Individual = U.T("GeneralSearchPolicyIndividual", "Content");
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- SearchPolicy source = (SearchPolicy)Enum.Parse(typeof(SearchPolicy), value.ToString());
- string target;
-
- switch (source)
- {
- case SearchPolicy.Global:
- default:
- target = SearchPolicy_Global;
- break;
-
- case SearchPolicy.Partial:
- target = SearchPolicy_Partial;
- break;
-
- case SearchPolicy.Individual:
- target = SearchPolicy_Individual;
- break;
- }
-
- return target;
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- /// <param name="targetType"></param>
- /// <param name="parameter"></param>
- /// <param name="culture"></param>
- /// <returns></returns>
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value == null)
- return null;
-
- string source = value.ToString();
-
- if (source == SearchPolicy_Partial)
- return SearchPolicy.Partial;
-
- else if (source == SearchPolicy_Individual)
- return SearchPolicy.Individual;
-
- else
- return SearchPolicy.Global;
- }
- }
-
- #endregion
-
- /// <summary>
- /// Listens keyboard globally.
- ///
- /// <remarks>Uses WH_KEYBOARD_LL.</remarks>
- /// </summary>
- public class KeyboardListener : IDisposable
- {
- #region Constructor
-
- /// <summary>
- /// Creates global keyboard listener.
- /// </summary>
- public KeyboardListener()
- {
- // We have to store the HookCallback, so that it is not garbage collected runtime
- hookedLowLevelKeyboardProc = (InterceptKeys.LowLevelKeyboardProc)LowLevelKeyboardProc;
-
- // Set the hook
- hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
-
- // Assign the asynchronous callback event
- hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);
- }
-
- #endregion
-
- #region Destructor
-
- /// <summary>
- /// Destroys global keyboard listener.
- /// </summary>
- ~KeyboardListener()
- {
- Dispose();
- }
-
- #endregion
-
- #region Methods
- /// <summary>
- /// Check if the handlers are present
- /// </summary>
- /// <returns>true if both handlers are not null, otherwise false</returns>
- public bool CheckHandlers()
- {
- return (KeyDown != null && KeyUp != null);
- }
- #endregion
-
- #region Events
-
- /// <summary>
- /// Fired when any of the keys is pressed down.
- /// </summary>
- public event RawKeyEventHandler KeyDown;
-
- /// <summary>
- /// Fired when any of the keys is released.
- /// </summary>
- public event RawKeyEventHandler KeyUp;
-
- #endregion
-
- #region Inner workings
-
- /// <summary>
- /// Hook ID
- /// </summary>
- private IntPtr hookId = IntPtr.Zero;
-
- /// <summary>
- /// Asynchronous callback hook.
- /// </summary>
- /// <param name="keyEvent"></param>
- /// <param name="vkCode"></param>
- private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode);
-
- /// <summary>
- /// Actual callback hook.
- ///
- /// <remarks>Calls asynchronously the asyncCallback.</remarks>
- /// </summary>
- /// <param name="nCode"></param>
- /// <param name="wParam"></param>
- /// <param name="lParam"></param>
- /// <returns></returns>
- [MethodImpl(MethodImplOptions.NoInlining)]
- private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
- {
- if (nCode >= 0)
- if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
- wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP ||
- wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN ||
- wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYUP)
- hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), null, null);
-
- return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
- }
-
- /// <summary>
- /// Event to be invoked asynchronously (BeginInvoke) each time key is pressed.
- /// </summary>
- private KeyboardCallbackAsync hookedKeyboardCallbackAsync;
-
- /// <summary>
- /// Contains the hooked callback in runtime.
- /// </summary>
- private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
-
- /// <summary>
- /// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events.
- /// </summary>
- /// <param name="keyEvent">Keyboard event</param>
- /// <param name="vkCode">vkCode</param>
- void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode)
- {
- switch (keyEvent)
- {
- // KeyDown events
- case InterceptKeys.KeyEvent.WM_KEYDOWN:
- if (KeyDown != null)
- KeyDown(this, new RawKeyEventArgs(vkCode, false));
- break;
- case InterceptKeys.KeyEvent.WM_SYSKEYDOWN:
- if (KeyDown != null)
- KeyDown(this, new RawKeyEventArgs(vkCode, true));
- break;
-
- // KeyUp events
- case InterceptKeys.KeyEvent.WM_KEYUP:
- if (KeyUp != null)
- KeyUp(this, new RawKeyEventArgs(vkCode, false));
- break;
- case InterceptKeys.KeyEvent.WM_SYSKEYUP:
- if (KeyUp != null)
- KeyUp(this, new RawKeyEventArgs(vkCode, true));
- break;
-
- default:
- break;
- }
- }
-
- #endregion
-
- #region IDisposable Members
-
- /// <summary>
- /// Disposes the hook.
- /// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks>
- /// </summary>
- public void Dispose()
- {
- InterceptKeys.UnhookWindowsHookEx(hookId);
- }
-
- #endregion
- }
-
- /// <summary>
- /// Raw KeyEvent arguments.
- /// </summary>
- public class RawKeyEventArgs : EventArgs
- {
- #region Members
-
- /// <summary>
- /// vkCode of the key.
- /// </summary>
- public int vkCode;
-
- /// <summary>
- /// WPF key of the key.
- /// </summary>
- public Key key;
-
- /// <summary>
- /// Is the hitted key system key.
- /// </summary>
- public bool isSysKey;
-
- #endregion
-
- #region Constructor
-
- /// <summary>
- /// Create raw keyevent arguments.
- /// </summary>
- /// <param name="vkCode"></param>
- /// <param name="isSysKey"></param>
- public RawKeyEventArgs(int VKCode, bool isSysKey)
- {
- this.vkCode = VKCode;
- this.isSysKey = isSysKey;
- this.key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
- }
-
- #endregion
- }
-
- /// <summary>
- /// Raw keyevent handler.
- /// </summary>
- /// <param name="sender">sender</param>
- /// <param name="args">raw keyevent arguments</param>
- public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
-
- /// <summary>
- /// Exception for an unknown column
- /// </summary>
- class UnknownColumnException : ApplicationException
- {
- #region Constructor
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="name"></param>
- public UnknownColumnException(string name)
- : base("The list view doesn't contain the column '" + name + "'")
- {
- }
-
- #endregion
- }
-
- #region WINAPI Helper class
-
- /// <summary>
- /// Winapi key interception helper class.
- /// </summary>
- internal static class InterceptKeys
- {
- #region Members
-
- public static int WH_KEYBOARD_LL = 13;
-
- #endregion
-
- #region Delegates
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="nCode"></param>
- /// <param name="wParam"></param>
- /// <param name="lParam"></param>
- /// <returns></returns>
- public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
-
- #endregion
-
- #region Enums
-
- /// <summary>
- ///
- /// </summary>
- public enum KeyEvent : int
- {
- /// <summary>
- ///
- /// </summary>
- WM_KEYDOWN = 256,
-
- /// <summary>
- ///
- /// </summary>
- WM_KEYUP = 257,
-
- /// <summary>
- ///
- /// </summary>
- WM_SYSKEYUP = 261,
-
- /// <summary>
- ///
- /// </summary>
- WM_SYSKEYDOWN = 260
- }
-
- #endregion
-
- #region Statics
-
- public static IntPtr SetHook(LowLevelKeyboardProc proc)
- {
- using (Process curProcess = Process.GetCurrentProcess())
- using (ProcessModule curModule = curProcess.MainModule)
- {
- return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
- GetModuleHandle(curModule.ModuleName), 0);
- }
- }
-
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
-
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool UnhookWindowsHookEx(IntPtr hhk);
-
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);
-
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr GetModuleHandle(string lpModuleName);
-
- #endregion
- }
-
- #endregion
- }