From: Panagiotis Kanavos Date: Wed, 2 May 2012 13:08:51 +0000 (+0300) Subject: Modified to allow initial selection of all folders and containers X-Git-Url: https://code.grnet.gr/git/pithos-ms-client/commitdiff_plain/d31e609c8f704200ed495aec3bdf5e0cb3557c00?hp=7d855abd516b3881a486b5cc175aeeab06cd0162 Modified to allow initial selection of all folders and containers --- diff --git a/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs index 3970428..2b5f249 100644 --- a/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs +++ b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs @@ -1,699 +1,708 @@ -#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.Collections.Specialized; -using System.ComponentModel.Composition; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Forms; -using Caliburn.Micro; -using Pithos.Client.WPF.Configuration; -using Pithos.Client.WPF.Properties; -using Pithos.Client.WPF.SelectiveSynch; -using Pithos.Client.WPF.Utils; -using Pithos.Core; -using Pithos.Interfaces; -using System; -using System.Linq; -using Pithos.Network; -using MessageBox = System.Windows.MessageBox; -using Screen = Caliburn.Micro.Screen; - -namespace Pithos.Client.WPF.Preferences -{ - /// - /// 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, PartCreationPolicy(CreationPolicy.Shared)] - public class PreferencesViewModel : Screen - { - 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 - { - get { return _settings; } - set - { - _settings = value; - NotifyOfPropertyChange(()=>Settings); - } - } - - private ObservableConcurrentCollection _accounts; - public ObservableConcurrentCollection Accounts - { - get { return _accounts; } - set - { - _accounts = value; - NotifyOfPropertyChange(()=>Accounts); - } - } - - public bool StartOnSystemStartup { get; set; } - - public ShellViewModel Shell { get; set; } - //ShellExtensionController _extensionController=new ShellExtensionController(); - - 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; - - Shell = shell; - - Settings=settings; - 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"); - - - 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; - public bool NoProxy - { - get { return _noProxy; } - set - { - _noProxy = value; - NotifyOfPropertyChange(()=>NoProxy); - } - } - - - private bool _defaultProxy; - - public bool DefaultProxy - { - get { return _defaultProxy; } - set - { - _defaultProxy = value; - NotifyOfPropertyChange(() => DefaultProxy); - } - } - - - private bool _manualProxy; - - public bool ManualProxy - { - get { return _manualProxy; } - set - { - _manualProxy = value; - NotifyOfPropertyChange(() => ManualProxy); - } - } - #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 - - public bool CanSelectiveSyncFolders - { - get { return CurrentAccount != null; } - } - - public void SelectiveSyncFolders() - { - //var monitor = Shell.Monitors[CurrentAccount.AccountKey]; - - - var model = new SelectiveSynchViewModel(/*monitor,*/_events,CurrentAccount.Account,CurrentAccount.ApiKey); - if (_windowManager.ShowDialog(model) == true) - { - - } - } - - /* private bool _networkTracing; - public bool NetworkTracing - { - get { return _networkTracing; } - set - { - _networkTracing = value; - - } - }*/ - - 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 == CurrentAccount.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(); - TryClose(true); - } - - public void RejectChanges() - { - Settings.Reload(); - TryClose(false); - } - - public void ApplyChanges() - { - DoSave(); - } - - private void DoSave() - { - //SetStartupMode(); - - //Ensure we save the settings changes first - foreach (var account in _accountsToRemove) - { - Settings.Accounts.Remove(account); - } - - foreach (var account in _accountsToAdd) - { - Settings.Accounts.Add(account); - } - - Settings.Save(); - - - try - { - foreach (var account in _accountsToRemove) - { - Shell.RemoveMonitor(account.ServerUrl, account.AccountName); - Shell.RemoveAccountFromDatabase(account); - } - - foreach (var account in Settings.Accounts) - { - Shell.MonitorAccount(account); - } - } - finally - { - _accountsToRemove.Clear(); - _accountsToAdd.Clear(); - } - - NotifyOfPropertyChange(()=>Settings); - - if (IgnoreCertificateErrors) - ServicePointManager.ServerCertificateValidationCallback= (sender,certificate,chain,errors)=> true; - else - { - ServicePointManager.ServerCertificateValidationCallback = null; - } - } - - /* public void ChangePithosFolder() - { - var browser = new FolderBrowserDialog(); - browser.SelectedPath = Settings.PithosPath; - var result = browser.ShowDialog((IWin32Window)GetView()); - if (result == DialogResult.OK) - { - var newPath = browser.SelectedPath; - var accountName = CurrentAccount.AccountName; - var monitor = Shell.Monitors[accountName]; - monitor.Stop(); - - Shell.Monitors.Remove(accountName); - - Directory.Move(Settings.PithosPath, newPath); - Settings.PithosPath = newPath; - Settings.Save(); - - Shell.MonitorAccount(CurrentAccount); - - NotifyOfPropertyChange(() => Settings); - } - } -*/ - - - 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++); - } - } - - - - var account = Accounts.FirstOrDefault(act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer); - if (account != null) - { - if (MessageBox.Show("The account you specified already exists. Do you want to update it?", "The account exists") == MessageBoxResult.Yes) - { - account.ApiKey = wizard.Token; - account.IsExpired = false; - CurrentAccount = account; - } - } - else - { - var newAccount = new AccountSettings - { - AccountName = wizard.AccountName, - ServerUrl = wizard.CurrentServer, - ApiKey = wizard.Token, - RootPath = actualRootPath, - IsActive = wizard.IsAccountActive, - }; - - - var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey) - { - AuthenticationUrl = newAccount.ServerUrl, UsePithos = true - }; - client.Authenticate(); - - - var dirs = (from container in client.ListContainers(newAccount.AccountName) - from dir in client.ListObjects(newAccount.AccountName, container.Name) - where container.Name != "trash" - select dir) - .ToTree() - .Select(d=>d.Uri.ToString()) - .ToArray(); - - newAccount.SelectiveFolders.AddRange(dirs); - - //TODO:Add the "pithos" container as a default selection - - _accountsToAdd.Add(newAccount); - var accountVm = new AccountViewModel(newAccount); - (Accounts as IProducerConsumerCollection).TryAdd(accountVm); - CurrentAccount = accountVm; - } - NotifyOfPropertyChange(() => Accounts); - NotifyOfPropertyChange(() => Settings); - } - - - - } - -/* - public void AddPithosAccount() - { - 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 - }; - Settings.Accounts.Add(account); - accountVM = new AccountViewModel(account); - (Accounts as IProducerConsumerCollection).TryAdd(accountVM); - } - else - { - account.ApiKey=credentials.Password; - } - //SelectedAccountIndex= Settings.Accounts.IndexOf(account); - CurrentAccount = accountVM; - NotifyOfPropertyChange(() => Accounts); - NotifyOfPropertyChange(()=>Settings); - } -*/ - - - readonly List _accountsToRemove = new List(); - public void RemoveAccount() - { - Accounts.TryRemove(CurrentAccount); - _accountsToRemove.Add(CurrentAccount.Account); - - CurrentAccount = null; - NotifyOfPropertyChange(() => Accounts); - - - //NotifyOfPropertyChange("Settings.Accounts"); - } - - public bool CanRemoveAccount - { - get { return (CurrentAccount != null); } - } - - public bool CanClearAccountCache - { - get { return (CurrentAccount != null); } - } - - public void ClearAccountCache() - { - if (MessageBoxResult.Yes == MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" + - " You will have to download all partially downloaded data again\n" + - "This change can not be undone\n\n" + - "Do you wish to delete all partially downloaded data?", "Warning! Clearing account cache", - MessageBoxButton.YesNo,MessageBoxImage.Question,MessageBoxResult.No)) - { - - var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder); - var dir = new DirectoryInfo(cachePath); - //The file may not exist if we just created the account - if (!dir.Exists) - return; - dir.EnumerateFiles().Apply(file=>file.Delete()); - dir.EnumerateDirectories().Apply(folder => folder.Delete(true)); - } - } - - - public bool ExtensionsActivated - { - get { return Settings.ExtensionsActivated; } - set - { - if (Settings.ExtensionsActivated == value) - return; - - Settings.ExtensionsActivated = value; - -/* - if (value) - _extensionController.RegisterExtensions(); - else - { - _extensionController.UnregisterExtensions(); - } -*/ - NotifyOfPropertyChange(() => ExtensionsActivated); - } - } - - public bool DebugLoggingEnabled - { - get { return Settings.DebugLoggingEnabled; } - set { - Settings.DebugLoggingEnabled = value; - NotifyOfPropertyChange(()=>DebugLoggingEnabled); - } - } - - public bool IgnoreCertificateErrors - { - get { return Settings.IgnoreCertificateErrors; } - set { - Settings.IgnoreCertificateErrors = value; - NotifyOfPropertyChange(() => IgnoreCertificateErrors); - } - } - - #endregion - - /* private int _selectedAccountIndex; - public int SelectedAccountIndex - { - get { return _selectedAccountIndex; } - set - { - //var accountCount=Settings.Accounts.Count; - //if (accountCount == 0) - // return; - //if (0 <= value && value < accountCount) - // _selectedAccountIndex = value; - //else - // _selectedAccountIndex = 0; - _selectedAccountIndex = value; - NotifyOfPropertyChange(() => CurrentAccount); - NotifyOfPropertyChange(() => CanRemoveAccount); - NotifyOfPropertyChange(()=>SelectedAccountIndex); - } - }*/ - - private AccountViewModel _currentAccount; - private readonly IWindowManager _windowManager; - private readonly string _shortcutPath; - - - - public AccountViewModel CurrentAccount - { - get { return _currentAccount; } - set - { - _currentAccount = value; - NotifyOfPropertyChange(()=>CurrentAccount); - NotifyOfPropertyChange(() => CanRemoveAccount); - NotifyOfPropertyChange(() => CanSelectiveSyncFolders); - NotifyOfPropertyChange(() => CanMoveAccountFolder); - NotifyOfPropertyChange(() => CanClearAccountCache); - } - } - -/* - public AccountSettings CurrentAccount - { - get { - if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count) - return Settings.Accounts[SelectedAccountIndex]; - return null; - } - - } -*/ - - - public bool CanMoveAccountFolder - { - get { return CurrentAccount != null; } - } - - public void MoveAccountFolder() - { - - using (var dlg = new FolderBrowserDialog()) - { - var currentFolder = CurrentAccount.RootPath; - dlg.SelectedPath = currentFolder; - //Ask the user to select a folder - //Note: We need a parent window here, which we retrieve with GetView - var view = (Window)GetView(); - if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view))) - return; - - var newPath= dlg.SelectedPath; - //Find the account's monitor and stop it - PithosMonitor monitor; - if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor)) - { - monitor.Stop(); - - - var oldPath = monitor.RootPath; - //The old directory may not exist eg. if we create an account for the first time - if (Directory.Exists(oldPath)) - { - //If it does, do the move - - //Now Create all of the directories - foreach (string dirPath in Directory.EnumerateDirectories(oldPath, "*", - SearchOption.AllDirectories)) - Directory.CreateDirectory(dirPath.Replace(oldPath, newPath)); - - //Copy all the files - foreach (string newFilePath in Directory.EnumerateFiles(oldPath, "*.*", - 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 - monitor.MoveFileStates(oldPath, newPath); - } - } - //Replace the old rootpath with the new - CurrentAccount.RootPath = newPath; - //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date - Settings.Save(); - //And start the monitor on the new RootPath - if (monitor != null) - { - monitor.RootPath = newPath; - if (CurrentAccount.IsActive) - monitor.Start(); - } - else - Shell.MonitorAccount(CurrentAccount.Account); - //Finally, notify that the Settings, CurrentAccount have changed - NotifyOfPropertyChange(() => CurrentAccount); - NotifyOfPropertyChange(() => Settings); - - } - } - } -} +#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.Collections.Specialized; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Forms; +using Caliburn.Micro; +using Pithos.Client.WPF.Configuration; +using Pithos.Client.WPF.Properties; +using Pithos.Client.WPF.SelectiveSynch; +using Pithos.Client.WPF.Utils; +using Pithos.Core; +using Pithos.Interfaces; +using System; +using System.Linq; +using Pithos.Network; +using MessageBox = System.Windows.MessageBox; +using Screen = Caliburn.Micro.Screen; + +namespace Pithos.Client.WPF.Preferences +{ + /// + /// 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, PartCreationPolicy(CreationPolicy.Shared)] + public class PreferencesViewModel : Screen + { + 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 + { + get { return _settings; } + set + { + _settings = value; + NotifyOfPropertyChange(()=>Settings); + } + } + + private ObservableConcurrentCollection _accounts; + public ObservableConcurrentCollection Accounts + { + get { return _accounts; } + set + { + _accounts = value; + NotifyOfPropertyChange(()=>Accounts); + } + } + + public bool StartOnSystemStartup { get; set; } + + public ShellViewModel Shell { get; set; } + //ShellExtensionController _extensionController=new ShellExtensionController(); + + 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; + + Shell = shell; + + Settings=settings; + 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"); + + + 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; + public bool NoProxy + { + get { return _noProxy; } + set + { + _noProxy = value; + NotifyOfPropertyChange(()=>NoProxy); + } + } + + + private bool _defaultProxy; + + public bool DefaultProxy + { + get { return _defaultProxy; } + set + { + _defaultProxy = value; + NotifyOfPropertyChange(() => DefaultProxy); + } + } + + + private bool _manualProxy; + + public bool ManualProxy + { + get { return _manualProxy; } + set + { + _manualProxy = value; + NotifyOfPropertyChange(() => ManualProxy); + } + } + #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 + + public bool CanSelectiveSyncFolders + { + get { return CurrentAccount != null; } + } + + public void SelectiveSyncFolders() + { + //var monitor = Shell.Monitors[CurrentAccount.AccountKey]; + + + var model = new SelectiveSynchViewModel(/*monitor,*/_events,CurrentAccount.Account,CurrentAccount.ApiKey); + if (_windowManager.ShowDialog(model) == true) + { + + } + } + + /* private bool _networkTracing; + public bool NetworkTracing + { + get { return _networkTracing; } + set + { + _networkTracing = value; + + } + }*/ + + 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 == CurrentAccount.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(); + TryClose(true); + } + + public void RejectChanges() + { + Settings.Reload(); + TryClose(false); + } + + public void ApplyChanges() + { + DoSave(); + } + + private void DoSave() + { + //SetStartupMode(); + + //Ensure we save the settings changes first + foreach (var account in _accountsToRemove) + { + Settings.Accounts.Remove(account); + } + + foreach (var account in _accountsToAdd) + { + Settings.Accounts.Add(account); + } + + Settings.Save(); + + + try + { + foreach (var account in _accountsToRemove) + { + Shell.RemoveMonitor(account.ServerUrl, account.AccountName); + Shell.RemoveAccountFromDatabase(account); + } + + foreach (var account in Settings.Accounts) + { + Shell.MonitorAccount(account); + } + } + finally + { + _accountsToRemove.Clear(); + _accountsToAdd.Clear(); + } + + NotifyOfPropertyChange(()=>Settings); + + if (IgnoreCertificateErrors) + ServicePointManager.ServerCertificateValidationCallback= (sender,certificate,chain,errors)=> true; + else + { + ServicePointManager.ServerCertificateValidationCallback = null; + } + } + + /* public void ChangePithosFolder() + { + var browser = new FolderBrowserDialog(); + browser.SelectedPath = Settings.PithosPath; + var result = browser.ShowDialog((IWin32Window)GetView()); + if (result == DialogResult.OK) + { + var newPath = browser.SelectedPath; + var accountName = CurrentAccount.AccountName; + var monitor = Shell.Monitors[accountName]; + monitor.Stop(); + + Shell.Monitors.Remove(accountName); + + Directory.Move(Settings.PithosPath, newPath); + Settings.PithosPath = newPath; + Settings.Save(); + + Shell.MonitorAccount(CurrentAccount); + + NotifyOfPropertyChange(() => Settings); + } + } +*/ + + + 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++); + } + } + + + + var account = Accounts.FirstOrDefault(act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer); + if (account != null) + { + if (MessageBox.Show("The account you specified already exists. Do you want to update it?", "The account exists") == MessageBoxResult.Yes) + { + account.ApiKey = wizard.Token; + account.IsExpired = false; + CurrentAccount = account; + } + } + else + { + var newAccount = new AccountSettings + { + AccountName = wizard.AccountName, + ServerUrl = wizard.CurrentServer, + ApiKey = wizard.Token, + RootPath = actualRootPath, + IsActive = wizard.IsAccountActive, + }; + + + var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey) + { + AuthenticationUrl = newAccount.ServerUrl, UsePithos = true + }; + client.Authenticate(); + + + var containers = client.ListContainers(newAccount.AccountName); + var containerUris = from container in containers + select String.Format(@"{0}/v1/{1}/{2}", + newAccount.ServerUrl, newAccount.AccountName, container.Name); + + newAccount.SelectiveFolders.AddRange(containerUris.ToArray()); + + var objectInfos = (from container in containers + from dir in client.ListObjects(newAccount.AccountName, container.Name) + where container.Name != "trash" + select dir).ToList(); + var tree = objectInfos.ToTree(); + + var selected = (from root in tree + from child in root + select child.Uri.ToString()).ToArray(); + newAccount.SelectiveFolders.AddRange(selected); + + + //TODO:Add the "pithos" container as a default selection + + _accountsToAdd.Add(newAccount); + var accountVm = new AccountViewModel(newAccount); + (Accounts as IProducerConsumerCollection).TryAdd(accountVm); + CurrentAccount = accountVm; + } + NotifyOfPropertyChange(() => Accounts); + NotifyOfPropertyChange(() => Settings); + } + + + + } + +/* + public void AddPithosAccount() + { + 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 + }; + Settings.Accounts.Add(account); + accountVM = new AccountViewModel(account); + (Accounts as IProducerConsumerCollection).TryAdd(accountVM); + } + else + { + account.ApiKey=credentials.Password; + } + //SelectedAccountIndex= Settings.Accounts.IndexOf(account); + CurrentAccount = accountVM; + NotifyOfPropertyChange(() => Accounts); + NotifyOfPropertyChange(()=>Settings); + } +*/ + + + readonly List _accountsToRemove = new List(); + public void RemoveAccount() + { + Accounts.TryRemove(CurrentAccount); + _accountsToRemove.Add(CurrentAccount.Account); + + CurrentAccount = null; + NotifyOfPropertyChange(() => Accounts); + + + //NotifyOfPropertyChange("Settings.Accounts"); + } + + public bool CanRemoveAccount + { + get { return (CurrentAccount != null); } + } + + public bool CanClearAccountCache + { + get { return (CurrentAccount != null); } + } + + public void ClearAccountCache() + { + if (MessageBoxResult.Yes == MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" + + " You will have to download all partially downloaded data again\n" + + "This change can not be undone\n\n" + + "Do you wish to delete all partially downloaded data?", "Warning! Clearing account cache", + MessageBoxButton.YesNo,MessageBoxImage.Question,MessageBoxResult.No)) + { + + var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder); + var dir = new DirectoryInfo(cachePath); + //The file may not exist if we just created the account + if (!dir.Exists) + return; + dir.EnumerateFiles().Apply(file=>file.Delete()); + dir.EnumerateDirectories().Apply(folder => folder.Delete(true)); + } + } + + + public bool ExtensionsActivated + { + get { return Settings.ExtensionsActivated; } + set + { + if (Settings.ExtensionsActivated == value) + return; + + Settings.ExtensionsActivated = value; + +/* + if (value) + _extensionController.RegisterExtensions(); + else + { + _extensionController.UnregisterExtensions(); + } +*/ + NotifyOfPropertyChange(() => ExtensionsActivated); + } + } + + public bool DebugLoggingEnabled + { + get { return Settings.DebugLoggingEnabled; } + set { + Settings.DebugLoggingEnabled = value; + NotifyOfPropertyChange(()=>DebugLoggingEnabled); + } + } + + public bool IgnoreCertificateErrors + { + get { return Settings.IgnoreCertificateErrors; } + set { + Settings.IgnoreCertificateErrors = value; + NotifyOfPropertyChange(() => IgnoreCertificateErrors); + } + } + + #endregion + + /* private int _selectedAccountIndex; + public int SelectedAccountIndex + { + get { return _selectedAccountIndex; } + set + { + //var accountCount=Settings.Accounts.Count; + //if (accountCount == 0) + // return; + //if (0 <= value && value < accountCount) + // _selectedAccountIndex = value; + //else + // _selectedAccountIndex = 0; + _selectedAccountIndex = value; + NotifyOfPropertyChange(() => CurrentAccount); + NotifyOfPropertyChange(() => CanRemoveAccount); + NotifyOfPropertyChange(()=>SelectedAccountIndex); + } + }*/ + + private AccountViewModel _currentAccount; + private readonly IWindowManager _windowManager; + private readonly string _shortcutPath; + + + + public AccountViewModel CurrentAccount + { + get { return _currentAccount; } + set + { + _currentAccount = value; + NotifyOfPropertyChange(()=>CurrentAccount); + NotifyOfPropertyChange(() => CanRemoveAccount); + NotifyOfPropertyChange(() => CanSelectiveSyncFolders); + NotifyOfPropertyChange(() => CanMoveAccountFolder); + NotifyOfPropertyChange(() => CanClearAccountCache); + } + } + +/* + public AccountSettings CurrentAccount + { + get { + if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count) + return Settings.Accounts[SelectedAccountIndex]; + return null; + } + + } +*/ + + + public bool CanMoveAccountFolder + { + get { return CurrentAccount != null; } + } + + public void MoveAccountFolder() + { + + using (var dlg = new FolderBrowserDialog()) + { + var currentFolder = CurrentAccount.RootPath; + dlg.SelectedPath = currentFolder; + //Ask the user to select a folder + //Note: We need a parent window here, which we retrieve with GetView + var view = (Window)GetView(); + if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view))) + return; + + var newPath= dlg.SelectedPath; + //Find the account's monitor and stop it + PithosMonitor monitor; + if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor)) + { + monitor.Stop(); + + + var oldPath = monitor.RootPath; + //The old directory may not exist eg. if we create an account for the first time + if (Directory.Exists(oldPath)) + { + //If it does, do the move + + //Now Create all of the directories + foreach (string dirPath in Directory.EnumerateDirectories(oldPath, "*", + SearchOption.AllDirectories)) + Directory.CreateDirectory(dirPath.Replace(oldPath, newPath)); + + //Copy all the files + foreach (string newFilePath in Directory.EnumerateFiles(oldPath, "*.*", + 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 + monitor.MoveFileStates(oldPath, newPath); + } + } + //Replace the old rootpath with the new + CurrentAccount.RootPath = newPath; + //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date + Settings.Save(); + //And start the monitor on the new RootPath + if (monitor != null) + { + monitor.RootPath = newPath; + if (CurrentAccount.IsActive) + monitor.Start(); + } + else + Shell.MonitorAccount(CurrentAccount.Account); + //Finally, notify that the Settings, CurrentAccount have changed + NotifyOfPropertyChange(() => CurrentAccount); + NotifyOfPropertyChange(() => Settings); + + } + } + } +} diff --git a/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs b/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs index 555aa92..8355103 100644 --- a/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs +++ b/trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs @@ -173,7 +173,11 @@ namespace Pithos.Client.WPF.SelectiveSynch public bool IsExplicitlyChecked { - set { _isChecked=value; } + set + { + _isChecked=value; + this.RaisePropertyChangedEventImmediately("IsChecked"); + } } public DirectoryRecord(ObjectInfo info) diff --git a/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs index 8d8583a..b332064 100644 --- a/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs +++ b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs @@ -1,248 +1,249 @@ -#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; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using Caliburn.Micro; -using Pithos.Client.WPF.Properties; -using Pithos.Client.WPF.Utils; -using Pithos.Core; -using Pithos.Interfaces; -using Pithos.Network; - -namespace Pithos.Client.WPF.SelectiveSynch -{ - class SelectiveSynchViewModel:Screen - { - private readonly IEventAggregator _events ; - - - public AccountSettings Account { get; set; } - - private readonly ObservableCollection _rootNodes=new ObservableCollection(); - public ObservableCollection RootNodes - { - get { return _rootNodes; } - } - - private ObservableCollection _checks; - //private readonly PithosMonitor _monitor; - private bool _isBusy=true; - private string _apiKey; - - public ObservableCollection Checks - { - get { return _checks; } - } - - public void GetChecks() - { - var root = RootNodes[0]; - _checks = new ObservableCollection( - from DirectoryRecord record in root - where record.IsChecked==true - select record.ObjectInfo); - NotifyOfPropertyChange(() => Checks); - } - - public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey) - { - Account = account; - AccountName = account.AccountName; - DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName); - //_monitor = monitor; - _events = events; - _apiKey = apiKey; - TaskEx.Run(LoadRootNode); - } - - private void LoadRootNode() - { - //TODO: Check this - var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true}; - client.Authenticate(); - - - var dirs = from container in client.ListContainers(AccountName) - where container.Name != "trash" - select new DirectoryRecord - { - DisplayName = container.Name, - Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)), - Directories = (from dir in client.ListObjects(AccountName, container.Name) - select dir).ToTree() - }; - var ownFolders = dirs.ToList(); - - var accountNodes=from account in client.ListSharingAccounts() - select new DirectoryRecord - { - DisplayName=account.name, - Uri=new Uri(client.StorageUrl,"../"+ account.name), - Directories=(from container in client.ListContainers(account.name) - select new DirectoryRecord - { - DisplayName=container.Name, - Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name), - Directories=(from folder in client.ListObjects(account.name,container.Name) - select folder).ToTree() - }).ToList() - }; - - var othersNode = new DirectoryRecord - { - DisplayName = "Shared to me", - Directories=accountNodes.ToList() - }; - - - var rootItem = new DirectoryRecord - { - DisplayName = AccountName , - Directories = ownFolders.ToList() - }; - - Execute.OnUIThread(() => - { - RootNodes.Add(rootItem); - RootNodes.Add(othersNode); - }); - - SetInitialSelections(Account); - - IsBusy = false; - } - - public bool IsBusy - { - get { - return _isBusy; - } - set { - _isBusy = value; - NotifyOfPropertyChange(()=>IsBusy); - } - } - - private void SetInitialSelections(AccountSettings account) - { - var selections = account.SelectiveFolders; - - - - //Initially, all nodes are checked - //We need to *uncheck* the nodes that are not selected - - var allNodes = (from DirectoryRecord rootRecord in RootNodes - from DirectoryRecord record in rootRecord - select record).ToList(); - - allNodes.Apply(record => record.IsChecked = false); - - if (selections.Count == 0) - { - // allNodes.Apply(record => record.IsChecked = false); - return; - } - - var selects = (from DirectoryRecord rootRecord in RootNodes - from DirectoryRecord record in rootRecord - where record.Uri !=null && selections.Contains(record.Uri.ToString()) - select record).ToList(); - //var shouldBeChecked = allNodes.Except(selects).ToList(); - - selects.Apply(record=>record.IsExplicitlyChecked=true); - - //shouldBeChecked.Apply(record => record.IsChecked = true); - - - - } - - protected string AccountName { get; set; } - - public void SaveChanges() - { - var uris = (from DirectoryRecord root in RootNodes - from DirectoryRecord record in root - where record.IsChecked == true && record.Uri != null - select record.Uri).ToArray(); - - SaveSettings(uris); - - //RootNodes is an ObservableCollection, it can't be enumerated iterativelly - - var added = (from DirectoryRecord root in RootNodes - from DirectoryRecord record in root - where record.Added && record.Uri != null - select record.Uri).ToArray(); - var removed = (from DirectoryRecord root in RootNodes - from DirectoryRecord record in root - where record.Removed && record.Uri != null - select record.Uri).ToArray(); - //TODO: Include Uris for the containers as well - _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed}); - - - - - TryClose(true); - } - - - private void SaveSettings(IEnumerable uris) - { - var selections = uris.Select(uri => uri.ToString()).ToArray(); - - Account.SelectiveFolders.Clear(); - Account.SelectiveFolders.AddRange(selections); - Settings.Default.Save(); - } - - public void RejectChanges() - { - TryClose(false); - } - } -} +#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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using Caliburn.Micro; +using Pithos.Client.WPF.Properties; +using Pithos.Client.WPF.Utils; +using Pithos.Core; +using Pithos.Interfaces; +using Pithos.Network; + +namespace Pithos.Client.WPF.SelectiveSynch +{ + class SelectiveSynchViewModel:Screen + { + private readonly IEventAggregator _events ; + + + public AccountSettings Account { get; set; } + + private readonly ObservableCollection _rootNodes=new ObservableCollection(); + public ObservableCollection RootNodes + { + get { return _rootNodes; } + } + + private ObservableCollection _checks; + //private readonly PithosMonitor _monitor; + private bool _isBusy=true; + private string _apiKey; + + public ObservableCollection Checks + { + get { return _checks; } + } + + public void GetChecks() + { + var root = RootNodes[0]; + _checks = new ObservableCollection( + from DirectoryRecord record in root + where record.IsChecked==true + select record.ObjectInfo); + NotifyOfPropertyChange(() => Checks); + } + + public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey) + { + Account = account; + AccountName = account.AccountName; + DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName); + //_monitor = monitor; + _events = events; + _apiKey = apiKey; + TaskEx.Run(LoadRootNode); + } + + private void LoadRootNode() + { + //TODO: Check this + var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true}; + client.Authenticate(); + + + var dirs = from container in client.ListContainers(AccountName) + where container.Name != "trash" + select new DirectoryRecord + { + DisplayName = container.Name, + Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)), + Directories = (from dir in client.ListObjects(AccountName, container.Name) + select dir).ToTree() + }; + var ownFolders = dirs.ToList(); + + var accountNodes=from account in client.ListSharingAccounts() + select new DirectoryRecord + { + DisplayName=account.name, + Uri=new Uri(client.StorageUrl,"../"+ account.name), + Directories=(from container in client.ListContainers(account.name) + select new DirectoryRecord + { + DisplayName=container.Name, + Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name), + Directories=(from folder in client.ListObjects(account.name,container.Name) + select folder).ToTree() + }).ToList() + }; + + var othersNode = new DirectoryRecord + { + DisplayName = "Shared to me", + Directories=accountNodes.ToList() + }; + + + var rootItem = new DirectoryRecord + { + DisplayName = AccountName , + Directories = ownFolders.ToList() + }; + + Execute.OnUIThread(() => + { + RootNodes.Add(rootItem); + RootNodes.Add(othersNode); + }); + + SetInitialSelections(Account); + + IsBusy = false; + } + + public bool IsBusy + { + get { + return _isBusy; + } + set { + _isBusy = value; + NotifyOfPropertyChange(()=>IsBusy); + } + } + + private void SetInitialSelections(AccountSettings account) + { + var selections = account.SelectiveFolders; + + + + //Initially, all nodes are checked + //We need to *uncheck* the nodes that are not selected + + var allNodes = (from DirectoryRecord rootRecord in RootNodes + from DirectoryRecord record in rootRecord + select record).ToList(); + //WARNING: Using IsChecked marks the item as REMOVED + allNodes.Apply(record => record.IsExplicitlyChecked = false); + + if (selections.Count == 0) + { + // allNodes.Apply(record => record.IsChecked = false); + return; + } + + var selects = (from DirectoryRecord rootRecord in RootNodes + from DirectoryRecord record in rootRecord + where record.Uri !=null && selections.Contains(record.Uri.ToString()) + select record).ToList(); + //var shouldBeChecked = allNodes.Except(selects).ToList(); + + //WARNING: Using IsChecked marks the item as ADDED + selects.Apply(record=>record.IsExplicitlyChecked=true); + + //shouldBeChecked.Apply(record => record.IsChecked = true); + + + + } + + protected string AccountName { get; set; } + + public void SaveChanges() + { + var uris = (from DirectoryRecord root in RootNodes + from DirectoryRecord record in root + where record.IsChecked == true && record.Uri != null + select record.Uri).ToArray(); + + SaveSettings(uris); + + //RootNodes is an ObservableCollection, it can't be enumerated iterativelly + + var added = (from DirectoryRecord root in RootNodes + from DirectoryRecord record in root + where record.Added && record.Uri != null + select record.Uri).ToArray(); + var removed = (from DirectoryRecord root in RootNodes + from DirectoryRecord record in root + where record.Removed && record.Uri != null + select record.Uri).ToArray(); + //TODO: Include Uris for the containers as well + _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed}); + + + + + TryClose(true); + } + + + private void SaveSettings(IEnumerable uris) + { + var selections = uris.Select(uri => uri.ToString()).ToArray(); + + Account.SelectiveFolders.Clear(); + Account.SelectiveFolders.AddRange(selections); + Settings.Default.Save(); + } + + public void RejectChanges() + { + TryClose(false); + } + } +}