root / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs @ b517d0d3
History | View | Annotate | Download (40.9 kB)
1 | d7288179 | pkanavos | #region |
---|---|---|---|
2 | d7288179 | pkanavos | /* ----------------------------------------------------------------------- |
3 | d7288179 | pkanavos | * <copyright file="ShellViewModel.cs" company="GRNet"> |
4 | d7288179 | pkanavos | * |
5 | d7288179 | pkanavos | * Copyright 2011-2012 GRNET S.A. All rights reserved. |
6 | d7288179 | pkanavos | * |
7 | d7288179 | pkanavos | * Redistribution and use in source and binary forms, with or |
8 | d7288179 | pkanavos | * without modification, are permitted provided that the following |
9 | d7288179 | pkanavos | * conditions are met: |
10 | d7288179 | pkanavos | * |
11 | d7288179 | pkanavos | * 1. Redistributions of source code must retain the above |
12 | d7288179 | pkanavos | * copyright notice, this list of conditions and the following |
13 | d7288179 | pkanavos | * disclaimer. |
14 | d7288179 | pkanavos | * |
15 | d7288179 | pkanavos | * 2. Redistributions in binary form must reproduce the above |
16 | d7288179 | pkanavos | * copyright notice, this list of conditions and the following |
17 | d7288179 | pkanavos | * disclaimer in the documentation and/or other materials |
18 | d7288179 | pkanavos | * provided with the distribution. |
19 | d7288179 | pkanavos | * |
20 | d7288179 | pkanavos | * |
21 | d7288179 | pkanavos | * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
22 | d7288179 | pkanavos | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23 | d7288179 | pkanavos | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | d7288179 | pkanavos | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
25 | d7288179 | pkanavos | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | d7288179 | pkanavos | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | d7288179 | pkanavos | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
28 | d7288179 | pkanavos | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
29 | d7288179 | pkanavos | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | d7288179 | pkanavos | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
31 | d7288179 | pkanavos | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | d7288179 | pkanavos | * POSSIBILITY OF SUCH DAMAGE. |
33 | d7288179 | pkanavos | * |
34 | d7288179 | pkanavos | * The views and conclusions contained in the software and |
35 | d7288179 | pkanavos | * documentation are those of the authors and should not be |
36 | d7288179 | pkanavos | * interpreted as representing official policies, either expressed |
37 | d7288179 | pkanavos | * or implied, of GRNET S.A. |
38 | d7288179 | pkanavos | * </copyright> |
39 | d7288179 | pkanavos | * ----------------------------------------------------------------------- |
40 | d7288179 | pkanavos | */ |
41 | d7288179 | pkanavos | #endregion |
42 | d7288179 | pkanavos | using System.Collections.Concurrent; |
43 | d7288179 | pkanavos | using System.Diagnostics; |
44 | d7288179 | pkanavos | using System.Diagnostics.Contracts; |
45 | d7288179 | pkanavos | using System.IO; |
46 | d7288179 | pkanavos | using System.Net; |
47 | dd5f5163 | pkanavos | using System.Net.Http; |
48 | d7288179 | pkanavos | using System.Reflection; |
49 | d7288179 | pkanavos | using System.Runtime.InteropServices; |
50 | d7288179 | pkanavos | using System.ServiceModel; |
51 | d7288179 | pkanavos | using System.Threading; |
52 | d7288179 | pkanavos | using System.Threading.Tasks; |
53 | d7288179 | pkanavos | using System.Windows; |
54 | d7288179 | pkanavos | using System.Windows.Controls.Primitives; |
55 | d7288179 | pkanavos | using System.Windows.Input; |
56 | d7288179 | pkanavos | using AppLimit.NetSparkle; |
57 | d7288179 | pkanavos | using Caliburn.Micro; |
58 | d7288179 | pkanavos | using Hardcodet.Wpf.TaskbarNotification; |
59 | d7288179 | pkanavos | using Pithos.Client.WPF.Configuration; |
60 | d7288179 | pkanavos | using Pithos.Client.WPF.FileProperties; |
61 | d7288179 | pkanavos | using Pithos.Client.WPF.Preferences; |
62 | d7288179 | pkanavos | using Pithos.Client.WPF.SelectiveSynch; |
63 | d7288179 | pkanavos | using Pithos.Client.WPF.Services; |
64 | d7288179 | pkanavos | using Pithos.Client.WPF.Shell; |
65 | d7288179 | pkanavos | using Pithos.Core; |
66 | d7288179 | pkanavos | using Pithos.Core.Agents; |
67 | d7288179 | pkanavos | using Pithos.Interfaces; |
68 | d7288179 | pkanavos | using System; |
69 | d7288179 | pkanavos | using System.Collections.Generic; |
70 | d7288179 | pkanavos | using System.Linq; |
71 | d7288179 | pkanavos | using Pithos.Network; |
72 | 6b816c1f | pkanavos | using Pithos.OFM; |
73 | d7288179 | pkanavos | using StatusService = Pithos.Client.WPF.Services.StatusService; |
74 | d7288179 | pkanavos | |
75 | 302c5b7d | George Pantazis | |
76 | d7288179 | pkanavos | namespace Pithos.Client.WPF { |
77 | d7288179 | pkanavos | using System.ComponentModel.Composition; |
78 | d7288179 | pkanavos | |
79 | d7288179 | pkanavos | public class ToggleStatusCommand:ICommand |
80 | d7288179 | pkanavos | { |
81 | d7288179 | pkanavos | private readonly ShellViewModel _model; |
82 | d7288179 | pkanavos | public ToggleStatusCommand(ShellViewModel model) |
83 | d7288179 | pkanavos | { |
84 | d7288179 | pkanavos | _model = model; |
85 | d7288179 | pkanavos | } |
86 | d7288179 | pkanavos | public void Execute(object parameter) |
87 | d7288179 | pkanavos | { |
88 | d7288179 | pkanavos | _model.CurrentSyncStatus(); |
89 | d7288179 | pkanavos | } |
90 | d7288179 | pkanavos | |
91 | d7288179 | pkanavos | public bool CanExecute(object parameter) |
92 | d7288179 | pkanavos | { |
93 | d7288179 | pkanavos | return true; |
94 | d7288179 | pkanavos | } |
95 | d7288179 | pkanavos | |
96 | d7288179 | pkanavos | public event EventHandler CanExecuteChanged; |
97 | d7288179 | pkanavos | } |
98 | d7288179 | pkanavos | |
99 | d7288179 | pkanavos | |
100 | d7288179 | pkanavos | ///<summary> |
101 | d7288179 | pkanavos | /// The "shell" of the Pithos application displays the taskbar icon, menu and notifications. |
102 | d7288179 | pkanavos | /// The shell also hosts the status service called by shell extensions to retrieve file info |
103 | d7288179 | pkanavos | ///</summary> |
104 | d7288179 | pkanavos | ///<remarks> |
105 | d7288179 | pkanavos | /// It is a strange "shell" as its main visible element is an icon instead of a window |
106 | d7288179 | pkanavos | /// The shell subscribes to the following events: |
107 | d7288179 | pkanavos | /// * Notification: Raised by components that want to notify the user. Usually displayed in a balloon |
108 | d7288179 | pkanavos | /// * SelectiveSynchChanges: Notifies that the user made changes to the selective synch folders for an account. Raised by the Selective Synch dialog. Located here because the monitors are here |
109 | d7288179 | pkanavos | /// * ShowFilePropertiesEvent: Raised when a shell command requests the display of the file/container properties dialog |
110 | d7288179 | pkanavos | ///</remarks> |
111 | d7288179 | pkanavos | //TODO: CODE SMELL Why does the shell handle the SelectiveSynchChanges? |
112 | d7288179 | pkanavos | [Export(typeof(IShell)), Export(typeof(ShellViewModel)),Export(typeof(IStatusNotification))] |
113 | d7288179 | pkanavos | public class ShellViewModel : Screen, IStatusNotification, IShell, |
114 | d7288179 | pkanavos | IHandle<Notification>, IHandle<SelectiveSynchChanges>, IHandle<ShowFilePropertiesEvent> |
115 | d7288179 | pkanavos | { |
116 | d7288179 | pkanavos | |
117 | d7288179 | pkanavos | private readonly IEventAggregator _events; |
118 | d7288179 | pkanavos | |
119 | dd5f5163 | pkanavos | |
120 | d7288179 | pkanavos | public PithosSettings Settings { get; private set; } |
121 | d7288179 | pkanavos | |
122 | d7288179 | pkanavos | |
123 | d7288179 | pkanavos | private readonly ConcurrentDictionary<Uri, PithosMonitor> _monitors = new ConcurrentDictionary<Uri, PithosMonitor>(); |
124 | d7288179 | pkanavos | ///<summary> |
125 | d7288179 | pkanavos | /// Dictionary of account monitors, keyed by account |
126 | d7288179 | pkanavos | ///</summary> |
127 | d7288179 | pkanavos | ///<remarks> |
128 | d7288179 | pkanavos | /// One monitor class is created for each account. The Shell needs access to the monitors to execute start/stop/pause commands, |
129 | d7288179 | pkanavos | /// retrieve account and boject info |
130 | d7288179 | pkanavos | ///</remarks> |
131 | d7288179 | pkanavos | // TODO: Does the Shell REALLY need access to the monitors? Could we achieve the same results with a better design? |
132 | d7288179 | pkanavos | // TODO: The monitors should be internal to Pithos.Core, even though exposing them makes coding of the Object and Container windows easier |
133 | d7288179 | pkanavos | public ConcurrentDictionary<Uri, PithosMonitor> Monitors |
134 | d7288179 | pkanavos | { |
135 | d7288179 | pkanavos | get { return _monitors; } |
136 | d7288179 | pkanavos | } |
137 | d7288179 | pkanavos | |
138 | d7288179 | pkanavos | |
139 | d7288179 | pkanavos | ///<summary> |
140 | d7288179 | pkanavos | /// The status service is used by Shell extensions to retrieve file status information |
141 | d7288179 | pkanavos | ///</summary> |
142 | d7288179 | pkanavos | //TODO: CODE SMELL! This is the shell! While hosting in the shell makes executing start/stop commands easier, it is still a smell |
143 | d7288179 | pkanavos | private ServiceHost _statusService; |
144 | d7288179 | pkanavos | |
145 | d7288179 | pkanavos | //Logging in the Pithos client is provided by log4net |
146 | d7288179 | pkanavos | private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
147 | d7288179 | pkanavos | |
148 | 96e5791c | pkanavos | #pragma warning disable 649 |
149 | d7288179 | pkanavos | [Import] |
150 | d7288179 | pkanavos | private PollAgent _pollAgent; |
151 | d7288179 | pkanavos | |
152 | d7288179 | pkanavos | [Import] |
153 | d7288179 | pkanavos | private NetworkAgent _networkAgent; |
154 | d7288179 | pkanavos | |
155 | d7288179 | pkanavos | [Import] |
156 | d7288179 | pkanavos | public Selectives Selectives { get; set; } |
157 | d7288179 | pkanavos | |
158 | 96e5791c | pkanavos | #pragma warning restore 649 |
159 | d7288179 | pkanavos | |
160 | 96e5791c | pkanavos | public ToggleStatusCommand ToggleMiniStatusCommand { get; set; } |
161 | d7288179 | pkanavos | |
162 | d7288179 | pkanavos | private MiniStatusViewModel _miniStatus; |
163 | d7288179 | pkanavos | |
164 | d7288179 | pkanavos | [Import] |
165 | d7288179 | pkanavos | public MiniStatusViewModel MiniStatus |
166 | d7288179 | pkanavos | { |
167 | d7288179 | pkanavos | get { return _miniStatus; } |
168 | d7288179 | pkanavos | set |
169 | d7288179 | pkanavos | { |
170 | d7288179 | pkanavos | _miniStatus = value; |
171 | d7288179 | pkanavos | _miniStatus.Shell = this; |
172 | d7288179 | pkanavos | _miniStatus.Deactivated += (sender, arg) => |
173 | d7288179 | pkanavos | { |
174 | d7288179 | pkanavos | _statusVisible = false; |
175 | d7288179 | pkanavos | NotifyOfPropertyChange(()=>MiniStatusCaption); |
176 | d7288179 | pkanavos | }; |
177 | d7288179 | pkanavos | } |
178 | d7288179 | pkanavos | } |
179 | d7288179 | pkanavos | |
180 | d7288179 | pkanavos | ///<summary> |
181 | d7288179 | pkanavos | /// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings |
182 | d7288179 | pkanavos | ///</summary> |
183 | d7288179 | pkanavos | ///<remarks> |
184 | d7288179 | pkanavos | /// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry) |
185 | d7288179 | pkanavos | ///</remarks> |
186 | d7288179 | pkanavos | [ImportingConstructor] |
187 | d7288179 | pkanavos | public ShellViewModel(IWindowManager windowManager, IEventAggregator events, PithosSettings settings/*,PollAgent pollAgent,NetworkAgent networkAgent*/) |
188 | d7288179 | pkanavos | { |
189 | d7288179 | pkanavos | try |
190 | d7288179 | pkanavos | { |
191 | d7288179 | pkanavos | |
192 | d7288179 | pkanavos | _windowManager = windowManager; |
193 | d7288179 | pkanavos | //CHECK: Caliburn doesn't need explicit command construction |
194 | d7288179 | pkanavos | //CurrentSyncStatusCommand = new PithosCommand(OpenPithosFolder); |
195 | d7288179 | pkanavos | //The event subst |
196 | d7288179 | pkanavos | _events = events; |
197 | d7288179 | pkanavos | _events.Subscribe(this); |
198 | d7288179 | pkanavos | |
199 | d7288179 | pkanavos | /* |
200 | d7288179 | pkanavos | _pollAgent = pollAgent; |
201 | d7288179 | pkanavos | _networkAgent = networkAgent; |
202 | d7288179 | pkanavos | */ |
203 | d7288179 | pkanavos | Settings = settings; |
204 | d7288179 | pkanavos | |
205 | d7288179 | pkanavos | Proxy.SetFromSettings(settings); |
206 | d7288179 | pkanavos | |
207 | d7288179 | pkanavos | StatusMessage = Settings.Accounts.Count==0 |
208 | d7288179 | pkanavos | ? "No Accounts added\r\nPlease add an account" |
209 | d7288179 | pkanavos | : "Starting"; |
210 | d7288179 | pkanavos | |
211 | d7288179 | pkanavos | _accounts.CollectionChanged += (sender, e) => |
212 | d7288179 | pkanavos | { |
213 | d7288179 | pkanavos | NotifyOfPropertyChange(() => OpenFolderCaption); |
214 | d7288179 | pkanavos | NotifyOfPropertyChange(() => HasAccounts); |
215 | d7288179 | pkanavos | }; |
216 | d7288179 | pkanavos | |
217 | d7288179 | pkanavos | SetVersionMessage(); |
218 | d7288179 | pkanavos | |
219 | d7288179 | pkanavos | ToggleMiniStatusCommand=new ToggleStatusCommand(this); |
220 | d7288179 | pkanavos | } |
221 | d7288179 | pkanavos | catch (Exception exc) |
222 | d7288179 | pkanavos | { |
223 | d7288179 | pkanavos | Log.Error("Error while starting the ShellViewModel",exc); |
224 | d7288179 | pkanavos | throw; |
225 | d7288179 | pkanavos | } |
226 | d7288179 | pkanavos | |
227 | d7288179 | pkanavos | } |
228 | d7288179 | pkanavos | |
229 | d7288179 | pkanavos | private void SetVersionMessage() |
230 | d7288179 | pkanavos | { |
231 | d7288179 | pkanavos | Assembly assembly = Assembly.GetExecutingAssembly(); |
232 | d7288179 | pkanavos | var fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location); |
233 | d7288179 | pkanavos | VersionMessage = String.Format("Pithos+ {0}", fileVersion.FileVersion); |
234 | d7288179 | pkanavos | } |
235 | d7288179 | pkanavos | |
236 | 6b816c1f | pkanavos | |
237 | 302c5b7d | George Pantazis | public void openOFM() |
238 | 302c5b7d | George Pantazis | { |
239 | 6b816c1f | pkanavos | var fileManager = IoC.Get<FileManagerViewModel>(); |
240 | df12ed4c | pkanavos | fileManager.Accounts = Settings.Accounts; |
241 | df12ed4c | pkanavos | fileManager.CurrentAccount = fileManager.Accounts.First();// Settings.Accounts.First(); |
242 | 6b816c1f | pkanavos | _windowManager.ShowWindow(fileManager); |
243 | 6b816c1f | pkanavos | //var ofm = new OFM.GUI.OFM(); |
244 | 6b816c1f | pkanavos | //ofm.Show(); |
245 | 302c5b7d | George Pantazis | } |
246 | 302c5b7d | George Pantazis | |
247 | d7288179 | pkanavos | public void CurrentSyncStatus() |
248 | d7288179 | pkanavos | { |
249 | d7288179 | pkanavos | if (Accounts.Count == 0) |
250 | d7288179 | pkanavos | { |
251 | d7288179 | pkanavos | ShowPreferences("AccountTab"); |
252 | d7288179 | pkanavos | } |
253 | d7288179 | pkanavos | else |
254 | d7288179 | pkanavos | { |
255 | d7288179 | pkanavos | if (!_statusVisible) |
256 | d7288179 | pkanavos | { |
257 | d7288179 | pkanavos | _windowManager.ShowWindow(MiniStatus); |
258 | d7288179 | pkanavos | _statusVisible = true; |
259 | d7288179 | pkanavos | } |
260 | d7288179 | pkanavos | else |
261 | d7288179 | pkanavos | { |
262 | d7288179 | pkanavos | if (MiniStatus.IsActive) |
263 | d7288179 | pkanavos | MiniStatus.TryClose(); |
264 | d7288179 | pkanavos | _statusVisible = false; |
265 | d7288179 | pkanavos | } |
266 | d7288179 | pkanavos | |
267 | d7288179 | pkanavos | NotifyOfPropertyChange(() => MiniStatusCaption); |
268 | d7288179 | pkanavos | } |
269 | d7288179 | pkanavos | } |
270 | d7288179 | pkanavos | |
271 | d7288179 | pkanavos | protected override void OnActivate() |
272 | d7288179 | pkanavos | { |
273 | d7288179 | pkanavos | base.OnActivate(); |
274 | d7288179 | pkanavos | |
275 | d7288179 | pkanavos | InitializeSparkle(); |
276 | d7288179 | pkanavos | |
277 | d7288179 | pkanavos | //Must delay opening the upgrade window |
278 | d7288179 | pkanavos | //to avoid Windows Messages sent by the TaskbarIcon |
279 | d7288179 | pkanavos | TaskEx.Delay(5000).ContinueWith(_=> |
280 | d7288179 | pkanavos | Execute.OnUIThread(()=> _sparkle.StartLoop(true,Settings.UpdateForceCheck,Settings.UpdateCheckInterval))); |
281 | d7288179 | pkanavos | |
282 | d7288179 | pkanavos | |
283 | d7288179 | pkanavos | StartMonitoring(); |
284 | d7288179 | pkanavos | } |
285 | d7288179 | pkanavos | |
286 | d7288179 | pkanavos | |
287 | d7288179 | pkanavos | private void OnCheckFinished(object sender, bool updaterequired) |
288 | d7288179 | pkanavos | { |
289 | d7288179 | pkanavos | |
290 | d7288179 | pkanavos | Log.InfoFormat("Upgrade check finished. Need Upgrade: {0}", updaterequired); |
291 | d7288179 | pkanavos | if (_manualUpgradeCheck) |
292 | d7288179 | pkanavos | { |
293 | d7288179 | pkanavos | _manualUpgradeCheck = false; |
294 | d7288179 | pkanavos | if (!updaterequired) |
295 | d7288179 | pkanavos | //Sparkle raises events on a background thread |
296 | d7288179 | pkanavos | Execute.OnUIThread(()=> |
297 | d7288179 | pkanavos | ShowBalloonFor(new Notification{Title="Pithos+ is up to date",Message="You have the latest Pithos+ version. No update is required"})); |
298 | d7288179 | pkanavos | } |
299 | d7288179 | pkanavos | } |
300 | d7288179 | pkanavos | |
301 | d7288179 | pkanavos | private void OnUpgradeDetected(object sender, UpdateDetectedEventArgs e) |
302 | d7288179 | pkanavos | { |
303 | d7288179 | pkanavos | Log.InfoFormat("Update detected {0}",e.LatestVersion); |
304 | d7288179 | pkanavos | } |
305 | d7288179 | pkanavos | |
306 | d7288179 | pkanavos | public void CheckForUpgrade() |
307 | d7288179 | pkanavos | { |
308 | d7288179 | pkanavos | ShowBalloonFor(new Notification{Title="Checking for upgrades",Message="Contacting the server to retrieve the latest Pithos+ version."}); |
309 | d7288179 | pkanavos | _sparkle.StopLoop(); |
310 | d7288179 | pkanavos | _sparkle.updateDetected -= OnUpgradeDetected; |
311 | d7288179 | pkanavos | _sparkle.checkLoopFinished -= OnCheckFinished; |
312 | d7288179 | pkanavos | _sparkle.Dispose(); |
313 | d7288179 | pkanavos | |
314 | d7288179 | pkanavos | _manualUpgradeCheck = true; |
315 | d7288179 | pkanavos | InitializeSparkle(); |
316 | d7288179 | pkanavos | _sparkle.StartLoop(true,true,Settings.UpdateCheckInterval); |
317 | d7288179 | pkanavos | } |
318 | d7288179 | pkanavos | |
319 | d7288179 | pkanavos | private void InitializeSparkle() |
320 | d7288179 | pkanavos | { |
321 | b517d0d3 | George Pantazis | _sparkle = new Sparkle(Settings.UpdateUrl+"?Version="+Assembly.GetExecutingAssembly().GetName().Version); |
322 | d7288179 | pkanavos | _sparkle.updateDetected += OnUpgradeDetected; |
323 | d7288179 | pkanavos | _sparkle.checkLoopFinished += OnCheckFinished; |
324 | d7288179 | pkanavos | _sparkle.ShowDiagnosticWindow = Settings.UpdateDiagnostics; |
325 | d7288179 | pkanavos | } |
326 | d7288179 | pkanavos | |
327 | 2115e2a5 | pkanavos | private async Task StartMonitoring() |
328 | d7288179 | pkanavos | { |
329 | d7288179 | pkanavos | try |
330 | d7288179 | pkanavos | { |
331 | d7288179 | pkanavos | if (Settings.IgnoreCertificateErrors) |
332 | d7288179 | pkanavos | { |
333 | d7288179 | pkanavos | ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; |
334 | d7288179 | pkanavos | } |
335 | d7288179 | pkanavos | |
336 | d7288179 | pkanavos | var accounts = Settings.Accounts.Select(MonitorAccount); |
337 | d7288179 | pkanavos | await TaskEx.WhenAll(accounts).ConfigureAwait(false); |
338 | d7288179 | pkanavos | _statusService = StatusService.Start(); |
339 | d7288179 | pkanavos | |
340 | d7288179 | pkanavos | } |
341 | d7288179 | pkanavos | catch (AggregateException exc) |
342 | d7288179 | pkanavos | { |
343 | d7288179 | pkanavos | exc.Handle(e => |
344 | d7288179 | pkanavos | { |
345 | d7288179 | pkanavos | Log.Error("Error while starting monitoring", e); |
346 | d7288179 | pkanavos | return true; |
347 | d7288179 | pkanavos | }); |
348 | d7288179 | pkanavos | throw; |
349 | d7288179 | pkanavos | } |
350 | d7288179 | pkanavos | } |
351 | d7288179 | pkanavos | |
352 | d7288179 | pkanavos | protected override void OnDeactivate(bool close) |
353 | d7288179 | pkanavos | { |
354 | d7288179 | pkanavos | base.OnDeactivate(close); |
355 | d7288179 | pkanavos | if (close) |
356 | d7288179 | pkanavos | { |
357 | d7288179 | pkanavos | StatusService.Stop(_statusService); |
358 | d7288179 | pkanavos | _statusService = null; |
359 | d7288179 | pkanavos | } |
360 | d7288179 | pkanavos | } |
361 | d7288179 | pkanavos | |
362 | 2115e2a5 | pkanavos | public async Task MonitorAccount(AccountSettings account) |
363 | d7288179 | pkanavos | { |
364 | 2115e2a5 | pkanavos | await TaskEx.Yield(); |
365 | d7288179 | pkanavos | PithosMonitor monitor; |
366 | d7288179 | pkanavos | var accountName = account.AccountName; |
367 | d7288179 | pkanavos | |
368 | d7288179 | pkanavos | MigrateFolders(account); |
369 | d7288179 | pkanavos | |
370 | d7288179 | pkanavos | Selectives.SetIsSelectiveEnabled(account.AccountKey, account.SelectiveSyncEnabled); |
371 | d7288179 | pkanavos | |
372 | d7288179 | pkanavos | if (Monitors.TryGetValue(account.AccountKey, out monitor)) |
373 | d7288179 | pkanavos | { |
374 | d7288179 | pkanavos | //If the account is active |
375 | d7288179 | pkanavos | if (account.IsActive) |
376 | d7288179 | pkanavos | { |
377 | d7288179 | pkanavos | //The Api Key may have changed throuth the Preferences dialog |
378 | d7288179 | pkanavos | monitor.ApiKey = account.ApiKey; |
379 | d7288179 | pkanavos | Debug.Assert(monitor.StatusNotification == this,"An existing monitor should already have a StatusNotification service object"); |
380 | d7288179 | pkanavos | monitor.RootPath = account.RootPath; |
381 | d7288179 | pkanavos | //Start the monitor. It's OK to start an already started monitor, |
382 | d7288179 | pkanavos | //it will just ignore the call |
383 | 2115e2a5 | pkanavos | await StartMonitor(monitor); |
384 | d7288179 | pkanavos | } |
385 | d7288179 | pkanavos | else |
386 | d7288179 | pkanavos | { |
387 | d7288179 | pkanavos | //If the account is inactive |
388 | d7288179 | pkanavos | //Stop and remove the monitor |
389 | d7288179 | pkanavos | RemoveMonitor(account.ServerUrl,accountName); |
390 | d7288179 | pkanavos | } |
391 | d7288179 | pkanavos | return; |
392 | d7288179 | pkanavos | } |
393 | d7288179 | pkanavos | |
394 | d7288179 | pkanavos | |
395 | d7288179 | pkanavos | //Create a new monitor/ Can't use MEF here, it would return a single instance for all monitors |
396 | d7288179 | pkanavos | monitor = new PithosMonitor |
397 | d7288179 | pkanavos | { |
398 | d7288179 | pkanavos | UserName = accountName, |
399 | d7288179 | pkanavos | ApiKey = account.ApiKey, |
400 | d7288179 | pkanavos | StatusNotification = this, |
401 | d7288179 | pkanavos | RootPath = account.RootPath |
402 | d7288179 | pkanavos | }; |
403 | d7288179 | pkanavos | //PithosMonitor uses MEF so we need to resolve it |
404 | d7288179 | pkanavos | IoC.BuildUp(monitor); |
405 | d7288179 | pkanavos | |
406 | d7288179 | pkanavos | monitor.AuthenticationUrl = account.ServerUrl; |
407 | d7288179 | pkanavos | |
408 | d7288179 | pkanavos | Monitors[account.AccountKey] = monitor; |
409 | d7288179 | pkanavos | |
410 | 6e596fcb | pkanavos | if (!Directory.Exists(account.RootPath)) |
411 | 6e596fcb | pkanavos | { |
412 | 6e596fcb | pkanavos | account.IsActive = false; |
413 | 855fc9c9 | pkanavos | Settings.Save(); |
414 | 6e596fcb | pkanavos | Notify(new Notification |
415 | 6e596fcb | pkanavos | { |
416 | 6e596fcb | pkanavos | Level = TraceLevel.Error, |
417 | 6e596fcb | pkanavos | Title = "Missing account folder", |
418 | 6e596fcb | pkanavos | Message = String.Format("Can't find the root folder for account {0} at {1}. The account was deactivated.\r" + |
419 | 6e596fcb | pkanavos | "If the account's files were stored in a removable disk, please connect it and reactivate the account", account.AccountName, account.RootPath) |
420 | 6e596fcb | pkanavos | }); |
421 | 6e596fcb | pkanavos | } |
422 | 6e596fcb | pkanavos | |
423 | 6e596fcb | pkanavos | |
424 | d7288179 | pkanavos | if (account.IsActive) |
425 | d7288179 | pkanavos | { |
426 | d7288179 | pkanavos | //Don't start a monitor if it doesn't have an account and ApiKey |
427 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(monitor.UserName) || |
428 | d7288179 | pkanavos | String.IsNullOrWhiteSpace(monitor.ApiKey)) |
429 | d7288179 | pkanavos | return; |
430 | 2115e2a5 | pkanavos | await StartMonitor(monitor); |
431 | d7288179 | pkanavos | } |
432 | 2115e2a5 | pkanavos | |
433 | d7288179 | pkanavos | } |
434 | d7288179 | pkanavos | |
435 | d7288179 | pkanavos | private void MigrateFolders(AccountSettings account) |
436 | d7288179 | pkanavos | { |
437 | d7288179 | pkanavos | var oldOthersFolder=Path.Combine(account.RootPath, FolderConstants.OldOthersFolder); |
438 | d7288179 | pkanavos | var newOthersFolder = Path.Combine(account.RootPath, FolderConstants.OthersFolder); |
439 | d7288179 | pkanavos | var oldFolder = new DirectoryInfo(oldOthersFolder); |
440 | d7288179 | pkanavos | var newFolder = new DirectoryInfo(newOthersFolder); |
441 | d7288179 | pkanavos | |
442 | d7288179 | pkanavos | if (oldFolder.Exists && !newFolder.Exists) |
443 | d7288179 | pkanavos | { |
444 | d7288179 | pkanavos | oldFolder.MoveTo(newOthersFolder); |
445 | d7288179 | pkanavos | } |
446 | d7288179 | pkanavos | } |
447 | d7288179 | pkanavos | |
448 | d7288179 | pkanavos | |
449 | d7288179 | pkanavos | protected override void OnViewLoaded(object view) |
450 | d7288179 | pkanavos | { |
451 | d7288179 | pkanavos | UpdateStatus(); |
452 | d7288179 | pkanavos | var window = (Window)view; |
453 | d7288179 | pkanavos | TaskEx.Delay(1000).ContinueWith(t => Execute.OnUIThread(window.Hide)); |
454 | d7288179 | pkanavos | base.OnViewLoaded(view); |
455 | d7288179 | pkanavos | } |
456 | d7288179 | pkanavos | |
457 | d7288179 | pkanavos | |
458 | d7288179 | pkanavos | #region Status Properties |
459 | d7288179 | pkanavos | |
460 | d7288179 | pkanavos | private string _statusMessage; |
461 | d7288179 | pkanavos | public string StatusMessage |
462 | d7288179 | pkanavos | { |
463 | d7288179 | pkanavos | get { return _statusMessage; } |
464 | d7288179 | pkanavos | set |
465 | d7288179 | pkanavos | { |
466 | d7288179 | pkanavos | _statusMessage = value; |
467 | d7288179 | pkanavos | NotifyOfPropertyChange(() => StatusMessage); |
468 | d7288179 | pkanavos | NotifyOfPropertyChange(() => TooltipMessage); |
469 | d7288179 | pkanavos | } |
470 | d7288179 | pkanavos | } |
471 | d7288179 | pkanavos | |
472 | f3b6a335 | pkanavos | public int Progress |
473 | f3b6a335 | pkanavos | { |
474 | f3b6a335 | pkanavos | get { return _progress; } |
475 | f3b6a335 | pkanavos | set |
476 | f3b6a335 | pkanavos | { |
477 | f3b6a335 | pkanavos | _progress = value; |
478 | f3b6a335 | pkanavos | NotifyOfPropertyChange(()=>Progress); |
479 | f3b6a335 | pkanavos | } |
480 | f3b6a335 | pkanavos | } |
481 | f3b6a335 | pkanavos | |
482 | f3b6a335 | pkanavos | public string VersionMessage { get; set; } |
483 | d7288179 | pkanavos | |
484 | d7288179 | pkanavos | public string TooltipMessage |
485 | d7288179 | pkanavos | { |
486 | d7288179 | pkanavos | get |
487 | d7288179 | pkanavos | { |
488 | d7288179 | pkanavos | return String.Format("{0}\r\n{1}",VersionMessage,StatusMessage); |
489 | d7288179 | pkanavos | } |
490 | d7288179 | pkanavos | } |
491 | d7288179 | pkanavos | |
492 | d7288179 | pkanavos | public string TooltipMiniStatus |
493 | d7288179 | pkanavos | { |
494 | d7288179 | pkanavos | get |
495 | d7288179 | pkanavos | { |
496 | d7288179 | pkanavos | return String.Format("{0}\r\n{1}", "Status Window", "Enable / Disable the status window"); |
497 | d7288179 | pkanavos | } |
498 | d7288179 | pkanavos | } |
499 | d7288179 | pkanavos | |
500 | d7288179 | pkanavos | /*public string ToggleStatusWindowMessage |
501 | d7288179 | pkanavos | { |
502 | d7288179 | pkanavos | get |
503 | d7288179 | pkanavos | { |
504 | d7288179 | pkanavos | return String.Format("{0}" + Environment.NewLine + "{1} Toggle Mini Status"); |
505 | d7288179 | pkanavos | } |
506 | d7288179 | pkanavos | }*/ |
507 | d7288179 | pkanavos | |
508 | d7288179 | pkanavos | private readonly ObservableConcurrentCollection<AccountInfo> _accounts = new ObservableConcurrentCollection<AccountInfo>(); |
509 | d7288179 | pkanavos | public ObservableConcurrentCollection<AccountInfo> Accounts |
510 | d7288179 | pkanavos | { |
511 | d7288179 | pkanavos | get { return _accounts; } |
512 | d7288179 | pkanavos | } |
513 | d7288179 | pkanavos | |
514 | d7288179 | pkanavos | public bool HasAccounts |
515 | d7288179 | pkanavos | { |
516 | d7288179 | pkanavos | get { return _accounts.Count > 0; } |
517 | d7288179 | pkanavos | } |
518 | d7288179 | pkanavos | |
519 | d7288179 | pkanavos | |
520 | d7288179 | pkanavos | public string OpenFolderCaption |
521 | d7288179 | pkanavos | { |
522 | d7288179 | pkanavos | get |
523 | d7288179 | pkanavos | { |
524 | d7288179 | pkanavos | return (_accounts.Count == 0) |
525 | d7288179 | pkanavos | ? "No Accounts Defined" |
526 | d7288179 | pkanavos | : "Open Pithos Folder"; |
527 | d7288179 | pkanavos | } |
528 | d7288179 | pkanavos | } |
529 | d7288179 | pkanavos | |
530 | d7288179 | pkanavos | private string _pauseSyncCaption="Pause Synching"; |
531 | d7288179 | pkanavos | public string PauseSyncCaption |
532 | d7288179 | pkanavos | { |
533 | d7288179 | pkanavos | get { return _pauseSyncCaption; } |
534 | d7288179 | pkanavos | set |
535 | d7288179 | pkanavos | { |
536 | d7288179 | pkanavos | _pauseSyncCaption = value; |
537 | d7288179 | pkanavos | NotifyOfPropertyChange(() => PauseSyncCaption); |
538 | d7288179 | pkanavos | } |
539 | d7288179 | pkanavos | } |
540 | d7288179 | pkanavos | |
541 | d7288179 | pkanavos | private readonly ObservableConcurrentCollection<FileEntry> _recentFiles = new ObservableConcurrentCollection<FileEntry>(); |
542 | d7288179 | pkanavos | public ObservableConcurrentCollection<FileEntry> RecentFiles |
543 | d7288179 | pkanavos | { |
544 | d7288179 | pkanavos | get { return _recentFiles; } |
545 | d7288179 | pkanavos | } |
546 | d7288179 | pkanavos | |
547 | d7288179 | pkanavos | |
548 | d7288179 | pkanavos | private string _statusIcon="../Images/Pithos.ico"; |
549 | d7288179 | pkanavos | public string StatusIcon |
550 | d7288179 | pkanavos | { |
551 | d7288179 | pkanavos | get { return _statusIcon; } |
552 | d7288179 | pkanavos | set |
553 | d7288179 | pkanavos | { |
554 | d7288179 | pkanavos | //TODO: Ensure all status icons use the Pithos logo |
555 | d7288179 | pkanavos | _statusIcon = value; |
556 | d7288179 | pkanavos | NotifyOfPropertyChange(() => StatusIcon); |
557 | d7288179 | pkanavos | } |
558 | d7288179 | pkanavos | } |
559 | d7288179 | pkanavos | |
560 | d7288179 | pkanavos | #endregion |
561 | d7288179 | pkanavos | |
562 | d7288179 | pkanavos | #region Commands |
563 | d7288179 | pkanavos | |
564 | d7288179 | pkanavos | public void CancelCurrentOperation() |
565 | d7288179 | pkanavos | { |
566 | d7288179 | pkanavos | _pollAgent.CancelCurrentOperation(); |
567 | d7288179 | pkanavos | } |
568 | d7288179 | pkanavos | |
569 | d7288179 | pkanavos | public void ShowPreferences() |
570 | d7288179 | pkanavos | { |
571 | d7288179 | pkanavos | ShowPreferences(null); |
572 | d7288179 | pkanavos | } |
573 | d7288179 | pkanavos | |
574 | d7288179 | pkanavos | public void ShowPreferences(string currentTab) |
575 | d7288179 | pkanavos | { |
576 | d7288179 | pkanavos | //Settings.Reload(); |
577 | d7288179 | pkanavos | |
578 | d7288179 | pkanavos | var preferences = IoC.Get<PreferencesViewModel>();//??new PreferencesViewModel(_windowManager, _events, this, Settings,currentTab); |
579 | d7288179 | pkanavos | if (!String.IsNullOrWhiteSpace(currentTab)) |
580 | d7288179 | pkanavos | preferences.SelectedTab = currentTab; |
581 | d7288179 | pkanavos | if (!preferences.IsActive) |
582 | d7288179 | pkanavos | _windowManager.ShowWindow(preferences); |
583 | d7288179 | pkanavos | var view = (Window)preferences.GetView(); |
584 | d7288179 | pkanavos | view.NullSafe(v=>v.Activate()); |
585 | d7288179 | pkanavos | } |
586 | d7288179 | pkanavos | |
587 | d7288179 | pkanavos | public void AboutPithos() |
588 | d7288179 | pkanavos | { |
589 | d7288179 | pkanavos | var about = IoC.Get<AboutViewModel>(); |
590 | d7288179 | pkanavos | about.LatestVersion=_sparkle.LatestVersion; |
591 | d7288179 | pkanavos | _windowManager.ShowWindow(about); |
592 | d7288179 | pkanavos | } |
593 | d7288179 | pkanavos | |
594 | d7288179 | pkanavos | public void SendFeedback() |
595 | d7288179 | pkanavos | { |
596 | d7288179 | pkanavos | var feedBack = IoC.Get<FeedbackViewModel>(); |
597 | d7288179 | pkanavos | _windowManager.ShowWindow(feedBack); |
598 | d7288179 | pkanavos | } |
599 | d7288179 | pkanavos | |
600 | d7288179 | pkanavos | //public PithosCommand OpenPithosFolderCommand { get; private set; } |
601 | d7288179 | pkanavos | |
602 | d7288179 | pkanavos | public void OpenPithosFolder() |
603 | d7288179 | pkanavos | { |
604 | d7288179 | pkanavos | var account = Settings.Accounts.FirstOrDefault(acc => acc.IsActive); |
605 | d7288179 | pkanavos | if (account == null) |
606 | d7288179 | pkanavos | return; |
607 | d7288179 | pkanavos | Process.Start(account.RootPath); |
608 | d7288179 | pkanavos | } |
609 | d7288179 | pkanavos | |
610 | d7288179 | pkanavos | public void OpenPithosFolder(AccountInfo account) |
611 | d7288179 | pkanavos | { |
612 | d7288179 | pkanavos | Process.Start(account.AccountPath); |
613 | d7288179 | pkanavos | } |
614 | d7288179 | pkanavos | |
615 | d7288179 | pkanavos | |
616 | d7288179 | pkanavos | |
617 | d7288179 | pkanavos | public void GoToSite() |
618 | d7288179 | pkanavos | { |
619 | d7288179 | pkanavos | var site = Properties.Settings.Default.ProductionServer; |
620 | d7288179 | pkanavos | Process.Start(site); |
621 | d7288179 | pkanavos | } |
622 | d7288179 | pkanavos | |
623 | d7288179 | pkanavos | |
624 | d7288179 | pkanavos | public void GoToSite(AccountInfo account) |
625 | d7288179 | pkanavos | { |
626 | d7288179 | pkanavos | var uri = account.SiteUri.Replace("http://","https://"); |
627 | d7288179 | pkanavos | Process.Start(uri); |
628 | d7288179 | pkanavos | } |
629 | d7288179 | pkanavos | |
630 | d7288179 | pkanavos | private bool _statusVisible; |
631 | d7288179 | pkanavos | |
632 | d7288179 | pkanavos | public string MiniStatusCaption |
633 | d7288179 | pkanavos | { |
634 | d7288179 | pkanavos | get |
635 | d7288179 | pkanavos | { |
636 | d7288179 | pkanavos | return _statusVisible ? "Hide Status Window" : "Show Status Window"; |
637 | d7288179 | pkanavos | } |
638 | d7288179 | pkanavos | } |
639 | d7288179 | pkanavos | |
640 | d7288179 | pkanavos | public bool HasConflicts |
641 | d7288179 | pkanavos | { |
642 | d7288179 | pkanavos | get { return true; } |
643 | d7288179 | pkanavos | } |
644 | d7288179 | pkanavos | public void ShowConflicts() |
645 | d7288179 | pkanavos | { |
646 | d7288179 | pkanavos | _windowManager.ShowWindow(IoC.Get<ConflictsViewModel>()); |
647 | d7288179 | pkanavos | } |
648 | d7288179 | pkanavos | |
649 | d7288179 | pkanavos | /// <summary> |
650 | d7288179 | pkanavos | /// Open an explorer window to the target path's directory |
651 | d7288179 | pkanavos | /// and select the file |
652 | d7288179 | pkanavos | /// </summary> |
653 | d7288179 | pkanavos | /// <param name="entry"></param> |
654 | d7288179 | pkanavos | public void GoToFile(FileEntry entry) |
655 | d7288179 | pkanavos | { |
656 | d7288179 | pkanavos | var fullPath = entry.FullPath; |
657 | d7288179 | pkanavos | if (!File.Exists(fullPath) && !Directory.Exists(fullPath)) |
658 | d7288179 | pkanavos | return; |
659 | d7288179 | pkanavos | Process.Start("explorer.exe","/select, " + fullPath); |
660 | d7288179 | pkanavos | } |
661 | d7288179 | pkanavos | |
662 | d7288179 | pkanavos | public void OpenLogPath() |
663 | d7288179 | pkanavos | { |
664 | d7288179 | pkanavos | var pithosDataPath = PithosSettings.PithosDataPath; |
665 | d7288179 | pkanavos | |
666 | d7288179 | pkanavos | Process.Start(pithosDataPath); |
667 | d7288179 | pkanavos | } |
668 | d7288179 | pkanavos | |
669 | d7288179 | pkanavos | public void ShowFileProperties() |
670 | d7288179 | pkanavos | { |
671 | d7288179 | pkanavos | var account = Settings.Accounts.First(acc => acc.IsActive); |
672 | d7288179 | pkanavos | var dir = new DirectoryInfo(account.RootPath + @"\pithos"); |
673 | d7288179 | pkanavos | var files=dir.GetFiles(); |
674 | d7288179 | pkanavos | var r=new Random(); |
675 | d7288179 | pkanavos | var idx=r.Next(0, files.Length); |
676 | d7288179 | pkanavos | ShowFileProperties(files[idx].FullName); |
677 | d7288179 | pkanavos | } |
678 | d7288179 | pkanavos | |
679 | 96e5791c | pkanavos | public void ShowFileProperties(string filePath) |
680 | d7288179 | pkanavos | { |
681 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(filePath)) |
682 | d7288179 | pkanavos | throw new ArgumentNullException("filePath"); |
683 | d7288179 | pkanavos | if (!File.Exists(filePath) && !Directory.Exists(filePath)) |
684 | d7288179 | pkanavos | throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath"); |
685 | d7288179 | pkanavos | Contract.EndContractBlock(); |
686 | d7288179 | pkanavos | |
687 | d7288179 | pkanavos | var pair=(from monitor in Monitors |
688 | d7288179 | pkanavos | where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase) |
689 | d7288179 | pkanavos | select monitor).FirstOrDefault(); |
690 | d7288179 | pkanavos | var accountMonitor = pair.Value; |
691 | d7288179 | pkanavos | |
692 | d7288179 | pkanavos | if (accountMonitor == null) |
693 | d7288179 | pkanavos | return; |
694 | d7288179 | pkanavos | |
695 | 397b9100 | pkanavos | var infoTask=accountMonitor.GetObjectInfo(filePath); |
696 | d7288179 | pkanavos | |
697 | d7288179 | pkanavos | |
698 | d7288179 | pkanavos | |
699 | d7288179 | pkanavos | var fileProperties = new FilePropertiesViewModel(this, infoTask,filePath); |
700 | d7288179 | pkanavos | _windowManager.ShowWindow(fileProperties); |
701 | d7288179 | pkanavos | } |
702 | d7288179 | pkanavos | |
703 | d7288179 | pkanavos | public void ShowContainerProperties() |
704 | d7288179 | pkanavos | { |
705 | d7288179 | pkanavos | var account = Settings.Accounts.First(acc => acc.IsActive); |
706 | d7288179 | pkanavos | var dir = new DirectoryInfo(account.RootPath); |
707 | d7288179 | pkanavos | var fullName = (from folder in dir.EnumerateDirectories() |
708 | d7288179 | pkanavos | where (folder.Attributes & FileAttributes.Hidden) == 0 |
709 | d7288179 | pkanavos | select folder.FullName).First(); |
710 | d7288179 | pkanavos | ShowContainerProperties(fullName); |
711 | d7288179 | pkanavos | } |
712 | d7288179 | pkanavos | |
713 | d7288179 | pkanavos | public void ShowContainerProperties(string filePath) |
714 | d7288179 | pkanavos | { |
715 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(filePath)) |
716 | d7288179 | pkanavos | throw new ArgumentNullException("filePath"); |
717 | d7288179 | pkanavos | if (!Directory.Exists(filePath)) |
718 | d7288179 | pkanavos | throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath"); |
719 | d7288179 | pkanavos | Contract.EndContractBlock(); |
720 | d7288179 | pkanavos | |
721 | d7288179 | pkanavos | var pair=(from monitor in Monitors |
722 | d7288179 | pkanavos | where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase) |
723 | d7288179 | pkanavos | select monitor).FirstOrDefault(); |
724 | d7288179 | pkanavos | var accountMonitor = pair.Value; |
725 | d7288179 | pkanavos | var info = accountMonitor.GetContainerInfo(filePath); |
726 | d7288179 | pkanavos | |
727 | d7288179 | pkanavos | |
728 | d7288179 | pkanavos | |
729 | d7288179 | pkanavos | var containerProperties = new ContainerPropertiesViewModel(this, info,filePath); |
730 | d7288179 | pkanavos | _windowManager.ShowWindow(containerProperties); |
731 | d7288179 | pkanavos | } |
732 | d7288179 | pkanavos | |
733 | d7288179 | pkanavos | public void SynchNow() |
734 | d7288179 | pkanavos | { |
735 | d7288179 | pkanavos | _pollAgent.SynchNow(); |
736 | d7288179 | pkanavos | } |
737 | d7288179 | pkanavos | |
738 | 397b9100 | pkanavos | public async Task<ObjectInfo> RefreshObjectInfo(ObjectInfo currentInfo) |
739 | d7288179 | pkanavos | { |
740 | d7288179 | pkanavos | if (currentInfo==null) |
741 | d7288179 | pkanavos | throw new ArgumentNullException("currentInfo"); |
742 | d7288179 | pkanavos | Contract.EndContractBlock(); |
743 | d7288179 | pkanavos | var monitor = Monitors[currentInfo.AccountKey]; |
744 | 397b9100 | pkanavos | var newInfo=await monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name).ConfigureAwait(false); |
745 | d7288179 | pkanavos | return newInfo; |
746 | d7288179 | pkanavos | } |
747 | d7288179 | pkanavos | |
748 | 8d38a269 | pkanavos | public async Task<ContainerInfo> RefreshContainerInfo(ContainerInfo container) |
749 | d7288179 | pkanavos | { |
750 | d7288179 | pkanavos | if (container == null) |
751 | d7288179 | pkanavos | throw new ArgumentNullException("container"); |
752 | d7288179 | pkanavos | Contract.EndContractBlock(); |
753 | d7288179 | pkanavos | |
754 | d7288179 | pkanavos | var monitor = Monitors[container.AccountKey]; |
755 | 8d38a269 | pkanavos | var newInfo = await monitor.CloudClient.GetContainerInfo(container.Account, container.Name).ConfigureAwait(false); |
756 | d7288179 | pkanavos | return newInfo; |
757 | d7288179 | pkanavos | } |
758 | d7288179 | pkanavos | |
759 | d7288179 | pkanavos | private bool _isPaused; |
760 | d7288179 | pkanavos | public bool IsPaused |
761 | d7288179 | pkanavos | { |
762 | d7288179 | pkanavos | get { return _isPaused; } |
763 | d7288179 | pkanavos | set |
764 | d7288179 | pkanavos | { |
765 | d7288179 | pkanavos | _isPaused = value; |
766 | d7288179 | pkanavos | PauseSyncCaption = IsPaused ? "Resume syncing" : "Pause syncing"; |
767 | d7288179 | pkanavos | var iconKey = IsPaused ? "TraySyncPaused" : "TrayInSynch"; |
768 | d7288179 | pkanavos | StatusIcon = String.Format(@"../Images/{0}.ico", iconKey); |
769 | d7288179 | pkanavos | |
770 | d7288179 | pkanavos | NotifyOfPropertyChange(() => IsPaused); |
771 | d7288179 | pkanavos | } |
772 | d7288179 | pkanavos | } |
773 | d7288179 | pkanavos | |
774 | d7288179 | pkanavos | public void ToggleSynching() |
775 | d7288179 | pkanavos | { |
776 | d7288179 | pkanavos | IsPaused=!IsPaused; |
777 | d7288179 | pkanavos | foreach (var monitor in Monitors.Values) |
778 | d7288179 | pkanavos | { |
779 | d7288179 | pkanavos | monitor.Pause = IsPaused ; |
780 | d7288179 | pkanavos | } |
781 | d7288179 | pkanavos | _pollAgent.Pause = IsPaused; |
782 | d7288179 | pkanavos | _networkAgent.Pause = IsPaused; |
783 | d7288179 | pkanavos | |
784 | d7288179 | pkanavos | |
785 | d7288179 | pkanavos | } |
786 | d7288179 | pkanavos | |
787 | d7288179 | pkanavos | public void ExitPithos() |
788 | d7288179 | pkanavos | { |
789 | d7288179 | pkanavos | try |
790 | d7288179 | pkanavos | { |
791 | d7288179 | pkanavos | |
792 | d7288179 | pkanavos | foreach (var monitor in Monitors.Select(pair => pair.Value)) |
793 | d7288179 | pkanavos | { |
794 | d7288179 | pkanavos | monitor.Stop(); |
795 | d7288179 | pkanavos | } |
796 | d7288179 | pkanavos | |
797 | d7288179 | pkanavos | var view = GetView() as Window; |
798 | d7288179 | pkanavos | if (view != null) |
799 | d7288179 | pkanavos | view.Close(); |
800 | d7288179 | pkanavos | } |
801 | d7288179 | pkanavos | catch (Exception exc) |
802 | d7288179 | pkanavos | { |
803 | d7288179 | pkanavos | Log.Info("Exception while exiting", exc); |
804 | d7288179 | pkanavos | } |
805 | d7288179 | pkanavos | finally |
806 | d7288179 | pkanavos | { |
807 | d7288179 | pkanavos | Application.Current.Shutdown(); |
808 | d7288179 | pkanavos | } |
809 | d7288179 | pkanavos | } |
810 | d7288179 | pkanavos | |
811 | d7288179 | pkanavos | #endregion |
812 | d7288179 | pkanavos | |
813 | d7288179 | pkanavos | |
814 | d7288179 | pkanavos | private readonly Dictionary<PithosStatus, StatusInfo> _iconNames = new List<StatusInfo> |
815 | d7288179 | pkanavos | { |
816 | d7288179 | pkanavos | new StatusInfo(PithosStatus.InSynch, "All files up to date", "TrayInSynch"), |
817 | d7288179 | pkanavos | new StatusInfo(PithosStatus.PollSyncing, "Polling Files", "TraySynching"), |
818 | d7288179 | pkanavos | new StatusInfo(PithosStatus.LocalSyncing, "Syncing Files", "TraySynching"), |
819 | d7288179 | pkanavos | new StatusInfo(PithosStatus.SyncPaused, "Sync Paused", "TraySyncPaused") |
820 | d7288179 | pkanavos | }.ToDictionary(s => s.Status); |
821 | d7288179 | pkanavos | |
822 | d7288179 | pkanavos | readonly IWindowManager _windowManager; |
823 | d7288179 | pkanavos | |
824 | d7288179 | pkanavos | //private int _syncCount=0; |
825 | d7288179 | pkanavos | |
826 | d7288179 | pkanavos | |
827 | d7288179 | pkanavos | private PithosStatus _pithosStatus = PithosStatus.Disconnected; |
828 | d7288179 | pkanavos | |
829 | d7288179 | pkanavos | public void SetPithosStatus(PithosStatus status) |
830 | d7288179 | pkanavos | { |
831 | d7288179 | pkanavos | if (_pithosStatus == PithosStatus.LocalSyncing && status == PithosStatus.PollComplete) |
832 | d7288179 | pkanavos | return; |
833 | d7288179 | pkanavos | if (_pithosStatus == PithosStatus.PollSyncing && status == PithosStatus.LocalComplete) |
834 | d7288179 | pkanavos | return; |
835 | d7288179 | pkanavos | if (status == PithosStatus.LocalComplete || status == PithosStatus.PollComplete) |
836 | d7288179 | pkanavos | _pithosStatus = PithosStatus.InSynch; |
837 | d7288179 | pkanavos | else |
838 | d7288179 | pkanavos | _pithosStatus = status; |
839 | d7288179 | pkanavos | UpdateStatus(); |
840 | d7288179 | pkanavos | } |
841 | d7288179 | pkanavos | |
842 | d7288179 | pkanavos | public void SetPithosStatus(PithosStatus status,string message) |
843 | d7288179 | pkanavos | { |
844 | d7288179 | pkanavos | StatusMessage = message; |
845 | d7288179 | pkanavos | SetPithosStatus(status); |
846 | d7288179 | pkanavos | } |
847 | d7288179 | pkanavos | |
848 | d7288179 | pkanavos | /* public Notifier GetNotifier(Notification startNotification, Notification endNotification) |
849 | d7288179 | pkanavos | { |
850 | d7288179 | pkanavos | return new Notifier(this, startNotification, endNotification); |
851 | d7288179 | pkanavos | }*/ |
852 | d7288179 | pkanavos | |
853 | cfb09103 | pkanavos | public Notifier GetNotifier(string startMessage, string endMessage, bool isActive=true,params object[] args) |
854 | d7288179 | pkanavos | { |
855 | cfb09103 | pkanavos | return isActive?new Notifier(this, |
856 | e7fb3ef2 | George Pantazis | new StatusNotification(String.Format(startMessage,args)), |
857 | cfb09103 | pkanavos | new StatusNotification(String.Format(endMessage,args))) |
858 | cfb09103 | pkanavos | :new Notifier(this,(Notification) null,null); |
859 | d7288179 | pkanavos | } |
860 | d7288179 | pkanavos | |
861 | d7288179 | pkanavos | |
862 | d7288179 | pkanavos | ///<summary> |
863 | d7288179 | pkanavos | /// Updates the visual status indicators of the application depending on status changes, e.g. icon, stat |
864 | d7288179 | pkanavos | ///</summary> |
865 | d7288179 | pkanavos | public void UpdateStatus() |
866 | d7288179 | pkanavos | { |
867 | d7288179 | pkanavos | |
868 | d7288179 | pkanavos | if (_iconNames.ContainsKey(_pithosStatus)) |
869 | d7288179 | pkanavos | { |
870 | d7288179 | pkanavos | var info = _iconNames[_pithosStatus]; |
871 | d7288179 | pkanavos | StatusIcon = String.Format(@"../Images/{0}.ico", info.IconName); |
872 | d7288179 | pkanavos | } |
873 | d7288179 | pkanavos | |
874 | d7288179 | pkanavos | if (_pithosStatus == PithosStatus.InSynch) |
875 | d7288179 | pkanavos | StatusMessage = "All files up to date"; |
876 | d7288179 | pkanavos | } |
877 | d7288179 | pkanavos | |
878 | d7288179 | pkanavos | |
879 | d7288179 | pkanavos | |
880 | dd5f5163 | pkanavos | public async Task StartMonitor(PithosMonitor monitor,int retries=0) |
881 | dd5f5163 | pkanavos | { |
882 | dd5f5163 | pkanavos | using (log4net.ThreadContext.Stacks["Monitor"].Push("Start")) |
883 | dd5f5163 | pkanavos | { |
884 | dd5f5163 | pkanavos | try |
885 | dd5f5163 | pkanavos | { |
886 | dd5f5163 | pkanavos | Log.InfoFormat("Start Monitoring {0}", monitor.UserName); |
887 | dd5f5163 | pkanavos | |
888 | dd5f5163 | pkanavos | await monitor.Start(); |
889 | dd5f5163 | pkanavos | } |
890 | dd5f5163 | pkanavos | catch (HttpRequestWithStatusException exc) |
891 | dd5f5163 | pkanavos | { |
892 | dd5f5163 | pkanavos | if (AbandonRetry(monitor, retries)) |
893 | dd5f5163 | pkanavos | return; |
894 | dd5f5163 | pkanavos | |
895 | dd5f5163 | pkanavos | //HttpStatusCode statusCode = HttpStatusCode.OK; |
896 | dd5f5163 | pkanavos | //var response = as HttpWebResponse; |
897 | dd5f5163 | pkanavos | //if (response != null) |
898 | dd5f5163 | pkanavos | var statusCode = exc.StatusCode;//response.StatusCode; |
899 | dd5f5163 | pkanavos | |
900 | dd5f5163 | pkanavos | switch (statusCode) |
901 | dd5f5163 | pkanavos | { |
902 | dd5f5163 | pkanavos | case HttpStatusCode.Unauthorized: |
903 | dd5f5163 | pkanavos | var message = String.Format("API Key Expired for {0}. Starting Renewal", |
904 | dd5f5163 | pkanavos | monitor.UserName); |
905 | dd5f5163 | pkanavos | Log.Error(message, exc); |
906 | dd5f5163 | pkanavos | var account = |
907 | dd5f5163 | pkanavos | Settings.Accounts.Find( |
908 | dd5f5163 | pkanavos | acc => acc.AccountKey == new Uri(monitor.AuthenticationUrl).Combine(monitor.UserName)); |
909 | dd5f5163 | pkanavos | account.IsExpired = true; |
910 | dd5f5163 | pkanavos | Settings.Save(); |
911 | dd5f5163 | pkanavos | Notify(new ExpirationNotification(account)); |
912 | dd5f5163 | pkanavos | //TryAuthorize(monitor.UserName, retries).Wait(); |
913 | dd5f5163 | pkanavos | break; |
914 | dd5f5163 | pkanavos | case HttpStatusCode.ProxyAuthenticationRequired: |
915 | dd5f5163 | pkanavos | TryAuthenticateProxy(monitor, retries); |
916 | dd5f5163 | pkanavos | break; |
917 | dd5f5163 | pkanavos | default: |
918 | dd5f5163 | pkanavos | TryLater(monitor, exc, retries); |
919 | dd5f5163 | pkanavos | break; |
920 | dd5f5163 | pkanavos | } |
921 | dd5f5163 | pkanavos | } |
922 | dd5f5163 | pkanavos | catch (Exception exc) |
923 | dd5f5163 | pkanavos | { |
924 | dd5f5163 | pkanavos | if (AbandonRetry(monitor, retries)) |
925 | dd5f5163 | pkanavos | return; |
926 | dd5f5163 | pkanavos | |
927 | dd5f5163 | pkanavos | TryLater(monitor, exc, retries); |
928 | dd5f5163 | pkanavos | } |
929 | dd5f5163 | pkanavos | } |
930 | dd5f5163 | pkanavos | |
931 | d7288179 | pkanavos | } |
932 | d7288179 | pkanavos | |
933 | dd5f5163 | pkanavos | private void TryAuthenticateProxy(PithosMonitor monitor,int retries) |
934 | d7288179 | pkanavos | { |
935 | 2115e2a5 | pkanavos | Execute.OnUIThread(async () => |
936 | d7288179 | pkanavos | { |
937 | d7288179 | pkanavos | var proxyAccount = IoC.Get<ProxyAccountViewModel>(); |
938 | d7288179 | pkanavos | proxyAccount.Settings = Settings; |
939 | d7288179 | pkanavos | if (true != _windowManager.ShowDialog(proxyAccount)) |
940 | d7288179 | pkanavos | return; |
941 | 2115e2a5 | pkanavos | await StartMonitor(monitor, retries); |
942 | d7288179 | pkanavos | NotifyOfPropertyChange(() => Accounts); |
943 | d7288179 | pkanavos | }); |
944 | d7288179 | pkanavos | } |
945 | d7288179 | pkanavos | |
946 | d7288179 | pkanavos | private bool AbandonRetry(PithosMonitor monitor, int retries) |
947 | d7288179 | pkanavos | { |
948 | d7288179 | pkanavos | if (retries > 3) |
949 | d7288179 | pkanavos | { |
950 | d7288179 | pkanavos | var message = String.Format("Monitoring of account {0} has failed too many times. Will not retry", |
951 | d7288179 | pkanavos | monitor.UserName); |
952 | d7288179 | pkanavos | _events.Publish(new Notification |
953 | d7288179 | pkanavos | {Title = "Account monitoring failed", Message = message, Level = TraceLevel.Error}); |
954 | d7288179 | pkanavos | return true; |
955 | d7288179 | pkanavos | } |
956 | d7288179 | pkanavos | return false; |
957 | d7288179 | pkanavos | } |
958 | d7288179 | pkanavos | |
959 | d7288179 | pkanavos | |
960 | d7288179 | pkanavos | private void TryLater(PithosMonitor monitor, Exception exc,int retries) |
961 | d7288179 | pkanavos | { |
962 | d7288179 | pkanavos | var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds"); |
963 | 2115e2a5 | pkanavos | |
964 | 2115e2a5 | pkanavos | TaskEx.Delay(10000).ContinueWith(t=>StartMonitor(monitor,retries+1)); |
965 | d7288179 | pkanavos | _events.Publish(new Notification |
966 | d7288179 | pkanavos | {Title = "Error", Message = message, Level = TraceLevel.Error}); |
967 | d7288179 | pkanavos | Log.Error(message, exc); |
968 | d7288179 | pkanavos | } |
969 | d7288179 | pkanavos | |
970 | d7288179 | pkanavos | |
971 | d7288179 | pkanavos | public void NotifyChange(string status, TraceLevel level=TraceLevel.Info) |
972 | d7288179 | pkanavos | { |
973 | d7288179 | pkanavos | StatusMessage = status; |
974 | d7288179 | pkanavos | |
975 | d7288179 | pkanavos | _events.Publish(new Notification { Title = "Pithos+", Message = status, Level = level }); |
976 | d7288179 | pkanavos | } |
977 | d7288179 | pkanavos | |
978 | d7288179 | pkanavos | public void NotifyChangedFile(string filePath) |
979 | d7288179 | pkanavos | { |
980 | d7288179 | pkanavos | if (RecentFiles.Any(e => e.FullPath == filePath)) |
981 | d7288179 | pkanavos | return; |
982 | d7288179 | pkanavos | |
983 | d7288179 | pkanavos | IProducerConsumerCollection<FileEntry> files=RecentFiles; |
984 | d7288179 | pkanavos | FileEntry popped; |
985 | d7288179 | pkanavos | while (files.Count > 5) |
986 | d7288179 | pkanavos | files.TryTake(out popped); |
987 | d7288179 | pkanavos | var entry = new FileEntry { FullPath = filePath }; |
988 | d7288179 | pkanavos | files.TryAdd(entry); |
989 | d7288179 | pkanavos | } |
990 | d7288179 | pkanavos | |
991 | d7288179 | pkanavos | public void NotifyAccount(AccountInfo account) |
992 | d7288179 | pkanavos | { |
993 | d7288179 | pkanavos | if (account== null) |
994 | d7288179 | pkanavos | return; |
995 | d7288179 | pkanavos | //TODO: What happens to an existing account whose Token has changed? |
996 | d7288179 | pkanavos | account.SiteUri= String.Format("{0}/ui/?token={1}&user={2}", |
997 | d7288179 | pkanavos | account.SiteUri, Uri.EscapeDataString(account.Token), |
998 | d7288179 | pkanavos | Uri.EscapeDataString(account.UserName)); |
999 | d7288179 | pkanavos | |
1000 | d7288179 | pkanavos | if (!Accounts.Any(item => item.UserName == account.UserName && item.SiteUri == account.SiteUri)) |
1001 | d7288179 | pkanavos | Accounts.TryAdd(account); |
1002 | d7288179 | pkanavos | |
1003 | d7288179 | pkanavos | } |
1004 | d7288179 | pkanavos | |
1005 | d7288179 | pkanavos | public void NotifyConflicts(IEnumerable<FileSystemInfo> conflictFiles, string message) |
1006 | d7288179 | pkanavos | { |
1007 | d7288179 | pkanavos | if (conflictFiles == null) |
1008 | d7288179 | pkanavos | return; |
1009 | d7288179 | pkanavos | //Convert to list to avoid multiple iterations |
1010 | d7288179 | pkanavos | var files = conflictFiles.ToList(); |
1011 | d7288179 | pkanavos | if (files.Count==0) |
1012 | d7288179 | pkanavos | return; |
1013 | d7288179 | pkanavos | |
1014 | d7288179 | pkanavos | UpdateStatus(); |
1015 | d7288179 | pkanavos | //TODO: Create a more specific message. For now, just show a warning |
1016 | d7288179 | pkanavos | NotifyForFiles(files,message,TraceLevel.Warning); |
1017 | d7288179 | pkanavos | |
1018 | d7288179 | pkanavos | } |
1019 | d7288179 | pkanavos | |
1020 | d7288179 | pkanavos | public void NotifyForFiles(IEnumerable<FileSystemInfo> files, string message,TraceLevel level=TraceLevel.Info) |
1021 | d7288179 | pkanavos | { |
1022 | d7288179 | pkanavos | if (files == null) |
1023 | d7288179 | pkanavos | return; |
1024 | d7288179 | pkanavos | if (!files.Any()) |
1025 | d7288179 | pkanavos | return; |
1026 | d7288179 | pkanavos | |
1027 | d7288179 | pkanavos | StatusMessage = message; |
1028 | d7288179 | pkanavos | |
1029 | d7288179 | pkanavos | _events.Publish(new Notification { Title = "Pithos+", Message = message, Level = level}); |
1030 | d7288179 | pkanavos | } |
1031 | d7288179 | pkanavos | |
1032 | d7288179 | pkanavos | public void Notify(Notification notification) |
1033 | d7288179 | pkanavos | { |
1034 | d7288179 | pkanavos | TaskEx.Run(()=> _events.Publish(notification)); |
1035 | d7288179 | pkanavos | } |
1036 | d7288179 | pkanavos | |
1037 | d7288179 | pkanavos | |
1038 | d7288179 | pkanavos | public void RemoveMonitor(string serverUrl,string accountName) |
1039 | d7288179 | pkanavos | { |
1040 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(accountName)) |
1041 | d7288179 | pkanavos | return; |
1042 | d7288179 | pkanavos | |
1043 | d7288179 | pkanavos | var accountInfo=_accounts.FirstOrDefault(account => account.UserName == accountName && account.StorageUri.ToString().StartsWith(serverUrl)); |
1044 | d7288179 | pkanavos | if (accountInfo != null) |
1045 | d7288179 | pkanavos | { |
1046 | d7288179 | pkanavos | _accounts.TryRemove(accountInfo); |
1047 | d7288179 | pkanavos | _pollAgent.RemoveAccount(accountInfo); |
1048 | d7288179 | pkanavos | } |
1049 | d7288179 | pkanavos | |
1050 | d7288179 | pkanavos | var accountKey = new Uri(serverUrl).Combine(accountName); |
1051 | d7288179 | pkanavos | PithosMonitor monitor; |
1052 | d7288179 | pkanavos | if (Monitors.TryRemove(accountKey, out monitor)) |
1053 | d7288179 | pkanavos | { |
1054 | d7288179 | pkanavos | monitor.Stop(); |
1055 | d7288179 | pkanavos | //TODO: Also remove any pending actions for this account |
1056 | d7288179 | pkanavos | //from the network queue |
1057 | d7288179 | pkanavos | } |
1058 | d7288179 | pkanavos | } |
1059 | d7288179 | pkanavos | |
1060 | d7288179 | pkanavos | public void RefreshOverlays() |
1061 | d7288179 | pkanavos | { |
1062 | d7288179 | pkanavos | foreach (var pair in Monitors) |
1063 | d7288179 | pkanavos | { |
1064 | d7288179 | pkanavos | var monitor = pair.Value; |
1065 | d7288179 | pkanavos | |
1066 | d7288179 | pkanavos | var path = monitor.RootPath; |
1067 | d7288179 | pkanavos | |
1068 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(path)) |
1069 | d7288179 | pkanavos | continue; |
1070 | d7288179 | pkanavos | |
1071 | d7288179 | pkanavos | if (!Directory.Exists(path) && !File.Exists(path)) |
1072 | d7288179 | pkanavos | continue; |
1073 | d7288179 | pkanavos | |
1074 | d7288179 | pkanavos | IntPtr pathPointer = Marshal.StringToCoTaskMemAuto(path); |
1075 | d7288179 | pkanavos | |
1076 | d7288179 | pkanavos | try |
1077 | d7288179 | pkanavos | { |
1078 | d7288179 | pkanavos | NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM, |
1079 | d7288179 | pkanavos | HChangeNotifyFlags.SHCNF_PATHW | HChangeNotifyFlags.SHCNF_FLUSHNOWAIT, |
1080 | d7288179 | pkanavos | pathPointer, IntPtr.Zero); |
1081 | d7288179 | pkanavos | } |
1082 | d7288179 | pkanavos | finally |
1083 | d7288179 | pkanavos | { |
1084 | d7288179 | pkanavos | Marshal.FreeHGlobal(pathPointer); |
1085 | d7288179 | pkanavos | } |
1086 | d7288179 | pkanavos | } |
1087 | d7288179 | pkanavos | } |
1088 | d7288179 | pkanavos | |
1089 | d7288179 | pkanavos | #region Event Handlers |
1090 | d7288179 | pkanavos | |
1091 | d7288179 | pkanavos | public void Handle(SelectiveSynchChanges message) |
1092 | d7288179 | pkanavos | { |
1093 | d7288179 | pkanavos | TaskEx.Run(() => |
1094 | d7288179 | pkanavos | { |
1095 | d7288179 | pkanavos | PithosMonitor monitor; |
1096 | d7288179 | pkanavos | if (Monitors.TryGetValue(message.Account.AccountKey, out monitor)) |
1097 | d7288179 | pkanavos | { |
1098 | d7288179 | pkanavos | Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled); |
1099 | d7288179 | pkanavos | monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed); |
1100 | d7288179 | pkanavos | } |
1101 | d7288179 | pkanavos | |
1102 | d7288179 | pkanavos | var account = Accounts.FirstOrDefault(acc => acc.AccountKey == message.Account.AccountKey); |
1103 | d7288179 | pkanavos | if (account != null) |
1104 | d7288179 | pkanavos | { |
1105 | d7288179 | pkanavos | var added=monitor.UrisToFilePaths(message.Added); |
1106 | d7288179 | pkanavos | _pollAgent.SynchNow(added); |
1107 | d7288179 | pkanavos | } |
1108 | d7288179 | pkanavos | }); |
1109 | d7288179 | pkanavos | |
1110 | d7288179 | pkanavos | } |
1111 | d7288179 | pkanavos | |
1112 | d7288179 | pkanavos | |
1113 | d7288179 | pkanavos | private bool _pollStarted; |
1114 | d7288179 | pkanavos | private Sparkle _sparkle; |
1115 | d7288179 | pkanavos | private bool _manualUpgradeCheck; |
1116 | f3b6a335 | pkanavos | private int _progress; |
1117 | d7288179 | pkanavos | |
1118 | d7288179 | pkanavos | //SMELL: Doing so much work for notifications in the shell is wrong |
1119 | d7288179 | pkanavos | //The notifications should be moved to their own view/viewmodel pair |
1120 | d7288179 | pkanavos | //and different templates should be used for different message types |
1121 | d7288179 | pkanavos | //This will also allow the addition of extra functionality, eg. actions |
1122 | d7288179 | pkanavos | // |
1123 | d7288179 | pkanavos | public void Handle(Notification notification) |
1124 | d7288179 | pkanavos | { |
1125 | d7288179 | pkanavos | UpdateStatus(); |
1126 | d7288179 | pkanavos | |
1127 | d7288179 | pkanavos | if (!Settings.ShowDesktopNotifications) |
1128 | d7288179 | pkanavos | return; |
1129 | d7288179 | pkanavos | |
1130 | f3b6a335 | pkanavos | var progress = notification as ProgressNotification; |
1131 | f3b6a335 | pkanavos | |
1132 | f3b6a335 | pkanavos | |
1133 | f3b6a335 | pkanavos | if (progress != null) |
1134 | f3b6a335 | pkanavos | { |
1135 | f3b6a335 | pkanavos | double percentage = (progress.TotalBlocks == progress.Block) ? 1 |
1136 | f3b6a335 | pkanavos | : (progress.Block + progress.BlockPercentage / 100.0) / (double)progress.TotalBlocks; |
1137 | f3b6a335 | pkanavos | StatusMessage = String.Format("{0} {1:p2} of {2} - {3}", |
1138 | f3b6a335 | pkanavos | progress.Action, |
1139 | f3b6a335 | pkanavos | percentage, |
1140 | f3b6a335 | pkanavos | progress.FileSize.ToByteSize(), |
1141 | f3b6a335 | pkanavos | progress.FileName); |
1142 | f3b6a335 | pkanavos | Progress = (int)(percentage * 100); |
1143 | f3b6a335 | pkanavos | return; |
1144 | f3b6a335 | pkanavos | } |
1145 | f3b6a335 | pkanavos | |
1146 | f3b6a335 | pkanavos | //If this is not a progress bar message, set the bar to 0 |
1147 | f3b6a335 | pkanavos | Progress = 0; |
1148 | f3b6a335 | pkanavos | |
1149 | f3b6a335 | pkanavos | if (notification is PollNotification) |
1150 | d7288179 | pkanavos | { |
1151 | d7288179 | pkanavos | _pollStarted = true; |
1152 | d7288179 | pkanavos | return; |
1153 | d7288179 | pkanavos | } |
1154 | d7288179 | pkanavos | if (notification is CloudNotification) |
1155 | d7288179 | pkanavos | { |
1156 | d7288179 | pkanavos | if (!_pollStarted) |
1157 | d7288179 | pkanavos | return; |
1158 | d7288179 | pkanavos | _pollStarted= false; |
1159 | d7288179 | pkanavos | notification.Title = "Pithos+"; |
1160 | d7288179 | pkanavos | notification.Message = "Start Synchronisation"; |
1161 | d7288179 | pkanavos | } |
1162 | d7288179 | pkanavos | |
1163 | d7288179 | pkanavos | var deleteNotification = notification as CloudDeleteNotification; |
1164 | d7288179 | pkanavos | if (deleteNotification != null) |
1165 | d7288179 | pkanavos | { |
1166 | d7288179 | pkanavos | StatusMessage = String.Format("Deleted {0}", deleteNotification.Data.Name); |
1167 | d7288179 | pkanavos | return; |
1168 | d7288179 | pkanavos | } |
1169 | d7288179 | pkanavos | |
1170 | d7288179 | pkanavos | |
1171 | d7288179 | pkanavos | var info = notification as StatusNotification; |
1172 | d7288179 | pkanavos | if (info != null) |
1173 | d7288179 | pkanavos | { |
1174 | d7288179 | pkanavos | StatusMessage = info.Title; |
1175 | d7288179 | pkanavos | return; |
1176 | d7288179 | pkanavos | } |
1177 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(notification.Message) && String.IsNullOrWhiteSpace(notification.Title)) |
1178 | d7288179 | pkanavos | return; |
1179 | d7288179 | pkanavos | |
1180 | d7288179 | pkanavos | if (notification.Level <= TraceLevel.Warning) |
1181 | d7288179 | pkanavos | ShowBalloonFor(notification); |
1182 | d7288179 | pkanavos | } |
1183 | d7288179 | pkanavos | |
1184 | d7288179 | pkanavos | private void ShowBalloonFor(Notification notification) |
1185 | d7288179 | pkanavos | { |
1186 | d7288179 | pkanavos | Contract.Requires(notification!=null); |
1187 | d7288179 | pkanavos | |
1188 | d7288179 | pkanavos | if (!Settings.ShowDesktopNotifications) |
1189 | d7288179 | pkanavos | return; |
1190 | d7288179 | pkanavos | |
1191 | d7288179 | pkanavos | BalloonIcon icon; |
1192 | d7288179 | pkanavos | switch (notification.Level) |
1193 | d7288179 | pkanavos | { |
1194 | d7288179 | pkanavos | case TraceLevel.Verbose: |
1195 | d7288179 | pkanavos | return; |
1196 | d7288179 | pkanavos | case TraceLevel.Info: |
1197 | d7288179 | pkanavos | icon = BalloonIcon.Info; |
1198 | d7288179 | pkanavos | break; |
1199 | d7288179 | pkanavos | case TraceLevel.Error: |
1200 | d7288179 | pkanavos | icon = BalloonIcon.Error; |
1201 | d7288179 | pkanavos | break; |
1202 | d7288179 | pkanavos | case TraceLevel.Warning: |
1203 | d7288179 | pkanavos | icon = BalloonIcon.Warning; |
1204 | d7288179 | pkanavos | break; |
1205 | d7288179 | pkanavos | default: |
1206 | d7288179 | pkanavos | return; |
1207 | d7288179 | pkanavos | } |
1208 | d7288179 | pkanavos | |
1209 | d7288179 | pkanavos | var tv = (ShellView) GetView(); |
1210 | d7288179 | pkanavos | System.Action clickAction = null; |
1211 | d7288179 | pkanavos | if (notification is ExpirationNotification) |
1212 | d7288179 | pkanavos | { |
1213 | d7288179 | pkanavos | clickAction = () => ShowPreferences("AccountTab"); |
1214 | d7288179 | pkanavos | } |
1215 | d7288179 | pkanavos | var balloon = new PithosBalloon |
1216 | d7288179 | pkanavos | { |
1217 | d7288179 | pkanavos | Title = notification.Title, |
1218 | d7288179 | pkanavos | Message = notification.Message, |
1219 | d7288179 | pkanavos | Icon = icon, |
1220 | d7288179 | pkanavos | ClickAction = clickAction |
1221 | d7288179 | pkanavos | }; |
1222 | d7288179 | pkanavos | tv.TaskbarView.ShowCustomBalloon(balloon, PopupAnimation.Fade, 4000); |
1223 | d7288179 | pkanavos | } |
1224 | d7288179 | pkanavos | |
1225 | d7288179 | pkanavos | #endregion |
1226 | d7288179 | pkanavos | |
1227 | d7288179 | pkanavos | public void Handle(ShowFilePropertiesEvent message) |
1228 | d7288179 | pkanavos | { |
1229 | d7288179 | pkanavos | if (message == null) |
1230 | d7288179 | pkanavos | throw new ArgumentNullException("message"); |
1231 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(message.FileName) ) |
1232 | d7288179 | pkanavos | throw new ArgumentException("message"); |
1233 | d7288179 | pkanavos | Contract.EndContractBlock(); |
1234 | d7288179 | pkanavos | |
1235 | d7288179 | pkanavos | var fileName = message.FileName; |
1236 | d7288179 | pkanavos | //TODO: Display file properties for non-container folders |
1237 | d7288179 | pkanavos | if (File.Exists(fileName)) |
1238 | d7288179 | pkanavos | //Retrieve the full name with exact casing. Pithos names are case sensitive |
1239 | d7288179 | pkanavos | ShowFileProperties(FileInfoExtensions.GetProperFilePathCapitalization(fileName)); |
1240 | d7288179 | pkanavos | else if (Directory.Exists(fileName)) |
1241 | d7288179 | pkanavos | //Retrieve the full name with exact casing. Pithos names are case sensitive |
1242 | d7288179 | pkanavos | { |
1243 | d7288179 | pkanavos | var path = FileInfoExtensions.GetProperDirectoryCapitalization(fileName); |
1244 | d7288179 | pkanavos | if (IsContainer(path)) |
1245 | d7288179 | pkanavos | ShowContainerProperties(path); |
1246 | d7288179 | pkanavos | else |
1247 | d7288179 | pkanavos | ShowFileProperties(path); |
1248 | d7288179 | pkanavos | } |
1249 | d7288179 | pkanavos | } |
1250 | d7288179 | pkanavos | |
1251 | d7288179 | pkanavos | private bool IsContainer(string path) |
1252 | d7288179 | pkanavos | { |
1253 | d7288179 | pkanavos | var matchingFolders = from account in _accounts |
1254 | d7288179 | pkanavos | from rootFolder in Directory.GetDirectories(account.AccountPath) |
1255 | d7288179 | pkanavos | where rootFolder.Equals(path, StringComparison.InvariantCultureIgnoreCase) |
1256 | d7288179 | pkanavos | select rootFolder; |
1257 | d7288179 | pkanavos | return matchingFolders.Any(); |
1258 | d7288179 | pkanavos | } |
1259 | d7288179 | pkanavos | |
1260 | d7288179 | pkanavos | public FileStatus GetFileStatus(string localFileName) |
1261 | d7288179 | pkanavos | { |
1262 | d7288179 | pkanavos | if (String.IsNullOrWhiteSpace(localFileName)) |
1263 | d7288179 | pkanavos | throw new ArgumentNullException("localFileName"); |
1264 | d7288179 | pkanavos | Contract.EndContractBlock(); |
1265 | d7288179 | pkanavos | |
1266 | d7288179 | pkanavos | var statusKeeper = IoC.Get<IStatusKeeper>(); |
1267 | d7288179 | pkanavos | var status=statusKeeper.GetFileStatus(localFileName); |
1268 | d7288179 | pkanavos | return status; |
1269 | d7288179 | pkanavos | } |
1270 | d7288179 | pkanavos | |
1271 | d7288179 | pkanavos | public void RemoveAccountFromDatabase(AccountSettings account) |
1272 | d7288179 | pkanavos | { |
1273 | d7288179 | pkanavos | var statusKeeper = IoC.Get<IStatusKeeper>(); |
1274 | d7288179 | pkanavos | statusKeeper.ClearFolderStatus(account.RootPath); |
1275 | d7288179 | pkanavos | } |
1276 | d7288179 | pkanavos | } |
1277 | d7288179 | pkanavos | } |