diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs
index 7a527c2..e922b2c 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs
@@ -361,7 +361,7 @@ namespace Acacia.Features.GAB
{
try
{
- if (IsGABContactsFolder(folder))
+ if (IsGABContactsFolder(folder, accounts))
{
Logger.Instance.Debug(this, "FullResync: Deleting contacts folder: {0}", folder.Name);
folder.Delete();
@@ -378,16 +378,27 @@ namespace Acacia.Features.GAB
}
// Do the resync
- int remaining = _gabsByDomainName.Count;
- foreach (GABHandler gab in _gabsByDomainName.Values)
+ using (completion.Begin())
{
- CompletionTracker partCompletion = new CompletionTracker(() => OnGabSyncFinished(gab));
- // TODO: merge partCompletion into total completion
- Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
- Tasks.Task(partCompletion, this, "FullResync", () =>
+ foreach (GABHandler gab in _gabsByDomainName.Values)
{
- gab.FullResync(partCompletion);
- });
+ // Check if the gab is appropriate for the accounts
+ if (accounts == null || accounts.Contains(gab.ActiveAccount))
+ {
+ completion.Begin();
+ CompletionTracker partCompletion = new CompletionTracker(() =>
+ {
+ OnGabSyncFinished(gab);
+ completion.End();
+ });
+
+ Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
+ Tasks.Task(partCompletion, this, "FullResync", () =>
+ {
+ gab.FullResync(partCompletion);
+ });
+ }
+ }
}
}
finally
@@ -499,9 +510,30 @@ namespace Acacia.Features.GAB
return GABInfo.Get(folder);
}
- public static bool IsGABContactsFolder(IFolder folder)
+ ///
+ /// Checks if the folder is a relevant GAB contacts folder.
+ ///
+ /// The folder.
+ /// If specified, the folder is considered relevant only if it is the GAB for one of the specified
+ /// accounts. Otherwise, any GAB folder is considered relevant.
+ public static bool IsGABContactsFolder(IFolder folder, ZPushAccount[] accounts)
{
- return GetGABContactsFolderInfo(folder) != null;
+ // Check if this is a GAB folder at all
+ GABInfo gab = GetGABContactsFolderInfo(folder);
+ if (gab == null)
+ return false;
+
+ // If we don't have a list of accounts, it is what we're looking for
+ if (accounts == null)
+ return true;
+
+ // Check if the domain is specified
+ foreach(ZPushAccount account in accounts)
+ {
+ if (account.Account.DomainName == gab.Domain)
+ return true;
+ }
+ return false;
}
private void AccountDiscovered(ZPushAccount zpush)
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
index b1c48de..48142a6 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
@@ -41,6 +41,39 @@ namespace Acacia.Features.SyncState
public class FeatureSyncState : FeatureDisabled, FeatureWithRibbon
{
+
+ #region Sync configuration
+
+ [AcaciaOption("Sets the period to check synchronisation state if a sync is in progress.")]
+ public TimeSpan CheckPeriod
+ {
+ get { return GetOption(OPTION_CHECK_PERIOD); }
+ set { SetOption(OPTION_CHECK_PERIOD, value); }
+ }
+ private static readonly TimeSpanOption OPTION_CHECK_PERIOD = new TimeSpanOption("CheckPeriod", new TimeSpan(0, 5, 0));
+
+ [AcaciaOption("Sets the period to check synchronisation state if a sync is in progress and the dialog is open.")]
+ public TimeSpan CheckPeriodDialog
+ {
+ get { return GetOption(OPTION_CHECK_PERIOD_DIALOG); }
+ set { SetOption(OPTION_CHECK_PERIOD_DIALOG, value); }
+ }
+ private static readonly TimeSpanOption OPTION_CHECK_PERIOD_DIALOG = new TimeSpanOption("CheckPeriodDialog", new TimeSpan(0, 1, 0));
+
+ private TimeSpan DelayTime
+ {
+ get
+ {
+ if (_dialogOpen)
+ return CheckPeriodDialog;
+ else
+ return CheckPeriod;
+ }
+ }
+ private bool _dialogOpen;
+
+ #endregion
+
// TODO: this is largely about progress bars, separate that?
private class SyncStateData : DataProvider
{
@@ -152,7 +185,7 @@ namespace Acacia.Features.SyncState
public override void Startup()
{
_state = new SyncStateData(this);
- _button = RegisterButton(this, "Progress", true, ShowSyncState, ZPushBehaviour.Disable);
+ _button = RegisterButton(this, "Progress", true, ShowSyncState, ZPushBehaviour.None);
_button.DataProvider = _state;
// Add a sync task to start checking. If this finds it's not fully synchronised, it will check more often
Watcher.Sync.AddTask(this, Name, CheckSyncState);
@@ -306,10 +339,14 @@ namespace Acacia.Features.SyncState
DeviceDetails details = deviceService.Execute(new GetDeviceDetailsRequest());
// Determine the totals
- details.Calculate();
+ details?.Calculate();
// And store with the account
account.SetFeatureData(this, null, details);
+
+ // If syncing, check again soon.
+ if (details?.IsSyncing == true)
+ Util.Delayed(this, (int)DelayTime.TotalMilliseconds, () => CheckSyncState(account));
}
// Update the total for all accounts
@@ -340,7 +377,15 @@ namespace Acacia.Features.SyncState
private void ShowSyncState()
{
- new SyncStateDialog(this).ShowDialog();
+ _dialogOpen = true;
+ try
+ {
+ new SyncStateDialog(this).ShowDialog();
+ }
+ finally
+ {
+ _dialogOpen = false;
+ }
}
private class SyncStateImpl : SyncState
@@ -362,7 +407,6 @@ namespace Acacia.Features.SyncState
_canResync[(int)ResyncOption.Signatures] = _featureSignatures != null;
_canResync[(int)ResyncOption.ServerData] = ThisAddIn.Instance.Watcher.Sync.Enabled;
_canResync[(int)ResyncOption.Full] = true;
- Update();
}
public long Done
@@ -399,14 +443,29 @@ namespace Acacia.Features.SyncState
{
if (!CanResync(option))
return true;
- _canResync [(int)option] = false;
switch(option)
{
case ResyncOption.GAB:
- // TODO: use completion tracker if not synching
- _featureGAB.FullResync(null, _accounts);
- return false;
+ if (IsSyncing)
+ {
+ // Already syncing, resync GAB asynchronously
+ _featureGAB.FullResync(null, _accounts);
+ // Cannot resync again until the dialog is reopened
+ _canResync[(int)ResyncOption.GAB] = false;
+ return false;
+ }
+ else
+ {
+ ProgressDialog.Execute("GABSync",
+ (ct, tracker) =>
+ {
+ _featureGAB.FullResync(tracker, _accounts);
+ return 0;
+ }
+ );
+ return true;
+ }
case ResyncOption.Signatures:
ProgressDialog.Execute("SignaturesSync",
(ct) =>
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs
index 608621a..573c5fa 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs
@@ -50,6 +50,15 @@ namespace Acacia.Features.SyncState
// Add the accounts
foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts())
comboAccounts.Items.Add(account);
+
+ // Add a timer to update the UI
+ Timer timer = new Timer();
+ timer.Interval = 2500;
+ timer.Tick += (o, args) =>
+ {
+ UpdateUI();
+ };
+ timer.Start();
}
private void ShowHint(object sender, KHintButton.HintEventArgs e)
@@ -119,6 +128,8 @@ namespace Acacia.Features.SyncState
private void UpdateUI()
{
+ _syncState.Update();
+
// Set up the UI
foreach (ResyncOption option in Enum.GetValues(typeof(ResyncOption)))
{
@@ -127,7 +138,7 @@ namespace Acacia.Features.SyncState
if (_syncState.IsSyncing)
{
- textRemaining.Text = _syncState.Remaining.ToString();
+ textRemaining.Text = _syncState.Remaining.ToString() + " / " + _syncState.Total.ToString();
progress.Value = (int)(_syncState.Done * 100.0 / _syncState.Total);
}
else
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
index 2ee2e88..e8a4977 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
@@ -168,6 +168,24 @@ namespace Acacia.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to The global address book is being synchronised..
+ ///
+ internal static string GABSync_Label {
+ get {
+ return ResourceManager.GetString("GABSync_Label", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Global Address Book.
+ ///
+ internal static string GABSync_Title {
+ get {
+ return ResourceManager.GetString("GABSync_Title", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
///
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
index 8c1e697..4d3f06d 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
@@ -494,4 +494,10 @@
Server data
+
+ The global address book is being synchronised.
+
+
+ Global Address Book
+
\ No newline at end of file
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs
index e65be5f..fbc06b5 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs
@@ -89,6 +89,61 @@ namespace Acacia.UI
return task.Result;
}
+ public static ResultType Execute(string resourcePrefix, Func action)
+ {
+ // TODO: merge with above
+
+ Logger.Instance.Info(typeof(ProgressDialog), "Opening");
+ // Determine the UI context, creating a new one if required
+ if (SynchronizationContext.Current == null)
+ SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
+ var context = TaskScheduler.FromCurrentSynchronizationContext();
+
+ // Create the dialog, so it is available for the task
+ ProgressDialog dlg = new ProgressDialog();
+ // Set the strings
+ dlg.Text = StringUtil.GetResourceString(resourcePrefix + "_Title");
+ dlg.labelMessage.Text = StringUtil.GetResourceString(resourcePrefix + "_Label");
+
+ // Start the task
+ Exception caught = null;
+ Task task = null;
+ // And close the dialog when done
+ CompletionTracker tracker = new CompletionTracker(() =>
+ {
+ // This extra step is needed to go back into the thread context
+ task.ContinueWith(_ => { dlg._isComplete = true; dlg.DialogResult = DialogResult.OK; }, context);
+ });
+
+ task = Task.Factory.StartNew(
+ () =>
+ {
+ try
+ {
+ return action(dlg.cancel.Token, tracker);
+ }
+ catch (Exception e)
+ {
+ caught = e;
+ return default(ResultType);
+ }
+ },
+ dlg.cancel.Token);
+ dlg.task = task;
+
+ // Show the dialog
+ if (dlg.ShowDialog() != DialogResult.OK)
+ return default(ResultType);
+
+ // Rethrow any exception.
+ // The framework already handles this, but that causes breaks into the debugger
+ if (caught != null)
+ throw caught;
+
+ // Result the result
+ return task.Result;
+ }
+
private void ProgressDialog_FormClosing(object sender, FormClosingEventArgs e)
{
if (!_isComplete)
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs
index 268ca1f..7465625 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs
@@ -125,7 +125,7 @@ namespace Acacia.ZPush
private static bool IsCustomFolder(IFolder folder)
{
- return Features.GAB.FeatureGAB.IsGABContactsFolder(folder);
+ return Features.GAB.FeatureGAB.IsGABContactsFolder(folder, null);
}
private static void HideAllFolders(IStore store)