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 readonly 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 IsEnabled = account.SelectiveSyncEnabled;
\r
98 TaskEx.Run(LoadRootNode);
\r
101 private void LoadRootNode()
\r
104 var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};
\r
105 client.Authenticate();
\r
107 //NEED to get the local folders here as well,
\r
108 // and combine them with the cloud folders
\r
111 var dirs = from container in client.ListContainers(AccountName)
\r
112 where container.Name != "trash"
\r
113 select new DirectoryRecord
\r
115 DisplayName = container.Name,
\r
116 Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)),
\r
117 Directories = (from dir in client.ListObjects(AccountName, container.Name)
\r
118 select dir).ToTree()
\r
120 var ownFolders = dirs.ToList();
\r
124 var accountNodes=from account in client.ListSharingAccounts()
\r
125 select new DirectoryRecord
\r
127 DisplayName=account.name,
\r
128 Uri=new Uri(client.StorageUrl,"../"+ account.name),
\r
129 Directories=(from container in client.ListContainers(account.name)
\r
130 select new DirectoryRecord
\r
132 DisplayName=container.Name,
\r
133 Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name),
\r
134 Directories=(from folder in client.ListObjects(account.name,container.Name)
\r
135 select folder).ToTree()
\r
139 var othersNode = new DirectoryRecord
\r
141 DisplayName = "Shared with me",
\r
142 Directories=accountNodes.ToList()
\r
146 var rootItem = new DirectoryRecord
\r
148 DisplayName = AccountName ,
\r
149 Directories = ownFolders.ToList()
\r
153 // Add Local Folders
\r
154 ///var localFolders = SelectiveExtensions.LocalFolders(AccountName, Account.RootPath,client.StorageUrl.AbsoluteUri);
\r
156 ///AppendToTree(localFolders, rootItem);
\r
158 >>>>>>> 8b6aa653d6c8a8cc3c40a93fca96459df726135a
160 //For each local folder that doesn't exist in the server nodes
\r
161 //find the best matching parent and add the folder below it.
\r
163 Execute.OnUIThread(() =>
\r
165 RootNodes.Add(rootItem);
\r
166 RootNodes.Add(othersNode);
\r
169 SetInitialSelections(Account);
\r
174 private static void AppendToTree(IEnumerable<DirectoryRecord> localFolders, DirectoryRecord rootItem)
\r
176 foreach (var folder in localFolders)
\r
178 var items = from root in rootItem
\r
181 //If this folder is not included in the server folders
\r
182 if (items.Any(dir => dir.Uri == folder.Uri))
\r
185 //we need to add it
\r
186 //Find the best parent
\r
188 //One way to do this, is to break the the Uri to its parts
\r
189 //and try to find a parent using progressively fewer parts
\r
190 var parts = folder.Uri.AbsoluteUri.Split('/');
\r
191 for (var i = parts.Length - 1; i > 2; i--)
\r
193 var parentUrl = String.Join("/", parts.Splice(0, i));
\r
194 var parentUri = new Uri(parentUrl);
\r
196 var parent = items.FirstOrDefault(dir => dir.Uri == parentUri);
\r
197 if (parent != null)
\r
199 parent.Directories.Add(folder);
\r
213 NotifyOfPropertyChange(()=>IsBusy);
\r
217 private void SetInitialSelections(AccountSettings account)
\r
219 var selections = account.SelectiveFolders;
\r
223 //Initially, all nodes are checked
\r
224 //We need to *uncheck* the nodes that are not selected
\r
226 var allNodes = (from DirectoryRecord rootRecord in RootNodes
\r
227 from DirectoryRecord record in rootRecord
\r
228 select record).ToList();
\r
229 //WARNING: Using IsChecked marks the item as REMOVED
\r
230 allNodes.Apply(record => record.IsExplicitlyChecked = false);
\r
232 if (selections.Count == 0)
\r
234 // allNodes.Apply(record => record.IsChecked = false);
\r
238 var selects = (from DirectoryRecord rootRecord in RootNodes
\r
239 from DirectoryRecord record in rootRecord
\r
240 where record.Uri !=null && selections.Contains(record.Uri.ToString())
\r
241 select record).ToList();
\r
242 //var shouldBeChecked = allNodes.Except(selects).ToList();
\r
244 //WARNING: Using IsChecked marks the item as ADDED
\r
245 selects.Apply(record=>record.IsExplicitlyChecked=true);
\r
247 //shouldBeChecked.Apply(record => record.IsChecked = true);
\r
253 protected string AccountName { get; set; }
\r
255 public void SaveChanges()
\r
257 var uris = (from DirectoryRecord root in RootNodes
\r
258 from DirectoryRecord record in root
\r
259 where record.IsChecked == true && record.Uri != null
\r
260 select record.Uri).ToArray();
\r
262 SaveSettings(uris);
\r
264 //RootNodes is an ObservableCollection, it can't be enumerated iterativelly
\r
266 var added = (from DirectoryRecord root in RootNodes
\r
267 from DirectoryRecord record in root
\r
268 where record.Added && record.Uri != null
\r
269 select record.Uri).ToArray();
\r
270 var removed = (from DirectoryRecord root in RootNodes
\r
271 from DirectoryRecord record in root
\r
272 where record.Removed && record.Uri != null
\r
273 select record.Uri).ToArray();
\r
274 //TODO: Include Uris for the containers as well
\r
275 _events.Publish(new SelectiveSynchChanges{Enabled=IsEnabled, Account=Account,Uris=uris,Added=added,Removed=removed});
\r
283 private bool _isEnabled;
\r
284 public bool IsEnabled
\r
286 get { return _isEnabled; }
\r
289 _isEnabled = value;
\r
290 NotifyOfPropertyChange(()=>IsEnabled);
\r
294 private void SaveSettings(IEnumerable<Uri> uris)
\r
296 var selections = uris.Select(uri => uri.ToString()).ToArray();
\r
297 Account.SelectiveSyncEnabled = IsEnabled;
\r
298 Account.SelectiveFolders.Clear();
\r
299 Account.SelectiveFolders.AddRange(selections);
\r
300 Settings.Default.Save();
\r
303 public void RejectChanges()
\r