diff --git a/Src/LexText/LexTextDll/AreaListener.cs b/Src/LexText/LexTextDll/AreaListener.cs
index 61ecee5ef7..bd454aa5a4 100644
--- a/Src/LexText/LexTextDll/AreaListener.cs
+++ b/Src/LexText/LexTextDll/AreaListener.cs
@@ -130,6 +130,7 @@ protected virtual void Dispose(bool disposing)
Subscriber.Unsubscribe(EventConstants.SetToolFromName, SetToolFromName);
Subscriber.Unsubscribe(EventConstants.ReloadAreaTools, ReloadAreaTools);
Subscriber.Unsubscribe(EventConstants.GetContentControlParameters, GetContentControlParameters);
+ Subscriber.Unsubscribe(EventConstants.GetToolForList, GetToolForList);
Subscriber.Unsubscribe(EventConstants.SetInitialContentObject, SetInitialContentObject);
// Dispose managed resources here.
@@ -157,6 +158,7 @@ public void Init(Mediator mediator, PropertyTable propertyTable, XmlNode configu
Subscriber.Subscribe(EventConstants.SetToolFromName, SetToolFromName);
Subscriber.Subscribe(EventConstants.ReloadAreaTools, ReloadAreaTools);
Subscriber.Subscribe(EventConstants.GetContentControlParameters, GetContentControlParameters);
+ Subscriber.Subscribe(EventConstants.GetToolForList, GetToolForList);
}
private DateTime m_lastToolChange = DateTime.MinValue;
@@ -379,12 +381,11 @@ private bool FillListAreaList(UIListDisplayProperties display)
}
///
- /// This method is called BY REFLECTION through the mediator from LinkListener.FollowActiveLink, because the assembly dependencies
+ /// This method is called through the FwUtils Publisher/Subscriber from LinkListener.FollowActiveLink, because the assembly dependencies
/// are in the wrong direction. It finds the name of the tool we need to invoke to edit a given list.
+ /// The result is returned via the second element of the object array payload.
///
- ///
- ///
- public bool OnGetToolForList(object parameters)
+ private void GetToolForList(object parameters)
{
var realParams = (object[]) parameters;
var list = (ICmPossibilityList)realParams[0];
@@ -409,12 +410,11 @@ public bool OnGetToolForList(object parameters)
if (possibleList == list)
{
realParams[1] = toolName;
- return true;
+ return;
}
}
// If it's not a known list, try custom.
realParams[1] = GetCustomListToolName(list);
- return true;
}
#region Custom List Methods
diff --git a/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs b/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs
index 665773ec92..0277589f58 100644
--- a/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs
+++ b/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs
@@ -12,8 +12,10 @@
using NUnit.Framework;
using SIL.LCModel;
using SIL.LCModel.DomainServices;
+using SIL.FieldWorks.Common.FwUtils;
using SIL.FieldWorks.XWorks.LexText;
using XCore;
+using static SIL.FieldWorks.Common.FwUtils.FwUtils;
namespace LexTextDllTests
{
@@ -115,6 +117,35 @@ private static XmlNode SetupMinimalWindowConfig()
return fakeWindowConfig.DocumentElement;
}
+ ///
+ /// Builds a window configuration whose 'lists' area has a single tool wired, via its clerk's
+ /// recordList, to the possibility list identified by .
+ ///
+ private static XmlNode SetupWindowConfigWithListTool(string clerkId, string toolValue, string listGuid)
+ {
+ var fakeWindowConfig = new XmlDocument();
+ fakeWindowConfig.LoadXml(
+ ""
+ + ""
+ + ""
+ + "- "
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + "
"
+ + "");
+ return fakeWindowConfig.DocumentElement;
+ }
+
#endregion
///--------------------------------------------------------------------------------------
@@ -161,5 +192,61 @@ public void AddListToXmlConfig()
var ccontextNodesAfter = node.SelectNodes(contextXPath).Count;
Assert.That(ccontextNodesAfter, Is.EqualTo(ccontextNodesBefore + 1), "Didn't add a context menu node.");
}
+
+ ///--------------------------------------------------------------------------------------
+ ///
+ /// Publishing EventConstants.GetToolForList for a list that is wired into the window
+ /// configuration must return that tool's name via the second element of the payload array.
+ /// This exercises the full Pub/Sub path that LinkListener.FollowActiveLink relies on:
+ /// publish through the Publisher, the AreaListener subscriber handles it synchronously,
+ /// and the result comes back in parameters[1]. (LT-21515)
+ ///
+ ///--------------------------------------------------------------------------------------
+ [Test]
+ public void GetToolForList_KnownList_ReturnsConfiguredToolName()
+ {
+ // Setup: a list wired to a configured tool via its clerk's recordList.
+ var ws = WritingSystemServices.kwsAnals;
+ var list = Cache.ServiceLocator.GetInstance().CreateUnowned("Some List", ws);
+ var windowConfig = SetupWindowConfigWithListTool("someListClerk", "myConfiguredListEdit", list.Guid.ToString());
+ m_propertyTable.SetProperty("WindowConfiguration", windowConfig, true);
+ m_propertyTable.SetPropertyPersistence("WindowConfiguration", false);
+
+ var parameters = new object[2];
+ parameters[0] = list;
+
+ // SUT: publish exactly as LinkListener.FollowActiveLink does.
+ Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters));
+
+ // Verify: the configured tool name was returned via the payload.
+ Assert.That(parameters[1], Is.EqualTo("myConfiguredListEdit"));
+ }
+
+ ///--------------------------------------------------------------------------------------
+ ///
+ /// Publishing EventConstants.GetToolForList for a list that is NOT in the configuration
+ /// must fall back to the generated custom-list tool name (the list name with whitespace
+ /// removed, plus "Edit"), returned via parameters[1]. (LT-21515)
+ ///
+ ///--------------------------------------------------------------------------------------
+ [Test]
+ public void GetToolForList_UnknownList_ReturnsCustomToolName()
+ {
+ // Setup: a window configuration whose 'tools' section has no matching tool.
+ m_propertyTable.SetProperty("WindowConfiguration", SetupMinimalWindowConfig(), true);
+ m_propertyTable.SetPropertyPersistence("WindowConfiguration", false);
+
+ var ws = WritingSystemServices.kwsAnals;
+ var customList = Cache.ServiceLocator.GetInstance().CreateUnowned("My Custom List", ws);
+
+ var parameters = new object[2];
+ parameters[0] = customList;
+
+ // SUT
+ Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters));
+
+ // Verify: whitespace stripped from the name, with "Edit" appended.
+ Assert.That(parameters[1], Is.EqualTo("MyCustomListEdit"));
+ }
}
}
diff --git a/Src/xWorks/LinkListener.cs b/Src/xWorks/LinkListener.cs
index 640761ab86..c69a9065df 100644
--- a/Src/xWorks/LinkListener.cs
+++ b/Src/xWorks/LinkListener.cs
@@ -509,12 +509,10 @@ private bool FollowActiveLink(bool suspendLoadingRecord)
// Unfortunately AreaListener is in an assembly we can't reference.
// But there may be custom ones, so just listing them all here does not seem to be an option,
// and anyway it would be hard to maintain.
- // Thus we've created this method (on AreaListener) which we call awkwardly throught the mediator.
+ // Thus we've created this method (on AreaListener) which we call through the FwUtils Publisher/Subscriber.
var parameters = new object[2];
parameters[0] = majorObject;
-#pragma warning disable 618 // suppress obsolete warning
- m_mediator.SendMessage("GetToolForList", parameters);
-#pragma warning restore 618
+ Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters));
realTool = (string)parameters[1];
break;
case RnResearchNbkTags.kClassId: