X-Git-Url: https://code.grnet.gr/git/pithos-ms-client/blobdiff_plain/1a41e9ec4f09e3670be11cb03991b87562be614a..2313b22d680c12277646ac923c3954b91f25d5f6:/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs diff --git a/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs index 71074a8..4141d0f 100644 --- a/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs +++ b/trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs @@ -1,226 +1,285 @@ -#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; - -namespace Pithos.Client.WPF.SelectiveSynch -{ - class SelectiveSynchViewModel:Screen - { - private const string DirectoryType = "application/directory"; - 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; - - 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) - { - Account = account; - AccountName = account.AccountName; - DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName); - _monitor = monitor; - _events = events; - TaskEx.Run(LoadRootNode); - } - - private void LoadRootNode() - { - var client = _monitor.CloudClient; - - var dirs = from container in client.ListContainers(_monitor.UserName) - 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(_monitor.UserName, container.Name) - where dir.Content_Type == DirectoryType - 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) - where folder.Content_Type==DirectoryType - select folder).ToTree() - }).ToList() - }; - - var othersNode = new DirectoryRecord - { - DisplayName = "Others", - 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; - - if (selections.Count == 0) - return; - //Initially, all nodes are checked - //We need to *uncheck* the nodes that are not selected - - var selects = from DirectoryRecord rootRecord in RootNodes - from DirectoryRecord record in rootRecord - where record.Uri !=null && !selections.Contains(record.Uri.ToString()) - select record; - - selects.Apply(record=>record.IsChecked=false); - } - - 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(); + + //NEED to get the local folders here as well, + // and combine them with the cloud folders + + + 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() + }; + + var localFolders = SelectiveExtensions.LocalFolders(AccountName, Account.RootPath,client.StorageUrl.AbsoluteUri); + + foreach (var folder in localFolders) + { + //If this folder is not included in the server folders + if (!rootItem.Directories.Any(dir => dir.Uri == folder.Uri)) + { + //we need to add it + //Find the best parent + + //One way to do this, is to break the the Uri to its parts + //and try to find a parent using progressively fewer parts + var parts = folder.Uri.AbsoluteUri.Split('/'); + for (var i = parts.Length - 1; i > 0; i--) + { + var parentUrl = String.Join("/",parts.Splice(0, i)); + var parentUri = new Uri(parentUrl); + + var parent = rootItem.Directories.FirstOrDefault(dir => dir.Uri == parentUri); + if (parent != null) + { + parent.Directories.Add(folder); + break; + } + } + } + } + + //For each local folder that doesn't exist in the server nodes + //find the best matching parent and add the folder below it. + + 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); + } + } +}