Added Clear Conflict action to resolver
[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             pithosFile.ContinueWith(t =>
356             {
357                 if (t.IsFaulted)
358                 {
359                     IsBusy = false;
360                     Execute.OnUIThread(()=>ShowError(t.Exception));
361                     this.TryClose();
362
363                 }
364                 else
365                     Execute.OnUIThread(() => PithosFile = t.Result);
366             });       
367                  
368         }
369
370         private void ShowError(AggregateException exception)
371         {
372             MessageView view;
373             if (exception.InnerException is RetryException)
374                 view = new MessageView(exception.InnerException as RetryException);
375             else if (exception.InnerException is WebException)
376                 view = new MessageView(exception.InnerException as WebException);
377             else
378                 view = new MessageView(exception.InnerException);
379             view.ShowDialog();
380         }
381
382
383         protected ShellViewModel Shell { get; set; }
384
385         private ObjectInfo _pithosFile;
386         public ObjectInfo PithosFile
387         {
388             get { return _pithosFile; }
389             set
390             {
391                 _pithosFile = value;
392                 
393                 Permissions.Clear();
394                 Tags.Clear();
395
396                 var perms=from permission in value.Permissions
397                             select new Permission(permission.Key, permission.Value);
398                 perms.Apply(perm=>Permissions.Add(perm));
399                 
400                 var tags=from tag in value.Tags
401                              select new MetaValue(tag.Key, tag.Value);
402                 tags.Apply(tag=>Tags.Add(tag));
403
404                 Title = String.Format("{0} Properties", value.Name);
405                 Kind=value.Content_Type;
406                 ShortSize = value.Bytes.ToByteSize();
407                 Size = String.Format("{0} ({1:N0} bytes)", ShortSize, value.Bytes);
408                 Where = Uri.UnescapeDataString(value.Name);
409                 FileName = Uri.UnescapeDataString(value.Name.Split('/').Last());
410                 Container = value.Container;
411                 Modified = value.Last_Modified;
412                 ModifiedBy = value.ModifiedBy;
413                 Version = value.Version??0;
414
415                 ContentDisposition = value.ContendDisposition;
416                 ContentEncoding = value.ContentEncoding;
417                 Manifest = value.Manifest;
418                 IsPublic = value.IsPublic;
419                 if (IsPublic)
420                     PublicUrl = String.Format("{0}/v1{1}", Shell.Accounts.First(account=>account.UserName==PithosFile.Account).SiteUri,value.PublicUrl);
421
422                 if (Directory.Exists(LocalFileName))
423                 {
424                     FileIcon= new BitmapImage(new Uri("../Images/Folder.ico",UriKind.Relative));
425                 }
426                 else if (File.Exists(LocalFileName))
427                 {
428                     using (var icon = Icon.ExtractAssociatedIcon(LocalFileName))
429                     {
430                         FileIcon = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty,
431                                                                        BitmapSizeOptions.FromEmptyOptions());
432                     }
433                 }
434
435                 var status=Shell.GetFileStatus(LocalFileName);
436                 SynchStatus = Enum.GetName(typeof (FileStatus), status);
437
438
439                 NotifyOfPropertyChange(()=>PithosFile);
440                 IsBusy = false;
441             }
442         }
443
444         private MetaValue _currentTag;
445         public MetaValue CurrentTag
446         {
447             get { return _currentTag; }
448             set
449             {
450                 _currentTag = (value==null)?new MetaValue() : value.Clone();
451                 _currentTag.PropertyChanged += (o, e) => NotifyOfPropertyChange(() => CanAddTag);
452
453                 NotifyOfPropertyChange(()=>CurrentTag);
454                 NotifyOfPropertyChange(() => CanAddTag);
455             }
456         }
457
458         private readonly ObservableCollection<MetaValue> _tags ;
459         public ObservableCollection<MetaValue> Tags
460         {
461             get { return _tags;}
462         }
463
464         private readonly ObservableCollection<Permission> _permissions ;
465         
466
467         public ObservableCollection<Permission> Permissions
468         {
469             get { return _permissions; }
470         }
471
472         public void Reload()
473         {
474             PithosFile=Shell.RefreshObjectInfo(PithosFile);
475         }
476
477         public override void CanClose(Action<bool> callback)
478         {
479             base.CanClose(callback);
480         }
481
482         public void SaveChanges()
483         {
484             DoSave();
485             TryClose();
486         }
487
488         public void RejectChanges()
489         {
490             TryClose();
491         }
492
493         public void ApplyChanges()
494         {
495             DoSave();
496         }
497
498         private void DoSave()
499         {
500             if (TagsChanged)
501             {
502                 PithosFile.Tags = this.Tags.ToDictionary(tag => tag.Name, tag => tag.Value);
503             }
504             
505             if (PermissionsChanged)
506             {
507                 PithosFile.Permissions = this.Permissions.ToDictionary(perm => perm.UserName, perm => 
508                     (perm.Value.Trim()));
509             }
510
511             PithosFile.ContendDisposition = ContentDisposition;
512             PithosFile.ContentEncoding = ContentEncoding;
513             PithosFile.Manifest = Manifest;
514             PithosFile.IsPublic = IsPublic;
515             
516             var monitor = Shell.Monitors[PithosFile.AccountKey];
517             monitor.CloudClient.UpdateMetadata(PithosFile);
518
519
520             TagsChanged = false;
521             PermissionsChanged = false;
522         }
523
524
525     }
526 }