Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Preferences / PreferencesViewModel.cs @ 2115e2a5

History | View | Annotate | Download (31.3 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="PreferencesViewModel.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42

    
43

    
44
using System.Collections.Concurrent;
45
using System.Collections.Generic;
46
using System.Collections.Specialized;
47
using System.ComponentModel.Composition;
48
using System.Diagnostics;
49
using System.IO;
50
using System.Net;
51
using System.Reflection;
52
using System.Threading.Tasks;
53
using System.Windows;
54
using System.Windows.Forms;
55
using Caliburn.Micro;
56
using Pithos.Client.WPF.Configuration;
57
using Pithos.Client.WPF.Properties;
58
using Pithos.Client.WPF.SelectiveSynch;
59
using Pithos.Client.WPF.Utils;
60
using Pithos.Core;
61
using Pithos.Core.Agents;
62
using Pithos.Interfaces;
63
using System;
64
using System.Linq;
65
using Pithos.Network;
66
using MessageBox = System.Windows.MessageBox;
67
using Screen = Caliburn.Micro.Screen;
68

    
69
namespace Pithos.Client.WPF.Preferences
70
{
71
    /// <summary>
72
    /// The preferences screen displays user and account settings and updates the PithosMonitor
73
    /// classes when account settings change.
74
    /// </summary>
75
    /// <remarks>
76
    /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate
77
    /// ViewModels, one for each tab.
78
    /// </remarks>
79
    [Export, PartCreationPolicy(CreationPolicy.Shared)]
80
    public class PreferencesViewModel : Screen
81
    {
82
        private readonly IEventAggregator _events;
83

    
84
        //Logging in the Pithos client is provided by log4net
85
        private static readonly log4net.ILog Log =
86
            log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
87

    
88
        private PithosSettings _settings;
89

    
90
        public PithosSettings Settings
91
        {
92
            get { return _settings; }
93
            set
94
            {
95
                _settings = value;
96
                NotifyOfPropertyChange(() => Settings);
97
            }
98
        }
99

    
100
        private ObservableConcurrentCollection<AccountViewModel> _accounts;
101

    
102
        public ObservableConcurrentCollection<AccountViewModel> Accounts
103
        {
104
            get { return _accounts; }
105
            set
106
            {
107
                _accounts = value;
108
                NotifyOfPropertyChange(() => Accounts);
109
            }
110
        }
111

    
112
        public bool IsBusy
113
        {
114
            get { return _isBusy; }
115
            set
116
            {
117
                if (value.Equals(_isBusy)) return;
118
                _isBusy = value;
119
                NotifyOfPropertyChange(() => IsBusy);
120
            }
121
        }
122

    
123
        public bool StartOnSystemStartup { get; set; }
124

    
125
        public ShellViewModel Shell { get; set; }
126
        //ShellExtensionController _extensionController=new ShellExtensionController();
127

    
128
        [ImportingConstructor]
129
        public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell,
130
                                    PithosSettings settings)
131
        {
132
            this.DisplayName = "Pithos+ Preferences";
133

    
134
            // ReSharper disable DoNotCallOverridableMethodsInConstructor
135
            //Caliburn.Micro uses DisplayName for the view's title
136
            DisplayName = "Pithos+ Preferences";
137
            // ReSharper restore DoNotCallOverridableMethodsInConstructor
138

    
139
            _windowManager = windowManager;
140
            _events = events;
141

    
142
            Shell = shell;
143

    
144
            Settings = settings;
145
            Accounts = new ObservableConcurrentCollection<AccountViewModel>();
146

    
147

    
148
            var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
149
            _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");
150

    
151

    
152
            StartOnSystemStartup = File.Exists(_shortcutPath);
153

    
154
            //SelectedTab = currentTab;
155
        }
156

    
157
        protected override void OnViewLoaded(object view)
158
        {
159
            base.OnViewLoaded(view);
160

    
161
            Settings.Reload();
162

    
163
            Accounts.Clear();
164

    
165
            if (Settings.Accounts == null)
166
            {
167
                Settings.Accounts = new AccountsCollection();
168
                Settings.Save();
169
            }
170
            var accountVMs = from account in Settings.Accounts
171
                             select new AccountViewModel(account);
172

    
173
            Accounts.AddFromEnumerable(accountVMs);
174
            if (Accounts.Count > 0)
175
                CurrentAccount = Accounts.First();
176

    
177
        }
178

    
179
        private string _selectedTab = "General";
180

    
181
        public string SelectedTab
182
        {
183
            get { return _selectedTab; }
184
            set
185
            {
186
                _selectedTab = value ?? "GeneralTab";
187
                NotifyOfPropertyChange(() => SelectedTab);
188
                NotifyOfPropertyChange(() => AccountTabSelected);
189
            }
190
        }
191

    
192

    
193
        public bool AccountTabSelected
194
        {
195
            get { return _selectedTab == "AccountTab"; }
196
        }
197

    
198
        #region Preferences Properties
199

    
200
        private bool _noProxy;
201

    
202
        public bool NoProxy
203
        {
204
            get { return _noProxy; }
205
            set
206
            {
207
                _noProxy = value;
208
                NotifyOfPropertyChange(() => NoProxy);
209
            }
210
        }
211

    
212

    
213
        private bool _defaultProxy;
214

    
215
        public bool DefaultProxy
216
        {
217
            get { return _defaultProxy; }
218
            set
219
            {
220
                _defaultProxy = value;
221
                NotifyOfPropertyChange(() => DefaultProxy);
222
            }
223
        }
224

    
225

    
226
        private bool _manualProxy;
227

    
228
        public bool ManualProxy
229
        {
230
            get { return _manualProxy; }
231
            set
232
            {
233
                _manualProxy = value;
234
                NotifyOfPropertyChange(() => ManualProxy);
235
            }
236
        }
237

    
238
        #endregion
239

    
240

    
241
        public int StartupDelay
242
        {
243
            get { return (int) Settings.StartupDelay.TotalMinutes; }
244
            set
245
            {
246
                if (value < 0)
247
                    throw new ArgumentOutOfRangeException("value",
248
                                                          Resources.
249
                                                              PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);
250
                Settings.StartupDelay = TimeSpan.FromMinutes(value);
251
                NotifyOfPropertyChange(() => StartupDelay);
252
            }
253
        }
254

    
255
        #region Commands
256

    
257
        public bool CanSelectiveSyncFolders
258
        {
259
            get { return CurrentAccount != null && CurrentAccount.SelectiveSyncEnabled; }
260
        }
261

    
262
        public void SelectiveSyncFolders()
263
        {
264
            //var monitor = Shell.Monitors[CurrentAccount.AccountKey];
265

    
266

    
267
            var model = new SelectiveSynchViewModel(_events, CurrentAccount.Account, CurrentAccount.ApiKey, false);
268
            if (_windowManager.ShowDialog(model) == true)
269
            {
270

    
271
            }
272
        }
273

    
274
        /* private bool _networkTracing;
275
        public bool NetworkTracing
276
        {
277
            get { return _networkTracing; }
278
            set
279
            {
280
                _networkTracing = value;
281
                
282
            }
283
        }*/
284

    
285
        private DisposeGuard GetBusyGuard()
286
        {
287
            return new DisposeGuard(()=>IsBusy=true,()=>IsBusy=false);
288
        }
289

    
290
        public async Task RefreshApiKey()
291
        {
292
            //_events.Publish(new Notification { Title = "Authorization failed", Message = "Your API Key has probably expired. You will be directed to a page where you can renew it", Level = TraceLevel.Error });
293
            if (CurrentAccount == null)
294
                return;
295
            using (GetBusyGuard())
296
            {
297
                try
298
                {
299
                    var name = CurrentAccount.AccountName;
300

    
301
                    var loginUri = PithosAccount.GetLoginUri(CurrentAccount.ServerUrl);
302
                    var credentials = PithosAccount.RetrieveCredentials(loginUri.ToString(), name);
303
                    if (credentials == null)
304
                        return;
305
                    //The server will return credentials for a different account, not just the current account
306
                    //We need to find the correct account first
307
                    AccountViewModel account = null;
308
                    Guid token;
309
                    if (Guid.TryParse(name, out token))
310
                    {
311
                        account =
312
                            Accounts.First(
313
                                act =>
314
                                act.AccountName == credentials.UserName && act.ServerUrl == CurrentAccount.ServerUrl);
315
                    }
316
                    else
317
                    {
318
                        account =
319
                            Accounts.First(
320
                                act => act.AccountName == name && act.ServerUrl == CurrentAccount.ServerUrl);
321
                        account.AccountName = credentials.UserName;
322
                        account.DisplayName = name;
323
                        Shell.RemoveMonitor(account.ServerUrl, name);
324
                        CurrentAccount.AccountName = credentials.UserName;
325
                        CurrentAccount.DisplayName = name;
326
                        await Shell.MonitorAccount(account.Account);
327
                    }
328
                    account.ApiKey = credentials.Password;
329
                    account.IsExpired = false;
330
                    Settings.Save();
331
                    TaskEx.Delay(10000).ContinueWith(_ => Shell.MonitorAccount(account.Account));
332
                    NotifyOfPropertyChange(() => Accounts);
333
                }
334
                catch (AggregateException exc)
335
                {
336
                    string message = String.Format("API Key retrieval failed");
337
                    Log.Error(message, exc.InnerException);
338
                    _events.Publish(new Notification
339
                        {Title = "Authorization failed", Message = message, Level = TraceLevel.Error});
340
                }
341
                catch (Exception exc)
342
                {
343
                    string message = String.Format("API Key retrieval failed");
344
                    Log.Error(message, exc);
345
                    _events.Publish(new Notification
346
                        {Title = "Authorization failed", Message = message, Level = TraceLevel.Error});
347
                }
348
            }
349
        }
350

    
351
        public bool CanWipeAccount
352
        {
353
            get { return CurrentAccount != null 
354
                && Shell.Monitors.ContainsKey(CurrentAccount.AccountKey)
355
                && Shell.Monitors[CurrentAccount.AccountKey].CloudClient!=null;
356
            }
357
        }
358

    
359
        public async Task WipeAccount()
360
        {
361
            PithosMonitor aMonitor;
362
            if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out aMonitor))
363
            {
364
                if (aMonitor.CloudClient == null)
365
                {
366
                    Log.ErrorFormat("Tried to wipe account [{0}] before authenticating",CurrentAccount.AccountKey);
367
                    return;
368
                }
369
                var message = String.Format("You are about to wipe all data in the {0} account at {1}. Are you sure?",
370
                                            CurrentAccount.AccountName, CurrentAccount.ServerUrl);
371
                if (MessageBoxResult.Yes !=
372
                    MessageBox.Show(message, "Warning! Account data will be wiped", MessageBoxButton.YesNo,
373
                                    MessageBoxImage.Hand, MessageBoxResult.No))
374
                    return;
375

    
376
                using(GetBusyGuard())
377
                {
378

    
379
                   await aMonitor.CloudClient.WipeContainer("", new Uri("pithos", UriKind.Relative));
380
                    aMonitor.Stop();
381
                    await aMonitor.Start();
382
                    MessageBox.Show("Account wiped");
383
                }
384

    
385
            }
386
        }
387

    
388

    
389
        public void OpenLogPath()
390
        {
391
            Shell.OpenLogPath();
392
        }
393

    
394
        public void OpenLogConsole()
395
        {
396
            var logView = IoC.Get<LogConsole.LogConsoleViewModel>();
397
            _windowManager.ShowWindow(logView);
398
        }
399

    
400
        public async Task SaveChanges()
401
        {
402
            using (GetBusyGuard())
403
            {
404

    
405
                await DoSave();
406
                TryClose( /*true*/);
407
            }
408
        }
409

    
410
        public void RejectChanges()
411
        {
412
            Settings.Reload();
413
            TryClose( /*false*/);
414
        }
415

    
416
        public async Task ApplyChanges()
417
        {
418
            using (GetBusyGuard())
419
            {
420
                await DoSave();
421
            }
422
        }
423

    
424
        private async Task DoSave()
425
        {
426
            //SetStartupMode();            
427

    
428
            //Ensure we save the settings changes first
429
            foreach (var account in _accountsToRemove)
430
            {
431
                Settings.Accounts.Remove(account);
432
            }
433

    
434
            foreach (var account in _accountsToAdd)
435
            {
436
                Settings.Accounts.Add(account);
437
            }
438

    
439
            Settings.Save();
440

    
441

    
442
            try
443
            {
444
                foreach (var account in _accountsToRemove)
445
                {
446
                    Shell.RemoveMonitor(account.ServerUrl, account.AccountName);
447
                    Shell.RemoveAccountFromDatabase(account);
448
                }
449

    
450
                foreach (var account in Settings.Accounts)
451
                {
452
                    await Shell.MonitorAccount(account);
453
                }
454

    
455
                var poller = IoC.Get<PollAgent>();
456
                poller.SynchNow();
457
            }
458
            finally
459
            {
460
                _accountsToRemove.Clear();
461
                _accountsToAdd.Clear();
462
            }
463

    
464
            NotifyOfPropertyChange(() => Settings);
465

    
466
            if (IgnoreCertificateErrors)
467
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
468
            else
469
            {
470
                ServicePointManager.ServerCertificateValidationCallback = null;
471
            }
472
        }
473

    
474
        /*   public void ChangePithosFolder()
475
        {
476
            var browser = new FolderBrowserDialog();
477
            browser.SelectedPath = Settings.PithosPath;
478
            var result = browser.ShowDialog((IWin32Window)GetView());
479
            if (result == DialogResult.OK)
480
            {
481
                var newPath = browser.SelectedPath;
482
                var accountName = CurrentAccount.AccountName;
483
                var monitor = Shell.Monitors[accountName];
484
                monitor.Stop();
485
                
486
                Shell.Monitors.Remove(accountName);
487

    
488
                Directory.Move(Settings.PithosPath, newPath);
489
                Settings.PithosPath = newPath;
490
                Settings.Save();
491

    
492
                Shell.MonitorAccount(CurrentAccount);
493

    
494
                NotifyOfPropertyChange(() => Settings);                
495
            }
496
        }
497
*/
498

    
499

    
500
        private readonly List<AccountSettings> _accountsToAdd = new List<AccountSettings>();
501

    
502
        public async Task AddAccount()
503
        {
504
            var wizard = new AddAccountViewModel();
505
            if (_windowManager.ShowDialog(wizard) == true)
506
            {
507
                try
508
                {
509
                    string selectedPath = wizard.AccountPath;
510
                    var initialRootPath = wizard.ShouldCreateOkeanosFolder
511
                                              ? Path.Combine(selectedPath, "okeanos")
512
                                              : selectedPath;
513
                    var actualRootPath = initialRootPath;
514
                    if (wizard.ShouldCreateOkeanosFolder)
515
                    {
516
                        int attempt = 1;
517
                        while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))
518
                        {
519
                            actualRootPath = String.Format("{0} {1}", initialRootPath, attempt++);
520
                        }
521
                        Directory.CreateDirectory(actualRootPath);
522
                    }
523

    
524

    
525

    
526
                    var account =
527
                        Accounts.FirstOrDefault(
528
                            act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer);
529
                    if (account != null)
530
                    {
531
                        if (
532
                            MessageBox.Show("The account you specified already exists. Do you want to update it?",
533
                                            "The account exists") == MessageBoxResult.Yes)
534
                        {
535
                            account.ApiKey = wizard.Token;
536
                            account.IsExpired = false;
537
                            CurrentAccount = account;
538
                        }
539
                    }
540
                    else
541
                    {
542
                        var newAccount = new AccountSettings
543
                                             {
544
                                                 AccountName = wizard.AccountName,
545
                                                 ServerUrl = wizard.CurrentServer,
546
                                                 ApiKey = wizard.Token,
547
                                                 RootPath = actualRootPath,
548
                                                 IsActive = wizard.IsAccountActive,
549
                                             };
550

    
551
                        
552
                        var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey)
553
                                         {
554
                                             AuthenticationUrl = newAccount.ServerUrl,
555
                                             UsePithos = true
556
                                         };
557
                        await client.Authenticate().ConfigureAwait(false);
558

    
559
                        Guid token;
560
                        if (Guid.TryParse(wizard.AccountName, out token))
561
                        {
562
                            newAccount.AccountToken = token;
563
                            newAccount.DisplayName = await client.ResolveName(token).ConfigureAwait(false);    
564
                        }
565

    
566
                        
567
                        await InitializeSelectiveFolders(newAccount, client);
568

    
569

    
570
                        //TODO:Add the "pithos" container as a default selection                   
571

    
572
                        _accountsToAdd.Add(newAccount);
573
                        var accountVm = new AccountViewModel(newAccount);
574
                        (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);
575
                        CurrentAccount = accountVm;
576
                    }
577
                    NotifyOfPropertyChange(() => Accounts);
578
                    NotifyOfPropertyChange(() => Settings);
579
                }
580
                catch (WebException exc)
581
                {
582
                    Log.ErrorFormat("[Add Account] Connectivity Error: {0}", exc);
583
                    MessageBox.Show("Unable to connect to Pithos. Please try again later", "Connectivity Error",
584
                                    MessageBoxButton.OK, MessageBoxImage.Exclamation);
585
                }
586
            }
587

    
588

    
589

    
590
        }
591

    
592
        private async Task InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,
593
                                                      int retries = 3)
594
        {
595
            while (true)
596
            {
597
                try
598
                {
599
                    
600

    
601
                    var containers = await client.ListContainers(newAccount.AccountName).ConfigureAwait(false);
602
                    var containerUris = from container in containers
603
                                        select String.Format(@"{0}/v1/{1}/{2}",
604
                                                             newAccount.ServerUrl, newAccount.AccountName,
605
                                                             container.Name);
606
                    lock (newAccount.SelectiveFolders)
607
                    {
608
                        newAccount.SelectiveFolders.AddRange(containerUris.ToArray());
609
                    }
610

    
611
                    var objectInfos = (from container in containers
612
                                       from dir in client.ListObjects(newAccount.AccountName, container.Name)
613
                                       where container.Name.ToString() != "trash"
614
                                       select dir).ToList();
615
                    var tree = objectInfos.ToTree();
616

    
617
                    var selected = (from root in tree
618
                                    from child in root
619
                                    select child.Uri.ToString()).ToArray();
620
                    lock (newAccount.SelectiveFolders)
621
                    {
622
                        newAccount.SelectiveFolders.AddRange(selected);
623
                    }
624
                    return;
625
                }
626
                catch (WebException)
627
                {
628
                    if (retries > 0)
629
                        retries--;
630
                    else
631
                        throw;
632
                }
633
            }
634
        }
635

    
636
/*
637
        public void AddPithosAccount()
638
       {
639
            var credentials=PithosAccount.RetrieveCredentials(null);
640
            if (credentials == null)
641
                return;
642
            var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
643
            var accountVM = new AccountViewModel(account);
644
            if (account == null)
645
            {
646
                account=new AccountSettings{
647
                    AccountName=credentials.UserName,
648
                    ApiKey=credentials.Password
649
                };
650
                Settings.Accounts.Add(account);
651
                accountVM = new AccountViewModel(account);
652
                (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
653
            }
654
            else
655
            {
656
                account.ApiKey=credentials.Password;
657
            }
658
            //SelectedAccountIndex= Settings.Accounts.IndexOf(account);
659
            CurrentAccount = accountVM;
660
            NotifyOfPropertyChange(() => Accounts);
661
            NotifyOfPropertyChange(()=>Settings);                       
662
       }
663
*/
664

    
665

    
666
        private readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();
667

    
668
        public void RemoveAccount()
669
        {
670
            Accounts.TryRemove(CurrentAccount);
671
            _accountsToRemove.Add(CurrentAccount.Account);
672

    
673
            CurrentAccount = null;
674
            NotifyOfPropertyChange(() => Accounts);
675

    
676

    
677
            //NotifyOfPropertyChange("Settings.Accounts");
678
        }
679

    
680
        public bool CanRemoveAccount
681
        {
682
            get { return (CurrentAccount != null); }
683
        }
684

    
685
        public bool CanClearAccountCache
686
        {
687
            get { return (CurrentAccount != null); }
688
        }
689

    
690
        public void ClearAccountCache()
691
        {
692
            if (MessageBoxResult.Yes ==
693
                MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" +
694
                                " You will have to download all partially downloaded data again\n" +
695
                                "This change can not be undone\n\n" +
696
                                "Do you wish to delete all partially downloaded data?",
697
                                "Warning! Clearing account cache",
698
                                MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))
699
            {
700

    
701
                var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder);
702
                var dir = new DirectoryInfo(cachePath);
703
                //The file may not exist if we just created the account
704
                if (!dir.Exists)
705
                    return;
706
                dir.EnumerateFiles().Apply(file => file.Delete());
707
                dir.EnumerateDirectories().Apply(folder => folder.Delete(true));
708
            }
709
        }
710

    
711

    
712
        public bool ExtensionsActivated
713
        {
714
            get { return Settings.ExtensionsActivated; }
715
            set
716
            {
717
                if (Settings.ExtensionsActivated == value)
718
                    return;
719

    
720
                Settings.ExtensionsActivated = value;
721

    
722
/*
723
                if (value)
724
                    _extensionController.RegisterExtensions();
725
                else
726
                {
727
                    _extensionController.UnregisterExtensions();
728
                }
729
*/
730
                NotifyOfPropertyChange(() => ExtensionsActivated);
731
            }
732
        }
733

    
734
        public bool DebugLoggingEnabled
735
        {
736
            get { return Settings.DebugLoggingEnabled; }
737
            set
738
            {
739
                Settings.DebugLoggingEnabled = value;
740
                NotifyOfPropertyChange(() => DebugLoggingEnabled);
741
            }
742
        }
743

    
744
        public bool IgnoreCertificateErrors
745
        {
746
            get { return Settings.IgnoreCertificateErrors; }
747
            set
748
            {
749
                Settings.IgnoreCertificateErrors = value;
750
                NotifyOfPropertyChange(() => IgnoreCertificateErrors);
751
            }
752
        }
753

    
754
        #endregion
755

    
756
        /* private int _selectedAccountIndex;
757
        public int SelectedAccountIndex
758
        {
759
            get { return _selectedAccountIndex; }
760
            set
761
            {
762
                //var accountCount=Settings.Accounts.Count;
763
                //if (accountCount == 0)
764
                //    return;
765
                //if (0 <= value && value < accountCount)
766
                //    _selectedAccountIndex = value;
767
                //else
768
                //    _selectedAccountIndex = 0;
769
                _selectedAccountIndex = value;
770
                NotifyOfPropertyChange(() => CurrentAccount);
771
                NotifyOfPropertyChange(() => CanRemoveAccount);
772
                NotifyOfPropertyChange(()=>SelectedAccountIndex);
773
            }
774
        }*/
775

    
776
        private AccountViewModel _currentAccount;
777
        private readonly IWindowManager _windowManager;
778
        private readonly string _shortcutPath;
779
        private bool _isBusy;
780

    
781

    
782
        public AccountViewModel CurrentAccount
783
        {
784
            get { return _currentAccount; }
785
            set
786
            {
787
                _currentAccount = value;
788

    
789
                if (_currentAccount != null)
790
                    _currentAccount.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanSelectiveSyncFolders);
791

    
792
                NotifyOfPropertyChange(() => CurrentAccount);
793
                NotifyOfPropertyChange(() => CanRemoveAccount);
794
                NotifyOfPropertyChange(() => CanSelectiveSyncFolders);
795
                NotifyOfPropertyChange(() => CanMoveAccountFolder);
796
                NotifyOfPropertyChange(() => CanClearAccountCache);
797
                NotifyOfPropertyChange(() => CanWipeAccount);
798
            }
799
        }
800

    
801
/*
802
        public AccountSettings CurrentAccount
803
        {
804
            get {
805
                if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count)                    
806
                    return Settings.Accounts[SelectedAccountIndex];
807
                return null;
808
            }
809

    
810
        }
811
*/
812

    
813

    
814
        public bool CanMoveAccountFolder
815
        {
816
            get { return CurrentAccount != null; }
817
        }
818

    
819
        public async Task MoveAccountFolder()
820
        {
821

    
822
            using (var dlg = new FolderBrowserDialog())
823
            {
824
                var currentFolder = CurrentAccount.RootPath;
825
                dlg.SelectedPath = currentFolder;
826
                //Ask the user to select a folder
827
                //Note: We need a parent window here, which we retrieve with GetView            
828
                var view = (Window) GetView();
829
                if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))
830
                    return;
831

    
832
                var newPath = dlg.SelectedPath;
833
                //Find the account's monitor and stop it
834
                PithosMonitor monitor;
835
                if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor))
836
                {
837
                    //Problem: Doesn't stop the poll agent
838
                    monitor.Stop();
839

    
840
                    monitor.MoveRootFolder(newPath);
841

    
842
                   
843
                }
844
                //Replace the old rootpath with the new
845
                CurrentAccount.RootPath = newPath;
846
                //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date
847
                Settings.Save();
848
                //And start the monitor on the new RootPath            
849
                if (monitor != null)
850
                {
851
                    monitor.RootPath = newPath;
852
                    if (CurrentAccount.IsActive)
853
                        await Shell.StartMonitor(monitor);
854
                        
855
                }
856
                else
857
                    await Shell.MonitorAccount(CurrentAccount.Account);
858
                //Finally, notify that the Settings, CurrentAccount have changed
859
                NotifyOfPropertyChange(() => CurrentAccount);
860
                NotifyOfPropertyChange(() => Settings);
861

    
862
            }
863
        }
864

    
865
    }
866

    
867
    public class DisposeGuard : IDisposable
868
    {
869
        private readonly System.Action _disposeCall;
870

    
871
        public DisposeGuard(System.Action start, System.Action dispose)
872
        {
873
            _disposeCall = dispose;
874
            start();
875
        }
876

    
877
        public void Dispose()
878
        {
879
            _disposeCall();
880
            GC.SuppressFinalize(this);
881
        }       
882
    }
883
}