PageRenderTime 75ms CodeModel.GetById 19ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/SparkleShare/SparkleSetupController.cs

http://github.com/hbons/SparkleShare
C# | 594 lines | 414 code | 153 blank | 27 comment | 66 complexity | 9a4053c581af235114495c622de92ced 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.Collections.Generic;
 20using System.IO;
 21using System.Text.RegularExpressions;
 22using System.Threading;
 23
 24using SparkleLib;
 25
 26namespace SparkleShare {
 27
 28    public enum PageType {
 29        None,
 30        Setup,
 31        Add,
 32        Invite,
 33        Syncing,
 34        Error,
 35        Finished,
 36        Tutorial,
 37        CryptoSetup,
 38        CryptoPassword
 39    }
 40
 41    public enum FieldState {
 42        Enabled,
 43        Disabled
 44    }
 45
 46
 47    public class SparkleSetupController {
 48
 49        public event Action ShowWindowEvent = delegate { };
 50        public event Action HideWindowEvent = delegate { };
 51
 52        public event ChangePageEventHandler ChangePageEvent = delegate { };
 53        public delegate void ChangePageEventHandler (PageType page, string [] warnings);
 54        
 55        public event UpdateProgressBarEventHandler UpdateProgressBarEvent = delegate { };
 56        public delegate void UpdateProgressBarEventHandler (double percentage, string speed);
 57
 58        public event UpdateSetupContinueButtonEventHandler UpdateSetupContinueButtonEvent = delegate { };
 59        public delegate void UpdateSetupContinueButtonEventHandler (bool button_enabled);
 60
 61        public event UpdateCryptoSetupContinueButtonEventHandler UpdateCryptoSetupContinueButtonEvent = delegate { };
 62        public delegate void UpdateCryptoSetupContinueButtonEventHandler (bool button_enabled);
 63
 64        public event UpdateCryptoPasswordContinueButtonEventHandler UpdateCryptoPasswordContinueButtonEvent = delegate { };
 65        public delegate void UpdateCryptoPasswordContinueButtonEventHandler (bool button_enabled);
 66
 67        public event UpdateAddProjectButtonEventHandler UpdateAddProjectButtonEvent = delegate { };
 68        public delegate void UpdateAddProjectButtonEventHandler (bool button_enabled);
 69
 70        public event ChangeAddressFieldEventHandler ChangeAddressFieldEvent = delegate { };
 71        public delegate void ChangeAddressFieldEventHandler (string text, string example_text, FieldState state);
 72
 73        public event ChangePathFieldEventHandler ChangePathFieldEvent = delegate { };
 74        public delegate void ChangePathFieldEventHandler (string text, string example_text, FieldState state);
 75
 76        public readonly List<SparklePlugin> Plugins = new List<SparklePlugin> ();
 77        public SparklePlugin SelectedPlugin;
 78
 79        public bool WindowIsOpen { get; private set; }
 80        public SparkleInvite PendingInvite { get; private set; }
 81        public int TutorialPageNumber { get; private set; }
 82        public string PreviousUrl { get; private set; }
 83        public string PreviousAddress { get; private set; }
 84        public string PreviousPath { get; private set; }
 85        public string SyncingFolder { get; private set; }
 86        public double ProgressBarPercentage  { get; private set; }
 87
 88
 89        public int SelectedPluginIndex {
 90            get {
 91                return Plugins.IndexOf (SelectedPlugin);
 92            }
 93        }
 94
 95        public bool FetchPriorHistory {
 96            get {
 97                return this.fetch_prior_history;
 98            }
 99        }
100
101        private PageType current_page;
102        private string saved_address     = "";
103        private string saved_remote_path = "";
104        private bool create_startup_item = true;
105        private bool fetch_prior_history = false;
106
107
108        public SparkleSetupController ()
109        {
110            ChangePageEvent += delegate (PageType page_type, string [] warnings) {
111                this.current_page = page_type;
112            };
113
114            TutorialPageNumber = 0;
115            PreviousAddress    = "";
116            PreviousPath       = "";
117            PreviousUrl        = "";
118            SyncingFolder      = "";
119
120            string local_plugins_path = SparklePlugin.LocalPluginsPath;
121            int local_plugins_count   = 0;
122
123            // Import all of the plugins
124            if (Directory.Exists (local_plugins_path))
125                // Local plugins go first...
126                foreach (string xml_file_path in Directory.GetFiles (local_plugins_path, "*.xml")) {
127                    Plugins.Add (new SparklePlugin (xml_file_path));
128                    local_plugins_count++;
129                }
130
131            // ...system plugins after that...
132            if (Directory.Exists (Program.Controller.PluginsPath)) {
133                foreach (string xml_file_path in Directory.GetFiles (Program.Controller.PluginsPath, "*.xml")) {
134                    // ...and "Own server" at the very top
135                    if (xml_file_path.EndsWith ("own-server.xml")) {
136                        Plugins.Insert (0, new SparklePlugin (xml_file_path));
137
138                    } else if (xml_file_path.EndsWith ("ssnet.xml")) {
139                        // Plugins.Insert ((local_plugins_count + 1), new SparklePlugin (xml_file_path)); 
140                        // TODO: Skip this plugin for now
141
142                    } else {
143                        Plugins.Add (new SparklePlugin (xml_file_path));
144                    }
145                }
146            }
147
148            SelectedPlugin = Plugins [0];
149
150            Program.Controller.InviteReceived += delegate (SparkleInvite invite) {
151                PendingInvite = invite;
152
153                ChangePageEvent (PageType.Invite, null);
154                ShowWindowEvent ();
155            };
156
157            Program.Controller.ShowSetupWindowEvent += delegate (PageType page_type) {
158                if (page_type == PageType.CryptoSetup || page_type == PageType.CryptoPassword) {
159                    ChangePageEvent (page_type, null);
160                    return;
161                }
162
163                if (PendingInvite != null) {
164                    WindowIsOpen = true;
165                    ShowWindowEvent ();
166                    return;
167                }
168
169                if (this.current_page == PageType.Syncing ||
170                    this.current_page == PageType.Finished ||
171                    this.current_page == PageType.CryptoSetup ||
172                    this.current_page == PageType.CryptoPassword) {
173
174                    ShowWindowEvent ();
175                    return;
176                }
177
178                if (page_type == PageType.Add) {
179                    if (WindowIsOpen) {
180                        if (this.current_page == PageType.Error ||
181                            this.current_page == PageType.Finished ||
182                            this.current_page == PageType.None) {
183
184                            ChangePageEvent (PageType.Add, null);
185                        }
186
187                    } else if (!Program.Controller.FirstRun && TutorialPageNumber == 0) {
188                        WindowIsOpen = true;
189                        ChangePageEvent (PageType.Add, null);
190                    }
191
192                    ShowWindowEvent ();
193                    return;
194                }
195
196                WindowIsOpen = true;
197                ChangePageEvent (page_type, null);
198                ShowWindowEvent ();
199            };
200        }
201
202
203        public void PageCancelled ()
204        {
205            PendingInvite   = null;
206            SelectedPlugin  = Plugins [0];
207
208            PreviousAddress = "";
209            PreviousPath    = "";
210            PreviousUrl     = "";
211
212            this.saved_address     = "";
213            this.saved_remote_path = "";
214            this.fetch_prior_history = false;
215
216            WindowIsOpen = false;
217            HideWindowEvent ();
218        }
219
220
221        public void CheckSetupPage (string full_name, string email)
222        {
223            full_name = full_name.Trim ();
224            email     = email.Trim ();
225
226            bool fields_valid = (!string.IsNullOrEmpty (full_name) && IsValidEmail (email));
227            UpdateSetupContinueButtonEvent (fields_valid);
228        }
229
230        
231        public void SetupPageCancelled ()
232        {
233            Program.Controller.Quit ();
234        }
235        
236        
237        public void SetupPageCompleted (string full_name, string email)
238        {
239            Program.Controller.CurrentUser = new SparkleUser (full_name, email);
240
241            TutorialPageNumber = 1;
242            ChangePageEvent (PageType.Tutorial, null);
243        }
244
245
246        public void TutorialSkipped ()
247        {
248            TutorialPageNumber = 4;
249            ChangePageEvent (PageType.Tutorial, null);
250        }
251
252
253        public void HistoryItemChanged (bool fetch_prior_history)
254        {
255            this.fetch_prior_history = fetch_prior_history;
256        }
257
258
259        public void TutorialPageCompleted ()
260        {
261            TutorialPageNumber++;
262
263            if (TutorialPageNumber == 5) {
264                TutorialPageNumber = 0;
265
266                WindowIsOpen = false;
267                HideWindowEvent ();
268
269                if (this.create_startup_item)
270                    new Thread (() => Program.Controller.CreateStartupItem ()).Start ();
271
272            } else {
273                ChangePageEvent (PageType.Tutorial, null);
274            }
275        }
276
277
278        public void SelectedPluginChanged (int plugin_index)
279        {
280            SelectedPlugin = Plugins [plugin_index];
281
282            if (SelectedPlugin.Address != null) {
283                ChangeAddressFieldEvent (SelectedPlugin.Address, "", FieldState.Disabled);
284
285            } else if (SelectedPlugin.AddressExample != null) {
286                ChangeAddressFieldEvent (this.saved_address, SelectedPlugin.AddressExample, FieldState.Enabled);
287
288            } else {
289                ChangeAddressFieldEvent (this.saved_address, "", FieldState.Enabled);
290            }
291
292            if (SelectedPlugin.Path != null) {
293                ChangePathFieldEvent (SelectedPlugin.Path, "", FieldState.Disabled);
294
295            } else if (SelectedPlugin.PathExample != null) {
296                ChangePathFieldEvent (this.saved_remote_path, SelectedPlugin.PathExample, FieldState.Enabled);
297
298            } else {
299                ChangePathFieldEvent (this.saved_remote_path, "", FieldState.Enabled);
300            }
301        }
302
303
304        public void StartupItemChanged (bool create_startup_item)
305        {
306            this.create_startup_item = create_startup_item;
307        }
308
309
310        public void CheckAddPage (string address, string remote_path, int selected_plugin)
311        {
312            address     = address.Trim ();
313            remote_path = remote_path.Trim ();
314
315            if (selected_plugin == 0)
316                this.saved_address = address;
317
318            this.saved_remote_path = remote_path;
319
320            bool fields_valid = (!string.IsNullOrEmpty (address) &&
321                !string.IsNullOrEmpty (remote_path) && !remote_path.Contains ("\""));
322
323            UpdateAddProjectButtonEvent (fields_valid);
324        }
325
326
327        public void AddPageCompleted (string address, string remote_path)
328        {
329            SyncingFolder = Path.GetFileName (remote_path);
330
331            if (remote_path.EndsWith (".git"))
332                SyncingFolder = remote_path.Substring (0, remote_path.Length - 4);
333
334			SyncingFolder         = SyncingFolder.Replace ("-crypto", "");
335			SyncingFolder         = SyncingFolder.ReplaceUnderscoreWithSpace ();
336            ProgressBarPercentage = 1.0;
337
338            ChangePageEvent (PageType.Syncing, null);
339
340            address     = Uri.EscapeUriString (address.Trim ());
341            remote_path = remote_path.Trim ();
342            remote_path = remote_path.TrimEnd ("/".ToCharArray ());
343
344            if (SelectedPlugin.PathUsesLowerCase)
345                remote_path = remote_path.ToLower ();
346
347            PreviousAddress = address;
348            PreviousPath    = remote_path;
349
350            Program.Controller.FolderFetched    += AddPageFetchedDelegate;
351            Program.Controller.FolderFetchError += AddPageFetchErrorDelegate;
352            Program.Controller.FolderFetching   += SyncingPageFetchingDelegate;
353
354            SparkleFetcherInfo info = new SparkleFetcherInfo {
355                Address           = address,
356                Fingerprint       = SelectedPlugin.Fingerprint,
357                RemotePath        = remote_path,
358                FetchPriorHistory = this.fetch_prior_history,
359                AnnouncementsUrl  = SelectedPlugin.AnnouncementsUrl,
360                Backend           = SelectedPlugin.Backend 
361            };
362
363            new Thread (() => { Program.Controller.StartFetcher (info); }).Start ();
364        }
365
366        // The following private methods are
367        // delegates used by the previous method
368
369        private void AddPageFetchedDelegate (string remote_url, string [] warnings)
370        {
371            SyncingFolder = "";
372
373            // Create a local plugin for succesfully added projects, so
374            // so the user can easily use the same host again
375            if (SelectedPluginIndex == 0) {
376                SparklePlugin new_plugin;
377                Uri uri = new Uri (remote_url);
378
379                try {
380                    string address = remote_url.Replace (uri.AbsolutePath, "");
381                    new_plugin = SparklePlugin.Create (uri.Host, address, address, "", "", "/path/to/project");
382    
383                    if (new_plugin != null) {
384                        Plugins.Insert (1, new_plugin);
385                        SparkleLogger.LogInfo ("Controller", "Added plugin for " + uri.Host);
386                    }
387
388                } catch {
389                    SparkleLogger.LogInfo ("Controller", "Failed adding plugin for " + uri.Host);
390                }
391            }
392
393            ChangePageEvent (PageType.Finished, warnings);
394
395            Program.Controller.FolderFetched    -= AddPageFetchedDelegate;
396            Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
397            Program.Controller.FolderFetching   -= SyncingPageFetchingDelegate;
398        }
399
400        private void AddPageFetchErrorDelegate (string remote_url, string [] errors)
401        {
402            SyncingFolder = "";
403            PreviousUrl   = remote_url;
404
405            ChangePageEvent (PageType.Error, errors);
406
407            Program.Controller.FolderFetched    -= AddPageFetchedDelegate;
408            Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
409            Program.Controller.FolderFetching   -= SyncingPageFetchingDelegate;
410        }
411
412        private void SyncingPageFetchingDelegate (double percentage, double speed)
413        {
414            ProgressBarPercentage = percentage;
415
416            if (speed == 0.0)
417                UpdateProgressBarEvent (ProgressBarPercentage, "");
418            else
419                UpdateProgressBarEvent (ProgressBarPercentage, "Fetching files… " + speed.ToSize () + "/s");
420        }
421
422
423        public void InvitePageCompleted ()
424        {
425            SyncingFolder = Path.GetFileName (PendingInvite.RemotePath);
426
427            if (PendingInvite.RemotePath.EndsWith (".git"))
428                SyncingFolder = PendingInvite.RemotePath.Substring (0, PendingInvite.RemotePath.Length - 4);
429
430			SyncingFolder   = SyncingFolder.Replace ("-crypto", "");
431			SyncingFolder   = SyncingFolder.ReplaceUnderscoreWithSpace ();
432            PreviousAddress = PendingInvite.Address;
433            PreviousPath    = PendingInvite.RemotePath;
434
435            ChangePageEvent (PageType.Syncing, null);
436
437            new Thread (() => {
438                if (!PendingInvite.Accept (Program.Controller.CurrentUser.PublicKey)) {
439                    PreviousUrl = PendingInvite.Address + PendingInvite.RemotePath.TrimStart ("/".ToCharArray ());
440                    ChangePageEvent (PageType.Error, new string [] { "error: Failed to upload the public key" });
441                    return;
442                }
443
444                Program.Controller.FolderFetched    += InvitePageFetchedDelegate;
445                Program.Controller.FolderFetchError += InvitePageFetchErrorDelegate;
446                Program.Controller.FolderFetching   += SyncingPageFetchingDelegate;
447
448                SparkleFetcherInfo info = new SparkleFetcherInfo {
449                    Address           = PendingInvite.Address,
450                    Fingerprint       = PendingInvite.Fingerprint,
451                    RemotePath        = PendingInvite.RemotePath,
452                    FetchPriorHistory = false, // TODO: checkbox on invite page
453                    AnnouncementsUrl  = PendingInvite.AnnouncementsUrl
454                };
455
456                Program.Controller.StartFetcher (info);
457
458            }).Start ();
459        }
460
461        // The following private methods are
462        // delegates used by the previous method
463
464        private void InvitePageFetchedDelegate (string remote_url, string [] warnings)
465        {
466            SyncingFolder   = "";
467            PendingInvite = null;
468
469            ChangePageEvent (PageType.Finished, warnings);
470
471            Program.Controller.FolderFetched    -= AddPageFetchedDelegate;
472            Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
473            Program.Controller.FolderFetching   -= SyncingPageFetchingDelegate;
474        }
475
476        private void InvitePageFetchErrorDelegate (string remote_url, string [] errors)
477        {
478            SyncingFolder = "";
479            PreviousUrl   = remote_url;
480
481            ChangePageEvent (PageType.Error, errors);
482
483            Program.Controller.FolderFetched    -= AddPageFetchedDelegate;
484            Program.Controller.FolderFetchError -= AddPageFetchErrorDelegate;
485            Program.Controller.FolderFetching   -= SyncingPageFetchingDelegate;
486        }
487
488
489        public void SyncingCancelled ()
490        {
491            Program.Controller.StopFetcher ();
492
493            if (PendingInvite != null)
494                ChangePageEvent (PageType.Invite, null);
495            else
496                ChangePageEvent (PageType.Add, null);
497        }
498
499
500        public void ErrorPageCompleted ()
501        {
502            if (PendingInvite != null)
503                ChangePageEvent (PageType.Invite, null);
504            else
505                ChangePageEvent (PageType.Add, null);
506        }
507
508
509        public void CheckCryptoSetupPage (string password)
510        {
511            new Thread (() => {
512                bool is_valid_password = (password.Length > 0 && !password.StartsWith (" ") && !password.EndsWith (" "));
513                UpdateCryptoSetupContinueButtonEvent (is_valid_password);
514            }).Start ();
515        }
516
517
518        public void CheckCryptoPasswordPage (string password)
519        {
520            bool is_password_correct = Program.Controller.CheckPassword (password);
521            UpdateCryptoPasswordContinueButtonEvent (is_password_correct);
522        }
523
524
525        public void CryptoPageCancelled ()
526        {
527            SyncingCancelled ();
528        }
529
530
531        public void CryptoSetupPageCompleted (string password)
532        {
533            CryptoPasswordPageCompleted (password);
534        }
535
536
537        public void CryptoPasswordPageCompleted (string password)
538        {
539            ProgressBarPercentage = 100.0;
540            ChangePageEvent (PageType.Syncing, null);
541
542            new Thread (() => {
543                Thread.Sleep (1000);
544                Program.Controller.FinishFetcher (password);
545
546            }).Start ();
547        }
548
549
550        public void CopyToClipboardClicked ()
551        {
552            Program.Controller.CopyToClipboard (Program.Controller.CurrentUser.PublicKey);
553        }
554
555
556        public void ShowFilesClicked ()
557        {
558            string folder_name = Path.GetFileName (PreviousPath);
559            folder_name        = folder_name.ReplaceUnderscoreWithSpace ();
560
561            if (PreviousPath.EndsWith ("-crypto"))
562                folder_name = folder_name.Replace ("-crypto", "");
563
564            if (PreviousPath.EndsWith ("-crypto.git"))
565                folder_name = folder_name.Replace ("-crypto.git", "");
566
567            Program.Controller.OpenSparkleShareFolder (folder_name);
568            FinishPageCompleted ();
569        }
570
571
572        public void FinishPageCompleted ()
573        {
574            SelectedPlugin  = Plugins [0];
575            PreviousUrl     = "";
576            PreviousAddress = "";
577            PreviousPath    = "";
578
579            this.fetch_prior_history = false;
580            this.saved_address     = "";
581            this.saved_remote_path = "";
582            this.current_page = PageType.None;
583
584            WindowIsOpen = false;
585            HideWindowEvent ();
586        }
587
588
589        private bool IsValidEmail (string email)
590        {
591            return new Regex (@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$", RegexOptions.IgnoreCase).IsMatch (email);
592        }
593    }
594}