/// <summary> /// Make the necessary Free Translation annotation comments for the specified group /// of roughly matching segments. In general, we transfer corresponding material from /// the BT segment to the FT annotation of the main paragraph segment, with any left-over /// paragraph segments blank, and any left-over BT segments added to the end of the /// last FT segment. As a special case, if some FTs at the end of the list already have the /// exact text of corresponding BT ones (counting from the end of the lists), we assume that /// those pairs correspond, even if not in corresponding positions counting from the start, /// and don't change them. This helps preserve alignment when something may merge or split /// a segment in the base text after much of it is annotated. /// </summary> /// <param name="igroup"></param> private void MakeSegmentBtsForGroup(int igroup) { SegGroup group = m_segGroups[igroup]; // Discard any items at the end of both lists which already match exactly. Leave at least one in each group. DiscardMatchingSegsAtEnd(group); // The remaining (often all) segments are transferred one-for-one. (We don't need to check for // exactly matching ones at the start, because in that case, copying will be a no-op.) for (int iParaSeg = 0; iParaSeg < group.ParaSegs.Count; iParaSeg++) { // We may assume hvoFt is non-zero, because LoadSegmentFreeTranslations ensures every segment has one. var seg = group.ParaSegs[iParaSeg]; if (iParaSeg >= group.BtSegs.Count) { // no more Bt segments, make the annotation FT empty (in case set previously). // But don't overwrite if unchanged, since PropChanged can do a good deal of work // and sometimes destroy selections we want to preserve. if (seg.FreeTranslation.get_String(m_wsBt).Length != 0) { seg.FreeTranslation.set_String(m_wsBt, string.Empty); } continue; } ITsString tssFt = group.BtSegs[iParaSeg].String; tssFt = InsertOrphanBtFromPreviousGroup(igroup, iParaSeg, tssFt); tssFt = AppendLeftoverBtToLastSeg(group, iParaSeg, tssFt); // But don't overwrite if unchanged, since PropChanged can do a good deal of work // and sometimes destroy selections we want to preserve. if (!seg.FreeTranslation.get_String(m_wsBt).Equals(tssFt)) { seg.FreeTranslation.set_String(m_wsBt, tssFt); } } }
/// <summary> /// If this paragraph segment is the last one for its group, but there are left-over BT segments, /// append them to this. /// </summary> /// <param name="group"></param> /// <param name="iParaSeg"></param> /// <param name="tssFt"></param> /// <returns></returns> private ITsString AppendLeftoverBtToLastSeg(SegGroup group, int iParaSeg, ITsString tssFt) { if (iParaSeg == group.ParaSegs.Count - 1 && iParaSeg < group.BtSegs.Count - 1) { // We have left over translations. Append them. ITsStrBldr bldr = tssFt.GetBldr(); for (int j = iParaSeg + 1; j < group.BtSegs.Count; j++) { AppendWithOptionalSpace(bldr, group.BtSegs[j].String); } tssFt = bldr.GetString(); } return(tssFt); }
/// <summary> /// If this is the first segment in the group and NOT the first group, check for the possibility that /// there was no segment to attach the previous group's BTs to. I think this can only /// happen for the first group. Put the orphan BT at the start of this segment so it isn't lost. /// </summary> /// <param name="igroup"></param> /// <param name="iParaSeg"></param> /// <param name="tssFt"></param> /// <returns></returns> private ITsString InsertOrphanBtFromPreviousGroup(int igroup, int iParaSeg, ITsString tssFt) { if (iParaSeg == 0 && igroup > 0 && m_segGroups[igroup - 1].ParaSegs.Count == 0) { ITsStrBldr bldr = TsStrBldrClass.Create(); SegGroup prevGroup = m_segGroups[igroup - 1]; foreach (TsStringSegment seg in prevGroup.BtSegs) { AppendWithOptionalSpace(bldr, seg.String); } AppendWithOptionalSpace(bldr, tssFt); tssFt = bldr.GetString(); } return(tssFt); }
/// <summary> /// We have determined that corresponding groups start at iStartSegPara in m_paraSegs/m_segments and /// iStartSegBt in m_BtSegs. Make a SegGroup out of the corresponding segments and return the /// index of the indexes of the starts of the next group (in each case one more than the index of /// the matching verse segment which ended the group in the paragraph sequence). One or both indexes might /// be greater than the length of the corresponding array, indicating that the group extends to the end. /// One or both parts of the group might be empty. /// </summary> /// <returns>start index of next para segment (and next BT one in startOfNextBtSeg)</returns> int MakeGroup(int iStartSegPara, int iStartSegBt, out int startOfNextBtSeg) { SegGroup group = new SegGroup(); m_segGroups.Add(group); int iLimSegPara = iStartSegPara; startOfNextBtSeg = -1; for (; iLimSegPara < m_segments.Count; iLimSegPara++) { // The group also ends here if it is a CV-styled run and we can find a matching one in the BT. if (m_labelSegIndexes.Contains(iLimSegPara)) { var seg = m_segments[iLimSegPara]; ITsString targetT = ConvertedBtLabel(seg); startOfNextBtSeg = IndexOfMatchingVerseSegInBt(targetT, iStartSegBt); if (startOfNextBtSeg < 0) { // We failed to find a match at the location we expected, so just try search the whole BT startOfNextBtSeg = IndexOfMatchingVerseSegInBt(targetT, 0); } if (startOfNextBtSeg >= 0) { startOfNextBtSeg++; // actual contents starts AFTER the common label break; } } } // Make the group's ParaSegs be the non-label segments from the range we decided. var paraSegs = new List <ISegment>(iLimSegPara - iStartSegPara); for (int i = iStartSegPara; i < iLimSegPara; i++) { if (!m_labelSegIndexes.Contains(i)) { paraSegs.Add(m_segments[i]); } } group.ParaSegs = paraSegs; group.BtSegs = GetSegGroup(iStartSegBt); return(iLimSegPara + 1); }
// Discard any items at the end of both lists which already match exactly. Leave at least one in each group. private void DiscardMatchingSegsAtEnd(SegGroup group) { int ipara = group.ParaSegs.Count - 1; int itrans = group.BtSegs.Count - 1; while (ipara > 0 && itrans > 0) { // See if the existing FT matches string desiredFT = group.BtSegs[itrans].Text; var seg = group.ParaSegs[ipara]; string currentFT = seg.FreeTranslation.get_String(m_wsBt).Text; if (desiredFT != currentFT) { break; } // The two last items are already identical, don't need to do anything more about them. group.BtSegs.RemoveAt(itrans); group.ParaSegs.RemoveAt(ipara); itrans--; ipara--; } }
/// <summary> /// We have determined that corresponding groups start at iStartSegPara in m_paraSegs/m_segments and /// iStartSegBt in m_BtSegs. Make a SegGroup out of the corresponding segments and return the /// index of the indexes of the starts of the next group (in each case one more than the index of /// the matching verse segment which ended the group in the paragraph sequence). One or both indexes might /// be greater than the length of the corresponding array, indicating that the group extends to the end. /// One or both parts of the group might be empty. /// </summary> /// <returns>start index of next para segment (and next BT one in startOfNextBtSeg)</returns> int MakeGroup(int iStartSegPara, int iStartSegBt, out int startOfNextBtSeg) { SegGroup group = new SegGroup(); m_segGroups.Add(group); int iLimSegPara = iStartSegPara; startOfNextBtSeg = -1; for (; iLimSegPara < m_segments.Count; iLimSegPara++) { // The group also ends here if it is a CV-styled run and we can find a matching one in the BT. if (m_labelSegIndexes.Contains(iLimSegPara)) { var seg = m_segments[iLimSegPara]; ITsString targetT = ConvertedBtLabel(seg); startOfNextBtSeg = IndexOfMatchingVerseSegInBt(targetT, iStartSegBt); if (startOfNextBtSeg < 0) { // We failed to find a match at the location we expected, so just try search the whole BT startOfNextBtSeg = IndexOfMatchingVerseSegInBt(targetT, 0); } if (startOfNextBtSeg >= 0) { startOfNextBtSeg++; // actual contents starts AFTER the common label break; } } } // Make the group's ParaSegs be the non-label segments from the range we decided. var paraSegs = new List<ISegment>(iLimSegPara - iStartSegPara); for (int i = iStartSegPara; i < iLimSegPara; i++) { if (!m_labelSegIndexes.Contains(i)) paraSegs.Add(m_segments[i]); } group.ParaSegs = paraSegs; group.BtSegs = GetSegGroup(iStartSegBt); return iLimSegPara + 1; }
/// <summary> /// If this paragraph segment is the last one for its group, but there are left-over BT segments, /// append them to this. /// </summary> /// <param name="group"></param> /// <param name="iParaSeg"></param> /// <param name="tssFt"></param> /// <returns></returns> private ITsString AppendLeftoverBtToLastSeg(SegGroup group, int iParaSeg, ITsString tssFt) { if (iParaSeg == group.ParaSegs.Count - 1 && iParaSeg < group.BtSegs.Count - 1) { // We have left over translations. Append them. ITsStrBldr bldr = tssFt.GetBldr(); for (int j = iParaSeg + 1; j < group.BtSegs.Count; j++) AppendWithOptionalSpace(bldr, group.BtSegs[j].String); tssFt = bldr.GetString(); } return tssFt; }
// Discard any items at the end of both lists which already match exactly. Leave at least one in each group. private void DiscardMatchingSegsAtEnd(SegGroup group) { int ipara = group.ParaSegs.Count - 1; int itrans = group.BtSegs.Count - 1; while (ipara > 0 && itrans > 0) { // See if the existing FT matches string desiredFT = group.BtSegs[itrans].Text; var seg = group.ParaSegs[ipara]; string currentFT = seg.FreeTranslation.get_String(m_wsBt).Text; if (desiredFT != currentFT) break; // The two last items are already identical, don't need to do anything more about them. group.BtSegs.RemoveAt(itrans); group.ParaSegs.RemoveAt(ipara); itrans--; ipara--; } }