Modified to allow initial selection of all folders and containers
[pithos-ms-client] / trunk / Pithos.Client.WPF / SelectiveSynch / SelectiveSynchViewModel.cs
1 #region\r
2 /* -----------------------------------------------------------------------\r
3  * <copyright file="SelectiveSynchViewModel.cs" company="GRNet">\r
4  * \r
5  * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
6  *\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
10  *\r
11  *   1. Redistributions of source code must retain the above\r
12  *      copyright notice, this list of conditions and the following\r
13  *      disclaimer.\r
14  *\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
19  *\r
20  *\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
33  *\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
38  * </copyright>\r
39  * -----------------------------------------------------------------------\r
40  */\r
41 #endregion\r
42 using System;\r
43 using System.Collections.Generic;\r
44 using System.Collections.ObjectModel;\r
45 using System.Linq;\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
50 using Pithos.Core;\r
51 using Pithos.Interfaces;\r
52 using Pithos.Network;\r
53 \r
54 namespace Pithos.Client.WPF.SelectiveSynch\r
55 {\r
56     class SelectiveSynchViewModel:Screen\r
57     {        \r
58         private readonly IEventAggregator _events ;\r
59 \r
60 \r
61         public AccountSettings Account { get; set; }\r
62 \r
63         private readonly ObservableCollection<DirectoryRecord> _rootNodes=new ObservableCollection<DirectoryRecord>();\r
64         public ObservableCollection<DirectoryRecord> RootNodes\r
65         {\r
66             get { return _rootNodes; }\r
67         }\r
68 \r
69         private ObservableCollection<ObjectInfo> _checks;\r
70         //private readonly PithosMonitor _monitor;\r
71         private bool _isBusy=true;\r
72         private string _apiKey;\r
73 \r
74         public ObservableCollection<ObjectInfo> Checks\r
75         {\r
76             get { return _checks; }\r
77         }\r
78 \r
79         public void GetChecks()\r
80         {\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
87         }\r
88 \r
89         public SelectiveSynchViewModel(/*PithosMonitor monitor,*/ IEventAggregator events, AccountSettings account, string apiKey)\r
90         {\r
91             Account = account;\r
92             AccountName = account.AccountName;\r
93             DisplayName = String.Format("Selective folder synchronization for {0}",account.AccountName);\r
94             //_monitor = monitor;\r
95             _events = events;\r
96             _apiKey = apiKey;\r
97             TaskEx.Run(LoadRootNode);\r
98         }\r
99 \r
100         private void LoadRootNode()\r
101         {            \r
102             //TODO: Check this\r
103             var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};\r
104             client.Authenticate();\r
105             \r
106 \r
107             var dirs = from container in client.ListContainers(AccountName)  \r
108                        where container.Name != "trash"\r
109                        select new DirectoryRecord\r
110                                   {\r
111                                       DisplayName = container.Name,\r
112                                       Uri=new Uri(client.StorageUrl,String.Format(@"{0}/{1}",Account.AccountName, container.Name)),\r
113                                       Directories = (from dir in client.ListObjects(AccountName, container.Name)                                                                                                          \r
114                                                      select dir).ToTree()\r
115                                   };\r
116             var ownFolders = dirs.ToList();\r
117 \r
118             var accountNodes=from account in client.ListSharingAccounts()\r
119                              select new DirectoryRecord\r
120                              {\r
121                                 DisplayName=account.name,\r
122                                 Uri=new Uri(client.StorageUrl,"../"+ account.name),\r
123                                 Directories=(from container in client.ListContainers(account.name)\r
124                                             select new DirectoryRecord\r
125                                                         {\r
126                                                             DisplayName=container.Name,\r
127                                                             Uri = new Uri(client.StorageUrl, "../" + account.name + "/" + container.Name),\r
128                                                             Directories=(from folder in client.ListObjects(account.name,container.Name)                                                                        \r
129                                                                         select folder).ToTree()\r
130                                                         }).ToList()\r
131                              };                                                          \r
132 \r
133             var othersNode = new DirectoryRecord\r
134                                  {\r
135                                      DisplayName = "Shared to me",\r
136                                      Directories=accountNodes.ToList()\r
137                                  };\r
138 \r
139             \r
140             var rootItem = new DirectoryRecord\r
141                                {\r
142                                    DisplayName = AccountName ,\r
143                                    Directories = ownFolders.ToList()\r
144                                };\r
145 \r
146             Execute.OnUIThread(() =>\r
147                                    {\r
148                                        RootNodes.Add(rootItem);\r
149                                        RootNodes.Add(othersNode);\r
150                                    });\r
151 \r
152             SetInitialSelections(Account);\r
153             \r
154             IsBusy = false;\r
155         }\r
156 \r
157         public bool IsBusy\r
158         {\r
159             get {\r
160                 return _isBusy;\r
161             }\r
162             set {\r
163                 _isBusy = value;\r
164                 NotifyOfPropertyChange(()=>IsBusy);\r
165             }\r
166         }\r
167 \r
168         private void SetInitialSelections(AccountSettings account)\r
169         {\r
170             var selections = account.SelectiveFolders;\r
171 \r
172 \r
173                 \r
174             //Initially, all nodes are checked\r
175             //We need to *uncheck* the nodes that are not selected\r
176 \r
177             var allNodes = (from DirectoryRecord rootRecord in RootNodes\r
178                            from DirectoryRecord record in rootRecord\r
179                            select record).ToList();\r
180             //WARNING: Using IsChecked marks the item as REMOVED\r
181             allNodes.Apply(record => record.IsExplicitlyChecked = false);\r
182 \r
183             if (selections.Count == 0)\r
184             {\r
185             //    allNodes.Apply(record => record.IsChecked = false);\r
186                 return;\r
187             } \r
188             \r
189             var selects = (from DirectoryRecord rootRecord in RootNodes\r
190                           from DirectoryRecord record in rootRecord\r
191                           where record.Uri !=null &&  selections.Contains(record.Uri.ToString())\r
192                           select record).ToList();\r
193             //var shouldBeChecked = allNodes.Except(selects).ToList();\r
194             \r
195             //WARNING: Using IsChecked marks the item as ADDED\r
196             selects.Apply(record=>record.IsExplicitlyChecked=true);\r
197 \r
198             //shouldBeChecked.Apply(record => record.IsChecked = true);\r
199             \r
200             \r
201 \r
202         }\r
203 \r
204         protected string AccountName { get; set; }\r
205 \r
206         public void SaveChanges()\r
207         {\r
208             var uris = (from DirectoryRecord root in RootNodes\r
209                         from DirectoryRecord record in root\r
210                         where record.IsChecked == true && record.Uri != null\r
211                         select record.Uri).ToArray();            \r
212 \r
213             SaveSettings(uris);\r
214             \r
215             //RootNodes is an ObservableCollection, it can't be enumerated iterativelly\r
216 \r
217             var added = (from DirectoryRecord root in RootNodes\r
218                          from DirectoryRecord record in root\r
219                          where record.Added && record.Uri != null\r
220                          select record.Uri).ToArray();\r
221             var removed = (from DirectoryRecord root in RootNodes\r
222                            from DirectoryRecord record in root\r
223                           where record.Removed && record.Uri != null\r
224                          select record.Uri).ToArray();\r
225             //TODO: Include Uris for the containers as well\r
226             _events.Publish(new SelectiveSynchChanges{Account=Account,Uris=uris,Added=added,Removed=removed});\r
227             \r
228 \r
229             \r
230 \r
231             TryClose(true);\r
232         }\r
233 \r
234         \r
235         private void SaveSettings(IEnumerable<Uri> uris)\r
236         {\r
237             var selections = uris.Select(uri => uri.ToString()).ToArray();\r
238 \r
239             Account.SelectiveFolders.Clear();\r
240             Account.SelectiveFolders.AddRange(selections);\r
241             Settings.Default.Save();            \r
242         }        \r
243 \r
244         public void RejectChanges()\r
245         {\r
246             TryClose(false);\r
247         }\r
248     }\r
249 }\r