Fix incorrect check in Selective Sync that prevented folder changes to propagate...
[pithos-ms-client] / trunk / Pithos.Client.WPF / FileProperties / FilePropertiesViewModel.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="FilePropertiesViewModel.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
43 using System.Collections.ObjectModel;
44 using System.ComponentModel.Composition;
45 using System.Diagnostics.Contracts;
46 using System.Drawing;
47 using System.IO;
48 using System.Net;
49 using System.Threading.Tasks;
50 using System.Windows;
51 using System.Windows.Interop;
52 using System.Windows.Media.Imaging;
53 using Caliburn.Micro;
54 using Pithos.Client.WPF.FileProperties;
55 using Pithos.Core;
56 using Pithos.Interfaces;
57 using Pithos.Network;
58
59 namespace Pithos.Client.WPF
60 {
61     using System;
62     using System.Linq;
63
64     /// <summary>
65     /// TODO: Update summary.
66     /// </summary>
67     [Export(typeof(FilePropertiesViewModel))]
68     public class FilePropertiesViewModel : Screen
69     {
70         private string _title;
71         public string Title
72         {
73             get { return _title; }
74             set
75             {
76                 _title = value;
77                 NotifyOfPropertyChange(()=>Title);
78             }
79         }
80
81
82         private bool _isPublic;
83         public bool IsPublic
84         {
85             get { return _isPublic; }
86             set
87             {
88                 _isPublic = value;
89                 NotifyOfPropertyChange(()=>IsPublic);
90             }
91         }
92
93         private string _contentDisposition;
94         public string ContentDisposition
95         {
96             get { return _contentDisposition; }
97             set
98             {
99                 _contentDisposition = value;
100                 NotifyOfPropertyChange(() => ContentDisposition);
101             }
102         }
103
104         private string _contentEncoding;
105         public string ContentEncoding
106         {
107             get { return _contentEncoding; }
108             set
109             {
110                 _contentEncoding = value;
111                 NotifyOfPropertyChange(() => ContentEncoding);
112             }
113         }
114
115
116         private string _manifest;
117         public string Manifest
118         {
119             get { return _manifest; }
120             set
121             {
122                 _manifest = value;
123                 NotifyOfPropertyChange(() => Manifest);
124             }
125         }
126
127         private string _kind;
128         public string Kind
129         {
130             get { return _kind; }
131             set
132             {
133                 _kind = value;
134                 NotifyOfPropertyChange(() => Kind);
135             }
136         }
137
138         private string _size;
139         public string Size
140         {
141             get { return _size; }
142             set
143             {
144                 _size = value;
145                 NotifyOfPropertyChange(() => Size);
146             }
147         }
148
149         private string _shortSize;
150         public string ShortSize
151         {
152             get { return _shortSize; }
153             set
154             {
155                 _shortSize = value;
156                 NotifyOfPropertyChange(() => ShortSize);
157             }
158         }
159
160         private string _where;
161         public string Where
162         {
163             get { return _where; }
164             set
165             {
166                 _where = value;
167                 NotifyOfPropertyChange(() => Where);
168             }
169         }
170
171         private DateTime _modified;
172         public DateTime Modified
173         {
174             get { return _modified; }
175             set
176             {
177                 _modified = value;
178                 NotifyOfPropertyChange(() => Modified);
179             }
180         }
181
182         private string _modifiedBy;
183         public string ModifiedBy
184         {
185             get { return _modifiedBy; }
186             set
187             {
188                 _modifiedBy = value;
189                 NotifyOfPropertyChange(() => ModifiedBy);
190             }
191         }
192
193         private long _version;
194         public long Version
195         {
196             get { return _version; }
197             set
198             {
199                 _version = value;
200                 NotifyOfPropertyChange(() => Version);
201             }
202         }
203
204         private string _localFileName;
205         protected string LocalFileName
206         {
207             get { return _localFileName; }
208             set
209             {
210                 _localFileName = value;
211                 NotifyOfPropertyChange(() => LocalFileName);
212             }
213         }
214
215         private BitmapSource _fileIcon;
216         public BitmapSource FileIcon
217         {
218             get { return _fileIcon; }
219             set
220             {
221                 _fileIcon = value;
222                 NotifyOfPropertyChange(() => FileIcon);
223             }
224         }
225
226         private string _publicUrl;
227         public string PublicUrl
228         {
229             get { return _publicUrl; }
230             set
231             {
232                 _publicUrl = value;
233                 NotifyOfPropertyChange(() => PublicUrl);
234             }
235         }
236
237         private string _fileName;
238         public string FileName
239         {
240             get { return _fileName; }
241             set
242             {
243                 _fileName = value;
244                 NotifyOfPropertyChange(() => FileName);
245             }
246         }
247
248         private string _container;
249         public string Container
250         {
251             get { return _container; }
252             set
253             {
254                 _container = value;
255                 NotifyOfPropertyChange(() => Container);
256             }
257         }
258
259         private string _synchStatus;
260         public string SynchStatus
261         {
262             get { return _synchStatus; }
263             set
264             {
265                 _synchStatus = value;
266                 NotifyOfPropertyChange(()=>SynchStatus);
267             }
268         }
269         
270         private Permission _currentPermission;
271         public Permission CurrentPermission
272         {
273             get { return _currentPermission; }
274             set
275             {                
276                 _currentPermission = (value==null)?new Permission() : value.Clone();
277                 _currentPermission.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanAddPermission);
278
279                 NotifyOfPropertyChange(()=>CurrentPermission);
280                 NotifyOfPropertyChange(() => CanAddPermission);
281             }
282         }
283
284         public bool CanAddPermission
285         {
286             get { return !String.IsNullOrWhiteSpace(CurrentPermission.UserName); }
287         }
288
289         public void AddPermission()
290         {
291             var existingPermission = Permissions.FirstOrDefault(perm => perm.UserName == CurrentPermission.UserName);
292             if (existingPermission==null)
293                 Permissions.Add(CurrentPermission.Clone());
294             else
295             {
296                 existingPermission.Read = CurrentPermission.Read;
297             }
298         }
299
300         public bool CanAddTag
301         {
302             get { return !String.IsNullOrWhiteSpace(CurrentTag.Name); }
303         }
304
305         public void AddTag()
306         {
307             var existingTag = Tags.FirstOrDefault(tag => tag.Name == CurrentTag.Name);           
308             if (existingTag == null)
309                 Tags.Add(CurrentTag.Clone());
310             else
311             {
312                 existingTag.Value = CurrentTag.Value;
313             }
314         }
315
316
317         public bool TagsChanged { get; private set; }
318         public bool PermissionsChanged { get; private set; }
319
320         private bool _isBusy = true;
321         public bool IsBusy
322         {
323             get { return _isBusy; }
324             set
325             {
326                 _isBusy = value;
327                 NotifyOfPropertyChange(() => IsBusy);
328             }
329         }
330
331
332         public FilePropertiesViewModel(ShellViewModel shell,Task<ObjectInfo> pithosFile,string localFileName)
333         {
334             if (shell==null)
335                 throw new ArgumentNullException("shell");
336             if (pithosFile==null)
337                 throw new ArgumentNullException("pithosFile");
338             if (String.IsNullOrWhiteSpace(localFileName))
339                 throw new ArgumentNullException("localFileName");
340             Contract.EndContractBlock();
341
342
343             _tags = new ObservableCollection<MetaValue>();
344             _tags.CollectionChanged += (sender, evt) => { TagsChanged = true; };
345             _permissions = new ObservableCollection<Permission>();
346             _permissions.CollectionChanged += (sender, evt) => { PermissionsChanged = true; };
347             
348
349             CurrentPermission=new Permission();
350             CurrentTag=new MetaValue();
351
352
353             Shell = shell;
354             LocalFileName = localFileName;
355
356             var name=Path.GetFileName(localFileName);
357             DisplayName = String.Format("{0} File Properties", name);
358
359             pithosFile.ContinueWith(t =>
360             {
361                 if (t.IsFaulted)
362                 {
363                     IsBusy = false;
364                     Execute.OnUIThread(()=>ShowError(t.Exception));
365                     this.TryClose();
366
367                 }
368                 else
369                     Execute.OnUIThread(() => PithosFile = t.Result);
370             });       
371                  
372         }
373
374         private void ShowError(AggregateException exception)
375         {
376             MessageView view;
377             if (exception.InnerException is RetryException)
378                 view = new MessageView(exception.InnerException as RetryException);
379             else if (exception.InnerException is WebException)
380                 view = new MessageView(exception.InnerException as WebException);
381             else
382                 view = new MessageView(exception.InnerException);
383             view.ShowDialog();
384         }
385
386
387         protected ShellViewModel Shell { get; set; }
388
389         private ObjectInfo _pithosFile;
390         public ObjectInfo PithosFile
391         {
392             get { return _pithosFile; }
393             set
394             {
395                 _pithosFile = value;
396                 
397                 Permissions.Clear();
398                 Tags.Clear();
399
400                 var perms=from permission in value.Permissions
401                             select new Permission(permission.Key, permission.Value);
402                 perms.Apply(perm=>Permissions.Add(perm));
403                 
404                 var tags=from tag in value.Tags
405                              select new MetaValue(tag.Key, tag.Value);
406                 tags.Apply(tag=>Tags.Add(tag));
407
408                 Title = String.Format("{0} Properties", value.Name);
409                 Kind=value.Content_Type;
410                 ShortSize = value.Bytes.ToByteSize();
411                 Size = String.Format("{0} ({1:N0} bytes)", ShortSize, value.Bytes);
412                 Where = Uri.UnescapeDataString(value.Name);
413                 FileName = Uri.UnescapeDataString(value.Name.Split('/').Last());
414                 Container = value.Container;
415                 Modified = value.Last_Modified;
416                 ModifiedBy = value.ModifiedBy;
417                 Version = value.Version??0;
418
419                 ContentDisposition = value.ContendDisposition;
420                 ContentEncoding = value.ContentEncoding;
421                 Manifest = value.Manifest;
422                 IsPublic = value.IsPublic;
423                 if (IsPublic)
424                     PublicUrl = String.Format("{0}/v1{1}", Shell.Accounts.First(account=>account.UserName==PithosFile.Account).SiteUri,value.PublicUrl);
425
426                 if (Directory.Exists(LocalFileName))
427                 {
428                     FileIcon= new BitmapImage(new Uri("../Images/Folder.ico",UriKind.Relative));
429                 }
430                 else if (File.Exists(LocalFileName))
431                 {
432                     using (var icon = Icon.ExtractAssociatedIcon(LocalFileName))
433                     {
434                         FileIcon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty,
435                                                                        BitmapSizeOptions.FromEmptyOptions());
436                     }
437                 }
438
439                 var status=Shell.GetFileStatus(LocalFileName);
440                 SynchStatus = Enum.GetName(typeof (FileStatus), status);
441
442
443                 NotifyOfPropertyChange(()=>PithosFile);
444                 IsBusy = false;
445             }
446         }
447
448         private MetaValue _currentTag;
449         public MetaValue CurrentTag
450         {
451             get { return _currentTag; }
452             set
453             {
454                 _currentTag = (value==null)?new MetaValue() : value.Clone();
455                 _currentTag.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanAddTag);
456
457                 NotifyOfPropertyChange(()=>CurrentTag);
458                 NotifyOfPropertyChange(() => CanAddTag);
459             }
460         }
461
462         private readonly ObservableCollection<MetaValue> _tags ;
463         public ObservableCollection<MetaValue> Tags
464         {
465             get { return _tags;}
466         }
467
468         private readonly ObservableCollection<Permission> _permissions ;
469         
470
471         public ObservableCollection<Permission> Permissions
472         {
473             get { return _permissions; }
474         }
475
476         public void Reload()
477         {
478             PithosFile=Shell.RefreshObjectInfo(PithosFile);
479         }
480
481         public override void CanClose(Action<bool> callback)
482         {
483             base.CanClose(callback);
484         }
485
486         public void SaveChanges()
487         {
488             DoSave();
489             TryClose();
490         }
491
492         public void RejectChanges()
493         {
494             TryClose();
495         }
496
497         public void ApplyChanges()
498         {
499             DoSave();
500         }
501
502         private void DoSave()
503         {
504             if (TagsChanged)
505             {
506                 PithosFile.Tags = this.Tags.ToDictionary(tag => tag.Name, tag => tag.Value);
507             }
508             
509             if (PermissionsChanged)
510             {
511                 PithosFile.Permissions = this.Permissions.ToDictionary(perm => perm.UserName, perm => 
512                     (perm.Value.Trim()));
513             }
514
515             PithosFile.ContendDisposition = ContentDisposition;
516             PithosFile.ContentEncoding = ContentEncoding;
517             PithosFile.Manifest = Manifest;
518             PithosFile.IsPublic = IsPublic;
519             
520             var monitor = Shell.Monitors[PithosFile.AccountKey];
521             monitor.CloudClient.UpdateMetadata(PithosFile);
522
523
524             TagsChanged = false;
525             PermissionsChanged = false;
526         }
527
528
529     }
530 }