Fix when wiping an account that hasn't been authenticated
[pithos-ms-client] / trunk / Pithos.Client.WPF / Preferences / PreferencesViewModel.cs
1 #region\r
2 /* -----------------------------------------------------------------------\r
3  * <copyright file="PreferencesViewModel.cs" company="GRNet">\r
4  * \r
5  * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
6  *\r
7  * Redistribution and use in source and binary forms, with or\r
8  * without modification, are permitted provided that the following\r
9  * conditions are met:\r
10  *\r
11  *   1. Redistributions of source code must retain the above\r
12  *      copyright notice, this list of conditions and the following\r
13  *      disclaimer.\r
14  *\r
15  *   2. Redistributions in binary form must reproduce the above\r
16  *      copyright notice, this list of conditions and the following\r
17  *      disclaimer in the documentation and/or other materials\r
18  *      provided with the distribution.\r
19  *\r
20  *\r
21  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
32  * POSSIBILITY OF SUCH DAMAGE.\r
33  *\r
34  * The views and conclusions contained in the software and\r
35  * documentation are those of the authors and should not be\r
36  * interpreted as representing official policies, either expressed\r
37  * or implied, of GRNET S.A.\r
38  * </copyright>\r
39  * -----------------------------------------------------------------------\r
40  */\r
41 #endregion\r
42 \r
43 \r
44 using System.Collections.Concurrent;\r
45 using System.Collections.Generic;\r
46 using System.Collections.Specialized;\r
47 using System.ComponentModel.Composition;\r
48 using System.Diagnostics;\r
49 using System.IO;\r
50 using System.Net;\r
51 using System.Reflection;\r
52 using System.Threading.Tasks;\r
53 using System.Windows;\r
54 using System.Windows.Forms;\r
55 using Caliburn.Micro;\r
56 using Pithos.Client.WPF.Configuration;\r
57 using Pithos.Client.WPF.Properties;\r
58 using Pithos.Client.WPF.SelectiveSynch;\r
59 using Pithos.Client.WPF.Utils;\r
60 using Pithos.Core;\r
61 using Pithos.Core.Agents;\r
62 using Pithos.Interfaces;\r
63 using System;\r
64 using System.Linq;\r
65 using Pithos.Network;\r
66 using MessageBox = System.Windows.MessageBox;\r
67 using Screen = Caliburn.Micro.Screen;\r
68 \r
69 namespace Pithos.Client.WPF.Preferences\r
70 {\r
71     /// <summary>\r
72     /// The preferences screen displays user and account settings and updates the PithosMonitor\r
73     /// classes when account settings change.\r
74     /// </summary>\r
75     /// <remarks>\r
76     /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate\r
77     /// ViewModels, one for each tab.\r
78     /// </remarks>\r
79     [Export, PartCreationPolicy(CreationPolicy.Shared)]\r
80     public class PreferencesViewModel : Screen\r
81     {\r
82         private readonly IEventAggregator _events;\r
83 \r
84         //Logging in the Pithos client is provided by log4net\r
85         private static readonly log4net.ILog Log =\r
86             log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
87 \r
88         private PithosSettings _settings;\r
89 \r
90         public PithosSettings Settings\r
91         {\r
92             get { return _settings; }\r
93             set\r
94             {\r
95                 _settings = value;\r
96                 NotifyOfPropertyChange(() => Settings);\r
97             }\r
98         }\r
99 \r
100         private ObservableConcurrentCollection<AccountViewModel> _accounts;\r
101 \r
102         public ObservableConcurrentCollection<AccountViewModel> Accounts\r
103         {\r
104             get { return _accounts; }\r
105             set\r
106             {\r
107                 _accounts = value;\r
108                 NotifyOfPropertyChange(() => Accounts);\r
109             }\r
110         }\r
111 \r
112         public bool StartOnSystemStartup { get; set; }\r
113 \r
114         public ShellViewModel Shell { get; set; }\r
115         //ShellExtensionController _extensionController=new ShellExtensionController();\r
116 \r
117         [ImportingConstructor]\r
118         public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell,\r
119                                     PithosSettings settings)\r
120         {\r
121             this.DisplayName = "Pithos+ Preferences";\r
122 \r
123             // ReSharper disable DoNotCallOverridableMethodsInConstructor\r
124             //Caliburn.Micro uses DisplayName for the view's title\r
125             DisplayName = "Pithos+ Preferences";\r
126             // ReSharper restore DoNotCallOverridableMethodsInConstructor\r
127 \r
128             _windowManager = windowManager;\r
129             _events = events;\r
130 \r
131             Shell = shell;\r
132 \r
133             Settings = settings;\r
134             Accounts = new ObservableConcurrentCollection<AccountViewModel>();\r
135 \r
136 \r
137             var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);\r
138             _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");\r
139 \r
140 \r
141             StartOnSystemStartup = File.Exists(_shortcutPath);\r
142 \r
143             //SelectedTab = currentTab;\r
144         }\r
145 \r
146         protected override void OnViewLoaded(object view)\r
147         {\r
148             base.OnViewLoaded(view);\r
149 \r
150             Settings.Reload();\r
151 \r
152             Accounts.Clear();\r
153 \r
154             if (Settings.Accounts == null)\r
155             {\r
156                 Settings.Accounts = new AccountsCollection();\r
157                 Settings.Save();\r
158             }\r
159             var accountVMs = from account in Settings.Accounts\r
160                              select new AccountViewModel(account);\r
161 \r
162             Accounts.AddFromEnumerable(accountVMs);\r
163 \r
164         }\r
165 \r
166         private string _selectedTab = "General";\r
167 \r
168         public string SelectedTab\r
169         {\r
170             get { return _selectedTab; }\r
171             set\r
172             {\r
173                 _selectedTab = value ?? "GeneralTab";\r
174                 NotifyOfPropertyChange(() => SelectedTab);\r
175                 NotifyOfPropertyChange(() => AccountTabSelected);\r
176             }\r
177         }\r
178 \r
179 \r
180         public bool AccountTabSelected\r
181         {\r
182             get { return _selectedTab == "AccountTab"; }\r
183         }\r
184 \r
185         #region Preferences Properties\r
186 \r
187         private bool _noProxy;\r
188 \r
189         public bool NoProxy\r
190         {\r
191             get { return _noProxy; }\r
192             set\r
193             {\r
194                 _noProxy = value;\r
195                 NotifyOfPropertyChange(() => NoProxy);\r
196             }\r
197         }\r
198 \r
199 \r
200         private bool _defaultProxy;\r
201 \r
202         public bool DefaultProxy\r
203         {\r
204             get { return _defaultProxy; }\r
205             set\r
206             {\r
207                 _defaultProxy = value;\r
208                 NotifyOfPropertyChange(() => DefaultProxy);\r
209             }\r
210         }\r
211 \r
212 \r
213         private bool _manualProxy;\r
214 \r
215         public bool ManualProxy\r
216         {\r
217             get { return _manualProxy; }\r
218             set\r
219             {\r
220                 _manualProxy = value;\r
221                 NotifyOfPropertyChange(() => ManualProxy);\r
222             }\r
223         }\r
224 \r
225         #endregion\r
226 \r
227 \r
228         public int StartupDelay\r
229         {\r
230             get { return (int) Settings.StartupDelay.TotalMinutes; }\r
231             set\r
232             {\r
233                 if (value < 0)\r
234                     throw new ArgumentOutOfRangeException("value",\r
235                                                           Resources.\r
236                                                               PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);\r
237                 Settings.StartupDelay = TimeSpan.FromMinutes(value);\r
238                 NotifyOfPropertyChange(() => StartupDelay);\r
239             }\r
240         }\r
241 \r
242         #region Commands\r
243 \r
244         public bool CanSelectiveSyncFolders\r
245         {\r
246             get { return CurrentAccount != null && CurrentAccount.SelectiveSyncEnabled; }\r
247         }\r
248 \r
249         public void SelectiveSyncFolders()\r
250         {\r
251             //var monitor = Shell.Monitors[CurrentAccount.AccountKey];\r
252 \r
253 \r
254             var model = new SelectiveSynchViewModel(_events, CurrentAccount.Account, CurrentAccount.ApiKey, false);\r
255             if (_windowManager.ShowDialog(model) == true)\r
256             {\r
257 \r
258             }\r
259         }\r
260 \r
261         /* private bool _networkTracing;\r
262         public bool NetworkTracing\r
263         {\r
264             get { return _networkTracing; }\r
265             set\r
266             {\r
267                 _networkTracing = value;\r
268                 \r
269             }\r
270         }*/\r
271 \r
272         public void RefreshApiKey()\r
273         {\r
274             //_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 });\r
275             if (CurrentAccount == null)\r
276                 return;\r
277             try\r
278             {\r
279 \r
280                 var name = CurrentAccount.AccountName;\r
281 \r
282                 var loginUri = new Uri(CurrentAccount.ServerUrl).Combine("login");\r
283                 var credentials = PithosAccount.RetrieveCredentials(loginUri.ToString(), name);\r
284                 if (credentials == null)\r
285                     return;\r
286                 //The server will return credentials for a different account, not just the current account\r
287                 //We need to find the correct account first\r
288                 var account =\r
289                     Accounts.First(\r
290                         act => act.AccountName == credentials.UserName && act.ServerUrl == CurrentAccount.ServerUrl);\r
291                 account.ApiKey = credentials.Password;\r
292                 account.IsExpired = false;\r
293                 Settings.Save();\r
294                 TaskEx.Delay(10000).ContinueWith(_ => Shell.MonitorAccount(account.Account));\r
295                 NotifyOfPropertyChange(() => Accounts);\r
296             }\r
297             catch (AggregateException exc)\r
298             {\r
299                 string message = String.Format("API Key retrieval failed");\r
300                 Log.Error(message, exc.InnerException);\r
301                 _events.Publish(new Notification\r
302                                     {Title = "Authorization failed", Message = message, Level = TraceLevel.Error});\r
303             }\r
304             catch (Exception exc)\r
305             {\r
306                 string message = String.Format("API Key retrieval failed");\r
307                 Log.Error(message, exc);\r
308                 _events.Publish(new Notification\r
309                                     {Title = "Authorization failed", Message = message, Level = TraceLevel.Error});\r
310             }\r
311 \r
312         }\r
313 \r
314         public bool CanWipeAccount\r
315         {\r
316             get { return CurrentAccount != null \r
317                 && Shell.Monitors.ContainsKey(CurrentAccount.AccountKey)\r
318                 && Shell.Monitors[CurrentAccount.AccountKey].CloudClient!=null;\r
319             }\r
320         }\r
321 \r
322         public async void WipeAccount()\r
323         {\r
324             PithosMonitor aMonitor;\r
325             if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out aMonitor))\r
326             {\r
327                 if (aMonitor.CloudClient == null)\r
328                 {\r
329                     Log.ErrorFormat("Tried to wipe account [{0}] before authenticating",CurrentAccount.AccountKey);\r
330                     return;\r
331                 }\r
332                 var message = String.Format("You are about to wipe all data in the {0} account at {1}. Are you sure?",\r
333                                             CurrentAccount.AccountName, CurrentAccount.ServerUrl);\r
334                 if (MessageBoxResult.Yes !=\r
335                     MessageBox.Show(message, "Warning! Account data will be wiped", MessageBoxButton.YesNo,\r
336                                     MessageBoxImage.Hand, MessageBoxResult.No))\r
337                     return;      \r
338                           \r
339                 await aMonitor.CloudClient.WipeContainer("", new Uri("pithos", UriKind.Relative));\r
340                 aMonitor.Stop();\r
341                 aMonitor.Start();\r
342                 MessageBox.Show("Account wiped");\r
343             }\r
344         }\r
345 \r
346 \r
347         public void OpenLogPath()\r
348         {\r
349             Shell.OpenLogPath();\r
350         }\r
351 \r
352         public void OpenLogConsole()\r
353         {\r
354             var logView = IoC.Get<LogConsole.LogConsoleViewModel>();\r
355             _windowManager.ShowWindow(logView);\r
356         }\r
357 \r
358         public void SaveChanges()\r
359         {\r
360             DoSave();\r
361             TryClose( /*true*/);\r
362         }\r
363 \r
364         public void RejectChanges()\r
365         {\r
366             Settings.Reload();\r
367             TryClose( /*false*/);\r
368         }\r
369 \r
370         public void ApplyChanges()\r
371         {\r
372             DoSave();\r
373         }\r
374 \r
375         private void DoSave()\r
376         {\r
377             //SetStartupMode();            \r
378 \r
379             //Ensure we save the settings changes first\r
380             foreach (var account in _accountsToRemove)\r
381             {\r
382                 Settings.Accounts.Remove(account);\r
383             }\r
384 \r
385             foreach (var account in _accountsToAdd)\r
386             {\r
387                 Settings.Accounts.Add(account);\r
388             }\r
389 \r
390             Settings.Save();\r
391 \r
392 \r
393             try\r
394             {\r
395                 foreach (var account in _accountsToRemove)\r
396                 {\r
397                     Shell.RemoveMonitor(account.ServerUrl, account.AccountName);\r
398                     Shell.RemoveAccountFromDatabase(account);\r
399                 }\r
400 \r
401                 foreach (var account in Settings.Accounts)\r
402                 {\r
403                     Shell.MonitorAccount(account);\r
404                 }\r
405 \r
406                 var poller = IoC.Get<PollAgent>();\r
407                 poller.SynchNow();\r
408             }\r
409             finally\r
410             {\r
411                 _accountsToRemove.Clear();\r
412                 _accountsToAdd.Clear();\r
413             }\r
414 \r
415             NotifyOfPropertyChange(() => Settings);\r
416 \r
417             if (IgnoreCertificateErrors)\r
418                 ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;\r
419             else\r
420             {\r
421                 ServicePointManager.ServerCertificateValidationCallback = null;\r
422             }\r
423         }\r
424 \r
425         /*   public void ChangePithosFolder()\r
426         {\r
427             var browser = new FolderBrowserDialog();\r
428             browser.SelectedPath = Settings.PithosPath;\r
429             var result = browser.ShowDialog((IWin32Window)GetView());\r
430             if (result == DialogResult.OK)\r
431             {\r
432                 var newPath = browser.SelectedPath;\r
433                 var accountName = CurrentAccount.AccountName;\r
434                 var monitor = Shell.Monitors[accountName];\r
435                 monitor.Stop();\r
436                 \r
437                 Shell.Monitors.Remove(accountName);\r
438 \r
439                 Directory.Move(Settings.PithosPath, newPath);\r
440                 Settings.PithosPath = newPath;\r
441                 Settings.Save();\r
442 \r
443                 Shell.MonitorAccount(CurrentAccount);\r
444 \r
445                 NotifyOfPropertyChange(() => Settings);                \r
446             }\r
447         }\r
448 */\r
449 \r
450 \r
451         private readonly List<AccountSettings> _accountsToAdd = new List<AccountSettings>();\r
452 \r
453         public async void AddAccount()\r
454         {\r
455             var wizard = new AddAccountViewModel();\r
456             if (_windowManager.ShowDialog(wizard) == true)\r
457             {\r
458                 try\r
459                 {\r
460                     string selectedPath = wizard.AccountPath;\r
461                     var initialRootPath = wizard.ShouldCreateOkeanosFolder\r
462                                               ? Path.Combine(selectedPath, "Okeanos")\r
463                                               : selectedPath;\r
464                     var actualRootPath = initialRootPath;\r
465                     if (wizard.ShouldCreateOkeanosFolder)\r
466                     {\r
467                         int attempt = 1;\r
468                         while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))\r
469                         {\r
470                             actualRootPath = String.Format("{0} {1}", initialRootPath, attempt++);\r
471                         }\r
472                     }\r
473 \r
474 \r
475 \r
476                     var account =\r
477                         Accounts.FirstOrDefault(\r
478                             act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer);\r
479                     if (account != null)\r
480                     {\r
481                         if (\r
482                             MessageBox.Show("The account you specified already exists. Do you want to update it?",\r
483                                             "The account exists") == MessageBoxResult.Yes)\r
484                         {\r
485                             account.ApiKey = wizard.Token;\r
486                             account.IsExpired = false;\r
487                             CurrentAccount = account;\r
488                         }\r
489                     }\r
490                     else\r
491                     {\r
492                         var newAccount = new AccountSettings\r
493                                              {\r
494                                                  AccountName = wizard.AccountName,\r
495                                                  ServerUrl = wizard.CurrentServer,\r
496                                                  ApiKey = wizard.Token,\r
497                                                  RootPath = actualRootPath,\r
498                                                  IsActive = wizard.IsAccountActive,\r
499                                              };\r
500 \r
501 \r
502                         var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey)\r
503                                          {\r
504                                              AuthenticationUrl = newAccount.ServerUrl,\r
505                                              UsePithos = true\r
506                                          };\r
507 \r
508                         await InitializeSelectiveFolders(newAccount, client);\r
509 \r
510 \r
511                         //TODO:Add the "pithos" container as a default selection                   \r
512 \r
513                         _accountsToAdd.Add(newAccount);\r
514                         var accountVm = new AccountViewModel(newAccount);\r
515                         (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);\r
516                         CurrentAccount = accountVm;\r
517                     }\r
518                     NotifyOfPropertyChange(() => Accounts);\r
519                     NotifyOfPropertyChange(() => Settings);\r
520                 }\r
521                 catch (WebException exc)\r
522                 {\r
523                     Log.ErrorFormat("[Add Account] Connectivity Error: {0}", exc);\r
524                     MessageBox.Show("Unable to connect to Pithos. Please try again later", "Connectivity Error",\r
525                                     MessageBoxButton.OK, MessageBoxImage.Exclamation);\r
526                 }\r
527             }\r
528 \r
529 \r
530 \r
531         }\r
532 \r
533         private async Task InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,\r
534                                                       int retries = 3)\r
535         {\r
536             while (true)\r
537             {\r
538                 try\r
539                 {\r
540                     await client.Authenticate().ConfigureAwait(false);\r
541 \r
542                     var containers = await client.ListContainers(newAccount.AccountName).ConfigureAwait(false);\r
543                     var containerUris = from container in containers\r
544                                         select String.Format(@"{0}/v1/{1}/{2}",\r
545                                                              newAccount.ServerUrl, newAccount.AccountName,\r
546                                                              container.Name);\r
547 \r
548                     newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
549 \r
550                     var objectInfos = (from container in containers\r
551                                        from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
552                                        where container.Name.ToString() != "trash"\r
553                                        select dir).ToList();\r
554                     var tree = objectInfos.ToTree();\r
555 \r
556                     var selected = (from root in tree\r
557                                     from child in root\r
558                                     select child.Uri.ToString()).ToArray();\r
559                     newAccount.SelectiveFolders.AddRange(selected);\r
560                     return;\r
561                 }\r
562                 catch (WebException)\r
563                 {\r
564                     if (retries > 0)\r
565                         retries--;\r
566                     else\r
567                         throw;\r
568                 }\r
569             }\r
570         }\r
571 \r
572 /*\r
573         public void AddPithosAccount()\r
574        {\r
575             var credentials=PithosAccount.RetrieveCredentials(null);\r
576             if (credentials == null)\r
577                 return;\r
578             var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);\r
579             var accountVM = new AccountViewModel(account);\r
580             if (account == null)\r
581             {\r
582                 account=new AccountSettings{\r
583                     AccountName=credentials.UserName,\r
584                     ApiKey=credentials.Password\r
585                 };\r
586                 Settings.Accounts.Add(account);\r
587                 accountVM = new AccountViewModel(account);\r
588                 (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);\r
589             }\r
590             else\r
591             {\r
592                 account.ApiKey=credentials.Password;\r
593             }\r
594             //SelectedAccountIndex= Settings.Accounts.IndexOf(account);\r
595             CurrentAccount = accountVM;\r
596             NotifyOfPropertyChange(() => Accounts);\r
597             NotifyOfPropertyChange(()=>Settings);                       \r
598        }\r
599 */\r
600 \r
601 \r
602         private readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();\r
603 \r
604         public void RemoveAccount()\r
605         {\r
606             Accounts.TryRemove(CurrentAccount);\r
607             _accountsToRemove.Add(CurrentAccount.Account);\r
608 \r
609             CurrentAccount = null;\r
610             NotifyOfPropertyChange(() => Accounts);\r
611 \r
612 \r
613             //NotifyOfPropertyChange("Settings.Accounts");\r
614         }\r
615 \r
616         public bool CanRemoveAccount\r
617         {\r
618             get { return (CurrentAccount != null); }\r
619         }\r
620 \r
621         public bool CanClearAccountCache\r
622         {\r
623             get { return (CurrentAccount != null); }\r
624         }\r
625 \r
626         public void ClearAccountCache()\r
627         {\r
628             if (MessageBoxResult.Yes ==\r
629                 MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" +\r
630                                 " You will have to download all partially downloaded data again\n" +\r
631                                 "This change can not be undone\n\n" +\r
632                                 "Do you wish to delete all partially downloaded data?",\r
633                                 "Warning! Clearing account cache",\r
634                                 MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))\r
635             {\r
636 \r
637                 var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder);\r
638                 var dir = new DirectoryInfo(cachePath);\r
639                 //The file may not exist if we just created the account\r
640                 if (!dir.Exists)\r
641                     return;\r
642                 dir.EnumerateFiles().Apply(file => file.Delete());\r
643                 dir.EnumerateDirectories().Apply(folder => folder.Delete(true));\r
644             }\r
645         }\r
646 \r
647 \r
648         public bool ExtensionsActivated\r
649         {\r
650             get { return Settings.ExtensionsActivated; }\r
651             set\r
652             {\r
653                 if (Settings.ExtensionsActivated == value)\r
654                     return;\r
655 \r
656                 Settings.ExtensionsActivated = value;\r
657 \r
658 /*\r
659                 if (value)\r
660                     _extensionController.RegisterExtensions();\r
661                 else\r
662                 {\r
663                     _extensionController.UnregisterExtensions();\r
664                 }\r
665 */\r
666                 NotifyOfPropertyChange(() => ExtensionsActivated);\r
667             }\r
668         }\r
669 \r
670         public bool DebugLoggingEnabled\r
671         {\r
672             get { return Settings.DebugLoggingEnabled; }\r
673             set\r
674             {\r
675                 Settings.DebugLoggingEnabled = value;\r
676                 NotifyOfPropertyChange(() => DebugLoggingEnabled);\r
677             }\r
678         }\r
679 \r
680         public bool IgnoreCertificateErrors\r
681         {\r
682             get { return Settings.IgnoreCertificateErrors; }\r
683             set\r
684             {\r
685                 Settings.IgnoreCertificateErrors = value;\r
686                 NotifyOfPropertyChange(() => IgnoreCertificateErrors);\r
687             }\r
688         }\r
689 \r
690         #endregion\r
691 \r
692         /* private int _selectedAccountIndex;\r
693         public int SelectedAccountIndex\r
694         {\r
695             get { return _selectedAccountIndex; }\r
696             set\r
697             {\r
698                 //var accountCount=Settings.Accounts.Count;\r
699                 //if (accountCount == 0)\r
700                 //    return;\r
701                 //if (0 <= value && value < accountCount)\r
702                 //    _selectedAccountIndex = value;\r
703                 //else\r
704                 //    _selectedAccountIndex = 0;\r
705                 _selectedAccountIndex = value;\r
706                 NotifyOfPropertyChange(() => CurrentAccount);\r
707                 NotifyOfPropertyChange(() => CanRemoveAccount);\r
708                 NotifyOfPropertyChange(()=>SelectedAccountIndex);\r
709             }\r
710         }*/\r
711 \r
712         private AccountViewModel _currentAccount;\r
713         private readonly IWindowManager _windowManager;\r
714         private readonly string _shortcutPath;\r
715 \r
716 \r
717 \r
718         public AccountViewModel CurrentAccount\r
719         {\r
720             get { return _currentAccount; }\r
721             set\r
722             {\r
723                 _currentAccount = value;\r
724 \r
725                 if (_currentAccount != null)\r
726                     _currentAccount.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanSelectiveSyncFolders);\r
727 \r
728                 NotifyOfPropertyChange(() => CurrentAccount);\r
729                 NotifyOfPropertyChange(() => CanRemoveAccount);\r
730                 NotifyOfPropertyChange(() => CanSelectiveSyncFolders);\r
731                 NotifyOfPropertyChange(() => CanMoveAccountFolder);\r
732                 NotifyOfPropertyChange(() => CanClearAccountCache);\r
733                 NotifyOfPropertyChange(() => CanWipeAccount);\r
734             }\r
735         }\r
736 \r
737 /*\r
738         public AccountSettings CurrentAccount\r
739         {\r
740             get {\r
741                 if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count)                    \r
742                     return Settings.Accounts[SelectedAccountIndex];\r
743                 return null;\r
744             }\r
745 \r
746         }\r
747 */\r
748 \r
749 \r
750         public bool CanMoveAccountFolder\r
751         {\r
752             get { return CurrentAccount != null; }\r
753         }\r
754 \r
755         public void MoveAccountFolder()\r
756         {\r
757 \r
758             using (var dlg = new FolderBrowserDialog())\r
759             {\r
760                 var currentFolder = CurrentAccount.RootPath;\r
761                 dlg.SelectedPath = currentFolder;\r
762                 //Ask the user to select a folder\r
763                 //Note: We need a parent window here, which we retrieve with GetView            \r
764                 var view = (Window) GetView();\r
765                 if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))\r
766                     return;\r
767 \r
768                 var newPath = dlg.SelectedPath;\r
769                 //Find the account's monitor and stop it\r
770                 PithosMonitor monitor;\r
771                 if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor))\r
772                 {\r
773                     //Problem: Doesn't stop the poll agent\r
774                     monitor.Stop();\r
775 \r
776                     monitor.MoveRootFolder(newPath);\r
777 \r
778                    \r
779                 }\r
780                 //Replace the old rootpath with the new\r
781                 CurrentAccount.RootPath = newPath;\r
782                 //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date\r
783                 Settings.Save();\r
784                 //And start the monitor on the new RootPath            \r
785                 if (monitor != null)\r
786                 {\r
787                     monitor.RootPath = newPath;\r
788                     if (CurrentAccount.IsActive)\r
789                         Shell.StartMonitor(monitor);\r
790                         \r
791                 }\r
792                 else\r
793                     Shell.MonitorAccount(CurrentAccount.Account);\r
794                 //Finally, notify that the Settings, CurrentAccount have changed\r
795                 NotifyOfPropertyChange(() => CurrentAccount);\r
796                 NotifyOfPropertyChange(() => Settings);\r
797 \r
798             }\r
799         }\r
800 \r
801     }\r
802 }\r