diff --git a/Src/xWorks/Avalonia/Composer/DetailComposer.cs b/Src/xWorks/Avalonia/Composer/DetailComposer.cs index d748be529a..a818a74f60 100644 --- a/Src/xWorks/Avalonia/Composer/DetailComposer.cs +++ b/Src/xWorks/Avalonia/Composer/DetailComposer.cs @@ -536,10 +536,15 @@ private ViewDefinitionModel CompileForObjectWithOverrides(ICmObject obj, string private bool HideWhenEmpty(ViewNode node) => node.Visibility == ViewVisibility.IfData && !_showHidden; /// - /// Whether the DOMAIN says this field does not apply to this object, which legacy - /// asks before building a slice (SliceFilter -> ICmObject.IsFieldRelevant). StemName - /// is irrelevant on a clitic or particle, Position on a non-infix, InflectionClasses - /// on some affix forms. + /// Whether the DOMAIN says this field does not apply to this object. StemName is + /// irrelevant on a clitic or particle, Position on a non-infix, InflectionClasses on + /// some affix forms, FromPartsOfSpeech on an entry with no clitic. + /// + /// This is the SECOND of the two gates legacy's SliceFilter.IncludeSlice applies, not + /// the whole of it. The first looks the slice's id up in the tool's filter list and + /// withholds the row when it is listed; that one is NOT implemented here, because + /// the id never reaches the composer -- the importer does not carry it, and + /// ViewNode has no Id. Tracked as LT-22802. /// /// Not the same as hidden: show-hidden-fields does NOT reveal an irrelevant field, so /// this is checked whatever _showHidden says. Legacy's propsToMonitor set is diff --git a/Src/xWorks/xWorksTests/Avalonia/Composer/DetailFieldRelevanceTests.cs b/Src/xWorks/xWorksTests/Avalonia/Composer/DetailFieldRelevanceTests.cs index 9883332317..a500d43f06 100644 --- a/Src/xWorks/xWorksTests/Avalonia/Composer/DetailFieldRelevanceTests.cs +++ b/Src/xWorks/xWorksTests/Avalonia/Composer/DetailFieldRelevanceTests.cs @@ -12,12 +12,13 @@ namespace SIL.FieldWorks.XWorks { /// /// The composer asks the DOMAIN whether a field applies to an object before emitting a row, - /// which legacy does through SliceFilter -> ICmObject.IsFieldRelevant. + /// through ICmObject.IsFieldRelevant -- the second of the two gates legacy's + /// SliceFilter.IncludeSlice applies (the id/filter-list gate is LT-22802). /// /// Five classes override it in liblcm. MoStemAllomorph.StemName is covered by - /// AllomorphSectionCompositionTests; the detail-view relevant remainder is covered here. - /// VirtualOrdering also overrides it, but that class is not shown in a detail view, so there - /// is nothing for the composer to gate. + /// AllomorphSectionCompositionTests; VirtualOrdering is not shown in a detail view, so there + /// is nothing to gate. The rest are here, EXCEPT the InflectionClass limb that withholds the + /// row from a compound rule's left/right MSA, which no test reaches. /// /// Every test runs with showHiddenFields TRUE. Relevance is not a hidden field -- legacy /// withholds an irrelevant row even with Show Hidden Fields on -- and the flag also keeps an @@ -130,6 +131,44 @@ public void Compose_AffixInflectionClasses_OnlyWhenTheEntrySupportsThem() "now there is something to choose from, so the row composes"); } + /// + /// MoStemMsa.FromPartsOfSpeech ("Attaches to Categories") is relevant only when the + /// owning entry has a proclitic or enclitic allomorph. The layout declares that part + /// visibility="always", so before the relevance gate it composed on EVERY stem MSA -- + /// making this the gate's most visible consequence, and the one with the most rows + /// riding on it. + /// + [Test] + public void Compose_FromPartsOfSpeech_OnlyForAnEntryWithAClitic() + { + ILexEntry entry = null; + IMoStemMsa msa = null; + NonUndoableUnitOfWorkHelper.Do(Cache.ActionHandlerAccessor, () => + { + entry = Cache.ServiceLocator.GetInstance().Create(); + msa = Cache.ServiceLocator.GetInstance().Create(); + entry.MorphoSyntaxAnalysesOC.Add(msa); + }); + + var fields = DetailComposer.Compose(entry, Cache, showHiddenFields: true).Model.Fields; + Assert.That(HasRow(fields, "FromPartsOfSpeech", msa.Hvo), Is.False, + "no clitic on the entry, so the domain says the row does not apply"); + + // The positive control: add a proclitic allomorph, change nothing else. + NonUndoableUnitOfWorkHelper.Do(Cache.ActionHandlerAccessor, () => + { + var clitic = Cache.ServiceLocator.GetInstance().Create(); + entry.AlternateFormsOS.Add(clitic); + clitic.Form.set_String(Cache.DefaultVernWs, + TsStringUtils.MakeString("clitico", Cache.DefaultVernWs)); + clitic.MorphTypeRA = MorphTypes.GetObject(MoMorphTypeTags.kguidMorphProclitic); + }); + + fields = DetailComposer.Compose(entry, Cache, showHiddenFields: true).Model.Fields; + Assert.That(HasRow(fields, "FromPartsOfSpeech", msa.Hvo), Is.True, + "the same row on the same object composes once the entry has a clitic"); + } + /// /// MoStemMsa.InflectionClass is irrelevant until a part of speech is chosen -- there is /// no inflection class to pick without one. This one is NOT an allomorph field; it is the