Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / SelectiveSynch / SelectiveSynchViewModel.cs @ 5b2e4db4

History | View | Annotate | Download (13.2 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="SelectiveSynchViewModel.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using System;
43
using System.Collections.Generic;
44
using System.Collections.ObjectModel;
45
using System.Linq;
46
using System.Threading.Tasks;
47
using Caliburn.Micro;
48
using Pithos.Client.WPF.Properties;
49
using Pithos.Client.WPF.Utils;
50
using Pithos.Core;
51
using Pithos.Interfaces;
52
using Pithos.Network;
53

    
54
namespace Pithos.Client.WPF.SelectiveSynch
55
{
56
    class SelectiveSynchViewModel:Screen
57
    {        
58
        private readonly IEventAggregator _events ;
59

    
60

    
61
        public AccountSettings Account { get; set; }
62

    
63
        private readonly ObservableCollection<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();
64
        public ObservableCollection<DirectoryRecord> RootNodes
65
        {
66
            get { return _rootNodes; }
67
        }
68

    
69
        private ObservableCollection<ObjectInfo> _checks;
70
        //private readonly PithosMonitor _monitor;
71
        private bool _isBusy=true;
72
        private readonly string _apiKey;
73

    
74
        public ObservableCollection<ObjectInfo> Checks
75
        {
76
            get { return _checks; }
77
        }
78

    
79
        public void GetChecks()
80
        {
81
            var root = RootNodes[0];            
82
            _checks = new ObservableCollection<ObjectInfo>(
83
                from DirectoryRecord record in root
84
                where record.IsChecked==true
85
                select record.ObjectInfo);
86
            NotifyOfPropertyChange(() => Checks);
87
        }
88

    
89
        public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey,bool forSelectiveActivation)
90
        {
91
            Account = account;
92
            AccountName = account.AccountName;
93
            DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName);
94
            //_monitor = monitor;
95
            _events = events;
96
            _apiKey = apiKey;
97
            //IsEnabled = account.SelectiveSyncEnabled;            
98
            TaskEx.Run(()=>LoadRootNode(forSelectiveActivation));
99
        }
100

    
101
        private async void LoadRootNode(bool forSelectiveActivation)
102
        {            
103
            //TODO: Check this
104
            var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};
105
            await client.Authenticate().ConfigureAwait(false);
106
            
107
            //NEED to get the local folders here as well,
108
            // and combine them with the cloud folders
109

    
110

    
111
            var containerInfos = await client.ListContainers(AccountName).ConfigureAwait(false);
112
            var dirs = from container in containerInfos  
113
                       where container.Name.ToUnescapedString() != "trash"
114
                       select new DirectoryRecord
115
                                  {
116
                                      DisplayName = container.Name.ToUnescapedString(),
117
                                      Uri=client.StorageUrl.Combine(String.Format(@"{0}/{1}",Account.AccountName, container.Name)),
118
                                      Directories = (from dir in client.ListObjects(AccountName, container.Name)                                                                                                          
119
                                                     select dir).ToTree()
120
                                  };
121
            var ownFolders = dirs.ToList();
122

    
123

    
124

    
125
            var accountNodes=from account in client.ListSharingAccounts()
126
                             select new DirectoryRecord
127
                             {
128
                                DisplayName=account.name,
129
                                Uri=client.StorageUrl.Combine("../"+ account.name),
130
                                Directories=(from container in client.ListContainers(account.name).Result
131
                                            select new DirectoryRecord
132
                                                        {
133
                                                            DisplayName=container.Name.ToUnescapedString(),
134
                                                            Uri = client.StorageUrl.Combine("../" + account.name + "/" + container.Name),
135
                                                            Directories=(from folder in client.ListObjects(account.name,container.Name)                                                                        
136
                                                                        select folder).ToTree()
137
                                                        }).ToList()
138
                             };                                                          
139

    
140
            var othersNode = new DirectoryRecord
141
                                 {
142
                                     DisplayName = "Shared with me",
143
                                     Directories=accountNodes.ToList()
144
                                 };
145

    
146
            
147
            var rootItem = new DirectoryRecord
148
                               {
149
                                   DisplayName = AccountName ,
150
                                   Directories = ownFolders.ToList()
151
                               };
152

    
153
            // Add Local Folders
154
            //var localFolders = SelectiveExtensions.LocalFolders(AccountName, Account.RootPath,client.StorageUrl.AbsoluteUri);
155
            //AppendToTree(localFolders, rootItem);
156

    
157
            
158
            //For each local folder that doesn't exist in the server nodes 
159
            //find the best matching parent and add the folder below it.
160

    
161
            Execute.OnUIThread(() =>
162
                                   {
163
                                       RootNodes.Add(rootItem);
164
                                       RootNodes.Add(othersNode);
165
                                   });
166

    
167
            SetInitialSelections(Account,forSelectiveActivation);
168
            
169
            IsBusy = false;
170
        }
171

    
172
        private static void AppendToTree(IEnumerable<DirectoryRecord> localFolders, DirectoryRecord rootItem)
173
        {
174
            foreach (var folder in localFolders)
175
            {
176
                var items = from root in rootItem
177
                            from child in root
178
                            select child;
179
                //If this folder is not included in the server folders
180
                if (items.Any(dir => dir.Uri == folder.Uri)) 
181
                    continue;
182

    
183
                //we need to add it
184
                //Find the best parent
185

    
186
                //One way to do this, is to break the the Uri to its parts
187
                //and try to find a parent using progressively fewer parts
188
                var parts = folder.Uri.AbsoluteUri.Split('/');
189
                for (var i = parts.Length - 1; i > 2; i--)
190
                {
191
                    var parentUrl = String.Join("/", parts.Splice(0, i));
192
                    var parentUri = new Uri(parentUrl);
193

    
194
                    var parent = items.FirstOrDefault(dir => dir.Uri == parentUri);
195
                    if (parent != null)
196
                    {
197
                        parent.Directories.Add(folder);
198
                        break;
199
                    }
200
                }
201
            }
202
        }
203

    
204
        public bool IsBusy
205
        {
206
            get {
207
                return _isBusy;
208
            }
209
            set {
210
                _isBusy = value;
211
                NotifyOfPropertyChange(()=>IsBusy);
212
            }
213
        }
214

    
215
        private void SetInitialSelections(AccountSettings account,bool forSelectiveActivation)
216
        {
217
            var selections = account.SelectiveFolders;
218

    
219

    
220
                
221
            //Initially, all nodes are checked
222
            //We need to *uncheck* the nodes that are not selected
223

    
224
            var allNodes = (from DirectoryRecord rootRecord in RootNodes
225
                           from DirectoryRecord record in rootRecord
226
                           select record).ToList();
227
            //WARNING: Using IsChecked marks the item as REMOVED
228
            allNodes.Apply(record => record.IsExplicitlyChecked = false);
229

    
230
            if (selections.Count == 0)
231
            {
232
            //    allNodes.Apply(record => record.IsChecked = false);
233
                return;
234
            } 
235
            
236
            var selects = (from DirectoryRecord rootRecord in RootNodes
237
                          from DirectoryRecord record in rootRecord
238
                          where record.Uri !=null &&  selections.Contains(record.Uri.ToString())
239
                          select record).ToList();
240
            //var shouldBeChecked = allNodes.Except(selects).ToList();
241
            
242
            //WARNING: Using IsChecked marks the item as ADDED
243
            selects.Apply(record => record.IsExplicitlyChecked = !forSelectiveActivation);
244

    
245
            //If any of the root nodes has at least one selected child, set it to gray
246
            SetRootNodeSelections(forSelectiveActivation);
247

    
248
            //shouldBeChecked.Apply(record => record.IsChecked = true);
249

    
250

    
251

    
252
        }
253

    
254
        private void SetRootNodeSelections(bool forSelectiveActivation)
255
        {
256
            var selectedRoots = from DirectoryRecord rootRecord in RootNodes
257
                                from DirectoryRecord record in rootRecord
258
                                where record.IsChecked == true
259
                                select rootRecord;
260
            selectedRoots.Apply(record => record.IsExplicitlyChecked = !forSelectiveActivation);
261
        }
262

    
263
        protected string AccountName { get; set; }
264

    
265
        public void SaveChanges()
266
        {
267
            var uris = (from DirectoryRecord root in RootNodes
268
                        from DirectoryRecord record in root
269
                        where record.IsChecked == true && record.Uri != null
270
                        select record.Uri).ToArray();            
271

    
272
            SaveSettings(uris);
273
            
274
            //RootNodes is an ObservableCollection, it can't be enumerated iterativelly
275

    
276
            var added = (from DirectoryRecord root in RootNodes
277
                         from DirectoryRecord record in root
278
                         where record.Added && record.Uri != null
279
                         select record.Uri).ToArray();
280
            var removed = (from DirectoryRecord root in RootNodes
281
                           from DirectoryRecord record in root
282
                          where record.Removed && record.Uri != null
283
                         select record.Uri).ToArray();
284
            //TODO: Include Uris for the containers as well
285
            _events.Publish(new SelectiveSynchChanges{Enabled=true, Account=Account,Uris=uris,Added=added,Removed=removed});
286
            
287

    
288
            
289

    
290
            TryClose(true);
291
        }
292

    
293
/*
294
        private bool _isEnabled;
295
        public bool IsEnabled
296
        {
297
            get { return _isEnabled; }
298
            set
299
            {
300
                _isEnabled = value;
301
                NotifyOfPropertyChange(()=>IsEnabled);
302
            }
303
        }
304
*/
305

    
306
        private void SaveSettings(IEnumerable<Uri> uris)
307
        {
308
            var selections = uris.Select(uri => uri.ToString()).ToArray();
309
            //Account.SelectiveSyncEnabled = IsEnabled;
310
            Account.SelectiveFolders.Clear();
311
            Account.SelectiveFolders.AddRange(selections);
312
            Settings.Default.Save();            
313
        }        
314

    
315
        public void RejectChanges()
316
        {
317
            TryClose(false);
318
        }
319
    }
320
}