PageRenderTime 47ms CodeModel.GetById 15ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 17
 18using System;
 19using System.Collections.Generic;
 20using System.Drawing;
 21using System.IO;
 22
 23using MonoMac.Foundation;
 24using MonoMac.AppKit;
 25
 26namespace SparkleShare {
 27
 28    public class SparkleStatusIcon {
 29
 30        public SparkleStatusIconController Controller = new SparkleStatusIconController ();
 31
 32        private NSStatusItem status_item = NSStatusBar.SystemStatusBar.CreateStatusItem (28);
 33        private NSMenu menu, submenu, link_code_submenu;
 34        private SparkleMenuDelegate menu_delegate;
 35
 36        private NSMenuItem state_item, folder_item, add_item, about_item, recent_events_item, quit_item,
 37            code_item, copy_item, link_code_item;
 38
 39        private NSMenuItem [] folder_menu_items, try_again_menu_items, pause_menu_items,
 40            resume_menu_items, state_menu_items;
 41
 42        private NSImage syncing_idle_image  = NSImage.ImageNamed ("process-syncing-idle");
 43        private NSImage syncing_up_image    = NSImage.ImageNamed ("process-syncing-up");
 44        private NSImage syncing_down_image  = NSImage.ImageNamed ("process-syncing-down");
 45        private NSImage syncing_image       = NSImage.ImageNamed ("process-syncing");
 46        private NSImage syncing_error_image = NSImage.ImageNamed ("process-syncing-error");
 47        
 48        private NSImage folder_image       = NSImage.ImageNamed ("NSFolder");
 49        private NSImage caution_image      = NSImage.ImageNamed ("NSCaution");
 50        private NSImage sparkleshare_image;
 51
 52
 53        public SparkleStatusIcon ()
 54        {
 55            this.status_item.HighlightMode  = true;
 56            this.status_item.Image          = this.syncing_idle_image;
 57            this.status_item.Image.Template = true;
 58
 59            if (Environment.OSVersion.Version.Major >= 14)
 60                this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder-yosemite.icns").Copy();
 61            else
 62                this.sparkleshare_image = (NSImage)NSImage.ImageNamed ("sparkleshare-folder.icns").Copy();
 63
 64            CreateMenu ();
 65
 66            Controller.UpdateIconEvent += delegate (IconState state) {
 67                Program.Controller.Invoke (() => {
 68                    switch (state) {
 69                    case IconState.Idle: { this.status_item.Image = this.syncing_idle_image; break; }
 70                    case IconState.SyncingUp: { this.status_item.Image = this.syncing_up_image; break; }
 71                    case IconState.SyncingDown: { this.status_item.Image = this.syncing_down_image; break; }
 72                    case IconState.Syncing: { this.status_item.Image = this.syncing_image; break; }
 73                    case IconState.Error: { this.status_item.Image = this.syncing_error_image; break; }
 74                    }
 75
 76                    this.status_item.Image.Template = true;
 77                });
 78            };
 79            
 80            Controller.UpdateStatusItemEvent += delegate (string state_text) {
 81                Program.Controller.Invoke (() => {
 82                    this.state_item.Title = state_text;
 83
 84                    if (Controller.Projects.Length == this.state_menu_items.Length) {
 85                        for (int i = 0; i < Controller.Projects.Length; i++)
 86                            this.state_menu_items [i].Title = Controller.Projects [i].StatusMessage;
 87                    }
 88                });
 89            };
 90
 91            Controller.UpdateMenuEvent += delegate {
 92                while (this.menu_delegate.MenuIsOpen)
 93                    System.Threading.Thread.Sleep (100);
 94
 95                Program.Controller.Invoke (() => CreateMenu ());
 96            };
 97
 98            Controller.UpdateQuitItemEvent += delegate (bool quit_item_enabled) {
 99                Program.Controller.Invoke (() => { this.quit_item.Enabled = quit_item_enabled; });
100            };
101        }
102
103
104        public void CreateMenu ()
105        {
106            this.menu = new NSMenu () { AutoEnablesItems = false };
107
108            this.state_item = new NSMenuItem () {
109                Title   = Controller.StateText,
110                Enabled = false
111            };
112
113            this.folder_item = new NSMenuItem () {
114                Title   = "SparkleShare",
115                Enabled = true
116            };
117
118            this.folder_item.Image = this.sparkleshare_image;
119            this.folder_item.Image.Size = new SizeF (16, 16);
120
121            this.add_item = new NSMenuItem () {
122                Title   = "Add Hosted Project…",
123                Enabled = true
124            };
125
126            this.recent_events_item = new NSMenuItem () {
127                Title   = "Recent Changes…",
128                Enabled = Controller.RecentEventsItemEnabled
129            };
130
131            this.link_code_item = new NSMenuItem ();
132            this.link_code_item.Title = "Client ID";
133
134            if (Controller.LinkCodeItemEnabled) {
135                this.link_code_submenu = new NSMenu ();
136
137                this.code_item = new NSMenuItem ();
138                this.code_item.Title = Program.Controller.CurrentUser.PublicKey.Substring (0, 20) + "...";
139
140                this.copy_item = new NSMenuItem ();
141                this.copy_item.Title = "Copy to Clipboard";
142                this.copy_item.Activated += delegate { Controller.CopyToClipboardClicked (); };
143
144                this.link_code_submenu.AddItem (this.code_item);
145                this.link_code_submenu.AddItem (NSMenuItem.SeparatorItem);
146                this.link_code_submenu.AddItem (this.copy_item);
147            
148                this.link_code_item.Submenu = this.link_code_submenu;
149            }
150
151            this.about_item = new NSMenuItem () {
152                Title   = "About SparkleShare",
153                Enabled = true
154            };
155
156            this.quit_item = new NSMenuItem () {
157                Title   = "Quit",
158                Enabled = Controller.QuitItemEnabled
159            };
160
161            this.folder_menu_items    = new NSMenuItem [Controller.Projects.Length];
162            this.try_again_menu_items = new NSMenuItem [Controller.Projects.Length];
163            this.pause_menu_items     = new NSMenuItem [Controller.Projects.Length];
164            this.resume_menu_items    = new NSMenuItem [Controller.Projects.Length];
165            this.state_menu_items     = new NSMenuItem [Controller.Projects.Length];
166
167            if (Controller.Projects.Length > 0) {
168                int i = 0;
169                foreach (ProjectInfo project in Controller.Projects) {
170                    NSMenuItem item = new NSMenuItem () { Title = project.Name };
171                    this.folder_menu_items [i] = item;
172
173                    item.Submenu = new NSMenu ();
174                    item.Image   = this.folder_image;
175
176                    this.state_menu_items [i] = new NSMenuItem (project.StatusMessage);
177
178                    item.Submenu.AddItem (this.state_menu_items [i]);
179                    item.Submenu.AddItem (NSMenuItem.SeparatorItem);
180
181                    if (project.IsPaused) {
182                        if (project.UnsyncedChangesInfo.Count > 0) {
183                            foreach (KeyValuePair<string, string> pair in project.UnsyncedChangesInfo)
184                                item.Submenu.AddItem (new NSMenuItem (pair.Key) {
185                                    Image = NSImage.ImageNamed (pair.Value)
186                                });
187
188                            if (!string.IsNullOrEmpty (project.MoreUnsyncedChanges))
189                                item.Submenu.AddItem (new NSMenuItem (project.MoreUnsyncedChanges));
190
191                            item.Submenu.AddItem (NSMenuItem.SeparatorItem);
192                            this.resume_menu_items [i] = new NSMenuItem ("Sync and Resume…"); 
193                        
194                        } else {
195                            this.resume_menu_items [i] = new NSMenuItem ("Resume");
196                        }
197
198                        this.resume_menu_items [i].Activated += Controller.ResumeDelegate (project.Name);
199                        item.Submenu.AddItem (this.resume_menu_items [i]);
200                    
201                    } else {
202                        if (Controller.Projects [i].HasError) {
203                            item.Image = this.caution_image;
204                            
205                            this.try_again_menu_items [i]           = new NSMenuItem ();
206                            this.try_again_menu_items [i].Title     = "Try Again";
207                            this.try_again_menu_items [i].Activated += Controller.TryAgainDelegate (project.Name);
208
209                            item.Submenu.AddItem (this.try_again_menu_items [i]);
210                            
211                        } else {
212                            this.pause_menu_items [i] = new NSMenuItem ("Pause"); 
213                            this.pause_menu_items [i].Activated += Controller.PauseDelegate (project.Name);
214
215                            item.Submenu.AddItem (this.pause_menu_items [i]);
216                        }
217                    }
218
219                    if (!Controller.Projects [i].HasError)
220                        this.folder_menu_items [i].Activated += Controller.OpenFolderDelegate (project.Name);
221
222                    item.Image.Size = new SizeF (16, 16);
223                    i++;
224                };
225            }
226
227            
228            if (Controller.RecentEventsItemEnabled)
229                this.recent_events_item.Activated += delegate { Controller.RecentEventsClicked (); };
230
231            this.add_item.Activated   += delegate { Controller.AddHostedProjectClicked (); };
232            this.about_item.Activated += delegate { Controller.AboutClicked (); };
233            this.quit_item.Activated  += delegate { Controller.QuitClicked (); };
234
235
236            this.menu.AddItem (this.state_item);
237            this.menu.AddItem (NSMenuItem.SeparatorItem);
238            this.menu.AddItem (this.folder_item);
239            
240            this.submenu = new NSMenu ();
241
242            this.submenu.AddItem (this.recent_events_item);
243            this.submenu.AddItem (this.add_item);
244            this.submenu.AddItem (NSMenuItem.SeparatorItem);
245            this.submenu.AddItem (link_code_item);
246            this.submenu.AddItem (NSMenuItem.SeparatorItem);
247            this.submenu.AddItem (this.about_item);
248            
249            this.folder_item.Submenu = this.submenu;
250
251            foreach (NSMenuItem item in this.folder_menu_items)
252                this.menu.AddItem (item);
253
254            this.menu.AddItem (NSMenuItem.SeparatorItem);
255            this.menu.AddItem (this.quit_item);
256
257            this.menu_delegate    = new SparkleMenuDelegate ();
258            this.menu.Delegate    = this.menu_delegate;
259            this.status_item.Menu = this.menu;
260        }
261    
262
263        private class SparkleMenuDelegate : NSMenuDelegate {
264            
265            public SparkleMenuDelegate (IntPtr handle) : base (handle) { }
266            public SparkleMenuDelegate () { }
267
268            public bool MenuIsOpen { get; private set; }
269
270            
271            public override void MenuWillHighlightItem (NSMenu menu, NSMenuItem item)
272            {
273            }
274
275
276            public override void MenuWillOpen (NSMenu menu)
277            {
278                MenuIsOpen = true;
279            }
280
281
282            public override void MenuDidClose (NSMenu menu)
283            {
284                MenuIsOpen = false;
285            }
286        }
287    }
288}