Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 113 additions & 94 deletions Src/LexText/Interlinear/InterlinVc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// <summary>
/// Implementation of displaying a word bundle as Method Object
/// </summary>
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -2604,64 +2666,21 @@ 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;
default:
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)
Expand Down
2 changes: 1 addition & 1 deletion Src/LexText/Interlinear/SandboxBase.ComboHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
49 changes: 38 additions & 11 deletions Src/LexText/Interlinear/SandboxBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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)
{
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -1574,6 +1596,7 @@ protected virtual void CopySenseToWordGloss(bool fCopyWordGloss, int hvoSbRootSe
}
}
}

protected virtual int CopyLexPosToWordPos(bool fCopyToWordCat, int hvoMsaPos)
{
int hvoPos = 0;
Expand Down Expand Up @@ -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);
Expand Down
Loading