Modified to allow initial selection of all folders and containers
authorPanagiotis Kanavos <pkanavos@gmail.com>
Wed, 2 May 2012 13:08:51 +0000 (16:08 +0300)
committerPanagiotis Kanavos <pkanavos@gmail.com>
Wed, 2 May 2012 13:08:51 +0000 (16:08 +0300)
trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
trunk/Pithos.Client.WPF/SelectiveSynch/DirectoryRecord.cs
trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs

index 3970428..2b5f249 100644 (file)
-#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.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
-{
-    /// <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, 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<AccountViewModel> _accounts;
-        public ObservableConcurrentCollection<AccountViewModel> 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<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");
-
-
-            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<LogConsole.LogConsoleViewModel>();            
-            _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<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++);
-                   }
-               }
-
-
-
-               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<AccountViewModel>).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<AccountViewModel>).TryAdd(accountVM);
-            }
-            else
-            {
-                account.ApiKey=credentials.Password;
-            }
-            //SelectedAccountIndex= Settings.Accounts.IndexOf(account);
-            CurrentAccount = accountVM;
-            NotifyOfPropertyChange(() => Accounts);
-            NotifyOfPropertyChange(()=>Settings);                       
-       }
-*/
-
-
-        readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();
-        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\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="PreferencesViewModel.cs" company="GRNet">\r
+ * \r
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ *   1. Redistributions of source code must retain the above\r
+ *      copyright notice, this list of conditions and the following\r
+ *      disclaimer.\r
+ *\r
+ *   2. Redistributions in binary form must reproduce the above\r
+ *      copyright notice, this list of conditions and the following\r
+ *      disclaimer in the documentation and/or other materials\r
+ *      provided with the distribution.\r
+ *\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * The views and conclusions contained in the software and\r
+ * documentation are those of the authors and should not be\r
+ * interpreted as representing official policies, either expressed\r
+ * or implied, of GRNET S.A.\r
+ * </copyright>\r
+ * -----------------------------------------------------------------------\r
+ */\r
+#endregion\r
+\r
+\r
+using System.Collections.Concurrent;\r
+using System.Collections.Generic;\r
+using System.Collections.Specialized;\r
+using System.ComponentModel.Composition;\r
+using System.Diagnostics;\r
+using System.IO;\r
+using System.Net;\r
+using System.Reflection;\r
+using System.Threading.Tasks;\r
+using System.Windows;\r
+using System.Windows.Forms;\r
+using Caliburn.Micro;\r
+using Pithos.Client.WPF.Configuration;\r
+using Pithos.Client.WPF.Properties;\r
+using Pithos.Client.WPF.SelectiveSynch;\r
+using Pithos.Client.WPF.Utils;\r
+using Pithos.Core;\r
+using Pithos.Interfaces;\r
+using System;\r
+using System.Linq;\r
+using Pithos.Network;\r
+using MessageBox = System.Windows.MessageBox;\r
+using Screen = Caliburn.Micro.Screen;\r
+\r
+namespace Pithos.Client.WPF.Preferences\r
+{\r
+    /// <summary>\r
+    /// The preferences screen displays user and account settings and updates the PithosMonitor\r
+    /// classes when account settings change.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate\r
+    /// ViewModels, one for each tab.\r
+    /// </remarks>\r
+    [Export, PartCreationPolicy(CreationPolicy.Shared)]\r
+    public class PreferencesViewModel : Screen\r
+    {\r
+        private readonly IEventAggregator _events;\r
+\r
+        //Logging in the Pithos client is provided by log4net\r
+        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
+\r
+        private PithosSettings _settings;\r
+        public PithosSettings Settings\r
+        {\r
+            get { return _settings; }\r
+            set\r
+            {\r
+                _settings = value;\r
+                NotifyOfPropertyChange(()=>Settings);\r
+            }\r
+        }\r
+\r
+        private ObservableConcurrentCollection<AccountViewModel> _accounts;\r
+        public ObservableConcurrentCollection<AccountViewModel> Accounts\r
+        {\r
+            get { return _accounts; }\r
+            set \r
+            { \r
+                _accounts = value;\r
+                NotifyOfPropertyChange(()=>Accounts);\r
+            }\r
+        }\r
+        \r
+        public bool StartOnSystemStartup { get; set; }\r
+\r
+        public ShellViewModel Shell { get;  set; }\r
+        //ShellExtensionController _extensionController=new ShellExtensionController();\r
+\r
+        public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings, string currentTab)\r
+        {\r
+            // ReSharper disable DoNotCallOverridableMethodsInConstructor\r
+            //Caliburn.Micro uses DisplayName for the view's title\r
+            DisplayName = "Pithos+ Preferences";\r
+            // ReSharper restore DoNotCallOverridableMethodsInConstructor\r
+\r
+            _windowManager = windowManager;\r
+            _events = events;\r
+\r
+            Shell = shell;\r
+            \r
+            Settings=settings;\r
+            Accounts = new ObservableConcurrentCollection<AccountViewModel>();\r
+            if (settings.Accounts == null)\r
+            {\r
+                settings.Accounts=new AccountsCollection();\r
+                settings.Save();\r
+            }\r
+            var accountVMs = from account in settings.Accounts\r
+                             select new AccountViewModel(account);\r
+\r
+            Accounts.AddFromEnumerable(accountVMs);\r
+            \r
+            var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);\r
+            _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");\r
+\r
+\r
+            StartOnSystemStartup = File.Exists(_shortcutPath);\r
+\r
+            SelectedTab = currentTab;\r
+        }\r
+\r
+        private string _selectedTab="General";\r
+        public string SelectedTab\r
+        {\r
+            get { return _selectedTab; }\r
+            set\r
+            {\r
+                _selectedTab = value??"General";\r
+                NotifyOfPropertyChange(()=>SelectedTab);\r
+                NotifyOfPropertyChange(() => AccountTabSelected);\r
+            }\r
+        }\r
+\r
+\r
+        public bool AccountTabSelected\r
+        {\r
+            get { return _selectedTab == "AccountTab"; }\r
+        }\r
+        #region Preferences Properties\r
+\r
+        private bool _noProxy;\r
+        public bool NoProxy\r
+        {\r
+            get { return _noProxy; }\r
+            set\r
+            {\r
+                _noProxy = value;\r
+                NotifyOfPropertyChange(()=>NoProxy);\r
+            }\r
+        }\r
+\r
+\r
+        private bool _defaultProxy;\r
+\r
+        public bool DefaultProxy\r
+        {\r
+            get { return _defaultProxy; }\r
+            set\r
+            {\r
+                _defaultProxy = value;\r
+                NotifyOfPropertyChange(() => DefaultProxy);\r
+            }\r
+        }\r
+\r
+\r
+        private bool _manualProxy;\r
+\r
+        public bool ManualProxy\r
+        {\r
+            get { return _manualProxy; }\r
+            set\r
+            {\r
+                _manualProxy = value;\r
+                NotifyOfPropertyChange(() => ManualProxy);\r
+            }\r
+        }\r
+        #endregion\r
+\r
+\r
+        public int StartupDelay\r
+        {\r
+            get { return (int) Settings.StartupDelay.TotalMinutes; }\r
+            set\r
+            {\r
+                if (value<0)\r
+                    throw new ArgumentOutOfRangeException("value",Resources.PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);\r
+                Settings.StartupDelay = TimeSpan.FromMinutes(value);\r
+                NotifyOfPropertyChange(()=>StartupDelay);\r
+            }\r
+        }\r
+       \r
+        #region Commands\r
+        \r
+        public bool CanSelectiveSyncFolders\r
+        {\r
+            get { return CurrentAccount != null; }\r
+        }\r
+\r
+        public void SelectiveSyncFolders()\r
+        {\r
+            //var monitor = Shell.Monitors[CurrentAccount.AccountKey];\r
+            \r
+\r
+            var model = new SelectiveSynchViewModel(/*monitor,*/_events,CurrentAccount.Account,CurrentAccount.ApiKey);\r
+            if (_windowManager.ShowDialog(model) == true)\r
+            {\r
+                \r
+            }\r
+        }\r
+\r
+       /* private bool _networkTracing;\r
+        public bool NetworkTracing\r
+        {\r
+            get { return _networkTracing; }\r
+            set\r
+            {\r
+                _networkTracing = value;\r
+                \r
+            }\r
+        }*/\r
+\r
+        public void RefreshApiKey()\r
+        {\r
+            //_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 });\r
+            if (CurrentAccount == null)\r
+                return;\r
+            try\r
+            {\r
+\r
+                var name = CurrentAccount.AccountName;\r
+\r
+                var loginUri = new Uri(new Uri(CurrentAccount.ServerUrl), "login");\r
+                var credentials = PithosAccount.RetrieveCredentials(loginUri.ToString(),name);\r
+                if (credentials==null)\r
+                    return;\r
+                //The server will return credentials for a different account, not just the current account\r
+                //We need to find the correct account first\r
+                var account = Accounts.First(act => act.AccountName == credentials.UserName && act.ServerUrl == CurrentAccount.ServerUrl);\r
+                account.ApiKey = credentials.Password;                \r
+                account.IsExpired = false;\r
+                Settings.Save();\r
+                TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));\r
+                NotifyOfPropertyChange(() => Accounts);\r
+            }\r
+            catch (AggregateException exc)\r
+            {\r
+                string message = String.Format("API Key retrieval failed");\r
+                Log.Error(message, exc.InnerException);\r
+                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });\r
+            }\r
+            catch (Exception exc)\r
+            {\r
+                string message = String.Format("API Key retrieval failed");\r
+                Log.Error(message, exc);\r
+                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });\r
+            }\r
+\r
+        }\r
+\r
+    \r
+        public void OpenLogPath()\r
+        {\r
+            Shell.OpenLogPath();\r
+        }\r
+\r
+        public void OpenLogConsole()\r
+        {\r
+            var logView=IoC.Get<LogConsole.LogConsoleViewModel>();            \r
+            _windowManager.ShowWindow(logView);\r
+        }\r
+\r
+        public void SaveChanges()\r
+        {\r
+            DoSave();\r
+            TryClose(true);\r
+        }\r
+\r
+        public void RejectChanges()\r
+        {\r
+            Settings.Reload();\r
+            TryClose(false);\r
+        }\r
+\r
+        public void ApplyChanges()\r
+        {\r
+            DoSave();\r
+        }\r
+\r
+        private void DoSave()\r
+        {\r
+            //SetStartupMode();            \r
+\r
+            //Ensure we save the settings changes first\r
+            foreach (var account in _accountsToRemove)\r
+            {\r
+                Settings.Accounts.Remove(account);\r
+            }\r
+\r
+            foreach (var account in _accountsToAdd)\r
+            {\r
+                Settings.Accounts.Add(account);    \r
+            }\r
+\r
+            Settings.Save();\r
+\r
+\r
+            try\r
+            {\r
+                foreach (var account in _accountsToRemove)\r
+                {\r
+                    Shell.RemoveMonitor(account.ServerUrl, account.AccountName);\r
+                    Shell.RemoveAccountFromDatabase(account);\r
+                }\r
+\r
+                foreach (var account in Settings.Accounts)\r
+                {\r
+                    Shell.MonitorAccount(account);\r
+                }\r
+            }                \r
+            finally\r
+            {\r
+                _accountsToRemove.Clear();\r
+                _accountsToAdd.Clear();\r
+            }\r
+\r
+            NotifyOfPropertyChange(()=>Settings);\r
+\r
+            if (IgnoreCertificateErrors)\r
+                ServicePointManager.ServerCertificateValidationCallback= (sender,certificate,chain,errors)=> true;\r
+            else\r
+            {\r
+                ServicePointManager.ServerCertificateValidationCallback = null;\r
+            }\r
+        }\r
+\r
+     /*   public void ChangePithosFolder()\r
+        {\r
+            var browser = new FolderBrowserDialog();\r
+            browser.SelectedPath = Settings.PithosPath;\r
+            var result = browser.ShowDialog((IWin32Window)GetView());\r
+            if (result == DialogResult.OK)\r
+            {\r
+                var newPath = browser.SelectedPath;\r
+                var accountName = CurrentAccount.AccountName;\r
+                var monitor = Shell.Monitors[accountName];\r
+                monitor.Stop();\r
+                \r
+                Shell.Monitors.Remove(accountName);\r
+\r
+                Directory.Move(Settings.PithosPath, newPath);\r
+                Settings.PithosPath = newPath;\r
+                Settings.Save();\r
+\r
+                Shell.MonitorAccount(CurrentAccount);\r
+\r
+                NotifyOfPropertyChange(() => Settings);                \r
+            }\r
+        }\r
+*/\r
+\r
+\r
+        readonly List<AccountSettings> _accountsToAdd=new List<AccountSettings>();\r
+       public void AddAccount()\r
+       {\r
+           var wizard = new AddAccountViewModel();\r
+           if (_windowManager.ShowDialog(wizard) == true)\r
+           {\r
+               string selectedPath = wizard.AccountPath;\r
+               var initialRootPath = wizard.ShouldCreateOkeanosFolder?\r
+                   Path.Combine(selectedPath, "Okeanos")\r
+                   :selectedPath;\r
+               var actualRootPath= initialRootPath;\r
+               if (wizard.ShouldCreateOkeanosFolder)\r
+               {\r
+                   int attempt = 1;\r
+                   while (Directory.Exists(actualRootPath) || File.Exists(actualRootPath))\r
+                   {\r
+                       actualRootPath = String.Format("{0} {1}", initialRootPath, attempt++);\r
+                   }\r
+               }\r
+\r
+\r
+\r
+               var account = Accounts.FirstOrDefault(act => act.AccountName == wizard.AccountName && act.ServerUrl == wizard.CurrentServer);\r
+               if (account != null)\r
+               {\r
+                   if (MessageBox.Show("The account you specified already exists. Do you want to update it?", "The account exists") == MessageBoxResult.Yes)\r
+                   {\r
+                       account.ApiKey = wizard.Token;\r
+                       account.IsExpired = false;\r
+                       CurrentAccount = account;\r
+                   }\r
+               }\r
+               else\r
+               {\r
+                   var newAccount = new AccountSettings\r
+                                        {\r
+                                            AccountName = wizard.AccountName,\r
+                                            ServerUrl = wizard.CurrentServer,\r
+                                            ApiKey = wizard.Token,\r
+                                            RootPath = actualRootPath,\r
+                                            IsActive = wizard.IsAccountActive,\r
+                                        };\r
+\r
+\r
+                   var client = new CloudFilesClient(newAccount.AccountName, newAccount.ApiKey)\r
+                                    {\r
+                                        AuthenticationUrl = newAccount.ServerUrl, UsePithos = true\r
+                                    };\r
+                   client.Authenticate();\r
+\r
+\r
+                   var containers = client.ListContainers(newAccount.AccountName);\r
+                   var containerUris = from container in containers\r
+                                       select String.Format(@"{0}/v1/{1}/{2}",\r
+                                            newAccount.ServerUrl, newAccount.AccountName, container.Name);\r
+                   \r
+                   newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
+\r
+                   var objectInfos = (from container in containers\r
+                                      from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
+                                      where container.Name != "trash"\r
+                                      select dir).ToList();\r
+                   var tree = objectInfos.ToTree();\r
+\r
+                   var selected = (from root in tree \r
+                                   from child in root \r
+                                   select child.Uri.ToString()).ToArray();\r
+                   newAccount.SelectiveFolders.AddRange(selected);\r
+\r
+                   \r
+                   //TODO:Add the "pithos" container as a default selection                   \r
+\r
+                   _accountsToAdd.Add(newAccount);\r
+                   var accountVm = new AccountViewModel(newAccount);\r
+                   (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);\r
+                   CurrentAccount = accountVm;\r
+               }\r
+               NotifyOfPropertyChange(() => Accounts);\r
+               NotifyOfPropertyChange(() => Settings);   \r
+           }\r
+\r
+\r
+            \r
+       }\r
+\r
+/*\r
+        public void AddPithosAccount()\r
+       {\r
+            var credentials=PithosAccount.RetrieveCredentials(null);\r
+            if (credentials == null)\r
+                return;\r
+            var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);\r
+            var accountVM = new AccountViewModel(account);\r
+            if (account == null)\r
+            {\r
+                account=new AccountSettings{\r
+                    AccountName=credentials.UserName,\r
+                    ApiKey=credentials.Password\r
+                };\r
+                Settings.Accounts.Add(account);\r
+                accountVM = new AccountViewModel(account);\r
+                (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);\r
+            }\r
+            else\r
+            {\r
+                account.ApiKey=credentials.Password;\r
+            }\r
+            //SelectedAccountIndex= Settings.Accounts.IndexOf(account);\r
+            CurrentAccount = accountVM;\r
+            NotifyOfPropertyChange(() => Accounts);\r
+            NotifyOfPropertyChange(()=>Settings);                       \r
+       }\r
+*/\r
+\r
+\r
+        readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();\r
+        public void RemoveAccount()\r
+        {\r
+            Accounts.TryRemove(CurrentAccount);\r
+            _accountsToRemove.Add(CurrentAccount.Account);\r
+\r
+            CurrentAccount = null;\r
+            NotifyOfPropertyChange(() => Accounts);\r
+\r
+            \r
+            //NotifyOfPropertyChange("Settings.Accounts");\r
+        }\r
+\r
+        public bool CanRemoveAccount\r
+        {\r
+            get { return (CurrentAccount != null); }\r
+        }\r
+\r
+        public bool CanClearAccountCache\r
+        {\r
+            get { return (CurrentAccount != null); }\r
+        }\r
+\r
+        public void ClearAccountCache()\r
+        {\r
+            if (MessageBoxResult.Yes == MessageBox.Show("You are about to delete all partially downloaded files from the account's cache.\n" +\r
+                            " You will have to download all partially downloaded data again\n" +\r
+                            "This change can not be undone\n\n" +\r
+            "Do you wish to delete all partially downloaded data?", "Warning! Clearing account cache",\r
+                            MessageBoxButton.YesNo,MessageBoxImage.Question,MessageBoxResult.No))\r
+            {\r
+\r
+                var cachePath = Path.Combine(CurrentAccount.RootPath, FolderConstants.CacheFolder);\r
+                var dir = new DirectoryInfo(cachePath);\r
+                //The file may not exist if we just created the account\r
+                if (!dir.Exists)\r
+                    return;\r
+                dir.EnumerateFiles().Apply(file=>file.Delete());\r
+                dir.EnumerateDirectories().Apply(folder => folder.Delete(true));\r
+            }\r
+        }\r
+\r
+\r
+        public bool ExtensionsActivated\r
+        {\r
+            get { return Settings.ExtensionsActivated; }\r
+            set\r
+            {\r
+                if (Settings.ExtensionsActivated == value)\r
+                    return;\r
+\r
+                Settings.ExtensionsActivated = value;\r
+\r
+/*\r
+                if (value)\r
+                    _extensionController.RegisterExtensions();\r
+                else\r
+                {\r
+                    _extensionController.UnregisterExtensions();\r
+                }\r
+*/\r
+                NotifyOfPropertyChange(() => ExtensionsActivated);\r
+            }\r
+        }\r
+\r
+        public bool DebugLoggingEnabled\r
+        {\r
+            get { return Settings.DebugLoggingEnabled; }\r
+            set { \r
+                Settings.DebugLoggingEnabled = value;\r
+                NotifyOfPropertyChange(()=>DebugLoggingEnabled);\r
+            }\r
+        }\r
+\r
+        public bool IgnoreCertificateErrors\r
+        {\r
+            get { return Settings.IgnoreCertificateErrors; }\r
+            set {\r
+                Settings.IgnoreCertificateErrors = value;\r
+                NotifyOfPropertyChange(() => IgnoreCertificateErrors);\r
+            }\r
+        }\r
+       \r
+        #endregion\r
+\r
+       /* private int _selectedAccountIndex;\r
+        public int SelectedAccountIndex\r
+        {\r
+            get { return _selectedAccountIndex; }\r
+            set\r
+            {\r
+                //var accountCount=Settings.Accounts.Count;\r
+                //if (accountCount == 0)\r
+                //    return;\r
+                //if (0 <= value && value < accountCount)\r
+                //    _selectedAccountIndex = value;\r
+                //else\r
+                //    _selectedAccountIndex = 0;\r
+                _selectedAccountIndex = value;\r
+                NotifyOfPropertyChange(() => CurrentAccount);\r
+                NotifyOfPropertyChange(() => CanRemoveAccount);\r
+                NotifyOfPropertyChange(()=>SelectedAccountIndex);\r
+            }\r
+        }*/\r
+\r
+        private AccountViewModel _currentAccount;\r
+        private readonly IWindowManager _windowManager;\r
+        private readonly string _shortcutPath;\r
+\r
+\r
+        \r
+        public AccountViewModel CurrentAccount\r
+        {\r
+            get { return _currentAccount; }\r
+            set\r
+            {\r
+                _currentAccount = value;\r
+                NotifyOfPropertyChange(()=>CurrentAccount);\r
+                NotifyOfPropertyChange(() => CanRemoveAccount);\r
+                NotifyOfPropertyChange(() => CanSelectiveSyncFolders);\r
+                NotifyOfPropertyChange(() => CanMoveAccountFolder);\r
+                NotifyOfPropertyChange(() => CanClearAccountCache);\r
+            }\r
+        }\r
+\r
+/*\r
+        public AccountSettings CurrentAccount\r
+        {\r
+            get {\r
+                if (0 <= SelectedAccountIndex && SelectedAccountIndex < Settings.Accounts.Count)                    \r
+                    return Settings.Accounts[SelectedAccountIndex];\r
+                return null;\r
+            }\r
+\r
+        }\r
+*/\r
+\r
+\r
+        public bool CanMoveAccountFolder\r
+        {\r
+            get { return CurrentAccount != null; }\r
+        }\r
+\r
+    public void MoveAccountFolder()\r
+    {\r
+\r
+        using (var dlg = new FolderBrowserDialog())\r
+        {\r
+            var currentFolder = CurrentAccount.RootPath;\r
+            dlg.SelectedPath = currentFolder;\r
+            //Ask the user to select a folder\r
+            //Note: We need a parent window here, which we retrieve with GetView            \r
+            var view = (Window)GetView();            \r
+            if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))\r
+                return;            \r
+\r
+            var newPath= dlg.SelectedPath;                \r
+            //Find the account's monitor and stop it\r
+            PithosMonitor monitor;\r
+            if (Shell.Monitors.TryGetValue(CurrentAccount.AccountKey, out monitor))\r
+            {\r
+                monitor.Stop();\r
+\r
+\r
+                var oldPath = monitor.RootPath;\r
+                //The old directory may not exist eg. if we create an account for the first time\r
+                if (Directory.Exists(oldPath))\r
+                {\r
+                    //If it does, do the move\r
+\r
+                    //Now Create all of the directories\r
+                    foreach (string dirPath in Directory.EnumerateDirectories(oldPath, "*",\r
+                                                           SearchOption.AllDirectories))\r
+                        Directory.CreateDirectory(dirPath.Replace(oldPath, newPath));\r
+\r
+                    //Copy all the files\r
+                    foreach (string newFilePath in Directory.EnumerateFiles(oldPath, "*.*",\r
+                                                                            SearchOption.AllDirectories))\r
+                        File.Copy(newFilePath, newFilePath.Replace(oldPath, newPath));\r
+\r
+                    Log.InfoFormat("Deleting account folder {0}",oldPath);\r
+                    Directory.Delete(oldPath, true);\r
+\r
+                    //We also need to change the path of the existing file states\r
+                    monitor.MoveFileStates(oldPath, newPath);\r
+                }\r
+            }\r
+            //Replace the old rootpath with the new\r
+            CurrentAccount.RootPath = newPath;\r
+            //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date\r
+            Settings.Save();            \r
+            //And start the monitor on the new RootPath            \r
+            if (monitor != null)\r
+            {\r
+                monitor.RootPath = newPath;\r
+                if (CurrentAccount.IsActive)\r
+                    monitor.Start();\r
+            }\r
+            else\r
+                Shell.MonitorAccount(CurrentAccount.Account);\r
+            //Finally, notify that the Settings, CurrentAccount have changed\r
+            NotifyOfPropertyChange(() => CurrentAccount);\r
+            NotifyOfPropertyChange(() => Settings);\r
+\r
+        }\r
+    }\r
+    }\r
+}\r
index 555aa92..8355103 100644 (file)
@@ -173,7 +173,11 @@ namespace Pithos.Client.WPF.SelectiveSynch
 
         public bool IsExplicitlyChecked
         {
-            set { _isChecked=value; }
+            set\r
+            {\r
+                _isChecked=value;\r
+                this.RaisePropertyChangedEventImmediately("IsChecked");\r
+            }
         }
 
         public DirectoryRecord(ObjectInfo info)
index 8d8583a..b332064 100644 (file)
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="SelectiveSynchViewModel.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;
-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<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();
-        public ObservableCollection<DirectoryRecord> RootNodes
-        {
-            get { return _rootNodes; }
-        }
-
-        private ObservableCollection<ObjectInfo> _checks;
-        //private readonly PithosMonitor _monitor;
-        private bool _isBusy=true;
-        private string _apiKey;
-
-        public ObservableCollection<ObjectInfo> Checks
-        {
-            get { return _checks; }
-        }
-
-        public void GetChecks()
-        {
-            var root = RootNodes[0];            
-            _checks = new ObservableCollection<ObjectInfo>(
-                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<Uri> 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\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="SelectiveSynchViewModel.cs" company="GRNet">\r
+ * \r
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ *   1. Redistributions of source code must retain the above\r
+ *      copyright notice, this list of conditions and the following\r
+ *      disclaimer.\r
+ *\r
+ *   2. Redistributions in binary form must reproduce the above\r
+ *      copyright notice, this list of conditions and the following\r
+ *      disclaimer in the documentation and/or other materials\r
+ *      provided with the distribution.\r
+ *\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * The views and conclusions contained in the software and\r
+ * documentation are those of the authors and should not be\r
+ * interpreted as representing official policies, either expressed\r
+ * or implied, of GRNET S.A.\r
+ * </copyright>\r
+ * -----------------------------------------------------------------------\r
+ */\r
+#endregion\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Collections.ObjectModel;\r
+using System.Linq;\r
+using System.Threading.Tasks;\r
+using Caliburn.Micro;\r
+using Pithos.Client.WPF.Properties;\r
+using Pithos.Client.WPF.Utils;\r
+using Pithos.Core;\r
+using Pithos.Interfaces;\r
+using Pithos.Network;\r
+\r
+namespace Pithos.Client.WPF.SelectiveSynch\r
+{\r
+    class SelectiveSynchViewModel:Screen\r
+    {        \r
+        private readonly IEventAggregator _events ;\r
+\r
+\r
+        public AccountSettings Account { get; set; }\r
+\r
+        private readonly ObservableCollection<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();\r
+        public ObservableCollection<DirectoryRecord> RootNodes\r
+        {\r
+            get { return _rootNodes; }\r
+        }\r
+\r
+        private ObservableCollection<ObjectInfo> _checks;\r
+        //private readonly PithosMonitor _monitor;\r
+        private bool _isBusy=true;\r
+        private string _apiKey;\r
+\r
+        public ObservableCollection<ObjectInfo> Checks\r
+        {\r
+            get { return _checks; }\r
+        }\r
+\r
+        public void GetChecks()\r
+        {\r
+            var root = RootNodes[0];            \r
+            _checks = new ObservableCollection<ObjectInfo>(\r
+                from DirectoryRecord record in root\r
+                where record.IsChecked==true\r
+                select record.ObjectInfo);\r
+            NotifyOfPropertyChange(() => Checks);\r
+        }\r
+\r
+        public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey)\r
+        {\r
+            Account = account;\r
+            AccountName = account.AccountName;\r
+            DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName);\r
+            //_monitor = monitor;\r
+            _events = events;\r
+            _apiKey = apiKey;\r
+            TaskEx.Run(LoadRootNode);\r
+        }\r
+\r
+        private void LoadRootNode()\r
+        {            \r
+            //TODO: Check this\r
+            var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};\r
+            client.Authenticate();\r
+            \r
+\r
+            var dirs = from container in client.ListContainers(AccountName)  \r
+                       where container.Name != "trash"\r
+                       select new DirectoryRecord\r
+                                  {\r
+                                      DisplayName = container.Name,\r
+                                      Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)),\r
+                                      Directories = (from dir in client.ListObjects(AccountName, container.Name)                                                                                                          \r
+                                                     select dir).ToTree()\r
+                                  };\r
+            var ownFolders = dirs.ToList();\r
+\r
+            var accountNodes=from account in client.ListSharingAccounts()\r
+                             select new DirectoryRecord\r
+                             {\r
+                                DisplayName=account.name,\r
+                                Uri=new Uri(client.StorageUrl,"../"+ account.name),\r
+                                Directories=(from container in client.ListContainers(account.name)\r
+                                            select new DirectoryRecord\r
+                                                        {\r
+                                                            DisplayName=container.Name,\r
+                                                            Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name),\r
+                                                            Directories=(from folder in client.ListObjects(account.name,container.Name)                                                                        \r
+                                                                        select folder).ToTree()\r
+                                                        }).ToList()\r
+                             };                                                          \r
+\r
+            var othersNode = new DirectoryRecord\r
+                                 {\r
+                                     DisplayName = "Shared to me",\r
+                                     Directories=accountNodes.ToList()\r
+                                 };\r
+\r
+            \r
+            var rootItem = new DirectoryRecord\r
+                               {\r
+                                   DisplayName = AccountName ,\r
+                                   Directories = ownFolders.ToList()\r
+                               };\r
+\r
+            Execute.OnUIThread(() =>\r
+                                   {\r
+                                       RootNodes.Add(rootItem);\r
+                                       RootNodes.Add(othersNode);\r
+                                   });\r
+\r
+            SetInitialSelections(Account);\r
+            \r
+            IsBusy = false;\r
+        }\r
+\r
+        public bool IsBusy\r
+        {\r
+            get {\r
+                return _isBusy;\r
+            }\r
+            set {\r
+                _isBusy = value;\r
+                NotifyOfPropertyChange(()=>IsBusy);\r
+            }\r
+        }\r
+\r
+        private void SetInitialSelections(AccountSettings account)\r
+        {\r
+            var selections = account.SelectiveFolders;\r
+\r
+\r
+                \r
+            //Initially, all nodes are checked\r
+            //We need to *uncheck* the nodes that are not selected\r
+\r
+            var allNodes = (from DirectoryRecord rootRecord in RootNodes\r
+                           from DirectoryRecord record in rootRecord\r
+                           select record).ToList();\r
+            //WARNING: Using IsChecked marks the item as REMOVED\r
+            allNodes.Apply(record => record.IsExplicitlyChecked = false);\r
+\r
+            if (selections.Count == 0)\r
+            {\r
+            //    allNodes.Apply(record => record.IsChecked = false);\r
+                return;\r
+            } \r
+            \r
+            var selects = (from DirectoryRecord rootRecord in RootNodes\r
+                          from DirectoryRecord record in rootRecord\r
+                          where record.Uri !=null &&  selections.Contains(record.Uri.ToString())\r
+                          select record).ToList();\r
+            //var shouldBeChecked = allNodes.Except(selects).ToList();\r
+            \r
+            //WARNING: Using IsChecked marks the item as ADDED\r
+            selects.Apply(record=>record.IsExplicitlyChecked=true);\r
+\r
+            //shouldBeChecked.Apply(record => record.IsChecked = true);\r
+            \r
+            \r
+\r
+        }\r
+\r
+        protected string AccountName { get; set; }\r
+\r
+        public void SaveChanges()\r
+        {\r
+            var uris = (from DirectoryRecord root in RootNodes\r
+                        from DirectoryRecord record in root\r
+                        where record.IsChecked == true && record.Uri != null\r
+                        select record.Uri).ToArray();            \r
+\r
+            SaveSettings(uris);\r
+            \r
+            //RootNodes is an ObservableCollection, it can't be enumerated iterativelly\r
+\r
+            var added = (from DirectoryRecord root in RootNodes\r
+                         from DirectoryRecord record in root\r
+                         where record.Added && record.Uri != null\r
+                         select record.Uri).ToArray();\r
+            var removed = (from DirectoryRecord root in RootNodes\r
+                           from DirectoryRecord record in root\r
+                          where record.Removed && record.Uri != null\r
+                         select record.Uri).ToArray();\r
+            //TODO: Include Uris for the containers as well\r
+            _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed});\r
+            \r
+\r
+            \r
+\r
+            TryClose(true);\r
+        }\r
+\r
+        \r
+        private void SaveSettings(IEnumerable<Uri> uris)\r
+        {\r
+            var selections = uris.Select(uri => uri.ToString()).ToArray();\r
+\r
+            Account.SelectiveFolders.Clear();\r
+            Account.SelectiveFolders.AddRange(selections);\r
+            Settings.Default.Save();            \r
+        }        \r
+\r
+        public void RejectChanges()\r
+        {\r
+            TryClose(false);\r
+        }\r
+    }\r
+}\r