/Application/GUI/Controls/SearchBox.xaml.cs

http://yet-another-music-application.googlecode.com/ · C# · 700 lines · 360 code · 106 blank · 234 comment · 31 complexity · e35be7dc32010aaa0ae2f5fdca883c44 MD5 · raw file

  1. /**
  2. * SearchBox.xaml.cs
  3. *
  4. * The search box.
  5. *
  6. * * * * * * * * *
  7. *
  8. * This code is part of the Stoffi Music Player Project.
  9. * Visit our website at: stoffiplayer.com
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version
  14. * 3 of the License, or (at your option) any later version.
  15. *
  16. * See stoffiplayer.com/license for more information.
  17. **/
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Linq;
  21. using System.Text;
  22. using System.Windows;
  23. using System.Windows.Controls;
  24. using System.Windows.Data;
  25. using System.Windows.Documents;
  26. using System.Windows.Input;
  27. using System.Windows.Media;
  28. using System.Windows.Media.Imaging;
  29. using System.Windows.Navigation;
  30. using System.Windows.Shapes;
  31. using System.Windows.Threading;
  32. namespace Stoffi
  33. {
  34. /// <summary>
  35. /// A Windows Explorer styled search box
  36. /// </summary>
  37. public partial class SearchBox : UserControl
  38. {
  39. #region Members
  40. private bool isActive = false;
  41. private bool changingActiveStatus = false;
  42. private DispatcherTimer delay = new DispatcherTimer();
  43. #endregion
  44. #region Properties
  45. /// <summary>
  46. /// Gets or sets the current state of the search box
  47. /// </summary>
  48. public bool IsActive
  49. {
  50. get { return isActive; }
  51. set
  52. {
  53. changingActiveStatus = true;
  54. if (value)
  55. {
  56. Box.Text = "";
  57. Box.FontStyle = System.Windows.FontStyles.Normal;
  58. Box.Foreground = System.Windows.Media.Brushes.Black;
  59. SearchBackground.Background = System.Windows.Media.Brushes.White;
  60. Button.Style = (Style)FindResource("SearchClearButtonStyle");
  61. Box.Focus();
  62. }
  63. else
  64. {
  65. Box.Text = U.T("PlaybackSearch", "Text");
  66. Box.FontStyle = System.Windows.FontStyles.Italic;
  67. Box.Foreground = new SolidColorBrush(Color.FromRgb(0x79, 0x7a, 0x7a));
  68. SearchBackground.Background = new SolidColorBrush(Color.FromArgb(0xC0, 0xFF, 0xFF, 0xFF));
  69. Button.Style = (Style)FindResource("SearchButtonStyle");
  70. }
  71. changingActiveStatus = false;
  72. isActive = value;
  73. DispatchActiveStateChangedEvent(value, Text);
  74. }
  75. }
  76. /// <summary>
  77. /// Get or sets the search text.
  78. /// An empty string if the search box is not active.
  79. /// </summary>
  80. public String Text
  81. {
  82. get
  83. {
  84. if (IsActive)
  85. return Box.Text;
  86. else
  87. return "";
  88. }
  89. set { Box.Text = value; }
  90. }
  91. /// <summary>
  92. /// Gets or sets the position of the cursor in the text box.
  93. /// </summary>
  94. public int Position
  95. {
  96. get { return Box.SelectionStart; }
  97. set { Box.SelectionStart = value; }
  98. }
  99. #endregion
  100. #region Constructor
  101. /// <summary>
  102. /// Create a search box
  103. /// </summary>
  104. public SearchBox()
  105. {
  106. U.L(LogLevel.Debug, "SEARCH BOX", "Initialize");
  107. InitializeComponent();
  108. U.L(LogLevel.Debug, "SEARCH BOX", "Initialized");
  109. delay.Interval = new TimeSpan(0, 0, 0, 0, 500);
  110. delay.Tick += new EventHandler(Delay_Tick);
  111. }
  112. #endregion
  113. #region Methods
  114. #region Public
  115. /// <summary>
  116. /// Add a new playlist to the search box's context menu
  117. /// </summary>
  118. /// <param name="playlist">The playlist to be added</param>
  119. public void AddPlaylist(PlaylistData playlist)
  120. {
  121. // create the menu item in "Add to Playlist" in list
  122. MenuItem ListAddMenu = new MenuItem();
  123. ListAddMenu.Header = playlist.Name;
  124. ListAddMenu.Click += AddToPlaylist_Clicked;
  125. Menu_Add.Items.Insert(Menu_Add.Items.Count - 1, ListAddMenu);
  126. // create the menu item in "Remove from Playlist" in list
  127. MenuItem ListDelMenu = new MenuItem();
  128. ListDelMenu.Header = playlist.Name;
  129. ListDelMenu.Click += RemoveFromPlaylist_Clicked;
  130. Menu_Remove.Items.Insert(Menu_Remove.Items.Count, ListDelMenu);
  131. Menu_Remove.IsEnabled = true;
  132. }
  133. /// <summary>
  134. /// Remove a playlist from the search box's context menu
  135. /// </summary>
  136. /// <param name="playlist">The playlist to be removed</param>
  137. public void RemovePlaylist(PlaylistData playlist)
  138. {
  139. // remove from "add to playlist" menu in list
  140. List<MenuItem> menu_items_to_remove = new List<MenuItem>();
  141. foreach (MenuItem item in Menu_Add.Items)
  142. {
  143. if (item.Header.ToString() == playlist.Name)
  144. menu_items_to_remove.Add(item);
  145. }
  146. foreach (MenuItem item in menu_items_to_remove)
  147. Menu_Add.Items.Remove(item);
  148. // remove from "remove from playlist" menu in list
  149. menu_items_to_remove.Clear();
  150. foreach (MenuItem item in Menu_Remove.Items)
  151. {
  152. if (item.Header.ToString() == playlist.Name)
  153. menu_items_to_remove.Add(item);
  154. }
  155. foreach (MenuItem item in menu_items_to_remove)
  156. Menu_Remove.Items.Remove(item);
  157. if (SettingsManager.Playlists.Count <= 0)
  158. Menu_Remove.IsEnabled = false;
  159. }
  160. /// <summary>
  161. /// Rename a playlist in the search box's context menu
  162. /// </summary>
  163. /// <param name="oldName">The old name of the playlist</param>
  164. /// <param name="newName">The new name of the playlist</param>
  165. public void RenamePlaylist(String oldName, String newName)
  166. {
  167. foreach (MenuItem item in Menu_Add.Items)
  168. if (item.Header.ToString() == oldName)
  169. item.Header = newName;
  170. foreach (MenuItem item in Menu_Remove.Items)
  171. if (item.Header.ToString() == oldName)
  172. item.Header = newName;
  173. }
  174. /// <summary>
  175. ///
  176. /// </summary>
  177. public void Clear()
  178. {
  179. Box.Text = "";
  180. IsActive = false;
  181. Box.Text = U.T("PlaybackSearch", "Text");
  182. Box.FontStyle = System.Windows.FontStyles.Italic;
  183. Box.Foreground = new SolidColorBrush(Color.FromRgb(0x79, 0x7a, 0x7a));
  184. SearchBackground.Background = new SolidColorBrush(Color.FromArgb(0xC0, 0xFF, 0xFF, 0xFF));
  185. Box.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
  186. Button.Style = (Style)FindResource("SearchButtonStyle");
  187. DispatchClearedEvent();
  188. }
  189. #endregion
  190. #region Event handlers
  191. /// <summary>
  192. ///
  193. /// </summary>
  194. /// <param name="sender"></param>
  195. /// <param name="e"></param>
  196. private void Button_Clicked(object sender, RoutedEventArgs e)
  197. {
  198. Clear();
  199. }
  200. /// <summary>
  201. ///
  202. /// </summary>
  203. /// <param name="sender"></param>
  204. /// <param name="e"></param>
  205. private void AddToNew_Clicked(object sender, RoutedEventArgs e)
  206. {
  207. DispatchAddToNewClickedEvent();
  208. }
  209. /// <summary>
  210. ///
  211. /// </summary>
  212. /// <param name="sender"></param>
  213. /// <param name="e"></param>
  214. private void AddToPlaylist_Clicked(object sender, RoutedEventArgs e)
  215. {
  216. if (sender is MenuItem)
  217. {
  218. MenuItem item = sender as MenuItem;
  219. String name = item.Header.ToString();
  220. DispatchAddToPlaylistClickedEvent(name);
  221. }
  222. }
  223. /// <summary>
  224. ///
  225. /// </summary>
  226. /// <param name="sender"></param>
  227. /// <param name="e"></param>
  228. private void RemoveFromPlaylist_Clicked(object sender, RoutedEventArgs e)
  229. {
  230. if (sender is MenuItem)
  231. {
  232. MenuItem item = sender as MenuItem;
  233. String name = item.Header.ToString();
  234. DispatchRemoveFromPlaylistClickedEvent(name);
  235. }
  236. }
  237. /// <summary>
  238. ///
  239. /// </summary>
  240. /// <param name="sender"></param>
  241. /// <param name="e"></param>
  242. private void Box_GotFocus(object sender, RoutedEventArgs e)
  243. {
  244. U.ListenForShortcut = false;
  245. if (Box.Text == U.T("PlaybackSearch", "Text"))
  246. IsActive = true;
  247. else
  248. Box.SelectAll();
  249. }
  250. /// <summary>
  251. ///
  252. /// </summary>
  253. /// <param name="sender"></param>
  254. /// <param name="e"></param>
  255. private void Box_LostFocus(object sender, RoutedEventArgs e)
  256. {
  257. U.ListenForShortcut = true;
  258. if (Box.Text == "")
  259. IsActive = false;
  260. }
  261. /// <summary>
  262. ///
  263. /// </summary>
  264. /// <param name="sender"></param>
  265. /// <param name="e"></param>
  266. private void Box_TextChanged(object sender, TextChangedEventArgs e)
  267. {
  268. if (IsActive && !changingActiveStatus)
  269. {
  270. delay.Stop();
  271. delay.Start();
  272. }
  273. }
  274. /// <summary>
  275. /// Called after a search has been performed.
  276. /// </summary>
  277. /// <param name="sender">The sender of the event</param>
  278. /// <param name="e">The event arguments</param>
  279. private void Delay_Tick(object sender, EventArgs e)
  280. {
  281. delay.Stop();
  282. DispatchTextChangedEvent(IsActive, Text);
  283. }
  284. #endregion
  285. #endregion
  286. #region Events
  287. /// <summary>
  288. /// Invoked when the active status of the search box changes
  289. /// For example when it receives focus
  290. /// </summary>
  291. public event SearchBoxDelegate ActiveStateChanged;
  292. /// <summary>
  293. /// TODO
  294. /// </summary>
  295. public event SearchBoxClearedDelegate Cleared;
  296. /// <summary>
  297. /// TODO
  298. /// </summary>
  299. public event SearchBoxAddToNewDelegate AddToNewClicked;
  300. /// <summary>
  301. /// TODO
  302. /// </summary>
  303. public event SearchBoxAddDelegate AddClicked;
  304. /// <summary>
  305. /// TODO
  306. /// </summary>
  307. public event SearchBoxRemoveDelegate RemoveClicked;
  308. /// <summary>
  309. /// TODO
  310. /// </summary>
  311. public event SearchBoxDelegate TextChanged;
  312. /// <summary>
  313. ///
  314. /// </summary>
  315. /// <param name="eventHandler"></param>
  316. public void SubscribeActiveStateChanged(SearchBoxDelegate eventHandler)
  317. {
  318. ActiveStateChanged += eventHandler;
  319. }
  320. /// <summary>
  321. ///
  322. /// </summary>
  323. /// <param name="eventHandler"></param>
  324. public void SubscribeTextChanged(SearchBoxDelegate eventHandler)
  325. {
  326. TextChanged += eventHandler;
  327. }
  328. /// <summary>
  329. ///
  330. /// </summary>
  331. /// <param name="eventHandler"></param>
  332. public void SubscribeClearClicked(SearchBoxClearedDelegate eventHandler)
  333. {
  334. Cleared += eventHandler;
  335. }
  336. /// <summary>
  337. ///
  338. /// </summary>
  339. /// <param name="eventHandler"></param>
  340. public void SubscribeAddToNewClicked(SearchBoxAddToNewDelegate eventHandler)
  341. {
  342. AddToNewClicked += eventHandler;
  343. }
  344. /// <summary>
  345. ///
  346. /// </summary>
  347. /// <param name="eventHandler"></param>
  348. public void SubscribeAddClicked(SearchBoxAddDelegate eventHandler)
  349. {
  350. AddClicked += eventHandler;
  351. }
  352. /// <summary>
  353. ///
  354. /// </summary>
  355. /// <param name="eventHandler"></param>
  356. public void SubscribeRemoveClicked(SearchBoxRemoveDelegate eventHandler)
  357. {
  358. RemoveClicked += eventHandler;
  359. }
  360. /// <summary>
  361. ///
  362. /// </summary>
  363. /// <param name="eventHandler"></param>
  364. public void UnsubsribeActiveStateChanged(SearchBoxDelegate eventHandler)
  365. {
  366. ActiveStateChanged -= eventHandler;
  367. }
  368. /// <summary>
  369. ///
  370. /// </summary>
  371. /// <param name="eventHandler"></param>
  372. public void UnsubscribeTextChanged(SearchBoxDelegate eventHandler)
  373. {
  374. TextChanged -= eventHandler;
  375. }
  376. /// <summary>
  377. ///
  378. /// </summary>
  379. /// <param name="eventHandler"></param>
  380. public void UnsubscribeClearClicked(SearchBoxClearedDelegate eventHandler)
  381. {
  382. Cleared -= eventHandler;
  383. }
  384. /// <summary>
  385. ///
  386. /// </summary>
  387. /// <param name="eventHandler"></param>
  388. public void UnsubscribeAddToNewClicked(SearchBoxAddToNewDelegate eventHandler)
  389. {
  390. AddToNewClicked -= eventHandler;
  391. }
  392. /// <summary>
  393. ///
  394. /// </summary>
  395. /// <param name="eventHandler"></param>
  396. public void UnsubscribeAddClicked(SearchBoxAddDelegate eventHandler)
  397. {
  398. AddClicked -= eventHandler;
  399. }
  400. /// <summary>
  401. ///
  402. /// </summary>
  403. /// <param name="eventHandler"></param>
  404. public void UnsubscribeRemoveClicked(SearchBoxRemoveDelegate eventHandler)
  405. {
  406. RemoveClicked -= eventHandler;
  407. }
  408. /// <summary>
  409. ///
  410. /// </summary>
  411. /// <param name="active"></param>
  412. /// <param name="text"></param>
  413. public void DispatchActiveStateChangedEvent(bool active, string text)
  414. {
  415. if (ActiveStateChanged != null)
  416. {
  417. ActiveStateChanged(new SearchBoxEventArgs(active, text));
  418. }
  419. }
  420. /// <summary>
  421. ///
  422. /// </summary>
  423. public void DispatchClearedEvent()
  424. {
  425. if (Cleared != null)
  426. {
  427. Cleared();
  428. }
  429. }
  430. /// <summary>
  431. ///
  432. /// </summary>
  433. public void DispatchAddToNewClickedEvent()
  434. {
  435. if (AddToNewClicked != null)
  436. {
  437. AddToNewClicked(new SearchBoxAddToNewEventArgs());
  438. }
  439. }
  440. /// <summary>
  441. ///
  442. /// </summary>
  443. /// <param name="name"></param>
  444. public void DispatchAddToPlaylistClickedEvent(string name)
  445. {
  446. if (AddClicked != null)
  447. {
  448. AddClicked(new SearchBoxAddEventArgs(name));
  449. }
  450. }
  451. /// <summary>
  452. ///
  453. /// </summary>
  454. /// <param name="name"></param>
  455. public void DispatchRemoveFromPlaylistClickedEvent(string name)
  456. {
  457. if (RemoveClicked != null)
  458. {
  459. RemoveClicked(new SearchBoxRemoveEventArgs(name));
  460. }
  461. }
  462. /// <summary>
  463. ///
  464. /// </summary>
  465. /// <param name="active"></param>
  466. /// <param name="text"></param>
  467. public void DispatchTextChangedEvent(bool active, string text)
  468. {
  469. if (TextChanged != null)
  470. {
  471. TextChanged(new SearchBoxEventArgs(active, text));
  472. }
  473. }
  474. #endregion
  475. }
  476. /// <summary>
  477. /// Provides data for a search box event
  478. /// </summary>
  479. public class SearchBoxEventArgs : EventArgs
  480. {
  481. #region Members
  482. private bool isActive;
  483. private string text;
  484. #endregion
  485. #region Properties
  486. /// <summary>
  487. ///
  488. /// </summary>
  489. public bool IsActive { get { return isActive; } }
  490. /// <summary>
  491. ///
  492. /// </summary>
  493. public string Text { get { return text; } }
  494. #endregion
  495. #region Methods
  496. #region Public
  497. public SearchBoxEventArgs(bool active, string txt)
  498. {
  499. isActive = active;
  500. text = txt;
  501. }
  502. #endregion
  503. #endregion
  504. }
  505. /// <summary>
  506. /// Provides data for the <see cref="SearchBox.AddClicked"/> event
  507. /// </summary>
  508. public class SearchBoxAddEventArgs : EventArgs
  509. {
  510. #region Members
  511. private string playlistName;
  512. #endregion
  513. #region Properties
  514. /// <summary>
  515. ///
  516. /// </summary>
  517. public string PlaylistName { get { return playlistName; } }
  518. #endregion
  519. #region Methods
  520. #region Public
  521. /// <summary>
  522. ///
  523. /// </summary>
  524. /// <param name="name"></param>
  525. public SearchBoxAddEventArgs(string name)
  526. {
  527. playlistName = name;
  528. }
  529. #endregion
  530. #endregion
  531. }
  532. /// <summary>
  533. /// Provides data for the <see cref="SearchBox.RemoveClicked"/> event
  534. /// </summary>
  535. public class SearchBoxRemoveEventArgs : EventArgs
  536. {
  537. #region Members
  538. private string playlistName;
  539. #endregion
  540. #region Properties
  541. /// <summary>
  542. ///
  543. /// </summary>
  544. public string PlaylistName { get { return playlistName; } }
  545. #endregion
  546. #region Methods
  547. #region Public
  548. public SearchBoxRemoveEventArgs(string name)
  549. {
  550. playlistName = name;
  551. }
  552. #endregion
  553. #endregion
  554. }
  555. /// <summary>
  556. /// Provides data for the <see cref="SearchBox.AddToNewClicked"/> event
  557. /// </summary>
  558. public class SearchBoxAddToNewEventArgs : EventArgs
  559. {
  560. #region Constructor
  561. /// <summary>
  562. ///
  563. /// </summary>
  564. public SearchBoxAddToNewEventArgs()
  565. { }
  566. #endregion
  567. }
  568. #region Delegates
  569. /// <summary>
  570. ///
  571. /// </summary>
  572. /// <param name="e"></param>
  573. public delegate void SearchBoxDelegate(SearchBoxEventArgs e);
  574. /// <summary>
  575. ///
  576. /// </summary>
  577. /// <param name="e"></param>
  578. public delegate void SearchBoxAddDelegate(SearchBoxAddEventArgs e);
  579. /// <summary>
  580. ///
  581. /// </summary>
  582. /// <param name="e"></param>
  583. public delegate void SearchBoxRemoveDelegate(SearchBoxRemoveEventArgs e);
  584. /// <summary>
  585. ///
  586. /// </summary>
  587. /// <param name="e"></param>
  588. public delegate void SearchBoxAddToNewDelegate(SearchBoxAddToNewEventArgs e);
  589. /// <summary>
  590. ///
  591. /// </summary>
  592. public delegate void SearchBoxClearedDelegate();
  593. #endregion
  594. }