diff --git a/Src/LexText/Interlinear/InterlinVc.cs b/Src/LexText/Interlinear/InterlinVc.cs index 44b5143f41..0cfb747d29 100644 --- a/Src/LexText/Interlinear/InterlinVc.cs +++ b/Src/LexText/Interlinear/InterlinVc.cs @@ -2311,6 +2311,101 @@ private void DisplayMorphForm(IVwEnv vwenv, int hvo, int ws) vwenv.CloseParagraph(); } + internal static ILexSense GuessWordSense(IWfiAnalysis wa) + { + if (wa.MeaningsOC.Count != 0) + { + return null; + } + // This is modeled after SandboxBase.SyncMonomorphemicGlossAndPos. + ILexSense rootSense = null; + foreach (IWfiMorphBundle morphBundle in wa.MorphBundlesOS) + { + // Get the sense for morphBundle. + ILexSense sense = morphBundle.SenseRA; + if (sense == null && morphBundle.MorphRA != null) + { + ILexEntry lexEntry = morphBundle.MorphRA.Owner as ILexEntry; + if (lexEntry != null && lexEntry.SensesOS.Count > 0) + { + sense = lexEntry.SensesOS[0]; + } + } + if (sense?.Gloss?.BestAnalysisAlternative == null) + continue; + // Consider the sense's gloss. + IMoMorphSynAnalysis msa = sense.MorphoSyntaxAnalysisRA; + bool fStem = msa is IMoStemMsa; + // If we have only one morpheme, treat it as the stem from which we will copy the gloss. + // otherwise, use the first stem we find, if any. + if ((fStem && rootSense == null) || wa.MorphBundlesOS.Count == 1) + rootSense = sense; + } + return rootSense; + } + + internal static ITsString GuessWordPOSName(IAnalysis analysis) + { + IPartOfSpeech lexPOS = GuessWordPOS(analysis); + if (lexPOS == null) + return null; + if (lexPOS.Abbreviation.BestAnalysisAlternative.Length > 0) + return lexPOS.Abbreviation.BestAnalysisAlternative; + return lexPOS.Name.BestAnalysisAlternative; + } + + internal static IPartOfSpeech GuessWordPOS(IAnalysis analysis) + { + var wa = analysis.Analysis; + if (wa.CategoryRA != null) + { + return null; + } + // This is modeled after SandboxBase.SyncMonomorphemicGlossAndPos. + IPartOfSpeech stemPOS = null; + IPartOfSpeech derivedPOS = null; + foreach (IWfiMorphBundle morphBundle in wa.MorphBundlesOS) + { + // Get the sense for morphBundle. + ILexSense sense = morphBundle.SenseRA; + if (sense == null && morphBundle.MorphRA != null) + { + if (morphBundle.MorphRA.Owner is ILexEntry lexEntry && lexEntry.SensesOS.Count > 0) + { + sense = lexEntry.SensesOS[0]; + } + } + if (sense == null) + continue; + // Consider the sense's part of speech. + IMoMorphSynAnalysis msa = sense.MorphoSyntaxAnalysisRA; + bool fStem = msa is IMoStemMsa; + if (fStem) + { + IPartOfSpeech POS = (msa as IMoStemMsa).PartOfSpeechRA; + if (POS != stemPOS && stemPOS != null) + { + // found conflicting stems + return null; + } + else + stemPOS = POS; + } + else if (msa is IMoDerivAffMsa) + { + if (derivedPOS != null) + return null; // more than one DA + else + derivedPOS = (msa as IMoDerivAffMsa).ToPartOfSpeechRA; + } + } + if (stemPOS == null) + return null; + + IPartOfSpeech lexPOS = derivedPOS ?? stemPOS; + return lexPOS; + } + /// /// Implementation of displaying a word bundle as Method Object /// @@ -2495,7 +2590,7 @@ private void DisplayWordGloss(InterlinLineSpec spec, int choiceIndex) var wa = (IWfiAnalysis) m_defaultObj; if (wa.MeaningsOC.Count == 0) { - ITsString rootGlossName = GetRootGlossName(wa); + ITsString rootGlossName = GuessWordSense(wa)?.Gloss?.BestAnalysisAlternative; if (m_hvoDefault != m_hvoWordBundleAnalysis && rootGlossName != null) { // Display our best guess for the gloss. @@ -2538,37 +2633,9 @@ private void DisplayWordGloss(InterlinLineSpec spec, int choiceIndex) } } - private ITsString GetRootGlossName(IWfiAnalysis wa) - { - // This is modeled after SandboxBase.SyncMonomorphemicGlossAndPos. - ITsString rootGloss = null; - foreach (IWfiMorphBundle morphBundle in wa.MorphBundlesOS) - { - // Get the sense for morphBundle. - ILexSense sense = morphBundle.SenseRA; - if (sense == null && morphBundle.MorphRA != null) - { - ILexEntry lexEntry = morphBundle.MorphRA.Owner as ILexEntry; - if (lexEntry != null && lexEntry.SensesOS.Count > 0) - { - sense = lexEntry.SensesOS[0]; - } - } - if (sense?.Gloss?.BestAnalysisAlternative == null) - continue; - // Consider the sense's gloss. - IMoMorphSynAnalysis msa = sense.MorphoSyntaxAnalysisRA; - bool fStem = msa is IMoStemMsa; - // If we have only one morpheme, treat it as the stem from which we will copy the gloss. - // otherwise, use the first stem we find, if any. - if ((fStem && rootGloss == null) || wa.MorphBundlesOS.Count == 1) - rootGloss = sense.Gloss.BestAnalysisAlternative; - } - return rootGloss; - } - private void DisplayWordPOS(int choiceIndex) { + ITsString guessedPOSName = null; switch(m_defaultObj.ClassID) { case WfiWordformTags.kClassId: @@ -2581,19 +2648,14 @@ private void DisplayWordPOS(int choiceIndex) m_this.SetGuessing(m_vwenv, m_this.GetGuessColor(m_defaultObj)); // Let the exporter know that this is a guessed analysis. m_vwenv.set_StringProperty(ktagAnalysisStatus, "guess"); - var wa = (IWfiAnalysis) m_defaultObj; - int hvoPos = wa.CategoryRA != null ? wa.CategoryRA.Hvo : 0; - if (hvoPos == 0) - { - ITsString rootPOSName = GetRootPOSName(wa); - if (rootPOSName != null) - { - // Display our best guess for the gloss. - m_this.SetColor(m_vwenv, m_this.LabelRGBFor(choiceIndex)); - m_vwenv.AddString(rootPOSName); - break; - } - } + guessedPOSName = GuessWordPOSName((IAnalysis)m_defaultObj); + } + if (guessedPOSName != null) + { + // Display our best guess for the gloss. + m_this.SetColor(m_vwenv, m_this.LabelRGBFor(choiceIndex)); + m_vwenv.AddString(guessedPOSName); + break; } m_this.AddAnalysisPos(m_vwenv, m_hvoDefault, m_hvoWordBundleAnalysis, choiceIndex); break; @@ -2604,6 +2666,14 @@ private void DisplayWordPOS(int choiceIndex) m_this.SetGuessing(m_vwenv, m_this.GetGuessColor(m_defaultObj)); // Let the exporter know that this is a guessed analysis. m_vwenv.set_StringProperty(ktagAnalysisStatus, "guess"); + guessedPOSName = GuessWordPOSName((IAnalysis)m_defaultObj); + } + if (guessedPOSName != null) + { + // Display our best guess for the gloss. + m_this.SetColor(m_vwenv, m_this.LabelRGBFor(choiceIndex)); + m_vwenv.AddString(guessedPOSName); + break; } m_vwenv.AddObj(m_hvoWfiAnalysis, m_this, kfragAnalysisCategoryChoices + choiceIndex); break; @@ -2611,57 +2681,6 @@ private void DisplayWordPOS(int choiceIndex) throw new Exception("Invalid type found in Segment analysis"); } } - - private ITsString GetRootPOSName(IWfiAnalysis wa) - { - // This is modeled after SandboxBase.SyncMonomorphemicGlossAndPos. - IPartOfSpeech stemPOS = null; - IPartOfSpeech derivedPOS = null; - foreach (IWfiMorphBundle morphBundle in wa.MorphBundlesOS) - { - // Get the sense for morphBundle. - ILexSense sense = morphBundle.SenseRA; - if (sense == null && morphBundle.MorphRA != null) - { - if (morphBundle.MorphRA.Owner is ILexEntry lexEntry && lexEntry.SensesOS.Count > 0) - { - sense = lexEntry.SensesOS[0]; - } - } - if (sense == null) - continue; - // Consider the sense's part of speech. - IMoMorphSynAnalysis msa = sense.MorphoSyntaxAnalysisRA; - bool fStem = msa is IMoStemMsa; - if (fStem) - { - IPartOfSpeech POS = (msa as IMoStemMsa).PartOfSpeechRA; - if (POS != stemPOS && stemPOS != null) - { - // found conflicting stems - return null; - } - else - stemPOS = POS; - } - else if (msa is IMoDerivAffMsa) - { - if (derivedPOS != null) - return null; // more than one DA - else - derivedPOS = (msa as IMoDerivAffMsa).ToPartOfSpeechRA; - } - } - if (stemPOS == null) - return null; - - IPartOfSpeech lexPOS = derivedPOS ?? stemPOS; - if (lexPOS == null) - return null; - if (lexPOS.Abbreviation.BestAnalysisAlternative.Length > 0) - return lexPOS.Abbreviation.BestAnalysisAlternative; - return lexPOS.Name.BestAnalysisAlternative; - } } public override void DisplayVec(IVwEnv vwenv, int hvo, int tag, int frag) diff --git a/Src/LexText/Interlinear/SandboxBase.ComboHandlers.cs b/Src/LexText/Interlinear/SandboxBase.ComboHandlers.cs index 1cac7a0310..9b12c2d3c1 100644 --- a/Src/LexText/Interlinear/SandboxBase.ComboHandlers.cs +++ b/Src/LexText/Interlinear/SandboxBase.ComboHandlers.cs @@ -1213,7 +1213,7 @@ internal void UpdateMorphBreaks(string sMorphs) MorphemeBreaker mb = new MorphemeBreaker(m_caches, sMorphs, m_hvoSbWord, m_wsVern, m_sandbox); mb.Run(); - m_sandbox.CopyLexEntryInfoToMonomorphemicWordGlossAndPos(m_sandbox.UsingGuess); + m_sandbox.CopyLexEntryInfoToWordGlossAndPosIfEmpty(m_sandbox.UsingGuess); m_rootb.Reconstruct(); // Everything changed, more or less. // We've changed properties that the morph manager cares about, but we don't want it // to fire when we fix the selection. diff --git a/Src/LexText/Interlinear/SandboxBase.cs b/Src/LexText/Interlinear/SandboxBase.cs index 03791a6611..0ad89a906a 100644 --- a/Src/LexText/Interlinear/SandboxBase.cs +++ b/Src/LexText/Interlinear/SandboxBase.cs @@ -1410,9 +1410,17 @@ private bool LoadRealDataIntoSec1(int hvoSbWord, bool fLookForDefaults, bool fAd hasMf = true; } } - if (hasMf) + if (fGuessing != 0) + { // Wait until all of the morphemes have been loaded (cf. LT-22235). - CopyLexEntryInfoToMonomorphemicWordGlossAndPos(fGuessing != 0); + if (gloss != null) + { + GuessWordCatAndGloss(gloss); + } else if (analysis != null) + { + GuessWordCatAndGloss(analysis); + } + } if (bldrError.Length > 0) { var msg = bldrError.ToString().Trim(); @@ -1454,7 +1462,22 @@ private bool LoadRealDataIntoSec1(int hvoSbWord, bool fLookForDefaults, bool fAd return fGuessing != 0; } - internal void CopyLexEntryInfoToMonomorphemicWordGlossAndPos(bool usingGuess) + private void GuessWordCatAndGloss(IAnalysis analysis) + { + // Use the same guesses as InterlinVc to avoid confusing the user (LT-22616). + IPartOfSpeech wordCatGuess = InterlinVc.GuessWordPOS(analysis); + ILexSense wordSenseGuess = InterlinVc.GuessWordSense(analysis.Analysis); + if (wordCatGuess != null) + { + CopyLexPosToWordPos(true, wordCatGuess.Hvo); + } + if (wordSenseGuess != null) + { + CopySenseToWordGloss(true, wordSenseGuess.Hvo); + } + } + + internal void CopyLexEntryInfoToWordGlossAndPosIfEmpty(bool usingGuess) { bool fDirty = Caches.DataAccess.IsDirty(); bool fApproved = !usingGuess; @@ -1490,7 +1513,7 @@ internal void SyncMonomorphemicGlossAndPos(bool fCopyToWordGloss, bool fCopyToWo ISilDataAccess sda = m_caches.DataAccess; int cmorphs = sda.get_VecSize(RootWordHvo, ktagSbWordMorphs); - int hvoSbRootSense = 0; + int hvoRealRootSense = 0; int hvoStemPos = 0; // ID in real database of part-of-speech of stem. bool fGiveUpOnPOS = false; int hvoDerivedPos = 0; // real ID of POS output of derivational MSA. @@ -1511,8 +1534,8 @@ internal void SyncMonomorphemicGlossAndPos(bool fCopyToWordGloss, bool fCopyToWo // If we have only one morpheme, treat it as the stem from which we will copy the gloss. // otherwise, use the first stem we find, if any. - if ((fStem && hvoSbRootSense == 0) || cmorphs == 1) - hvoSbRootSense = hvoSbSense; + if ((fStem && hvoRealRootSense == 0) || cmorphs == 1) + hvoRealRootSense = m_caches.RealHvo(hvoSbSense); if (fStem) { @@ -1537,7 +1560,7 @@ internal void SyncMonomorphemicGlossAndPos(bool fCopyToWordGloss, bool fCopyToWo // If we found a sense to copy from, do it. Replace the word gloss even there already is // one, since users get confused/frustrated if we don't. (See LT-6141.) It's marked as a // guess after all! - CopySenseToWordGloss(fCopyToWordGloss, hvoSbRootSense); + CopySenseToWordGloss(fCopyToWordGloss, hvoRealRootSense); // If we didn't find a stem, we don't have enough information to find a POS. if (hvoStemPos == 0) @@ -1554,13 +1577,12 @@ internal void SyncMonomorphemicGlossAndPos(bool fCopyToWordGloss, bool fCopyToWo CopyLexPosToWordPos(fCopyToWordPos, hvoLexPos); } - protected virtual void CopySenseToWordGloss(bool fCopyWordGloss, int hvoSbRootSense) + protected virtual void CopySenseToWordGloss(bool fCopyWordGloss, int hvoRealSense) { - if (hvoSbRootSense != 0 && fCopyWordGloss) + if (hvoRealSense != 0 && fCopyWordGloss) { ISilDataAccess sda = m_caches.DataAccess; m_caches.DataAccess.SetInt(RootWordHvo, ktagSbWordGlossGuess, 1); - int hvoRealSense = m_caches.RealHvo(hvoSbRootSense); foreach (int wsId in m_choices.EnabledWritingSystemsForFlid(InterlinLineChoices.kflidWordGloss)) { // Update the guess, by copying the glosses of the SbNamedObj representing the sense @@ -1574,6 +1596,7 @@ protected virtual void CopySenseToWordGloss(bool fCopyWordGloss, int hvoSbRootSe } } } + protected virtual int CopyLexPosToWordPos(bool fCopyToWordCat, int hvoMsaPos) { int hvoPos = 0; @@ -4258,7 +4281,11 @@ protected override void HandleSelectionChange(IVwRootBox rootb, IVwSelection vws base.HandleSelectionChange(rootb, vwselNew); if (!vwselNew.IsValid) return; - m_editMonitor.DoPendingMorphemeUpdates(); + if (m_editMonitor.NeedMorphemeUpdate) + { + m_editMonitor.DoPendingMorphemeUpdates(); + CopyLexEntryInfoToWordGlossAndPosIfEmpty(true); + } if (!vwselNew.IsValid) return; DoActionOnIconSelection(vwselNew);