/// ------------------------------------------------------------------------------------ /// <summary> /// Create a new section, to be owned by the given book. Since the StTexts are empty, /// this version of the function is generic (i.e. the new section may be made either /// an intro section or a scripture text section by the calling code). /// </summary> /// <param name="book">The book where the new section will be created</param> /// <param name="iSection">The zero-based index of the new section</param> /// <returns>The newly created <see cref="ScrSection"/></returns> /// ------------------------------------------------------------------------------------ public static IScrSection CreateEmptySection(IScrBook book, int iSection) { Debug.Assert(book != null); FdoCache cache = book.Cache; Debug.Assert(iSection >= 0 && iSection <= book.SectionsOS.Count); ScrSection prevSection = null; if (iSection > 0) { prevSection = new ScrSection(cache, book.SectionsOS.HvoArray[iSection - 1]); } // Now insert the section in the book at the specified location. IScrSection section = (IScrSection)book.SectionsOS.InsertAt(new ScrSection(), iSection); // Insert StTexts for section heading and section content. section.HeadingOA = new StText(); section.ContentOA = new StText(); return(section); }
public void MoveNext_ImplicitChapter1AndVerse1() { CheckDisposed(); IScrSection sectionCur = ScrSection.CreateSectionWithEmptyParas(m_genesis, 0, false); TsStringAccessor heading = ((StTxtPara)sectionCur.HeadingOA.ParagraphsOS[0]).Contents; ITsStrBldr strBldr = heading.UnderlyingTsString.GetBldr(); strBldr.Replace(0, strBldr.Length, "My aching head!", null); heading.UnderlyingTsString = strBldr.GetString(); TsStringAccessor content = ((StTxtPara)sectionCur.ContentOA.ParagraphsOS[0]).Contents; strBldr = content.UnderlyingTsString.GetBldr(); strBldr.Replace(0, strBldr.Length, "Verse One. ", null); content.UnderlyingTsString = strBldr.GetString(); sectionCur.AdjustReferences(); ScrTxtPara stPara = new ScrTxtPara(Cache, sectionCur.ContentOA.ParagraphsOS.HvoArray[0]); ScrVerseSet verseSet = new ScrVerseSet(stPara); // Iterate through the verses in the paragraph ScrVerse verse; Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("Verse One. ", verse.Text.Text); Assert.AreEqual(01001001, verse.StartRef); Assert.AreEqual(01001001, verse.EndRef); Assert.IsFalse(verseSet.MoveNext()); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Creates a section with optional heading/content paragraphs. /// </summary> /// <param name="book">The book where the new section will be created</param> /// <param name="iSection">The zero-based index of the new section</param> /// <param name="isIntro">True to create an intro section, false to create a /// normal scripture section</param> /// <param name="createHeadingPara">if true, heading paragraph will be created</param> /// <param name="createContentPara">if true, content paragraph will be created</param> /// <returns>The newly created <see cref="ScrSection"/></returns> /// ------------------------------------------------------------------------------------ private static ScrSection CreateSection(IScrBook book, int iSection, bool isIntro, bool createHeadingPara, bool createContentPara) { Debug.Assert(book != null); // Create an empty section. The end reference needs to be set to indicate to // AdjustReferences if the section is an intro section ScrSection section = (ScrSection)CreateEmptySection(book, iSection); section.VerseRefEnd = new ScrReference(book.CanonicalNum, 1, isIntro ? 0 : 1, book.Cache.LangProject.TranslatedScriptureOA.Versification); section.AdjustReferences(); // Add an empty paragraph to the section head. if (createHeadingPara) { string paraStyle = isIntro ? ScrStyleNames.IntroSectionHead : ScrStyleNames.SectionHead; StTxtParaBldr.CreateEmptyPara(book.Cache, section.HeadingOAHvo, paraStyle, book.Cache.DefaultVernWs); } // Add an empty paragraph to the section content. if (createContentPara) { string paraStyle = isIntro ? ScrStyleNames.IntroParagraph : ScrStyleNames.NormalParagraph; StTxtParaBldr.CreateEmptyPara(book.Cache, section.ContentOAHvo, paraStyle, book.Cache.DefaultVernWs); } return(section); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs ParaNode map using the paragraph. /// </summary> /// <param name="para">The given paragraph.</param> /// ------------------------------------------------------------------------------------ private void ConstructFromPara(StTxtPara para) { // Get the iPara first m_location[kParaIndex] = para.IndexInOwner; // Prepare to get the others StText text = new StText(para.Cache, para.OwnerHVO); int hvoOwner = para.Cache.GetOwnerOfObject(text.Hvo); int ownerClass = para.Cache.GetClassOfObject(hvoOwner); // If the ownerClass is a book, we know that sections are not relevant // to this paragraph and can process accordingly if (ownerClass == ScrBook.kClassId) { // If we've got a title, we can set the rest in short order // (we know that there are no sections) Debug.Assert(text.OwningFlid == (int)ScrBook.ScrBookTags.kflidTitle); m_location[kSectionFlidIndex] = 0; m_location[kSectionIndex] = 0; m_location[kBookFlidIndex] = kTitle; ScrBook book = new ScrBook(para.Cache, text.OwnerHVO); m_location[kBookIndex] = book.IndexInOwner; } // Otherwise, we'll need to use the section data else if (ownerClass == ScrSection.kClassId) { // Since we have sections, get the flid and set others based upon it int sectionFlid = text.OwningFlid; if (sectionFlid == (int)ScrSection.ScrSectionTags.kflidHeading) { m_location[kSectionFlidIndex] = kHeading; } else if (sectionFlid == (int)ScrSection.ScrSectionTags.kflidContent) { m_location[kSectionFlidIndex] = kContent; } // If it was not one of these types, something is wrong, it's an invalid // flid else { Debug.Assert(false); } ScrSection section = new ScrSection(para.Cache, text.OwnerHVO); m_location[kSectionIndex] = section.IndexInOwner; m_location[kBookFlidIndex] = kSections; m_location[kBookIndex] = section.OwningBook.IndexInOwner; } else { Debug.Assert(false); } // default char offset m_location[kCharIndex] = 0; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Merges the heading and content of this section into the previous section content. /// </summary> /// <param name="cache">the fdocache</param> /// <param name="book">the current book</param> /// <param name="iSection">index of the section to be moved</param> /// <returns>number of paragraphs in previous section before merge (use as index /// of first moved paragraph)</returns> /// ------------------------------------------------------------------------------------ public static int MergeIntoPreviousSectionContent(FdoCache cache, ScrBook book, int iSection) { ScrSection prevSection = (ScrSection)book.SectionsOS[iSection - 1]; ScrSection origSection = (ScrSection)book.SectionsOS[iSection]; int cInitParaCount = prevSection.ContentOA.ParagraphsOS.Count; StText.MoveTextContents(origSection.HeadingOA, prevSection.ContentOA, true); StText.MoveTextContents(origSection.ContentOA, prevSection.ContentOA, true); book.SectionsOS.RemoveAt(iSection); // Number of paragraphs originally in the target section return(cInitParaCount); }
public void MoveNext_NonNumericChapter() { CheckDisposed(); IScrSection sectionCur = ScrSection.CreateSectionWithEmptyParas(m_genesis, 0, false); TsStringAccessor heading = ((StTxtPara)sectionCur.HeadingOA.ParagraphsOS[0]).Contents; ITsStrBldr strBldr = heading.UnderlyingTsString.GetBldr(); strBldr.Replace(0, strBldr.Length, "My aching head!", null); heading.UnderlyingTsString = strBldr.GetString(); TsStringAccessor content = ((StTxtPara)sectionCur.ContentOA.ParagraphsOS[0]).Contents; strBldr = content.UnderlyingTsString.GetBldr(); strBldr.Replace(0, strBldr.Length, "A", StyleUtils.CharStyleTextProps(ScrStyleNames.ChapterNumber, Cache.DefaultVernWs)); strBldr.Replace(strBldr.Length, strBldr.Length, "Verse One. ", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); strBldr.Replace(strBldr.Length, strBldr.Length, "2", StyleUtils.CharStyleTextProps(ScrStyleNames.VerseNumber, Cache.DefaultVernWs)); strBldr.Replace(strBldr.Length, strBldr.Length, " Verse Two. ", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); content.UnderlyingTsString = strBldr.GetString(); sectionCur.AdjustReferences(); ScrTxtPara stPara = new ScrTxtPara(Cache, sectionCur.ContentOA.ParagraphsOS.HvoArray[0]); ScrVerseSet verseSet = new ScrVerseSet(stPara); // Iterate through the verses in the paragraph ScrVerse verse; Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("AVerse One. ", verse.Text.Text); Assert.AreEqual(01001001, verse.StartRef); Assert.AreEqual(01001001, verse.EndRef); Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("2 Verse Two. ", verse.Text.Text); Assert.AreEqual(01001002, verse.StartRef); Assert.AreEqual(01001002, verse.EndRef); Assert.IsFalse(verseSet.MoveNext()); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Creates a new section using the contents of the given paragraph as it's heading /// and the remaining paragraphs of this section as it's content. /// </summary> /// <param name="iPara">Index of paragraph to be changed to section head.</param> /// <param name="cParagraphs">Number of paragraphs changed.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public IScrSection ChangeParagraphToSectionHead(int iPara, int cParagraphs) { ScrBook book = OwningBook; int iSection = 0; while (book.SectionsOS.HvoArray[iSection] != Hvo) { iSection++; Debug.Assert(iSection < book.SectionsOS.Count, "Couldn't find index of section " + Hvo); } //Set up parameters depending on the type of change iSection++; //New section follows original one. ScrSection newSection = (ScrSection)ScrSection.CreateEmptySection(book, iSection); // move paragraphs following the changed paragraphs, if any if (iPara + cParagraphs < ContentOA.ParagraphsOS.Count) { StText.MoveTextParagraphs(ContentOA, newSection.ContentOA, iPara + cParagraphs, false); } else { // if the paragraph was at the end of a section then we need to create a // blank content paragraph in the new section. string styleName = IsIntro ? ScrStyleNames.IntroParagraph : ScrStyleNames.NormalParagraph; StTxtParaBldr.CreateEmptyPara(book.Cache, newSection.ContentOAHvo, styleName, Cache.DefaultVernWs); } // move paragraphs to section head StText.MoveTextParagraphs(ContentOA, newSection.HeadingOA, iPara, false); // Make sure the references are correct for both the sections. AdjustReferences(); newSection.AdjustReferences(); // notify views that new section exists m_cache.PropChanged(null, PropChangeType.kpctNotifyAll, book.Hvo, (int)ScrBook.ScrBookTags.kflidSections, iSection, 1, 0); return(newSection as IScrSection); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Creates a new section using the contents of the given section heading as it's content /// and the remaining paragraphs above the selection will become the heading of the new /// section /// </summary> /// <param name="iPara">index of paragraph to be changed to section content</param> /// <param name="cParagraphs">number of paragraphs to move</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public IScrSection ChangeParagraphToSectionContent(int iPara, int cParagraphs) { ScrBook book = OwningBook; int iSection = 0; while (book.SectionsOS.HvoArray[iSection] != Hvo) { iSection++; Debug.Assert(iSection < book.SectionsOS.Count, "Couldn't find index of section " + Hvo); } ScrSection newSection = (ScrSection)ScrSection.CreateEmptySection(book, iSection); // move paragraphs preceding the changed paragraphs, if any if (iPara > 0) { StText.MoveTextParagraphs(HeadingOA, newSection.HeadingOA, iPara - 1, true); } else { // if the paragraph was at the beginning of a section then we need to create a // blank heading paragraph in the new section. string styleName = IsIntro ? ScrStyleNames.IntroSectionHead : ScrStyleNames.SectionHead; StTxtParaBldr.CreateEmptyPara(book.Cache, newSection.HeadingOAHvo, styleName, Cache.DefaultVernWs); } // move paragraphs to section head StText.MoveTextParagraphs(HeadingOA, newSection.ContentOA, cParagraphs - 1, true); // Make sure the sections have correct references AdjustReferences(); newSection.AdjustReferences(); // notify views that new section exists m_cache.PropChanged(null, PropChangeType.kpctNotifyAll, book.Hvo, (int)ScrBook.ScrBookTags.kflidSections, iSection, 1, 0); return(newSection as IScrSection); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Create a new section, to be owned by the given book. Since the StTexts are empty, /// this version of the function is generic (i.e. the new section may be made either /// an intro section or a scripture text section by the calling code). /// </summary> /// <param name="book">The book where the new section will be created</param> /// <param name="iSection">The zero-based index of the new section</param> /// <returns>The newly created <see cref="ScrSection"/></returns> /// ------------------------------------------------------------------------------------ public static IScrSection CreateEmptySection(IScrBook book, int iSection) { Debug.Assert(book != null); FdoCache cache = book.Cache; Debug.Assert(iSection >= 0 && iSection <= book.SectionsOS.Count); ScrSection prevSection = null; if (iSection > 0) prevSection = new ScrSection(cache, book.SectionsOS.HvoArray[iSection - 1]); // Now insert the section in the book at the specified location. IScrSection section = (IScrSection)book.SectionsOS.InsertAt(new ScrSection(), iSection); // Insert StTexts for section heading and section content. section.HeadingOA = new StText(); section.ContentOA = new StText(); return section; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the section index and paragraph index for the specified object, when this /// method assumes is an StTxtPara. /// </summary> /// <param name="obj">An ICmObject associated with an annotation (i.e. the annotation's /// BeginObjectRA) which is assumed to be an StTxtPara.</param> /// <param name="iNewNoteSection">The index of the section, or -1 if the index cannot /// be determined.</param> /// <param name="iNewNotePara">The index of paragraph, or int.MaxValue if the index /// cannot be determined.</param> /// ------------------------------------------------------------------------------------ private void GetLocationInfoForObj(ICmObject obj, out int iNewNoteSection, out int iNewNotePara) { iNewNoteSection = -1; iNewNotePara = int.MaxValue; if (obj is StTxtPara) { StTxtPara para = (StTxtPara)obj; iNewNotePara = para.IndexInOwner; ScrSection section = ScrSection.GetSectionFromParagraph(para); if (section != null) { iNewNoteSection = section.IndexInBook; } } else if (obj is CmTranslation) { CmTranslation trans = (CmTranslation)obj; Debug.Assert(trans.Owner is StTxtPara); GetLocationInfoForObj(trans.Owner, out iNewNoteSection, out iNewNotePara); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Divides the current section into two sections with section index iSection and /// iSection + 1. Moves the selected paragraphs from the heading of /// the current section into the content of the current section. /// </summary> /// <param name="iSection">index of the current section</param> /// <param name="iParaStart">index of the first heading paragraph to be moved into /// content</param> /// <param name="iParaEnd">index of the last heading paragraph to be moved into /// content</param> /// ------------------------------------------------------------------------------------ public void SplitSectionHeading(int iSection, int iParaStart, int iParaEnd) { // Create empty section after the current section ScrSection newSection = (ScrSection)ScrSection.CreateEmptySection(OwningBook, iSection + 1); // Move Heading and Content to new section: // the heading paras after selection, StText.MoveTextParagraphs(this.HeadingOA, newSection.HeadingOA, iParaEnd + 1, false); // all content paras StText.MoveTextParagraphs(this.ContentOA, newSection.ContentOA, 0, false); // Move current selection in heading to content // note: because we already moved the "heading paras after selection" // we will now move all paras from start of selection MoveHeadingParasToContent(iParaStart); // Adjust references for the two sections AdjustReferences(); newSection.AdjustReferences(); Cache.PropChanged(OwnerHVO, (int)ScrBook.ScrBookTags.kflidSections, iSection + 1, 1, 0); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Notifies a section that needs to have the highlighting refreshed. /// </summary> /// <param name="hvoSection"></param> /// ------------------------------------------------------------------------------------ private void NotifySection(int hvoSection) { if (m_cache.IsRealObject(hvoSection, ScrSection.kClassId)) { ScrSection section = new ScrSection(m_cache, hvoSection); m_cache.PropChanged(null, PropChangeType.kpctNotifyAll, section.OwnerHVO, (int)ScrBook.ScrBookTags.kflidSections, section.IndexInBook, 1, 1); } }
public void MoveNext_SpacesInVerses() { CheckDisposed(); ScrSection sectionCur = new ScrSection(); m_genesis.SectionsOS.Append(sectionCur); // Create a section head for this section sectionCur.HeadingOA = new StText(); StTxtParaBldr paraBldr = new StTxtParaBldr(Cache); paraBldr.ParaProps = StyleUtils.ParaStyleTextProps(ScrStyleNames.SectionHead); paraBldr.AppendRun("My aching head!", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); paraBldr.CreateParagraph(sectionCur.HeadingOAHvo); sectionCur.ContentOA = new StText(); paraBldr = new StTxtParaBldr(Cache); paraBldr.ParaProps = StyleUtils.ParaStyleTextProps(ScrStyleNames.NormalParagraph); paraBldr.AppendRun("1", StyleUtils.CharStyleTextProps(ScrStyleNames.ChapterNumber, Cache.DefaultVernWs)); paraBldr.AppendRun("Verse One. ", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); paraBldr.AppendRun("2", StyleUtils.CharStyleTextProps(ScrStyleNames.VerseNumber, Cache.DefaultVernWs)); paraBldr.AppendRun(" Verse Two. ", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); paraBldr.AppendRun("3", StyleUtils.CharStyleTextProps(ScrStyleNames.VerseNumber, Cache.DefaultVernWs)); paraBldr.AppendRun("Verse Three.", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); paraBldr.AppendRun("4", StyleUtils.CharStyleTextProps(ScrStyleNames.VerseNumber, Cache.DefaultVernWs)); paraBldr.AppendRun(" ", StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); StTxtPara para = paraBldr.CreateParagraph(sectionCur.ContentOA.Hvo); sectionCur.AdjustReferences(); ScrTxtPara stPara = new ScrTxtPara(Cache, para.Hvo); ScrVerseSet verseSet = new ScrVerseSet(stPara); // Iterate through the verses in the paragraph ScrVerse verse; Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("1", verse.Text.Text); Assert.AreEqual(01001001, verse.StartRef); Assert.AreEqual(01001001, verse.EndRef); Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("Verse One. ", verse.Text.Text); Assert.AreEqual(01001001, verse.StartRef); Assert.AreEqual(01001001, verse.EndRef); Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("2 Verse Two. ", verse.Text.Text); Assert.AreEqual(01001002, verse.StartRef); Assert.AreEqual(01001002, verse.EndRef); Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("3Verse Three.", verse.Text.Text); Assert.AreEqual(01001003, verse.StartRef); Assert.AreEqual(01001003, verse.EndRef); Assert.IsTrue(verseSet.MoveNext()); verse = (ScrVerse)verseSet.Current; Assert.AreEqual("4 ", verse.Text.Text); Assert.AreEqual(01001004, verse.StartRef); Assert.AreEqual(01001004, verse.EndRef); Assert.IsFalse(verseSet.MoveNext()); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Selections at end of section. /// </summary> /// <param name="helper">The helper.</param> /// <param name="bottomInfo">The bottom info.</param> /// <param name="clev">The clev.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private bool IsSelectionAtEndOfSection(SelectionHelper helper, SelLevInfo[] bottomInfo, int clev) { bool atEndOfSection = false; // Is the bottom of the selection in the last para of the section? ScrSection bottomSection = new ScrSection(m_cache, ((ITeView)Control).LocationTracker.GetSectionHvo( helper, SelectionHelper.SelLimitType.Bottom)); IStText bottomContent = bottomSection.ContentOA; int levelPara = helper.GetLevelForTag((int)StText.StTextTags.kflidParagraphs); if (bottomInfo[levelPara].ihvo == bottomContent.ParagraphsOS.Count - 1) { StTxtPara lastPara = new StTxtPara(m_cache, bottomInfo[levelPara].hvo); ITsString lastParaContents = lastPara.Contents.UnderlyingTsString; int ichBottom = helper.GetIch(SelectionHelper.SelLimitType.Bottom); atEndOfSection = ichBottom == lastParaContents.Length; } return atEndOfSection; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Remove any duplicate verse numbers following the new verse number in the following /// text in the current as well as the following section, if any. /// </summary> /// <param name="hvoObj">The id of the para or translation being modified</param> /// <param name="propTag">The flid (Contents or Translation)</param> /// <param name="tss">The structured string or the para or trans with the new verse /// number</param> /// <param name="wsAlt">The writing system, if a back trans multiString alt</param> /// <param name="chapterToRemove">A string representation of the duplicate chapter number /// to remove.</param> /// <param name="verseRangeToRemove">A string representation of the duplicate verse number to /// remove. This may also be a verse bridge, in which case we will remove all verse /// numbers up to the end value of the bridge</param> /// <param name="ich">The character offset after which we start looking for dups</param> /// ------------------------------------------------------------------------------------ private void RemoveDuplicateVerseNumbers(int hvoObj, int propTag, ITsString tss, int wsAlt, string chapterToRemove, string verseRangeToRemove, int ich) { // Determine the verse number we will remove up to int removeUpToVerse = ScrReference.VerseToIntEnd(verseRangeToRemove); bool inBackTrans = (m_cache.GetClassOfObject(hvoObj) == CmTranslation.kClassId); // Get my current StText, ScrSection and ScrBook int hvoCurrPara = inBackTrans ? (new CmTranslation(m_cache, hvoObj)).OwnerHVO : hvoObj; ScrTxtPara currentPara = new ScrTxtPara(m_cache, hvoCurrPara); // Determine the last chapter reference to remove. int removeChapter = (chapterToRemove != null && chapterToRemove.Length > 0) ? ScrReference.ChapterToInt(chapterToRemove) : 0; // First look in the paragraph where the verse was inserted. if (RemoveDuplicateVerseNumbersInPara(hvoObj, propTag, tss, wsAlt, removeChapter, removeUpToVerse, ich)) { return; } // Search through current and subsequent section (if any) for duplicate verse numbers. StText text = new StText(m_cache, currentPara.OwnerHVO); ScrSection currentSection = new ScrSection(m_cache, text.OwnerHVO); IScrBook currentBook = currentSection.OwningBook; // First look through successive paragraphs for duplicate verse numbers, and then // try the next section if necessary. if (!RemoveDuplicateVerseNumbersInText(text, currentPara.IndexInOwner + 1, inBackTrans, propTag, wsAlt, removeChapter, removeUpToVerse)) { ScrSection nextSection = currentSection.NextSection; if (nextSection != null) { RemoveDuplicateVerseNumbersInText(nextSection.ContentOA, 0, inBackTrans, propTag, wsAlt, removeChapter, removeUpToVerse); } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Goes to the verse reference in the back translation paragraph or the closest /// location to where it would occur /// </summary> /// ------------------------------------------------------------------------------------ protected virtual void GotoVerseBT(ScrReference targetRef, int bookIndex, ScrSection section, int paraIndex, ScrTxtPara para) { ScrVerseSet verseSet = new ScrVerseSetBT(para, ViewConstructorWS); // Look for an exact match of the target verse number in the BT para foreach (ScrVerse verse in verseSet) { if (!verse.VerseNumberRun) continue; if (verse.StartRef <= targetRef && targetRef <= verse.EndRef) { // set the IP here now SetInsertionPoint(bookIndex, section.IndexInBook, paraIndex, verse.TextStartIndex, false); return; } } // An exact match was not found, so look for a best guess spot for it foreach (ScrVerse verse in verseSet) { if (!verse.VerseNumberRun) continue; if (verse.StartRef >= targetRef) { // set the IP here now SetInsertionPoint(bookIndex, section.IndexInBook, paraIndex, verse.VerseStartIndex, false); return; } } // A best guess spot was not found so put the selection at the end of the paragraph SetIpAtEndOfPara(bookIndex, section.IndexInBook, paraIndex, para); }
public void DetermineOverwritability_DataLoss_OneVerseAddedToStart() { DummyScrBook genesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1cur = new ScrSection(); genesis.SectionsOS.Append(section1cur); section1cur.VerseRefStart = section1cur.VerseRefMin = new BCVRef(1, 1, 1).BBCCCVVV; section1cur.VerseRefEnd = section1cur.VerseRefMax = new BCVRef(1, 1, 12).BBCCCVVV; DummyScrBook savedGenesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddArchiveBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1saved = new ScrSection(); savedGenesis.SectionsOS.Append(section1saved); section1saved.VerseRefStart = section1saved.VerseRefMin = new BCVRef(1, 1, 2).BBCCCVVV; section1saved.VerseRefEnd = section1saved.VerseRefMax = new BCVRef(1, 1, 12).BBCCCVVV; string sDetails; List<IScrSection> sectionsToRemove; List<int> missingBtWs; Assert.AreEqual(OverwriteType.DataLoss, genesis.DetermineOverwritability(savedGenesis, out sDetails, out sectionsToRemove, out missingBtWs), "Cannot overwrite without data loss when a section in a saved book is missing the first verse"); Assert.IsNull(sectionsToRemove); Assert.AreEqual(" GEN 1:1", sDetails); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Given a Scripture section, this method returns the index of the paragraph containing /// the requested verse and the position of the character immediately following the /// verse number in that paragraph. If an exact match isn't found, the closest /// approximate place is found. /// </summary> /// <param name="section">The section whose paragraphs will be searched</param> /// <param name="targetRef">The reference being sought</param> /// <param name="iPara">The index of the paragraph where the verse was found</param> /// <param name="ichPosition">The index of the character immediately following the /// verse number in that paragraph</param> /// ------------------------------------------------------------------------------------ protected void FindVerseNumber(ScrSection section, ScrReference targetRef, out int iPara, out int ichPosition) { iPara = 0; ichPosition = 0; bool fChapterFound = (BCVRef.GetChapterFromBcv(section.VerseRefMin) == targetRef.Chapter); foreach (StTxtPara para in section.ContentOA.ParagraphsOS) { TsStringAccessor contents = para.Contents; if (para.Contents.Text == null) continue; TsRunInfo tsi; ITsTextProps ttpRun; int ich = 0; while (ich < contents.UnderlyingTsString.Length) { // Get props of current run. ttpRun = contents.UnderlyingTsString.FetchRunInfoAt(ich, out tsi); // See if it is our verse number style. if (fChapterFound) { if (StStyle.IsStyle(ttpRun, ScrStyleNames.VerseNumber)) { // The whole run is the verse number. Extract it. string sVerseNum = contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); int startVerse, endVerse; ScrReference.VerseToInt(sVerseNum, out startVerse, out endVerse); if ((targetRef.Verse >= startVerse && targetRef.Verse <= endVerse) || targetRef.Verse < startVerse) { ichPosition = tsi.ichLim; return; } } } // 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 = contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); fChapterFound = (ScrReference.ChapterToInt(sChapterNum) == targetRef.Chapter); } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } } ich = tsi.ichLim; } iPara++; } iPara = 0; // Couldn't find it. }
/// ----------------------------------------------------------------------------------- /// <summary> /// If user presses Enter and a new style is applied to the following paragraph, we /// need to mark that style as being in use. If in a section Head, we might need to fix /// the structure. /// </summary> /// <param name="fCalledFromKeyDown">True if this method gets called from OnKeyDown</param> /// <param name="stuInput">input string</param> /// <param name="cchBackspace">number of backspace characters in stuInput</param> /// <param name="cchDelForward">number of delete characters in stuInput</param> /// <param name="ss">Status of Shift/Control/Alt key</param> /// <param name="graphics">graphics for processing input</param> /// <param name="modifiers">key modifiers - shift status, etc.</param> /// <remarks>I (EberhardB) added the parameter <paramref name="fCalledFromKeyDown"/> /// to be able to distinguish between Ctrl-Delete and Ctrl-Backspace.</remarks> /// ----------------------------------------------------------------------------------- protected void HandleEnterKey(bool fCalledFromKeyDown, string stuInput, int cchBackspace, int cchDelForward, VwShiftStatus ss, IVwGraphics graphics, Keys modifiers) { if (IsPictureSelected) // Enter should do nothing if a picture or caption is selected. return; SelLevInfo[] levInfo; // If we are at the end of a heading paragraph, we need to check the "next" style to // see if it is a body type. If it is not, then allow processing to proceed as normal. // If it is a body type, then don't create a new paragraph, just move down to the start // of the first body paragraph in the section. if (InSectionHead) { // if the selection is a range selection then try to delete the selected text first. if (CurrentSelection.Selection.IsRange) { ITsStrFactory factory = TsStrFactoryClass.Create(); CurrentSelection.Selection.ReplaceWithTsString( factory.MakeString("", m_cache.DefaultVernWs)); // If selection is still a range selection, the deletion failed and we don't // need to do anything else. if (CurrentSelection.Selection.IsRange || !InSectionHead) return; } // If the heading style has a following style that is a body style and we are at the // end of the paragraph then move the IP to the beginning of the body paragraph. levInfo = CurrentSelection.GetLevelInfo(SelectionHelper.SelLimitType.Anchor); // This is the paragraph that was originally selected ScrTxtPara headPara = new ScrTxtPara(m_cache, levInfo[0].hvo); IStStyle headParaStyle = m_scr.FindStyle(headPara.StyleName); IStStyle followStyle = headParaStyle != null ? headParaStyle.NextRA : null; if (followStyle != null && followStyle.Structure == StructureValues.Body && SelectionAtEndParagraph()) { // if there is another section head paragraph, then the section needs to be split ScrSection section = new ScrSection(m_cache, ((ITeView)Control).LocationTracker.GetSectionHvo(CurrentSelection, SelectionHelper.SelLimitType.Anchor)); if (CurrentSelection.LevelInfo[0].ihvo < section.HeadingOA.ParagraphsOS.Count - 1) { // Setting the style rules destroys the selection, so we have to remember // the current location before we change the style rules. int iBook = BookIndex; int iSection = SectionIndex; // break the section // create a new empty paragraph in the first section // set the IP to the start of the new paragraph CreateSection(BCVRef.GetVerseFromBcv(section.VerseRefMin) == 0); Debug.Assert(CurrentSelection != null && CurrentSelection.IsValid, "Creating the section didn't set a selection"); StTxtPara contentPara = new StTxtPara(m_cache, CurrentSelection.LevelInfo[0].hvo); contentPara.StyleRules = StyleUtils.ParaStyleTextProps(followStyle.Name); SetInsertionPoint(iBook, iSection, 0, 0, false); } else { SetInsertionPoint(BookIndex, SectionIndex, 0, 0, false); // If the first paragraph is not empty, then insert a new paragraph with the // follow-on style of the section head. StTxtPara contentPara = new StTxtPara(m_cache, CurrentSelection.LevelInfo[0].hvo); if (contentPara.Contents.Length > 0) { StTxtParaBldr bldr = new StTxtParaBldr(m_cache); bldr.ParaProps = StyleUtils.ParaStyleTextProps(followStyle.Name); bldr.AppendRun(String.Empty, StyleUtils.CharStyleTextProps(null, m_cache.DefaultVernWs)); bldr.CreateParagraph(contentPara.OwnerHVO, 0); SetInsertionPoint(BookIndex, SectionIndex, 0, 0, false); } } return; } } // Call the base to handle the key base.OnCharAux('\r', fCalledFromKeyDown, stuInput, cchBackspace, cchDelForward, ss, graphics, modifiers); try { levInfo = CurrentSelection.GetLevelInfo(SelectionHelper.SelLimitType.Anchor); ScrTxtPara para = new ScrTxtPara(m_cache, levInfo[0].hvo); IStStyle style = m_scr.FindStyle(para.StyleName); if (style != null) style.InUse = true; } catch { // Oh, well. We tried. } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Bring the paragraph difference into view in the diff view. /// </summary> /// <param name="hvoPara">hvo of paragraph containing the difference</param> /// <param name="ichMin">starting character position of the difference</param> /// ------------------------------------------------------------------------------------ public void ScrollToParaDiff(int hvoPara, int ichMin) { CheckDisposed(); StTxtPara para = new StTxtPara(m_fdoCache, hvoPara); int iPara = para.IndexInOwner; StText text = new StText(m_fdoCache, para.OwnerHVO); if (m_fdoCache.GetClassOfObject(text.OwnerHVO) == ScrSection.kClassId) { int tag = text.OwningFlid == (int)ScrSection.ScrSectionTags.kflidHeading ? (int)ScrSection.ScrSectionTags.kflidHeading : (int)ScrSection.ScrSectionTags.kflidContent; ScrSection section = new ScrSection(m_fdoCache, text.OwnerHVO); SetInsertionPoint(tag, 0, section.IndexInBook, iPara, ichMin, false); } else SetInsertionPoint((int)ScrBook.ScrBookTags.kflidTitle, 0, 0, iPara, ichMin, false); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Find a paragraph in a section that matches the given HVO /// </summary> /// <param name="section"></param> /// <param name="hvoPara"></param> /// <param name="iPara"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private bool FindPara(ScrSection section, int hvoPara, out int iPara) { iPara = 0; foreach (StPara para in section.ContentOA.ParagraphsOS) { if (para.Hvo == hvoPara) return true; iPara++; } return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Append a new section to the given book, having the specified text as the section /// head. The new section will have an empty content text created also. /// </summary> /// <param name="styleName">Style name for section</param> /// <param name="book">The book to which the section is to be appended</param> /// <param name="sSectionHead">The text of the new section head</param> /// <returns>The newly created section</returns> /// ------------------------------------------------------------------------------------ private IScrSection CreateSection(string styleName, IScrBook book, params string[] sSectionHead) { // Create a section IScrSection section = new ScrSection(); book.SectionsOS.Append(section); // Create a section head for this section section.HeadingOA = new StText(); StTxtParaBldr paraBldr = new StTxtParaBldr(Cache); for (int i = 0; i < sSectionHead.Length; i++) { paraBldr.ParaProps = StyleUtils.ParaStyleTextProps(styleName); paraBldr.AppendRun(sSectionHead[i], StyleUtils.CharStyleTextProps(null, Cache.DefaultVernWs)); paraBldr.CreateParagraph(section.HeadingOAHvo); } int verse = (styleName == ScrStyleNames.SectionHead) ? 1 : 0; section.ContentOA = new StText(); section.VerseRefEnd = section.VerseRefStart = new ScrReference(book.CanonicalNum, 1, verse, m_scr.Versification); return section; }
public void DetermineOverwritability_DataLoss_NastyMismatchedHoles() { DummyScrBook genesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddBookToMockedScripture(1, "Genesis").Hvo); ScrSection sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 1, 1).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 1, 15).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 1, 18).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 1, 29).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 2, 1).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 2, 25).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 3, 4).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 3, 15).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 3, 18).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 3, 24).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 4, 1).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 4, 4).BBCCCVVV; sectionCur = new ScrSection(); genesis.SectionsOS.Append(sectionCur); sectionCur.VerseRefStart = sectionCur.VerseRefMin = new BCVRef(1, 4, 10).BBCCCVVV; sectionCur.VerseRefEnd = sectionCur.VerseRefMax = new BCVRef(1, 4, 18).BBCCCVVV; DummyScrBook savedGenesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddArchiveBookToMockedScripture(1, "Genesis").Hvo); ScrSection sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 1, 1).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 1, 10).BBCCCVVV; sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 2, 22).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 2, 25).BBCCCVVV; sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 3, 4).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 3, 15).BBCCCVVV; sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 3, 18).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 3, 21).BBCCCVVV; sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 4, 1).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 4, 6).BBCCCVVV; sectionSaved = new ScrSection(); savedGenesis.SectionsOS.Append(sectionSaved); sectionSaved.VerseRefStart = sectionSaved.VerseRefMin = new BCVRef(1, 4, 8).BBCCCVVV; sectionSaved.VerseRefEnd = sectionSaved.VerseRefMax = new BCVRef(1, 4, 18).BBCCCVVV; string sDetails; List<IScrSection> sectionsToRemove; List<int> missingBtWs; Assert.AreEqual(OverwriteType.DataLoss, genesis.DetermineOverwritability(savedGenesis, out sDetails, out sectionsToRemove, out missingBtWs), "Cannot overwrite with saved book that contains a hole"); Assert.IsNull(sectionsToRemove); Assert.AreEqual(" GEN 1:11-15" + Environment.NewLine + " GEN 1:18-29" + Environment.NewLine + " GEN 2:1-21" + Environment.NewLine + " GEN 3:22-24", sDetails); }
public void DetermineOverwritability_DataLoss_MultipleHolesBefore() { DummyScrBook genesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1cur = new ScrSection(); genesis.SectionsOS.Append(section1cur); section1cur.VerseRefStart = section1cur.VerseRefMin = new BCVRef(1, 1, 1).BBCCCVVV; section1cur.VerseRefEnd = section1cur.VerseRefMax = new BCVRef(1, 1, 15).BBCCCVVV; ScrSection section2cur = new ScrSection(); genesis.SectionsOS.Append(section2cur); section2cur.VerseRefStart = section2cur.VerseRefMin = new BCVRef(1, 1, 16).BBCCCVVV; section2cur.VerseRefEnd = section2cur.VerseRefMax = new BCVRef(1, 1, 19).BBCCCVVV; ScrSection section3cur = new ScrSection(); genesis.SectionsOS.Append(section3cur); section3cur.VerseRefStart = section3cur.VerseRefMin = new BCVRef(1, 1, 20).BBCCCVVV; section3cur.VerseRefEnd = section3cur.VerseRefMax = new BCVRef(1, 1, 31).BBCCCVVV; ScrSection section4cur = new ScrSection(); genesis.SectionsOS.Append(section4cur); section4cur.VerseRefStart = section4cur.VerseRefMin = new BCVRef(1, 2, 1).BBCCCVVV; section4cur.VerseRefEnd = section4cur.VerseRefMax = new BCVRef(1, 2, 13).BBCCCVVV; DummyScrBook savedGenesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddArchiveBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1saved = new ScrSection(); savedGenesis.SectionsOS.Append(section1saved); section1saved.VerseRefStart = section1saved.VerseRefMin = new BCVRef(1, 1, 16).BBCCCVVV; section1saved.VerseRefEnd = section1saved.VerseRefMax = new BCVRef(1, 1, 19).BBCCCVVV; ScrSection section2saved = new ScrSection(); savedGenesis.SectionsOS.Append(section2saved); section2saved.VerseRefStart = section2saved.VerseRefMin = new BCVRef(1, 2, 1).BBCCCVVV; section2saved.VerseRefEnd = section2saved.VerseRefMax = new BCVRef(1, 2, 12).BBCCCVVV; string sDetails; List<IScrSection> sectionsToRemove; List<int> missingBtWs; Assert.AreEqual(OverwriteType.DataLoss, genesis.DetermineOverwritability(savedGenesis, out sDetails, out sectionsToRemove, out missingBtWs), "Cannot overwrite without data loss when a section in a saved book is missing the first verse"); Assert.IsNull(sectionsToRemove); Assert.AreEqual(" GEN 1:1-15" + Environment.NewLine + " GEN 1:20-31" + Environment.NewLine + " GEN 2:13", sDetails); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the previous footnote and returns it. <paramref name="iSection"/>, /// <paramref name="iParagraph"/>, <paramref name="ich"/> and <paramref name="tag"/> /// reflect the position before the previous footnote marker. If no footnote can be found /// <paramref name="iSection"/>, <paramref name="iParagraph"/>, <paramref name="ich"/> /// and <paramref name="tag"/> won't change. /// </summary> /// <param name="fcCache">FDO cache</param> /// <param name="book">Current book</param> /// <param name="iSection">Index of section to start search</param> /// <param name="iParagraph">Index of paragraph to start search, or -1 to start search /// in last paragraph.</param> /// <param name="ich">Character index to start search, or -1 to start at the end of /// the paragraph.</param> /// <param name="tag">Flid to start search</param> /// <param name="fSkipFirstRun"><c>true</c> if the current run where ich is in should /// be skipped, otherwise <c>false</c>.</param> /// <returns>Previous footnote, or <c>null</c> if there isn't a previous footnote in the /// current book.</returns> /// ------------------------------------------------------------------------------------ public static ScrFootnote FindPreviousFootnote(FdoCache fcCache, IScrBook book, ref int iSection, ref int iParagraph, ref int ich, ref int tag, bool fSkipFirstRun) { // Don't bother looking if book has no footnotes. if (book.FootnotesOS.Count == 0) return null; ScrFootnote footnote = null; FdoOwningSequence<IScrSection> sections = book.SectionsOS; IScrSection section = null; if (tag != (int)ScrBook.ScrBookTags.kflidTitle) section = new ScrSection(fcCache, sections.HvoArray[iSection]); int iSectionTmp = iSection; int iParagraphTmp = iParagraph; int ichTmp = ich; int tagTmp = tag; if (tagTmp == (int)ScrSection.ScrSectionTags.kflidContent) { footnote = FindPreviousFootnoteInText(section.ContentOA, ref iParagraphTmp, ref ichTmp, fSkipFirstRun); if (footnote == null) { tagTmp = (int)ScrSection.ScrSectionTags.kflidHeading; iParagraphTmp = -1; ichTmp = -1; fSkipFirstRun = false; } } if (tagTmp == (int)ScrSection.ScrSectionTags.kflidHeading) { footnote = FindPreviousFootnoteInText(section.HeadingOA, ref iParagraphTmp, ref ichTmp, fSkipFirstRun); while (footnote == null && iSectionTmp > 0) { iSectionTmp--; section = new ScrSection(fcCache, sections.HvoArray[iSectionTmp]); footnote = FindLastFootnoteInSection(section, out iParagraphTmp, out ichTmp, out tagTmp); } if (footnote == null) { iSectionTmp = 0; iParagraphTmp = -1; ichTmp = -1; fSkipFirstRun = false; } } if (footnote == null && book.TitleOA != null) { tagTmp = (int)ScrBook.ScrBookTags.kflidTitle; footnote = FindPreviousFootnoteInText(book.TitleOA, ref iParagraphTmp, ref ichTmp, fSkipFirstRun); } if (footnote != null) { iSection = iSectionTmp; iParagraph = iParagraphTmp; ich = ichTmp; tag = tagTmp; } return footnote; }
/// <summary> /// Load data needed to display the specified objects using the specified fragment. /// This is called before attempting to Display an item that has been listed for lazy /// display using AddLazyItems. It may be used to load the necessary data into the /// DataAccess object. /// </summary> /// <param name="vwenv"></param> /// <param name="rghvo"></param> /// <param name="chvo"></param> /// <param name="hvoParent"></param> /// <param name="tag"></param> /// <param name="frag"></param> /// <param name="ihvoMin"></param> public override void LoadDataFor(IVwEnv vwenv, int[] rghvo, int chvo, int hvoParent, int tag, int frag, int ihvoMin) { CheckDisposed(); // ENHANCE TomB: Implement progress bar bool fStartProgressBar = false; // m_stbr && !m_stbr.IsProgressBarActive(); switch((ScrFrags)frag) { case ScrFrags.kfrBook: { // REVIEW EberhardB: we might want some optimizations on the loading // (see DraftTextVc::LoadDataFor) ScrBook scrBook; foreach (int hvo in rghvo) { scrBook = new ScrBook(m_stvc.Cache, hvo); foreach (StTxtPara stPara in scrBook.TitleOA.ParagraphsOS) { string text = stPara.Contents.Text; } } break; } case ScrFrags.kfrSection: { // REVIEW EberhardB: optimize, especially implement reading +/- 3 paragraphs ScrSection sect; foreach (int hvo in rghvo) { sect = new ScrSection(m_stvc.Cache, hvo); foreach (StTxtPara stPara in sect.HeadingOA.ParagraphsOS) { string text = stPara.Contents.Text; } foreach (StTxtPara stPara in sect.ContentOA.ParagraphsOS) { string text = stPara.Contents.Text; } } break; } default: Debug.Assert(false); break; } // If we had to start a progress bar, return things to normal. if (fStartProgressBar) { // TODO m_qstbr->EndProgressBar(); } }
/// ----------------------------------------------------------------------------------- /// <summary> /// Get a string that describes the Scripture passage based on the selection. /// </summary> /// <param name="tag">The flid of the selected element</param> /// <param name="hvoSel">The hvo of the selected element, either a ScrSection (usually) /// or ScrBook (if in a title)</param> /// <param name="fSimpleFormat">Gets a simple, standardized reference (uses SIL 3-letter /// codes and no verse bridges)</param> /// <returns>String that describes the Scripture passage or null if the selection /// can't be interpreted as a book and/or section reference.</returns> /// ----------------------------------------------------------------------------------- public virtual string GetPassageAsString(int tag, int hvoSel, bool fSimpleFormat) { CheckDisposed(); if (m_cache == null) return null; string sEditRef = null; // Title/reference/etc of text being edited in the draft pane switch (tag) { case (int)ScrSection.ScrSectionTags.kflidHeading: case (int)ScrSection.ScrSectionTags.kflidContent: { // ENHANCE TomB: might want to use low-level methods to get // cached values directly instead of creating the FDO objects // and having them reread the info from the DB. Also, may want // to cache the hvoSel in a method static variable so that when // the selection hasn't really changed to a new section or book, // we stop here. ScrSection section = new ScrSection(m_cache, hvoSel, false, false); BCVRef startRef; BCVRef endRef; section.GetDisplayRefs(out startRef, out endRef); if (fSimpleFormat) sEditRef = startRef.AsString; else { sEditRef = ScrReference.MakeReferenceString(section.OwningBook.BestUIName, startRef, endRef, m_scr.ChapterVerseSepr, m_scr.Bridge); } break; } case (int)ScrBook.ScrBookTags.kflidTitle: { ScrBook book = new ScrBook(m_cache, hvoSel, false, false); sEditRef = (fSimpleFormat ? (book.BookId + " 0:0") : book.BestUIName); break; } default: return null; } // Add the back translation writing system info to the output string, if needed if (IsBackTranslation) { LgWritingSystem ws = new LgWritingSystem(m_cache, ViewConstructorWS); sEditRef = string.Format( TeResourceHelper.GetResourceString("kstidCaptionInBackTrans"), sEditRef, ws.Name.UserDefaultWritingSystem); } return (sEditRef != null && sEditRef.Length != 0) ? sEditRef : null; }
// This is the start of an alternative implementation of GotoVerseBtSeg, actually searching the text. //BCVRef m_startRef; //BCVRef m_endRef; //para.GetBCVRefAtPosition(0, out m_startRef, out m_endRef); //int ktagParaSegments = StTxtPara.SegmentsFlid(Cache); //int cseg = Cache.GetVectorSize(para.Hvo, ktagParaSegments); //int kflidFT = StTxtPara.SegmentFreeTranslationFlid(Cache); //ISilDataAccess sda = Cache.MainCacheAccessor; //int btWs = ViewConstructorWS; //for (int iseg = 0; iseg < cseg; iseg++) //{ // int hvoSeg = sda.get_VecItem(para.Hvo, ktagParaSegments, iseg); // if (!sda.get_IsPropInCache(hvoSeg, kflidFT, (int)CellarModuleDefns.kcptReferenceAtom, 0)) // { // StTxtPara.LoadSegmentFreeTranslations(new int[] {para.Hvo}, Cache, btWs); // } // int hvoFt = sda.get_ObjectProp(hvoSeg, kflidFT); // ITsString tssTrans = sda.get_MultiStringAlt(hvoFt, kflidComment, btWs); // int crun = tssTrans.RunCount; // for (int irun = 0; irun < crun; irun++) // { // ITsTextProps ttpRun = tssTrans.get_Properties(irun); // if (StStyle.IsStyle(ttpRun, ScrStyleNames.VerseNumber)) // { // string sVerseNum = tssTrans.get_RunText(irun); // int nVerseStart, nVerseEnd; // ScrReference.VerseToInt(sVerseNum, out nVerseStart, out nVerseEnd); // m_startRef.Verse = nVerseStart; // m_endRef.Verse = nVerseEnd; // } // else if (StStyle.IsStyle(ttpRun, ScrStyleNames.ChapterNumber)) // { // string sChapterNum = tssTrans.get_RunText(irun); // int nChapter = ScrReference.ChapterToInt(sChapterNum); // m_startRef.Chapter = m_endRef.Chapter = nChapter; // // Set the verse number to 1, since the first verse number after a // // chapter is optional. If we happen to get a verse number in the // // next run, this '1' will be overridden (though it will probably // // still be a 1). // m_startRef.Verse = m_endRef.Verse = 1; // } // } /// ------------------------------------------------------------------------------------ /// <summary> /// Inserts the IP and scrolls it to near the top of the view. Used for going to a /// location in the BT or vernacular where a verse starts (or as close as possible). /// </summary> /// <param name="targetRef">ScrReference to find</param> /// <param name="bookIndex">index of book to look in</param> /// <param name="section">section to search</param> /// <param name="paraIndex">paragraph to look in</param> /// <param name="ichPosition">starting character index to look at</param> /// ------------------------------------------------------------------------------------ protected virtual void GoToPosition(ScrReference targetRef, int bookIndex, ScrSection section, int paraIndex, int ichPosition) { if (ContentType == StVc.ContentTypes.kctSimpleBT) { GotoVerseBT(targetRef, bookIndex, section, paraIndex, new ScrTxtPara(m_cache, section[paraIndex].Hvo)); } else if (ContentType == StVc.ContentTypes.kctSegmentBT) { GotoVerseBtSeg(targetRef, bookIndex, section, paraIndex, new ScrTxtPara(m_cache, section[paraIndex].Hvo), ichPosition); } else { SetInsertionPoint((int)ScrSection.ScrSectionTags.kflidContent, bookIndex, section.IndexInBook, paraIndex, ichPosition, false, VwScrollSelOpts.kssoNearTop); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Makes changes in text structure when the context of the new paragraph style does not /// match the context of the current paragraph style. /// </summary> /// <remarks>This method properly adjusts the text structure for newStyle; the style is /// not applied here - the caller should do that.</remarks> /// <param name="selHelper">the selection to which the new style is being applied</param> /// <param name="curStyle">current style at the selection anchor</param> /// <param name="newStyle">new style to be applied (has a new style context)</param> /// <returns>Returns true if the style change can now be applied.</returns> /// ------------------------------------------------------------------------------------ protected virtual bool AdjustTextStructure(SelectionHelper selHelper, IStStyle curStyle, IStStyle newStyle) { SelLevInfo[] top = selHelper.GetLevelInfo(SelectionHelper.SelLimitType.Top); SelLevInfo[] bottom = selHelper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom); ILocationTracker tracker = ((ITeView)Control).LocationTracker; int scrLevelCount = tracker.GetLevelCount((int)ScrSection.ScrSectionTags.kflidContent); // Adjustments will only be done in section level selections. if (top.Length != scrLevelCount || bottom.Length != scrLevelCount) return true; // CASE 1: Change a section head to a content paragraph // If style of paragraphs of the section heading are changed to something // that is not a section head style, restructure heading paragraphs if (top[1].tag == (int)ScrSection.ScrSectionTags.kflidHeading && newStyle.Structure == StructureValues.Body) { // these will be adjusted to the new indices after the structure is changed int iSection = tracker.GetSectionIndexInBook(selHelper, SelectionHelper.SelLimitType.Top); int iPara; bool firstSectionInContext = (iSection == 0); int iBook = tracker.GetBookIndex(selHelper, SelectionHelper.SelLimitType.Top); ScrBook book = BookFilter.GetBook(iBook); ScrSection section = (ScrSection)book.SectionsOS[iSection]; // for an interior section, need to check context of next section if (!firstSectionInContext) { IScrSection prevSection = book.SectionsOS[iSection - 1]; firstSectionInContext = !SectionsHaveSameContext(section, prevSection); } // If all paragraphs of heading are selected, merge selected section // with previous section if (AreAllParagraphsSelected(top, bottom, section.HeadingOA)) { if (!firstSectionInContext) { iPara = ScrSection.MergeIntoPreviousSectionContent(m_cache, book, iSection); iSection--; } else { // Just need to move all heading paragraphs to the content. The move // method will create a new empty heading paragraph. iPara = 0; section.MoveHeadingParasToContent(0); } } // If selection starts at first paragraph of the heading, move heading paragraphs to // content of previous section. else if (top[0].ihvo == 0) { if (!firstSectionInContext) { iPara = ScrSection.MoveHeadingToPreviousSectionContent(m_cache, book, iSection, bottom[0].ihvo); iSection--; } else { // In this case, we want the selected paragraphs to become the content // of a new section, and the preceding paragraph(s) to become the // heading of the new section. section.ChangeParagraphToSectionContent(top[0].ihvo, bottom[0].ihvo - top[0].ihvo + 1); // update insertion point to first paragraph(s) of new section content iPara = 0; } } else { // If selection bottoms at the last paragraph of the heading, move heading // paragraphs to content of this section if (section.HeadingOA.ParagraphsOS.Count - 1 == bottom[0].ihvo) { section.MoveHeadingParasToContent(top[0].ihvo); iPara = 0; } else // The selection must be only inner paragraphs in the section head, // not including the first or last paragraphs. // In this case, we want the selected paragraph(s) to become content for // the heading paragraph(s) above it, and the following section head // paragraph(s) become the heading of a new section object. { int iParaStart = top[0].ihvo; int iParabottom = bottom[0].ihvo; section.SplitSectionHeading(iSection, iParaStart, iParabottom); iPara = 0; } } // Select all paragraphs in content that were part of section heading (and have // now been moved to iSection, iPara) SetInsertionPoint(iBook, iSection, iPara, 0, false); // Get bottom point of selection and update it to point to beginning of // last paragraph of old heading. Use offsets of current selection. SelectionHelper newHelper = SelectionHelper.Create(Callbacks.EditedRootBox.Site); SelLevInfo[] levInfo = newHelper.GetLevelInfo(SelectionHelper.SelLimitType.End); levInfo[0].ihvo += bottom[0].ihvo - top[0].ihvo; newHelper.SetLevelInfo(SelectionHelper.SelLimitType.End, levInfo); newHelper.IchAnchor = selHelper.GetIch(SelectionHelper.SelLimitType.Top); newHelper.IchEnd = selHelper.GetIch(SelectionHelper.SelLimitType.Bottom); newHelper.SetSelection(true); } //bottom of CASE 1 "Change a section head to a scripture paragraph" // CASE 2: Change scripture paragraph to a section head // - only if the new style has "section head" structure, the selection is in // one paragraph, and that paragraph is part of the section content else if (top[1].tag == (int)ScrSection.ScrSectionTags.kflidContent && newStyle.Structure == StructureValues.Heading) { // Check selected paragraphs for chapter or verse numbers - style will not be // changed if any are found. ScrSection section = new ScrSection(m_cache, tracker.GetSectionHvo(selHelper, SelectionHelper.SelLimitType.Top)); for (int i = top[0].ihvo; i <= bottom[0].ihvo; i++) { ScrTxtPara para = new ScrTxtPara(m_cache, section.ContentOA.ParagraphsOS.HvoArray[i]); if (para.HasChapterOrVerseNumbers()) { // Cancel the request if chapter or verse numbers are present. // display message box if not running in a test if (!InTestMode) { MessageBox.Show(Control, TeResourceHelper.GetResourceString("kstidParaHasNumbers"), TeResourceHelper.GetResourceString("kstidApplicationName"), MessageBoxButtons.OK); } return false; } } int iBook = tracker.GetBookIndex(selHelper, SelectionHelper.SelLimitType.Top); int iSection = tracker.GetSectionIndexInBook(selHelper, SelectionHelper.SelLimitType.Top); int iPara; ScrBook book = section.OwningBook; // End of book is end of context type bool lastSectionInContext = (iSection == book.SectionsOS.Count - 1); // for an interior section, need to check context of next section if (!lastSectionInContext) { IScrSection nextSection = book.SectionsOS[iSection + 1]; lastSectionInContext = !SectionsHaveSameContext(section, nextSection); } if (AreAllParagraphsSelected(top, bottom, section.ContentOA)) { if (!lastSectionInContext) { // Need to combine this section with the following section. // Heading of combined section will be section1.Heading + // section1.Content + section2.Heading iPara = section.HeadingOA.ParagraphsOS.Count; IScrSection nextSection = book.SectionsOS[iSection + 1]; StText.MoveTextContents(section.ContentOA, nextSection.HeadingOA, false); StText.MoveTextContents(section.HeadingOA, nextSection.HeadingOA, false); nextSection.AdjustReferences(); book.SectionsOS.RemoveAt(iSection); } else { // Just need to move all content paragraphs to the heading. The move // method will create a new empty content paragraph. iPara = section.HeadingOA.ParagraphsOS.Count; section.MoveContentParasToHeading(section.ContentOA.ParagraphsOS.Count - 1); } } else if (top[0].ihvo == 0) { // Move the first content paragraphs to become the last para of the // section head section.MoveContentParasToHeading(bottom[0].ihvo); iPara = section.HeadingOA.ParagraphsOS.Count - (bottom[0].ihvo - top[0].ihvo + 1); } else if (bottom[0].ihvo == section.ContentOA.ParagraphsOS.Count - 1 && !lastSectionInContext) { // Move the last content paragraphs to become the first para of the next // section in the book. ScrSection.MoveContentParasToNextSectionHeading(m_cache, book, iSection, top[0].ihvo); // update insertion point to first paragraph(s) of next section head iSection++; iPara = 0; } else { // In this case, we want the selected paragraph to become the heading // of a new section, and the following paragraph(s) to become the // content of the new section object. section.ChangeParagraphToSectionHead(top[0].ihvo, bottom[0].ihvo - top[0].ihvo + 1); // update insertion point to first paragraph(s) of next section head iSection++; iPara = 0; } // Select all paragraphs in content that were part of section heading (and have // now been moved to iSection, iPara) SetInsertionPoint((int)ScrSection.ScrSectionTags.kflidHeading, iBook, iSection, iPara); // Get bottom point of selection and update it to point to beginning of // last paragraph of old heading. Use offsets of current selection. SelectionHelper newHelper = SelectionHelper.Create(Callbacks.EditedRootBox.Site); SelLevInfo[] levInfo = newHelper.GetLevelInfo(SelectionHelper.SelLimitType.End); levInfo[0].ihvo += bottom[0].ihvo - top[0].ihvo; newHelper.SetLevelInfo(SelectionHelper.SelLimitType.End, levInfo); newHelper.IchAnchor = selHelper.GetIch(SelectionHelper.SelLimitType.Top); newHelper.IchEnd = selHelper.GetIch(SelectionHelper.SelLimitType.Bottom); newHelper.SetSelection(true); } return true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Navigate to the beginning of the text of the first (implicit or explicit) chapter /// in the first paragraph in the specified scripture section. If a chapter isn't /// found then the IP is put at the beginning of the content paragraph. /// </summary> /// <param name="iBook">0-based index of the book (in this view)</param> /// <param name="section">The section (in the given book, as displayed in this view) /// </param> /// ------------------------------------------------------------------------------------ private void GoToFirstChapterInSection(int iBook, ScrSection section) { int ichChapterStart = 0; ScrVerseSet verseSet = new ScrVerseSet(new ScrTxtPara(m_cache, section[0].Hvo)); if (verseSet.MoveNext()) { ScrVerse verse = (ScrVerse)verseSet.Current; if (!verse.VerseNumberRun) ichChapterStart = verse.TextStartIndex; } ScrReference scrRef = new ScrReference(section.VerseRefStart, m_scr.Versification); GoToPosition(scrRef, iBook, section, 0, ichChapterStart); }
/// <summary> /// Go to the indicated verse in the BT. We've already determined the index of the book, the section, /// the paragraph, and the character index in the vernacular. We want to figure the corresponding /// position in the BT, which should be the non-label segment closest to (hopefully containing) the /// vernacular position, and select it. /// </summary> /// <param name="targetRef"></param> /// <param name="bookIndex"></param> /// <param name="section"></param> /// <param name="paraIndex"></param> /// <param name="para"></param> /// <param name="ichMainPosition">The position where this verse occurs in the main paragraph.</param> protected virtual void GotoVerseBtSeg(ScrReference targetRef, int bookIndex, ScrSection section, int paraIndex, ScrTxtPara para, int ichMainPosition) { int isegTarget = GetBtSegIndexForVernChar(para, ichMainPosition, ViewConstructorWS); // Select the appropriate segment (or if nothing matched, the last place we can edit). if (isegTarget < 0) return; // pathological. SelectRangeOfChars(bookIndex, section.IndexInBook, (int)ScrSection.ScrSectionTags.kflidContent, paraIndex, isegTarget, 0, 0, true, true, false, VwScrollSelOpts.kssoDefault); }
public void DetermineOverwritability_DataLoss_SavedSubsetOfCurrent() { DummyScrBook genesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1cur = new ScrSection(); genesis.SectionsOS.Append(section1cur); section1cur.VerseRefStart = section1cur.VerseRefMin = new BCVRef(1, 1, 1).BBCCCVVV; section1cur.VerseRefEnd = section1cur.VerseRefMax = new BCVRef(1, 1, 20).BBCCCVVV; DummyScrBook savedGenesis = new DummyScrBook(Cache, m_scrInMemoryCache.AddArchiveBookToMockedScripture(1, "Genesis").Hvo); ScrSection section1saved = new ScrSection(); savedGenesis.SectionsOS.Append(section1saved); section1saved.VerseRefStart = section1saved.VerseRefMin = new BCVRef(1, 1, 5).BBCCCVVV; section1saved.VerseRefEnd = section1saved.VerseRefMax = new BCVRef(1, 1, 15).BBCCCVVV; string sDetails; List<IScrSection> sectionsToRemove; List<int> missingBtWs; Assert.AreEqual(OverwriteType.DataLoss, genesis.DetermineOverwritability(savedGenesis, out sDetails, out sectionsToRemove, out missingBtWs), "Cannot overwrite with saved book that starts after and ends before the current"); Assert.IsNull(sectionsToRemove); Assert.AreEqual(" GEN 1:1-4" + Environment.NewLine + " GEN 1:16-20", sDetails); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Set the IP to the end of the section. Check for vernacular or BT. /// </summary> /// ------------------------------------------------------------------------------------ private void SetIpAtEndOfSection(int bookIndex, ScrSection section) { SetIpAtEndOfPara(bookIndex, section.IndexInBook, section.ContentParagraphCount - 1, section.LastContentParagraph); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Refreshes cache for all footnotes in the StText containing the paragraph. We only /// use this method when verses of a paragraph are changed - this will only happen on /// content paragraphs of a ScrSection. /// </summary> /// <param name="cache"></param> /// <param name="hvoObj"></param> /// ------------------------------------------------------------------------------------ internal static void RefreshCacheForParagraph(FdoCache cache, int hvoObj) { int hvoPara = hvoObj; if (cache.GetClassOfObject(hvoObj) == CmTranslation.kClassId) hvoPara = cache.GetOwnerOfObject(hvoObj); int hvoText = cache.GetOwnerOfObject(hvoPara); IStText text = new StText(cache, hvoText); ScrSection section = new ScrSection(cache, text.OwnerHVO); BCVRef verseRef = new BCVRef(section.VerseRefStart); Dictionary<int, FootnoteHashEntry> dict; // Don't bother on empty cache - it will be created when needed. Need to use HVO to get GUID so we // don't create the book and potentially cause the refresh routine to be called. Guid bookGuid = cache.GetGuidFromId(section.OwnerHVO); if (!cache.TryGetHashtable<int, FootnoteHashEntry>(bookGuid, out dict) || dict.Count == 0) { return; } AddFootnoteRefsInText(text, dict, ref verseRef); }
/// ------------------------------------------------------------------------------------ /// <summary> /// For the Insert Section menu, if IP at the end of a section, inserts a new section. /// Sets the IP in the new para of the new section. /// </summary> /// <param name="insertIntroSection">True to make the created section an intro section, /// false otherwise</param> /// <returns><c>true</c> if we handle this.</returns> /// ------------------------------------------------------------------------------------ public bool CreateSection(bool insertIntroSection) { CheckDisposed(); if (CurrentSelection == null) return false; // REVIEW: What should be done if user has a range selection? if (CurrentSelection.Selection.IsRange) { SelectionHelper.ReduceSelectionToIp(Callbacks.EditedRootBox.Site, SelectionHelper.SelLimitType.Top, true); } // if someone is updating data don't do the insertion if (DataUpdateMonitor.IsUpdateInProgress(m_cache.MainCacheAccessor)) return true; Debug.Assert(EditedRootBox != null); if (m_cache == null) return false; int iSection = SectionIndex; int iBook = BookIndex; // Verify that IP is in valid location for new section if (iSection == -1 && !InBookTitle) { if (!InTestMode) { MessageBox.Show(Control, TeResourceHelper.GetResourceString("kstidInsertSectionNotAllowed"), TeResourceHelper.GetResourceString("kstidApplicationName")); } return true; } IVwRootSite rootSite = EditedRootBox.Site; // make sure noone else can update the data string undo; string redo; TeResourceHelper.MakeUndoRedoLabels("kstidInsertSection", out undo, out redo); using (UndoTaskHelper undoTaskHelper = new UndoTaskHelper(rootSite, undo, redo, true)) using (new DataUpdateMonitor(Control, m_cache.MainCacheAccessor, rootSite, "Insert Section")) using (new WaitCursor(Control)) { try { ScrBook book = BookFilter.GetBook(iBook); IScrSection section = null; if (iSection >= 0) section = book[iSection]; int ichIP = CurrentSelection.IchAnchor; int iPara = CurrentSelection.LevelInfo[0].ihvo; StTxtPara para = null; if (InBookTitle) { iSection = 0; InsertSectionAtIndex(book, iSection, insertIntroSection); } else if (CurrentSelection.LevelInfo[1].tag == (int)ScrSection.ScrSectionTags.kflidContent) { // if IP is in a content paragraph para = (StTxtPara)section.ContentOA.ParagraphsOS[iPara]; if (ichIP > para.Contents.Length) ichIP = para.Contents.Length; // we insert the new section after the current one, so the current section // moves down iSection++; // Now insert the new section // if IP is at the end of the last paragraph of the section... if (iPara == section.ContentOA.ParagraphsOS.Count - 1 && (para.Contents.Text == null || ichIP == para.Contents.Length)) { InsertSectionAtIndex(book, iSection, insertIntroSection); } else { // Need to create a new section and split the section content between // the new section and the existing section IScrSection newSection = ScrSection.CreateSectionWithHeadingPara(book, iSection, insertIntroSection); StText.MovePartialContents(section.ContentOA, newSection.ContentOA, iPara, ichIP, false); } } else if (CurrentSelection.LevelInfo[1].tag == (int)ScrSection.ScrSectionTags.kflidHeading) { para = (StTxtPara)section.HeadingOA.ParagraphsOS[iPara]; if (ichIP > para.Contents.Length) ichIP = para.Contents.Length; if (iPara == 0 && ichIP == 0) { // Insert an empty section before the current section InsertSectionAtIndex(book, iSection, insertIntroSection); } else { // Need to create a new section and split the section heading between // the new section and the existing section IScrSection newSection = ScrSection.CreateSectionWithContentPara(book, iSection, insertIntroSection); StText.MovePartialContents(section.HeadingOA, newSection.HeadingOA, iPara, ichIP, true); } } m_cache.PropChanged(null, PropChangeType.kpctNotifyAll, book.Hvo, (int)ScrBook.ScrBookTags.kflidSections, iSection, 1, 0); // Set the insertion point at the beg of the new section contents if (iBook > -1) { ScrSection newSection = new ScrSection(m_cache, book[iSection].Hvo); SelectionHelper selHelperIP = null; StTxtPara firstPara = newSection.FirstContentParagraph; // if dividing an existing section... if (firstPara != null && firstPara.Contents.Length > 0) { // otherwise, set the IP in the section heading selHelperIP = SetInsertionPoint( (int)ScrSection.ScrSectionTags.kflidHeading, iBook, iSection); } else { // set the IP in the paragraph content selHelperIP = SetInsertionPoint(iBook, iSection, 0, 0, false); } // Don't set the character props if the selection is a range // selection. This most likely is the case only if the new // selection is in a user prompt. The user prompt consists of // 2 runs which makes the below code fail because we only give // it enough props to replace 1 run. if (selHelperIP != null && selHelperIP.Selection != null && !selHelperIP.Selection.IsRange) { //TODO: Only do this if we're creating a brand new section, not if // we're splitting one ITsTextProps[] rgttp = new ITsTextProps[] { StyleUtils.CharStyleTextProps(null, m_cache.DefaultVernWs) }; selHelperIP.Selection.SetSelectionProps(1, rgttp); } } return true; } catch (Exception) { undoTaskHelper.EndUndoTask = false; if (FwApp.App != null) // can be null when testing FwApp.App.RefreshAllViews(m_cache); throw; } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the next footnote and returns it. <paramref name="iSection"/>, /// <paramref name="iParagraph"/>, <paramref name="ich"/> and <paramref name="tag"/> /// reflect the position after the next footnote marker. If no footnote can be found /// <paramref name="iSection"/>, <paramref name="iParagraph"/>, <paramref name="ich"/> /// and <paramref name="tag"/> won't change. /// </summary> /// <param name="fcCache">FDO cache</param> /// <param name="book">Current book</param> /// <param name="iSection">Index of section to start search</param> /// <param name="iParagraph">Index of paragraph to start search</param> /// <param name="ich">Character index to start search</param> /// <param name="tag">Flid to start search</param> /// <param name="fSkipCurrentPos"><c>true</c> to start search with run after ich, /// <c>false</c> to start with current run.</param> /// <returns>Next footnote, or <c>null</c> if there isn't a next footnote in the /// current book.</returns> /// ------------------------------------------------------------------------------------ public static ScrFootnote FindNextFootnote(FdoCache fcCache, IScrBook book, ref int iSection, ref int iParagraph, ref int ich, ref int tag, bool fSkipCurrentPos) { // Don't bother looking if book has no footnotes. if (book.FootnotesOS.Count == 0) return null; ScrFootnote footnote = null; int iSectionTmp = iSection; int iParagraphTmp = iParagraph; int ichTmp = ich; int tagTmp = tag; if (tagTmp == (int)ScrBook.ScrBookTags.kflidTitle) { footnote = FindNextFootnoteInText(book.TitleOA, ref iParagraphTmp, ref ichTmp, fSkipCurrentPos); if (footnote == null) { iSectionTmp = 0; iParagraphTmp = 0; ichTmp = 0; tagTmp = (int)ScrSection.ScrSectionTags.kflidHeading; fSkipCurrentPos = false; } } FdoSequence<IScrSection> sections = book.SectionsOS; IScrSection section = null; if (footnote == null) section = new ScrSection(fcCache, sections.HvoArray[iSectionTmp]); if (tagTmp == (int)ScrSection.ScrSectionTags.kflidHeading) { footnote = FindNextFootnoteInText(section.HeadingOA, ref iParagraphTmp, ref ichTmp, fSkipCurrentPos); if (footnote == null) { iParagraphTmp = 0; ichTmp = 0; tagTmp = (int)ScrSection.ScrSectionTags.kflidContent; fSkipCurrentPos = false; } } if (tagTmp == (int)ScrSection.ScrSectionTags.kflidContent) { footnote = FindNextFootnoteInText(section.ContentOA, ref iParagraphTmp, ref ichTmp, fSkipCurrentPos); } while (footnote == null && iSectionTmp < sections.Count - 1) { iSectionTmp++; section = new ScrSection(fcCache, sections.HvoArray[iSectionTmp]); footnote = FindFirstFootnoteInSection(section, out iParagraphTmp, out ichTmp, out tagTmp); } if (footnote != null) { iSection = iSectionTmp; iParagraph = iParagraphTmp; ich = ichTmp; tag = tagTmp; } return footnote; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles deletion of empty section heading paragraph on backspace key being pressed /// at text boundary. /// </summary> /// <param name="helper">The selection helper.</param> /// <returns><c>true</c> if we handled the deletion, otherwise <c>false</c></returns> /// ------------------------------------------------------------------------------------ private bool HandleBackspaceAfterEmptySectionHeadParagraph(SelectionHelper helper) { ILocationTracker tracker = ((ITeView)Control).LocationTracker; SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); ScrBook book = new ScrBook(m_cache, tracker.GetBookHvo(helper, SelectionHelper.SelLimitType.Top)); ScrSection section = new ScrSection(m_cache, tracker.GetSectionHvo(helper, SelectionHelper.SelLimitType.Top)); int iSection = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); int cParas = section.HeadingOA != null ? section.HeadingOA.ParagraphsOS.Count : 0; if (cParas > 0) { // If we are the beginning of content before a multi-paragraph heading // and the last paragraph is empty, we delete the last paragraph of // the heading. if (cParas > 1) { StTxtPara para = (StTxtPara)section.HeadingOA.ParagraphsOS[cParas - 1]; if (para.Contents.Length == 0) { section.HeadingOA.ParagraphsOS.RemoveAt(cParas - 1); return true; } } // If we are at beginning of content before an empty section head and // not in the first section, we should merge sections. else if (iSection > 0) { StTxtPara para = (StTxtPara)section.HeadingOA.ParagraphsOS[cParas - 1]; if (para.Contents.Length == 0) { return MergeWithPreviousSectionIfInSameContext(helper, book, section, iSection, false); } } return false; // heading is not empty } // don't crash if database is corrupt - allow user to merge with // previous section (TE-4869) if (iSection > 0) { return MergeWithPreviousSectionIfInSameContext(helper, book, section, iSection, false); } return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the footnote at the specified position. /// </summary> /// <param name="cache">FDO cache</param> /// <param name="book">The book to search for footnote</param> /// <param name="iSection">Index of section.</param> /// <param name="iParagraph">Index of paragraph.</param> /// <param name="ich">Character position.</param> /// <param name="tag">Tag</param> /// <returns>Footnote at specified position, or <c>null</c> if specified position is /// not in front of a footnote marker run.</returns> /// ------------------------------------------------------------------------------------ public static ScrFootnote FindCurrentFootnote(FdoCache cache, IScrBook book, int iSection, int iParagraph, int ich, int tag) { // Don't bother looking if book has no footnotes. if (book.FootnotesOS.Count == 0) return null; IStTxtPara para = null; if (tag == (int)ScrBook.ScrBookTags.kflidTitle) para = (IStTxtPara)book.TitleOA.ParagraphsOS[iParagraph]; else { IScrSection section = new ScrSection(cache, book.SectionsOS.HvoArray[iSection]); if (tag == (int)ScrSection.ScrSectionTags.kflidHeading) para = (StTxtPara)section.HeadingOA.ParagraphsOS[iParagraph]; else if (tag == (int)ScrSection.ScrSectionTags.kflidContent) para = (StTxtPara)section.ContentOA.ParagraphsOS[iParagraph]; else { Debug.Assert(false, "Unexpected tag"); return null; } } ITsString tss = para.Contents.UnderlyingTsString; Debug.Assert(tss.Length >= ich); ITsTextProps tprops = tss.get_PropertiesAt(ich); int footnoteHvo = GetFootnoteFromProps(cache, tprops); if (footnoteHvo > 0) return new ScrFootnote(cache, footnoteHvo); return null; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Common utility for the CurrentRef* properties /// </summary> /// <param name="selection"></param> /// <param name="selLimit">The limit of the selection (anchor, end, etc.) to get the /// reference of</param> /// <returns>the start and end reference of the given selection, as an array of two /// ScrReference objects</returns> /// ------------------------------------------------------------------------------------ protected virtual ScrReference[] GetCurrentRefRange(SelectionHelper selection, SelectionHelper.SelLimitType selLimit) { if (m_cache == null || selection == null || BookFilter == null) return new ScrReference[] {ScrReference.Empty, ScrReference.Empty}; ILocationTracker tracker = ((ITeView)Control).LocationTracker; // If there is a current book... BCVRef start = new BCVRef(); BCVRef end = new BCVRef(); int iBook = tracker.GetBookIndex(selection, selLimit); if (iBook >= 0 && BookFilter.BookCount > 0) { try { ScrBook book = BookFilter.GetBook(iBook); // if there is not a current section, then use the book and chapter/verse of 0. int hvoSection = tracker.GetSectionHvo(CurrentSelection, selLimit); if (hvoSection >= 0) { // If there is a section... ScrSection section = new ScrSection(m_cache, hvoSection); int paraHvo = selection.GetLevelInfoForTag( (int)StText.StTextTags.kflidParagraphs, selLimit).hvo; ScrTxtPara scrPara = new ScrTxtPara(m_cache, paraHvo); // Get the ich at either the beginning or the end of the selection, // as specified with limit. (NB that this is relative to the property, not the whole paragraph.) int ich; // Get the TsString, whether in vern or BT ITsString tss; SelLevInfo segInfo; int refWs; if (selection.GetLevelInfoForTag(StTxtPara.SegmentsFlid(Cache), selLimit, out segInfo)) { // selection is in a segmented BT segment. Figure the reference based on where the segment is // in the underlying paragraph. tss = scrPara.Contents.UnderlyingTsString; // for check below on range of ich. CmBaseAnnotation seg = new CmBaseAnnotation(Cache, segInfo.hvo); ich = seg.BeginOffset; Debug.Assert(seg.BeginObjectRAHvo == scrPara.Hvo); refWs = -1; // ich is in the paragraph itself, not some CmTranslation } else { ich = selection.GetIch(selLimit); // Get the TsString, whether in vern or BT tss = selection.GetTss(selLimit); refWs = GetCurrentBtWs(selLimit); // figures out whether it's in a CmTranslation or the para itself. } Debug.Assert(tss == null || ich <= tss.Length); if (tss != null && ich <= tss.Length) { scrPara.GetBCVRefAtPosition(refWs, ich, true, out start, out end); // If the chapter number is 0, then use the chapter from the section reference if (end.Chapter == 0) end.Chapter = BCVRef.GetChapterFromBcv(section.VerseRefMin); if (start.Chapter == 0) start.Chapter = BCVRef.GetChapterFromBcv(section.VerseRefMin); } } else { // either it didn't find a level or it didn't find an index. Either way, // it couldn't find a section. start.Book = end.Book = book.CanonicalNum; } } catch { // Bummer man, something went wrong... don't sweat it though, it happens... // This can occur if you are in the introduction or other location that lacks // relevant information or other necessary stuff. } } return new ScrReference[] {new ScrReference(start, m_scr.Versification), new ScrReference(end, m_scr.Versification)}; ; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the previous footnote and returns it. /// </summary> /// <param name="para">Paragraph to start search</param> /// <param name="ich">Character index to start search, or -1 to start at the end of /// the paragraph.</param> /// <returns>Previous footnote, or <c>null</c> if there isn't a previous footnote in the /// current book.</returns> /// ------------------------------------------------------------------------------------ public static ScrFootnote FindPreviousFootnote(IStTxtPara para, int ich) { FdoCache cache = para.Cache; IScrBook book; IStText text = new StText(cache, para.OwnerHVO); int iPara = Array.IndexOf(text.ParagraphsOS.HvoArray, para.Hvo); int flid = text.OwningFlid; if (flid == (int)ScrSection.ScrSectionTags.kflidHeading || flid == (int)ScrSection.ScrSectionTags.kflidContent) { ScrSection section = new ScrSection(cache, text.OwnerHVO); int iSection = section.IndexInBook; return ScrFootnote.FindPreviousFootnote(cache, section.OwningBook, ref iSection, ref iPara, ref ich, ref flid); } else if (flid == (int)ScrBook.ScrBookTags.kflidTitle) { book = new ScrBook(cache, text.OwnerHVO); return ScrFootnote.FindPreviousFootnoteInText(text, ref iPara, ref ich, false); } else throw new Exception("Can only create footnotes in Scripture Book titles, section heads, and contents"); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Find the difference in both views and bring it into view. /// </summary> /// <param name="diff">difference to seek</param> /// ------------------------------------------------------------------------------------ internal void ScrollToDiff(Difference diff) { CheckDisposed(); // Things aren't yet fully initialized, so quit and we'll get back here later. if (diff == null || m_diffViewWrapper.CurrentDiffView == null || m_diffViewWrapper.RevisionDiffView == null) return; if (diff.DiffType == DifferenceType.SectionAddedToCurrent || diff.DiffType == DifferenceType.SectionHeadAddedToCurrent) { // For Section*AddedToCurrent diff, the Current pane will highlight the // entire section (or head), the Revision pane will show a paragraph location. ScrSection sectionCurr = new ScrSection(m_cache, diff.GetHvoOfFirstSection(false)); m_diffViewWrapper.CurrentDiffView.ScrollToSectionDiff(sectionCurr.IndexInBook); m_diffViewWrapper.RevisionDiffView.ScrollToParaDiff(diff.HvoRev, diff.IchMinRev); } else if (diff.DiffType == DifferenceType.SectionMissingInCurrent || diff.DiffType == DifferenceType.SectionHeadMissingInCurrent) { // For Section*MissingInCurrent diff, the Revsion pane will highlight the // entire section. ScrSection sectionRev = new ScrSection(m_cache, diff.GetHvoOfFirstSection(true)); m_diffViewWrapper.RevisionDiffView.ScrollToSectionDiff(sectionRev.IndexInBook); if (diff.DiffType == DifferenceType.SectionMissingInCurrent) { // Since the para hvo for the current may have been changed by deleting // sections, we will find a new insert index every time, and scroll to that section m_diffViewWrapper.CurrentDiffView.ScrollToSectionDiff( m_bookMerger.GetCurrSectionInsertIndex(diff.RefEnd)); } else if (diff.DiffType == DifferenceType.SectionHeadMissingInCurrent) { // the Current pane will show a paragraph location. m_diffViewWrapper.CurrentDiffView.ScrollToParaDiff(diff.HvoCurr, diff.IchMinCurr); } } else { // Paragraph Diff case. // TODO: For ParagraphMissingInCurrent differences: Someday when we can // show a paragraph insertion point, we will need to call the book merger to get // the correct insertion point because it's possible that the hvoCurr paragraph // may have been deleted, e.g. m_bookMerger.GetCurrParaInsertIndex(diff) m_diffViewWrapper.CurrentDiffView.ScrollToParaDiff(diff.HvoCurr, diff.IchMinCurr); m_diffViewWrapper.RevisionDiffView.ScrollToParaDiff(diff.HvoRev, diff.IchMinRev); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adjust the start and end section references to reflect the content of the section. /// </summary> /// <param name="fIsIntro">if set to <c>true</c> this is an intro section.</param> /// ------------------------------------------------------------------------------------ public void AdjustReferences(bool fIsIntro) { // If this is not the first section then get the previous section's end reference // as a starting point for this section ScrSection prevSection = PreviousSection; ScrReference currentRefStart = new ScrReference(OwningBook.CanonicalNum, 1, 0, Cache.LangProject.TranslatedScriptureOA.Versification); if (prevSection != null) { currentRefStart.BBCCCVVV = prevSection.VerseRefEnd; } // If this is not an intro section then start the verse at 1 so it will not // be an intro section. if (currentRefStart.Verse == 0 && !fIsIntro) { currentRefStart.Verse = 1; } // Default the starting reference for the case that there is no content. int newSectionStart = currentRefStart; // Scan the paragraphs of the section to get the min and max references ScrReference refMin = new ScrReference(currentRefStart); ScrReference refMax = new ScrReference(currentRefStart); ScrReference currentRefEnd = new ScrReference(currentRefStart); bool isFirstTextRun = true; if (ContentOA != null) { foreach (StTxtPara para in ContentOA.ParagraphsOS) { ITsString paraContents = para.Contents.UnderlyingTsString; int iLim = paraContents.RunCount; RefRunType runType = RefRunType.None; for (int iRun = 0; iRun < iLim;) { // for very first run in StText we want to set VerseRefStart int iLimTmp = (iRun == 0 && isFirstTextRun) ? iRun + 1 : iLim; runType = Scripture.GetNextRef(iRun, iLimTmp, paraContents, true, ref currentRefStart, ref currentRefEnd, out iRun); // If a verse or chapter was found, adjust the max and min if the current // verse refs are less than min or greater than max if (runType != RefRunType.None) { // If a chapter or verse is found at the start of the section, then use that // reference instead of the one from the previous section as the min and max. if (isFirstTextRun || currentRefStart < refMin) { refMin.BBCCCVVV = currentRefStart.BBCCCVVV; } if (isFirstTextRun || currentRefEnd > refMax) { refMax.BBCCCVVV = currentRefEnd.BBCCCVVV; } } // after the first run, store the starting reference if (isFirstTextRun) { newSectionStart = currentRefStart; isFirstTextRun = false; } } } } // Store the min and max as the reference range for the section VerseRefStart = newSectionStart; VerseRefMin = refMin; VerseRefMax = refMax; // Store the last reference for the section. bool verseRefEndHasChanged = (VerseRefEnd != currentRefEnd.BBCCCVVV); bool verseRefEndChapterHasChanged = (BCVRef.GetChapterFromBcv(VerseRefEnd) != currentRefEnd.Chapter); VerseRefEnd = currentRefEnd; // If the last reference changes then the next section's references have potentially been invalidated ScrSection nextSection = NextSection; if (nextSection != null) { if ((verseRefEndChapterHasChanged && !nextSection.StartsWithChapterNumber) || (verseRefEndHasChanged && !nextSection.StartsWithVerseOrChapterNumber)) { nextSection.AdjustReferences(); } } }