/// <summary> /// Requirement is to figure the annotaion before e.Annotation and store it /// along with its current annotation in e. /// If e.Annotation is 0, go to the very last word of the document. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void BackWord(object sender, AdvanceWordArgs e, bool fNeedsAnalysis) { int[] indexes; int[] hvos; int[] tags = new int[] { (int)StText.StTextTags.kflidParagraphs, m_vc.ktagParaSegments, m_vc.ktagSegmentForms }; ISilDataAccess sda = m_rootb.DataAccess; if (e.Annotation == 0) { // Very last word. // We set indexes as if the current word was at the very start of the non-existent // paragraph after the last one. hvos = new int[tags.Length]; hvos[0] = m_hvoRoot; indexes = new int[tags.Length]; // full of zeros. indexes[0] = m_fdoCache.MainCacheAccessor.get_VecSize(hvos[0], (int)StText.StTextTags.kflidParagraphs); } else { if (IndexOf(m_hvoRoot, tags, e.Annotation, out indexes, out hvos) < 0) { return; // can't find it at all. } } // This is used for ensuring that paragraphs are loaded. SelLevInfo[] rgvsli = new SelLevInfo[1]; rgvsli[0].tag = (int)StText.StTextTags.kflidParagraphs; rgvsli[0].cpropPrevious = 0; rgvsli[0].ihvo = 0; rgvsli[0].hvo = 0; rgvsli[0].ws = 0; rgvsli[0].ich = 0; // Loop until we can't go back further or find a valid previous word. for (; ; ) { int ilev; // Work back till we find a non-zero index we can decrement. for (ilev = indexes.Length - 1; ilev >= 0 && indexes[ilev] == 0; ilev--) ; if (ilev < 0) return; // at start. indexes[ilev]--; if (ilev == 0) { // Ensure that the paragraph we're moving back to is not lazy. // This may seem a bit of a hack, but should minimize the amount of code // exercised by loading the data for a lazy paragraph: we make an object // selection of the previous paragraph, which automatically loads things // into the cache if needed, but does minimal work if it's already there. // Note that indexes[0] is already set to the index of the previous // paragraph. rgvsli[0].ihvo = indexes[0]; IVwSelection selNew = m_rootb.MakeTextSelInObj( /*[in] int ihvoRoot */ 0, /*[in] int cvsli */ rgvsli.Length, /*[in, size_is(cvsli)] VwSelLevInfo * */ rgvsli, /*[in] int cvsliEnd */ 0, /*[in, size_is(cvsliEnd)] VwSelLevInfo * rgvsliEnd */ null, /*[in] ComBool fInitial */ false, /*[in] ComBool fEdit */ false, /*[in] ComBool fRange */ false, /*[in] ComBool fWholeObj */ true, /*[in] ComBool fInstall */ false ); } ilev++; // work forward choosing the last item in any higher-level list. for (; ilev < indexes.Length; ilev++) { int chvo = 0; // iterate backward thru until we find a list that isn't empty, for example // we iterate thru the paragraphs in a text starting from the currently set index and // move backwards until we find a paragraph that is not empty. for (int offset = 0; offset <= indexes[ilev - 1]; offset++) { int hvo = sda.get_VecItem(hvos[ilev - 1], tags[ilev - 1], indexes[ilev - 1] - offset); hvos[ilev] = hvo; chvo = sda.get_VecSize(hvo, tags[ilev]); if (chvo > 0) // found non-empty list break; } if (chvo == 0) return; // something empty; give up indexes[ilev] = chvo - 1; // last one } // Our target is indicated by the last item in the wordforms of the last // segment. int hvoAnn = sda.get_VecItem(hvos[2], m_vc.ktagSegmentForms, indexes[2]); int hvoAnalysis = sda.get_ObjectProp(hvoAnn, (int)CmAnnotation.CmAnnotationTags.kflidInstanceOf); if (hvoAnalysis == 0 || !m_vc.CanBeAnalyzed(hvoAnn)) continue; // punctuation. // If we're looking for a word that needs analysis, skip this one if it doesn't. if (fNeedsAnalysis && FullyAnalyzed(m_fdoCache, m_vc.ListManager, hvoAnalysis, hvoAnalysis)) continue; // Otherwise this is it. e.Annotation = hvoAnn; e.Analysis = hvoAnalysis; return; } }
/// <summary> /// Requirement is to figure the next annotaion after e.Annotation and store it /// along with its current annotation in e. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// <param name="fNeedsAnalysis">True to advance to a word that needs analysis; /// false to just advance to the immediately next word.</param> public void AdvanceWord(object sender, AdvanceWordArgs e, bool fNeedsAnalysis) { int hvoCurrent = e.Annotation; ISilDataAccess sda = m_fdoCache.MainCacheAccessor; int hvoPara; if (CmObject.IsValidObject(m_fdoCache, hvoCurrent)) { int twficType = CmAnnotationDefn.Twfic(Cache).Hvo; // We should assert that hvoCurrent is Twfic int annoType = sda.get_ObjectProp(hvoCurrent, (int)CmBaseAnnotation.CmAnnotationTags.kflidAnnotationType); Debug.Assert(annoType == twficType, "Given annotation type should be twfic(" + twficType + ") but was " + annoType + "."); hvoPara = sda.get_ObjectProp(hvoCurrent, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject); } else { // Start with first para of text if (m_hvoRoot == 0) return; // can't do anything. int hvoStText = m_hvoRoot; if (sda.get_VecSize(hvoStText, (int)StText.StTextTags.kflidParagraphs) == 0) return; // newly created, no contents yet. hvoPara = sda.get_VecItem(hvoStText, (int)StText.StTextTags.kflidParagraphs, 0); } if (hvoPara != 0) { int cseg = sda.get_VecSize(hvoPara, m_vc.ktagParaSegments); // This flag is set if we have found the word we're advancing from...or // immediately, if hvoCurrent is zero, which means we're 'advancing' from the // start of the text. bool prevMatch = (hvoCurrent == 0); for (int iseg = 0; iseg < cseg; iseg++) { int hvoSeg = sda.get_VecItem(hvoPara, m_vc.ktagParaSegments, iseg); int cann = sda.get_VecSize(hvoSeg, m_vc.ktagSegmentForms); for (int iann = 0; iann < cann; iann++) { int hvoAnn = sda.get_VecItem(hvoSeg, m_vc.ktagSegmentForms, iann); if (prevMatch) { int hvoAnalysis = sda.get_ObjectProp(hvoAnn, (int)CmAnnotation.CmAnnotationTags.kflidInstanceOf); if (hvoAnalysis == 0 || !m_vc.CanBeAnalyzed(hvoAnn)) continue; // skip punctuation. if (fNeedsAnalysis && FullyAnalyzed(m_fdoCache, m_vc.ListManager, hvoAnn, hvoAnalysis)) continue; // Some previous annotation was a match, and this one isn't fully // analyzed, so this is the one we want. e.Annotation = hvoAnn; e.Analysis = hvoAnalysis; // if, for some reason, the next annotation is invalid // reset these to 0. if (!CmObject.IsValidObject(m_fdoCache, hvoAnn)) { e.Annotation = 0; e.Analysis = 0; } return; } prevMatch = (hvoAnn == hvoCurrent); } } // Didn't find another one in the expected paragraph. // If prevmatch is false, something is wrong. // if prevMatch is true, hvoCurrent is the last word in the paragraph, and we // should move to the next. But it's complicated: it might be a paragraph we // haven't expanded from laziness yet, and which therefore doesn't have all its // segment info cached. For now we'll skip doing that. // Sorry, we can't be that lazy about handling laziness! So here goes ... Debug.Assert(prevMatch); Debug.Assert(m_rootb != null); // In the loop above, we searched the paragraph for the relevant word. Now we // need to search the text for the relevant paragraph, and return the first word // in the next paragraph. // Start with first para of text if (m_hvoRoot == 0) return; // can't do anything. int hvoStText = m_hvoRoot; if (hvoStText == 0) return; // newly created text, has no Contents yet. int cpara = sda.get_VecSize(hvoStText, (int)StText.StTextTags.kflidParagraphs); if (cpara == 0) return; SelLevInfo[] rgvsli = new SelLevInfo[1]; rgvsli[0].tag = (int)StText.StTextTags.kflidParagraphs; rgvsli[0].cpropPrevious = 0; rgvsli[0].ihvo = 0; rgvsli[0].hvo = 0; rgvsli[0].ws = 0; rgvsli[0].ich = 0; for (int ipara = 0; ipara < cpara; ++ipara) { int hvoPara1 = sda.get_VecItem(hvoStText, (int)StText.StTextTags.kflidParagraphs, ipara); if (hvoPara1 == hvoPara && (ipara + 1) < cpara) { rgvsli[0].ihvo = ipara + 1; hvoPara = sda.get_VecItem(hvoStText, (int)StText.StTextTags.kflidParagraphs, ipara + 1); if (GetWordInNextPara(hvoPara, rgvsli, e, fNeedsAnalysis)) return; } } } }
/// <summary> /// /// /// </summary> /// <param name="hvoPara"></param> /// <param name="rgvsli"></param> /// <param name="e"></param> /// <param name="fNeedsAnalysis"></param> private bool GetWordInNextPara(int hvoPara, SelLevInfo[] rgvsli, AdvanceWordArgs e, bool fNeedsAnalysis) { // This may seem a bit of a hack, but should minimize the amount of code exercised // by loading the data for a lazy paragraph: we make an object selection of the next // paragraph, which automatically loads things into the cache if needed, but does // minimal work if it's already there. IVwSelection selNew = m_rootb.MakeTextSelInObj( /*[in] int ihvoRoot */ 0, /*[in] int cvsli */ rgvsli.Length, /*[in, size_is(cvsli)] VwSelLevInfo * */ rgvsli, /*[in] int cvsliEnd */ 0, /*[in, size_is(cvsliEnd)] VwSelLevInfo * rgvsliEnd */ null, /*[in] ComBool fInitial */ false, /*[in] ComBool fEdit */ false, /*[in] ComBool fRange */ false, /*[in] ComBool fWholeObj */ true, /*[in] ComBool fInstall */ false ); if (selNew == null) { // If we can't even make a selection, assume there's nothing there. return false; } ISilDataAccess sda = m_fdoCache.MainCacheAccessor; int cseg = sda.get_VecSize(hvoPara, m_vc.ktagParaSegments); for (int iseg = 0; iseg < cseg; iseg++) { int hvoSeg = sda.get_VecItem(hvoPara, m_vc.ktagParaSegments, iseg); int cann = sda.get_VecSize(hvoSeg, m_vc.ktagSegmentForms); for (int iann = 0; iann < cann; iann++) { int hvoAnn = sda.get_VecItem(hvoSeg, m_vc.ktagSegmentForms, iann); int hvoAnalysis = sda.get_ObjectProp(hvoAnn, (int)CmAnnotation.CmAnnotationTags.kflidInstanceOf); if (hvoAnalysis == 0) continue; // skip punctuation. if (fNeedsAnalysis && FullyAnalyzed(m_fdoCache, m_vc.ListManager, hvoAnn, hvoAnalysis)) continue; // conditionally skip analyzed words. // This is the one we want. e.Annotation = hvoAnn; e.Analysis = hvoAnalysis; return true; } } // Nothing valid in this paragraph: either no words or no unanalyzed words. return false; }
/// <summary> /// Move to the first bundle /// </summary> /// <param name="arg"></param> /// <returns></returns> public bool OnFirstBundle(object arg) { AdvanceWordArgs args = new AdvanceWordArgs(0, 0); AdvanceWord(this, args, false); if (args.Annotation != 0) TriggerAnnotationSelected(args.Annotation, args.Analysis, true); return true; }
internal bool OnDisplayShowLinkWords(int hvoAnnotation, int hvoAnalysis) { AdvanceWordArgs argsForNextAnnotation = new AdvanceWordArgs(hvoAnnotation, hvoAnalysis); AdvanceWord(this, argsForNextAnnotation, false); return CanExtendAnnotation(hvoAnnotation, argsForNextAnnotation.Annotation); }
private AdvanceWordArgs GetArgsForAdjacentAnnotation(int hvoAnnotation, int hvoAnalysis, bool fNeedsAnalysis, bool fAdvance) { AdvanceWordArgs args = new AdvanceWordArgs(hvoAnnotation, hvoAnalysis); if (fAdvance) AdvanceWord(this, args, fNeedsAnalysis); else BackWord(this, args, fNeedsAnalysis); return args; }
private int SelectFirstThingNeedingAnnotation(InterlinDocChild pane) { int hvoAnn = 0; AdvanceWordArgs args = new AdvanceWordArgs(0, 0); pane.AdvanceWord(this, args, true); if (args.Annotation != 0) hvoAnn = args.Annotation; return hvoAnn; }
// If the Clerk's object is an annotation, select the corresponding thing in whatever pane // is active. Or, if we have a bookmark, restore it. private void SelectAnnotation() { if (Clerk.CurrentObject == null || Clerk.SuspendLoadingRecordUntilOnJumpToRecord) return; ISilDataAccess sda = Cache.MainCacheAccessor; int annHvo = 0; // Use a bookmark, if we've set one. if (m_bookmark.IndexOfParagraph >= 0) { // Interlinear and Chart SelectAnnotation() must take TWFIC, but RawTextPane can // also handle text segments. // Chart and PrintView SelectAnnotation() don't need to worry about Sandbox. switch (m_tabCtrl.SelectedIndex) { case ktpsAnalyze: case ktpsGloss: annHvo = HandleBookmark(m_idcPane); break; case ktpsTagging: annHvo = HandleBookmark(m_taggingViewPane); break; case ktpsPrint: annHvo = HandleBookmark(m_printViewPane); break; case ktpsCChart: // Call Constituent Chart SelectBookmark() by reflection System.Type type = m_constChartPane.GetType(); MethodInfo info = type.GetMethod("SelectAndScrollToBookmark"); Debug.Assert(info != null, "Couldn't find 'SelectAndScrollToBookmark()' in CChart"); info.Invoke(m_constChartPane, new object[] { m_bookmark }); break; case ktpsRawText: m_rtPane.SelectBookMark(m_bookmark); break; case ktpsInfo: break; default: Debug.Fail("Unhandled tab index."); break; } } else { // This pane, as well as knowing how to work with a record list of Texts, knows // how to work with one of CmBaseAnnotations, that is, a list of occurrences of // a word. int clsid = Cache.GetClassOfObject(Clerk.CurrentObject.Hvo); if (clsid == CmBaseAnnotation.kClassId) annHvo = Clerk.CurrentObject.Hvo; } if (IsPersistedForAnInterlinearTabPage && InterlinearTabPageIsSelected()) { if (annHvo == 0) { // Select the first word needing attention. AdvanceWordArgs args = new AdvanceWordArgs(0, 0); m_idcPane.AdvanceWord(this, args, true); if (args.Annotation != 0) annHvo = args.Annotation; else return; // Can't select nothing, so return. } // Try our best not to select an annotation we know won't work. int twficType = CmAnnotationDefn.Twfic(Cache).Hvo; int annoType = sda.get_ObjectProp(annHvo, kflidAnnotationType); int annInstanceOfRAHvo = sda.get_ObjectProp(annHvo, kflidInstanceOf); if (annInstanceOfRAHvo == 0 || annoType != twficType) { // if we didn't set annHvo by our marker or Clerk.CurrentObject, // then we must have already tried the first word. if (m_bookmark.IndexOfParagraph < 0 && Clerk.CurrentObject.Hvo == 0) return; // reset our marker and return to avoid trying to reuse an "orphan annotation" // resulting from an Undo(). (cf. LT-2663). m_bookmark.Reset(); // See if we can at least select the first word. AdvanceWordArgs args = new AdvanceWordArgs(0, 0); m_idcPane.AdvanceWord(this, args, false); if (args.Annotation != 0) annHvo = args.Annotation; else return; // Can't select nothing, so return. annoType = sda.get_ObjectProp(annHvo, kflidAnnotationType); annInstanceOfRAHvo = sda.get_ObjectProp(annHvo, kflidInstanceOf); // If we still haven't found a good analysis, return. if (annInstanceOfRAHvo == 0 || annoType != twficType) return; } m_idcPane.SelectAnnotation(annHvo); } else if (m_tabCtrl.SelectedIndex == ktpsRawText) { if (annHvo == 0) return; // Can't select nothing, so return; // Select something in the RawTextPane m_bookmark.Save(annHvo, false); int hvoPara = sda.get_ObjectProp(annHvo, kflidBeginObject); int hvoStText = Cache.GetOwnerOfObject(hvoPara); m_rtPane.SelectAnnotation(hvoStText, hvoPara, annHvo); } else if (m_tabCtrl.SelectedIndex == ktpsTagging) { if (annHvo == 0) return; // Can't select nothing, so return; TrySelectAnnotation(sda, m_taggingViewPane, annHvo); } else if (m_tabCtrl.SelectedIndex == ktpsPrint) { if (annHvo == 0) return; // Can't select nothing, so return; TrySelectAnnotation(sda, m_printViewPane, annHvo); } }