PageRenderTime 49ms CodeModel.GetById 3ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/SparkleShare/Mac/SparkleEventLog.cs

http://github.com/hbons/SparkleShare
C# | 419 lines | 312 code | 90 blank | 17 comment | 13 complexity | 4facd19676576e4c42c1efaae6fe1380 MD5 | raw file
  1//   SparkleShare, a collaboration and sharing tool.
  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.Drawing;
 20using System.IO;
 21using System.Threading;
 22
 23using MonoMac.Foundation;
 24using MonoMac.AppKit;
 25using MonoMac.ObjCRuntime;
 26using MonoMac.WebKit;
 27
 28namespace SparkleShare {
 29
 30    public class SparkleEventLog : NSWindow {
 31
 32        public SparkleEventLogController Controller = new SparkleEventLogController ();
 33        public float TitlebarHeight;
 34
 35        private WebView web_view;
 36        private NSBox background;
 37        private NSBox cover;
 38        private NSPopUpButton popup_button;
 39        private NSProgressIndicator progress_indicator;
 40        private NSTextField size_label, size_label_value, history_label, history_label_value;
 41        private NSButton hidden_close_button;
 42
 43
 44        public SparkleEventLog (IntPtr handle) : base (handle) { }
 45
 46        public SparkleEventLog () : base ()
 47        {
 48            Title    = "Recent Changes";
 49            Delegate = new SparkleEventsDelegate ();
 50
 51            int min_width  = 480;
 52            int min_height = 640;
 53            int height     = (int) (NSScreen.MainScreen.Frame.Height * 0.85);
 54
 55            float x    = (float) (NSScreen.MainScreen.Frame.Width * 0.61);
 56            float y    = (float) (NSScreen.MainScreen.Frame.Height * 0.5 - (height * 0.5));
 57
 58            SetFrame (
 59                new RectangleF (
 60                    new PointF (x, y),
 61                    new SizeF (min_width, height)),
 62                true);
 63
 64            StyleMask = (NSWindowStyle.Closable | NSWindowStyle.Miniaturizable |
 65                         NSWindowStyle.Titled | NSWindowStyle.Resizable);
 66
 67            MinSize        = new SizeF (min_width, min_height);
 68            HasShadow      = true;
 69            BackingType    = NSBackingStore.Buffered;
 70            TitlebarHeight = Frame.Height - ContentView.Frame.Height;
 71            Level          = NSWindowLevel.Floating;
 72
 73
 74            this.web_view = new WebView (new RectangleF (0, 0, 481, 579), "", "") {
 75                Frame = new RectangleF (new PointF (0, 0),
 76                    new SizeF (ContentView.Frame.Width, ContentView.Frame.Height - 39))
 77            };
 78
 79            this.cover = new NSBox () {
 80                Frame = new RectangleF (
 81                    new PointF (-1, -1),
 82                    new SizeF (Frame.Width + 2, this.web_view.Frame.Height + 1)),
 83                FillColor = NSColor.White,
 84                BorderType = NSBorderType.NoBorder,
 85                BoxType = NSBoxType.NSBoxCustom
 86            };
 87
 88            this.hidden_close_button = new NSButton () {
 89                KeyEquivalentModifierMask = NSEventModifierMask.CommandKeyMask,
 90                KeyEquivalent = "w"
 91            };
 92
 93            this.hidden_close_button.Activated += delegate {
 94                Controller.WindowClosed ();
 95            };
 96
 97
 98            this.size_label = new NSTextField () {
 99                Alignment       = NSTextAlignment.Right,
100                BackgroundColor = NSColor.WindowBackground,
101                Bordered        = false,
102                Editable        = false,
103                Frame           = new RectangleF (
104                    new PointF (0, ContentView.Frame.Height - 31),
105                    new SizeF (60, 20)),
106                StringValue     = "Size:"
107            };
108
109            this.size_label_value = new NSTextField () {
110                Alignment       = NSTextAlignment.Left,
111                BackgroundColor = NSColor.WindowBackground,
112                Bordered        = false,
113                Editable        = false,
114                Frame           = new RectangleF (
115                    new PointF (60, ContentView.Frame.Height - 27),
116                    new SizeF (60, 20)),
117                StringValue     = "…",
118                Font            = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize)
119            };
120
121
122            this.history_label = new NSTextField () {
123                Alignment       = NSTextAlignment.Right,
124                BackgroundColor = NSColor.WindowBackground,
125                Bordered        = false,
126                Editable        = false,
127                Frame           = new RectangleF (
128                    new PointF (130, ContentView.Frame.Height - 31),
129                    new SizeF (60, 20)),
130                StringValue     = "History:"
131            };
132
133            this.history_label_value = new NSTextField () {
134                Alignment       = NSTextAlignment.Left,
135                BackgroundColor = NSColor.WindowBackground,
136                Bordered        = false,
137                Editable        = false,
138                Frame           = new RectangleF (
139                    new PointF (190, ContentView.Frame.Height - 27),
140                    new SizeF (60, 20)
141                ),
142                StringValue     = "…",
143                Font            = NSFont.FromFontName (SparkleUI.FontName + " Bold", NSFont.SystemFontSize)
144            };
145
146            this.popup_button = new NSPopUpButton () {
147                Frame = new RectangleF (
148                    new PointF (ContentView.Frame.Width - 156 - 12, ContentView.Frame.Height - 33),
149                    new SizeF (156, 26)),
150                PullsDown = false
151            };
152
153            this.background = new NSBox () {
154                Frame = new RectangleF (
155                    new PointF (-1, -1),
156                    new SizeF (Frame.Width + 2, this.web_view.Frame.Height + 2)),
157                FillColor = NSColor.White,
158                BorderColor = NSColor.LightGray,
159                BoxType = NSBoxType.NSBoxCustom
160            };
161
162            this.progress_indicator = new NSProgressIndicator () {
163                Frame = new RectangleF (
164                    new PointF (Frame.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10),
165                    new SizeF (20, 20)),
166                Style = NSProgressIndicatorStyle.Spinning
167            };
168
169            this.progress_indicator.StartAnimation (this);
170
171            ContentView.AddSubview (this.size_label);
172            ContentView.AddSubview (this.size_label_value);
173            ContentView.AddSubview (this.history_label);
174            ContentView.AddSubview (this.history_label_value);
175            ContentView.AddSubview (this.popup_button);
176            ContentView.AddSubview (this.progress_indicator);
177            ContentView.AddSubview (this.background);
178            ContentView.AddSubview (this.hidden_close_button);
179
180            (Delegate as SparkleEventsDelegate).WindowResized += delegate (SizeF new_window_size) {
181                Program.Controller.Invoke (() => Relayout (new_window_size));
182            };
183
184
185            // Hook up the controller events
186            Controller.HideWindowEvent += delegate {
187                Program.Controller.Invoke (() => {
188                    this.progress_indicator.Hidden = true;
189                    PerformClose (this);
190                });
191            };
192
193            Controller.ShowWindowEvent += delegate {
194                Program.Controller.Invoke (() => OrderFrontRegardless ());
195            };
196            
197            Controller.UpdateChooserEvent += delegate (string [] folders) {
198                Program.Controller.Invoke (() => UpdateChooser (folders));
199            };
200
201            Controller.UpdateChooserEnablementEvent += delegate (bool enabled) {
202                Program.Controller.Invoke (() => { this.popup_button.Enabled = enabled; });
203            };
204
205            Controller.UpdateContentEvent += delegate (string html) {
206                Program.Controller.Invoke (() => {
207                    this.cover.RemoveFromSuperview ();
208                    this.progress_indicator.Hidden = true;
209                    UpdateContent (html);
210                });
211            };
212
213            Controller.ContentLoadingEvent += delegate {
214                Program.Controller.Invoke (() => {
215                    this.web_view.RemoveFromSuperview ();
216                    // FIXME: Hack to hide that the WebView sometimes doesn't disappear
217                    ContentView.AddSubview (this.cover);
218                    this.progress_indicator.Hidden = false;
219                    this.progress_indicator.StartAnimation (this);
220                });
221            };
222            
223            Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) {
224                Program.Controller.Invoke (() => {
225                    this.size_label_value.StringValue    = size;
226                    this.history_label_value.StringValue = history_size;
227                });
228            };
229
230            Controller.ShowSaveDialogEvent += delegate (string file_name, string target_folder_path) {
231                Program.Controller.Invoke (() => {
232                    NSSavePanel panel = new NSSavePanel () {
233                        DirectoryUrl         = new NSUrl (target_folder_path, true),
234                        NameFieldStringValue = file_name,
235                        ParentWindow         = this,
236                        Title                = "Restore from History",
237                        PreventsApplicationTerminationWhenModal = false
238                    };
239
240                    if ((NSPanelButtonType) panel.RunModal () == NSPanelButtonType.Ok) {
241                        string target_file_path = Path.Combine (panel.DirectoryUrl.RelativePath, panel.NameFieldStringValue);
242                        Controller.SaveDialogCompleted (target_file_path);
243                    
244                    } else {
245                        Controller.SaveDialogCancelled ();
246                    }
247                });
248            };
249        }
250
251
252        public void Relayout (SizeF new_window_size)
253        {
254            this.web_view.Frame = new RectangleF (this.web_view.Frame.Location,
255                new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 39));
256
257            this.cover.Frame = new RectangleF (this.cover.Frame.Location,
258                new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 39));
259
260            this.background.Frame = new RectangleF (this.background.Frame.Location,
261                new SizeF (new_window_size.Width, new_window_size.Height - TitlebarHeight - 37));
262
263            this.size_label.Frame = new RectangleF (
264                new PointF (this.size_label.Frame.X, new_window_size.Height - TitlebarHeight - 30),
265                this.size_label.Frame.Size);
266
267            this.size_label_value.Frame = new RectangleF (
268                new PointF (this.size_label_value.Frame.X, new_window_size.Height - TitlebarHeight - 27),
269                this.size_label_value.Frame.Size);
270
271            this.history_label.Frame = new RectangleF (
272                new PointF (this.history_label.Frame.X, new_window_size.Height - TitlebarHeight - 30),
273                this.history_label.Frame.Size);
274
275            this.history_label_value.Frame = new RectangleF (
276                new PointF (this.history_label_value.Frame.X, new_window_size.Height - TitlebarHeight - 27),
277                this.history_label_value.Frame.Size);
278
279            this.progress_indicator.Frame = new RectangleF (
280                new PointF (new_window_size.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10),
281                this.progress_indicator.Frame.Size);
282
283            this.popup_button.RemoveFromSuperview (); // Needed to prevent redraw glitches
284
285            this.popup_button.Frame = new RectangleF (
286                new PointF (new_window_size.Width - this.popup_button.Frame.Width - 12, new_window_size.Height - TitlebarHeight - 33),
287                this.popup_button.Frame.Size);
288
289            ContentView.AddSubview (this.popup_button);
290        }
291
292
293        public void UpdateChooser (string [] folders)
294        {
295            if (folders == null)
296                folders = Controller.Folders;
297
298            this.popup_button.RemoveAllItems ();
299
300            this.popup_button.AddItem ("Summary");
301            this.popup_button.Menu.AddItem (NSMenuItem.SeparatorItem);
302			
303			int row = 2;
304       		foreach (string folder in folders) {
305                this.popup_button.AddItem (folder);
306				
307				if (folder.Equals (Controller.SelectedFolder))
308					this.popup_button.SelectItem (row);
309				
310				row++;
311        	}
312			
313            this.popup_button.AddItems (folders);
314
315            this.popup_button.Activated += delegate {
316                Program.Controller.Invoke (() => {
317                    if (this.popup_button.IndexOfSelectedItem == 0)
318                        Controller.SelectedFolder = null;
319                    else
320                        Controller.SelectedFolder = this.popup_button.SelectedItem.Title;
321                });
322            };
323        }
324
325
326        public void UpdateContent (string html)
327        {
328		    string pixmaps_path = "file://" + NSBundle.MainBundle.ResourcePath;
329			
330            html = html.Replace ("<!-- $body-font-family -->", "Helvetica Neue");
331            html = html.Replace ("<!-- $day-entry-header-font-size -->", "13.6px");
332            html = html.Replace ("<!-- $body-font-size -->", "13.4px");
333            html = html.Replace ("<!-- $secondary-font-color -->", "#bbb");
334            html = html.Replace ("<!-- $small-color -->", "#ddd");
335            html = html.Replace ("<!-- $small-font-size -->", "10px");
336            html = html.Replace ("<!-- $day-entry-header-background-color -->", "#f5f5f5");
337            html = html.Replace ("<!-- $a-color -->", "#009ff8");
338            html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
339            html = html.Replace ("<!-- $pixmaps-path -->", pixmaps_path);
340            html = html.Replace ("<!-- $document-added-background-image -->", pixmaps_path + "/document-added-12.png");
341            html = html.Replace ("<!-- $document-deleted-background-image -->", pixmaps_path + "/document-deleted-12.png");
342            html = html.Replace ("<!-- $document-edited-background-image -->", pixmaps_path + "/document-edited-12.png");
343            html = html.Replace ("<!-- $document-moved-background-image -->", pixmaps_path + "/document-moved-12.png");
344			
345            this.web_view = new WebView (new RectangleF (0, 0, 481, 579), "", "") {
346                Frame = new RectangleF (new PointF (0, 0), new SizeF (ContentView.Frame.Width, ContentView.Frame.Height - 39))
347            };
348
349            this.web_view.MainFrame.LoadHtmlString (html, new NSUrl (""));
350
351            this.web_view.PolicyDelegate = new SparkleWebPolicyDelegate ();
352            ContentView.AddSubview (this.web_view);
353
354            (this.web_view.PolicyDelegate as SparkleWebPolicyDelegate).LinkClicked += delegate (string href) {
355                if (href.StartsWith ("file:///"))
356                    href = href.Substring (7);
357
358                Controller.LinkClicked (href);
359            };
360
361            this.progress_indicator.Hidden = true;
362        }
363
364
365        public override void OrderFrontRegardless ()
366        {
367            NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
368            MakeKeyAndOrderFront (this);
369
370            if (Program.UI != null)
371                Program.UI.UpdateDockIconVisibility ();
372
373            base.OrderFrontRegardless ();
374        }
375
376
377        public override void PerformClose (NSObject sender)
378        {
379            base.OrderOut (this);
380
381            if (Program.UI != null)
382                Program.UI.UpdateDockIconVisibility ();
383
384            return;
385        }
386    }
387
388
389    public class SparkleEventsDelegate : NSWindowDelegate {
390
391        public event WindowResizedHandler WindowResized = delegate { };
392        public delegate void WindowResizedHandler (SizeF new_window_size);
393
394        public override SizeF WillResize (NSWindow sender, SizeF to_frame_size)
395        {
396            WindowResized (to_frame_size);
397            return to_frame_size;
398        }
399
400        public override bool WindowShouldClose (NSObject sender)
401        {
402            (sender as SparkleEventLog).Controller.WindowClosed ();
403            return false;
404        }
405    }
406    
407    
408    public class SparkleWebPolicyDelegate : WebPolicyDelegate {
409
410        public event LinkClickedHandler LinkClicked = delegate { };
411        public delegate void LinkClickedHandler (string href);
412
413        public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info,
414            NSUrlRequest request, WebFrame frame, NSObject decision_token)
415        {
416            LinkClicked (request.Url.ToString ());
417        }
418    }
419}