2 /* -----------------------------------------------------------------------
\r
3 * <copyright file="SelectiveSynchViewModel.cs" company="GRNet">
\r
5 * Copyright 2011-2012 GRNET S.A. All rights reserved.
\r
7 * Redistribution and use in source and binary forms, with or
\r
8 * without modification, are permitted provided that the following
\r
9 * conditions are met:
\r
11 * 1. Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\r
15 * 2. Redistributions in binary form must reproduce the above
\r
16 * copyright notice, this list of conditions and the following
\r
17 * disclaimer in the documentation and/or other materials
\r
18 * provided with the distribution.
\r
21 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
\r
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
\r
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
\r
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
\r
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
\r
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
\r
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
\r
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
32 * POSSIBILITY OF SUCH DAMAGE.
\r
34 * The views and conclusions contained in the software and
\r
35 * documentation are those of the authors and should not be
\r
36 * interpreted as representing official policies, either expressed
\r
37 * or implied, of GRNET S.A.
\r
39 * -----------------------------------------------------------------------
\r
43 using System.Collections.Generic;
\r
44 using System.Collections.ObjectModel;
\r
46 using System.Threading.Tasks;
\r
47 using Caliburn.Micro;
\r
48 using Pithos.Client.WPF.Properties;
\r
49 using Pithos.Client.WPF.Utils;
\r
51 using Pithos.Interfaces;
\r
52 using Pithos.Network;
\r
54 namespace Pithos.Client.WPF.SelectiveSynch
\r
56 class SelectiveSynchViewModel:Screen
\r
58 private readonly IEventAggregator _events ;
\r
61 public AccountSettings Account { get; set; }
\r
63 private readonly ObservableCollection<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();
\r
64 public ObservableCollection<DirectoryRecord> RootNodes
\r
66 get { return _rootNodes; }
\r
69 private ObservableCollection<ObjectInfo> _checks;
\r
70 //private readonly PithosMonitor _monitor;
\r
71 private bool _isBusy=true;
\r
72 private string _apiKey;
\r
74 public ObservableCollection<ObjectInfo> Checks
\r
76 get { return _checks; }
\r
79 public void GetChecks()
\r
81 var root = RootNodes[0];
\r
82 _checks = new ObservableCollection<ObjectInfo>(
\r
83 from DirectoryRecord record in root
\r
84 where record.IsChecked==true
\r
85 select record.ObjectInfo);
\r
86 NotifyOfPropertyChange(() => Checks);
\r
89 public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey)
\r
92 AccountName = account.AccountName;
\r
93 DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName);
\r
94 //_monitor = monitor;
\r
97 TaskEx.Run(LoadRootNode);
\r
100 private void LoadRootNode()
\r
103 var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};
\r
104 client.Authenticate();
\r
106 //NEED to get the local folders here as well,
\r
107 // and combine them with the cloud folders
\r
110 var dirs = from container in client.ListContainers(AccountName)
\r
111 where container.Name != "trash"
\r
112 select new DirectoryRecord
\r
114 DisplayName = container.Name,
\r
115 Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)),
\r
116 Directories = (from dir in client.ListObjects(AccountName, container.Name)
\r
117 select dir).ToTree()
\r
119 var ownFolders = dirs.ToList();
\r
123 var accountNodes=from account in client.ListSharingAccounts()
\r
124 select new DirectoryRecord
\r
126 DisplayName=account.name,
\r
127 Uri=new Uri(client.StorageUrl,"../"+ account.name),
\r
128 Directories=(from container in client.ListContainers(account.name)
\r
129 select new DirectoryRecord
\r
131 DisplayName=container.Name,
\r
132 Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name),
\r
133 Directories=(from folder in client.ListObjects(account.name,container.Name)
\r
134 select folder).ToTree()
\r
138 var othersNode = new DirectoryRecord
\r
140 DisplayName = "Shared to me",
\r
141 Directories=accountNodes.ToList()
\r
145 var rootItem = new DirectoryRecord
\r
147 DisplayName = AccountName ,
\r
148 Directories = ownFolders.ToList()
\r
151 var localFolders = SelectiveExtensions.LocalFolders(AccountName, Account.RootPath,client.StorageUrl.AbsoluteUri);
\r
153 foreach (var folder in localFolders)
\r
155 //If this folder is not included in the server folders
\r
156 if (!rootItem.Directories.Any(dir => dir.Uri == folder.Uri))
\r
158 //we need to add it
\r
159 //Find the best parent
\r
161 //One way to do this, is to break the the Uri to its parts
\r
162 //and try to find a parent using progressively fewer parts
\r
163 var parts = folder.Uri.AbsoluteUri.Split('/');
\r
164 for (var i = parts.Length - 1; i > 0; i--)
\r
166 var parentUrl = String.Join("/",parts.Splice(0, i));
\r
167 var parentUri = new Uri(parentUrl);
\r
169 var parent = rootItem.Directories.FirstOrDefault(dir => dir.Uri == parentUri);
\r
170 if (parent != null)
\r
172 parent.Directories.Add(folder);
\r
179 //For each local folder that doesn't exist in the server nodes
\r
180 //find the best matching parent and add the folder below it.
\r
182 Execute.OnUIThread(() =>
\r
184 RootNodes.Add(rootItem);
\r
185 RootNodes.Add(othersNode);
\r
188 SetInitialSelections(Account);
\r
200 NotifyOfPropertyChange(()=>IsBusy);
\r
204 private void SetInitialSelections(AccountSettings account)
\r
206 var selections = account.SelectiveFolders;
\r
210 //Initially, all nodes are checked
\r
211 //We need to *uncheck* the nodes that are not selected
\r
213 var allNodes = (from DirectoryRecord rootRecord in RootNodes
\r
214 from DirectoryRecord record in rootRecord
\r
215 select record).ToList();
\r
216 //WARNING: Using IsChecked marks the item as REMOVED
\r
217 allNodes.Apply(record => record.IsExplicitlyChecked = false);
\r
219 if (selections.Count == 0)
\r
221 // allNodes.Apply(record => record.IsChecked = false);
\r
225 var selects = (from DirectoryRecord rootRecord in RootNodes
\r
226 from DirectoryRecord record in rootRecord
\r
227 where record.Uri !=null && selections.Contains(record.Uri.ToString())
\r
228 select record).ToList();
\r
229 //var shouldBeChecked = allNodes.Except(selects).ToList();
\r
231 //WARNING: Using IsChecked marks the item as ADDED
\r
232 selects.Apply(record=>record.IsExplicitlyChecked=true);
\r
234 //shouldBeChecked.Apply(record => record.IsChecked = true);
\r
240 protected string AccountName { get; set; }
\r
242 public void SaveChanges()
\r
244 var uris = (from DirectoryRecord root in RootNodes
\r
245 from DirectoryRecord record in root
\r
246 where record.IsChecked == true && record.Uri != null
\r
247 select record.Uri).ToArray();
\r
249 SaveSettings(uris);
\r
251 //RootNodes is an ObservableCollection, it can't be enumerated iterativelly
\r
253 var added = (from DirectoryRecord root in RootNodes
\r
254 from DirectoryRecord record in root
\r
255 where record.Added && record.Uri != null
\r
256 select record.Uri).ToArray();
\r
257 var removed = (from DirectoryRecord root in RootNodes
\r
258 from DirectoryRecord record in root
\r
259 where record.Removed && record.Uri != null
\r
260 select record.Uri).ToArray();
\r
261 //TODO: Include Uris for the containers as well
\r
262 _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed});
\r
271 private void SaveSettings(IEnumerable<Uri> uris)
\r
273 var selections = uris.Select(uri => uri.ToString()).ToArray();
\r
275 Account.SelectiveFolders.Clear();
\r
276 Account.SelectiveFolders.AddRange(selections);
\r
277 Settings.Default.Save();
\r
280 public void RejectChanges()
\r