From 5478b61bd6916af78ce09df73d577deae3fd67cf Mon Sep 17 00:00:00 2001 From: mark-sil <83427558+mark-sil@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:06:44 -0400 Subject: [PATCH] =?UTF-8?q?LT-22568:=20Part=202=20=E2=80=93=20Scope=20Pub/?= =?UTF-8?q?Sub=20to=20a=20Main=20Window?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move these Subscribe calls to places where we can get the scope: ItemDataModified ConfigureCustomFields - Added PropertyTable to VwBaseVc and TextsFilterItem so a scope could be provided in additional Publish() calls. - Add support for subscribers in a new app window. - Null is still valid for a scope, but require that it is provided. - SFMImport is currently the only null (process-wide) scope. All other messages have a scope for all of the publishers and subscribers. --- .../Controls/DetailControls/StringSlice.cs | 2 +- Src/Common/Controls/XMLViews/FilterBar.cs | 2 +- Src/Common/FieldWorks/FieldWorks.cs | 9 ++-- .../FwUtils/FwUtilsTests/PubSubSystemTests.cs | 54 +++++++++---------- Src/Common/FwUtils/ISubscriber.cs | 8 +-- .../FwUtils/PublisherParameterObject.cs | 2 +- Src/Common/FwUtils/Subscriber.cs | 8 +-- Src/Common/SimpleRootSite/SimpleRootSite.cs | 1 + Src/Common/SimpleRootSite/VwBaseVc.cs | 7 ++- Src/LexText/Interlinear/TextsFilterItem.cs | 6 ++- Src/LexText/LexTextDll/LexTextApp.cs | 4 +- .../LexTextDllTests/AreaListenerTests.cs | 4 +- Src/LexText/Lexicon/FLExBridgeListener.cs | 26 ++++----- Src/xWorks/ConcDecorator.cs | 3 +- Src/xWorks/FwXWindow.cs | 13 +++++ Src/xWorks/XWorksViewBase.cs | 11 ++-- .../StubContentControlProvider.cs | 2 +- 17 files changed, 92 insertions(+), 70 deletions(-) diff --git a/Src/Common/Controls/DetailControls/StringSlice.cs b/Src/Common/Controls/DetailControls/StringSlice.cs index 872f2b1cdb..2bc0c7b352 100644 --- a/Src/Common/Controls/DetailControls/StringSlice.cs +++ b/Src/Common/Controls/DetailControls/StringSlice.cs @@ -335,7 +335,7 @@ public override void DoHotLinkAction(string strData, ISilDataAccess sda) FwLinkArgs linkArgs = new FwLinkArgs(url); linkArgs.DisplayErrorMsg = false; var retObj = new ReturnObject(linkArgs); - Publisher.Publish(new PublisherParameterObject(EventConstants.FollowLink, retObj)); + Publisher.Publish(new PublisherParameterObject(EventConstants.FollowLink, retObj, PropertyTable?.GetWindow())); if (retObj.ReturnValue) return; } diff --git a/Src/Common/Controls/XMLViews/FilterBar.cs b/Src/Common/Controls/XMLViews/FilterBar.cs index 8113ea7276..f5500ca750 100644 --- a/Src/Common/Controls/XMLViews/FilterBar.cs +++ b/Src/Common/Controls/XMLViews/FilterBar.cs @@ -1185,7 +1185,7 @@ private void MakeListChoiceFilterItem(FilterSortItem item, FwComboBox combo, str var specialItemName = MakeLabel(XmlUtils.GetOptionalAttributeValue(item.Spec, "specialItemName", XMLViewsStrings.ksChoose_)); var specialFilter = DynamicLoader.CreateObject(XmlUtils.FindNode(item.Spec, "dynamicloaderinfo"), - new object[] { specialItemName, m_cache, m_bv.Mediator }) as FilterComboItem; + new object[] { specialItemName, m_cache, m_bv.Mediator, m_bv.PropTable }) as FilterComboItem; combo.Items.Add(specialFilter); break; diff --git a/Src/Common/FieldWorks/FieldWorks.cs b/Src/Common/FieldWorks/FieldWorks.cs index 5d69adec14..67fcbc2136 100644 --- a/Src/Common/FieldWorks/FieldWorks.cs +++ b/Src/Common/FieldWorks/FieldWorks.cs @@ -478,7 +478,8 @@ private static bool LaunchApplicationFromCommandLine(FwAppArgs appArgs) private static void WarnUserAboutFailedLiftImportIfNecessary(FwApp fwApp) { - Publisher.Publish(new PublisherParameterObject(EventConstants.WarnUserAboutFailedLiftImportIfNecessary, null)); + Publisher.Publish(new PublisherParameterObject(EventConstants.WarnUserAboutFailedLiftImportIfNecessary, null, + fwApp.ActiveMainWindow as IxWindow)); } private static bool IsSharedXmlBackendNeeded(ProjectId projectId) @@ -1847,9 +1848,11 @@ private static ProjectId ShowWelcomeDialog(FwAppArgs args, FwApp startingApp, Pr if (projectLaunched) { s_projectId = projectToTry; // Window is open on this project, we must not try to initialize it again. - if (Form.ActiveForm is IxWindow mainWindow) + if (Form.ActiveForm is IxWindow) { - Publisher.Publish(new PublisherParameterObject(EventConstants.SFMImport, null, mainWindow)); + // SFMImport's subscriber is the app-level LexTextApp, which cannot be scoped, + // so this is intentionally published with a null (process-wide) scope. + Publisher.Publish(new PublisherParameterObject(EventConstants.SFMImport, null, null)); } else { diff --git a/Src/Common/FwUtils/FwUtilsTests/PubSubSystemTests.cs b/Src/Common/FwUtils/FwUtilsTests/PubSubSystemTests.cs index 95ce8fc649..4281c48736 100644 --- a/Src/Common/FwUtils/FwUtilsTests/PubSubSystemTests.cs +++ b/Src/Common/FwUtils/FwUtilsTests/PubSubSystemTests.cs @@ -76,7 +76,7 @@ public void Single_Publisher_Handler_Calls_Multiple_Publisher_on_Rentry_Does_Not // Run test. Assert.That(subscriber.One, Is.True); - Assert.DoesNotThrow(() => FwUtils.Publisher.Publish(new PublisherParameterObject("BadBoy", false))); + Assert.DoesNotThrow(() => FwUtils.Publisher.Publish(new PublisherParameterObject("BadBoy", false, null))); subscriber.DoUnsubscriptions(); SomeRandomMessageSubscriber.DoUnsubscriptions(); niceGuyMultipleSubscriber.DoUnsubscriptions(); @@ -245,7 +245,7 @@ public void Unscoped_Publish_Delivers_To_Scoped_And_Unscoped_Subscribers() unscopedSubscriber.DoSubscriptions(); // Run test. - FwUtils.Publisher.Publish(new PublisherParameterObject("MessageOne", false)); + FwUtils.Publisher.Publish(new PublisherParameterObject("MessageOne", false, null)); Assert.That(scopedSubscriber.One, Is.False); // Delivered. Assert.That(unscopedSubscriber.One, Is.False); // Delivered. @@ -352,7 +352,7 @@ public void Prefix_Subscriptions_Honor_Scope() [TestCase(" ")] public void IllFormedPublisherParameterObjectThrows(string message) { - Assert.Throws(() => { var dummy = new PublisherParameterObject(message); }); + Assert.Throws(() => { var dummy = new PublisherParameterObject(message, null, null); }); } [Test] @@ -362,9 +362,9 @@ public void VerifyPublishMessageCalls() Assert.Throws(() => FwUtils.Publisher.Publish((IList)null)); var publisherParameterObject = new List(); Assert.Throws(() => FwUtils.Publisher.Publish(publisherParameterObject)); - publisherParameterObject.Add(new PublisherParameterObject("MessageOne")); + publisherParameterObject.Add(new PublisherParameterObject("MessageOne", null, null)); Assert.Throws(() => FwUtils.Publisher.Publish(publisherParameterObject)); - publisherParameterObject.Add(new PublisherParameterObject("MessageTwo")); + publisherParameterObject.Add(new PublisherParameterObject("MessageTwo", null, null)); Assert.DoesNotThrow(() => FwUtils.Publisher.Publish(publisherParameterObject)); // Test single message Publish method override. @@ -390,8 +390,8 @@ public void Test_PublishAtEndOfAction() Assert.That(subscriber.One, Is.True); Assert.That(subscriber.Two, Is.EqualTo(int.MinValue)); - FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.RecordNavigation, false)); - FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue)); + FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.RecordNavigation, false, null)); + FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue, null)); // Confirm that nothing changed. Assert.That(subscriber.First, Is.Null); @@ -426,8 +426,8 @@ public void Test_PublishAtEndOfAction_OrderDoesNotMatter() Assert.That(subscriber.One, Is.True); Assert.That(subscriber.Two, Is.EqualTo(int.MinValue)); - FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue)); - FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.RecordNavigation, false)); + FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue, null)); + FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.RecordNavigation, false, null)); // Confirm that nothing changed. Assert.That(subscriber.First, Is.Null); @@ -462,7 +462,7 @@ public void Test_PublishAtEndOfAction_OnlyExecuteEventsThatArePublished() Assert.That(subscriber.One, Is.True); Assert.That(subscriber.Two, Is.EqualTo(int.MinValue)); - FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue)); + FwUtils.Publisher.PublishAtEndOfAction(new PublisherParameterObject(EventConstants.SelectionChanged, int.MaxValue, null)); // Confirm that nothing changed. Assert.That(subscriber.First, Is.Null); @@ -482,20 +482,20 @@ private static class TestPublisher { internal static void PublishMessageOne() { - FwUtils.Publisher.Publish(new PublisherParameterObject("MessageOne", false)); + FwUtils.Publisher.Publish(new PublisherParameterObject("MessageOne", false, null)); } internal static void PublishMessageTwo() { - FwUtils.Publisher.Publish(new PublisherParameterObject("MessageTwo", 2)); + FwUtils.Publisher.Publish(new PublisherParameterObject("MessageTwo", 2, null)); } internal static void PublishBothMessages() { var messages = new List { - new PublisherParameterObject("MessageOne", false), - new PublisherParameterObject("MessageTwo", int.MaxValue) + new PublisherParameterObject("MessageOne", false, null), + new PublisherParameterObject("MessageTwo", int.MaxValue, null) }; FwUtils.Publisher.Publish(messages); } @@ -513,7 +513,7 @@ private static void SomeRandomMessageOneHandler(object newValue) internal static void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("SomeRandomMessage", SomeRandomMessageOneHandler); + FwUtils.Subscriber.Subscribe("SomeRandomMessage", SomeRandomMessageOneHandler, null); } internal static void DoUnsubscriptions() @@ -545,8 +545,8 @@ private void MessageTwoHandler(object newValue) internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("MessageOne", MessageOneHandler); - FwUtils.Subscriber.Subscribe("MessageTwo", MessageTwoHandler); + FwUtils.Subscriber.Subscribe("MessageOne", MessageOneHandler, null); + FwUtils.Subscriber.Subscribe("MessageTwo", MessageTwoHandler, null); } internal void DoUnsubscriptions() @@ -570,7 +570,7 @@ private void SecondMessageOneHandler(object newValue) internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("MessageOne", SecondMessageOneHandler); + FwUtils.Subscriber.Subscribe("MessageOne", SecondMessageOneHandler, null); } internal void DoUnsubscriptions() @@ -593,14 +593,14 @@ internal bool One if (ShouldDoReentrantPublish) { // Bad boy! Re-entrant test should fail on this. - FwUtils.Publisher.Publish(new PublisherParameterObject("SomeRandomMessage", "Whatever")); + FwUtils.Publisher.Publish(new PublisherParameterObject("SomeRandomMessage", "Whatever", null)); } } } internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("MessageOne", ReentrantMessageOneHandler); + FwUtils.Subscriber.Subscribe("MessageOne", ReentrantMessageOneHandler, null); } internal void DoUnsubscriptions() @@ -633,8 +633,8 @@ internal bool One // Bad boy! Re-entrant test should fail on this. var messages = new List { - new PublisherParameterObject("MessageOne", false), - new PublisherParameterObject("SomeRandomMessage", "Whatever") + new PublisherParameterObject("MessageOne", false, null), + new PublisherParameterObject("SomeRandomMessage", "Whatever", null) }; FwUtils.Publisher.Publish(messages); } @@ -643,7 +643,7 @@ internal bool One internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("BadBoy", ReentrantBadBoyHandler); + FwUtils.Subscriber.Subscribe("BadBoy", ReentrantBadBoyHandler, null); } internal void DoUnsubscriptions() @@ -667,8 +667,8 @@ private sealed class NiceGuy_MultipleSubscriber internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe("MessageOne", MessageOneHandler); - FwUtils.Subscriber.Subscribe("MessageTwo", MessageTwoHandler); + FwUtils.Subscriber.Subscribe("MessageOne", MessageOneHandler, null); + FwUtils.Subscriber.Subscribe("MessageTwo", MessageTwoHandler, null); } internal void DoUnsubscriptions() @@ -777,8 +777,8 @@ private sealed class EndOfAction_MultipleSubscriber internal void DoSubscriptions() { - FwUtils.Subscriber.Subscribe(EventConstants.RecordNavigation, RecordNavigationHandler); - FwUtils.Subscriber.Subscribe(EventConstants.SelectionChanged, SelectionChangedHandler); + FwUtils.Subscriber.Subscribe(EventConstants.RecordNavigation, RecordNavigationHandler, null); + FwUtils.Subscriber.Subscribe(EventConstants.SelectionChanged, SelectionChangedHandler, null); } internal void DoUnsubscriptions() diff --git a/Src/Common/FwUtils/ISubscriber.cs b/Src/Common/FwUtils/ISubscriber.cs index 9a8586979d..ffbdb99fd9 100644 --- a/Src/Common/FwUtils/ISubscriber.cs +++ b/Src/Common/FwUtils/ISubscriber.cs @@ -20,11 +20,11 @@ public interface ISubscriber /// The message being subscribed to receive. /// The method on subscriber to call, when /// has been published - /// Optional delivery scope (normally the subscriber's main window). + /// Delivery scope, normally the subscriber's main window; pass null to subscribe process-wide. /// When non-null, scoped publishes of are delivered only if they /// carry the same scope. Null subscribes will receive messages from all publishers. /// See . - void Subscribe(string message, Action messageHandler, IPubSubScope scope = null); + void Subscribe(string message, Action messageHandler, IPubSubScope scope); /// /// An object subscribes to messages that begin with using @@ -37,11 +37,11 @@ public interface ISubscriber /// The message prefix being subscribed to receive. /// The method on subscriber to call, when a message that /// begins with has been published. - /// Optional delivery scope (normally the subscriber's main window). + /// Delivery scope, normally the subscriber's main window; pass null to subscribe process-wide. /// When non-null, scoped publishes of matching messages are delivered only if they /// carry the same scope. Null subscribes will receive messages from all publishers. /// See . - void PrefixSubscribe(string messagePrefix, Action messageHandler, IPubSubScope scope = null); + void PrefixSubscribe(string messagePrefix, Action messageHandler, IPubSubScope scope); /// /// Register end of interest (unsubscribe) of an object in receiving diff --git a/Src/Common/FwUtils/PublisherParameterObject.cs b/Src/Common/FwUtils/PublisherParameterObject.cs index a678f4e054..8533129192 100644 --- a/Src/Common/FwUtils/PublisherParameterObject.cs +++ b/Src/Common/FwUtils/PublisherParameterObject.cs @@ -8,7 +8,7 @@ namespace SIL.FieldWorks.Common.FwUtils { public sealed class PublisherParameterObject { - public PublisherParameterObject(string message, object data = null, IPubSubScope scope = null) + public PublisherParameterObject(string message, object data, IPubSubScope scope) { if (string.IsNullOrWhiteSpace(message)) { diff --git a/Src/Common/FwUtils/Subscriber.cs b/Src/Common/FwUtils/Subscriber.cs index c838a354e4..4438e34f5c 100644 --- a/Src/Common/FwUtils/Subscriber.cs +++ b/Src/Common/FwUtils/Subscriber.cs @@ -27,11 +27,11 @@ internal sealed class Subscriber : ISubscriber /// The message being subscribed to receive. /// The method on subscriber to call, when /// has been published - /// Optional delivery scope (normally the subscriber's main window). + /// Delivery scope, normally the subscriber's main window; pass null to subscribe process-wide. /// When non-null, scoped publishes of are delivered only if they /// carry the same scope. Null subscribes will receive messages from all publishers. /// See . - public void Subscribe(string message, Action messageHandler, IPubSubScope scope = null) + public void Subscribe(string message, Action messageHandler, IPubSubScope scope) { if (!_subscriptions.TryGetValue(message, out var subscribers)) { @@ -54,11 +54,11 @@ public void Subscribe(string message, Action messageHandler, IPubSubScop /// The message prefix being subscribed to receive. /// The method on subscriber to call, when a message that /// begins with has been published. - /// Optional delivery scope (normally the subscriber's main window). + /// Delivery scope, normally the subscriber's main window; pass null to subscribe process-wide. /// When non-null, scoped publishes of matching messages are delivered only if they /// carry the same scope. Null subscribes will receive messages from all publishers. /// See . - public void PrefixSubscribe(string messagePrefix, Action messageHandler, IPubSubScope scope = null) + public void PrefixSubscribe(string messagePrefix, Action messageHandler, IPubSubScope scope) { if (!_prefixSubscriptions.TryGetValue(messagePrefix, out var prefixSubscribers)) { diff --git a/Src/Common/SimpleRootSite/SimpleRootSite.cs b/Src/Common/SimpleRootSite/SimpleRootSite.cs index 651be51567..3f6e898759 100644 --- a/Src/Common/SimpleRootSite/SimpleRootSite.cs +++ b/Src/Common/SimpleRootSite/SimpleRootSite.cs @@ -6196,6 +6196,7 @@ private void SetupVc() { // This really only needs to be done once but I can't find another reliable way to do it. ((VwBaseVc) vc).Mediator = m_mediator; + ((VwBaseVc) vc).PropertyTable = m_propertyTable; } } diff --git a/Src/Common/SimpleRootSite/VwBaseVc.cs b/Src/Common/SimpleRootSite/VwBaseVc.cs index 8fe62baffa..10e502a4b9 100644 --- a/Src/Common/SimpleRootSite/VwBaseVc.cs +++ b/Src/Common/SimpleRootSite/VwBaseVc.cs @@ -210,6 +210,11 @@ public virtual ITsString UpdateProp(IVwSelection vwsel, int hvo, int tag, int fr /// internal Mediator Mediator { get; set; } + /// + /// PropertyTable is supplied during first real layout by the root site (see SetupVc). + /// + protected internal PropertyTable PropertyTable { get; set; } + /// ----------------------------------------------------------------------------------- /// /// Perform whatever action is appropriate when the user clicks on a hot link @@ -236,7 +241,7 @@ public virtual void DoHotLinkAction(string strData, ISilDataAccess sda) // See if we can handle it (via our own LinkListener) without starting a process. var args = new LocalLinkArgs { Link = url }; - Publisher.Publish(new PublisherParameterObject(EventConstants.HandleLocalHotlink, args)); + Publisher.Publish(new PublisherParameterObject(EventConstants.HandleLocalHotlink, args, PropertyTable?.GetWindow())); if (args.LinkHandledLocally) { return; diff --git a/Src/LexText/Interlinear/TextsFilterItem.cs b/Src/LexText/Interlinear/TextsFilterItem.cs index bae364f76e..2d710fb69e 100644 --- a/Src/LexText/Interlinear/TextsFilterItem.cs +++ b/Src/LexText/Interlinear/TextsFilterItem.cs @@ -19,15 +19,17 @@ namespace SIL.FieldWorks.IText public class TextsFilterItem : NoChangeFilterComboItem { private Mediator m_mediator; + private PropertyTable m_propertyTable; - public TextsFilterItem(ITsString tssName, LcmCache cache, Mediator mediator) : base(tssName) + public TextsFilterItem(ITsString tssName, LcmCache cache, Mediator mediator, PropertyTable propertyTable) : base(tssName) { m_mediator = mediator; + m_propertyTable = propertyTable; } public override bool Invoke() { - Publisher.Publish(new PublisherParameterObject(EventConstants.AddTexts, this)); + Publisher.Publish(new PublisherParameterObject(EventConstants.AddTexts, this, m_propertyTable?.GetWindow())); return false; // Whatever the user did, we don't currently count it as changing the filter. } diff --git a/Src/LexText/LexTextDll/LexTextApp.cs b/Src/LexText/LexTextDll/LexTextApp.cs index a7f6b33a1b..dd0b274b47 100644 --- a/Src/LexText/LexTextDll/LexTextApp.cs +++ b/Src/LexText/LexTextDll/LexTextApp.cs @@ -77,7 +77,9 @@ public override void DoApplicationInitialization(IProgress progressDlg) if (progressDlg != null) progressDlg.Message = LexTextStrings.ksLoading_; - Subscriber.Subscribe(EventConstants.SFMImport, SFMImport); + // LexTextApp is the per-application object (no single window), so this is intentionally + // subscribed with a null (process-wide) scope. + Subscriber.Subscribe(EventConstants.SFMImport, SFMImport, null); } /// ------------------------------------------------------------------------------------ diff --git a/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs b/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs index 0277589f58..484649e487 100644 --- a/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs +++ b/Src/LexText/LexTextDll/LexTextDllTests/AreaListenerTests.cs @@ -216,7 +216,7 @@ public void GetToolForList_KnownList_ReturnsConfiguredToolName() parameters[0] = list; // SUT: publish exactly as LinkListener.FollowActiveLink does. - Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters)); + Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters, null)); // Verify: the configured tool name was returned via the payload. Assert.That(parameters[1], Is.EqualTo("myConfiguredListEdit")); @@ -243,7 +243,7 @@ public void GetToolForList_UnknownList_ReturnsCustomToolName() parameters[0] = customList; // SUT - Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters)); + Publisher.Publish(new PublisherParameterObject(EventConstants.GetToolForList, parameters, null)); // Verify: whitespace stripped from the name, with "Edit" appended. Assert.That(parameters[1], Is.EqualTo("MyCustomListEdit")); diff --git a/Src/LexText/Lexicon/FLExBridgeListener.cs b/Src/LexText/Lexicon/FLExBridgeListener.cs index b3ca8c942f..40d42022b0 100644 --- a/Src/LexText/Lexicon/FLExBridgeListener.cs +++ b/Src/LexText/Lexicon/FLExBridgeListener.cs @@ -90,9 +90,9 @@ public void Init(Mediator mediator, PropertyTable propertyTable, XmlNode configu _parentForm = _propertyTable.GetValue
("window"); mediator.AddColleague(this); - Subscriber.Subscribe(EventConstants.WarnUserAboutFailedLiftImportIfNecessary, WarnUserAboutFailedLiftImportIfNecessary); - Subscriber.Subscribe(EventConstants.ViewLiftMessages, ViewLiftMessages); - Subscriber.Subscribe(EventConstants.ViewMessages, ViewMessages); + Subscriber.Subscribe(EventConstants.WarnUserAboutFailedLiftImportIfNecessary, WarnUserAboutFailedLiftImportIfNecessary, _propertyTable.GetWindow()); + Subscriber.Subscribe(EventConstants.ViewLiftMessages, ViewLiftMessages, _propertyTable.GetWindow()); + Subscriber.Subscribe(EventConstants.ViewMessages, ViewMessages, _propertyTable.GetWindow()); } public int Priority @@ -344,12 +344,13 @@ public bool OnFLExBridge(object commandObject) { bool conflictOccurred = DetectMainConflicts(projectFolder, savedState); var app = _propertyTable.GetValue("App"); - RefreshCacheWindowAndAll(app, fullProjectFileName); + var newAppWindow = RefreshCacheWindowAndAll(app, fullProjectFileName); if (conflictOccurred) { - // Send a message for the reopened instance to display the message viewer (used to be conflict report), - // we have been disposed by now. - Publisher.Publish(new PublisherParameterObject(EventConstants.ViewMessages, null)); + // Send a message for the reopened instance to display the message viewer (used to be conflict report); + // we have been disposed by now. Scope to the newly reopened window so only its listener + // responds, not the listeners of any other open windows. + Publisher.Publish(new PublisherParameterObject(EventConstants.ViewMessages, null, newAppWindow)); } } else //Re-lock project if we aren't trying to close the app @@ -494,12 +495,13 @@ public bool OnLiftBridge(object argument) { bool conflictOccurred = DetectLiftConflicts(liftFolder, savedState); var app = _propertyTable.GetValue("App"); - RefreshCacheWindowAndAll(app, fullProjectFileName); + var newAppWindow = RefreshCacheWindowAndAll(app, fullProjectFileName); if (conflictOccurred) { - // Send a message for the reopened instance to display the message viewer (used to be conflict report), - // we have been disposed by now. - Publisher.Publish(new PublisherParameterObject(EventConstants.ViewLiftMessages, null)); + // Send a message for the reopened instance to display the message viewer (used to be conflict report); + // we have been disposed by now. Scope to the newly reopened window so only its listener + // responds, not the listeners of any other open windows. + Publisher.Publish(new PublisherParameterObject(EventConstants.ViewLiftMessages, null, newAppWindow)); } } @@ -873,7 +875,7 @@ public static string SendReceiveUser ///
private void StopParser() { - Publisher.Publish(new PublisherParameterObject(EventConstants.StopParser)); + Publisher.Publish(new PublisherParameterObject(EventConstants.StopParser, null, _propertyTable.GetWindow())); } /// diff --git a/Src/xWorks/ConcDecorator.cs b/Src/xWorks/ConcDecorator.cs index 6825d9845b..e195574210 100644 --- a/Src/xWorks/ConcDecorator.cs +++ b/Src/xWorks/ConcDecorator.cs @@ -54,8 +54,6 @@ public ConcDecorator(ISilDataAccessManaged domainDataByFlid, XmlNode configurati { m_services = services; SetOverrideMdc(new ConcMdc(MetaDataCache as IFwMetaDataCacheManaged)); - - Subscriber.Subscribe(EventConstants.ItemDataModified, ItemDataModified); } internal const int kflidWfOccurrences = 899923; // occurrences of a wordform @@ -552,6 +550,7 @@ public void SetMediator(Mediator mediator, PropertyTable propertyTable) { Mediator = mediator; PropTable = propertyTable; + Subscriber.Subscribe(EventConstants.ItemDataModified, ItemDataModified, propertyTable.GetWindow()); } private InterestingTextList InterestingTextsList diff --git a/Src/xWorks/FwXWindow.cs b/Src/xWorks/FwXWindow.cs index abac6d170a..8b67cdfdd7 100644 --- a/Src/xWorks/FwXWindow.cs +++ b/Src/xWorks/FwXWindow.cs @@ -315,6 +315,7 @@ private void BasicInit(FwApp app) m_propertyTable.SetPropertyPersistence("App", false); } Subscriber.Subscribe(EventConstants.JumpToPopupLexEntry, JumpToPopupLexEntry, this); + Subscriber.Subscribe(EventConstants.ConfigureCustomFields, ConfigureCustomFields, this); } /// ------------------------------------------------------------------------------------ @@ -442,6 +443,7 @@ protected override void Dispose(bool disposing) if (disposing) { Subscriber.Unsubscribe(EventConstants.JumpToPopupLexEntry, JumpToPopupLexEntry); + Subscriber.Unsubscribe(EventConstants.ConfigureCustomFields, ConfigureCustomFields); if (m_viewHelper != null) m_viewHelper.Dispose(); @@ -1223,6 +1225,17 @@ protected bool OnFileProjectProperties(object command) return true; } + /// ------------------------------------------------------------------------------------ + /// + /// Pub/Sub subscriber for ConfigureCustomFields. The payload tuple carries the publishing + /// window's Mediator/PropertyTable/area. + /// + /// ------------------------------------------------------------------------------------ + private void ConfigureCustomFields(object args) + { + XWorksViewBase.ConfigureCustomFields(args); + } + /// ------------------------------------------------------------------------------------ /// /// Create a popup window to edit the given lexical entry. diff --git a/Src/xWorks/XWorksViewBase.cs b/Src/xWorks/XWorksViewBase.cs index b0ed0e75f6..d1fe3087c3 100644 --- a/Src/xWorks/XWorksViewBase.cs +++ b/Src/xWorks/XWorksViewBase.cs @@ -96,12 +96,6 @@ public enum TreebarAvailability #endregion Data members #region Construction and disposal - static XWorksViewBase() - { - // Subscribe to requests to display the ConfigureCustomFields dialog only once, not once per instance - Subscriber.Subscribe(EventConstants.ConfigureCustomFields, ConfigureCustomFields); - } - /// /// Initializes a new instance of the class. /// @@ -674,9 +668,10 @@ public bool OnAddCustomField(object _) } /// - /// Display a dialog to allow users to modify Custom Fields + /// Display a dialog to allow users to modify Custom Fields. Shared utility invoked both by + /// the OnAddCustomField menu handler and by FwXWindow's ConfigureCustomFields subscription. /// - private static void ConfigureCustomFields(object propTableAndArea) + internal static void ConfigureCustomFields(object propTableAndArea) { if (!(propTableAndArea is Tuple args)) { diff --git a/Src/xWorks/xWorksTests/DictionaryConfigurationMigrators/StubContentControlProvider.cs b/Src/xWorks/xWorksTests/DictionaryConfigurationMigrators/StubContentControlProvider.cs index ff6c432f84..d25ecf2dc8 100644 --- a/Src/xWorks/xWorksTests/DictionaryConfigurationMigrators/StubContentControlProvider.cs +++ b/Src/xWorks/xWorksTests/DictionaryConfigurationMigrators/StubContentControlProvider.cs @@ -65,7 +65,7 @@ public StubContentControlProvider() var reversalDoc = new XmlDocument(); reversalDoc.LoadXml(m_contentControlReversal); m_testControlRevNode = reversalDoc.DocumentElement; - Subscriber.Subscribe(EventConstants.GetContentControlParameters, GetContentControlParameters); + Subscriber.Subscribe(EventConstants.GetContentControlParameters, GetContentControlParameters, null); } public void Init(Mediator mediator, PropertyTable propertyTable, XmlNode configurationParameters)