diff --git a/Src/Common/Controls/DetailControls/DetailControlsTests/SliceInsertJumpTests.cs b/Src/Common/Controls/DetailControls/DetailControlsTests/SliceInsertJumpTests.cs new file mode 100644 index 0000000000..053703e6e0 --- /dev/null +++ b/Src/Common/Controls/DetailControls/DetailControlsTests/SliceInsertJumpTests.cs @@ -0,0 +1,126 @@ +// Copyright (c) 2026 SIL International +// This software is licensed under the LGPL, version 2.1 or later +// (http://www.gnu.org/licenses/lgpl-2.1.html) + +using System.Collections.Generic; +using System.Windows.Forms; +using NUnit.Framework; +using SIL.FieldWorks.Common.FwUtils; +using static SIL.FieldWorks.Common.FwUtils.FwUtils; +using SIL.LCModel; +using SIL.LCModel.Core.Text; +using XCore; + +namespace SIL.FieldWorks.Common.Framework.DetailControls +{ + /// + /// An insert that leaves no slice for the new object publishes JumpToRecord for it, to the + /// slice's own window only. + /// + [TestFixture] + public class SliceInsertJumpTests : MemoryOnlyBackendProviderRestoredForEachTestTestBase + { + private Inventory m_parts; + private Inventory m_layouts; + private ILexEntry m_entry; + private Mediator m_mediator; + private PropertyTable m_propertyTable; + private DataTree m_dtree; + private Form m_parent; + private StubWindow m_otherWindow; + private List m_jumps; + private List m_otherWindowJumps; + + public override void FixtureSetup() + { + base.FixtureSetup(); + m_layouts = DataTreeTests.GenerateLayouts(); + m_parts = DataTreeTests.GenerateParts(); + } + + public override void TestSetup() + { + base.TestSetup(); + + m_entry = Cache.ServiceLocator.GetInstance().Create(); + m_entry.CitationForm.VernacularDefaultWritingSystem = + TsStringUtils.MakeString("form", Cache.DefaultVernWs); + + m_mediator = new Mediator(); + m_propertyTable = new PropertyTable(m_mediator); + m_propertyTable.SetProperty("cache", Cache, false); + m_propertyTable.SetPropertyDispose("cache", false); + var window = new StubWindow(); + m_propertyTable.SetProperty("window", window, false); + m_otherWindow = new StubWindow(); + m_jumps = new List(); + m_otherWindowJumps = new List(); + Subscriber.Subscribe(EventConstants.JumpToRecord, RecordJump, window); + Subscriber.Subscribe(EventConstants.JumpToRecord, RecordOtherWindowJump, m_otherWindow); + + m_dtree = new DataTree(); + m_dtree.Init(m_mediator, m_propertyTable, null); + m_parent = new Form(); + m_parent.Controls.Add(m_dtree); + m_dtree.Initialize(Cache, false, m_layouts, m_parts); + // This layout shows the citation form only, so an etymology gets no slice. + m_dtree.ShowObject(m_entry, "CfOnly", null, m_entry, false); + + // The insert runs its own unit of work. + m_actionHandler.EndUndoTask(); + } + + public override void TestTearDown() + { + Subscriber.Unsubscribe(EventConstants.JumpToRecord, RecordJump); + Subscriber.Unsubscribe(EventConstants.JumpToRecord, RecordOtherWindowJump); + if (m_parent != null) + { + m_parent.Close(); + m_parent.Dispose(); + m_parent = null; + } + if (m_propertyTable != null) + { + m_propertyTable.Dispose(); + m_propertyTable = null; + } + if (m_mediator != null) + { + m_mediator.Dispose(); + m_mediator = null; + } + + base.TestTearDown(); + } + + private void RecordJump(object target) => m_jumps.Add(target); + + private void RecordOtherWindowJump(object target) => m_otherWindowJumps.Add(target); + + [Test] + public void InsertWithNoSliceForTheNewObject_JumpsToIt() + { + var slice = (Slice)m_dtree.Controls[0]; + + slice.HandleInsertCommand("Etymology", "LexEtymology", "LexEntry", null, + out var newObject); + + Assert.That(newObject, Is.InstanceOf(), "the insert happened"); + Assert.That(m_jumps, Is.EqualTo(new object[] { newObject.Hvo }), + "one jump, to the new object, by the time the insert returns"); + Assert.That(m_otherWindowJumps, Is.Empty, "another window hears nothing"); + Assert.That(m_mediator.JobItems, Is.Zero, "nothing is queued on the Mediator"); + } + + private sealed class StubWindow : IxWindow + { + public Mediator Mediator => null; + public PropertyTable PropTable => null; + public void SuspendIdleProcessing() { } + public void ResumeIdleProcessing() { } + public void SuspendWindowSizePersistence() { } + public void ResumeWindowSizePersistence() { } + } + } +} diff --git a/Src/Common/Controls/DetailControls/Slice.cs b/Src/Common/Controls/DetailControls/Slice.cs index bae37ac5fc..2f4d9e469a 100644 --- a/Src/Common/Controls/DetailControls/Slice.cs +++ b/Src/Common/Controls/DetailControls/Slice.cs @@ -13,6 +13,7 @@ using SIL.FieldWorks.Common.Controls; using SIL.FieldWorks.Common.Framework.DetailControls.Resources; using SIL.FieldWorks.Common.FwUtils; +using static SIL.FieldWorks.Common.FwUtils.FwUtils; using SIL.FieldWorks.Common.DetailRules; using SIL.FieldWorks.Common.RootSites; using SIL.FieldWorks.FdoUi; @@ -2091,10 +2092,8 @@ int InsertObject(int flid, int newObjectClassId, out ICmObject newObject) else { // If possible, jump to the newly inserted sub item. -#pragma warning disable 618 // suppress obsolete warning - if (m_mediator.BroadcastMessageUntilHandled("JumpToRecord", uiObj.Object.Hvo)) -#pragma warning restore 618 - return insertionPosition; + Publisher.Publish(new PublisherParameterObject(EventConstants.JumpToRecord, + uiObj.Object.Hvo, m_propertyTable.GetWindow())); // If we haven't found a slice...common now, because there's rarely a need to expand anything... // and some slice was added, focus it. foreach (Slice slice in Parent.Controls) diff --git a/Src/LexText/Lexicon/ReversalEntryPOS.cs b/Src/LexText/Lexicon/ReversalEntryPOS.cs index 7ded706ed7..5060288d9a 100644 --- a/Src/LexText/Lexicon/ReversalEntryPOS.cs +++ b/Src/LexText/Lexicon/ReversalEntryPOS.cs @@ -10,6 +10,7 @@ using SIL.FieldWorks.Common.Controls; using SIL.FieldWorks.Common.Framework.DetailControls; using SIL.FieldWorks.Common.FwUtils; +using static SIL.FieldWorks.Common.FwUtils.FwUtils; using SIL.LCModel; using SIL.LCModel.Infrastructure; using XCore; @@ -95,9 +96,8 @@ public bool OnMoveReversalPOS(object cmd) }); // Note: PropChanged should happen on the old owner and the new in the 'Add" method call. // Have to jump to a main PartOfSpeech, as RecordClerk doesn't know anything about subcategories. -#pragma warning disable 618 // suppress obsolete warning - m_mediator.BroadcastMessageUntilHandled("JumpToRecord", newOwner.MainPossibility.Hvo); -#pragma warning restore 618 + Publisher.Publish(new PublisherParameterObject(EventConstants.JumpToRecord, + newOwner.MainPossibility.Hvo, m_propertyTable.GetWindow())); } } @@ -165,9 +165,8 @@ public bool OnMergeReversalPOS(object cmd) ()=> survivor.MergeObject(currentPOS, false)); // Note: PropChanged should happen on the old owner and the new in the 'Add" method call. // Have to jump to a main PartOfSpeech, as RecordClerk doesn't know anything about subcategories. -#pragma warning disable 618 // suppress obsolete warning - m_mediator.BroadcastMessageUntilHandled("JumpToRecord", survivor.MainPossibility.Hvo); -#pragma warning restore 618 + Publisher.Publish(new PublisherParameterObject(EventConstants.JumpToRecord, + survivor.MainPossibility.Hvo, m_propertyTable.GetWindow())); } }