Revision 4f6d51d4 trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs

b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
1 1
using System.Collections.Concurrent;
2
using System.ComponentModel;
3
using System.ComponentModel.Composition;
4 2
using System.Diagnostics;
5 3
using System.Diagnostics.Contracts;
6 4
using System.IO;
......
8 6
using System.Reflection;
9 7
using System.Runtime.InteropServices;
10 8
using System.ServiceModel;
11
using System.ServiceModel.Description;
12 9
using System.Threading.Tasks;
13 10
using System.Windows;
14 11
using Caliburn.Micro;
15 12
using Hardcodet.Wpf.TaskbarNotification;
16 13
using Pithos.Client.WPF.Configuration;
17 14
using Pithos.Client.WPF.FileProperties;
18
using Pithos.Client.WPF.Properties;
19 15
using Pithos.Client.WPF.SelectiveSynch;
20 16
using Pithos.Client.WPF.Services;
21 17
using Pithos.Client.WPF.Shell;
......
24 20
using System;
25 21
using System.Collections.Generic;
26 22
using System.Linq;
27
using System.Text;
28 23
using Pithos.Network;
29 24
using StatusService = Pithos.Client.WPF.Services.StatusService;
30 25

  
......
50 45
	{
51 46
		//The Status Checker provides the current synch state
52 47
		//TODO: Could we remove the status checker and use events in its place?
53
		private IStatusChecker _statusChecker;
54
		private IEventAggregator _events;
48
		private readonly IStatusChecker _statusChecker;
49
		private readonly IEventAggregator _events;
55 50

  
56 51
		public PithosSettings Settings { get; private set; }
57 52

  
58 53

  
59
        private ConcurrentDictionary<string, PithosMonitor> _monitors = new ConcurrentDictionary<string, PithosMonitor>();
54
        private readonly ConcurrentDictionary<string, PithosMonitor> _monitors = new ConcurrentDictionary<string, PithosMonitor>();
60 55
		///<summary>
61 56
		/// Dictionary of account monitors, keyed by account
62 57
		///</summary>
......
72 67
		}
73 68

  
74 69

  
75
		///<summary>
76
		/// The status service is used by Shell extensions to retrieve file status information
77
		///</summary>
78
		//TODO: CODE SMELL! This is the shell! While hosting in the shell makes executing start/stop commands easier, it is still a smell
79
		private ServiceHost _statusService { get; set; }
70
	    ///<summary>
71
	    /// The status service is used by Shell extensions to retrieve file status information
72
	    ///</summary>
73
	    //TODO: CODE SMELL! This is the shell! While hosting in the shell makes executing start/stop commands easier, it is still a smell
74
	    private ServiceHost _statusService;
80 75

  
81 76
		//Logging in the Pithos client is provided by log4net
82 77
		private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
......
128 123
		}
129 124

  
130 125

  
131
		private async Task StartMonitoring()
126
		private async void StartMonitoring()
132 127
		{
133 128
			try
134 129
			{
......
169 164
		{
170 165
			return Task.Factory.StartNew(() =>
171 166
			{                                                
172
				PithosMonitor monitor = null;
167
				PithosMonitor monitor;
173 168
				var accountName = account.AccountName;
174 169

  
175 170
				if (_monitors.TryGetValue(accountName, out monitor))
......
199 194
				//PithosMonitor uses MEF so we need to resolve it
200 195
				IoC.BuildUp(monitor);
201 196

  
202
				var appSettings = Properties.Settings.Default;
203
				monitor.AuthenticationUrl = account.ServerUrl;
197
			    monitor.AuthenticationUrl = account.ServerUrl;
204 198

  
205 199
				_monitors[accountName] = monitor;
206 200

  
......
284 278
			get { return _statusIcon; }
285 279
			set
286 280
			{
287
				//_statusIcon = value;
281
                //TODO: Ensure all status icons use the Pithos logo
282
				_statusIcon = value;
288 283
				NotifyOfPropertyChange(() => StatusIcon);
289 284
			}
290 285
		}
......
359 354
		{
360 355
			if (String.IsNullOrWhiteSpace(filePath))
361 356
				throw new ArgumentNullException("filePath");
362
			if (!File.Exists(filePath))
357
			if (!File.Exists(filePath) && !Directory.Exists(filePath))
363 358
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
364 359
			Contract.EndContractBlock();
365 360

  
366 361
			var pair=(from monitor in  Monitors
367 362
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
368 363
								   select monitor).FirstOrDefault();
369
			var account = pair.Key;
370
			var accountMonitor = pair.Value;
364
		    var accountMonitor = pair.Value;
371 365

  
372 366
			if (accountMonitor == null)
373 367
				return;
......
401 395
			var pair=(from monitor in  Monitors
402 396
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
403 397
								   select monitor).FirstOrDefault();
404
			var account = pair.Key;
405
			var accountMonitor = pair.Value;            
398
		    var accountMonitor = pair.Value;            
406 399
			var info = accountMonitor.GetContainerInfo(filePath);
407 400

  
408 401
			
......
462 455
		#endregion
463 456

  
464 457

  
465
		private Dictionary<PithosStatus, StatusInfo> iconNames = new List<StatusInfo>
458
		private readonly Dictionary<PithosStatus, StatusInfo> _iconNames = new List<StatusInfo>
466 459
			{
467 460
				new StatusInfo(PithosStatus.InSynch, "All files up to date", "TrayInSynch"),
468 461
				new StatusInfo(PithosStatus.Syncing, "Syncing Files", "TraySynching"),
......
479 472
		{
480 473
			var pithosStatus = _statusChecker.GetPithosStatus();
481 474

  
482
			if (iconNames.ContainsKey(pithosStatus))
475
			if (_iconNames.ContainsKey(pithosStatus))
483 476
			{
484
				var info = iconNames[pithosStatus];
477
				var info = _iconNames[pithosStatus];
485 478
				StatusIcon = String.Format(@"../Images/{0}.ico", info.IconName);
486 479

  
487 480
				Assembly assembly = Assembly.GetExecutingAssembly();                               
......
558 551

  
559 552
				var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
560 553

  
561
				var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
554
				var account = Settings.Accounts.First(act => act.AccountName == credentials.UserName);
562 555
				account.ApiKey = credentials.Password;
563 556
				monitor.ApiKey = credentials.Password;
564 557
				Settings.Save();
......
571 564
				string message = String.Format("API Key retrieval for {0} failed", monitor.UserName);
572 565
				Log.Error(message, exc.InnerException);
573 566
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
574
				return;
575 567
			}
576 568
			catch (Exception exc)
577 569
			{
578 570
				string message = String.Format("API Key retrieval for {0} failed", monitor.UserName);
579 571
				Log.Error(message, exc);
580 572
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
581
				return;
582
				
583 573
			}
584 574

  
585 575
		}
......
608 598

  
609 599
		public void NotifyChange(string status, TraceLevel level=TraceLevel.Info)
610 600
		{
611
			this.StatusMessage = status;
601
			StatusMessage = status;
612 602
			
613 603
			_events.Publish(new Notification { Title = "Pithos", Message = status, Level = level });
614 604
		}
......
616 606
		public void NotifyChangedFile(string filePath)
617 607
		{
618 608
			var entry = new FileEntry {FullPath=filePath};
619
			IProducerConsumerCollection<FileEntry> files=this.RecentFiles;
609
			IProducerConsumerCollection<FileEntry> files=RecentFiles;
620 610
			FileEntry popped;
621 611
			while (files.Count > 5)
622 612
				files.TryTake(out popped);
......
702 692
		{
703 693
			if (!Settings.ShowDesktopNotifications)
704 694
				return;
705
			BalloonIcon icon = BalloonIcon.None;
695
			BalloonIcon icon;
706 696
			switch (notification.Level)
707 697
			{
708 698
				case TraceLevel.Error:
......
722 712

  
723 713
			if (Settings.ShowDesktopNotifications)
724 714
			{
725
				var tv = (ShellView) this.GetView();
715
				var tv = (ShellView) GetView();
726 716
				tv.TaskbarView.ShowBalloonTip(notification.Title, notification.Message, icon);
727 717
			}
728 718
		}
......
737 727
			Contract.EndContractBlock();
738 728

  
739 729
			var fileName = message.FileName;
740

  
730
            //TODO: Display file properties for non-container folders
741 731
			if (File.Exists(fileName))
742
				this.ShowFileProperties(fileName);
732
                //Retrieve the full name with exact casing. Pithos names are case sensitive				
733
                ShowFileProperties(GetProperFilePathCapitalization(fileName));
743 734
			else if (Directory.Exists(fileName))
744
				this.ShowContainerProperties(fileName);
735
                //Retrieve the full name with exact casing. Pithos names are case sensitive
736
			{
737
			    var path = GetProperDirectoryCapitalization(fileName);
738
                if (IsContainer(path))
739
			        ShowContainerProperties(path);
740
                else
741
                    ShowFileProperties(path);
742
			}
745 743
		}
744

  
745
	    private bool IsContainer(string path)
746
	    {
747
	        var matchingFolders = from account in _accounts
748
	                              from rootFolder in Directory.GetDirectories(account.AccountPath)
749
	                              where rootFolder.Equals(path, StringComparison.InvariantCultureIgnoreCase)
750
	                              select rootFolder;
751
	        return matchingFolders.Any();
752
	    }
753

  
754
	    static string GetProperDirectoryCapitalization(string fileName)
755
        {
756
            var dirInfo = new DirectoryInfo(fileName);
757
            var parentDirInfo = dirInfo.Parent;
758
            if (null == parentDirInfo)
759
                return dirInfo.Name;
760
            return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo.FullName),
761
                                parentDirInfo.GetDirectories(dirInfo.Name)[0].Name);
762
        }
763

  
764
        static string GetProperFilePathCapitalization(string fileName)
765
        {
766
            if (String.IsNullOrWhiteSpace(fileName))
767
                throw new ArgumentNullException("fileName");
768
            if (!Path.IsPathRooted(fileName))
769
                throw new ArgumentException("fileName must be an absolute path","fileName");
770
            Contract.EndContractBlock();
771

  
772
            
773
            var fileInfo = new FileInfo(fileName);
774
            var dirInfo = fileInfo.Directory;
775
            
776
            //Directory will not be null for an absolute path
777
            Contract.Assume(dirInfo!=null);
778
            
779
            return Path.Combine(GetProperDirectoryCapitalization(dirInfo.FullName),
780
                                dirInfo.GetFiles(fileInfo.Name)[0].Name);
781
        }
746 782
	}
747 783
}

Also available in: Unified diff