5ecba00f2ba664914629f395ad664caaec6a945d
[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 = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
86 \r
87         private PithosSettings _settings;\r
88         public PithosSettings Settings\r
89         {\r
90             get { return _settings; }\r
91             set\r
92             {\r
93                 _settings = value;\r
94                 NotifyOfPropertyChange(()=>Settings);\r
95             }\r
96         }\r
97 \r
98         private ObservableConcurrentCollection<AccountViewModel> _accounts;\r
99         public ObservableConcurrentCollection<AccountViewModel> Accounts\r
100         {\r
101             get { return _accounts; }\r
102             set \r
103             { \r
104                 _accounts = value;\r
105                 NotifyOfPropertyChange(()=>Accounts);\r
106             }\r
107         }\r
108         \r
109         public bool StartOnSystemStartup { get; set; }\r
110 \r
111         public ShellViewModel Shell { get;  set; }\r
112         //ShellExtensionController _extensionController=new ShellExtensionController();\r
113 \r
114         [ImportingConstructor]\r
115         public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings)\r
116         {\r
117             this.DisplayName = "Pithos+ Preferences";\r
118 \r
119             // ReSharper disable DoNotCallOverridableMethodsInConstructor\r
120             //Caliburn.Micro uses DisplayName for the view's title\r
121             DisplayName = "Pithos+ Preferences";\r
122             // ReSharper restore DoNotCallOverridableMethodsInConstructor\r
123 \r
124             _windowManager = windowManager;\r
125             _events = events;\r
126 \r
127             Shell = shell;\r
128             \r
129             Settings=settings;\r
130             Accounts = new ObservableConcurrentCollection<AccountViewModel>();\r
131             \r
132             \r
133             var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);\r
134             _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");\r
135 \r
136 \r
137             StartOnSystemStartup = File.Exists(_shortcutPath);\r
138 \r
139             //SelectedTab = currentTab;\r
140         }\r
141 \r
142         protected override void OnViewLoaded(object view)\r
143         {\r
144             base.OnViewLoaded(view);\r
145             Settings.Reload();\r
146             Accounts.Clear();\r
147 \r
148             if (Settings.Accounts == null)\r
149             {\r
150                 Settings.Accounts = new AccountsCollection();\r
151                 Settings.Save();\r
152             }\r
153             var accountVMs = from account in Settings.Accounts\r
154                              select new AccountViewModel(account);\r
155 \r
156             Accounts.AddFromEnumerable(accountVMs);\r
157         }\r
158 \r
159         private string _selectedTab="General";\r
160         public string SelectedTab\r
161         {\r
162             get { return _selectedTab; }\r
163             set\r
164             {\r
165                 _selectedTab = value??"GeneralTab";\r
166                 NotifyOfPropertyChange(()=>SelectedTab);\r
167                 NotifyOfPropertyChange(() => AccountTabSelected);\r
168             }\r
169         }\r
170 \r
171 \r
172         public bool AccountTabSelected\r
173         {\r
174             get { return _selectedTab == "AccountTab"; }\r
175         }\r
176         #region Preferences Properties\r
177 \r
178         private bool _noProxy;\r
179         public bool NoProxy\r
180         {\r
181             get { return _noProxy; }\r
182             set\r
183             {\r
184                 _noProxy = value;\r
185                 NotifyOfPropertyChange(()=>NoProxy);\r
186             }\r
187         }\r
188 \r
189 \r
190         private bool _defaultProxy;\r
191 \r
192         public bool DefaultProxy\r
193         {\r
194             get { return _defaultProxy; }\r
195             set\r
196             {\r
197                 _defaultProxy = value;\r
198                 NotifyOfPropertyChange(() => DefaultProxy);\r
199             }\r
200         }\r
201 \r
202 \r
203         private bool _manualProxy;\r
204 \r
205         public bool ManualProxy\r
206         {\r
207             get { return _manualProxy; }\r
208             set\r
209             {\r
210                 _manualProxy = value;\r
211                 NotifyOfPropertyChange(() => ManualProxy);\r
212             }\r
213         }\r
214         #endregion\r
215 \r
216 \r
217         public int StartupDelay\r
218         {\r
219             get { return (int) Settings.StartupDelay.TotalMinutes; }\r
220             set\r
221             {\r
222                 if (value<0)\r
223                     throw new ArgumentOutOfRangeException("value",Resources.PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);\r
224                 Settings.StartupDelay = TimeSpan.FromMinutes(value);\r
225                 NotifyOfPropertyChange(()=>StartupDelay);\r
226             }\r
227         }\r
228        \r
229         #region Commands\r
230         \r
231         public bool CanSelectiveSyncFolders\r
232         {\r
233             get { return CurrentAccount != null && CurrentAccount.SelectiveSyncEnabled; }\r
234         }\r
235 \r
236         public void SelectiveSyncFolders()\r
237         {\r
238             //var monitor = Shell.Monitors[CurrentAccount.AccountKey];\r
239             \r
240             \r
241             var model = new SelectiveSynchViewModel(_events,CurrentAccount.Account,CurrentAccount.ApiKey,false);            \r
242             if (_windowManager.ShowDialog(model) == true)\r
243             {\r
244                 \r
245             }\r
246         }\r
247 \r
248        /* private bool _networkTracing;\r
249         public bool NetworkTracing\r
250         {\r
251             get { return _networkTracing; }\r
252             set\r
253             {\r
254                 _networkTracing = value;\r
255                 \r
256             }\r
257         }*/\r
258 \r
259         public void RefreshApiKey()\r
260         {\r
261             //_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
262             if (CurrentAccount == null)\r
263                 return;\r
264             try\r
265             {\r
266 \r
267                 var name = CurrentAccount.AccountName;\r
268 \r
269                 var loginUri = new Uri(CurrentAccount.ServerUrl).Combine("login");\r
270                 var credentials = PithosAccount.RetrieveCredentials(loginUri.ToString(),name);\r
271                 if (credentials==null)\r
272                     return;\r
273                 //The server will return credentials for a different account, not just the current account\r
274                 //We need to find the correct account first\r
275                 var account = Accounts.First(act => act.AccountName == credentials.UserName && act.ServerUrl == CurrentAccount.ServerUrl);\r
276                 account.ApiKey = credentials.Password;                \r
277                 account.IsExpired = false;\r
278                 Settings.Save();\r
279                 TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));\r
280                 NotifyOfPropertyChange(() => Accounts);\r
281             }\r
282             catch (AggregateException exc)\r
283             {\r
284                 string message = String.Format("API Key retrieval failed");\r
285                 Log.Error(message, exc.InnerException);\r
286                 _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });\r
287             }\r
288             catch (Exception exc)\r
289             {\r
290                 string message = String.Format("API Key retrieval failed");\r
291                 Log.Error(message, exc);\r
292                 _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });\r
293             }\r
294 \r
295         }\r
296 \r
297     \r
298         public void OpenLogPath()\r
299         {\r
300             Shell.OpenLogPath();\r
301         }\r
302 \r
303         public void OpenLogConsole()\r
304         {\r
305             var logView=IoC.Get<LogConsole.LogConsoleViewModel>();            \r
306             _windowManager.ShowWindow(logView);\r
307         }\r
308 \r
309         public void SaveChanges()\r
310         {\r
311             DoSave();\r
312             TryClose(/*true*/);\r
313         }\r
314 \r
315         public void RejectChanges()\r
316         {\r
317             Settings.Reload();\r
318             TryClose(/*false*/);\r
319         }\r
320 \r
321         public void ApplyChanges()\r
322         {\r
323             DoSave();\r
324         }\r
325 \r
326         private void DoSave()\r
327         {\r
328             //SetStartupMode();            \r
329 \r
330             //Ensure we save the settings changes first\r
331             foreach (var account in _accountsToRemove)\r
332             {\r
333                 Settings.Accounts.Remove(account);\r
334             }\r
335 \r
336             foreach (var account in _accountsToAdd)\r
337             {\r
338                 Settings.Accounts.Add(account);    \r
339             }\r
340 \r
341             Settings.Save();\r
342 \r
343 \r
344             try\r
345             {\r
346                 foreach (var account in _accountsToRemove)\r
347                 {\r
348                     Shell.RemoveMonitor(account.ServerUrl, account.AccountName);\r
349                     Shell.RemoveAccountFromDatabase(account);\r
350                 }\r
351 \r
352                 foreach (var account in Settings.Accounts)\r
353                 {\r
354                     Shell.MonitorAccount(account);\r
355                 }\r
356 \r
357                 var poller=IoC.Get<PollAgent>();\r
358                 poller.SynchNow();\r
359             }                \r
360             finally\r
361             {\r
362                 _accountsToRemove.Clear();\r
363                 _accountsToAdd.Clear();\r
364             }\r
365 \r
366             NotifyOfPropertyChange(()=>Settings);\r
367 \r
368             if (IgnoreCertificateErrors)\r
369                 ServicePointManager.ServerCertificateValidationCallback= (sender,certificate,chain,errors)=> true;\r
370             else\r
371             {\r
372                 ServicePointManager.ServerCertificateValidationCallback = null;\r
373             }\r
374         }\r
375 \r
376      /*   public void ChangePithosFolder()\r
377         {\r
378             var browser = new FolderBrowserDialog();\r
379             browser.SelectedPath = Settings.PithosPath;\r
380             var result = browser.ShowDialog((IWin32Window)GetView());\r
381             if (result == DialogResult.OK)\r
382             {\r
383                 var newPath = browser.SelectedPath;\r
384                 var accountName = CurrentAccount.AccountName;\r
385                 var monitor = Shell.Monitors[accountName];\r
386                 monitor.Stop();\r
387                 \r
388                 Shell.Monitors.Remove(accountName);\r
389 \r
390                 Directory.Move(Settings.PithosPath, newPath);\r
391                 Settings.PithosPath = newPath;\r
392                 Settings.Save();\r
393 \r
394                 Shell.MonitorAccount(CurrentAccount);\r
395 \r
396                 NotifyOfPropertyChange(() => Settings);                \r
397             }\r
398         }\r
399 */\r
400 \r
401 \r
402         readonly List<AccountSettings> _accountsToAdd=new List<AccountSettings>();\r
403        public void AddAccount()\r
404        {\r
405            var wizard = new AddAccountViewModel();\r
406            if (_windowManager.ShowDialog(wizard) == true)\r
407            {\r
408                try\r
409                {\r
410                    string selectedPath = wizard.AccountPath;\r
411                    var initialRootPath = wizard.ShouldCreateOkeanosFolder?\r
412                                                                              Path.Combine(selectedPath, "Okeanos")\r
413                                              :selectedPath;\r
414                    var actualRootPath= initialRootPath;\r
415                    if (wizard.ShouldCreateOkeanosFolder)\r
416                    {\r
417                        int attempt = 1;\r
418                        while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))\r
419                        {\r
420                            actualRootPath = String.Format("{0} {1}", initialRootPath, attempt++);\r
421                        }\r
422                    }\r
423 \r
424 \r
425 \r
426                    var account = Accounts.FirstOrDefault(act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer);\r
427                    if (account != null)\r
428                    {\r
429                        if (MessageBox.Show("The account you specified already exists. Do you want to update it?", "The account exists") == MessageBoxResult.Yes)\r
430                        {\r
431                            account.ApiKey = wizard.Token;\r
432                            account.IsExpired = false;\r
433                            CurrentAccount = account;\r
434                        }\r
435                    }\r
436                    else\r
437                    {\r
438                        var newAccount = new AccountSettings\r
439                                             {\r
440                                                 AccountName = wizard.AccountName,\r
441                                                 ServerUrl = wizard.CurrentServer,\r
442                                                 ApiKey = wizard.Token,\r
443                                                 RootPath = actualRootPath,\r
444                                                 IsActive = wizard.IsAccountActive,\r
445                                             };\r
446 \r
447 \r
448                        var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey)\r
449                                         {\r
450                                             AuthenticationUrl = newAccount.ServerUrl, UsePithos = true\r
451                                         };\r
452 \r
453                        InitializeSelectiveFolders(newAccount, client);\r
454 \r
455                    \r
456                        //TODO:Add the "pithos" container as a default selection                   \r
457 \r
458                        _accountsToAdd.Add(newAccount);\r
459                        var accountVm = new AccountViewModel(newAccount);\r
460                        (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);\r
461                        CurrentAccount = accountVm;\r
462                    }\r
463                    NotifyOfPropertyChange(() => Accounts);\r
464                    NotifyOfPropertyChange(() => Settings);\r
465                }\r
466                catch (WebException exc)\r
467                {\r
468                    Log.ErrorFormat("[Add Account] Connectivity Error: {0}", exc);\r
469                    MessageBox.Show("Unable to connect to Pithos. Please try again later", "Connectivity Error",\r
470                                    MessageBoxButton.OK, MessageBoxImage.Exclamation);\r
471                }\r
472            }\r
473 \r
474 \r
475             \r
476        }\r
477 \r
478         private void InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,int retries=3)\r
479         {\r
480             try\r
481             {\r
482                 client.Authenticate();\r
483 \r
484                 var containers = client.ListContainers(newAccount.AccountName);\r
485                 var containerUris = from container in containers\r
486                                     select String.Format(@"{0}/v1/{1}/{2}",\r
487                                                          newAccount.ServerUrl, newAccount.AccountName,\r
488                                                          container.Name);\r
489 \r
490                 newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
491 \r
492                 var objectInfos = (from container in containers\r
493                                    from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
494                                    where container.Name.ToString() != "trash"\r
495                                    select dir).ToList();\r
496                 var tree = objectInfos.ToTree();\r
497 \r
498                 var selected = (from root in tree\r
499                                 from child in root\r
500                                 select child.Uri.ToString()).ToArray();\r
501                 newAccount.SelectiveFolders.AddRange(selected);                \r
502             }\r
503             catch (WebException)\r
504             {\r
505                 if (retries>0)\r
506                     InitializeSelectiveFolders(newAccount,client,retries-1);\r
507                 else\r
508                     throw;\r
509             }\r
510         }\r
511 \r
512 /*\r
513         public void AddPithosAccount()\r
514        {\r
515             var credentials=PithosAccount.RetrieveCredentials(null);\r
516             if (credentials == null)\r
517                 return;\r
518             var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);\r
519             var accountVM = new AccountViewModel(account);\r
520             if (account == null)\r
521             {\r
522                 account=new AccountSettings{\r
523                     AccountName=credentials.UserName,\r
524                     ApiKey=credentials.Password\r
525                 };\r
526                 Settings.Accounts.Add(account);\r
527                 accountVM = new AccountViewModel(account);\r
528                 (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);\r
529             }\r
530             else\r
531             {\r
532                 account.ApiKey=credentials.Password;\r
533             }\r
534             //SelectedAccountIndex= Settings.Accounts.IndexOf(account);\r
535             CurrentAccount = accountVM;\r
536             NotifyOfPropertyChange(() => Accounts);\r
537             NotifyOfPropertyChange(()=>Settings);                       \r
538        }\r
539 */\r
540 \r
541 \r
542         readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();\r
543         public void RemoveAccount()\r
544         {\r
545             Accounts.TryRemove(CurrentAccount);\r
546             _accountsToRemove.Add(CurrentAccount.Account);\r
547 \r
548             CurrentAccount = null;\r
549             NotifyOfPropertyChange(() => Accounts);\r
550 \r
551             \r
552             //NotifyOfPropertyChange("Settings.Accounts");\r
553         }\r
554 \r
555         public bool CanRemoveAccount\r
556         {\r
557             get { return (CurrentAccount != null); }\r
558         }\r
559 \r
560         public bool CanClearAccountCache\r
561         {\r
562             get { return (CurrentAccount != null); }\r
563         }\r
564 \r
565         public void ClearAccountCache()\r
566         {\r
567             if (MessageBoxResult.Yes == MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" +\r
568                             " You will have to download all partially downloaded data again\n" +\r
569                             "This change can not be undone\n\n" +\r
570             "Do you wish to delete all partially downloaded data?", "Warning! Clearing account cache",\r
571                             MessageBoxButton.YesNo,MessageBoxImage.Question,MessageBoxResult.No))\r
572             {\r
573 \r
574                 var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder);\r
575                 var dir = new DirectoryInfo(cachePath);\r
576                 //The file may not exist if we just created the account\r
577                 if (!dir.Exists)\r
578                     return;\r
579                 dir.EnumerateFiles().Apply(file=>file.Delete());\r
580                 dir.EnumerateDirectories().Apply(folder => folder.Delete(true));\r
581             }\r
582         }\r
583 \r
584 \r
585         public bool ExtensionsActivated\r
586         {\r
587             get { return Settings.ExtensionsActivated; }\r
588             set\r
589             {\r
590                 if (Settings.ExtensionsActivated == value)\r
591                     return;\r
592 \r
593                 Settings.ExtensionsActivated = value;\r
594 \r
595 /*\r
596                 if (value)\r
597                     _extensionController.RegisterExtensions();\r
598                 else\r
599                 {\r
600                     _extensionController.UnregisterExtensions();\r
601                 }\r
602 */\r
603                 NotifyOfPropertyChange(() => ExtensionsActivated);\r
604             }\r
605         }\r
606 \r
607         public bool DebugLoggingEnabled\r
608         {\r
609             get { return Settings.DebugLoggingEnabled; }\r
610             set { \r
611                 Settings.DebugLoggingEnabled = value;\r
612                 NotifyOfPropertyChange(()=>DebugLoggingEnabled);\r
613             }\r
614         }\r
615 \r
616         public bool IgnoreCertificateErrors\r
617         {\r
618             get { return Settings.IgnoreCertificateErrors; }\r
619             set {\r
620                 Settings.IgnoreCertificateErrors = value;\r
621                 NotifyOfPropertyChange(() => IgnoreCertificateErrors);\r
622             }\r
623         }\r
624        \r
625         #endregion\r
626 \r
627        /* private int _selectedAccountIndex;\r
628         public int SelectedAccountIndex\r
629         {\r
630             get { return _selectedAccountIndex; }\r
631             set\r
632             {\r
633                 //var accountCount=Settings.Accounts.Count;\r
634                 //if (accountCount == 0)\r
635                 //    return;\r
636                 //if (0 <= value && value < accountCount)\r
637                 //    _selectedAccountIndex = value;\r
638                 //else\r
639                 //    _selectedAccountIndex = 0;\r
640                 _selectedAccountIndex = value;\r
641                 NotifyOfPropertyChange(() => CurrentAccount);\r
642                 NotifyOfPropertyChange(() => CanRemoveAccount);\r
643                 NotifyOfPropertyChange(()=>SelectedAccountIndex);\r
644             }\r
645         }*/\r
646 \r
647         private AccountViewModel _currentAccount;\r
648         private readonly IWindowManager _windowManager;\r
649         private readonly string _shortcutPath;\r
650 \r
651 \r
652         \r
653         public AccountViewModel CurrentAccount\r
654         {\r
655             get { return _currentAccount; }\r
656             set\r
657             {\r
658                 _currentAccount = value;\r
659 \r
660                 if (_currentAccount!=null)\r
661                     _currentAccount.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanSelectiveSyncFolders);\r
662 \r
663                 NotifyOfPropertyChange(() => CurrentAccount);\r
664                 NotifyOfPropertyChange(() => CanRemoveAccount);\r
665                 NotifyOfPropertyChange(() => CanSelectiveSyncFolders);\r
666                 NotifyOfPropertyChange(() => CanMoveAccountFolder);\r
667                 NotifyOfPropertyChange(() => CanClearAccountCache);\r
668             }\r
669         }\r
670 \r
671 /*\r
672         public AccountSettings CurrentAccount\r
673         {\r
674             get {\r
675                 if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count)                    \r
676                     return Settings.Accounts[SelectedAccountIndex];\r
677                 return null;\r
678             }\r
679 \r
680         }\r
681 */\r
682 \r
683 \r
684         public bool CanMoveAccountFolder\r
685         {\r
686             get { return CurrentAccount != null; }\r
687         }\r
688 \r
689     public void MoveAccountFolder()\r
690     {\r
691 \r
692         using (var dlg = new FolderBrowserDialog())\r
693         {\r
694             var currentFolder = CurrentAccount.RootPath;\r
695             dlg.SelectedPath = currentFolder;\r
696             //Ask the user to select a folder\r
697             //Note: We need a parent window here, which we retrieve with GetView            \r
698             var view = (Window)GetView();            \r
699             if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))\r
700                 return;            \r
701 \r
702             var newPath= dlg.SelectedPath;                \r
703             //Find the account's monitor and stop it\r
704             PithosMonitor monitor;\r
705             if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor))\r
706             {\r
707                 monitor.Stop();\r
708 \r
709 \r
710                 var oldPath = monitor.RootPath;\r
711                 //The old directory may not exist eg. if we create an account for the first time\r
712                 if (Directory.Exists(oldPath))\r
713                 {\r
714                     //If it does, do the move\r
715 \r
716                     //Now Create all of the directories\r
717                     foreach (string dirPath in Directory.EnumerateDirectories(oldPath, "*",\r
718                                                            SearchOption.AllDirectories))\r
719                         Directory.CreateDirectory(dirPath.Replace(oldPath, newPath));\r
720 \r
721                     //Copy all the files\r
722                     foreach (string newFilePath in Directory.EnumerateFiles(oldPath, "*.*",\r
723                                                                             SearchOption.AllDirectories))\r
724                         File.Copy(newFilePath, newFilePath.Replace(oldPath, newPath));\r
725 \r
726                     Log.InfoFormat("Deleting account folder {0}",oldPath);\r
727                     Directory.Delete(oldPath, true);\r
728 \r
729                     //We also need to change the path of the existing file states\r
730                     monitor.MoveFileStates(oldPath, newPath);\r
731                 }\r
732             }\r
733             //Replace the old rootpath with the new\r
734             CurrentAccount.RootPath = newPath;\r
735             //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date\r
736             Settings.Save();            \r
737             //And start the monitor on the new RootPath            \r
738             if (monitor != null)\r
739             {\r
740                 monitor.RootPath = newPath;\r
741                 if (CurrentAccount.IsActive)\r
742                     monitor.Start();\r
743             }\r
744             else\r
745                 Shell.MonitorAccount(CurrentAccount.Account);\r
746             //Finally, notify that the Settings, CurrentAccount have changed\r
747             NotifyOfPropertyChange(() => CurrentAccount);\r
748             NotifyOfPropertyChange(() => Settings);\r
749 \r
750         }\r
751     }\r
752     }\r
753 }\r