Temp fixes
[pithos-ms-client] / trunk / Pithos.Client.WPF / Preferences / PreferencesViewModel.cs
index 1a9602f..2857dc8 100644 (file)
@@ -1,39 +1,82 @@
-// -----------------------------------------------------------------------
-// <copyright file="PreferencesViewModel.cs" company="Microsoft">
-// TODO: Update copyright text.
-// </copyright>
-// -----------------------------------------------------------------------
+#region
+/* -----------------------------------------------------------------------
+ * <copyright file="PreferencesViewModel.cs" company="GRNet">
+ * 
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ * </copyright>
+ * -----------------------------------------------------------------------
+ */
+#endregion
+
 
 using System.Collections.Concurrent;
+using System.Collections.Generic;
 using System.ComponentModel.Composition;
+using System.Diagnostics;
 using System.IO;
 using System.Reflection;
+using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Forms;
 using Caliburn.Micro;
-using IWshRuntimeLibrary;
 using Pithos.Client.WPF.Configuration;
-using Pithos.Client.WPF.Preferences;
+using Pithos.Client.WPF.Properties;
 using Pithos.Client.WPF.SelectiveSynch;
 using Pithos.Core;
 using Pithos.Interfaces;
-using File = System.IO.File;
+using System;
+using System.Linq;
 using Screen = Caliburn.Micro.Screen;
 
-namespace Pithos.Client.WPF
+namespace Pithos.Client.WPF.Preferences
 {
-    using System;
-    using System.Linq;
-    using System.Threading.Tasks;
-
     /// <summary>
-    /// TODO: Update summary.
+    /// The preferences screen displays user and account settings and updates the PithosMonitor
+    /// classes when account settings change.
     /// </summary>
+    /// <remarks>
+    /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate
+    /// ViewModels, one for each tab.
+    /// </remarks>
     [Export]
     public class PreferencesViewModel : Screen
     {
-        private IEventAggregator _events;
+        private readonly IEventAggregator _events;
 
+        //Logging in the Pithos client is provided by log4net
+        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
         private PithosSettings _settings;
         public PithosSettings Settings
@@ -46,8 +89,8 @@ namespace Pithos.Client.WPF
             }
         }
 
-        private ObservableConcurrentCollection<AccountSettings> _accounts;
-        public ObservableConcurrentCollection<AccountSettings> Accounts
+        private ObservableConcurrentCollection<AccountViewModel> _accounts;
+        public ObservableConcurrentCollection<AccountViewModel> Accounts
         {
             get { return _accounts; }
             set 
@@ -59,33 +102,32 @@ namespace Pithos.Client.WPF
         
         public bool StartOnSystemStartup { get; set; }
 
-        private static void CreateShortcut(string shortcutPath)
-        {
-            var wshShell = new WshShellClass();
-            var shortcut = (IWshRuntimeLibrary.IWshShortcut) wshShell.CreateShortcut(
-                shortcutPath);
-
-            var exePath = Assembly.GetExecutingAssembly().Location;
-            shortcut.TargetPath = exePath;
-            shortcut.WorkingDirectory = Path.GetDirectoryName(exePath);
-            shortcut.Description = "Pithos";            
-            shortcut.Save();
-        }
-
         public ShellViewModel Shell { get;  set; }
         //ShellExtensionController _extensionController=new ShellExtensionController();
 
-        public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings)
+        public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings, string currentTab)
         {
+            // ReSharper disable DoNotCallOverridableMethodsInConstructor
+            //Caliburn.Micro uses DisplayName for the view's title
+            DisplayName = "Pithos+ Preferences";
+            // ReSharper restore DoNotCallOverridableMethodsInConstructor
+
             _windowManager = windowManager;
             _events = events;
 
-            DisplayName = "Pithos Preferences";
             Shell = shell;
-
+            
             Settings=settings;
-            Accounts = new ObservableConcurrentCollection<AccountSettings>();
-            Accounts.AddFromEnumerable(settings.Accounts);
+            Accounts = new ObservableConcurrentCollection<AccountViewModel>();
+            if (settings.Accounts == null)
+            {
+                settings.Accounts=new AccountsCollection();
+                settings.Save();
+            }
+            var accountVMs = from account in settings.Accounts
+                             select new AccountViewModel(account);
+
+            Accounts.AddFromEnumerable(accountVMs);
             
             var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
             _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");
@@ -93,9 +135,26 @@ namespace Pithos.Client.WPF
 
             StartOnSystemStartup = File.Exists(_shortcutPath);
 
+            SelectedTab = currentTab;
+        }
+
+        private string _selectedTab="General";
+        public string SelectedTab
+        {
+            get { return _selectedTab; }
+            set
+            {
+                _selectedTab = value??"General";
+                NotifyOfPropertyChange(()=>SelectedTab);
+                NotifyOfPropertyChange(() => AccountTabSelected);
+            }
         }
 
 
+        public bool AccountTabSelected
+        {
+            get { return _selectedTab == "AccountTab"; }
+        }
         #region Preferences Properties
 
         private bool _noProxy;
@@ -136,6 +195,18 @@ namespace Pithos.Client.WPF
         }
         #endregion
 
+
+        public int StartupDelay
+        {
+            get { return (int) Settings.StartupDelay.TotalMinutes; }
+            set
+            {
+                if (value<0)
+                    throw new ArgumentOutOfRangeException("value",Resources.PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);
+                Settings.StartupDelay = TimeSpan.FromMinutes(value);
+                NotifyOfPropertyChange(()=>StartupDelay);
+            }
+        }
        
         #region Commands
         
@@ -147,15 +218,65 @@ namespace Pithos.Client.WPF
         public void SelectiveSyncFolders()
         {
             var monitor = Shell.Monitors[CurrentAccount.AccountName];
-            var folders=monitor.GetRootFolders();
+            
 
-            var model = new SelectiveSynchViewModel(folders,_events,CurrentAccount);
+            var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount.Account);
             if (_windowManager.ShowDialog(model) == true)
             {
                 
             }
         }
+
+        public void RefreshApiKey()
+        {
+            //_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 });
+            if (CurrentAccount == null)
+                return;
+            try
+            {
+
+                var name = CurrentAccount.AccountName;
+
+                var loginUri = new Uri(new Uri(CurrentAccount.ServerUrl), "login");
+                var credentials = PithosAccount.RetrieveCredentials(loginUri.ToString(),name);
+                if (credentials==null)
+                    return;
+                //The server will return credentials for a different account, not just the current account
+                //We need to find the correct account first
+                var account = Accounts.First(act => act.AccountName == credentials.UserName && act.ServerUrl == ?? );
+                account.ApiKey = credentials.Password;                
+                account.IsExpired = false;
+                Settings.Save();
+                TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));
+                NotifyOfPropertyChange(() => Accounts);
+            }
+            catch (AggregateException exc)
+            {
+                string message = String.Format("API Key retrieval failed");
+                Log.Error(message, exc.InnerException);
+                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
+            }
+            catch (Exception exc)
+            {
+                string message = String.Format("API Key retrieval failed");
+                Log.Error(message, exc);
+                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
+            }
+
+        }
+
     
+        public void OpenLogPath()
+        {
+            Shell.OpenLogPath();
+        }
+
+        public void OpenLogConsole()
+        {
+            var logView=IoC.Get<LogConsole.LogConsoleViewModel>();            
+            _windowManager.ShowWindow(logView);
+        }
+
         public void SaveChanges()
         {
             DoSave();
@@ -175,29 +296,42 @@ namespace Pithos.Client.WPF
 
         private void DoSave()
         {
-            Settings.Save();
-            SetStartupMode();
+            //SetStartupMode();            
 
+            //Ensure we save the settings changes first
+            foreach (var account in _accountsToRemove)
+            {
+                Settings.Accounts.Remove(account);
+            }
 
-            foreach (var account in Settings.Accounts)
-            {                                
-                Shell.MonitorAccount(account);
+            foreach (var account in _accountsToAdd)
+            {
+                Settings.Accounts.Add(account);    
             }
 
-            NotifyOfPropertyChange(()=>Settings);
-        }
+            Settings.Save();
 
-        private void SetStartupMode()
-        {
-            if (StartOnSystemStartup && !File.Exists(_shortcutPath))
+
+            try
             {
-                CreateShortcut(_shortcutPath);
-            }
-            else if (!StartOnSystemStartup && File.Exists(_shortcutPath))
+                foreach (var account in _accountsToRemove)
+                {
+                    Shell.RemoveMonitor(account.AccountName);
+                    Shell.RemoveAccountFromDatabase(account);
+                }
+
+                foreach (var account in Settings.Accounts)
+                {
+                    Shell.MonitorAccount(account);
+                }
+            }                
+            finally
             {
-                if (File.Exists(_shortcutPath))
-                    File.Delete(_shortcutPath);
+                _accountsToRemove.Clear();
+                _accountsToAdd.Clear();
             }
+
+            NotifyOfPropertyChange(()=>Settings);
         }
 
      /*   public void ChangePithosFolder()
@@ -224,22 +358,41 @@ namespace Pithos.Client.WPF
             }
         }
 */
+
+
+        readonly List<AccountSettings> _accountsToAdd=new List<AccountSettings>();
        public void AddAccount()
        {
            var wizard = new AddAccountViewModel();
            if (_windowManager.ShowDialog(wizard) == true)
            {
+               string selectedPath = wizard.AccountPath;
+               var initialRootPath = wizard.ShouldCreateOkeanosFolder?
+                   Path.Combine(selectedPath, "Okeanos")
+                   :selectedPath;
+               var actualRootPath= initialRootPath;
+               if (wizard.ShouldCreateOkeanosFolder)
+               {
+                   int attempt = 1;
+                   while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))
+                   {
+                       actualRootPath = String.Format("{0} {1}", initialRootPath, attempt++);
+                   }
+               }
+               ### Check that the account does not already exist
+
                var newAccount = new AccountSettings
                                     {
                                         AccountName = wizard.AccountName,
+                                        ServerUrl=wizard.CurrentServer,
                                         ApiKey=wizard.Token,
-                                        RootPath=wizard.AccountPath,
-                                        IsActive=wizard.IsAccountActive,
-                                        UsePithos=true
+                                        RootPath = actualRootPath,
+                                        IsActive=wizard.IsAccountActive
                                     };
-               Settings.Accounts.Add(newAccount);
-               (Accounts as IProducerConsumerCollection<AccountSettings>).TryAdd(newAccount);
-               CurrentAccount = newAccount;
+               _accountsToAdd.Add(newAccount);
+               var accountVm = new AccountViewModel(newAccount);
+               (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);
+               CurrentAccount = accountVm;
                NotifyOfPropertyChange(() => Accounts);
                NotifyOfPropertyChange(() => Settings);   
            }
@@ -248,44 +401,45 @@ namespace Pithos.Client.WPF
             
        }
 
-        public async void AddPithosAccount()
+/*
+        public void AddPithosAccount()
        {
-            var credentials=await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
+            var credentials=PithosAccount.RetrieveCredentials(null);
+            if (credentials == null)
+                return;
             var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
+            var accountVM = new AccountViewModel(account);
             if (account == null)
             {
                 account=new AccountSettings{
                     AccountName=credentials.UserName,
-                    ApiKey=credentials.Password,
-                    UsePithos=true
+                    ApiKey=credentials.Password
                 };
                 Settings.Accounts.Add(account);
-                (Accounts as IProducerConsumerCollection<AccountSettings>).TryAdd(account);
+                accountVM = new AccountViewModel(account);
+                (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
             }
             else
             {
                 account.ApiKey=credentials.Password;
             }
             //SelectedAccountIndex= Settings.Accounts.IndexOf(account);
-            CurrentAccount = account;
+            CurrentAccount = accountVM;
             NotifyOfPropertyChange(() => Accounts);
             NotifyOfPropertyChange(()=>Settings);                       
        }
+*/
+
 
+        readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();
         public void RemoveAccount()
         {
-            var accountName = CurrentAccount.AccountName;
-            Settings.Accounts.Remove(CurrentAccount);
-
             Accounts.TryRemove(CurrentAccount);
-            
-            
+            _accountsToRemove.Add(CurrentAccount.Account);
+
             CurrentAccount = null;
-            //Accounts = Settings.Accounts;
-            //Settings.Save();            
-            Shell.RemoveMonitor(accountName);
             NotifyOfPropertyChange(() => Accounts);
-            NotifyOfPropertyChange(() => Settings);                       
+
             
             //NotifyOfPropertyChange("Settings.Accounts");
         }
@@ -319,6 +473,14 @@ namespace Pithos.Client.WPF
             }
         }
 
+        public bool DebugLoggingEnabled
+        {
+            get { return Settings.DebugLoggingEnabled; }
+            set { 
+                Settings.DebugLoggingEnabled = value;
+                NotifyOfPropertyChange(()=>DebugLoggingEnabled);
+            }
+        }
        
         #endregion
 
@@ -342,13 +504,13 @@ namespace Pithos.Client.WPF
             }
         }*/
 
-        private AccountSettings _currentAccount;
-        private IWindowManager _windowManager;
-        private string _shortcutPath;
+        private AccountViewModel _currentAccount;
+        private readonly IWindowManager _windowManager;
+        private readonly string _shortcutPath;
 
 
         
-        public AccountSettings CurrentAccount
+        public AccountViewModel CurrentAccount
         {
             get { return _currentAccount; }
             set
@@ -416,11 +578,11 @@ namespace Pithos.Client.WPF
                                                                             SearchOption.AllDirectories))
                         File.Copy(newFilePath, newFilePath.Replace(oldPath, newPath));
 
+                    Log.InfoFormat("Deleting account folder {0}",oldPath);
                     Directory.Delete(oldPath, true);
 
                     //We also need to change the path of the existing file states
-                    if (monitor != null)
-                        monitor.MoveFileStates(oldPath, newPath);
+                    monitor.MoveFileStates(oldPath, newPath);
                 }
             }
             //Replace the old rootpath with the new
@@ -435,7 +597,7 @@ namespace Pithos.Client.WPF
                     monitor.Start();
             }
             else
-                Shell.MonitorAccount(CurrentAccount);
+                Shell.MonitorAccount(CurrentAccount.Account);
             //Finally, notify that the Settings, CurrentAccount have changed
             NotifyOfPropertyChange(() => CurrentAccount);
             NotifyOfPropertyChange(() => Settings);