public GetLevelInfo ( SelLimitType type ) : SIL.FieldWorks.Common.COMInterfaces.SelLevInfo[] | ||
type | SelLimitType | type |
return | SIL.FieldWorks.Common.COMInterfaces.SelLevInfo[] |
/// ------------------------------------------------------------------------------------ /// <summary> /// Merges the paras in table. /// </summary> /// <param name="helper">The helper.</param> /// <param name="dpt">The problem deletion type.</param> /// <returns><c>true</c> if we merged the paras, otherwise <c>false</c>.</returns> /// ------------------------------------------------------------------------------------ protected internal bool MergeParasInTable(SelectionHelper helper, VwDelProbType dpt) { SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); if (levInfo[0].tag != StTextTags.kflidParagraphs) return false; IStText text; int iPara; int tag; IStTxtPara currPara = GetPara(helper, out text, out iPara, out tag); // Backspace at beginning of paragraph ITsStrBldr bldr; if (dpt == VwDelProbType.kdptBsAtStartPara) { if (iPara <= 0) { MiscUtils.ErrorBeep(); return false; } IStTxtPara prevPara = text[iPara - 1]; int prevParaLen = prevPara.Contents.Length; prevPara.MergeParaWithNext(); helper.SetIch(SelectionHelper.SelLimitType.Top, prevParaLen); helper.SetIch(SelectionHelper.SelLimitType.Bottom, prevParaLen); levInfo[0].ihvo = iPara - 1; helper.SetLevelInfo(SelectionHelper.SelLimitType.Top, levInfo); helper.SetLevelInfo(SelectionHelper.SelLimitType.Bottom, levInfo); if (DeferSelectionUntilEndOfUOW) { // We are within a unit of work, so setting the selection will not work now. // we request that a selection be made after the unit of work. Debug.Assert(!helper.IsRange, "Currently, a selection made during a unit of work can only be an insertion point."); helper.SetIPAfterUOW(EditedRootBox.Site); } else { helper.SetSelection(true); } return true; } // delete at end of a paragraph int cParas = text.ParagraphsOS.Count; if (iPara + 1 >= cParas) return false; // We don't handle merging across StTexts currPara.MergeParaWithNext(); if (DeferSelectionUntilEndOfUOW) { // We are within a unit of work, so setting the selection will not work now. // we request that a selection be made after the unit of work. Debug.Assert(!helper.IsRange, "Currently, a selection made during a unit of work can only be an insertion point."); helper.SetIPAfterUOW(EditedRootBox.Site); } else { helper.SetSelection(true); } return true; }
protected override int GetCell(SelectionHelper sel, SelectionHelper.SelLimitType limit) { if (sel == null) return -1; int tag = sel.GetTextPropId(limit); if (tag == AffixRuleFormulaVc.ktagLeftEmpty || tag == AffixRuleFormulaVc.ktagRightEmpty || tag == MoAffixProcessTags.kflidOutput) return tag; foreach (SelLevInfo level in sel.GetLevelInfo(limit)) { if (level.tag == MoAffixProcessTags.kflidOutput) return level.tag; if (level.tag == MoAffixProcessTags.kflidInput) return level.hvo; } return -1; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Convert the scripture book tag to a filter tag. Also, convert book indices to /// filtered book indices. This is done when loading a selection to make it work /// in the context of the book filter. /// </summary> /// <param name="helper"></param> /// <param name="selType"></param> /// ------------------------------------------------------------------------------------ private void ConvertBookTagAndIndex(SelectionHelper helper, SelectionHelper.SelLimitType selType) { SelLevInfo[] info = helper.GetLevelInfo(selType); int bookPos = info.Length - 1; if (info[bookPos].tag == ScriptureTags.kflidScriptureBooks) { info[bookPos].tag = BookFilter.Tag; info[bookPos].ihvo = BookFilter.GetBookIndex( m_fdoCache.ServiceLocator.GetInstance<IScrBookRepository>().GetObject(info[bookPos].hvo)); helper.SetLevelInfo(selType, info); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles deletion of empty section content paragraph on delete key being pressed at /// text boundary. /// </summary> /// <param name="helper">The selection helper.</param> /// <returns><c>true</c> if we merged the sections, otherwise <c>false</c>.</returns> /// ------------------------------------------------------------------------------------ private bool HandleDeleteBeforeEmptySectionContentParagraph(SelectionHelper helper) { // delete problem deletion will occur at end of section heading SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); ILocationTracker tracker = ((ITeView)Control).LocationTracker; ScrBook book = new ScrBook(m_cache, tracker.GetBookHvo(helper, SelectionHelper.SelLimitType.Top)); int iSection = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); IScrSection section = book.SectionsOS[iSection]; int cParas = section.ContentOA != null ? section.ContentOA.ParagraphsOS.Count : 0; if (cParas > 0) { // If we are the end of heading before a multi-paragraph content // and the first paragraph is empty, we delete the first paragraph of // the content. if (cParas > 1) { StTxtPara para = (StTxtPara)section.ContentOA.ParagraphsOS[0]; if (para.Contents.Length == 0) { section.ContentOA.ParagraphsOS.RemoveAt(0); return true; } } // If we are at end of section heading or beginning of section content // and not in the last section, we should merge sections. else { if (iSection == book.SectionsOS.Count - 1) return false; StTxtPara para = (StTxtPara)section.ContentOA.ParagraphsOS[0]; if (para.Contents.Length == 0) { return MergeWithFollowingSectionIfInSameContext(helper, book, iSection, section, true); } } } else { return MergeWithFollowingSectionIfInSameContext(helper, book, iSection, section, true); } return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Deletes a section heading. /// </summary> /// <param name="helper">Selection information</param> /// <param name="allowHeadingText">if <code>true</code> section head will be deleted /// even if heading contains text</param> /// <param name="positionAtEnd">if <code>true</code> IP will be at end of paragraph /// before top point of current selection</param> /// <returns><code>true</code> if deletion was done</returns> /// ------------------------------------------------------------------------------------ private bool DeleteSectionHead(SelectionHelper helper, bool allowHeadingText, bool positionAtEnd) { ILocationTracker tracker = ((ITeView)Control).LocationTracker; if (helper.GetNumberOfLevels(SelectionHelper.SelLimitType.Top) != tracker.GetLevelCount((int)ScrSection.ScrSectionTags.kflidContent)) return false; int tag = helper.GetTextPropId(SelectionHelper.SelLimitType.Top); if (tag != (int)StTxtPara.StTxtParaTags.kflidContents && tag != SimpleRootSite.kTagUserPrompt) { // Currently this is the only possible leaf property in draft view; // if this changes somehow, we'll probably need to enhance this code. Debug.Assert(false); return false; } int hvoBook = tracker.GetBookHvo(helper, SelectionHelper.SelLimitType.Top); if (hvoBook < 0) { Debug.Assert(false); return false; } ScrBook book = new ScrBook(m_cache, hvoBook); int iSection = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); if (iSection < 0) { // Something changed catastrophically. Book has something in it other than sections. Debug.Assert(false); return false; } IScrSection section = book.SectionsOS[iSection]; if (helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].tag != (int)StText.StTextTags.kflidParagraphs) { // Something changed catastrophically. StText has something in it other than paragraphs! Debug.Assert(false); return false; } // For now we just handle the heading. if (helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[1].tag != (int)ScrSection.ScrSectionTags.kflidHeading) { // Add code here if desired to handle bsp/del at boundary of body. return false; } // OK, we're dealing with a change at the boundary of a section heading // (in a paragraph of an StText that is the heading of an ScrSection in an ScrBook). IStText text = section.HeadingOA; int ihvoPara = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].ihvo; IStTxtPara para = (IStTxtPara)(text.ParagraphsOS[ihvoPara]); if (!allowHeadingText && para.Contents.Length > 0) { // The current heading paragraph has something in it! // For now we won't try to handle this. // (The problem is knowing what to do with the undeleted header text... // make it part of the previous section? The previous header? Delete it?) return false; } if (text.ParagraphsOS.Count != 1) { // Backspace at start or delete at end of non-empty section, and the paragraph is // empty. Do nothing. return false; // Other options: // - delete the section? But what do we do with the rest of its heading? // - delete the empty paragraph? That's easy...just // text.ParagraphsOS.RemoveAt(ihvoPara); // But where do we put the IP afterwards? At the end of the previous body, // for bsp, or the start of our own body, for del? Or keep it in the heading? } // OK, we're in a completely empty section heading. // If it's the very first section of the book, we can't join it to the previous // section, so do nothing. (May eventually enhance to join the two books... // perhaps after asking for confirmation!) if (iSection == 0) return false; // Finally...we know we're going to merge the two sections. MergeContentWithPreviousSection(helper, book, section, iSection, positionAtEnd); return true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles deletions where the selection is not contained within paragraphs of a /// single section. /// </summary> /// <param name="helper"></param> /// <returns><code>true</code> if deletion was handled</returns> /// ------------------------------------------------------------------------------------ internal protected bool HandleComplexDeletion(SelectionHelper helper) { SelLevInfo[] topInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); SelLevInfo[] bottomInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom); // Determine if whole section head was deleted if (IsSectionHeadDeletion(helper, topInfo, bottomInfo)) { return DeleteSectionHead(helper, true, false); } else if (IsSectionDeletion(helper, topInfo, bottomInfo)) { return DeleteSections(helper, topInfo, bottomInfo); } else if (IsMultiSectionContentSelection(helper, topInfo, bottomInfo) && SectionsHaveSameContext(helper, topInfo, bottomInfo)) { return DeleteMultiSectionContentRange(helper); } else if (IsBookTitleSelection(helper, topInfo, bottomInfo)) { return DeleteBookTitle(); } else if (IsBookSelection(helper, topInfo, bottomInfo)) { // Don't use BookIndex, since it will use anchor which may be wrong book. RemoveBook(((ITeView)Control).LocationTracker.GetBookIndex( helper, SelectionHelper.SelLimitType.Top)); return true; } // TODO: Add complex deletion when deleting a range selection that includes two // partial sections. return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles deletion of empty section heading paragraph on delete key being pressed at /// text boundary. /// </summary> /// <param name="helper"></param> /// <returns><c>true</c> if we handled the deletion, otherwise <c>false</c></returns> /// ------------------------------------------------------------------------------------ private bool HandleDeleteBeforeEmptySectionHeadParagraph(SelectionHelper helper) { SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); ScrBook book = new ScrBook(m_cache, ((ITeView)Control).LocationTracker.GetBookHvo( helper, SelectionHelper.SelLimitType.Top)); // Delete problem deletion will be at end of last paragraph of content, // need to check following section head (if available) // Get next section of book. int iSection = ((ITeView)Control).LocationTracker.GetSectionIndexInBook( helper, SelectionHelper.SelLimitType.Top); bool positionAtEnd = false; if (!InSectionHead) { iSection++; if (iSection > book.SectionsOS.Count - 1) return false; positionAtEnd = true; } else if (iSection == 0) return false; IScrSection section = book.SectionsOS[iSection]; if (section.HeadingOA == null || section.HeadingOA.ParagraphsOS.Count == 0) { // don't crash if database is corrupt - allow user to merge the two // sections (TE-4869) return MergeWithPreviousSectionIfInSameContext(helper, book, section, iSection, positionAtEnd); } else { // if there are more than one paragraph in heading, check to see if first // paragraph can be deleted. if (section.HeadingOA.ParagraphsOS.Count > 1) { StTxtPara para = (StTxtPara)section.HeadingOA.ParagraphsOS[0]; if (para.Contents.Length == 0) { section.HeadingOA.ParagraphsOS.RemoveAt(0); return true; } } // If we are at end of content before an empty section head, // we should merge sections. else { StTxtPara para = (StTxtPara)section.HeadingOA.ParagraphsOS[0]; if (para.Contents.Length == 0) { return MergeWithPreviousSectionIfInSameContext(helper, book, section, iSection, positionAtEnd); } } } return false; }
protected override ICmObject GetItem(SelectionHelper sel, SelectionHelper.SelLimitType limit) { if (Rule.StrucDescOS.Count == 0 || sel.GetNumberOfLevels(limit) == 0) return null; var levels = sel.GetLevelInfo(limit); return m_cache.ServiceLocator.GetObject(levels[levels.Length - 1].hvo); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Set both book and section. Don't make a selection; typically the caller will proceed /// to do that. /// </summary> /// <param name="selHelper">The selection helper.</param> /// <param name="selLimitType">Which end of the selection</param> /// <param name="iBook">The index of the book (in the book filter).</param> /// <param name="iSection">The index of the section (relative to /// <paramref name="iBook"/>), or -1 for a selection that is not in a section (e.g. /// title).</param> /// <remarks>This method should change only the book and section levels of the /// selection, but not any other level.</remarks> /// ------------------------------------------------------------------------------------ public override void SetBookAndSection(SelectionHelper selHelper, SelectionHelper.SelLimitType selLimitType, int iBook, int iSection) { if (selHelper == null) return; // we can only deal with one book if (iBook != GetBookIndex(null, selLimitType) || iSection < 0) return; int nLevels = selHelper.GetNumberOfLevels(selLimitType); selHelper.GetLevelInfo(selLimitType)[nLevels - 1].tag = (int)ScrBook.ScrBookTags.kflidSections; selHelper.GetLevelInfo(selLimitType)[nLevels - 1].ihvo = iSection; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Get the index of the section (relative to RootBox), or -1 if we're not in a section /// (e.g. the IP is in a title). /// </summary> /// <param name="selHelper">The selection helper.</param> /// <param name="selLimitType">Which end of the selection</param> /// <returns> /// Index of the section, or -1 if we're not in a section. /// </returns> /// <remarks>The returned value is suitable for making a selection.</remarks> /// ------------------------------------------------------------------------------------ public virtual int GetSectionIndexInView(SelectionHelper selHelper, SelectionHelper.SelLimitType selLimitType) { int sectionLevel = GetSectionLevel(selHelper, selLimitType); return sectionLevel >= 0 ? selHelper.GetLevelInfo(selLimitType)[sectionLevel].ihvo : -1; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Set both book and section. Don't make a selection; typically the caller will proceed /// to do that. /// </summary> /// <param name="selHelper">The selection helper.</param> /// <param name="selLimitType">Which end of the selection</param> /// <param name="iBook">The index of the book (in the book filter).</param> /// <param name="iSection">The index of the section (relative to /// <paramref name="iBook"/>), or -1 for a selection that is not in a section (e.g. /// title).</param> /// <remarks>This method should change only the book and section levels of the /// selection, but not any other level.</remarks> /// ------------------------------------------------------------------------------------ public virtual void SetBookAndSection(SelectionHelper selHelper, SelectionHelper.SelLimitType selLimitType, int iBook, int iSection) { if (!Visible) return; int newHvoBook = m_bookFilter.GetBook(iBook).Hvo; ScrBook book = new ScrBook(m_cache, newHvoBook); int[] hvoAllSections = book.SectionsOS.HvoArray; if (iSection < 0 || iSection >= hvoAllSections.Length) return; // We won't be able to find our section (TE-8242) foreach (DivisionLayoutMgr div in Divisions) { if (div.Configurer.MainObjectId != newHvoBook) continue; // We don't care about the division if it doesn't use our book FocusedStream = div.MainLayoutStream; TePrintLayoutConfig configurer = div.Configurer as TePrintLayoutConfig; if (configurer == null) continue; int hvoSection = hvoAllSections[iSection]; IFilter filter = configurer.SectionFilter.Filter; if (!filter.MatchesCriteria(hvoSection)) { // This division doesn't contain the desired section, so we try // the following section continue; } // Find the index of the section in the filtered section list, // i.e. in the view int iSectionInView = -1; int iSectionLim = Math.Min(hvoAllSections.Length, iSection + 1); for (int iSectionInBook = 0; iSectionInBook < iSectionLim; iSectionInBook++) { if (filter.MatchesCriteria(hvoAllSections[iSectionInBook])) iSectionInView++; } if (iSectionInView < 0) continue; selHelper.GetLevelInfo(selLimitType)[selHelper.GetNumberOfLevels(selLimitType) - 1].tag = GetSectionTag(configurer); selHelper.GetLevelInfo(selLimitType)[selHelper.GetNumberOfLevels(selLimitType) - 1].ihvo = iSectionInView; // We found the division that used the book we care about so lets quit return; } ApplicationException e = new ApplicationException( "Can't find division for given book and index"); e.Data.Add("iBook", iBook); e.Data.Add("iSection", iSection); e.Data.Add("View name", Name); throw e; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the current section, or null if we're not in a section (e.g. the IP is in a title). /// </summary> /// <param name="selHelper">The selection helper.</param> /// <param name="selLimitType">Which end of the selection</param> /// <returns>The current section, or null</returns> /// ------------------------------------------------------------------------------------ public virtual IScrSection GetSection(SelectionHelper selHelper, SelectionHelper.SelLimitType selLimitType) { int sectionLevel = GetSectionLevel(selHelper, selLimitType); int hvoSection = (sectionLevel >= 0) ? selHelper.GetLevelInfo(selLimitType)[sectionLevel].hvo : -1; // section may have been deleted - stale reference can happen if this view is not active when book // is deleted ICmObject section; if (hvoSection >= 0 && Cache.ServiceLocator.ObjectRepository.TryGetObject(hvoSection, out section)) return section as IScrSection; return null; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the nearest footnote before the given selection. /// </summary> /// <param name="helper">The selection helper.</param> /// <param name="book">The book that owns the footnote collection.</param> /// <param name="fSearchForward">True to also search forward within the current paragraph</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private IStFootnote FindFootnoteNearSelection(SelectionHelper helper, IScrBook book, bool fSearchForward) { CheckDisposed(); if (helper == null) helper = CurrentSelection; if (helper == null || book == null) return null; SelLevInfo[] levels = helper.GetLevelInfo(SelectionHelper.SelLimitType.Anchor); int iParagraph = -1; int tag = 0; int ich = helper.IchAnchor; int paraLev = helper.GetLevelForTag(StTextTags.kflidParagraphs); int contentLev = helper.GetLevelForTag(StTxtParaTags.kflidContents); Debug.Assert(paraLev != -1, "Need a paragraph for this method"); iParagraph = levels[paraLev].ihvo; int iSection = ((ITeView)Control).LocationTracker.GetSectionIndexInBook( helper, SelectionHelper.SelLimitType.Anchor); if (iSection < 0) tag = ScrBookTags.kflidTitle; else { tag = (helper.GetLevelForTag(ScrSectionTags.kflidContent) >= 0 ? ScrSectionTags.kflidContent : ScrSectionTags.kflidHeading); } // Special case: if we're in the caption of a picture, get the ich from // the first level instead of the anchor. (TE-4696) if (contentLev >= 0 && levels[contentLev].ihvo == -1) ich = levels[contentLev].ich; IScrFootnote prevFootnote = null; if (fSearchForward) // look first at our current position, if we are searching foward prevFootnote = book.FindCurrentFootnote(iSection, iParagraph, ich, (int)tag); if (prevFootnote == null) { IScrTxtPara para = m_repoScrTxtPara.GetObject(levels[paraLev].hvo); ITsString tss = para.Contents; if (ich != 0) { // look backwards in our current paragraph - skip the current run, except when // at the end of the text. prevFootnote = para.FindPrevFootnoteInContents(ref ich, ich < tss.Length); } else if (iParagraph > 0) { // look at the previous paragraph for a footnote at the end IStText text = m_repoStText.GetObject(levels[paraLev + 1].hvo); IScrTxtPara prevPara = (IScrTxtPara)text[iParagraph - 1]; ITsString prevTss = prevPara.Contents; int ichTmp = -1; prevFootnote = prevPara.FindPrevFootnoteInContents(ref ichTmp, false); if (prevFootnote != null) { if (ichTmp == prevTss.Length - 1) ich = ichTmp; else prevFootnote = null; } // ENHANCE: Look across contexts. } } if (prevFootnote == null && fSearchForward) { // look ahead in the same paragraph IScrTxtPara para = m_repoScrTxtPara.GetObject(levels[paraLev].hvo); ITsString tss = para.Contents; prevFootnote = para.FindNextFootnoteInContents(ref ich, true); } if (prevFootnote == null) { // just go back until we find one prevFootnote = book.FindPrevFootnote(ref iSection, ref iParagraph, ref ich, ref tag); } return prevFootnote; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Delete the given selection, removing any spanned sections. Selection is assumed to /// start in content of one section and end in content of another section. /// </summary> /// <param name="helper"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private bool DeleteMultiSectionContentRange(SelectionHelper helper) { if (helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].tag != StTextTags.kflidParagraphs) { // Something changed catastrophically. StText has something in it other than paragraphs! Debug.Assert(false); return false; } ILocationTracker tracker = ((ITeView)Control).LocationTracker; int iBook = tracker.GetBookIndex(helper, SelectionHelper.SelLimitType.Top); int iSectionStart = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); int iSectionEnd = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Bottom); if (iBook < 0 || iSectionStart < 0 || iSectionEnd < 0) { // Something changed catastrophically. Maybe we added introductory material? Debug.Assert(false); return false; } int iParaStart = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].ihvo; int iParaEnd = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom)[0].ihvo; int ichStart = helper.GetIch(SelectionHelper.SelLimitType.Top); int ichEnd = helper.GetIch(SelectionHelper.SelLimitType.Bottom); // Do the deletion IScrBook book = BookFilter.GetBook(iBook); book.DeleteMultiSectionContentRange(iSectionStart, iSectionEnd, iParaStart, iParaEnd, ichStart, ichEnd); // Set the insertion point. SetInsertionPoint(iBook, iSectionStart, iParaStart, ichStart, helper.AssocPrev); return true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Try to do something about an IP selection deletion that is at the start or end of an /// StText. If successful return true, otherwise false. /// </summary> /// <param name="helper"></param> /// <param name="dpt"></param> /// <returns><c>true</c> if we successfully handled the deletion.</returns> /// ------------------------------------------------------------------------------------ internal bool HandleBsOrDelAtTextBoundary(SelectionHelper helper, VwDelProbType dpt) { CheckDisposed(); SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Anchor); ILocationTracker tracker = ((ITeView)Control).LocationTracker; // bail out if we are not in a paragraph within a scripture section if (levInfo.Length != tracker.GetLevelCount((int)ScrSection.ScrSectionTags.kflidContent) || tracker.GetSectionIndexInView(helper, SelectionHelper.SelLimitType.Anchor) < 0 || levInfo[0].tag != (int)StText.StTextTags.kflidParagraphs) { // Assume we are in a book title SelLevInfo dummyInfo; if (helper.GetLevelInfoForTag((int)ScrBook.ScrBookTags.kflidTitle, out dummyInfo)) return MergeParasInTable(helper, dpt); return false; } // Level 1 will have tags showing which field of section is selected int iLevelSection = helper.GetLevelForTag((int)ScrSection.ScrSectionTags.kflidHeading); if (iLevelSection >= 0) { if (levInfo[0].ihvo == 0 && dpt == VwDelProbType.kdptBsAtStartPara) { // first paragraph of section head return HandleBackspaceAfterEmptyContentParagraph(helper); } else if (levInfo[0].ihvo == 0 && helper.IchAnchor == 0) { // Delete was pressed in an empty section head - try to combine with previous // return DeleteSectionHead(helper, false, false); if (dpt == VwDelProbType.kdptBsAtStartPara) return HandleBackspaceAfterEmptySectionHeadParagraph(helper); return HandleDeleteBeforeEmptySectionHeadParagraph(helper); } // NOTE: we check the vector size for the parent of the paragraph (levInfo[1].hvo) // but with our own tag (levInfo[0].tag)! else if (levInfo[0].ihvo == m_cache.GetVectorSize(levInfo[iLevelSection].hvo, levInfo[0].tag) - 1 && dpt == VwDelProbType.kdptDelAtEndPara) { // last paragraph of section head return HandleDeleteBeforeEmptySectionContentParagraph(helper); } else { // other problem deletion: e.g. delete in BT side-by-side view. Because // we're displaying the paragraphs in a table with two columns, the views // code can't handle that. We have to merge the two paragraphs manually. return MergeParasInTable(helper, dpt); } } else if (helper.GetLevelForTag((int)ScrSection.ScrSectionTags.kflidContent) >= 0) { iLevelSection = helper.GetLevelForTag((int)ScrSection.ScrSectionTags.kflidContent); if (levInfo[0].ihvo == 0 && dpt == VwDelProbType.kdptBsAtStartPara) { // first paragraph of section return HandleBackspaceAfterEmptySectionHeadParagraph(helper); } else if (levInfo[0].ihvo == 0 && helper.IchAnchor == 0) { // Delete was pressed in an empty section content - try to combine with previous if (dpt == VwDelProbType.kdptBsAtStartPara) return HandleBackspaceAfterEmptyContentParagraph(helper); return HandleDeleteBeforeEmptySectionContentParagraph(helper); } // NOTE: we check the vector size for the parent of the paragraph (levInfo[1].hvo) // but with our own tag (levInfo[0].tag)! else if (levInfo[0].ihvo == m_cache.GetVectorSize(levInfo[iLevelSection].hvo, levInfo[0].tag) - 1 && dpt == VwDelProbType.kdptDelAtEndPara) { // last paragraph of section return HandleDeleteBeforeEmptySectionHeadParagraph(helper); } else { // other problem deletion: e.g. delete in BT side-by-side view. Because // we're displaying the paragraphs in a table with two columns, the views // code can't handle that. We have to merge the two paragraphs manually. return MergeParasInTable(helper, dpt); } } return false; }
/// -------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="LocationInfo"/> class. /// </summary> /// <param name="helper">The selection helper used to initialize this location. /// </param> /// -------------------------------------------------------------------------------- public LocationInfo(SelectionHelper helper) { m_location = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom); m_tag = helper.GetTextPropId(SelectionHelper.SelLimitType.Bottom); m_ichMin = m_ichLim = helper.GetIch(SelectionHelper.SelLimitType.Bottom); m_cpropPrev = helper.GetNumberOfPreviousProps(SelectionHelper.SelLimitType.Bottom); m_ws = SelectionHelper.GetFirstWsOfSelection(helper.Selection); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Merges the paras in table. /// </summary> /// <param name="helper">The helper.</param> /// <param name="dpt">The problem deletion type.</param> /// <returns><c>true</c> if we merged the paras, otherwise <c>false</c>.</returns> /// ------------------------------------------------------------------------------------ internal protected bool MergeParasInTable(SelectionHelper helper, VwDelProbType dpt) { SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); if (levInfo[0].tag != (int)StText.StTextTags.kflidParagraphs) return false; ILocationTracker tracker = ((ITeView)Control).LocationTracker; IScrBook book = new ScrBook(m_cache, tracker.GetBookHvo( helper, SelectionHelper.SelLimitType.Anchor)); SelLevInfo tmpInfo; IStText text; if (helper.GetLevelInfoForTag((int)ScrBook.ScrBookTags.kflidTitle, out tmpInfo)) text = book.TitleOA; else { IScrSection section = book.SectionsOS[tracker.GetSectionIndexInBook( helper, SelectionHelper.SelLimitType.Anchor)]; text = (levInfo[1].tag == (int)ScrSection.ScrSectionTags.kflidHeading ? section.HeadingOA : text = section.ContentOA); } int iPara = helper.GetLevelInfoForTag((int)StText.StTextTags.kflidParagraphs).ihvo; StTxtPara currPara = (StTxtPara)text.ParagraphsOS[iPara]; ITsStrBldr bldr; // Backspace at beginning of paragraph if (dpt == VwDelProbType.kdptBsAtStartPara) { if (iPara <= 0) { MiscUtils.ErrorBeep(); return false; } StTxtPara prevPara = (StTxtPara)text.ParagraphsOS[iPara - 1]; int prevParaLen = prevPara.Contents.Length; // Need to make sure we move the back translations AboutToDelete(helper, currPara.Hvo, text.Hvo, (int)StText.StTextTags.kflidParagraphs, iPara, false); bldr = prevPara.Contents.UnderlyingTsString.GetBldr(); bldr.ReplaceTsString(prevPara.Contents.Length, prevPara.Contents.Length, currPara.Contents.UnderlyingTsString); prevPara.Contents.UnderlyingTsString = bldr.GetString(); text.ParagraphsOS.RemoveAt(iPara); helper.SetIch(SelectionHelper.SelLimitType.Top, prevParaLen); helper.SetIch(SelectionHelper.SelLimitType.Bottom, prevParaLen); levInfo[0].ihvo = iPara - 1; helper.SetLevelInfo(SelectionHelper.SelLimitType.Top, levInfo); helper.SetLevelInfo(SelectionHelper.SelLimitType.Bottom, levInfo); helper.SetSelection(true); return true; } // delete at end of a paragraph int cParas = text.ParagraphsOS.Count; if (iPara + 1 >= cParas) return false; // We don't handle merging across StTexts StTxtPara nextPara = (StTxtPara)text.ParagraphsOS[iPara + 1]; // Need to make sure we move the back translations AboutToDelete(helper, nextPara.Hvo, text.Hvo, (int)StText.StTextTags.kflidParagraphs, iPara + 1, false); bldr = currPara.Contents.UnderlyingTsString.GetBldr(); bldr.ReplaceTsString(currPara.Contents.Length, currPara.Contents.Length, nextPara.Contents.UnderlyingTsString); currPara.Contents.UnderlyingTsString = bldr.GetString(); text.ParagraphsOS.RemoveAt(iPara + 1); helper.SetSelection(true); return true; }
protected override int GetItemHvo(SelectionHelper sel, SelectionHelper.SelLimitType limit) { if (Rule.StrucDescOS.Count == 0 || sel.GetNumberOfLevels(limit) == 0) return 0; SelLevInfo[] levels = sel.GetLevelInfo(limit); return levels[levels.Length - 1].hvo; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Delete the given selection, removing any spanned sections. Selection is assumed to /// start in content of one section and end in content of another section. /// </summary> /// <param name="helper"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private bool DeleteMultiSectionContentRange(SelectionHelper helper) { ILocationTracker tracker = ((ITeView)Control).LocationTracker; int ihvoBook = tracker.GetBookIndex(helper, SelectionHelper.SelLimitType.Top); int ihvoSectionStart = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); int ihvoSectionEnd = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Bottom); if (ihvoBook < 0 || ihvoSectionStart < 0 || ihvoSectionEnd < 0) { // Something changed catastrophically. Maybe we added introductory material? Debug.Assert(false); return false; } ScrBook book = BookFilter.GetBook(ihvoBook); IScrSection sectionStart = book.SectionsOS[ihvoSectionStart]; IScrSection sectionEnd = book.SectionsOS[ihvoSectionEnd]; int ihvoParaStart = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].ihvo; StTxtPara paraStart = (StTxtPara) sectionStart.ContentOA.ParagraphsOS[ihvoParaStart]; int ihvoParaEnd = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom)[0].ihvo; StTxtPara paraEnd = (StTxtPara) sectionEnd.ContentOA.ParagraphsOS[ihvoParaEnd]; int ichStart = helper.GetIch(SelectionHelper.SelLimitType.Top); int ichEnd = helper.GetIch(SelectionHelper.SelLimitType.Bottom); if (helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].tag != (int)StText.StTextTags.kflidParagraphs) { // Something changed catastrophically. StText has something in it other than paragraphs! Debug.Assert(false); return false; } // Remove footnotes of sections that will be deleted entirely int iSection = ihvoSectionStart; int iPara = ihvoParaStart; int ich = ichStart; int tag = (int)ScrSection.ScrSectionTags.kflidContent; ScrFootnote firstFootnoteToDelete = ScrFootnote.FindNextFootnote(m_cache, book, ref iSection, ref iPara, ref ich, ref tag, false); if (iSection < ihvoSectionEnd || (iSection == ihvoSectionEnd && (iPara < ihvoParaEnd || (iPara == ihvoParaEnd && ich <= ichEnd))) || tag != (int)ScrSection.ScrSectionTags.kflidContent) { iSection = ihvoSectionEnd; iPara = ihvoParaEnd; ich = ichEnd; tag = (int)ScrSection.ScrSectionTags.kflidContent; ScrFootnote lastFootnoteToDelete = ScrFootnote.FindPreviousFootnote(m_cache, book, ref iSection, ref iPara, ref ich, ref tag, true); if (iSection > ihvoSectionStart || (iSection == ihvoSectionStart && (iPara > ihvoParaStart || (iPara == ihvoParaStart && ich >= ichStart))) || tag != (int)ScrSection.ScrSectionTags.kflidContent) { DeleteFootnotes(book, firstFootnoteToDelete, lastFootnoteToDelete, paraStart.Hvo, paraEnd.Hvo); } } // Remove any trailing portion of the start section that is selected IStText content = sectionStart.ContentOA; for (iPara = content.ParagraphsOS.Count - 1; iPara > ihvoParaStart; iPara--) content.ParagraphsOS.RemoveAt(iPara); ITsStrBldr startContentBldr = paraStart.Contents.UnderlyingTsString.GetBldr(); startContentBldr.Replace(ichStart, startContentBldr.Length, string.Empty, null); // Copy any trailing portion (not selected) of the end section to the start section. int ihvoMoveStart; // Move whole ending paragraph of the selection if selection ends at the beginning // of the paragraph if (ichEnd == 0) ihvoMoveStart = ihvoParaEnd; else ihvoMoveStart = ihvoParaEnd + 1; if (ihvoMoveStart < sectionEnd.ContentOA.ParagraphsOS.Count) m_cache.MoveOwningSequence(sectionEnd.ContentOAHvo, (int)StText.StTextTags.kflidParagraphs, ihvoMoveStart, sectionEnd.ContentOA.ParagraphsOS.Count - 1, sectionStart.ContentOAHvo, (int)StText.StTextTags.kflidParagraphs, sectionStart.ContentOA.ParagraphsOS.Count); // Copy end of last paragraph of selection to end of first paragraph of selection if (ichEnd > 0) { AboutToDelete(helper, paraEnd.Hvo, sectionEnd.ContentOA.Hvo, (int)StText.StTextTags.kflidParagraphs, ihvoParaEnd, false); ITsStrBldr endContentBldr = paraEnd.Contents.UnderlyingTsString.GetBldr(); endContentBldr.Replace(0, ichEnd, string.Empty, null); int curEnd = startContentBldr.Length; startContentBldr.ReplaceTsString(curEnd, curEnd, endContentBldr.GetString()); paraStart.StyleRules = paraEnd.StyleRules; } paraStart.Contents.UnderlyingTsString = startContentBldr.GetString(); // Remove whole sections between start and end of selection, including the // ending section since content we want from it has been moved to the // starting section. for (iSection = ihvoSectionEnd; iSection > ihvoSectionStart; iSection--) book.SectionsOS.RemoveAt(iSection); // if selection starts at beginning of section head remove the whole beginning // section if (helper.IchAnchor == 0 && helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[1].tag == (int)ScrSection.ScrSectionTags.kflidHeading) { book.SectionsOS.RemoveAt(ihvoSectionStart); //set the IP to the end of the previous section if (ihvoSectionStart > 0) { ihvoSectionStart--; IScrSection section = book.SectionsOS[ihvoSectionStart]; ihvoParaStart = section.ContentOA.ParagraphsOS.Count - 1; StTxtPara para = (StTxtPara) section.ContentOA.ParagraphsOS[ihvoParaStart]; ichStart = para.Contents.Length; } } // Set the insertion point. SetInsertionPoint(ihvoBook, ihvoSectionStart, ihvoParaStart, ichStart, helper.AssocPrev); return true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Deletes footnotes when there is a range selection. /// </summary> /// <param name="helper"></param> /// ------------------------------------------------------------------------------------ private void DeleteFootnoteRange(SelectionHelper helper) { int nTopLevels = helper.GetNumberOfLevels(SelectionHelper.SelLimitType.Top); int nBottomLevels = helper.GetNumberOfLevels(SelectionHelper.SelLimitType.Bottom); // Get the index of the book containing the first footnote in the selection. // Then get the index of the footnote within that book. int iFirstBook = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[nTopLevels-1].ihvo; int iFirstFootnote = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[nTopLevels-2].ihvo; // Get the index of the book containing the last footnote in the selection. // Then get the index of the footnote within that book. int iLastBook = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom)[nBottomLevels-1].ihvo; int iLastFootnote = helper.GetLevelInfo(SelectionHelper.SelLimitType.Bottom)[nBottomLevels-2].ihvo; // Loop through the books containing footnotes in the selection. for (int iBook = iFirstBook; iBook <= iLastBook; iBook++) { ScrBook book = BookFilter.GetBook(iBook); int iBeg = iFirstFootnote; if (iFirstBook != iLastBook && iBook > iFirstBook) iBeg = 0; int iEnd = iLastFootnote; if (iFirstBook != iLastBook && iBook < iLastBook) iEnd = book.FootnotesOS.Count - 1; // Loop through the footnotes from the selection that are in the // current book. Go in reverse order through the collection. for (int i = iEnd; i >= iBeg; i--) { // TODO: check filter for each HVO ScrFootnote footnote = new ScrFootnote(m_fdoCache, book.FootnotesOS[i].Hvo); ScrFootnote.DeleteFootnoteAndMarker(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; }
private ComplexConcPatternNode GetNode(SelectionHelper sel, SelectionHelper.SelLimitType limit) { if (sel == null || m_patternModel.Root.IsLeaf) return null; SelLevInfo[] levels = sel.GetLevelInfo(limit); if (levels.Length == 0) return null; SelLevInfo level = levels.First(l => l.tag == ComplexConcPatternSda.ktagChildren); return m_patternModel.GetNode(level.hvo); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Handles deletion of empty section content paragraph on backspace key being pressed /// at text boundary. /// </summary> /// <param name="helper">The selection helper.</param> /// <returns><c>true</c> if we merged the sections, otherwise <c>false</c>.</returns> /// ------------------------------------------------------------------------------------ private bool HandleBackspaceAfterEmptyContentParagraph(SelectionHelper helper) { SelLevInfo[] levInfo = helper.GetLevelInfo(SelectionHelper.SelLimitType.Top); ILocationTracker tracker = ((ITeView)Control).LocationTracker; ScrBook book = new ScrBook(m_cache, tracker.GetBookHvo(helper, SelectionHelper.SelLimitType.Top)); int iSection = tracker.GetSectionIndexInBook(helper, SelectionHelper.SelLimitType.Top); if (iSection == 0) return false; IScrSection prevSection = book.SectionsOS[iSection - 1]; int cParas = prevSection.ContentOA != null ? prevSection.ContentOA.ParagraphsOS.Count : 0; if (cParas > 0) { // If we are the beginning of heading before a multi-paragraph content // and the last paragraph is empty, we delete the last paragraph of // the content. if (cParas > 1) { StTxtPara para = (StTxtPara)prevSection.ContentOA.ParagraphsOS[cParas - 1]; if (para.Contents.Length == 0) { prevSection.ContentOA.ParagraphsOS.RemoveAt(cParas - 1); return true; } } // If we are at beginning of heading before an empty section content and // not in the first section, we should merge sections. else { StTxtPara para = (StTxtPara)prevSection.ContentOA.ParagraphsOS[cParas - 1]; if (para.Contents.Length == 0) { return MergeWithFollowingSectionIfInSameContext(helper, book, iSection - 1, prevSection, false); } } } else { return MergeWithFollowingSectionIfInSameContext(helper, book, iSection - 1, prevSection, false); } return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds the nearest footnote before the given selection. /// </summary> /// <param name="helper">The selection helper.</param> /// <param name="book">The book that owns the footnote collection.</param> /// <param name="fSearchForward">True to also search forward within the current paragraph</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private StFootnote FindFootnoteNearSelection(SelectionHelper helper, IScrBook book, bool fSearchForward) { CheckDisposed(); if (helper == null) helper = CurrentSelection; if (helper == null || book == null) return null; SelLevInfo[] levels = helper.GetLevelInfo(SelectionHelper.SelLimitType.Anchor); int iParagraph = -1; int tag = 0; int ich = helper.IchAnchor; int paraLev = helper.GetLevelForTag((int)StText.StTextTags.kflidParagraphs); int contentLev = helper.GetLevelForTag((int)StTxtPara.StTxtParaTags.kflidContents); Debug.Assert(paraLev != -1, "Need a paragraph for this method"); iParagraph = levels[paraLev].ihvo; int iSection = ((ITeView)Control).LocationTracker.GetSectionIndexInBook( helper, SelectionHelper.SelLimitType.Anchor); if (iSection < 0) tag = (int)ScrBook.ScrBookTags.kflidTitle; else { tag = (helper.GetLevelForTag((int)ScrSection.ScrSectionTags.kflidContent) >= 0 ? (int)ScrSection.ScrSectionTags.kflidContent : (int)ScrSection.ScrSectionTags.kflidHeading); } // Special case: if we're in the caption of a picture, get the ich from // the first level instead of the anchor. (TE-4696) if (contentLev >= 0 && levels[contentLev].ihvo == -1) ich = levels[contentLev].ich; ScrFootnote prevFootnote = null; if (fSearchForward) // look first at our current position, if we are searching foward { prevFootnote = ScrFootnote.FindCurrentFootnote(m_cache, book, iSection, iParagraph, ich, tag); } if (prevFootnote == null) { StTxtPara para = new StTxtPara(m_cache, levels[paraLev].hvo); ITsString tss = para.Contents.UnderlyingTsString; if (ich != 0) { // look backwards in our current paragraph prevFootnote = ScrFootnote.FindLastFootnoteInString(m_cache, tss, ref ich, true); } else if (iParagraph > 0) { // look at the previous paragraph for a footnote at the end StText text = new StText(m_cache, levels[paraLev + 1].hvo); StTxtPara prevPara = (StTxtPara)text.ParagraphsOS[iParagraph - 1]; ITsString prevTss = prevPara.Contents.UnderlyingTsString; int ichTmp = -1; prevFootnote = ScrFootnote.FindLastFootnoteInString(m_cache, prevTss, ref ichTmp, false); if (prevFootnote != null) { if (ichTmp == prevTss.Length - 1) ich = ichTmp; else prevFootnote = null; } // ENHANCE: Look across contexts. } } if (prevFootnote == null && fSearchForward) { // look ahead in the same paragraph StTxtPara para = new StTxtPara(m_cache, levels[paraLev].hvo); ITsString tss = para.Contents.UnderlyingTsString; prevFootnote = ScrFootnote.FindFirstFootnoteInString(m_cache, tss, ref ich, true); } if (prevFootnote == null) { // just go back until we find one prevFootnote = ScrFootnote.FindPreviousFootnote(m_cache, book, ref iSection, ref iParagraph, ref ich, ref tag); } return prevFootnote; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Merges content of given section into the content of the previous section and then /// deletes the given section. /// </summary> /// <param name="helper"> </param> /// <param name="book"></param> /// <param name="section"></param> /// <param name="ihvoSection"></param> /// <param name="fPositionAtEnd">If true position of Selection is placed at end of /// paragraph, else at the beginning.</param> /// ------------------------------------------------------------------------------------ private void MergeContentWithPreviousSection(SelectionHelper helper, ScrBook book, IScrSection section, int ihvoSection, bool fPositionAtEnd) { //REVIEW: Can the methods that call this be refactored //to use (a refactored?) ScrSection.MergeWithPreviousSection? // // Get the previous section and move the paragraphs. IScrSection sectionPrev = book.SectionsOS[ihvoSection - 1]; IStText textPrev = sectionPrev.ContentOA; ILocationTracker tracker = ((ITeView)Control).LocationTracker; int iBook = tracker.GetBookIndex(helper, SelectionHelper.SelLimitType.Top); int cparaPrev = 0; if (textPrev == null) { // Prevent crash when dealing with corrupt database (TE-4869) // Since the previous section doesn't have a text, we simply move the entire text // object from the current section to the previous section. m_cache.ChangeOwner(section.ContentOAHvo, sectionPrev.Hvo, (int)ScrSection.ScrSectionTags.kflidContent); } else { cparaPrev = textPrev.ParagraphsOS.Count; IStText textOldContents = section.ContentOA; m_cache.MoveOwningSequence(textOldContents.Hvo, (int)StText.StTextTags.kflidParagraphs, 0, textOldContents.ParagraphsOS.Count - 1, textPrev.Hvo, (int)StText.StTextTags.kflidParagraphs, cparaPrev); } // protected for some reason...textPrev.ParagraphsOS.Append(text.ParagraphsOS.HvoArray); book.SectionsOS.RemoveAt(ihvoSection); // Now we have to re-establish a selection. Whatever happens, it will be in the // same book as before, and the previous section, and in the body. if (InSectionHead || !fPositionAtEnd) { tracker.SetBookAndSection(helper, SelectionHelper.SelLimitType.Top, iBook, ihvoSection - 1); helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[1].tag = (int)ScrSection.ScrSectionTags.kflidContent; } Debug.Assert(helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[1].tag == (int)ScrSection.ScrSectionTags.kflidContent); if (fPositionAtEnd) { // we want selection at end of last paragraph of old previous section. // (That is, at the end of paragraph cparaPrev - 1.) Debug.Assert(cparaPrev > 0); helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].ihvo = cparaPrev - 1; StTxtPara paraPrev = (StTxtPara)(textPrev.ParagraphsOS[cparaPrev - 1]); int cchParaPrev = paraPrev.Contents.Length; helper.IchAnchor = cchParaPrev; helper.IchEnd = cchParaPrev; helper.AssocPrev = true; } else { // want selection at start of old first paragraph of deleted section. // (That is, at the start of paragraph cparaPrev.) helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)[0].ihvo = cparaPrev; helper.IchAnchor = 0; helper.IchEnd = 0; helper.AssocPrev = false; } helper.SetLevelInfo(SelectionHelper.SelLimitType.Bottom, helper.GetLevelInfo(SelectionHelper.SelLimitType.Top)); helper.SetSelection(true); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Get the Hvo of the surviving paragraph. This will be either the paragraph before /// the selected paragraph if we have an IP or the paragraph at the top of a range /// selection. /// </summary> /// ------------------------------------------------------------------------------------ private int SurvivorParagraphHvo(SelectionHelper selHelper, IStText text, int ihvo, bool fMergeNext) { if (!selHelper.IsRange) { int iSurvivor = fMergeNext ? ihvo + 1 : ihvo - 1; return (iSurvivor >= 0 && iSurvivor < text.ParagraphsOS.Count ? text.ParagraphsOS.HvoArray[iSurvivor] : -1); } int paraLev = selHelper.GetLevelForTag((int)StText.StTextTags.kflidParagraphs, SelectionHelper.SelLimitType.Top); SelLevInfo[] rgSelLevInfo = selHelper.GetLevelInfo(SelectionHelper.SelLimitType.Top); return rgSelLevInfo[paraLev].hvo; }
protected override ICmObject GetCmObject(SelectionHelper sel, SelectionHelper.SelLimitType limit) { if (sel == null) return null; foreach (SelLevInfo level in sel.GetLevelInfo(limit)) { if (level.tag == MoAffixProcessTags.kflidInput || level.tag == PhSequenceContextTags.kflidMembers || level.tag == MoAffixProcessTags.kflidOutput) return m_cache.ServiceLocator.GetObject(level.hvo); } return null; }
/// ------------------------------------------------------------------------------------ /// <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> /// Replace the filter book tag with a scrpiture books tag. This is done before /// persisting the selection because the filter tag is not valid across sessions. /// Also, any filtered book indices are replaced with real scripture book indices /// for the same reason. /// </summary> /// <param name="helper"></param> /// <param name="selType"></param> /// ------------------------------------------------------------------------------------ private void ReplaceBookTagAndIndex(SelectionHelper helper, SelectionHelper.SelLimitType selType) { SelLevInfo[] info = helper.GetLevelInfo(selType); int bookPos = info.Length - 1; if (info[bookPos].tag == BookFilter.Tag) { info[bookPos].tag = ScriptureTags.kflidScriptureBooks; info[bookPos].ihvo = BookFilter.GetUnfilteredIndex(info[bookPos].ihvo); helper.SetLevelInfo(selType, info); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Makes changes in text structure when the context of the new paragraph style does not /// match the context of the current paragraph style, and applies the new paragraph style. /// </summary> /// <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> /// ------------------------------------------------------------------------------------ private void 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(ScrSectionTags.kflidContent); // Adjustments will only be done in section level selections. if (top.Length != scrLevelCount || bottom.Length != scrLevelCount) return; // 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 == ScrSectionTags.kflidHeading && newStyle.Structure == StructureValues.Body) { // These current indices will be adjusted after the structure is changed // to indicate where the new selection should be int iSection = tracker.GetSectionIndexInBook(selHelper, SelectionHelper.SelLimitType.Top); int iPara; int iBook = tracker.GetBookIndex(selHelper, SelectionHelper.SelLimitType.Top); IScrBook book = BookFilter.GetBook(iBook); IScrSection section = book[iSection]; // bool indicates if this section is the first one in either Intro or Scripture bool firstSectionInContext; if (iSection == 0) firstSectionInContext = true; else firstSectionInContext = !SectionsHaveSameContext(section, section.PreviousSection); // If all paragraphs of heading are selected, merge selected section // with previous section if (AreAllParagraphsSelected(top, bottom, section.HeadingOA)) { if (!firstSectionInContext) { iPara = book.MergeSectionIntoPreviousSectionContent(iSection, newStyle); 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, newStyle); } } // 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 = book.MoveHeadingParasToPreviousSectionContent(iSection, bottom[0].ihvo, newStyle); iSection--; } else { // This is the first section in context, and the selection includes the first para of the heading. // In this case, we want the selected paragraphs to become the content // of the first section, and the following section head // paragraph(s) become the heading of a new section object. section.SplitSectionHeading_ExistingParaBecomesContent(top[0].ihvo, bottom[0].ihvo, newStyle); // 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, newStyle); 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) to become the heading of a new section object. { int iParaStart = top[0].ihvo; int iParabottom = bottom[0].ihvo; section.SplitSectionHeading_ExistingParaBecomesContent(iParaStart, iParabottom, newStyle); iPara = 0; } } // Select the original range of paragraphs and characters, now in the new content para // TODO: FWR-1542 Currently, a selection made during a unit of work can only be an insertion point. SelectRangeOfChars(iBook, iSection, ScrSectionTags.kflidContent, iPara, selHelper.GetIch(SelectionHelper.SelLimitType.Top), selHelper.GetIch(SelectionHelper.SelLimitType.Top), true, true, selHelper.AssocPrev); } //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 and the paragraph(s) // is/are part of the section content. else if (top[1].tag == ScrSectionTags.kflidContent && newStyle.Structure == StructureValues.Heading) { IScrSection section = tracker.GetSection(selHelper, SelectionHelper.SelLimitType.Top); int iBook = tracker.GetBookIndex(selHelper, SelectionHelper.SelLimitType.Top); int iSection = tracker.GetSectionIndexInBook(selHelper, SelectionHelper.SelLimitType.Top); int iPara; IScrBook book = (IScrBook)section.Owner; // bool indicates if this section is the last one in either Intro or Scripture bool lastSectionInContext; if (iSection == book.SectionsOS.Count - 1) // last section ends book lastSectionInContext = true; else lastSectionInContext = !SectionsHaveSameContext(section, section.NextSection); try { 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 = book.MergeSectionIntoNextSectionHeading(iSection, newStyle); } 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, newStyle); } } else if (top[0].ihvo == 0) //selection starts at first content para { // Move the first content paragraphs to become the last para of the // section head section.MoveContentParasToHeading(bottom[0].ihvo, newStyle); iPara = section.HeadingOA.ParagraphsOS.Count - (bottom[0].ihvo - top[0].ihvo + 1); } else if (bottom[0].ihvo == section.ContentOA.ParagraphsOS.Count - 1 //selection ends at last content para && !lastSectionInContext) // this is not the last Intro or Scripture section { // Move the last content paragraphs to become the first para of the next // section in the book. book.MoveContentParasToNextSectionHeading(iSection, top[0].ihvo, newStyle); // update insertion point to first paragraph(s) of next section head iSection++; iPara = 0; } else { // Selection is of middle paragraph(s) in the contents, // or selection includes the last para of the last intro section or last Scripture section. // In this case, we want the selected paragraph to become the heading // of a new section, and the following paragraph(s), if any, become the // content of the new section object. section.SplitSectionContent_ExistingParaBecomesHeading( top[0].ihvo, bottom[0].ihvo - top[0].ihvo + 1, newStyle); // update insertion point to first paragraph(s) of next section head iSection++; iPara = 0; } } catch (InvalidStructureException e) { // Cancel the request if chapter or verse numbers are present. DisplayMessage(TeResourceHelper.GetResourceString("kstidParaHasNumbers")); return; } // Select the original range of paragraphs and characters, now in the new heading // TODO: FWR-1542 Currently, a selection made during a unit of work can only be an insertion point. SelectRangeOfChars(iBook, iSection, ScrSectionTags.kflidHeading, iPara, selHelper.GetIch(SelectionHelper.SelLimitType.Top), selHelper.GetIch(SelectionHelper.SelLimitType.Top), true, true, selHelper.AssocPrev); } return; }