Revision 7f5882da

b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
42 42

  
43 43

  
44 44
using System.Collections.Concurrent;
45
using System.Collections.Generic;
45 46
using System.ComponentModel.Composition;
46 47
using System.Diagnostics;
47 48
using System.IO;
......
280 281
            Settings.Save();
281 282
            //SetStartupMode();            
282 283

  
284
            foreach (var account in _accountsToRemove)
285
            {
286
                Settings.Accounts.Remove(account);
287
                Shell.RemoveMonitor(account.AccountName);
288
            }
289

  
283 290
            foreach (var account in Settings.Accounts)
284 291
            {                                
285 292
                Shell.MonitorAccount(account);
......
374 381
            NotifyOfPropertyChange(()=>Settings);                       
375 382
       }
376 383

  
384

  
385
        readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();
377 386
        public void RemoveAccount()
378 387
        {
379 388
            var accountName = CurrentAccount.AccountName;
380
            Settings.Accounts.Remove(CurrentAccount.Account);
381 389

  
382 390
            Accounts.TryRemove(CurrentAccount);
383
            
384
            
391
            _accountsToRemove.Add(CurrentAccount.Account);
392

  
385 393
            CurrentAccount = null;
386
            //Accounts = Settings.Accounts;
387
            //Settings.Save();            
388
            Shell.RemoveMonitor(accountName);
389 394
            NotifyOfPropertyChange(() => Accounts);
390
            NotifyOfPropertyChange(() => Settings);                       
395

  
391 396
            
392 397
            //NotifyOfPropertyChange("Settings.Accounts");
393 398
        }
b/trunk/Pithos.Client.WPF/Shell/ShellView.xaml
63 63
                    <MenuItem Header="Recently Changed Files" x:Name="RecentFiles" ItemsSource="{Binding RecentFiles}">
64 64
                        <MenuItem.ItemTemplate>
65 65
                            <DataTemplate>
66
                                <TextBlock Text="{Binding FileName}"/>
66
                                <TextBlock Text="{Binding FileName}" cal:Message.Attach="[Event MouseLeftButtonUp]=[Action GoToFile($dataContext)]" 
67
                                           cal:Action.TargetWithoutContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MenuItem, AncestorLevel=2}, Path=DataContext}" />
67 68
                            </DataTemplate>
68 69
                        </MenuItem.ItemTemplate>
69 70
                    </MenuItem>
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
55 55
using Pithos.Client.WPF.Configuration;
56 56
using Pithos.Client.WPF.FileProperties;
57 57
using Pithos.Client.WPF.Preferences;
58
using Pithos.Client.WPF.Properties;
59 58
using Pithos.Client.WPF.SelectiveSynch;
60 59
using Pithos.Client.WPF.Services;
61 60
using Pithos.Client.WPF.Shell;
......
122 121
		private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
123 122

  
124 123
		//Lazily initialized File Version info. This is done once and lazily to avoid blocking the UI
125
		private Lazy<FileVersionInfo> _fileVersion;
124
		private readonly Lazy<FileVersionInfo> _fileVersion;
126 125

  
127
	    private PollAgent _pollAgent;
126
	    private readonly PollAgent _pollAgent;
128 127

  
129 128
		///<summary>
130 129
		/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
......
408 407

  
409 408
		public void GoToSite(AccountInfo account)
410 409
		{
411
			/*var site = String.Format("{0}/ui/?token={1}&user={2}",
412
				account.SiteUri,account.Token,
413
				account.UserName);*/
414 410
			Process.Start(account.SiteUri);
415 411
		}
416 412

  
413
        /// <summary>
414
        /// Open an explorer window to the target path's directory
415
        /// and select the file
416
        /// </summary>
417
        /// <param name="entry"></param>
418
        public void GoToFile(FileEntry entry)
419
        {
420
            var fullPath = entry.FullPath;
421
            if (!File.Exists(fullPath) && !Directory.Exists(fullPath))
422
                return;
423
            Process.Start("explorer.exe","/select, " + fullPath);
424
        }
425

  
417 426
		public void ShowFileProperties()
418 427
		{
419 428
			var account = Settings.Accounts.First(acc => acc.IsActive);            
......
623 632
			Execute.OnUIThread(() =>
624 633
								   {                                       
625 634
									   var proxyAccount = IoC.Get<ProxyAccountViewModel>();
626
										proxyAccount.Settings = this.Settings;
635
										proxyAccount.Settings = Settings;
627 636
									   if (true != _windowManager.ShowDialog(proxyAccount)) 
628 637
										   return;
629 638
									   StartMonitor(monitor, retries);
......
645 654
		}
646 655

  
647 656

  
648

  
649
		private static bool IsUnauthorized(WebException exc)
650
		{
651
			if (exc==null)
652
				throw new ArgumentNullException("exc");
653
			Contract.EndContractBlock();
654

  
655
			var response = exc.Response as HttpWebResponse;
656
			if (response == null)
657
				return false;
658
			return (response.StatusCode == HttpStatusCode.Unauthorized);
659
		}
660

  
661
		private void TryLater(PithosMonitor monitor, Exception exc,int retries)
657
	    private void TryLater(PithosMonitor monitor, Exception exc,int retries)
662 658
		{
663 659
			var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds");
664 660
			Task.Factory.StartNewDelayed(10000, () => StartMonitor(monitor,retries+1));
......
677 673

  
678 674
		public void NotifyChangedFile(string filePath)
679 675
		{
680
			var entry = new FileEntry {FullPath=filePath};
676
            if (RecentFiles.Any(e => e.FullPath == filePath))
677
                return;
678
            
681 679
			IProducerConsumerCollection<FileEntry> files=RecentFiles;
682 680
			FileEntry popped;
683 681
			while (files.Count > 5)
684 682
				files.TryTake(out popped);
683
            var entry = new FileEntry { FullPath = filePath };
685 684
			files.TryAdd(entry);
686 685
		}
687 686

  
......
703 702
		{
704 703
			if (conflictFiles == null)
705 704
				return;
706
			if (!conflictFiles.Any())
705
		    //Convert to list to avoid multiple iterations
706
            var files = conflictFiles.ToList();
707
			if (files.Count==0)
707 708
				return;
708 709

  
709 710
			UpdateStatus();
710 711
			//TODO: Create a more specific message. For now, just show a warning
711
			NotifyForFiles(conflictFiles,message,TraceLevel.Warning);
712
			NotifyForFiles(files,message,TraceLevel.Warning);
712 713

  
713 714
		}
714 715

  
......
743 744
			if (Monitors.TryRemove(accountName, out monitor))
744 745
			{
745 746
				monitor.Stop();
747
                //TODO: Also remove any pending actions for this account
748
                //from the network queue                
746 749
			}
747 750
		}
748 751

  
......
790 793
		}
791 794

  
792 795

  
793
		private bool _pollStarted = false;
796
		private bool _pollStarted;
794 797

  
795 798
		//SMELL: Doing so much work for notifications in the shell is wrong
796 799
		//The notifications should be moved to their own view/viewmodel pair
b/trunk/Pithos.Core.Test/FileSystemWatcherAdapterTest.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="FileSystemWatcherAdapter.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using NUnit.Framework;
8

  
9
namespace Pithos.Core.Test
10
{
11
    using System;
12
    using System.Collections.Generic;
13
    using System.Linq;
14
    using System.Text;
15

  
16
    [TestFixture]
17
    public class FileSystemWatcherAdapterTest
18
    {
19
        
20

  
21
    }
22
}
b/trunk/Pithos.Core.Test/Pithos.Core.Test.csproj
212 212
    <Compile Include="MockSettings.cs" />
213 213
    <Compile Include="MockStatusKeeper.cs" />
214 214
    <Compile Include="SnapshotDifferencerTest.cs" />
215
    <Compile Include="TaskExtensionsTest.cs" />
215 216
    <Compile Include="WorkflowFileStatusTest.cs" />
216 217
  </ItemGroup>
217 218
  <ItemGroup>
b/trunk/Pithos.Core.Test/TaskExtensionsTest.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="TaskExtensionsTest.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.Collections.Concurrent;
8
using NUnit.Framework;
9

  
10
namespace Pithos.Core.Test
11
{
12
    using System;
13
    using System.Collections.Generic;
14
    using System.Linq;
15
    using System.Text;
16

  
17
    [TestFixture]
18
    public class TaskExtensionsTest
19
    {
20
        [Test]
21
        public void when_adding_to_ObservableConcurrentCollection()
22
        {
23
            var collection = new ObservableConcurrentCollection<string>();
24
            collection.TryAdd("1");
25
            Assert.That(collection,Contains.Item("1"));
26
            collection.TryAdd("2");
27
            Assert.That(collection, Contains.Item("2"));
28
            Assert.That(collection, Contains.Item("1"));
29
            
30
        }
31

  
32
        [Test]
33
        public void when_removing_from_ObservableConcurrentCollection()
34
        {
35
            var collection = new ObservableConcurrentCollection<string>();
36
            collection.TryAdd("1");
37
            collection.TryAdd("2");
38
            collection.TryAdd("3");
39
            collection.TryRemove("2");
40
            Assert.That(collection, Contains.Item("1"));
41
            Assert.That(collection.Contains("2"), Is.False);
42
            Assert.That(collection, Contains.Item("3"));
43
            
44
        }
45
    }
46
}
b/trunk/Pithos.Core/TaskExtensions.cs
157 157

  
158 158
        public static bool TryRemove<T>(this ObservableConcurrentCollection<T> collection,T item) where T:class
159 159
        {
160
            var found = false;
160 161
            IProducerConsumerCollection<T> items= collection;
161
            for (var i = 0; i < items.Count; i++)
162
            //Store the initial count
163
            var count = items.Count;
164
            for (var i = 0; i < count; i++)
162 165
            {
163 166
                T tempItem;
167
                //Take an item
164 168
                if (!items.TryTake(out tempItem)) 
165 169
                    return false;
166
                if (tempItem == item) 
167
                    return true;
168
                items.TryAdd(item);
170
                //If it isn't the one we are looking for
171
                if (tempItem != item)
172
                    //put it back
173
                    items.TryAdd(tempItem);
174
                else
175
                    //otherwise skip it and flag succcess
176
                    found = true;
169 177
            }
170
            return false;
178
            return found;
171 179
        }
172 180

  
173 181
        public static bool TryAdd<T>(this ObservableConcurrentCollection<T> collection,T item) where T:class

Also available in: Unified diff