/SparkleShare/Mac/SparkleStatusIcon.cs

http://github.com/hbons/SparkleShare · C# · 288 lines · 198 code · 75 blank · 15 comment · 17 complexity · a1ad2915ba32cbf224d7b40184b0d9e0 MD5 · raw file

  1. // SparkleShare, an instant update workflow to Git.
  2. // Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Drawing;
  19. using System.IO;
  20. using MonoMac.Foundation;
  21. using MonoMac.AppKit;
  22. namespace SparkleShare {
  23. public class SparkleStatusIcon {
  24. public SparkleStatusIconController Controller = new SparkleStatusIconController ();
  25. private NSStatusItem status_item = NSStatusBar.SystemStatusBar.CreateStatusItem (28);
  26. private NSMenu menu, submenu, link_code_submenu;
  27. private SparkleMenuDelegate menu_delegate;
  28. private NSMenuItem state_item, folder_item, add_item, about_item, recent_events_item, quit_item,
  29. code_item, copy_item, link_code_item;
  30. private NSMenuItem [] folder_menu_items, try_again_menu_items, pause_menu_items,
  31. resume_menu_items, state_menu_items;
  32. private NSImage syncing_idle_image = NSImage.ImageNamed ("process-syncing-idle");
  33. private NSImage syncing_up_image = NSImage.ImageNamed ("process-syncing-up");
  34. private NSImage syncing_down_image = NSImage.ImageNamed ("process-syncing-down");
  35. private NSImage syncing_image = NSImage.ImageNamed ("process-syncing");
  36. private NSImage syncing_error_image = NSImage.ImageNamed ("process-syncing-error");
  37. private NSImage folder_image = NSImage.ImageNamed ("NSFolder");
  38. private NSImage caution_image = NSImage.ImageNamed ("NSCaution");
  39. private NSImage sparkleshare_image;
  40. public SparkleStatusIcon ()
  41. {
  42. this.status_item.HighlightMode = true;
  43. this.status_item.Image = this.syncing_idle_image;
  44. this.status_item.Image.Template = true;
  45. if (Environment.OSVersion.Version.Major >= 14)
  46. this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder-yosemite.icns").Copy();
  47. else
  48. this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder.icns").Copy();
  49. CreateMenu ();
  50. Controller.UpdateIconEvent += delegate (IconState state) {
  51. Program.Controller.Invoke (() => {
  52. switch (state) {
  53. case IconState.Idle: { this.status_item.Image = this.syncing_idle_image; break; }
  54. case IconState.SyncingUp: { this.status_item.Image = this.syncing_up_image; break; }
  55. case IconState.SyncingDown: { this.status_item.Image = this.syncing_down_image; break; }
  56. case IconState.Syncing: { this.status_item.Image = this.syncing_image; break; }
  57. case IconState.Error: { this.status_item.Image = this.syncing_error_image; break; }
  58. }
  59. this.status_item.Image.Template = true;
  60. });
  61. };
  62. Controller.UpdateStatusItemEvent += delegate (string state_text) {
  63. Program.Controller.Invoke (() => {
  64. this.state_item.Title = state_text;
  65. if (Controller.Projects.Length == this.state_menu_items.Length) {
  66. for (int i = 0; i < Controller.Projects.Length; i++)
  67. this.state_menu_items [i].Title = Controller.Projects [i].StatusMessage;
  68. }
  69. });
  70. };
  71. Controller.UpdateMenuEvent += delegate {
  72. while (this.menu_delegate.MenuIsOpen)
  73. System.Threading.Thread.Sleep (100);
  74. Program.Controller.Invoke (() => CreateMenu ());
  75. };
  76. Controller.UpdateQuitItemEvent += delegate (bool quit_item_enabled) {
  77. Program.Controller.Invoke (() => { this.quit_item.Enabled = quit_item_enabled; });
  78. };
  79. }
  80. public void CreateMenu ()
  81. {
  82. this.menu = new NSMenu () { AutoEnablesItems = false };
  83. this.state_item = new NSMenuItem () {
  84. Title = Controller.StateText,
  85. Enabled = false
  86. };
  87. this.folder_item = new NSMenuItem () {
  88. Title = "SparkleShare",
  89. Enabled = true
  90. };
  91. this.folder_item.Image = this.sparkleshare_image;
  92. this.folder_item.Image.Size = new SizeF (16, 16);
  93. this.add_item = new NSMenuItem () {
  94. Title = "Add Hosted Project…",
  95. Enabled = true
  96. };
  97. this.recent_events_item = new NSMenuItem () {
  98. Title = "Recent Changes…",
  99. Enabled = Controller.RecentEventsItemEnabled
  100. };
  101. this.link_code_item = new NSMenuItem ();
  102. this.link_code_item.Title = "Client ID";
  103. if (Controller.LinkCodeItemEnabled) {
  104. this.link_code_submenu = new NSMenu ();
  105. this.code_item = new NSMenuItem ();
  106. this.code_item.Title = Program.Controller.CurrentUser.PublicKey.Substring (0, 20) + "...";
  107. this.copy_item = new NSMenuItem ();
  108. this.copy_item.Title = "Copy to Clipboard";
  109. this.copy_item.Activated += delegate { Controller.CopyToClipboardClicked (); };
  110. this.link_code_submenu.AddItem (this.code_item);
  111. this.link_code_submenu.AddItem (NSMenuItem.SeparatorItem);
  112. this.link_code_submenu.AddItem (this.copy_item);
  113. this.link_code_item.Submenu = this.link_code_submenu;
  114. }
  115. this.about_item = new NSMenuItem () {
  116. Title = "About SparkleShare",
  117. Enabled = true
  118. };
  119. this.quit_item = new NSMenuItem () {
  120. Title = "Quit",
  121. Enabled = Controller.QuitItemEnabled
  122. };
  123. this.folder_menu_items = new NSMenuItem [Controller.Projects.Length];
  124. this.try_again_menu_items = new NSMenuItem [Controller.Projects.Length];
  125. this.pause_menu_items = new NSMenuItem [Controller.Projects.Length];
  126. this.resume_menu_items = new NSMenuItem [Controller.Projects.Length];
  127. this.state_menu_items = new NSMenuItem [Controller.Projects.Length];
  128. if (Controller.Projects.Length > 0) {
  129. int i = 0;
  130. foreach (ProjectInfo project in Controller.Projects) {
  131. NSMenuItem item = new NSMenuItem () { Title = project.Name };
  132. this.folder_menu_items [i] = item;
  133. item.Submenu = new NSMenu ();
  134. item.Image = this.folder_image;
  135. this.state_menu_items [i] = new NSMenuItem (project.StatusMessage);
  136. item.Submenu.AddItem (this.state_menu_items [i]);
  137. item.Submenu.AddItem (NSMenuItem.SeparatorItem);
  138. if (project.IsPaused) {
  139. if (project.UnsyncedChangesInfo.Count > 0) {
  140. foreach (KeyValuePair<string, string> pair in project.UnsyncedChangesInfo)
  141. item.Submenu.AddItem (new NSMenuItem (pair.Key) {
  142. Image = NSImage.ImageNamed (pair.Value)
  143. });
  144. if (!string.IsNullOrEmpty (project.MoreUnsyncedChanges))
  145. item.Submenu.AddItem (new NSMenuItem (project.MoreUnsyncedChanges));
  146. item.Submenu.AddItem (NSMenuItem.SeparatorItem);
  147. this.resume_menu_items [i] = new NSMenuItem ("Sync and Resume…");
  148. } else {
  149. this.resume_menu_items [i] = new NSMenuItem ("Resume");
  150. }
  151. this.resume_menu_items [i].Activated += Controller.ResumeDelegate (project.Name);
  152. item.Submenu.AddItem (this.resume_menu_items [i]);
  153. } else {
  154. if (Controller.Projects [i].HasError) {
  155. item.Image = this.caution_image;
  156. this.try_again_menu_items [i] = new NSMenuItem ();
  157. this.try_again_menu_items [i].Title = "Try Again";
  158. this.try_again_menu_items [i].Activated += Controller.TryAgainDelegate (project.Name);
  159. item.Submenu.AddItem (this.try_again_menu_items [i]);
  160. } else {
  161. this.pause_menu_items [i] = new NSMenuItem ("Pause");
  162. this.pause_menu_items [i].Activated += Controller.PauseDelegate (project.Name);
  163. item.Submenu.AddItem (this.pause_menu_items [i]);
  164. }
  165. }
  166. if (!Controller.Projects [i].HasError)
  167. this.folder_menu_items [i].Activated += Controller.OpenFolderDelegate (project.Name);
  168. item.Image.Size = new SizeF (16, 16);
  169. i++;
  170. };
  171. }
  172. if (Controller.RecentEventsItemEnabled)
  173. this.recent_events_item.Activated += delegate { Controller.RecentEventsClicked (); };
  174. this.add_item.Activated += delegate { Controller.AddHostedProjectClicked (); };
  175. this.about_item.Activated += delegate { Controller.AboutClicked (); };
  176. this.quit_item.Activated += delegate { Controller.QuitClicked (); };
  177. this.menu.AddItem (this.state_item);
  178. this.menu.AddItem (NSMenuItem.SeparatorItem);
  179. this.menu.AddItem (this.folder_item);
  180. this.submenu = new NSMenu ();
  181. this.submenu.AddItem (this.recent_events_item);
  182. this.submenu.AddItem (this.add_item);
  183. this.submenu.AddItem (NSMenuItem.SeparatorItem);
  184. this.submenu.AddItem (link_code_item);
  185. this.submenu.AddItem (NSMenuItem.SeparatorItem);
  186. this.submenu.AddItem (this.about_item);
  187. this.folder_item.Submenu = this.submenu;
  188. foreach (NSMenuItem item in this.folder_menu_items)
  189. this.menu.AddItem (item);
  190. this.menu.AddItem (NSMenuItem.SeparatorItem);
  191. this.menu.AddItem (this.quit_item);
  192. this.menu_delegate = new SparkleMenuDelegate ();
  193. this.menu.Delegate = this.menu_delegate;
  194. this.status_item.Menu = this.menu;
  195. }
  196. private class SparkleMenuDelegate : NSMenuDelegate {
  197. public SparkleMenuDelegate (IntPtr handle) : base (handle) { }
  198. public SparkleMenuDelegate () { }
  199. public bool MenuIsOpen { get; private set; }
  200. public override void MenuWillHighlightItem (NSMenu menu, NSMenuItem item)
  201. {
  202. }
  203. public override void MenuWillOpen (NSMenu menu)
  204. {
  205. MenuIsOpen = true;
  206. }
  207. public override void MenuDidClose (NSMenu menu)
  208. {
  209. MenuIsOpen = false;
  210. }
  211. }
  212. }
  213. }