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