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