using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
Settings.Save();
//SetStartupMode();
+ foreach (var account in _accountsToRemove)
+ {
+ Settings.Accounts.Remove(account);
+ Shell.RemoveMonitor(account.AccountName);
+ }
+
foreach (var account in Settings.Accounts)
{
Shell.MonitorAccount(account);
NotifyOfPropertyChange(()=>Settings);
}
+
+ readonly List<AccountSettings> _accountsToRemove = new List<AccountSettings>();
public void RemoveAccount()
{
var accountName = CurrentAccount.AccountName;
- Settings.Accounts.Remove(CurrentAccount.Account);
Accounts.TryRemove(CurrentAccount);
-
-
+ _accountsToRemove.Add(CurrentAccount.Account);
+
CurrentAccount = null;
- //Accounts = Settings.Accounts;
- //Settings.Save();
- Shell.RemoveMonitor(accountName);
NotifyOfPropertyChange(() => Accounts);
- NotifyOfPropertyChange(() => Settings);
+
//NotifyOfPropertyChange("Settings.Accounts");
}
<MenuItem Header="Recently Changed Files" x:Name="RecentFiles" ItemsSource="{Binding RecentFiles}">
<MenuItem.ItemTemplate>
<DataTemplate>
- <TextBlock Text="{Binding FileName}"/>
+ <TextBlock Text="{Binding FileName}" cal:Message.Attach="[Event MouseLeftButtonUp]=[Action GoToFile($dataContext)]"
+ cal:Action.TargetWithoutContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MenuItem, AncestorLevel=2}, Path=DataContext}" />
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
using Pithos.Client.WPF.Configuration;
using Pithos.Client.WPF.FileProperties;
using Pithos.Client.WPF.Preferences;
-using Pithos.Client.WPF.Properties;
using Pithos.Client.WPF.SelectiveSynch;
using Pithos.Client.WPF.Services;
using Pithos.Client.WPF.Shell;
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
//Lazily initialized File Version info. This is done once and lazily to avoid blocking the UI
- private Lazy<FileVersionInfo> _fileVersion;
+ private readonly Lazy<FileVersionInfo> _fileVersion;
- private PollAgent _pollAgent;
+ private readonly PollAgent _pollAgent;
///<summary>
/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
public void GoToSite(AccountInfo account)
{
- /*var site = String.Format("{0}/ui/?token={1}&user={2}",
- account.SiteUri,account.Token,
- account.UserName);*/
Process.Start(account.SiteUri);
}
+ /// <summary>
+ /// Open an explorer window to the target path's directory
+ /// and select the file
+ /// </summary>
+ /// <param name="entry"></param>
+ public void GoToFile(FileEntry entry)
+ {
+ var fullPath = entry.FullPath;
+ if (!File.Exists(fullPath) && !Directory.Exists(fullPath))
+ return;
+ Process.Start("explorer.exe","/select, " + fullPath);
+ }
+
public void ShowFileProperties()
{
var account = Settings.Accounts.First(acc => acc.IsActive);
Execute.OnUIThread(() =>
{
var proxyAccount = IoC.Get<ProxyAccountViewModel>();
- proxyAccount.Settings = this.Settings;
+ proxyAccount.Settings = Settings;
if (true != _windowManager.ShowDialog(proxyAccount))
return;
StartMonitor(monitor, retries);
}
-
- private static bool IsUnauthorized(WebException exc)
- {
- if (exc==null)
- throw new ArgumentNullException("exc");
- Contract.EndContractBlock();
-
- var response = exc.Response as HttpWebResponse;
- if (response == null)
- return false;
- return (response.StatusCode == HttpStatusCode.Unauthorized);
- }
-
- private void TryLater(PithosMonitor monitor, Exception exc,int retries)
+ private void TryLater(PithosMonitor monitor, Exception exc,int retries)
{
var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds");
Task.Factory.StartNewDelayed(10000, () => StartMonitor(monitor,retries+1));
public void NotifyChangedFile(string filePath)
{
- var entry = new FileEntry {FullPath=filePath};
+ if (RecentFiles.Any(e => e.FullPath == filePath))
+ return;
+
IProducerConsumerCollection<FileEntry> files=RecentFiles;
FileEntry popped;
while (files.Count > 5)
files.TryTake(out popped);
+ var entry = new FileEntry { FullPath = filePath };
files.TryAdd(entry);
}
{
if (conflictFiles == null)
return;
- if (!conflictFiles.Any())
+ //Convert to list to avoid multiple iterations
+ var files = conflictFiles.ToList();
+ if (files.Count==0)
return;
UpdateStatus();
//TODO: Create a more specific message. For now, just show a warning
- NotifyForFiles(conflictFiles,message,TraceLevel.Warning);
+ NotifyForFiles(files,message,TraceLevel.Warning);
}
if (Monitors.TryRemove(accountName, out monitor))
{
monitor.Stop();
+ //TODO: Also remove any pending actions for this account
+ //from the network queue
}
}
}
- private bool _pollStarted = false;
+ private bool _pollStarted;
//SMELL: Doing so much work for notifications in the shell is wrong
//The notifications should be moved to their own view/viewmodel pair
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="FileSystemWatcherAdapter.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+using NUnit.Framework;
+
+namespace Pithos.Core.Test
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ [TestFixture]
+ public class FileSystemWatcherAdapterTest
+ {
+
+
+ }
+}
<Compile Include="MockSettings.cs" />
<Compile Include="MockStatusKeeper.cs" />
<Compile Include="SnapshotDifferencerTest.cs" />
+ <Compile Include="TaskExtensionsTest.cs" />
<Compile Include="WorkflowFileStatusTest.cs" />
</ItemGroup>
<ItemGroup>
--- /dev/null
+// -----------------------------------------------------------------------
+// <copyright file="TaskExtensionsTest.cs" company="Microsoft">
+// TODO: Update copyright text.
+// </copyright>
+// -----------------------------------------------------------------------
+
+using System.Collections.Concurrent;
+using NUnit.Framework;
+
+namespace Pithos.Core.Test
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ [TestFixture]
+ public class TaskExtensionsTest
+ {
+ [Test]
+ public void when_adding_to_ObservableConcurrentCollection()
+ {
+ var collection = new ObservableConcurrentCollection<string>();
+ collection.TryAdd("1");
+ Assert.That(collection,Contains.Item("1"));
+ collection.TryAdd("2");
+ Assert.That(collection, Contains.Item("2"));
+ Assert.That(collection, Contains.Item("1"));
+
+ }
+
+ [Test]
+ public void when_removing_from_ObservableConcurrentCollection()
+ {
+ var collection = new ObservableConcurrentCollection<string>();
+ collection.TryAdd("1");
+ collection.TryAdd("2");
+ collection.TryAdd("3");
+ collection.TryRemove("2");
+ Assert.That(collection, Contains.Item("1"));
+ Assert.That(collection.Contains("2"), Is.False);
+ Assert.That(collection, Contains.Item("3"));
+
+ }
+ }
+}
public static bool TryRemove<T>(this ObservableConcurrentCollection<T> collection,T item) where T:class
{
+ var found = false;
IProducerConsumerCollection<T> items= collection;
- for (var i = 0; i < items.Count; i++)
+ //Store the initial count
+ var count = items.Count;
+ for (var i = 0; i < count; i++)
{
T tempItem;
+ //Take an item
if (!items.TryTake(out tempItem))
return false;
- if (tempItem == item)
- return true;
- items.TryAdd(item);
+ //If it isn't the one we are looking for
+ if (tempItem != item)
+ //put it back
+ items.TryAdd(tempItem);
+ else
+ //otherwise skip it and flag succcess
+ found = true;
}
- return false;
+ return found;
}
public static bool TryAdd<T>(this ObservableConcurrentCollection<T> collection,T item) where T:class