/// <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++) { int hvoFt = m_cache.GetObjProperty(group.ParaSegs[iParaSeg], kflidFT); // We may assume hvoFt is non-zero, because LoadSegmentFreeTranslations ensures every segment has one. CmIndirectAnnotation ft = CmObject.CreateFromDBObject(m_cache, hvoFt) as CmIndirectAnnotation; 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 (ft.Comment.GetAlternative(m_wsBt).Length != 0) { ft.Comment.SetAlternative("", m_wsBt); } continue; } ITsString tssFt = group.BtSegs[iParaSeg].Text; 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 (!ft.Comment.GetAlternativeTss(m_wsBt).Equals(tssFt)) { ft.Comment.SetAlternative(tssFt, m_wsBt); } } }
/// <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++) { ITsString tssApp = group.BtSegs[j].Text; AppendWithOptionalSpace(bldr, tssApp); } 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]; for (int j = 0; j < prevGroup.BtSegs.Count; j++) { AppendWithOptionalSpace(bldr, prevGroup.BtSegs[j].Text); } AppendWithOptionalSpace(bldr, tssFt); 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.Text; int hvoFt = m_cache.GetObjProperty(group.ParaSegs[ipara], kflidFT); CmIndirectAnnotation ft = CmObject.CreateFromDBObject(m_cache, hvoFt) as CmIndirectAnnotation; string currentFT = ft.Comment.GetAlternative(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_paraSegs.Length; 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)) { ICmBaseAnnotation seg = m_segments[iLimSegPara]; string targetT = ConvertedBtLabel(seg); startOfNextBtSeg = IndexOfMatchingVerseInBt(targetT); 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. List <int> paraSegs = new List <int>(iLimSegPara - iStartSegPara); for (int i = iStartSegPara; i < iLimSegPara; i++) { if (!m_labelSegIndexes.Contains(i)) { paraSegs.Add(m_paraSegs[i]); } } group.ParaSegs = paraSegs; group.BtSegs = GetSegGroup(iStartSegBt); return(iLimSegPara + 1); }
/// <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_paraSegs.Length; 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)) { ICmBaseAnnotation seg = m_segments[iLimSegPara]; string targetT = ConvertedBtLabel(seg); startOfNextBtSeg = IndexOfMatchingVerseInBt(targetT); 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. List<int> paraSegs = new List<int>(iLimSegPara - iStartSegPara); for (int i = iStartSegPara; i < iLimSegPara; i++) { if (!m_labelSegIndexes.Contains(i)) paraSegs.Add(m_paraSegs[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++) { ITsString tssApp = group.BtSegs[j].Text; AppendWithOptionalSpace(bldr, tssApp); } 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.Text; int hvoFt = m_cache.GetObjProperty(group.ParaSegs[ipara], kflidFT); CmIndirectAnnotation ft = CmObject.CreateFromDBObject(m_cache, hvoFt) as CmIndirectAnnotation; string currentFT = ft.Comment.GetAlternative(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--; } }