diff --git a/DistFiles/Language Explorer/Configuration/CommonDataTreeInclude.xml b/DistFiles/Language Explorer/Configuration/CommonDataTreeInclude.xml index 73d26ec5a5..d7e19b9933 100644 --- a/DistFiles/Language Explorer/Configuration/CommonDataTreeInclude.xml +++ b/DistFiles/Language Explorer/Configuration/CommonDataTreeInclude.xml @@ -2,7 +2,6 @@ - @@ -11,7 +10,6 @@ - @@ -163,15 +161,9 @@ - - - - - - diff --git a/DistFiles/Language Explorer/Configuration/ContextHelp.xml b/DistFiles/Language Explorer/Configuration/ContextHelp.xml index aa45f1fdcd..4633cef854 100644 --- a/DistFiles/Language Explorer/Configuration/ContextHelp.xml +++ b/DistFiles/Language Explorer/Configuration/ContextHelp.xml @@ -37,7 +37,6 @@ Save Starts RAMP (if it is installed) and prepares an archive package for uploading. Refresh the screen. - Determine page layout options for printing. Print Import an existing lexicon. Export this FieldWorks project to a file. @@ -45,7 +44,6 @@ Restore a FieldWorks project. Delete FieldWorks project. Create a desktop shortcut to this project. - Edit the special properties of this FieldWorks project (such as name and writing systems). Send/Receive this Project (lexicon and texts) @@ -91,7 +89,6 @@ Display the dictionary entry for this lexeme above the Lexicon Edit pane. Display all possible fields. - Toggle between the baseline and interlinear text view. Turn off all filters. View the invisible, zero-width spaces in this text. - @@ -39,15 +37,6 @@ - - - - - - - @@ -57,19 +46,6 @@ - @@ -151,7 +127,6 @@ =========================================================== --> - @@ -184,18 +159,6 @@ - - - - - - - - - - @@ -207,13 +170,6 @@ - - - - diff --git a/DistFiles/Language Explorer/Configuration/Grammar/Edit/toolConfiguration.xml b/DistFiles/Language Explorer/Configuration/Grammar/Edit/toolConfiguration.xml index 3e80dac5a3..a5280dcdbd 100644 --- a/DistFiles/Language Explorer/Configuration/Grammar/Edit/toolConfiguration.xml +++ b/DistFiles/Language Explorer/Configuration/Grammar/Edit/toolConfiguration.xml @@ -152,9 +152,6 @@ - - - @@ -181,8 +178,6 @@ - - diff --git a/DistFiles/Language Explorer/Configuration/Grammar/InflAffixTemplateInclude.xml b/DistFiles/Language Explorer/Configuration/Grammar/InflAffixTemplateInclude.xml index 98b7e25cff..7af371d22a 100644 --- a/DistFiles/Language Explorer/Configuration/Grammar/InflAffixTemplateInclude.xml +++ b/DistFiles/Language Explorer/Configuration/Grammar/InflAffixTemplateInclude.xml @@ -1,6 +1,5 @@ - - - - - diff --git a/DistFiles/Language Explorer/Configuration/Grammar/areaConfiguration.xml b/DistFiles/Language Explorer/Configuration/Grammar/areaConfiguration.xml index 36a9dc33aa..219ac94e8c 100644 --- a/DistFiles/Language Explorer/Configuration/Grammar/areaConfiguration.xml +++ b/DistFiles/Language Explorer/Configuration/Grammar/areaConfiguration.xml @@ -31,11 +31,6 @@ - @@ -280,10 +275,6 @@ - @@ -365,10 +356,6 @@ - diff --git a/DistFiles/Language Explorer/Configuration/Lexicon/DataTreeInclude.xml b/DistFiles/Language Explorer/Configuration/Lexicon/DataTreeInclude.xml index a48e47e20c..76ea700dd7 100644 --- a/DistFiles/Language Explorer/Configuration/Lexicon/DataTreeInclude.xml +++ b/DistFiles/Language Explorer/Configuration/Lexicon/DataTreeInclude.xml @@ -1,13 +1,11 @@ - - @@ -15,12 +13,6 @@ Lexeme form --> - - - - - - @@ -42,12 +34,6 @@ - - - - - - @@ -98,35 +84,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -135,9 +92,6 @@ - - - @@ -147,12 +101,6 @@ - - - - - - @@ -222,9 +170,6 @@ - - - @@ -246,9 +191,6 @@ - - - - - - @@ -329,7 +265,6 @@ =========================================================== --> - @@ -347,18 +282,10 @@ - - - - - - - - @@ -415,30 +342,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -459,9 +362,6 @@ - @@ -479,20 +379,6 @@ - - - - - - - - - - - - - - @@ -528,16 +414,6 @@ - - - - - - - - - - @@ -552,10 +428,6 @@ - - - - diff --git a/DistFiles/Language Explorer/Configuration/Lexicon/areaConfiguration.xml b/DistFiles/Language Explorer/Configuration/Lexicon/areaConfiguration.xml index cc0dd533b2..af7ba7173a 100644 --- a/DistFiles/Language Explorer/Configuration/Lexicon/areaConfiguration.xml +++ b/DistFiles/Language Explorer/Configuration/Lexicon/areaConfiguration.xml @@ -272,7 +272,6 @@ - diff --git a/DistFiles/Language Explorer/Configuration/Lists/DataTreeInclude.xml b/DistFiles/Language Explorer/Configuration/Lists/DataTreeInclude.xml index 4b83f387ed..5c7ec38ab9 100644 --- a/DistFiles/Language Explorer/Configuration/Lists/DataTreeInclude.xml +++ b/DistFiles/Language Explorer/Configuration/Lists/DataTreeInclude.xml @@ -1,6 +1,5 @@ - - - - @@ -87,15 +74,6 @@ - - - - - - - - - @@ -108,9 +86,6 @@ - - - diff --git a/DistFiles/Language Explorer/Configuration/Main.xml b/DistFiles/Language Explorer/Configuration/Main.xml index 563dbb7ade..cea3f62af5 100644 --- a/DistFiles/Language Explorer/Configuration/Main.xml +++ b/DistFiles/Language Explorer/Configuration/Main.xml @@ -50,7 +50,6 @@ - @@ -66,7 +65,6 @@ - @@ -107,7 +105,6 @@ - @@ -127,11 +124,6 @@ - - @@ -146,7 +138,6 @@ - @@ -172,7 +163,6 @@ - @@ -415,7 +405,6 @@ - @@ -434,12 +423,7 @@ - - - @@ -616,8 +600,6 @@ - diff --git a/DistFiles/Language Explorer/Configuration/Parts/CmPossibility.fwlayout b/DistFiles/Language Explorer/Configuration/Parts/CmPossibility.fwlayout index f197991118..8b0555c3ce 100644 --- a/DistFiles/Language Explorer/Configuration/Parts/CmPossibility.fwlayout +++ b/DistFiles/Language Explorer/Configuration/Parts/CmPossibility.fwlayout @@ -295,8 +295,6 @@ - - diff --git a/DistFiles/Language Explorer/Configuration/Parts/LexSense.fwlayout b/DistFiles/Language Explorer/Configuration/Parts/LexSense.fwlayout index a23f24f22d..4439f6e69b 100644 --- a/DistFiles/Language Explorer/Configuration/Parts/LexSense.fwlayout +++ b/DistFiles/Language Explorer/Configuration/Parts/LexSense.fwlayout @@ -108,10 +108,6 @@ - - - - diff --git a/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout b/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout index 8ff98db609..355f1cce82 100644 --- a/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout +++ b/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout @@ -231,38 +231,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -337,32 +305,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -490,11 +432,6 @@ - - - - - diff --git a/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml b/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml index 720f4b1681..9eccaf26ed 100644 --- a/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml +++ b/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml @@ -1876,9 +1876,6 @@ - - - @@ -1903,59 +1900,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/DistFiles/Language Explorer/Configuration/Words/areaConfiguration.xml b/DistFiles/Language Explorer/Configuration/Words/areaConfiguration.xml index 2e74bf6e61..0573ab9d39 100644 --- a/DistFiles/Language Explorer/Configuration/Words/areaConfiguration.xml +++ b/DistFiles/Language Explorer/Configuration/Words/areaConfiguration.xml @@ -51,7 +51,6 @@ - @@ -63,26 +62,15 @@ - - - - - - - - - - - @@ -97,13 +85,7 @@ - - - - @@ -115,7 +97,6 @@ - @@ -322,11 +303,9 @@ - - @@ -384,15 +363,6 @@ - - - - - - - - - @@ -433,29 +403,12 @@ - - - - @@ -490,10 +443,6 @@ - @@ -503,10 +452,6 @@ - diff --git a/Src/Common/FwAvalonia/FwAvaloniaTests/LayoutImportCoverageTests.cs b/Src/Common/FwAvalonia/FwAvaloniaTests/LayoutImportCoverageTests.cs index 22b2dd94fa..d618409d69 100644 --- a/Src/Common/FwAvalonia/FwAvaloniaTests/LayoutImportCoverageTests.cs +++ b/Src/Common/FwAvalonia/FwAvaloniaTests/LayoutImportCoverageTests.cs @@ -616,53 +616,40 @@ public void ShippedLayouts_EveryDiagnosticCode_IsInTheKnownTaxonomy() } /// - /// With the metadata-driven base-class walk the importer - /// resolves every shipped part ref that legacy DataTree resolves. What remains is EXACTLY the - /// set of layout refs with no {class-chain}-Detail-{ref} part anywhere in the shipped - /// inventories -- refs legacy DataTree also silently omits ("Just omit the missing part", - /// DataTree.cs:2455-2457; the detail view has no PartGenerator). Asserting the exact set keeps - /// both regressions (new unresolved refs) and silent improvements (parts added) visible. + /// The part refs with no part in Language Explorer/Configuration/Parts, pinned + /// exactly so new unresolved refs and added parts both show. At runtime DataTree + /// also loads DistFiles/Parts (StandardParts.xml and the build's GeneratedParts.xml), + /// which resolves every one of them. /// [Test] - public void ShippedLayouts_UnresolvedParts_AreExactlyTheLegacyUnresolvableSet() + public void ShippedLayouts_UnresolvedParts_AreExactlyTheRefsWithNoConfigurationPart() { var repoRoot = FindRepoRoot(); var (layouts, parts) = LoadShippedFiles(repoRoot); var report = LayoutImportCoverage.Run(layouts, parts, LoadBaseClassMap(repoRoot)); - // Every entry below was verified to have no matching part id (case-insensitive) on the - // class or any base class in the shipped *Parts.xml files; legacy omits them too. Most are - // summary/section header parts that were never shipped, plus the DateCreated/DateModified - // refs Notebook hides (visibility='never') whose parts never existed in the detail view. - var legacyUnresolvable = new SortedDictionary(StringComparer.Ordinal) + // Summary, section and message refs resolve to StandardParts.xml's CmObject parts; + // field refs resolve to the build's GeneratedParts.xml. + var noConfigurationPart = new SortedDictionary(StringComparer.Ordinal) { { "CmAnthroItem-Summary", 1 }, - { "CmPerson-Role", 1 }, { "CmPossibility-Summary", 1 }, { "CmSemanticDomain-Summary", 1 }, - { "FsClosedValue-Summary", 1 }, { "FsComplexFeature-Message", 1 }, - { "FsComplexValue-Summary", 1 }, - { "FsFeatStruc-Blank", 1 }, { "FsFeatStrucType-Message", 1 }, - { "FsFeatureSpecification-Summary", 1 }, { "LexEntry-ImportResidue", 1 }, { "LexEntryInflType-Summary", 1 }, { "LexEntryType-Summary", 2 }, { "LexEtymology-NormalSummary", 1 }, { "LexExtendedNote-NormalSummary", 1 }, { "LexPronunciation-MediaFiles", 1 }, - { "LexReference-ShowSingleReference", 1 }, { "LexSense-HeavySummary", 1 }, { "LexSense-ImportResidue", 1 }, - // LexSense `Pictures` has no LexSense-Detail-Pictures part, so legacy DataTree (and this - // importer) omit sense pictures. { "LexSense-Pictures", 1 }, { "MoAlloAdhocProhib-Message", 1 }, { "MoEndoCompound-HeadLast", 2 }, { "MoExoCompound-ToMsa", 1 }, { "MoInflAffixSlot-Optional", 1 }, - { "MoInflClass-SubclassesAllA", 1 }, { "MoMorphAdhocProhib-Message", 1 }, { "PartOfSpeech-Section", 2 }, { "PhPhoneme-Codes", 1 }, @@ -675,10 +662,10 @@ public void ShippedLayouts_UnresolvedParts_AreExactlyTheLegacyUnresolvableSet() { "WfiWordform-HeavySummary", 1 } }; - Assert.That(report.UnresolvedPartRefs, Is.EquivalentTo(legacyUnresolvable), + Assert.That(report.UnresolvedPartRefs, Is.EquivalentTo(noConfigurationPart), "the unresolved-part set changed; if a part was added/renamed update this set, if a " - + "resolution rule regressed fix the resolver (B10 baseline: 63 occurrences, was 259)"); - Assert.That(report.UnresolvedPartRefs.Values.Sum(), Is.EqualTo(63), + + "resolution rule regressed fix the resolver (now 56 occurrences; B10 baseline 63, was 259)"); + Assert.That(report.UnresolvedPartRefs.Values.Sum(), Is.EqualTo(56), "B10 unresolved-part occurrence ceiling"); } diff --git a/Src/FdoUi/DetailRules/DetailObjectInsertion.cs b/Src/FdoUi/DetailRules/DetailObjectInsertion.cs index 15e111e134..99471d4597 100644 --- a/Src/FdoUi/DetailRules/DetailObjectInsertion.cs +++ b/Src/FdoUi/DetailRules/DetailObjectInsertion.cs @@ -15,7 +15,7 @@ namespace SIL.FieldWorks.Common.DetailRules /// /// The Insert command of a detail row (message DataTreeInsert): whether a field can take /// a new object now, which object and field the row's command inserts into, and where; - /// which allomorph inserts an entry offers, and which entry a variant insert extends. + /// whether an entry offers Insert Affix Process, and which entry a variant insert extends. /// Creation stays with CmObjectUi.CreateNewUiObject and the variant dialog. /// public static class DetailObjectInsertion @@ -156,9 +156,8 @@ public static int ConcreteClass(ICmObject owner, int classId) } /// - /// Whether an entry offers an allomorph Insert command, chosen by the end of its id: - /// Insert Affix Process only on an affix entry; Insert Stem or Affix Allomorph while the - /// entry has no allomorph or its first is of that kind. It offers any other command. + /// Whether an entry offers an Insert command: Insert Affix Process, chosen by the end + /// of its id, only on an affix entry; any other command on any valid entry. /// public static bool IsOfferedOnEntry(ILexEntry entry, string commandId) { @@ -166,12 +165,6 @@ public static bool IsOfferedOnEntry(ILexEntry entry, string commandId) return false; if (commandId.EndsWith("AffixProcess", StringComparison.Ordinal)) return entry.PrimaryMorphType != null && entry.PrimaryMorphType.IsAffixType; - if (entry.AlternateFormsOS.Count == 0) - return true; - if (commandId.EndsWith("AffixAllomorph", StringComparison.Ordinal)) - return entry.AlternateFormsOS[0] is IMoAffixAllomorph; - if (commandId.EndsWith("StemAllomorph", StringComparison.Ordinal)) - return entry.AlternateFormsOS[0] is IMoStemAllomorph; return true; } diff --git a/Src/FdoUi/FdoUiTests/DetailRules/DetailObjectInsertionTests.cs b/Src/FdoUi/FdoUiTests/DetailRules/DetailObjectInsertionTests.cs index 13dd9fb03b..0e7fbc8fb7 100644 --- a/Src/FdoUi/FdoUiTests/DetailRules/DetailObjectInsertionTests.cs +++ b/Src/FdoUi/FdoUiTests/DetailRules/DetailObjectInsertionTests.cs @@ -207,21 +207,11 @@ public void IsOfferedOnEntry_AnAffixProcess_OnlyOnAnAffixEntry() } [Test] - public void IsOfferedOnEntry_AStemOrAffixAllomorph_FollowsTheFirstAllomorph() + public void IsOfferedOnEntry_AnyOtherInsert_OnAnyEntry() { - const string stem = "CmdDataTree-Insert-StemAllomorph"; - const string affix = "CmdDataTree-Insert-AffixAllomorph"; - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, stem), Is.True, "no allomorph yet: either kind"); - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, affix), Is.True); - - NonUndoableUnitOfWorkHelper.Do(Cache.ActionHandlerAccessor, () => - _entry.AlternateFormsOS.Add(Cache.ServiceLocator.GetInstance().Create())); - - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, stem), Is.False, "the first allomorph is an affix"); - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, affix), Is.True); - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, "CmdDataTree-Insert-AlternateForm"), Is.True, - "any other insert"); - Assert.That(DetailObjectInsertion.IsOfferedOnEntry(null, "CmdDataTree-Insert-AlternateForm"), Is.False); + const string allomorph = "CmdDataTree-Insert-AlternateForm"; + Assert.That(DetailObjectInsertion.IsOfferedOnEntry(_entry, allomorph), Is.True); + Assert.That(DetailObjectInsertion.IsOfferedOnEntry(null, allomorph), Is.False); } [Test] diff --git a/Src/LexText/LexTextDll/LexTextApp.cs b/Src/LexText/LexTextDll/LexTextApp.cs index 5336aa52bc..8454ab1599 100644 --- a/Src/LexText/LexTextDll/LexTextApp.cs +++ b/Src/LexText/LexTextDll/LexTextApp.cs @@ -497,32 +497,6 @@ public bool OnRestoreDefaultLayouts(object commandObject) return true; } - /// - /// This implements the "Synchronize with LiftShare..." menu command. - /// - /// - /// - /// Until LiftShare is fully implemented, this is irrelevant. - public bool OnSynchronize(object sender) - { -#if WANTPORT // FWR-2845; this was not enabled in 6.0 and may be superseded by Randy's LiftBridge. - Form formActive = ActiveForm; - if (cache != null) - { - FwXWindow wndActive = formActive as FwXWindow; - LiftSynchronizeDlg dlg = new LiftSynchronizeDlg(Cache, wndActive.Mediator); - dlg.ShowDialog(formActive); - return true; - } - else - { - return false; - } -#else - return false; -#endif - } - /// /// On Refresh, we want to reload the XML configuration files. This greatly facilitates developing /// those files, even though it's not as useful for normal use. It might prove useful whenever we diff --git a/Src/LexText/Lexicon/LexEntryMenuHandler.cs b/Src/LexText/Lexicon/LexEntryMenuHandler.cs index 4742c6efe6..dcdd4ebb2c 100644 --- a/Src/LexText/Lexicon/LexEntryMenuHandler.cs +++ b/Src/LexText/Lexicon/LexEntryMenuHandler.cs @@ -2,6 +2,7 @@ // This software is licensed under the LGPL, version 2.1 or later // (http://www.gnu.org/licenses/lgpl-2.1.html) +using System; using System.Collections.Generic; using System.Diagnostics; using System.Windows.Forms; @@ -64,16 +65,12 @@ public override bool OnDisplayDataTreeInsert(object commandObject, ref UIItemDis return true; } XCore.Command command = (XCore.Command)commandObject; - var offered = DetailObjectInsertion.IsOfferedOnEntry(entry, command.Id); - if (command.Id.EndsWith("AffixProcess")) + if (command.Id.EndsWith("AffixProcess", StringComparison.Ordinal)) { + var offered = DetailObjectInsertion.IsOfferedOnEntry(entry, command.Id); display.Enabled = offered; display.Visible = offered; } - else if (!offered) - { - display.Visible = false; - } return true;//we handled this, no need to ask anyone else. } diff --git a/Src/LexText/Morphology/MEStrings.Designer.cs b/Src/LexText/Morphology/MEStrings.Designer.cs index 7d18fa9f16..348735476b 100644 --- a/Src/LexText/Morphology/MEStrings.Designer.cs +++ b/Src/LexText/Morphology/MEStrings.Designer.cs @@ -177,15 +177,6 @@ internal static string ksApply { } } - /// - /// Looks up a localized string similar to Merging wordforms needs serious definition, before it can be done. Sorry.. - /// - internal static string ksCannotMergeWordformsYet { - get { - return ResourceManager.GetString("ksCannotMergeWordformsYet", resourceCulture); - } - } - /// /// Looks up a localized string similar to Sorry. We are not able to support respelling the wordform in the required writing system at this time.. /// @@ -951,15 +942,6 @@ internal static string ksTargetFeature { } } - /// - /// Looks up a localized string similar to TODO: Basic wordform editing happens here.. - /// - internal static string ksTodo_WordformEditing { - get { - return ResourceManager.GetString("ksTodo_WordformEditing", resourceCulture); - } - } - /// /// Looks up a localized string similar to Undo Adding Affixes. /// diff --git a/Src/LexText/Morphology/MEStrings.resx b/Src/LexText/Morphology/MEStrings.resx index 98349248d6..e0cca24438 100644 --- a/Src/LexText/Morphology/MEStrings.resx +++ b/Src/LexText/Morphology/MEStrings.resx @@ -133,9 +133,6 @@ Find Wordform - - Merging wordforms needs serious definition, before it can be done. Sorry. - Analysis {0} {0} is a number ("Analysis 1" for first, etc) @@ -143,9 +140,6 @@ no analysis - - TODO: Basic wordform editing happens here. - &Go To diff --git a/Src/LexText/Morphology/MorphologyListener.cs b/Src/LexText/Morphology/MorphologyListener.cs index b6a55d7bdb..f6a50140c2 100644 --- a/Src/LexText/Morphology/MorphologyListener.cs +++ b/Src/LexText/Morphology/MorphologyListener.cs @@ -215,30 +215,6 @@ public int Priority #region XCore Message handlers - /// - /// - /// - /// - /// - /// - public virtual bool OnDisplayMergeWordform(object commandObject, - ref UIItemDisplayProperties display) - { - CheckDisposed(); - - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - public bool OnMergeWordform(object argument) - { - CheckDisposed(); - - // Do something meaningful, - // whenever the definition of merging wordforms gets developed. - MessageBox.Show(MEStrings.ksCannotMergeWordformsYet); - return true; - } - /// /// Enable the spelling tool always. Correct the property value if need be to match whether /// we are actually showing vernacular spelling. @@ -801,14 +777,6 @@ public virtual bool OnJumpToTool(object commandObject) #region Approval Status Message handlers - public virtual bool OnDisplayAnalysisApprove(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - display.Checked = Analysis != null && Analysis.IsValidObject && Analysis.ApprovalStatusIcon == 1; - return true; //we've handled this - } - /// /// Insert Word Gloss and Approve Analysis /// @@ -819,22 +787,18 @@ public bool OnInsertWordGlossAndApprove(object cmd) // Insert word gloss. OnDataTreeInsert(cmd); } - OnAnalysisApprove(cmd); + ApproveAnalysis(); return true; } /// - /// + /// Marks the current analysis approved. /// - /// The xCore Command object. - /// true - public bool OnAnalysisApprove(object argument) + private void ApproveAnalysis() { IWfiAnalysis anal = Analysis; Debug.Assert(anal != null, "Could not find analysis object."); SetNewStatus(anal, 1); - - return true; } public virtual bool OnDisplayAnalysisUnknown(object commandObject, @@ -883,71 +847,6 @@ public bool OnAnalysisDisapprove(object argument) #endregion Approval Status Message handlers -#if NOTYET - #region SpellingStatus Message handlers - - public virtual bool OnDisplaySpellingStatusUnknown(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - - /// - /// - /// - /// The xCore Command object. - /// true - public bool OnSpellingStatusUnknown(object argument) - { - MessageBox.Show("TODO: Set spelling status to 'Unknown' goes here, when the integer values that get stored in the database get defined."); - - return true; - } - - public virtual bool OnDisplaySpellingStatusGood(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - - /// - /// - /// - /// The xCore Command object. - /// true - public bool OnSpellingStatusGood(object argument) - { - MessageBox.Show("TODO: Set spelling status to 'Good' goes here, when the integer values that get stored in the database get defined."); - - return true; - } - - public virtual bool OnDisplaySpellingStatusDisapprove(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - - /// - /// - /// - /// The xCore Command object. - /// true - public bool OnSpellingStatusDisapprove(object argument) - { - MessageBox.Show("TODO: Set spelling status to 'Disapproved' goes here, when the integer values that get stored in the database get defined."); - - return true; - } - - #endregion SpellingStatus Message handlers -#endif - - #region Wordform edit Message handlers - protected override bool DeleteObject(Command command) { if (base.DeleteObject(command)) @@ -961,46 +860,6 @@ protected override bool DeleteObject(Command command) return false; } - public virtual bool OnDisplayWordformEditForm(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - - /// - /// - /// - /// The xCore Command object. - /// true - public bool OnWordformEditForm(object argument) - { - MessageBox.Show(MEStrings.ksTodo_WordformEditing); - - return true; - } - - public virtual bool OnDisplayWordformChangeCase(object commandObject, - ref UIItemDisplayProperties display) - { - display.Enabled = display.Visible = InFriendlyArea; - return true; //we've handled this - } - - /// - /// - /// - /// The xCore Command object. - /// true - public bool OnWordformChangeCase(object argument) - { - MessageBox.Show("TODO: Case changing editing happens here."); - - return true; - } - - #endregion Wordform edit Message handlers - #region New analysis message handler // diff --git a/Src/XCore/Ticker.cs b/Src/XCore/Ticker.cs index b6f98b691f..1558d1e327 100644 --- a/Src/XCore/Ticker.cs +++ b/Src/XCore/Ticker.cs @@ -226,17 +226,6 @@ public bool OnListPropertiesTable(object argument) WriteLine(m_propertyTable.GetPropertiesDumpString()); return true;//we handled this, no need to ask anyone else. } - /// - /// Receives the message "ListPropertiesTable" - /// - public bool OnListColleagues(object argument) - { - CheckDisposed(); - - WriteLine ("--------Colleagues"); - WriteLine(m_mediator.GetColleaguesDumpString()); - return true;//we handled this, no need to ask anyone else. - } /// /// enable this command because we are listening for it. diff --git a/Src/xWorks/Avalonia/Hosting/RecordEditView.LexiconMenus.cs b/Src/xWorks/Avalonia/Hosting/RecordEditView.LexiconMenus.cs index 620241867e..74d8561b40 100644 --- a/Src/xWorks/Avalonia/Hosting/RecordEditView.LexiconMenus.cs +++ b/Src/xWorks/Avalonia/Hosting/RecordEditView.LexiconMenus.cs @@ -116,7 +116,7 @@ internal bool InsertLeafInScope(DetailMenuLeaf leaf) /// /// The Insert item for the row: absent with no row or no object, and absent when the - /// entry of the row or the shown entry does not offer an allomorph insert; enabled + /// entry of the row or the shown entry does not offer the insert; enabled /// when the command resolves a target from the row's object (a ghost row's included), /// disabled otherwise. With displayNumber the label carries the position the /// shown record's or the row's object's field would give. diff --git a/Src/xWorks/FwXWindow.cs b/Src/xWorks/FwXWindow.cs index 5b12a37a58..e0d7fad2c2 100644 --- a/Src/xWorks/FwXWindow.cs +++ b/Src/xWorks/FwXWindow.cs @@ -993,18 +993,6 @@ public bool OnNewWindow(object command) return true; } - /// ------------------------------------------------------------------------------------ - /// - /// Start logging events. - /// - /// - /// - /// ------------------------------------------------------------------------------------ - protected bool OnStartLogging(object args) - { - return true; - } - /// ------------------------------------------------------------------------------------ /// /// diff --git a/Src/xWorks/xWorksTests/Avalonia/Hosting/DetailObjectCommandExecutionTests.cs b/Src/xWorks/xWorksTests/Avalonia/Hosting/DetailObjectCommandExecutionTests.cs index c5410582c1..24256f749e 100644 --- a/Src/xWorks/xWorksTests/Avalonia/Hosting/DetailObjectCommandExecutionTests.cs +++ b/Src/xWorks/xWorksTests/Avalonia/Hosting/DetailObjectCommandExecutionTests.cs @@ -1356,8 +1356,9 @@ public void UnownedMenu_StillAsksTheMediator_ForSubmenuLeaves() Assert.That(asked, Is.True, "the mediator path decides submenu visibility by asking colleagues"); } - // The XML walk must see what ChoiceGroup.Populate sees. The mediator path drops a - // submenu no colleague shows, so nested leaves compare as a subset, top-level exactly. + // The XML walk sees what ChoiceGroup.Populate sees: top-level leaves exactly, nested + // ones as a subset (the mediator drops unshown submenus). No item may name a missing + // command. [Test] public void ResolveMenu_ReadsWhatChoiceGroupPopulates_ForEveryContextMenuId() { @@ -1386,8 +1387,8 @@ public void ResolveMenu_ReadsWhatChoiceGroupPopulates_ForEveryContextMenuId() undefinedCommands.AddRange(resolved.Unanswerable.Where(u => u.StartsWith("command", StringComparison.Ordinal)) .Select(u => id + ": " + u)); } - TestContext.WriteLine("Context-menu items naming an undefined command (ChoiceGroup fails on them at display time):" - + Environment.NewLine + string.Join(Environment.NewLine, undefinedCommands)); + Assert.That(undefinedCommands, Is.Empty, + "context-menu items naming an undefined command (ChoiceGroup fails on them at display time)"); } // Walks the ChoiceGroup side exactly as the configuration-walk side describes a leaf; diff --git a/Src/xWorks/xWorksTests/Avalonia/Hosting/LexiconMenuAuthorityTests.cs b/Src/xWorks/xWorksTests/Avalonia/Hosting/LexiconMenuAuthorityTests.cs index 28278681c0..430d64dee9 100644 --- a/Src/xWorks/xWorksTests/Avalonia/Hosting/LexiconMenuAuthorityTests.cs +++ b/Src/xWorks/xWorksTests/Avalonia/Hosting/LexiconMenuAuthorityTests.cs @@ -50,10 +50,8 @@ public class LexiconMenuAuthorityTests : XWorksAppTestBase // Allomorphs and Variants hotlinks. "mnuDataTree-AlternateForms", "mnuDataTree-VariantForms", "mnuDataTree-Examples", "mnuDataTree-AlternateForms-Hotlinks", "mnuDataTree-VariantForms-Hotlinks", - // Lexicon ids no part reaches (-CmMedia's pronunciation part does not exist). - "mnuDataTree-CmMedia", "mnuDataTree-Variant", "mnuDataTree-DeleteEtymology", - "mnuDataTree-DeletePronunciation", "mnuDataTree-Translations", "mnuDataTree-Senses", "mnuDataTree-MSAs", - "mnuDataTree-Allomorphs", "mnuDataTree-Allomorphs-Hotlinks", "mnuDataTree-Variants", + // Lexicon: an id no part reaches (its pronunciation part does not exist). + "mnuDataTree-CmMedia", // Grammar: posEdit rows (two item rows, five section rows: Affix Templates, Affix // Slots, Inflection Classes, Subclasses, Stem Allomorph Labels), then other tools. "mnuDataTree-POS-InflectionClass", "mnuDataTree-POS-StemName", @@ -63,12 +61,11 @@ public class LexiconMenuAuthorityTests : XWorksAppTestBase "mnuDataTree-MoStemName-Regions", "mnuDataTree-Phoneme-Code", "mnuDataTree-Phoneme-Codes", "mnuDataTree-Delete-Adhoc-Allomorph", "mnuDataTree-Delete-Adhoc-Group", "mnuDataTree-Delete-Adhoc-Morpheme", "mnuDataTree-Adhoc-Group-Members", - "mnuDataTree-CompoundRule-LinkerAffixAllomorph", // Texts: the Info tab's jumps to the interlinear text and its notebook record; no // Avalonia detail view. "mnuDataTree-Text", "mnuTextInfo-Notebook", // Lists and Reversal: no Avalonia detail view. - "mnuDataTree-DeleteCustomItem", "mnuDataTree-DeletePossibility", "mnuDataTree-DeleteQuestion", + "mnuDataTree-DeletePossibility", "mnuDataTree-DeleteQuestion", "mnuDataTree-InsertQuestion", "mnuDataTree-InsertReversalSubentry", "mnuDataTree-InsertReversalSubentry-Hotlinks" }; @@ -438,7 +435,7 @@ public void InsertLeaf_IsOfferedOnTheGhostRow_DisabledWithoutATarget_AndAbsentWi } // Only the inserts that need the whole tree stay with the adapter, so their ids do - // too: SubPossibilities, and an insert into a plain reference field. + // too: SubPossibilities. [Test] public void InsertLeaves_OutsideTheScope_LeaveTheirIdsWithTheAdapter() { @@ -452,31 +449,25 @@ public void InsertLeaves_OutsideTheScope_LeaveTheirIdsWithTheAdapter() Is.True, "a virtual back reference: the dialog adds the variant"); Assert.That(m_view.InsertLeafInScope(Leaf("mnuDataTree-POS-SubPossibilities", "CmdDataTree-Insert-POS-SubPossibilities")), Is.False, "SubPossibilities needs the whole tree"); - Assert.That(m_view.InsertLeafInScope(Leaf("mnuDataTree-SubEntryLink", "CmdDataTree-Insert-SubEntryLink")), - Is.False, "a reference field with no class to create"); Assert.That(authority.Owns("mnuDataTree-POS-SubPossibilities"), Is.False); Assert.That(() => authority.Build("mnuDataTree-POS-SubPossibilities", Leaf("mnuDataTree-POS-SubPossibilities", "CmdDataTree-Insert-POS-SubPossibilities")), Throws.InvalidOperationException, "a leaf outside the scope is not answered"); } - // The allomorph inserts follow the entry: an affix process only on an affix entry, a - // stem or affix allomorph only while the first allomorph is of that kind. + // The allomorph inserts follow the entry: an affix process only on an affix entry, an + // allomorph on any entry. [Test] - public void AllomorphInserts_AreOfferedByTheEntrysMorphTypeAndFirstAllomorph() + public void AllomorphInserts_AreOfferedByTheEntrysMorphType() { var section = Rows().Single(f => f.MenuId == "mnuDataTree-AlternateForms"); var affixProcess = Leaf("mnuDataTree-AlternateForms", "CmdDataTree-Insert-AffixProcess"); var allomorph = Leaf("mnuDataTree-AlternateForms", "CmdDataTree-Insert-AlternateForm"); - var stem = Leaf("mnuDataTree-Allomorphs", "CmdDataTree-Insert-StemAllomorph"); - var affix = Leaf("mnuDataTree-Allomorphs", "CmdDataTree-Insert-AffixAllomorph"); Assert.That(m_view.InsertItem(affixProcess, section), Is.Null, "a stem entry has no affix process"); + Assert.That(m_view.InsertItem(affixProcess, LexemeFormRow()), Is.Null, "a row inside the entry asks the entry"); Assert.That(m_view.InsertItem(allomorph, section)?.IsEnabled, Is.True); Assert.That(m_view.InsertItem(allomorph, section).Label, Is.EqualTo("Insert Allomorph")); - Assert.That(m_view.InsertItem(stem, section)?.IsEnabled, Is.True, "the first allomorph is a stem"); - Assert.That(m_view.InsertItem(affix, section), Is.Null); - Assert.That(m_view.InsertItem(affix, LexemeFormRow()), Is.Null, "a row inside the entry asks the entry"); NonUndoableUnitOfWorkHelper.Do(Cache.ActionHandlerAccessor, () => m_entry.LexemeFormOA.MorphTypeRA = GetMorphTypeOrCreateOne("suffix")); diff --git a/Src/xWorks/xWorksTests/WindowConfigurationIntegrityTests.cs b/Src/xWorks/xWorksTests/WindowConfigurationIntegrityTests.cs new file mode 100644 index 0000000000..c2fa043dec --- /dev/null +++ b/Src/xWorks/xWorksTests/WindowConfigurationIntegrityTests.cs @@ -0,0 +1,107 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using NUnit.Framework; +using SIL.FieldWorks.Common.FwUtils; + +namespace SIL.FieldWorks.XWorks +{ + /// + /// Every command, menu and hotlinks reference in the shipped configuration and layouts + /// names something the configuration defines, so no menu throws when it is built. + /// + [TestFixture] + [Apartment(System.Threading.ApartmentState.STA)] + public class WindowConfigurationIntegrityTests : XWorksAppTestBase + { + private XmlNode m_configuration; + + protected override void Init() + { + m_application = new MockFwXApp(new MockFwManager { Cache = Cache }, null, null); + } + + [SetUp] + public void LoadConfiguration() + { + m_window = new MockFwXWindow(m_application, m_configFilePath); + ((MockFwXWindow)m_window).Init(Cache); + m_window.PropTable.RemoveLocalAndGlobalSettings(); + m_window.LoadUI(m_configFilePath); + m_configuration = m_window.PropTable.GetValue("WindowConfiguration"); + Assert.That(m_configuration, Is.Not.Null); + } + + [TearDown] + public void DisposeWindow() + { + m_configuration = null; + if (m_window != null && !m_window.IsDisposed) + { + m_window.PropTable.RemoveLocalAndGlobalSettings(); + m_window.Dispose(); + } + m_window = null; + } + + [Test] + public void EveryCommandReference_NamesADefinedCommand() + { + var defined = Ids(m_configuration.SelectNodes("//commands/command[@id]")); + var missing = m_configuration.SelectNodes("//*[@command]").Cast() + .Select(n => n.Attributes["command"].Value).Where(id => !defined.Contains(id)) + .Distinct().ToList(); + + Assert.That(missing, Is.Empty, "menu, toolbar or context-menu items naming an undefined command"); + } + + [Test] + public void EveryLayoutMenuReference_NamesADefinedMenu() + { + var defined = Ids(m_configuration.SelectNodes("//menu[@id]")); + var missing = new List(); + var files = ShippedLayoutFiles().ToList(); + Assert.That(files, Is.Not.Empty, "the shipped layout and part files"); + foreach (var path in files) + { + var doc = new XmlDocument(); + doc.Load(path); + foreach (XmlNode node in doc.SelectNodes("//*[@menu or @hotlinks]")) + { + foreach (var attribute in new[] { "menu", "hotlinks" }) + { + var id = node.Attributes[attribute]?.Value; + if (!string.IsNullOrEmpty(id) && !defined.Contains(id)) + missing.Add(Path.GetFileName(path) + ": " + attribute + "=" + id); + } + } + } + + Assert.That(missing, Is.Empty, "layout parts naming a context menu the window configuration lacks"); + } + + // The layout and part files DataTree loads: Language Explorer's and the shared ones. + private static IEnumerable ShippedLayoutFiles() + { + var folders = new[] + { + Path.Combine(FwDirectoryFinder.FlexFolder, "Configuration", "Parts"), + Path.Combine(FwDirectoryFinder.CodeDirectory, "Parts") + }; + return folders.Where(Directory.Exists).SelectMany(folder => + Directory.GetFiles(folder, "*.fwlayout").Concat(Directory.GetFiles(folder, "*Parts.xml"))); + } + + private static HashSet Ids(XmlNodeList nodes) + { + return new HashSet(nodes.Cast().Select(n => n.Attributes["id"].Value), + StringComparer.Ordinal); + } + } +}