/// ------------------------------------------------------------------------------------ /// <summary> /// Get the start and end reference of the specified position <paramref name="ivPos"/> /// in the paragraph. Section reference could be used, if available, to fill in missing /// information, but (at least for now) we will not search back into previous sections. /// </summary> /// <param name="wsBT">HVO of the writing system of the BT to search, or -1 to search /// the vernacular.</param> /// <param name="ivPos">Character offset in the paragraph.</param> /// <param name="fAssocPrev">Consider this position to be associated with any preceding /// text in the paragraph (in the case where ichPos is at a chapter boundary).</param> /// <param name="refStart">[out] Start reference</param> /// <param name="refEnd">[out] End reference</param> /// <remarks><p><paramref name="refStart"/> and <paramref name="refEnd"/> are only /// different if we have bridged verse numbers.</p> /// <p>May return incomplete or invalid reference if, for example, the section /// object does not have a valid start reference.</p> /// <p>If ivPos LT zero, we will not search this para, but look only in previous /// paragraphs</p></remarks> /// ------------------------------------------------------------------------------------ public void GetBCVRefAtPosition(int wsBT, int ivPos, bool fAssocPrev, out BCVRef refStart, out BCVRef refEnd) { refStart = new BCVRef(); refEnd = new BCVRef(); // Might be trying to get the BCVRef in a footnote int ownerOwnFlid = m_cache.GetOwningFlidOfObject(OwnerHVO); if (ownerOwnFlid == (int)ScrBook.ScrBookTags.kflidFootnotes) { ScrFootnote footnote = new ScrFootnote(m_cache, OwnerHVO); refStart = footnote.StartRef; refEnd = footnote.StartRef; return; } BCVRef refStartT = new BCVRef(); BCVRef refEndT = new BCVRef(); ChapterVerseFound found = ChapterVerseFound.None; bool fGotVerse = false; ScrTxtPara para = this; // curent paragraph being examined for reference int chvoParas = 0; // count of paragraphs in the section int ihvoPara = 0; // index of the paragraph within the section BCVRef sectRefStart; BCVRef sectRefEnd; GetSectionStartAndEndRefs(out sectRefStart, out sectRefEnd); while (true) { if (para == this) { found = para.GetBCVRefAtPosWithinPara(wsBT, ivPos, fAssocPrev, out refStartT, out refEndT); } else { found = para.GetBCVRefAtEndOfPara(out refStartT, out refEndT); } // if we found a verse, remember it if (!fGotVerse && ((found & ChapterVerseFound.Verse) != 0)) { refStart.Verse = refStartT.Verse; refEnd.Verse = refEndT.Verse; fGotVerse = true; } // if we found a chapter, process it if ((found & ChapterVerseFound.Chapter) != 0) { if (sectRefStart != null && !sectRefStart.IsEmpty) { refStart.Book = refEnd.Book = sectRefStart.Book; //may not exist } refStart.Chapter = refEnd.Chapter = refStartT.Chapter; // GetBCVwithinPara always returns a verse if it finds a chapter number // so we have already built the full reference Debug.Assert(fGotVerse); return; } // We got to the beginning of the paragraph being edited and still haven't // found a decent reference for our edited text, so keep looking back to // get it from a previous paragraph. // First time thru, figure out which paragraph we are in if (chvoParas == 0) { // REVIEW (EberhardB): does this work if not all paragraphs are // loaded in the cache? chvoParas = m_cache.GetVectorSize(OwnerHVO, (int)StText.StTextTags.kflidParagraphs); // Go forward through vector of paragraphs to find the one being parsed for (ihvoPara = 0; ihvoPara < chvoParas; ihvoPara++) { int hvoPara = m_cache.GetVectorItem(OwnerHVO, (int)StText.StTextTags.kflidParagraphs, ihvoPara); if (hvoPara == Hvo) { break; // found our current para } } } // Move to the previous paragraph ihvoPara--; if (ihvoPara < 0) { // We are at the beginning of the section. We can't look back any further. // ENHANCE TomB: If we search all the way through to the beginning of the // section and never get a valid reference, this section begins in the // middle of a verse or chapter (unlikely in the case of a verse, but // quite likely in the case of a chapter). OR (most likely) this edit // happened at the very beginning of the section, and when we start // parsing, the first thing we'll get is a decent reference. // REVIEW: we're using the section reference, but since they don't get // updated, a change (like removing a chapter) in a previous section // could mess up this section. if (fGotVerse) { // Use the verse we got previously (already set), along with the // first chapter for the section and the book, if available. if (sectRefStart != 0) { refStart.Chapter = refEnd.Chapter = sectRefStart.Chapter; refStart.Book = refEnd.Book = sectRefStart.Book; } } else { // REVIEW: // For now, we're just using the first verse for the section, but this // could be wrong if the section begins in the middle of a verse bridge // or misleading if the section just doesn't yet have verse numbers // marked. if (sectRefStart != 0) { refStart = new BCVRef(sectRefStart); refEnd = new BCVRef(sectRefStart); } // If we are looking for a negative position in the first para of a section // the needed result is not precisely defined yet, // but this is where you could set it // if (para == this && ivPos < 0) // refStart.Verse = refEnd.Verse = ????; } return; } // Set up for the previous paragraph in this section, and we'll try again int hvoNewPara = m_cache.GetVectorItem(OwnerHVO, (int)StText.StTextTags.kflidParagraphs, ihvoPara); // use a special constructor since we already know the section refs para = new ScrTxtPara(m_cache, hvoNewPara, false, false); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Find the start and end reference, by searching backwards in the given ITsString /// from the given position. /// </summary> /// <param name="tss">the given ITsString</param> /// <param name="ichPos">Index of character in paragraph whose reference we want</param> /// <param name="fAssocPrev">Consider this position to be associated with any preceding /// text in the paragraph (in the case where ichPos is at a chapter boundary).</param> /// <param name="refStart">[out] Start reference for the paragraph.</param> /// <param name="refEnd">[out] End reference for the paragraph.</param> /// <returns>A value of <see cref="ChapterVerseFound"/> that tells if a chapter and/or /// verse number was found in this paragraph.</returns> /// <remarks>If ichPos LT zero, we will not search this para, and simply return. /// Be careful not to use this method to search the contents of paragraph using /// character offsets from the BT! /// </remarks> /// ------------------------------------------------------------------------------------ static public ChapterVerseFound GetBCVRefAtPosWithinTss(ITsString tss, int ichPos, bool fAssocPrev, out BCVRef refStart, out BCVRef refEnd) { refStart = new BCVRef(); refEnd = new BCVRef(); ChapterVerseFound retVal = ChapterVerseFound.None; if (tss.Length <= 0) { return(retVal); } TsRunInfo tsi; ITsTextProps ttpRun; bool fGotVerse = false; int ich = ichPos; if (ich > tss.Length) { ich = tss.Length; } while (ich >= 0) { // Get props of current run. ttpRun = tss.FetchRunInfoAt(ich, out tsi); // If we're at (the front edge of) a C/V number boundary and the // caller said to associate the position with the previous material, then // ignore this run unless we're at the beginning of the para. // The run is actually the *following* run, which we don't care about. if (!fAssocPrev || ichPos <= 0 || ichPos != tsi.ichMin) { // See if it is our verse number style. if (!fGotVerse && StStyle.IsStyle(ttpRun, ScrStyleNames.VerseNumber)) { // The whole run is the verse number. Extract it. string sVerseNum = tss.get_RunText(tsi.irun); // string sVerseNum = tss.Text.Substring(tsi.ichMin, // tsi.ichLim - tsi.ichMin); int startVerse, endVerse; ScrReference.VerseToInt(sVerseNum, out startVerse, out endVerse); refStart.Verse = startVerse; refEnd.Verse = endVerse; fGotVerse = true; retVal = ChapterVerseFound.Verse; } // See if it is our chapter number style. else if (StStyle.IsStyle(ttpRun, ScrStyleNames.ChapterNumber)) { try { // Assume the whole run is the chapter number. Extract it. string sChapterNum = tss.get_RunText(tsi.irun); int nChapter = ScrReference.ChapterToInt(sChapterNum); refStart.Chapter = refEnd.Chapter = nChapter; if (fGotVerse) { // Found a chapter number to go with the verse number we // already found, so build the full reference using this // chapter with the previously found verse (already set). retVal |= ChapterVerseFound.Chapter; } else { // Found a chapter number but no verse number, so assume the // edited text is in verse 1 of the chapter. refStart.Verse = refEnd.Verse = 1; fGotVerse = true; retVal = ChapterVerseFound.Chapter | ChapterVerseFound.Verse; } break; } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } } } // move index (going backwards) to the character just before the Min of the run // we just looked at ich = tsi.ichMin - 1; } return(retVal); }