Changes to hide the warning image when an account token is refreshed
[pithos-ms-client] / trunk / Pithos.Client.WPF / Preferences / PreferencesViewModel.cs
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 // </copyright>
44 // -----------------------------------------------------------------------
45
46 using System.Collections.Concurrent;
47 using System.ComponentModel.Composition;
48 using System.Diagnostics;
49 using System.IO;
50 using System.Net;
51 using System.Threading.Tasks;
52 using System.Windows;
53 using System.Windows.Forms;
54 using Caliburn.Micro;
55 using Pithos.Client.WPF.Configuration;
56 using Pithos.Client.WPF.SelectiveSynch;
57 using Pithos.Core;
58 using Pithos.Interfaces;
59 using System;
60 using System.Linq;
61 using Screen = Caliburn.Micro.Screen;
62
63 namespace Pithos.Client.WPF.Preferences
64 {
65     /// <summary>
66     /// TODO: Update summary.
67     /// </summary>
68     [Export]
69     public class PreferencesViewModel : Screen
70     {
71         private IEventAggregator _events;
72
73         //Logging in the Pithos client is provided by log4net
74         private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
75
76         private PithosSettings _settings;
77         public PithosSettings Settings
78         {
79             get { return _settings; }
80             set
81             {
82                 _settings = value;
83                 NotifyOfPropertyChange(()=>Settings);
84             }
85         }
86
87         private ObservableConcurrentCollection<AccountViewModel> _accounts;
88         public ObservableConcurrentCollection<AccountViewModel> Accounts
89         {
90             get { return _accounts; }
91             set 
92             { 
93                 _accounts = value;
94                 NotifyOfPropertyChange(()=>Accounts);
95             }
96         }
97         
98         public bool StartOnSystemStartup { get; set; }
99
100         public ShellViewModel Shell { get;  set; }
101         //ShellExtensionController _extensionController=new ShellExtensionController();
102
103         public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings, string currentTab)
104         {
105             _windowManager = windowManager;
106             _events = events;
107
108             DisplayName = "Pithos Preferences";
109             Shell = shell;
110             
111             Settings=settings;
112             Accounts = new ObservableConcurrentCollection<AccountViewModel>();
113             if (settings.Accounts == null)
114             {
115                 settings.Accounts=new AccountsCollection();
116                 settings.Save();
117             }
118             var accountVMs = from account in settings.Accounts
119                              select new AccountViewModel(account);
120
121             Accounts.AddFromEnumerable(accountVMs);
122             
123             var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
124             _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");
125
126
127             StartOnSystemStartup = File.Exists(_shortcutPath);
128
129             SelectedTab = currentTab;
130         }
131
132         private string _selectedTab="General";
133         public string SelectedTab
134         {
135             get { return _selectedTab; }
136             set
137             {
138                 _selectedTab = value??"General";
139                 NotifyOfPropertyChange(()=>SelectedTab);
140                 NotifyOfPropertyChange(() => AccountTabSelected);
141             }
142         }
143
144
145         public bool AccountTabSelected
146         {
147             get { return _selectedTab == "AccountTab"; }
148         }
149         #region Preferences Properties
150
151         private bool _noProxy;
152         public bool NoProxy
153         {
154             get { return _noProxy; }
155             set
156             {
157                 _noProxy = value;
158                 NotifyOfPropertyChange(()=>NoProxy);
159             }
160         }
161
162
163         private bool _defaultProxy;
164
165         public bool DefaultProxy
166         {
167             get { return _defaultProxy; }
168             set
169             {
170                 _defaultProxy = value;
171                 NotifyOfPropertyChange(() => DefaultProxy);
172             }
173         }
174
175
176         private bool _manualProxy;
177
178         public bool ManualProxy
179         {
180             get { return _manualProxy; }
181             set
182             {
183                 _manualProxy = value;
184                 NotifyOfPropertyChange(() => ManualProxy);
185             }
186         }
187         #endregion
188
189
190         public int StartupDelay
191         {
192             get { return (int) Settings.StartupDelay.TotalMinutes; }
193             set
194             {
195                 if (value<0)
196                     throw new ArgumentOutOfRangeException("value","The Startup Delay must be greater or equal to 0");
197                 Settings.StartupDelay = TimeSpan.FromMinutes(value);
198                 NotifyOfPropertyChange(()=>StartupDelay);
199             }
200         }
201        
202         #region Commands
203         
204         public bool CanSelectiveSyncFolders
205         {
206             get { return CurrentAccount != null; }
207         }
208
209         public void SelectiveSyncFolders()
210         {
211             var monitor = Shell.Monitors[CurrentAccount.AccountName];
212             
213
214             var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount.Account);
215             if (_windowManager.ShowDialog(model) == true)
216             {
217                 
218             }
219         }
220
221         public async Task RefreshApiKey()
222         {
223             _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 });
224
225             //var userName = CurrentAccount.AccountName;
226             try
227             {
228
229                 var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
230
231                 var account = Accounts.First(act => act.AccountName == credentials.UserName);
232                 //The server may return credentials for a different account
233                 var monitor =  Shell.Monitors[account.AccountName];
234                 account.ApiKey = credentials.Password;
235                 monitor.ApiKey = credentials.Password;
236                 account.IsExpired = false;
237                 Settings.Save();
238                 TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));
239                 NotifyOfPropertyChange(() => Accounts);
240             }
241             catch (AggregateException exc)
242             {
243                 string message = String.Format("API Key retrieval failed");
244                 Log.Error(message, exc.InnerException);
245                 _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
246             }
247             catch (Exception exc)
248             {
249                 string message = String.Format("API Key retrieval failed");
250                 Log.Error(message, exc);
251                 _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
252             }
253
254         }
255
256     
257         public void SaveChanges()
258         {
259             DoSave();
260             TryClose(true);
261         }
262
263         public void RejectChanges()
264         {
265             Settings.Reload();
266             TryClose(false);
267         }
268
269         public void ApplyChanges()
270         {
271             DoSave();
272         }
273
274         private void DoSave()
275         {
276             Settings.Save();
277             //SetStartupMode();            
278
279             foreach (var account in Settings.Accounts)
280             {                                
281                 Shell.MonitorAccount(account);
282             }
283
284             NotifyOfPropertyChange(()=>Settings);
285         }
286
287      /*   public void ChangePithosFolder()
288         {
289             var browser = new FolderBrowserDialog();
290             browser.SelectedPath = Settings.PithosPath;
291             var result = browser.ShowDialog((IWin32Window)GetView());
292             if (result == DialogResult.OK)
293             {
294                 var newPath = browser.SelectedPath;
295                 var accountName = CurrentAccount.AccountName;
296                 var monitor = Shell.Monitors[accountName];
297                 monitor.Stop();
298                 
299                 Shell.Monitors.Remove(accountName);
300
301                 Directory.Move(Settings.PithosPath, newPath);
302                 Settings.PithosPath = newPath;
303                 Settings.Save();
304
305                 Shell.MonitorAccount(CurrentAccount);
306
307                 NotifyOfPropertyChange(() => Settings);                
308             }
309         }
310 */
311
312         
313
314        public void AddAccount()
315        {
316            var wizard = new AddAccountViewModel();
317            if (_windowManager.ShowDialog(wizard) == true)
318            {
319                string selectedPath = wizard.AccountPath;
320                var initialRootPath = Path.Combine(selectedPath, "Okeanos");
321                var actualRootPath= initialRootPath;
322                int attempt = 1;
323                while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))
324                {
325                    actualRootPath = String.Format("{0} {1}", initialRootPath,attempt++);
326                }
327
328                var newAccount = new AccountSettings
329                                     {
330                                         AccountName = wizard.AccountName,
331                                         ServerUrl=wizard.CurrentServer,
332                                         ApiKey=wizard.Token,
333                                         RootPath = actualRootPath,
334                                         IsActive=wizard.IsAccountActive
335                                     };
336                Settings.Accounts.Add(newAccount);
337                var accountVM = new AccountViewModel(newAccount);
338                (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
339                CurrentAccount = accountVM;
340                NotifyOfPropertyChange(() => Accounts);
341                NotifyOfPropertyChange(() => Settings);   
342            }
343
344
345             
346        }
347
348         public async void AddPithosAccount()
349        {
350             var credentials=await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
351             var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
352             var accountVM = new AccountViewModel(account);
353             if (account == null)
354             {
355                 account=new AccountSettings{
356                     AccountName=credentials.UserName,
357                     ApiKey=credentials.Password
358                 };
359                 Settings.Accounts.Add(account);
360                 accountVM = new AccountViewModel(account);
361                 (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
362             }
363             else
364             {
365                 account.ApiKey=credentials.Password;
366             }
367             //SelectedAccountIndex= Settings.Accounts.IndexOf(account);
368             CurrentAccount = accountVM;
369             NotifyOfPropertyChange(() => Accounts);
370             NotifyOfPropertyChange(()=>Settings);                       
371        }
372
373         public void RemoveAccount()
374         {
375             var accountName = CurrentAccount.AccountName;
376             Settings.Accounts.Remove(CurrentAccount.Account);
377
378             Accounts.TryRemove(CurrentAccount);
379             
380             
381             CurrentAccount = null;
382             //Accounts = Settings.Accounts;
383             //Settings.Save();            
384             Shell.RemoveMonitor(accountName);
385             NotifyOfPropertyChange(() => Accounts);
386             NotifyOfPropertyChange(() => Settings);                       
387             
388             //NotifyOfPropertyChange("Settings.Accounts");
389         }
390
391         public bool CanRemoveAccount
392         {
393             get { return (CurrentAccount != null); }
394         }
395
396
397
398         public bool ExtensionsActivated
399         {
400             get { return Settings.ExtensionsActivated; }
401             set
402             {
403                 if (Settings.ExtensionsActivated == value)
404                     return;
405
406                 Settings.ExtensionsActivated = value;
407
408 /*
409                 if (value)
410                     _extensionController.RegisterExtensions();
411                 else
412                 {
413                     _extensionController.UnregisterExtensions();
414                 }
415 */
416                 NotifyOfPropertyChange(() => ExtensionsActivated);
417             }
418         }
419
420        
421         #endregion
422
423        /* private int _selectedAccountIndex;
424         public int SelectedAccountIndex
425         {
426             get { return _selectedAccountIndex; }
427             set
428             {
429                 //var accountCount=Settings.Accounts.Count;
430                 //if (accountCount == 0)
431                 //    return;
432                 //if (0 <= value && value < accountCount)
433                 //    _selectedAccountIndex = value;
434                 //else
435                 //    _selectedAccountIndex = 0;
436                 _selectedAccountIndex = value;
437                 NotifyOfPropertyChange(() => CurrentAccount);
438                 NotifyOfPropertyChange(() => CanRemoveAccount);
439                 NotifyOfPropertyChange(()=>SelectedAccountIndex);
440             }
441         }*/
442
443         private AccountViewModel _currentAccount;
444         private IWindowManager _windowManager;
445         private string _shortcutPath;
446
447
448         
449         public AccountViewModel CurrentAccount
450         {
451             get { return _currentAccount; }
452             set
453             {
454                 _currentAccount = value;
455                 NotifyOfPropertyChange(()=>CurrentAccount);
456                 NotifyOfPropertyChange(() => CanRemoveAccount);
457                 NotifyOfPropertyChange(() => CanSelectiveSyncFolders);
458                 NotifyOfPropertyChange(() => CanMoveAccountFolder);
459             }
460         }
461
462 /*
463         public AccountSettings CurrentAccount
464         {
465             get {
466                 if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count)                    
467                     return Settings.Accounts[SelectedAccountIndex];
468                 return null;
469             }
470
471         }
472 */
473
474
475         public bool CanMoveAccountFolder
476         {
477             get { return CurrentAccount != null; }
478         }
479
480     public void MoveAccountFolder()
481     {
482
483         using (var dlg = new FolderBrowserDialog())
484         {
485             var currentFolder = CurrentAccount.RootPath;
486             dlg.SelectedPath = currentFolder;
487             //Ask the user to select a folder
488             //Note: We need a parent window here, which we retrieve with GetView            
489             var view = (Window)GetView();            
490             if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))
491                 return;            
492
493             var newPath= dlg.SelectedPath;                
494             //Find the account's monitor and stop it
495             PithosMonitor monitor;
496             if (Shell.Monitors.TryGetValue(CurrentAccount.AccountName, out monitor))
497             {
498                 monitor.Stop();
499
500
501                 var oldPath = monitor.RootPath;
502                 //The old directory may not exist eg. if we create an account for the first time
503                 if (Directory.Exists(oldPath))
504                 {
505                     //If it does, do the move
506
507                     //Now Create all of the directories
508                     foreach (string dirPath in Directory.EnumerateDirectories(oldPath, "*",
509                                                            SearchOption.AllDirectories))
510                         Directory.CreateDirectory(dirPath.Replace(oldPath, newPath));
511
512                     //Copy all the files
513                     foreach (string newFilePath in Directory.EnumerateFiles(oldPath, "*.*",
514                                                                             SearchOption.AllDirectories))
515                         File.Copy(newFilePath, newFilePath.Replace(oldPath, newPath));
516
517                     Directory.Delete(oldPath, true);
518
519                     //We also need to change the path of the existing file states
520                     if (monitor != null)
521                         monitor.MoveFileStates(oldPath, newPath);
522                 }
523             }
524             //Replace the old rootpath with the new
525             CurrentAccount.RootPath = newPath;
526             //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date
527             Settings.Save();            
528             //And start the monitor on the new RootPath            
529             if (monitor != null)
530             {
531                 monitor.RootPath = newPath;
532                 if (CurrentAccount.IsActive)
533                     monitor.Start();
534             }
535             else
536                 Shell.MonitorAccount(CurrentAccount.Account);
537             //Finally, notify that the Settings, CurrentAccount have changed
538             NotifyOfPropertyChange(() => CurrentAccount);
539             NotifyOfPropertyChange(() => Settings);
540
541         }
542     }
543     }
544 }