X-Git-Url: https://code.grnet.gr/git/pithos-ms-client/blobdiff_plain/6aa29f4fca0f3d139c45c0392148f4d3a1bd8607..84a3db1b645b989f2c512b66ab8097deb7316b5a:/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs diff --git a/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs index 1a9602f..2857dc8 100644 --- a/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs +++ b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs @@ -1,39 +1,82 @@ -// ----------------------------------------------------------------------- -// -// TODO: Update copyright text. -// -// ----------------------------------------------------------------------- +#region +/* ----------------------------------------------------------------------- + * + * + * 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. + * + * ----------------------------------------------------------------------- + */ +#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; - /// - /// TODO: Update summary. + /// The preferences screen displays user and account settings and updates the PithosMonitor + /// classes when account settings change. /// + /// + /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate + /// ViewModels, one for each tab. + /// [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 _accounts; - public ObservableConcurrentCollection Accounts + private ObservableConcurrentCollection _accounts; + public ObservableConcurrentCollection 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(); - Accounts.AddFromEnumerable(settings.Accounts); + Accounts = new ObservableConcurrentCollection(); + 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(); + _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 _accountsToAdd=new List(); 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).TryAdd(newAccount); - CurrentAccount = newAccount; + _accountsToAdd.Add(newAccount); + var accountVm = new AccountViewModel(newAccount); + (Accounts as IProducerConsumerCollection).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).TryAdd(account); + accountVM = new AccountViewModel(account); + (Accounts as IProducerConsumerCollection).TryAdd(accountVM); } else { account.ApiKey=credentials.Password; } //SelectedAccountIndex= Settings.Accounts.IndexOf(account); - CurrentAccount = account; + CurrentAccount = accountVM; NotifyOfPropertyChange(() => Accounts); NotifyOfPropertyChange(()=>Settings); } +*/ + + readonly List _accountsToRemove = new List(); 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);