Revision c636df1f

b/trunk/Pithos.Client.WPF/Preferences/AccountViewModel.cs
45 45
namespace Pithos.Client.WPF.Preferences
46 46
{
47 47
    /// <summary>
48
    /// ViewModel wrapper for an account
48
    /// ViewModel wrapper for a settings Account object with change notifications
49 49
    /// </summary>
50 50
    public class AccountViewModel:PropertyChangedBase
51 51
    {
......
120 120
            set 
121 121
            {
122 122
                _account.ApiKey = value;
123
                IsExpired = false;
123 124
                NotifyOfPropertyChange(() => ApiKey);
124 125
            }
125 126
        }
b/trunk/Pithos.Client.WPF/Preferences/AddAccountViewModel.cs
41 41
#endregion
42 42
using System;
43 43
using System.Collections.Generic;
44
using System.ComponentModel;
45 44
using System.ComponentModel.Composition;
46
using System.IO;
47
using System.Linq;
48
using System.Net;
49
using System.Text;
50 45
using System.Threading.Tasks;
51 46
using System.Windows;
52
using System.Windows.Controls;
53 47
using System.Windows.Forms;
54
using Caliburn.Micro;
55 48
using Pithos.Client.WPF.Properties;
56
using Pithos.Core;
57 49
using Pithos.Network;
58 50
using MessageBox = System.Windows.MessageBox;
59 51
using Screen = Caliburn.Micro.Screen;
......
178 170

  
179 171
        public void SelectAccount()
180 172
        {
181
            using (var dlg = new FolderBrowserDialog{Description="Please select a folder to store local files. Pithos will create a new folder called Okeanos under the folder you specify."})
173
            using (var dlg = new FolderBrowserDialog{Description=Resources.AddAccountViewModel_SelectAccount_Please_select_a_folder})
182 174
            {
183 175
                //Ask the user to select a folder
184 176
                //Note: We need a parent window here, which we retrieve with GetView            
......
219 211
            {
220 212
                ClearBusy();
221 213
                
222
                (this.GetView() as Window).Activate();
214
                ((Window) GetView()).Activate();
223 215
            }
224 216

  
225 217
        }
......
310 302
            {
311 303
                SetBusy("Validating Credentials", "");
312 304
                var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer,/*Proxy=Proxy */};                
313
                var containers = await TaskEx.Run(() =>
314
                                                      {
315
                                                          client.Authenticate();
316
                                                          return client.ListContainers(AccountName);
317
                                                      });
305
                await TaskEx.Run(() =>
306
                                     {
307
                                         client.Authenticate();
308
                                         return client.ListContainers(AccountName);
309
                                     });
318 310
                HasValidCredentials = true;
319 311
                ValidationMessage = "Credentials Validated";
320 312
            }
321
/*
322
            catch (AggregateException exc)
323
            {
324
                exc.Handle(ex=>
325
                               {
326
                                   HasValidCredentials = false;
327
                                   MessageBox.Show("The account is not valid", "Account Error", MessageBoxButton.OK, MessageBoxImage.Stop);                                                   
328
                               });
329
            }
330
*/
331 313
            catch
332 314
            {
333 315
                HasValidCredentials = false;
b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
40 40
 */
41 41
#endregion
42 42

  
43
// </copyright>
44
// -----------------------------------------------------------------------
45 43

  
46 44
using System.Collections.Concurrent;
47 45
using System.ComponentModel.Composition;
48 46
using System.Diagnostics;
49 47
using System.IO;
50
using System.Net;
51 48
using System.Threading.Tasks;
52 49
using System.Windows;
53 50
using System.Windows.Forms;
54 51
using Caliburn.Micro;
55 52
using Pithos.Client.WPF.Configuration;
53
using Pithos.Client.WPF.Properties;
56 54
using Pithos.Client.WPF.SelectiveSynch;
57 55
using Pithos.Core;
58 56
using Pithos.Interfaces;
......
63 61
namespace Pithos.Client.WPF.Preferences
64 62
{
65 63
    /// <summary>
66
    /// TODO: Update summary.
64
    /// The preferences screen displays user and account settings and updates the PithosMonitor
65
    /// classes when account settings change.
67 66
    /// </summary>
67
    /// <remarks>
68
    /// The class is a single ViewModel for all Preferences tabs. It can be broken in separate
69
    /// ViewModels, one for each tab.
70
    /// </remarks>
68 71
    [Export]
69 72
    public class PreferencesViewModel : Screen
70 73
    {
71
        private IEventAggregator _events;
74
        private readonly IEventAggregator _events;
72 75

  
73 76
        //Logging in the Pithos client is provided by log4net
74 77
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
......
102 105

  
103 106
        public PreferencesViewModel(IWindowManager windowManager, IEventAggregator events, ShellViewModel shell, PithosSettings settings, string currentTab)
104 107
        {
108
            // ReSharper disable DoNotCallOverridableMethodsInConstructor
109
            //Caliburn.Micro uses DisplayName for the view's title
110
            DisplayName = "Pithos Preferences";
111
            // ReSharper restore DoNotCallOverridableMethodsInConstructor
112

  
105 113
            _windowManager = windowManager;
106 114
            _events = events;
107 115

  
108
            DisplayName = "Pithos Preferences";
109 116
            Shell = shell;
110 117
            
111 118
            Settings=settings;
......
193 200
            set
194 201
            {
195 202
                if (value<0)
196
                    throw new ArgumentOutOfRangeException("value","The Startup Delay must be greater or equal to 0");
203
                    throw new ArgumentOutOfRangeException("value",Resources.PreferencesViewModel_StartupDelay_Greater_or_equal_to_0);
197 204
                Settings.StartupDelay = TimeSpan.FromMinutes(value);
198 205
                NotifyOfPropertyChange(()=>StartupDelay);
199 206
            }
......
222 229
        {
223 230
            _events.Publish(new Notification { Title = "Authorization failed", Message = "Your API Key has probably expired. You will be directed to a page where you can renew it", Level = TraceLevel.Error });
224 231

  
225
            //var userName = CurrentAccount.AccountName;
226 232
            try
227 233
            {
228 234

  
229 235
                var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
230

  
236
                //The server will return credentials for a different account, not just the current account
237
                //We need to find the correct account first
231 238
                var account = Accounts.First(act => act.AccountName == credentials.UserName);
232
                //The server may return credentials for a different account
233
                var monitor =  Shell.Monitors[account.AccountName];
234
                account.ApiKey = credentials.Password;
235
                monitor.ApiKey = credentials.Password;
239
                account.ApiKey = credentials.Password;                
236 240
                account.IsExpired = false;
237 241
                Settings.Save();
238 242
                TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));
......
334 338
                                        IsActive=wizard.IsAccountActive
335 339
                                    };
336 340
               Settings.Accounts.Add(newAccount);
337
               var accountVM = new AccountViewModel(newAccount);
338
               (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
339
               CurrentAccount = accountVM;
341
               var accountVm = new AccountViewModel(newAccount);
342
               (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVm);
343
               CurrentAccount = accountVm;
340 344
               NotifyOfPropertyChange(() => Accounts);
341 345
               NotifyOfPropertyChange(() => Settings);   
342 346
           }
......
441 445
        }*/
442 446

  
443 447
        private AccountViewModel _currentAccount;
444
        private IWindowManager _windowManager;
445
        private string _shortcutPath;
448
        private readonly IWindowManager _windowManager;
449
        private readonly string _shortcutPath;
446 450

  
447 451

  
448 452
        
......
517 521
                    Directory.Delete(oldPath, true);
518 522

  
519 523
                    //We also need to change the path of the existing file states
520
                    if (monitor != null)
521
                        monitor.MoveFileStates(oldPath, newPath);
524
                    monitor.MoveFileStates(oldPath, newPath);
522 525
                }
523 526
            }
524 527
            //Replace the old rootpath with the new
b/trunk/Pithos.Client.WPF/Properties/Resources.Designer.cs
1 1
//------------------------------------------------------------------------------
2 2
// <auto-generated>
3 3
//     This code was generated by a tool.
4
//     Runtime Version:4.0.30319.235
4
//     Runtime Version:4.0.30319.488
5 5
//
6 6
//     Changes to this file may cause incorrect behavior and will be lost if
7 7
//     the code is regenerated.
......
59 59
                resourceCulture = value;
60 60
            }
61 61
        }
62
        
63
        /// <summary>
64
        ///   Looks up a localized string similar to Please select a folder to store local files. Pithos will create a new folder called Okeanos under the folder you specify..
65
        /// </summary>
66
        internal static string AddAccountViewModel_SelectAccount_Please_select_a_folder {
67
            get {
68
                return ResourceManager.GetString("AddAccountViewModel_SelectAccount_Please_select_a_folder", resourceCulture);
69
            }
70
        }
71
        
72
        /// <summary>
73
        ///   Looks up a localized string similar to The Startup Delay must be greater or equal to 0.
74
        /// </summary>
75
        internal static string PreferencesViewModel_StartupDelay_Greater_or_equal_to_0 {
76
            get {
77
                return ResourceManager.GetString("PreferencesViewModel_StartupDelay_Greater_or_equal_to_0", resourceCulture);
78
            }
79
        }
62 80
    }
63 81
}
b/trunk/Pithos.Client.WPF/Properties/Resources.resx
114 114
  <resheader name="writer">
115 115
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116 116
  </resheader>
117
	<data name="PreferencesViewModel_StartupDelay_Greater_or_equal_to_0">
118
		<value xml:space="preserve">The Startup Delay must be greater or equal to 0</value>
119
	</data>
120
	<data name="AddAccountViewModel_SelectAccount_Please_select_a_folder">
121
		<value xml:space="preserve">Please select a folder to store local files. Pithos will create a new folder called Okeanos under the folder you specify.</value>
122
	</data>
117 123
</root>
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
232 232
				if (_monitors.TryGetValue(accountName, out monitor))
233 233
				{
234 234
					//If the account is active
235
					if (account.IsActive)
236
						//Start the monitor. It's OK to start an already started monitor,
237
						//it will just ignore the call                        
238
						StartMonitor(monitor).Wait();                        
239
					else
240
					{
241
						//If the account is inactive
242
						//Stop and remove the monitor
243
						RemoveMonitor(accountName);
244
					}
235
                    if (account.IsActive)
236
                    {
237
                        //The Api Key may have changed throuth the Preferences dialog
238
                        monitor.ApiKey = account.ApiKey;
239
						Debug.Assert(monitor.StatusNotification == this,"An existing monitor should already have a StatusNotification service object");
240
                        monitor.RootPath = account.RootPath;
241
                        //Start the monitor. It's OK to start an already started monitor,
242
                        //it will just ignore the call                        
243
                        StartMonitor(monitor).Wait();
244
                    }
245
                    else
246
                    {
247
                        //If the account is inactive
248
                        //Stop and remove the monitor
249
                        RemoveMonitor(accountName);
250
                    }
245 251
					return;
246 252
				}
247 253

  
b/trunk/Pithos.Core/PithosMonitor.cs
40 40
 */
41 41
#endregion
42 42
using System;
43
using System.Collections.Concurrent;
44 43
using System.Collections.Generic;
45 44
using System.ComponentModel.Composition;
46
using System.Diagnostics;
47 45
using System.Diagnostics.Contracts;
48 46
using System.IO;
49 47
using System.Linq;
50
using System.Net;
51
using System.Net.NetworkInformation;
52
using System.Security.Cryptography;
53
using System.ServiceModel.Description;
54
using System.Text;
55 48
using System.Threading;
56 49
using System.Threading.Tasks;
57
using Castle.ActiveRecord.Queries;
58
using Microsoft.WindowsAPICodePack.Net;
59 50
using Pithos.Core.Agents;
60 51
using Pithos.Interfaces;
61
using System.ServiceModel;
62 52
using Pithos.Network;
63 53
using log4net;
64 54

  
......
211 201
                    return;
212 202
            }
213 203
            _cancellationSource = new CancellationTokenSource();
214
            
215 204

  
216
            CloudClient=new CloudFilesClient(UserName,ApiKey);
217
            CloudClient.UsePithos = true;
218
            CloudClient.AuthenticationUrl = this.AuthenticationUrl;            
205

  
206
            CloudClient = new CloudFilesClient(UserName, ApiKey)
207
                              {UsePithos = true, AuthenticationUrl = AuthenticationUrl};
208

  
219 209

  
220 210
            _accountInfo = CloudClient.Authenticate();            
221 211
            _accountInfo.SiteUri = AuthenticationUrl;
......
259 249
            var pithosContainers = new List<string>{ FolderConstants.TrashContainer,FolderConstants.PithosContainer};
260 250
            foreach (var container in pithosContainers)
261 251
            {                
262
                var info=CloudClient.GetContainerInfo(this.UserName, container);
252
                var info=CloudClient.GetContainerInfo(UserName, container);
263 253
                if (info == ContainerInfo.Empty)
264 254
                {
265
                    CloudClient.CreateContainer(this.UserName, container);
266
                    info = CloudClient.GetContainerInfo(this.UserName, container);
255
                    CloudClient.CreateContainer(UserName, container);
256
                    info = CloudClient.GetContainerInfo(UserName, container);
267 257
                }
268 258
                _blockSize = info.BlockSize;
269 259
                _blockHash = info.BlockHash;
......
276 266

  
277 267
        private void IndexLocalFiles()
278 268
        {
279
            StatusNotification.NotifyChange("Indexing Local Files",TraceLevel.Info);
280
            using (log4net.ThreadContext.Stacks["Monitor"].Push("Indexing local files"))
269
            StatusNotification.NotifyChange("Indexing Local Files");
270
            using (ThreadContext.Stacks["Monitor"].Push("Indexing local files"))
281 271
            {
282 272
                Log.Info("START");
283 273
                try
......
359 349

  
360 350
            public override int GetHashCode(CloudAction obj)
361 351
            {
352
                if (obj == null)
353
                    return 0;
362 354
                var hash1 = (obj.LocalFile == null) ? int.MaxValue : obj.LocalFile.FullName.GetHashCode();
363 355
                var hash2 = (obj.CloudFile == null) ? int.MaxValue : (obj.CloudFile.Hash ?? obj.CloudFile.Name??"").GetHashCode();
364 356
                var hash3 = obj.Action.GetHashCode();
......
366 358
            }
367 359
        }        
368 360

  
369
        private Timer timer;
370

  
371 361
        private void StartNetworkAgent()
372 362
        {
373 363

  
......
385 375
        }
386 376

  
387 377
        //Make sure a hidden cache folder exists to store partial downloads
388
        private static string CreateHiddenFolder(string rootPath, string folderName)
378
        private static void CreateHiddenFolder(string rootPath, string folderName)
389 379
        {
390 380
            if (String.IsNullOrWhiteSpace(rootPath))
391 381
                throw new ArgumentNullException("rootPath");
......
412 402
                    Log.InfoFormat("Reset cache folder to hidden: {0}", folder);
413 403
                }                                
414 404
            }
415
            return folder;
416 405
        }
417 406

  
418 407
       
......
435 424
            if (FileAgent!=null)
436 425
                FileAgent.Stop();
437 426
            FileAgent = null;
438
            if (timer != null)
439
                timer.Dispose();
440
            timer = null;            
441 427
        }
442 428

  
443 429

  
......
545 531
                //Create the root URL for the target account
546 532
                var oldName = UserName;
547 533
                var absoluteUri =  _accountInfo.StorageUri.AbsoluteUri;
548
                var nameIndex=absoluteUri.IndexOf(oldName);
534
                var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal);
549 535
                var root=absoluteUri.Substring(0, nameIndex);
550 536

  
551 537
                accountInfo = new AccountInfo
......
560 546
            }
561 547
            else
562 548
            {
563
                accountName = this.UserName;
549
                accountName = UserName;
564 550
                container = parts[0];
565 551
                relativeUrl = String.Join("/", parts.Splice(1));
566 552
            }
......
591 577
                //Create the root URL for the target account
592 578
                var oldName = UserName;
593 579
                var absoluteUri =  _accountInfo.StorageUri.AbsoluteUri;
594
                var nameIndex=absoluteUri.IndexOf(oldName);
580
                var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal);
595 581
                var root=absoluteUri.Substring(0, nameIndex);
596 582

  
597 583
                accountInfo = new AccountInfo

Also available in: Unified diff