PageRenderTime 60ms CodeModel.GetById 2ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 1ms

/Application/GUI/Controls/ControlPanel.xaml.cs

http://yet-another-music-application.googlecode.com/
C# | 1811 lines | 1188 code | 204 blank | 419 comment | 161 complexity | c863f3adef0c7c9a3f31719f86eef2de MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * ControlPanel.xaml.cs
   3 * 
   4 * The "Control Panel" screen used to show all the preferences
   5 * of Stoffi.
   6 * 
   7 * * * * * * * * *
   8 * 
   9 * This code is part of the Stoffi Music Player Project.
  10 * Visit our website at: stoffiplayer.com
  11 *
  12 * This program is free software; you can redistribute it and/or
  13 * modify it under the terms of the GNU General Public License
  14 * as published by the Free Software Foundation; either version
  15 * 3 of the License, or (at your option) any later version.
  16 * 
  17 * See stoffiplayer.com/license for more information.
  18 **/
  19
  20using System;
  21using System.Collections;
  22using System.Collections.Generic;
  23using System.Linq;
  24using System.Text;
  25using System.Windows;
  26using System.Windows.Controls;
  27using System.Windows.Data;
  28using System.Windows.Documents;
  29using System.Windows.Input;
  30using System.Windows.Media;
  31using System.Windows.Media.Imaging;
  32using System.Windows.Navigation;
  33using System.Windows.Shapes;
  34using System.Windows.Threading;
  35using System.Threading;
  36using System.Globalization;
  37using Tomers.WPF.Localization;
  38
  39namespace Stoffi
  40{
  41	/// <summary>
  42	/// Interaction logic for ControlPanel.xaml
  43	/// </summary>
  44	public partial class ControlPanel : UserControl
  45	{
  46		#region Members
  47
  48		public StoffiWindow ParentWindow;
  49		private OpenAddPolicy openAddPolicy;
  50		private OpenPlayPolicy openFilePlay;
  51		private UpgradePolicy upgradePolicy;
  52		private SearchPolicy searchPolicy;
  53		private Boolean waitingForShortcut = false;
  54		private Button currentShortcutButton = null;
  55		private KeyboardShortcut currentShortcut = null;
  56		private List<Key> currentPressedKeys = new List<Key>();
  57		public List<TextBlock> ShortcutTitles = new List<TextBlock>();
  58		public List<TextBlock> ShortcutDescriptions = new List<TextBlock>();
  59		public List<Label> ShortcutLabels = new List<Label>();
  60		private Hashtable shortcutButtons = new Hashtable();
  61		private Hashtable shortcutCheckBoxes = new Hashtable();
  62		private Hashtable tabs = new Hashtable();
  63		private Hashtable tabLinks = new Hashtable();
  64		private MenuItem menuToggle;
  65		public MenuItem menuRemove;
  66		private ContextMenu sourceMenu;
  67		public Label GlobalLabel = new Label();
  68
  69		#endregion
  70
  71		#region Properties
  72
  73		/// <summary>
  74		/// 
  75		/// </summary>
  76		public OpenAddPolicy ExternalClickAdd
  77		{
  78			get { return openAddPolicy; }
  79			set
  80			{
  81				openAddPolicy = value;
  82				SettingsManager.OpenAddPolicy = value;
  83				Save();
  84			}
  85		}
  86
  87		/// <summary>
  88		/// 
  89		/// </summary>
  90		public OpenPlayPolicy ExternalClickPlay
  91		{
  92			get { return openFilePlay; }
  93			set
  94			{
  95				openFilePlay = value;
  96				SettingsManager.OpenPlayPolicy = value;
  97				Save();
  98			}
  99		}
 100
 101		/// <summary>
 102		/// 
 103		/// </summary>
 104		public UpgradePolicy UpgradePolicy
 105		{
 106			get { return upgradePolicy; }
 107			set
 108			{
 109				upgradePolicy = value;
 110				SettingsManager.UpgradePolicy = value;
 111				PrefDoUpgrade.Visibility = System.Windows.Visibility.Collapsed;
 112				Save();
 113
 114				if (value == Stoffi.UpgradePolicy.Manual)
 115				{
 116					UpgradeManager.Stop();
 117					EnableUpgradeCheck();
 118				}
 119				else // Notify or Automatic
 120				{
 121					PrefCheckForUpgrades.Visibility = System.Windows.Visibility.Collapsed;
 122					UpgradeProgress.Visibility = System.Windows.Visibility.Collapsed;
 123
 124					ThreadStart InitUpgradeManagerThread = delegate()
 125					{
 126						UpgradeManager.Stop();
 127						UpgradeManager.Start();
 128						UpgradeManager.Probe(null, null);
 129					};
 130					Thread um_thread = new Thread(InitUpgradeManagerThread);
 131					um_thread.Priority = ThreadPriority.BelowNormal;
 132					um_thread.Start();
 133				}
 134			}
 135		}
 136
 137		/// <summary>
 138		/// 
 139		/// </summary>
 140		public SearchPolicy SearchPolicy
 141		{
 142			get { return searchPolicy; }
 143			set
 144			{
 145				searchPolicy = value;
 146				SettingsManager.SearchPolicy = value;
 147				Save();
 148			}
 149		}
 150
 151		/// <summary>
 152		/// 
 153		/// </summary>
 154		public bool ShowOSD
 155		{
 156			get { return SettingsManager.ShowOSD; }
 157			set { SettingsManager.ShowOSD = value; Save(); }
 158		}
 159
 160		/// <summary>
 161		/// 
 162		/// </summary>
 163		public bool MinimizeToTray
 164		{
 165			get { return SettingsManager.MinimizeToTray; }
 166			set { SettingsManager.MinimizeToTray = value; Save(); }
 167		}
 168
 169		/// <summary>
 170		/// Gets or sets whether to submit songs when they are played
 171		/// </summary>
 172		public bool SubmitSongs
 173		{
 174			get { return SettingsManager.SubmitSongs; }
 175			set { SettingsManager.SubmitSongs = value; Save(); }
 176		}
 177
 178		/// <summary>
 179		/// Gets or sets whether to submit playlists when they are created
 180		/// </summary>
 181		public bool SubmitPlaylists
 182		{
 183			get { return SettingsManager.SubmitPlaylists; }
 184			set { SettingsManager.SubmitPlaylists = value; Save(); }
 185		}
 186
 187		/// <summary>
 188		/// Gets or sets whether to pause playback while computer is locked
 189		/// </summary>
 190		public bool PauseWhileLocked
 191		{
 192			get { return SettingsManager.PauseWhileLocked; }
 193			set { SettingsManager.PauseWhileLocked = value; Save(); }
 194		}
 195
 196		/// <summary>
 197		/// Gets or sets whether to pause playback while user is logged out
 198		/// </summary>
 199		public bool PauseWhileLoggedOut
 200		{
 201			get { return SettingsManager.PauseWhileLoggedOut; }
 202			set { SettingsManager.PauseWhileLoggedOut = value; Save(); }
 203		}
 204
 205		#endregion
 206
 207		#region Constructor
 208
 209		/// <summary>
 210		/// Creates a control panel
 211		/// </summary>
 212		public ControlPanel()
 213		{
 214			U.L(LogLevel.Debug, "CONTROL PANEL", "Initialize");
 215			InitializeComponent();
 216			U.L(LogLevel.Debug, "CONTROL PANEL", "Initialized");
 217
 218			openAddPolicy = SettingsManager.OpenAddPolicy;
 219			openFilePlay = SettingsManager.OpenPlayPolicy;
 220			upgradePolicy = SettingsManager.UpgradePolicy;
 221			searchPolicy = SettingsManager.SearchPolicy;
 222
 223			this.DataContext = this;
 224
 225			tabs.Add(Tab.General, ControlPanelGeneral);
 226			tabs.Add(Tab.Sources, ControlPanelSources);
 227			tabs.Add(Tab.Services, ControlPanelServices);
 228			tabs.Add(Tab.Shortcuts, ControlPanelShortcuts);
 229			tabs.Add(Tab.About, ControlPanelAbout);
 230			tabLinks.Add(Tab.General, ControlPanelLink_General);
 231			tabLinks.Add(Tab.Sources, ControlPanelLink_Sources);
 232			tabLinks.Add(Tab.Services, ControlPanelLink_Services);
 233			tabLinks.Add(Tab.Shortcuts, ControlPanelLink_Shortcuts);
 234			tabLinks.Add(Tab.About, ControlPanelLink_About);
 235
 236			menuRemove = new MenuItem();
 237			menuRemove.Header = U.T("MenuRemove");
 238			menuRemove.Click += new RoutedEventHandler(menuRemove_Click);
 239
 240			menuToggle = new MenuItem();
 241			menuToggle.Header = U.T("MenuIgnore");
 242			menuToggle.Click += new RoutedEventHandler(menuToggle_Click);
 243
 244			sourceMenu = new ContextMenu();
 245			sourceMenu.Items.Add(menuToggle);
 246			sourceMenu.Items.Add(menuRemove);
 247
 248			SourceList.ContextMenu = sourceMenu;
 249
 250			SettingsManager.PropertyChanged += new PropertyChangedWithValuesEventHandler(SettingsManager_PropertyChanged);
 251			ServiceManager.PropertyChanged += new PropertyChangedWithValuesEventHandler(ServiceManager_PropertyChanged);
 252			ServiceManager.Initialized += new EventHandler(ServiceManager_Initialized);
 253
 254			CloudSyncInterface csi = new CloudSyncInterface();
 255			ServiceBrowser.ObjectForScripting = csi;
 256
 257			U.L(LogLevel.Debug, "CONTROL PANEL", "Created");
 258		}
 259
 260		#endregion
 261
 262		#region Methods
 263
 264		#region Public
 265
 266		/// <summary>
 267		/// Initializes the controls for the shortcuts
 268		/// </summary>
 269		public void InitShortcuts()
 270		{
 271			String[,] categories = new String[4, 3]; // name, translation id (title), translation id (text
 272			categories[0, 0] = "Application";
 273			categories[0, 1] = "ShortcutApplicationTitle";
 274			categories[0, 2] = "ShortcutApplicationText";
 275
 276			categories[1, 0] = "MainWindow";
 277			categories[1, 1] = "ShortcutMainWindowTitle";
 278			categories[1, 2] = "ShortcutMainWindowText";
 279
 280			categories[2, 0] = "MediaCommands";
 281			categories[2, 1] = "ShortcutMediaCommandsTitle";
 282			categories[2, 2] = "ShortcutMediaCommandsText";
 283
 284			categories[3, 0] = "Track";
 285			categories[3, 1] = "ShortcutTrackTitle";
 286			categories[3, 2] = "ShortcutTrackText";
 287
 288			for (int i = 0; i < 4; i++)
 289			{
 290				DockPanel d = new DockPanel() { Margin = new Thickness(25, 15, 0, 5), LastChildFill = true };
 291
 292				TextBlock t = new TextBlock() { Text = U.T(categories[i, 1]) };
 293				t.Tag = categories[i, 1];
 294				DockPanel.SetDock(t, Dock.Left);
 295				ShortcutTitles.Add(t);
 296				d.Children.Add(t);
 297
 298				Separator s = new Separator();
 299				s.Background = Brushes.LightGray;
 300				s.Height = 1;
 301				s.Margin = new Thickness(5, 0, 5, 0);
 302				DockPanel.SetDock(s, Dock.Left);
 303				d.Children.Add(s);
 304
 305				DockPanel.SetDock(d, Dock.Top);
 306				ShortcutPanel.Children.Add(d);
 307
 308				TextBlock tb = new TextBlock();
 309				tb.Margin = new Thickness(50, 5, 0, 5);
 310				tb.TextWrapping = TextWrapping.Wrap;
 311				tb.Inlines.Add(U.T(categories[i, 2]));
 312				tb.Tag = categories[i, 2];
 313				ShortcutDescriptions.Add(tb);
 314				DockPanel.SetDock(tb, Dock.Top);
 315				ShortcutPanel.Children.Add(tb);
 316
 317				GridLengthConverter conv = new GridLengthConverter();
 318				Grid g = new Grid();
 319				g.Margin = new Thickness(50, 5, 0, 5);
 320				g.ColumnDefinitions.Add(new ColumnDefinition() { Width = (GridLength)conv.ConvertFrom(170) });
 321				g.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
 322				g.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
 323				g.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
 324
 325				int j;
 326				KeyboardShortcutProfile profile = SettingsManager.GetCurrentShortcutProfile();
 327				for (j = 0; j < profile.Shortcuts.Count; j++)
 328					g.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
 329
 330				if (categories[i, 0] == "MediaCommands")
 331				{
 332					GlobalLabel.Content = U.T("ShortcutGlobal");
 333					GlobalLabel.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
 334					Grid.SetColumn(GlobalLabel, 2);
 335					Grid.SetRow(GlobalLabel, 0);
 336					g.Children.Add(GlobalLabel);
 337				}
 338
 339				j = 1;
 340				foreach (KeyboardShortcut sc in profile.Shortcuts)
 341				{
 342					// skip now playing
 343					if (sc.Name == "Now playing") continue;
 344
 345					if (sc.Category != categories[i, 0]) continue;
 346					Label l = new Label() { Content = U.T("Shortcut_" + sc.Name.Replace(" ","_")) };
 347					l.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
 348					l.Tag = "Shortcut_" + sc.Name.Replace(" ", "_");
 349					Grid.SetColumn(l, 0);
 350					Grid.SetRow(l, j);
 351					g.Children.Add(l);
 352					ShortcutLabels.Add(l);
 353
 354					Button b = new Button() { Content = sc.Keys, MinWidth = 100 };
 355					b.Name = sc.Category + "_" + sc.Name.Replace(" ", "_");
 356					b.LostFocus += PrefShortcutButton_LostFocus;
 357					b.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
 358					b.Margin = new Thickness(2);
 359					b.Click += PrefShortcutButton_Clicked;
 360					shortcutButtons.Add(b.Name, b);
 361					Grid.SetColumn(b, 1);
 362					Grid.SetRow(b, j);
 363					g.Children.Add(b);
 364
 365					if (categories[i, 0] == "MediaCommands")
 366					{
 367						CheckBox cb = new CheckBox() { IsChecked = sc.IsGlobal, Name = b.Name, ToolTip = U.T("ShortcutGlobal", "ToolTip") };
 368						cb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
 369						cb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
 370						cb.Margin = new Thickness(10, 0, 10, 0);
 371						cb.Click += PrefShortcutGlobal_Clicked;
 372						shortcutCheckBoxes.Add(b.Name, cb);
 373						Grid.SetColumn(cb, 2);
 374						Grid.SetRow(cb, j);
 375						g.Children.Add(cb);
 376					}
 377
 378					j++;
 379				}
 380
 381				DockPanel.SetDock(g, Dock.Top);
 382				ShortcutPanel.Children.Add(g);
 383			}
 384
 385			((Grid)ShortcutPanel.Children[ShortcutPanel.Children.Count - 1]).Margin = new Thickness(50, 5, 0, 25);
 386
 387			string selTxt = SettingsManager.CurrentShortcutProfile;
 388			int sel = 0;
 389			foreach (KeyboardShortcutProfile p in SettingsManager.ShortcutProfiles)
 390			{
 391				if (selTxt == p.Name)
 392					sel = PrefShortcutProfile.Items.Count;
 393				PrefShortcutProfile.Items.Add(new ComboBoxItem() { Content = p.Name });
 394			}
 395			PrefShortcutProfile.SelectedIndex = sel;
 396		}
 397
 398		/// <summary>
 399		/// Updates the timestamp for the latest check for upgrades
 400		/// </summary>
 401		public void UpdateUpgradeCheck()
 402		{
 403			try
 404			{
 405				string text = Unix2Date(SettingsManager.UpgradeCheck);
 406				AboutUpgradeCheck.Text = text;
 407				if (UpgradeManager.Pending)
 408				{
 409					AboutUpgradePending.Visibility = System.Windows.Visibility.Visible;
 410					ParentWindow.UpgradeButton.Visibility = Visibility.Visible;
 411				}
 412			}
 413			catch
 414			{
 415				AboutUpgradeCheck.Text = U.T("UpgradeNotChecked");
 416			}
 417			if (SettingsManager.UpgradeCheck == 0)
 418				AboutUpgradeCheck.Text = U.T("UpgradeNotChecked");
 419		}
 420
 421		/// <summary>
 422		/// 
 423		/// </summary>
 424		/// <param name="timestamp"></param>
 425		/// <returns></returns>
 426		public String Unix2Date(long timestamp)
 427		{
 428			DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
 429			dt = dt.AddSeconds(timestamp);
 430			dt = dt.AddSeconds((DateTime.Now - DateTime.UtcNow).TotalSeconds);
 431			return String.Format("{0:ddd, MMM d, yyy HH:mm}", dt);
 432		}
 433
 434		/// <summary>
 435		/// 
 436		/// </summary>
 437		/// <param name="timestamp"></param>
 438		/// <returns></returns>
 439		public String Version2String(long timestamp)
 440		{
 441			int v1 = (int)(timestamp / 1000000000);
 442			int v2 = (int)(timestamp / 10000000) % 100;
 443			int v3 = (int)(timestamp / 10000) % 1000;
 444			int v4 = (int)(timestamp % 10000);
 445			return v1 + "." + v2 + "." + v3 + "." + v4;
 446		}
 447
 448		/// <summary>
 449		/// 
 450		/// </summary>
 451		public void EnableUpgradeDo()
 452		{
 453			U.L(LogLevel.Debug, "CONTROL", "Enabling upgrade button");
 454			PrefDoUpgrade.Visibility = System.Windows.Visibility.Visible;
 455			PrefDoUpgrade.IsEnabled = true;
 456			PrefDoUpgrade.Content = U.T("GeneralDoUpgrade", "Content");
 457
 458			PrefCheckForUpgrades.Visibility = System.Windows.Visibility.Collapsed;
 459			Restart.Visibility = System.Windows.Visibility.Collapsed;
 460			UpgradeProgress.Visibility = System.Windows.Visibility.Collapsed;
 461			if (ParentWindow.TaskbarItemInfo != null)
 462				ParentWindow.TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
 463		}
 464
 465		/// <summary>
 466		/// 
 467		/// </summary>
 468		public void EnableUpgradeCheck()
 469		{
 470			U.L(LogLevel.Debug, "CONTROL", "Enabling upgrade check button");
 471			PrefCheckForUpgrades.Visibility = System.Windows.Visibility.Visible;
 472			PrefCheckForUpgrades.IsEnabled = true;
 473			PrefCheckForUpgrades.Content = U.T("GeneralDoCheck", "Content");
 474
 475
 476			PrefDoUpgrade.Visibility = System.Windows.Visibility.Collapsed;
 477			Restart.Visibility = System.Windows.Visibility.Collapsed;
 478			UpgradeProgress.Visibility = System.Windows.Visibility.Collapsed;
 479			if (ParentWindow.TaskbarItemInfo != null)
 480				ParentWindow.TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
 481
 482		}
 483
 484		/// <summary>
 485		/// 
 486		/// </summary>
 487		public void EnableRestart()
 488		{
 489			U.L(LogLevel.Debug, "CONTROL", "Enabling restart button");
 490			Restart.Visibility = System.Windows.Visibility.Visible;
 491
 492			PrefCheckForUpgrades.Visibility = System.Windows.Visibility.Collapsed;
 493			PrefDoUpgrade.Visibility = System.Windows.Visibility.Collapsed;
 494			UpgradeProgress.Visibility = System.Windows.Visibility.Collapsed;
 495			if (ParentWindow.TaskbarItemInfo != null)
 496				ParentWindow.TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
 497		}
 498
 499		/// <summary>
 500		/// 
 501		/// </summary>
 502		/// <param name="tab"></param>
 503		public void SwitchTab(Tab tab)
 504		{
 505			foreach (DictionaryEntry c in tabs)
 506				((ScrollViewer)c.Value).Visibility = ((Tab)c.Key) == tab ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
 507			foreach (DictionaryEntry c in tabLinks)
 508				((Button)c.Value).Style = ((Tab)c.Key) == tab ? (Style)FindResource("ControlPanelLinkActiveStyle") : (Style)FindResource("ControlPanelLinkStyle");
 509		}
 510
 511		#endregion
 512
 513		#region Private
 514
 515		/// <summary>
 516		/// 
 517		/// </summary>
 518		/// <param name="str"></param>
 519		/// <param name="everyWord"></param>
 520		/// <returns></returns>
 521		private String Capitalize(String str, bool everyWord = false)
 522		{
 523			if (everyWord)
 524			{
 525				string[] r = str.Split(' ');
 526				for (int i = 0; i < r.Count(); i++)
 527					r[i] = Capitalize(r[i], false);
 528				return String.Join(" ", r);
 529			}
 530
 531			return str[0].ToString().ToUpper() + str.Substring(1).ToLower();
 532		}
 533
 534		/// <summary>
 535		/// 
 536		/// </summary>
 537		private void ResetShortcutButton()
 538		{
 539			if (!waitingForShortcut) return;
 540			waitingForShortcut = false;
 541			currentShortcutButton.Content = currentShortcut.Keys == "" ? U.T("ShortcutNotUsed") : currentShortcut.Keys;
 542			currentShortcutButton.FontStyle = currentShortcut.Keys == "" ? FontStyles.Italic : FontStyles.Normal;
 543			currentShortcut = null;
 544			currentShortcutButton = null;
 545		}
 546
 547		/// <summary>
 548		/// 
 549		/// </summary>
 550		/// <param name="name"></param>
 551		/// <returns></returns>
 552		private KeyboardShortcutProfile CreateShortcutProfile(String name = "")
 553		{
 554			KeyboardShortcutProfile profile = new KeyboardShortcutProfile();
 555			bool copy = false;
 556
 557			if (name == "")
 558			{
 559				// create a "CustomX" name
 560				int i=0;
 561				bool found;
 562				while (true)
 563				{
 564					i++;
 565					found = false;
 566					foreach (KeyboardShortcutProfile scp in SettingsManager.ShortcutProfiles)
 567						if (scp.Name == U.T("ShortcutCustom") + i.ToString())
 568							found = true;
 569					if (found) continue;
 570					name = U.T("ShortcutCustom") + i.ToString();
 571					break;
 572				}
 573
 574				copy = true;
 575			}
 576
 577			SettingsManager.InitShortcutProfile(profile, name, false);
 578
 579			if (copy) // copy shortcuts from current profile
 580			{
 581				KeyboardShortcutProfile currentProfile = SettingsManager.GetCurrentShortcutProfile();
 582				foreach (KeyboardShortcut sc in currentProfile.Shortcuts)
 583				{
 584					KeyboardShortcut newSc = SettingsManager.GetKeyboardShortcut(profile, sc.Category, sc.Name);
 585					newSc.Keys = sc.Keys;
 586				}
 587			}
 588
 589			SettingsManager.ShortcutProfiles.Add(profile);
 590			PrefShortcutProfile.Items.Add(new ComboBoxItem() { Content = profile.Name });
 591			PrefShortcutProfile.SelectedIndex = PrefShortcutProfile.Items.Count - 1;
 592			return profile;
 593		}
 594
 595		/// <summary>
 596		/// 
 597		/// </summary>
 598		private void Save()
 599		{
 600			// TODO: Try to save the settings in the background without any hickups
 601			/*
 602			ThreadStart SaveThread = delegate()
 603			{
 604				SettingsManager.Save();
 605			};
 606			Thread save_thread = new Thread(SaveThread);
 607			save_thread.Name = "Save Settings Thread";
 608			save_thread.Priority = ThreadPriority.Lowest;
 609			save_thread.Start();
 610			*/
 611		}
 612
 613		#endregion
 614
 615		#region Event handlers
 616
 617		/// <summary>
 618		/// Invoked when the service browser is navigating to a new URL.
 619		/// Will attempt to start linking at ServiceManager if the browser
 620		/// is detected to get redirected back to the designated callback URL.
 621		/// </summary>
 622		/// <param name="sender">The sender of the event</param>
 623		/// <param name="e">The event data</param>
 624		private void ServiceBrowser_Navigating(object sender, NavigatingCancelEventArgs e)
 625		{
 626			// hide browser and show loading indicator
 627			if (BrowserContainer.Children.Contains(ServiceBrowser))
 628				BrowserContainer.Children.Remove(ServiceBrowser);
 629			if (!BrowserContainer.Children.Contains(BrowserLoadingIndicator))
 630				BrowserContainer.Children.Add(BrowserLoadingIndicator);
 631
 632			// going to callback with extra parameters
 633			if (e.Uri.AbsoluteUri.StartsWith(ServiceManager.CallbackURL) && 
 634				e.Uri.AbsoluteUri != ServiceManager.CallbackURL &&
 635				e.Uri.AbsoluteUri != ServiceManager.CallbackURLWithAuthParams)
 636			{
 637				ServiceManager.Link(e.Uri.AbsoluteUri);
 638			}
 639
 640			// prevent going to root url
 641			else if (e.Uri.AbsoluteUri == "http://alpha.stoffiplayer.com/")
 642			{
 643				string url = ServiceManager.RequestURL;
 644				ServiceBrowser.Source = new Uri(url);
 645			}
 646		}
 647
 648		/// <summary>
 649		/// Invoked when the service browser has navigated to a new URL.
 650		/// Will hide the browser loading indicator and show the browser.
 651		/// </summary>
 652		/// <param name="sender">The sender of the event</param>
 653		/// <param name="e">The event data</param>
 654		private void ServiceBrowser_Navigated(object sender, NavigationEventArgs e)
 655		{
 656			if (!BrowserContainer.Children.Contains(ServiceBrowser))
 657				BrowserContainer.Children.Add(ServiceBrowser);
 658			if (BrowserContainer.Children.Contains(BrowserLoadingIndicator))
 659				BrowserContainer.Children.Remove(BrowserLoadingIndicator);
 660		}
 661
 662		/// <summary>
 663		/// Invoked when the user clicks on Delink.
 664		/// </summary>
 665		/// <param name="sender">The sender of the event</param>
 666		/// <param name="e">The event data</param>
 667		private void Delink_Click(object sender, RoutedEventArgs e)
 668		{
 669			ServiceManager.Delink();
 670		}
 671
 672		/// <summary>
 673		/// Invoked when the user changes the device name.
 674		/// Will send the new name to the server.
 675		/// </summary>
 676		/// <param name="sender">The sender of the event</param>
 677		/// <param name="e">The event data</param>
 678		private void DeviceName_Edited(object sender, EditableTextBlockEventArgs e)
 679		{
 680			ServiceManager.DeviceName = e.NewText;
 681		}
 682
 683		/// <summary>
 684		/// Invoked when a property changes in the service manager.
 685		/// </summary>
 686		/// <param name="sender">The sender of the event</param>
 687		/// <param name="e">The event data</param>
 688		private void ServiceManager_PropertyChanged(object sender, PropertyChangedWithValuesEventArgs e)
 689		{
 690			Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
 691			{
 692				switch (e.PropertyName)
 693				{
 694					case "DeviceName":
 695						DeviceName.Edited -= DeviceName_Edited;
 696						DeviceName.Text = e.NewValue as string;
 697						DeviceName.Edited += DeviceName_Edited;
 698						break;
 699
 700					case "Linked":
 701						if (ServiceManager.Linked)
 702						{
 703							if (!ServiceRootPanel.Children.Contains(ServicePanel))
 704								ServiceRootPanel.Children.Add(ServicePanel);
 705							Delink.Visibility = System.Windows.Visibility.Visible;
 706							DeviceNamePanel.Visibility = System.Windows.Visibility.Visible;
 707							ServiceBrowser.Source = new Uri(ServiceManager.CallbackURL);
 708						}
 709						else
 710						{
 711							if (ServiceRootPanel.Children.Contains(ServicePanel))
 712								ServiceRootPanel.Children.Remove(ServicePanel);
 713							Delink.Visibility = System.Windows.Visibility.Collapsed;
 714							DeviceNamePanel.Visibility = System.Windows.Visibility.Collapsed;
 715							ServiceBrowser.Source = new Uri(ServiceManager.LogoutURL);
 716						}
 717						break;
 718
 719					case "SyncProfiles":
 720						List<int> existingIDs = new List<int>();
 721
 722						// remove old
 723						for (int i=1; i < SynchronizeProfile.Items.Count; i++)
 724						{
 725							ComboBoxItem cbi = SynchronizeProfile.Items[i] as ComboBoxItem;
 726							int id = (int)cbi.Tag;
 727							if (id > 0)
 728							{
 729								if (ServiceManager.SyncProfiles.ContainsKey(id))
 730								{
 731									cbi.Content = ServiceManager.SyncProfiles[id];
 732									existingIDs.Add(id);
 733								}
 734								else
 735								{
 736									SynchronizeProfile.Items.RemoveAt(i);
 737									i--;
 738								}
 739							}
 740						}
 741						for (int i = 0; i < ConfigPanel.Children.Count - 1; i++)
 742						{
 743							StackPanel sp = ConfigPanel.Children[i] as StackPanel;
 744							int id = (int)sp.Tag;
 745							if (id > 0 && !ServiceManager.SyncProfiles.ContainsKey(id))
 746							{
 747								ConfigPanel.Children.RemoveAt(i);
 748								i--;
 749							}
 750						}
 751
 752						// add new
 753						foreach (KeyValuePair<int, string> profile in ServiceManager.SyncProfiles)
 754						{
 755							if (!existingIDs.Contains(profile.Key))
 756							{
 757								ComboBoxItem cbi = new ComboBoxItem();
 758								cbi.Tag = profile.Key;
 759								cbi.Content = profile.Value;
 760								SynchronizeProfile.Items.Add(cbi);
 761
 762								StackPanel sp = new StackPanel();
 763								sp.Orientation = Orientation.Horizontal;
 764								sp.Tag = profile.Key;
 765
 766								EditableTextBlock etb = new EditableTextBlock();
 767								etb.Text = profile.Value;
 768								etb.ClickToEdit = true;
 769								etb.SimpleHover = true;
 770								etb.Width = 150;
 771								etb.Margin = new Thickness(5);
 772								etb.Tag = profile.Key;
 773								etb.Edited += new EditableTextBlockDelegate(ConfigurationName_Edited);
 774
 775								Image img = new Image();
 776								img.Source = new BitmapImage(new Uri("../Images/Buttons/Close.gif", UriKind.RelativeOrAbsolute));
 777								img.MouseLeftButtonDown += new MouseButtonEventHandler(DeleteConfiguration_MouseLeftButtonDown);
 778								img.Width = 8;
 779								img.Height = 8;
 780								img.Margin = new Thickness(10, 0, 0, 0);
 781								img.Cursor = Cursors.Hand;
 782								img.Tag = profile.Key;
 783								img.VerticalAlignment = System.Windows.VerticalAlignment.Center;
 784
 785								sp.Children.Add(etb);
 786								sp.Children.Add(img);
 787
 788								ConfigPanel.Children.Insert(ConfigPanel.Children.Count - 1, sp);
 789							}
 790						}
 791
 792						// select current
 793						if (SettingsManager.SynchronizeID > 0)
 794						{
 795							foreach (ComboBoxItem cbi in SynchronizeProfile.Items)
 796							{
 797								int id = -1;
 798								try { id = (int)cbi.Tag; }
 799								catch { }
 800								if (id == SettingsManager.SynchronizeID)
 801								{
 802									cbi.IsSelected = true;
 803									break;
 804								}
 805							}
 806						}
 807						break;
 808				}
 809			}));
 810		}
 811
 812		/// <summary>
 813		/// Invoked when the user changes size of the control panel
 814		/// </summary>
 815		/// <param name="sender">The sender of the event</param>
 816		/// <param name="e">The event data</param>
 817		private void ControlPanel_SizeChanged(object sender, SizeChangedEventArgs e)
 818		{
 819			ScrollBarVisibility vis = e.NewSize.Width < 600 ? ScrollBarVisibility.Auto : ScrollBarVisibility.Disabled;
 820			//ControlPanelAbout.HorizontalScrollBarVisibility = vis;
 821			ControlPanelGeneral.HorizontalScrollBarVisibility = vis;
 822			ControlPanelShortcuts.HorizontalScrollBarVisibility = vis;
 823			ControlPanelSources.HorizontalScrollBarVisibility = vis;
 824		}
 825
 826		/// <summary>
 827		/// Invoked when the control panel is loaded
 828		/// </summary>
 829		/// <param name="sender">The sender of the event</param>
 830		/// <param name="e">The event data</param>
 831		private void ControlPanel_Loaded(object sender, RoutedEventArgs e)
 832		{
 833			if (System.Windows.Forms.VisualStyles.VisualStyleInformation.DisplayName == "")
 834			{
 835				ControlPanelMain.Background = SystemColors.WindowBrush;
 836				ControlPanelLeft.Background = SystemColors.WindowBrush;
 837			}
 838			AboutChannel.Text = Capitalize(SettingsManager.Channel);
 839			UpdateUpgradeCheck();
 840
 841			AboutVersion.Text = Capitalize(SettingsManager.Release, true); // release name
 842			AboutRelease.Text = Unix2Date(SettingsManager.Version); // release date
 843			AboutStamp.Text = Version2String(SettingsManager.Version); // release version
 844			AboutArch.Text = SettingsManager.Architecture + "-bit";
 845			SettingsManager.Sources.CollectionChanged +=
 846				new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SourceList.ItemsSource_CollectionChanged);
 847
 848			if (SettingsManager.UpgradePolicy == UpgradePolicy.Manual)
 849				PrefCheckForUpgrades.Visibility = System.Windows.Visibility.Visible;
 850
 851			// create languages
 852			foreach (ComboBoxItem cbi in PrefLanguage.Items)
 853			{
 854				if ((string)cbi.Tag == SettingsManager.Language)
 855				{
 856					PrefLanguage.SelectedItem = cbi;
 857					break;
 858				}
 859			}
 860
 861			UpgradePolicyDescriptionConverter uconv = new UpgradePolicyDescriptionConverter();
 862			string upolicy = (string)uconv.Convert(UpgradePolicy, null, null, null);
 863
 864			SearchPolicyDescriptionConverter sconv = new SearchPolicyDescriptionConverter();
 865			string spolicy = (string)sconv.Convert(SearchPolicy, null, null, null);
 866
 867			OpenFileAddDescriptionConverter aconv = new OpenFileAddDescriptionConverter();
 868			string apolicy = (string)aconv.Convert(ExternalClickAdd, null, null, null);
 869
 870			OpenFilePlayDescriptionConverter pconv = new OpenFilePlayDescriptionConverter();
 871			string ppolicy = (string)pconv.Convert(ExternalClickPlay, null, null, null);
 872
 873			foreach (ComboBoxItem cbi in SearchPolicyCombo.Items)
 874			{
 875				if ((string)cbi.Content == spolicy)
 876				{
 877					SearchPolicyCombo.SelectedItem = cbi;
 878					break;
 879				}
 880			}
 881
 882			foreach (ComboBoxItem cbi in UpgradePolicyCombo.Items)
 883			{
 884				if ((string)cbi.Content == upolicy)
 885				{
 886					UpgradePolicyCombo.SelectedItem = cbi;
 887					break;
 888				}
 889			}
 890
 891			foreach (ComboBoxItem cbi in AddPolicyCombo.Items)
 892			{
 893				if ((string)cbi.Content == apolicy)
 894				{
 895					AddPolicyCombo.SelectedItem = cbi;
 896					break;
 897				}
 898			}
 899
 900			foreach (ComboBoxItem cbi in PlayPolicyCombo.Items)
 901			{
 902				if ((string)cbi.Content == ppolicy)
 903				{
 904					PlayPolicyCombo.SelectedItem = cbi;
 905					break;
 906				}
 907			}
 908
 909			SearchPolicyCombo.SelectionChanged += new SelectionChangedEventHandler(SearchPolicyCombo_SelectionChanged);
 910			UpgradePolicyCombo.SelectionChanged += new SelectionChangedEventHandler(UpgradePolicyCombo_SelectionChanged);
 911			AddPolicyCombo.SelectionChanged += new SelectionChangedEventHandler(AddPolicyCombo_SelectionChanged);
 912			PlayPolicyCombo.SelectionChanged += new SelectionChangedEventHandler(PlayPolicyCombo_SelectionChanged);
 913			PrefLanguage.SelectionChanged += new SelectionChangedEventHandler(PrefLanguage_SelectionChanged);
 914		}
 915
 916		/// <summary>
 917		/// Invoked when the control panel has been initialized.
 918		/// </summary>
 919		/// <param name="sender">The sender of the event</param>
 920		/// <param name="e">The event data</param>
 921		private void ControlPanel_Initialized(object sender, EventArgs e)
 922		{
 923		}
 924
 925		/// <summary>
 926		/// Invoked when the service manager has been fully initialized.
 927		/// </summary>
 928		/// <param name="sender">The sender of the event</param>
 929		/// <param name="e">The event data</param>
 930		private void ServiceManager_Initialized(object sender, EventArgs e)
 931		{
 932			Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate()
 933			{
 934				ServiceBrowser.Source = new Uri(ServiceManager.Linked ? ServiceManager.CallbackURLWithAuthParams : ServiceManager.RequestURL);
 935			}));
 936		}
 937
 938		/// <summary>
 939		/// Invoked when the user clicks on "Back to music"
 940		/// </summary>
 941		/// <param name="sender">The sender of the event</param>
 942		/// <param name="e">The event data</param>
 943		private void Back_Clicked(object sender, RoutedEventArgs e)
 944		{
 945			ParentWindow.MainContainer.Children.Remove(ParentWindow.ControlPanel);
 946			ParentWindow.MusicPanel.Visibility = System.Windows.Visibility.Visible;
 947			ParentWindow.PlaybackControls.Search.Box.IsEnabled = (SettingsManager.CurrentSelectedNavigation != "NowPlaying");
 948		}
 949
 950		/// <summary>
 951		/// Invoked when the user clicks on General
 952		/// </summary>
 953		/// <param name="sender">The sender of the event</param>
 954		/// <param name="e">The event data</param>
 955		private void General_Clicked(object sender, RoutedEventArgs e)
 956		{
 957			SwitchTab(Tab.General);
 958		}
 959
 960		/// <summary>
 961		/// Invoked when the user clicks on Sources
 962		/// </summary>
 963		/// <param name="sender">The sender of the event</param>
 964		/// <param name="e">The event data</param>
 965		private void Sources_Clicked(object sender, RoutedEventArgs e)
 966		{
 967			SwitchTab(Tab.Sources);
 968		}
 969
 970		/// <summary>
 971		/// Invoked when the user clicks on Services
 972		/// </summary>
 973		/// <param name="sender">The sender of the event</param>
 974		/// <param name="e">The event data</param>
 975		private void Services_Clicked(object sender, RoutedEventArgs e)
 976		{
 977			SwitchTab(Tab.Services);
 978		}
 979
 980		/// <summary>
 981		/// Invoked when the user clicks on Shortcuts
 982		/// </summary>
 983		/// <param name="sender">The sender of the event</param>
 984		/// <param name="e">The event data</param>
 985		private void Shortcuts_Clicked(object sender, RoutedEventArgs e)
 986		{
 987			SwitchTab(Tab.Shortcuts);
 988		}
 989
 990		/// <summary>
 991		/// Invoked when the user clicks on About
 992		/// </summary>
 993		/// <param name="sender">The sender of the event</param>
 994		/// <param name="e">The event data</param>
 995		private void About_Clicked(object sender, RoutedEventArgs e)
 996		{
 997			SwitchTab(Tab.About);
 998		}
 999
1000		/// <summary>
1001		/// Invoked when the user clicks on Website
1002		/// </summary>
1003		/// <param name="sender">The sender of the event</param>
1004		/// <param name="e">The event data</param>
1005		private void Website_Clicked(object sender, RoutedEventArgs e)
1006		{
1007			System.Diagnostics.Process.Start("http://www.stoffiplayer.com/?ref=stoffi");
1008		}
1009
1010		/// <summary>
1011		/// Invoked when the user clicks on Blog
1012		/// </summary>
1013		/// <param name="sender">The sender of the event</param>
1014		/// <param name="e">The event data</param>
1015		private void Blog_Clicked(object sender, RoutedEventArgs e)
1016		{
1017			System.Diagnostics.Process.Start("http://blog.stoffiplayer.com/?ref=stoffi");
1018		}
1019
1020		/// <summary>
1021		/// Invoked when the user clicks on Project
1022		/// </summary>
1023		/// <param name="sender">The sender of the event</param>
1024		/// <param name="e">The event data</param>
1025		private void Project_Clicked(object sender, RoutedEventArgs e)
1026		{
1027			System.Diagnostics.Process.Start("http://dev.stoffiplayer.com/?ref=stoffi");
1028		}
1029
1030		/// <summary>
1031		/// Invoked when the user adds a folder
1032		/// </summary>
1033		/// <param name="sender">The sender of the event</param>
1034		/// <param name="e">The event data</param>
1035		public void AddFolder_Clicked(object sender, RoutedEventArgs e)
1036		{
1037			ParentWindow.AddFolder_Clicked(sender, e);
1038		}
1039
1040		/// <summary>
1041		/// Invoked when the user adds a file
1042		/// </summary>
1043		/// <param name="sender">The sender of the event</param>
1044		/// <param name="e">The event data</param>
1045		public void AddFile_Clicked(object sender, RoutedEventArgs e)
1046		{
1047			ParentWindow.AddFile_Clicked(sender, e);
1048		}
1049
1050		/// <summary>
1051		/// Invoked when the user ignores a folder
1052		/// </summary>
1053		/// <param name="sender">The sender of the event</param>
1054		/// <param name="e">The event data</param>
1055		private void IgnoreFolder_Clicked(object sender, RoutedEventArgs e)
1056		{
1057			ParentWindow.IgnoreFolder_Clicked(sender, e);
1058		}
1059
1060		/// <summary>
1061		/// Invoked when the user ignores a file
1062		/// </summary>
1063		/// <param name="sender">The sender of the event</param>
1064		/// <param name="e">The event data</param>
1065		private void IgnoreFile_Clicked(object sender, RoutedEventArgs e)
1066		{
1067			ParentWindow.IgnoreFile_Clicked(sender, e);
1068		}
1069
1070		/// <summary>
1071		/// Invoked when the user right-click on a source and clicks on Remove
1072		/// </summary>
1073		/// <param name="sender">The sender of the event</param>
1074		/// <param name="e">The event data</param>
1075		private void menuRemove_Click(object sender, RoutedEventArgs e)
1076		{
1077			int index = SourceList.SelectedIndex;
1078			ThreadStart RemoveThread = delegate()
1079			{
1080				Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate()
1081				{
1082					int keep = 0;
1083					while (SourceList.SelectedItems.Count > keep)
1084					{
1085						SourceData source = SourceList.SelectedItems[keep] as SourceData;
1086						if (source.Type == SourceType.Library)
1087						{
1088							FilesystemManager.ToggleSource(source);
1089							keep++;
1090						}
1091						else
1092							FilesystemManager.RemoveSource(source);
1093					}
1094
1095					if (index >= SourceList.Items.Count)
1096						index = SourceList.Items.Count - 1;
1097
1098					if (keep == 0)
1099						SourceList.SelectedIndex = index;
1100				}));
1101			};
1102			Thread rb_thread = new Thread(RemoveThread);
1103			rb_thread.Name = "Remove Sources";
1104			rb_thread.Priority = ThreadPriority.BelowNormal;
1105			rb_thread.Start();
1106		}
1107
1108		/// <summary>
1109		/// Invoked when the user right-click on a source and clicks on Ignore/Include
1110		/// </summary>
1111		/// <param name="sender">The sender of the event</param>
1112		/// <param name="e">The event data</param>
1113		private void menuToggle_Click(object sender, RoutedEventArgs e)
1114		{
1115			ThreadStart ToggleThread = delegate()
1116			{
1117				Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate()
1118				{
1119					foreach (SourceData source in SourceList.SelectedItems)
1120						FilesystemManager.ToggleSource(source);
1121				}));
1122			};
1123			Thread tog_thread = new Thread(ToggleThread);
1124			tog_thread.Name = "Toggle Sources";
1125			tog_thread.Priority = ThreadPriority.BelowNormal;
1126			tog_thread.Start();
1127		}
1128
1129		/// <summary>
1130		/// Invoked when the context menu of the source list is opening
1131		/// </summary>
1132		/// <param name="sender">The sender of the event</param>
1133		/// <param name="e">The event data</param>
1134		private void SourceList_ContextMenuOpening(object sender, ContextMenuEventArgs e)
1135		{
1136			bool hasOnlyLibrary = true;
1137			bool hasIgnored = false;
1138
1139			foreach (SourceData s in SourceList.SelectedItems)
1140			{
1141				if (s.Type != SourceType.Library)
1142					hasOnlyLibrary = false;
1143				if (s.Ignore)
1144					hasIgnored = true;
1145			}
1146
1147			menuRemove.Visibility = (hasOnlyLibrary ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible);
1148			menuToggle.Header = (hasIgnored ? U.T("MenuInclude") : U.T("MenuIgnore"));
1149		}
1150
1151		/// <summary>
1152		/// Invoked when the user presses a key
1153		/// </summary>
1154		/// <param name="sender">The sender of the event</param>
1155		/// <param name="e">The event data</param>
1156		private void SourceList_KeyDown(object sender, KeyEventArgs e)
1157		{
1158			if (e.Key == Key.Delete)
1159			{
1160				List<SourceData> sources = new List<SourceData>();
1161				foreach (SourceData s in ((ListView)sender).SelectedItems)
1162					sources.Add(s);
1163				menuRemove_Click(null, null);
1164			}
1165		}
1166
1167		/// <summary>
1168		/// Invoked when theuser clicks to check for upgrades
1169		/// </summary>
1170		/// <param name="sender">The sender of the event</param>
1171		/// <param name="e">The event data</param>
1172		private void CheckForUpgrades_Clicked(object sender, RoutedEventArgs e)
1173		{
1174			UpgradeMessageClose_MouseLeftButtonDown(null, null);
1175
1176			PrefCheckForUpgrades.IsEnabled = false;
1177			PrefCheckForUpgrades.Content = U.T("UpgradeWait");
1178
1179			UpgradeProgressLabel.Text = U.T("UpgradeConnecting");
1180			UpgradeProgressBar.IsIndeterminate = true;
1181			UpgradeProgress.Visibility = System.Windows.Visibility.Visible;
1182
1183			ThreadStart InitUpgradeManagerThread = delegate()
1184			{
1185				UpgradeManager.Probe(null, null);
1186			};
1187			Thread um_thread = new Thread(InitUpgradeManagerThread);
1188			um_thread.Priority = ThreadPriority.BelowNormal;
1189			um_thread.Start();
1190		}
1191
1192		/// <summary>
1193		/// Invoked when the user clicks to perform an upgrade
1194		/// </summary>
1195		/// <param name="sender">The sender of the event</param>
1196		/// <param name="e">The event data</param>
1197		private void PrefDoUpgrade_Clicked(object sender, RoutedEventArgs e)
1198		{
1199			UpgradeMessageClose_MouseLeftButtonDown(null, null);
1200
1201			PrefDoUpgrade.IsEnabled = false;
1202			PrefDoUpgrade.Content = U.T("UpgradeWait");
1203
1204			UpgradeProgressLabel.Text = U.T("UpgradeWait");
1205			UpgradeProgressBar.IsIndeterminate = false;
1206			UpgradeProgressBar.Value = 0;
1207			UpgradeProgress.Visibility = System.Windows.Visibility.Visible;
1208			UpgradeProgressInfo.Visibility = System.Windows.Visibility.Visible;
1209
1210			ThreadStart InitUpgradeManagerThread = delegate()
1211			{
1212				UpgradeManager.ForceDownload = true;
1213				UpgradeManager.Probe(null, null);
1214			};
1215			Thread um_thread = new Thread(InitUpgradeManagerThread);
1216			um_thread.Priority = ThreadPriority.BelowNormal;
1217			um_thread.Start();
1218		}
1219
1220		/// <summary>
1221		/// Invoked when the user clicks on the restart button
1222		/// </summary>
1223		/// <param name="sender">The sender of the event</param>
1224		/// <param name="e">The event data</param>
1225		private void Restart_Click(object sender, RoutedEventArgs e)
1226		{
1227			ParentWindow.Restart();
1228		}
1229
1230		/// <summary>
1231		/// Invoked when the user clicks on a shortcut
1232		/// </summary>
1233		/// <param name="sender">The sender of the event</param>
1234		/// <param name="e">The event data</param>
1235		private void PrefShortcutButton_Clicked(object sender, RoutedEventArgs e)
1236		{
1237			currentShortcutButton = sender as Button;
1238			string[] name = currentShortcutButton.Name.Split(new char[] { '_' }, 2);
1239			currentShortcut = SettingsManager.GetKeyboardShortcut(SettingsManager.GetCurrentShortcutProfile(), name[0], name[1].Replace("_", " "));
1240
1241			waitingForShortcut = true;
1242			U.ListenForShortcut = false;
1243			currentShortcutButton.Content = U.T("ShortcutPress");
1244			currentShortcutButton.FontStyle = FontStyles.Italic;
1245			currentPressedKeys.Clear();
1246		}
1247		
1248		/// <summary>
1249		/// 
1250		/// </summary>
1251		/// <param name="sender"></param>
1252		/// <param name="e"></param>
1253		private void PrefShortcutButton_LostFocus(object sender, RoutedEventArgs e)
1254		{
1255			ResetShortcutButton();
1256		}
1257
1258		/// <summary>
1259		/// 
1260		/// </summary>
1261		/// <param name="sender"></param>
1262		/// <param name="e"></param>
1263		private void PrefShortcutProfile_SelectionChanged(object sender, SelectionChangedEventArgs e)
1264		{
1265			if (!(PrefShortcutProfile.SelectedItem is ComboBoxItem)) return;
1266			if (!(((ComboBoxItem)PrefShortcutProfile.SelectedItem).Content is string)) return;
1267			SettingsManager.CurrentShortcutProfile = ((ComboBoxItem)PrefShortcutProfile.SelectedItem).Content as string;
1268			KeyboardShortcutProfile profile = SettingsManager.GetCurrentShortcutProfile();
1269
1270			foreach (KeyboardShortcut sc in profile.Shortcuts)
1271			{
1272				if (sc.Name == "Now playing") continue;
1273
1274				Button b = shortcutButtons[sc.Category + "_" + sc.Name.Replace(" ", "_")] as Button;
1275				b.Content = sc.Keys == "" ? U.T("ShortcutNotUsed") : sc.Keys;
1276				b.FontStyle = sc.Keys == "" ? FontStyles.Italic : FontStyles.Normal;
1277
1278				if (sc.Category == "MediaCommands")
1279				{
1280					CheckBox cb = shortcutCheckBoxes[sc.Category + "_" + sc.Name.Replace(" ", "_")] as CheckBox;
1281					cb.IsChecked = sc.IsGlobal;
1282				}
1283			}
1284
1285			System.Windows.Visibility vis = profile.IsProtected ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible;
1286			PrefRenameShortcutProfile.Visibility = vis;
1287			PrefDeleteShortcutProfile.Visibility = vis;
1288		}
1289
1290		/// <summary>
1291		/// Invoked when the user changes search policy
1292		/// </summary>
1293		/// <param name="sender">The sender of the event</param>
1294		/// <param name="e">The event data</param>
1295		private void SearchPolicyCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
1296		{
1297			SettingsManager.FileListConfig.Filter = "";
1298			SettingsManager.HistoryListConfig.Filter = "";
1299			SettingsManager.QueueListConfig.Filter = "";
1300			foreach (PlaylistData p in SettingsManager.Playlists)
1301				p.ListConfig.Filter = "";
1302			ParentWindow.PlaybackControls.Search.Clear();
1303
1304			SearchPolicyDescriptionConverter conv = new SearchPolicyDescriptionConverter();
1305			ComboBoxItem cbi = (ComboBoxItem)SearchPolicyCombo.SelectedValue;
1306			SearchPolicy = (SearchPolicy)conv.ConvertBack((string)cbi.Content, null, null, null);
1307		}
1308
1309		/// <summary>
1310		/// Invoked when the user changes search policy
1311		/// </summary>
1312		/// <param name="sender">The sender of the event</param>
1313		/// <param name="e">The event data</param>
1314		private void UpgradePolicyCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
1315		{
1316			UpgradeMessage.Visibility = System.Windows.Visibility.Collapsed;
1317			UpgradePolicyDescriptionConverter conv = new UpgradePolicyDescriptionConverter();
1318			ComboBoxItem cbi = (ComboBoxItem)UpgradePolicyCombo.SelectedValue;
1319			UpgradePolicy = (UpgradePolicy)conv.ConvertBack((string)cbi.Content, null, null, null);
1320		}
1321
1322		/// <summary>
1323		/// Invoked when the user changes search policy
1324		/// </summary>
1325		/// <param name="sender">The sender of the event</param>
1326		/// <param name="e">The event data</param>
1327		private void AddPolicyCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
1328		{
1329			OpenFileAddDescriptionConverter conv = new OpenFileAddDescriptionConverter();
1330			ComboBoxItem cbi = (ComboBoxItem)AddPolicyCombo.SelectedValue;
1331			ExternalClickAdd = (OpenAddPolicy)conv.ConvertBack((string)cbi.Content, null, null, null);
1332		}
1333
1334		/// <summary>
1335		/// Invoked when the user changes search policy
1336		/// </summary>
1337		/// <param name="sender">The sender of the event</param>
1338		/// <param name="e">The event data</param>
1339		private void PlayPolicyCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
1340		{
1341			OpenFilePlayDescriptionConverter conv = new OpenFilePlayDescriptionConverter();
1342			ComboBoxItem cbi = (ComboBoxItem)PlayPolicyCombo.SelectedValue;
1343			ExternalClickPlay = (OpenPlayPolicy)conv.ConvertBack((string)cbi.Content, null, null, null);
1344		}
1345
1346		/// <summary>
1347		/// 
1348		/// </summary>
1349		/// <param name="sender"></param>
1350		/// <param name="e"></param>
1351		private void PrefCreateShortcutProfile_Clicked(object sender, RoutedEventArgs e)
1352		{
1353			List<string> occupied = new List<string>();
1354			foreach (KeyboardShortcutProfile p in SettingsManager.ShortcutProfiles)
1355				occupied.Add(p.Name);
1356			NameDialog dialog = new NameDialog(occupied);
1357			dialog.ShowDialog();
1358			if (dialog.DialogResult == true)
1359				CreateShortcutProfile(U.CleanXMLString(dialog.ProfileName.Text));
1360		}
1361
1362		/// <summary>
1363		/// 
1364		/// </summary>
1365		/// <param name="sender"></param>
1366		/// <param name="e"></param>
1367		private void PrefRenameShortcutProfile_Clicked(object sender, RoutedEventArgs e)
1368		{
1369			KeyboardShortcutProfile profile = SettingsManager.GetCurrentShortcutProfile();
1370			List<string> occupied = new List<string>();
1371			foreach (KeyboardShortcutProfile p in SettingsManager.ShortcutProfiles)
1372				occupied.Add(p.Name);
1373			NameDialog dialog = new NameDialog(occupied, profile.Name);
1374			dialog.ShowDialog();
1375			if (dialog.DialogResult == true)
1376			{
1377				foreach (ComboBoxItem item in PrefShortcutProfile.Items)
1378					if (profile.Name == (string)item.Content)
1379						item.Content = dialog.ProfileName.Text;
1380				profile.Name = U.CleanXMLString(dialog.ProfileName.Text);
1381				SettingsManager.CurrentShortcutProfile = dialog.ProfileName.Text;
1382			}
1383		}
1384
1385		/// <summary>
1386		/// 
1387		/// </summary>
1388		/// <param name="sender"></param>
1389		/// <param name="e"></param>
1390		private void PrefDeleteShortcutProfile_Clicked(object sender, RoutedEventArgs e)
1391		{
1392			KeyboardShortcutProfile profile = SettingsManager.GetCurrentShortcutProfile();
1393			ComboBoxItem itemToRemove = PrefShortcutProfile.SelectedItem as ComboBoxItem;
1394			int index = PrefShortcutProfile.Items.IndexOf(itemToRemove) - 1;
1395			if (index == -1) index = 0;
1396			SettingsManager.ShortcutProfiles.Remove(profile);
1397			PrefShortcutProfile.SelectedIndex = index;
1398			PrefShortcutProfile.Items.Remove(itemToRemove);
1399		}
1400
1401		/// <summary>
1402		/// 
1403		/// </summary>
1404		/// <param name="sender"></param>
1405		/// <param name="e"></param>
1406		private void PrefShortcutGlobal_Clicked(object sender, RoutedEventArgs e)
1407		{
1408			CheckBox cb = sender as CheckBox;
1409			string[] name = cb.Name.Split(new char[] { '_' }, 2);
1410			KeyboardShortcut sc = SettingsManager.GetKeyboardShortcut(SettingsManager.GetCurrentShortcutProfile(), name[0], name[1].Replace("_", " "));
1411			sc.IsGlobal = (bool)cb.IsChecked;
1412		}
1413
1414		/// <summary>
1415		/// 
1416		/// </summary>
1417		/// <param name="sender"></param>
1418		/// <param name="e"></param>
1419		private void ControlPanel_KeyDown(object sender, KeyEventArgs e)
1420		{
1421			if (!waitingForShortcut) return;
1422
1423			switch (e.Key)
1424			{
1425				// convert right shift to left shift
1426				case Key.RightShift:
1427					if (!currentPressedKeys.Contains(Key.LeftShift)) currentPressedKeys.Add(Key.LeftShift);
1428					currentShortcutButton.Content = ParentWindow.GetModifiersAsText(currentPressedKeys);
1429					return;
1430				// catch modifier keys
1431				case Key.LeftShift:
1432				case Key.LeftCtrl:
1433				case Key.LeftAlt:
1434				case Key.LWin:
1435				case Key.RightCtrl:
1436				case Key.RightAlt:
1437				case Key.RWin:
1438					if (!currentPressedKeys.Contains(e.Key)) currentPressedKeys.Add(e.Key);
1439					currentShortcutButton.Content = ParentWindow.GetModifiersAsText(currentPressedKeys);
1440					return;
1441
1442				// catch alt/left ctrl key when disguised as system key
1443				case Key.System:
1444					if (e.SystemKey == Key.LeftAlt || e.SystemKey == Key.RightAlt || e.SystemKey == Key.LeftCtrl)
1445					{
1446						if (!currentPressedKeys.Contains(e.SystemKey)) currentPressedKeys.Add(e.SystemKey);
1447						currentShortcutButton.Content = ParentWindow.GetModifiersAsText(currentPressedKeys);
1448						return;
1449					}
1450					break;
1451					
1452				// ignore these keys
1453				case Key.None:
1454				case Key.DeadCharProcessed:
1455					return;
1456				default:
1457					break;
1458			}
1459
1460			// TODO: Convert Oem keys to nice strings
1461			String currentKey = e.Key == Key.System ? ParentWindow.KeyToString(e.SystemKey) : ParentWindow.KeyToString(e.Key);
1462			String txt = ParentWindow.GetModifiersAsText(currentPressedKeys);
1463			if (txt.Length > 0) txt += "+" + currentKey;
1464			else txt = currentKey;
1465
1466			KeyboardShortcutProfile profile = SettingsManager.GetCurrentShortcutProfile();
1467
1468			// see if shortcut already exists
1469			bool createdNew = false;
1470			foreach (KeyboardShortcut sc in profile.Shortcuts)
1471			{
1472				if (sc.Keys == txt && sc != currentShortcut)
1473				{
1474					string title = U.T("MessageShortcutClash", "Title");
1475					string message = U.T("MessageShortcutClash", "Message");
1476					string name = U.T("Shortcut_" + sc.Name.Replace(" ", "_"));
1477					string category = U.T("Shortcut" + sc.Category);
1478					message = message.Replace("%name", name);
1479					message = message.Replace("%category", category);
1480
1481					if (MessageBox.Show(message, title, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
1482					{
1483						// if current profile is protected we create a copy of it
1484						KeyboardShortcut _sc = sc;
1485						if (profile.IsProtected)
1486						{
1487							profile = CreateShortcutProfile();
1488							currentShortcut = SettingsManager.GetKeyboardShortcut(profile, currentShortcut.Keys);
1489							_sc = SettingsManager.GetKeyboardShortcut(profile, sc.Keys);
1490							createdNew = true

Large files files are truncated, but you can click here to view the full file