[KOE-51] Added tracking of changed names. To this end, the flag "TrackShareName" (=2) has been added. If this is set, and the name does not match the original folder's name, the name will be updated. The flag is set automatically when shares are applied and the share name matches the original name. Note that this flag does not cause the apply button to become enabled, to prevent having changes on existing shares.

This commit is contained in:
Patrick Simpson 2017-02-27 12:36:04 +01:00
parent 8ab30b53c1
commit 7773d7f973
7 changed files with 103 additions and 13 deletions

View File

@ -301,6 +301,17 @@ namespace Acacia.Features.SharedFolders
textName.Text = value ?? "";
}
}
private bool? OptionTrackName
{
get { return textName.Visible ? !_labelName.Enabled : (bool?)null; }
set
{
if (value != null)
{
_labelName.Enabled = !value.Value;
}
}
}
private FolderTreeNode _optionNameNode;
private CheckState? OptionSendAs
@ -367,6 +378,7 @@ namespace Acacia.Features.SharedFolders
_optionSendAsInitial.Clear();
_optionPermissionNodes.Clear();
OptionName = null;
OptionTrackName = null;
OptionSendAs = null;
OptionPermissions = null;
@ -406,6 +418,7 @@ namespace Acacia.Features.SharedFolders
if (_optionNameNode != null && nodes.Length == 1)
{
OptionName = _optionNameNode.SharedFolder.Name;
OptionTrackName = _optionNameNode.SharedFolder.FlagUpdateShareName;
}
else
{
@ -461,6 +474,10 @@ namespace Acacia.Features.SharedFolders
if (_optionNameNode != null)
{
_optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithName(textName.Text);
// If the share name matches the folder name, track update
bool track = _optionNameNode.SharedFolder.Name == _optionNameNode.AvailableFolder.DefaultName;
_optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithFlagUpdateShareName(track);
}
}

View File

@ -85,7 +85,7 @@ namespace Acacia.Features.SharedFolders
internal SharedFolder AddShare(AvailableFolder folder, SharedFolder state)
{
state = state ?? CreateDefaultShare(folder);
_currentShares[folder.BackendId] = state;
_currentShares[folder.BackendId] = state.PatchInformation(folder);
CheckDirty();
return state;
}
@ -98,10 +98,6 @@ namespace Acacia.Features.SharedFolders
if (folder.IsMailFolder)
share = share.WithFlagSendAsOwner(true);
// Default include the store name in root folders
if (folder.ParentId.IsNone)
share = share.WithName(folder.Name + " - " + folder.Store.UserName);
return share;
}
@ -118,6 +114,12 @@ namespace Acacia.Features.SharedFolders
SharedFolder state;
if (_initialShares.TryGetValue(folder.BackendId, out state))
{
// If the folder has been renamed, update if we're tracing it.
if (state.Name != folder.DefaultName)
{
if (state.FlagUpdateShareName)
state = state.WithName(folder.DefaultName);
}
return state;
}
return null;

View File

@ -73,9 +73,23 @@ namespace Acacia.ZPush.API.SharedFolders
public SyncId ServerId { get { return _data.ServerId; } }
public SyncId ParentId { get { return _data.ParentId; } }
public BackendId ParentIdAsBackend { get { return Parent?.BackendId ?? BackendId.NONE; } }
public BackendId BackendId { get { return _data.BackendId; } }
public string Name { get { return _data.DisplayName; } }
public string DefaultName
{
get
{
// Default include the store name in root folders
if (ParentId.IsNone)
return Name + " - " + Store.UserName;
else
return Name;
}
}
public OutlookConstants.SyncType Type { get { return _data.Type; } }
public GABUser Store { get; private set; }

View File

@ -55,13 +55,16 @@ namespace Acacia.ZPush.API.SharedFolders
return false;
SoapData rhs = (SoapData)o;
// TODO: this isn't really a full equality test, as flags is masked. This is because Equals is only used
// to test if there are changes that need to be applied. It would be nicer to rename this, and
// equals in SharedFolder to something like NeedsApply.
return
store == rhs.store &&
folderid == rhs.folderid &&
parentid == rhs.parentid &&
name == rhs.name &&
type == rhs.type &&
flags == rhs.flags;
(flags & ShareFlags.Mask_Apply) == (rhs.flags & ShareFlags.Mask_Apply);
}
public override int GetHashCode()
@ -86,6 +89,17 @@ namespace Acacia.ZPush.API.SharedFolders
return _data;
}
/// <summary>
/// Patches in any information that is available on AvailableFolder, but not SharedFolder. This is specifically the parent id.
/// </summary>
public SharedFolder PatchInformation(AvailableFolder folder)
{
if (folder.ParentIdAsBackend != _data.parentid)
{
_data.parentid = folder.ParentIdAsBackend;
}
return this;
}
#endregion
@ -100,8 +114,8 @@ namespace Acacia.ZPush.API.SharedFolders
{
store = folder.Store.UserName,
folderid = folder.BackendId,
parentid = folder.Parent?.BackendId ?? BackendId.NONE,
name = folder.Name,
parentid = folder.ParentIdAsBackend,
name = folder.DefaultName,
type = OutlookConstants.USER_SYNC_TYPES[(int)folder.Type],
flags = folder.IsMailFolder ? ShareFlags.SendAsOwner : ShareFlags.None
};
@ -161,6 +175,7 @@ namespace Acacia.ZPush.API.SharedFolders
}
public bool FlagSendAsOwner { get { return Flags.HasFlag(ShareFlags.SendAsOwner); } }
public bool FlagUpdateShareName { get { return Flags.HasFlag(ShareFlags.TrackShareName); } }
/// <summary>
/// Returns a copy with the specified 'send as owner' flag.
@ -170,6 +185,14 @@ namespace Acacia.ZPush.API.SharedFolders
return WithFlags(value ? (_data.flags | ShareFlags.SendAsOwner) : (_data.flags & ~ShareFlags.SendAsOwner));
}
/// <summary>
/// Returns a copy with the specified 'update share name' flag.
/// </summary>
public SharedFolder WithFlagUpdateShareName(bool value)
{
return WithFlags(value ? (_data.flags | ShareFlags.TrackShareName) : (_data.flags & ~ShareFlags.TrackShareName));
}
#endregion
#region Standard overrides

View File

@ -29,7 +29,22 @@ namespace Acacia.ZPush.API.SharedFolders
public enum ShareFlags
{
None = 0,
/// <summary>
/// Mails from folders containing this flag will be sent as the owner of the share, not the user.
/// </summary>
SendAsOwner = 1,
/// <summary>
/// Folders with this flag will be renamed when the original folder is renamed.
/// </summary>
TrackShareName = 2,
/// <summary>
/// The mask indicating which flag changes cause an Apply to become needed. I.e. flags not in the mask
/// are updated only if other changes are made.
/// </summary>
Mask_Apply = 1
}
/// <summary>

View File

@ -169,7 +169,21 @@ namespace Acacia.ZPush.Connect.Soap
}
private class TypeHandlerInt : TypeHandler
{
public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, "int", typeof(long)) { }
public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, null, typeof(int)) { }
public override void Serialize(string name, object value, StringBuilder s)
{
s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}</{0}>", name, value));
}
protected override object DeserializeContents(XmlNode node, Type expectedType)
{
return long.Parse(node.InnerText);
}
}
private class TypeHandlerLong : TypeHandler
{
public TypeHandlerLong() : base(SoapConstants.XMLNS_XSD, "int", typeof(long)) { }
public override void Serialize(string name, object value, StringBuilder s)
{
@ -439,6 +453,8 @@ namespace Acacia.ZPush.Connect.Soap
static SoapSerializer()
{
RegisterTypeHandler(new TypeHandlerBoolean());
// What is called an int in soap might actually be a long here.
RegisterTypeHandler(new TypeHandlerLong());
RegisterTypeHandler(new TypeHandlerInt());
RegisterTypeHandler(new TypeHandlerString());
RegisterTypeHandler(new TypeHandlerList());

View File

@ -130,11 +130,14 @@ namespace Acacia.ZPush.Connect
{
// Content
using (HttpContent content = request.GetContent())
using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel ?? CancellationToken.None).Result)
using (HttpContent responseContent = response.Content)
{
Logger.Instance.Debug(this, "Response: {0}", responseContent.ReadAsStringAsync().Result);
return request.ParseResponse(responseContent.ReadAsStreamAsync().Result);
Logger.Instance.Trace(this, "Request: {0}", content.ReadAsStringAsync().Result);
using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel ?? CancellationToken.None).Result)
using (HttpContent responseContent = response.Content)
{
Logger.Instance.Trace(this, "Response: {0}", responseContent.ReadAsStringAsync().Result);
return request.ParseResponse(responseContent.ReadAsStreamAsync().Result);
}
}
}
}