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