/// ------------------------------------------------------------------------------------ /// <summary> /// Verifies that the footnote marker was deleted from the specified back translation /// </summary> /// <param name="hvoPara">HVO of the paragraph that contains the footnote marker</param> /// <param name="guidFootnote">GUID of the deleted footnote</param> /// <param name="ws">The HVO of the back trans writing system to check</param> /// ------------------------------------------------------------------------------------ private void VerifyRemovedFootnoteMarker(int hvoPara, Guid guidFootnote, int ws) { StTxtPara para = new StTxtPara(Cache, hvoPara); ICmTranslation trans = para.GetBT(); if (trans == null) return; // no back translation exists to check ITsString tssBt = trans.Translation.GetAlternativeTss(ws); VerifyRemovedFootnoteMarker(guidFootnote, tssBt); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Removes the duplicate verse numbers in text. /// </summary> /// <param name="text">The text (either the remainder of the text following the /// paragraph where the insertion ocurred or in the next section)</param> /// <param name="iParaStart">The index of the para to start searching for dups.</param> /// <param name="inBackTrans">Indicates whether to search in back trans.</param> /// <param name="propTag">The flid (Contents or Translation)</param> /// <param name="wsAlt">The writing system, if a back trans multiString alt</param> /// <param name="chapterToRemove">The duplicate chapter number to remove.</param> /// <param name="removeUpToVerse">The last duplicate verse number to remove.</param> /// <returns><c>true</c> if all remaining duplicates have been removed; <c>false</c> /// if caller should re-call this method with the next section (or just give up) /// </returns> /// ------------------------------------------------------------------------------------ private bool RemoveDuplicateVerseNumbersInText(IStText text, int iParaStart, bool inBackTrans, int propTag, int wsAlt, int chapterToRemove, int removeUpToVerse) { ITsString tss; int[] paraHvos = text.ParagraphsOS.HvoArray; for (int iPara = iParaStart; iPara < paraHvos.Length; iPara++) { // Get hvo and tss for this para or translation StTxtPara para = new StTxtPara(m_cache, paraHvos[iPara]); int hvoObj = 0; if (inBackTrans) { ICmTranslation trans = para.GetBT(); if (trans == null) continue; hvoObj = trans.Hvo; tss = trans.Translation.GetAlternative(wsAlt).UnderlyingTsString; } else { hvoObj = para.Hvo; tss = para.Contents.UnderlyingTsString; } // Remove any duplicate verse number in this para or translation if (RemoveDuplicateVerseNumbersInPara(hvoObj, propTag, tss, wsAlt, chapterToRemove, removeUpToVerse, 0)) { return true; // removal is complete } } return false; // removal isn't complete }
/// ------------------------------------------------------------------------------------ /// <summary> /// Helper method: /// Verify the given copied paragraph, including footnotes and back translation, for /// any problems that the ChangeWatcher might cause. /// </summary> /// ------------------------------------------------------------------------------------ private void VerifyCopiedPara(StTxtPara newPara) { int btWs = Cache.DefaultAnalWs; // Check the paragraph BT // para must have only only 1 translation, the BT Assert.AreEqual(1, newPara.TranslationsOC.Count); ICmTranslation paraTrans = newPara.GetBT(); // BT alternate must have the original status Assert.AreEqual(BackTranslationStatus.Checked.ToString(), paraTrans.Status.GetAlternative(btWs)); // Check the footnote BT Assert.AreEqual(1, m_genesis.FootnotesOS.Count); StFootnote footnote = (StFootnote)m_genesis.FootnotesOS[0]; StTxtPara footnotePara = (StTxtPara)footnote.ParagraphsOS[0]; // footnote must have only only 1 translation, the BT Assert.AreEqual(1, footnotePara.TranslationsOC.Count); ICmTranslation footnoteTrans = footnotePara.GetBT(); // BT alternate must have the original status Assert.AreEqual(BackTranslationStatus.Finished.ToString(), footnoteTrans.Status.GetAlternative(btWs)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adjust the back translation of footnotes to reference the newly-created guid in the /// archive. /// </summary> /// <param name="origGuid">guid for footnote in original book</param> /// <param name="newGuid">guid for footnote in archive</param> /// <param name="para">paragraph (potentially containing a translation)</param> /// ------------------------------------------------------------------------------------ private void AdjustBtFootnoteInArchivedBook(Guid origGuid, Guid newGuid, StTxtPara para) { //TODO: TE- 5082 Duplicate code! Should call StTxtPara.UpdateOrcsInTranslations(), or common code ICmTranslation trans = para.GetBT(); if (trans != null) { // Check the back translation for each writing system. foreach (ILgWritingSystem ws in m_cache.LangProject.AnalysisWssRC) { ITsString btTss = trans.Translation.GetAlternative(ws.Hvo).UnderlyingTsString; if (btTss.RunCount > 0) { // Scan through runs searching for a reference guid with the original guid. int cRuns = btTss.RunCount; TsRunInfo tri; ITsTextProps ttp; for (int iRun = 0; iRun < cRuns; iRun++) { Guid guid = StringUtils.GetGuidFromRun(btTss, iRun, out tri, out ttp); if (guid != Guid.Empty && guid == origGuid) { // Guid mapping back to orignal draft found. Update it. byte[] objData; objData = MiscUtils.GetObjData(newGuid, (byte)FwObjDataTypes.kodtNameGuidHot); ITsPropsBldr propsBldr; propsBldr = ttp.GetBldr(); propsBldr.SetStrPropValueRgch( (int)FwTextPropType.ktptObjData, objData, objData.Length); ITsStrBldr btTssBldr = btTss.GetBldr(); btTssBldr.SetProperties(tri.ichMin, tri.ichLim, propsBldr.GetTextProps()); // Set the translation alt string to the new value // (but prevent side effects from ChangeWatchers) using (new IgnorePropChanged(m_cache, PropChangedHandling.SuppressChangeWatcher)) { trans.Translation.SetAlternative(btTssBldr.GetString(), ws.Hvo); } break; } } } } } }
public void ReplaceCurWithRev_ParaMissingInCurrent_WithBT() { // Build Current section (two paragraphs with verses 1, 3) IScrSection sectionCur = CreateSection(m_genesis, "My aching head!"); StTxtPara para1Curr = m_scrInMemoryCache.AddParaToMockedSectionContent(sectionCur.Hvo, ScrStyleNames.NormalParagraph); m_scrInMemoryCache.AddRunToMockedPara(para1Curr, "1", ScrStyleNames.VerseNumber); m_scrInMemoryCache.AddRunToMockedPara(para1Curr, "verse one", Cache.DefaultVernWs); StTxtPara para3Curr = m_scrInMemoryCache.AddParaToMockedSectionContent(sectionCur.Hvo, ScrStyleNames.NormalParagraph); m_scrInMemoryCache.AddRunToMockedPara(para3Curr, "3", ScrStyleNames.VerseNumber); m_scrInMemoryCache.AddRunToMockedPara(para3Curr, "verse three", Cache.DefaultVernWs); sectionCur.AdjustReferences(); // Build Revision section (three paragraphs - verses 1, 2, and 3) IScrSection sectionRev = CreateSection(m_genesisRevision, "My aching head!"); // this first para matches the current StTxtPara para1Rev = m_scrInMemoryCache.AddParaToMockedSectionContent(sectionRev.Hvo, ScrStyleNames.NormalParagraph); m_scrInMemoryCache.AddRunToMockedPara(para1Rev, "1", ScrStyleNames.VerseNumber); m_scrInMemoryCache.AddRunToMockedPara(para1Rev, "verse one", Cache.DefaultVernWs); // this second para is missing in the current StTxtPara para2Rev = m_scrInMemoryCache.AddParaToMockedSectionContent(sectionRev.Hvo, ScrStyleNames.NormalParagraph); m_scrInMemoryCache.AddRunToMockedPara(para2Rev, "2", ScrStyleNames.VerseNumber); m_scrInMemoryCache.AddRunToMockedPara(para2Rev, "verse two", Cache.DefaultVernWs); // this third para matches the current StTxtPara para3Rev = m_scrInMemoryCache.AddParaToMockedSectionContent(sectionRev.Hvo, ScrStyleNames.NormalParagraph); m_scrInMemoryCache.AddRunToMockedPara(para3Rev, "3", ScrStyleNames.VerseNumber); m_scrInMemoryCache.AddRunToMockedPara(para3Rev, "verse three", Cache.DefaultVernWs); // The second para includes a footnote StFootnote footnote2Rev = m_scrInMemoryCache.AddFootnote(m_genesisRevision, para2Rev, 1, "New footnote text"); // Add back translation to the second revision paragraph, and its status int btWs = Cache.DefaultAnalWs; ICmTranslation transPara2Rev = m_inMemoryCache.AddBtToMockedParagraph(para2Rev, btWs); m_inMemoryCache.AddRunToMockedTrans(transPara2Rev, btWs, "BT of verse two", null); transPara2Rev.Status.SetAlternative(BackTranslationStatus.Finished.ToString(), btWs); // Add back translation of footnote ICmTranslation transFootnote = m_scrInMemoryCache.AddFootnoteORCtoTrans(transPara2Rev, 2, btWs, footnote2Rev, "BT of footnote"); transFootnote.Status.SetAlternative(BackTranslationStatus.Checked.ToString(), btWs); sectionRev.AdjustReferences(); // Set up the Scripture ChangeWatcher ScriptureChangeWatcher.Create(Cache); // Detect differences m_bookMerger.DetectDifferences(null); // find the diffs for Genesis Assert.AreEqual(1, m_bookMerger.Differences.Count); // Get the first difference, verify it Difference diff = m_bookMerger.Differences.MoveFirst(); Assert.AreEqual(DifferenceType.ParagraphMissingInCurrent, diff.DiffType); Assert.AreEqual(01001002, diff.RefStart); //do a ReplaceCurrentWithRevision to simulate clicking the "revert to old" button m_bookMerger.ReplaceCurrentWithRevision(diff); // we expect this to insert the second para from the revision, and it's back translation // Confirm that the vernacular paragraph is restored correctly. Assert.AreEqual(3, sectionCur.ContentOA.ParagraphsOS.Count); StTxtPara para2Curr = new StTxtPara(Cache, sectionCur.ContentOA.ParagraphsOS[1].Hvo); Assert.AreEqual(ScrStyleNames.NormalParagraph, para2Curr.StyleRules.GetStrPropValue((int)FwTextStringProp.kstpNamedStyle)); Assert.AreEqual("2" + StringUtils.kchObject + "verse two", para2Curr.Contents.Text); ITsString tssNewParaContents = para2Curr.Contents.UnderlyingTsString; Assert.AreEqual(3, tssNewParaContents.RunCount); AssertEx.RunIsCorrect(tssNewParaContents, 0, "2", ScrStyleNames.VerseNumber, Cache.DefaultVernWs, true); // Run #1 is ORC for footnote, checked below... AssertEx.RunIsCorrect(tssNewParaContents, 2, "verse two", null, Cache.DefaultVernWs, true); StFootnote footnoteNew = (StFootnote)m_genesis.FootnotesOS.FirstItem; VerifyFootnote(footnoteNew, para2Curr, 1); // Confirm that the paragraph's back translation is restored correctly. ICmTranslation newPara2trans = para2Curr.GetBT(); Assert.IsNotNull(newPara2trans, "Second paragraph did not have translation restored from rev"); ITsString tssNewBtParaContents = newPara2trans.Translation.GetAlternativeTss(btWs); Assert.AreEqual("BT" + StringUtils.kchObject + " of verse two", tssNewBtParaContents.Text); Assert.AreEqual(3, tssNewBtParaContents.RunCount); AssertEx.RunIsCorrect(tssNewBtParaContents, 0, "BT", null, btWs); // Run #1 is ORC for footnote, checked below... AssertEx.RunIsCorrect(tssNewBtParaContents, 2, " of verse two", null, btWs); StTxtParaTests.VerifyBtFootnote(footnoteNew, para2Curr, btWs, 2); // BT alternate must have the original status Assert.AreEqual(BackTranslationStatus.Finished.ToString(), newPara2trans.Status.GetAlternative(btWs)); // Confirm that the footnote's back translation is restored correctly ICmTranslation newFootnoteTrans = ((StTxtPara)footnoteNew.ParagraphsOS[0]).GetBT(); Assert.IsNotNull(newFootnoteTrans, "Footnote paragraph did not have translation restored from rev"); Assert.AreEqual("BT of footnote", newFootnoteTrans.Translation.GetAlternativeTss(btWs).Text); // BT alternate must have the original status Assert.AreEqual(BackTranslationStatus.Checked.ToString(), newFootnoteTrans.Status.GetAlternative(btWs)); Assert.AreEqual(0, m_bookMerger.Differences.Count); // Recheck that Current is now identical to Revision m_bookMerger.DetectDifferences_ReCheck(); Assert.AreEqual(0, m_bookMerger.Differences.Count); }
public static void UpdateMainTransFromSegmented(StTxtPara para, int[] wss) { if (!para.IsValidObject()) return; // in merge, paragraph may be modified then deleted. FdoCache cache = para.Cache; BtConverter.EnsureMainParaSegments(para, wss[0]); ISilDataAccess sda = cache.MainCacheAccessor; List<int> segments = para.Segments; int kflidFT = StTxtPara.SegmentFreeTranslationFlid(cache); ITsString tssContents = para.Contents.UnderlyingTsString; IScripture scr = para.Cache.LangProject.TranslatedScriptureOA; ICmTranslation originalBT = para.GetBT(); // Can be null string sUnfinished = BackTranslationStatus.Unfinished.ToString(); foreach (int ws in wss) { ITsStrBldr bldr = TsStrBldrClass.Create(); bool wantNextSpace = false; // suppresses space before the first thing we add. bool haveBtText = false; // Text that isn't segment label text foreach (int hvoSeg in segments) { // If it's a label, insert it directly. Suppress following space. int beginOffset = sda.get_IntProp(hvoSeg, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginOffset); int endOffset = sda.get_IntProp(hvoSeg, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidEndOffset); ITsString tssFt; // Whether we want to insert a space before the current segment is determined by the previous one. // Save that value so we can set wantSpace appropriately for the following one. bool wantSpace = wantNextSpace; if (SegmentBreaker.HasLabelText(tssContents, beginOffset, endOffset)) { tssFt = (new CmBaseAnnotation(cache, hvoSeg)).TextAnnotated; tssFt = scr.ConvertCVNumbersInStringForBT(CorrectFootnotes(tssFt), ws); wantNextSpace = false; } else { int hvoFt = sda.get_ObjectProp(hvoSeg, kflidFT); tssFt = sda.get_MultiStringAlt(hvoFt, (int) CmAnnotation.CmAnnotationTags.kflidComment, ws); haveBtText |= (tssFt.Length > 0); wantNextSpace = EndsWithNonSpace(tssFt); } if (tssFt.Length > 0) { if (wantSpace) { // The preceding segment should typically be followed by a space. if (!StartsWithSpaceOrOrc(tssFt)) bldr.Replace(bldr.Length, bldr.Length, " ", null); } bldr.ReplaceTsString(bldr.Length, bldr.Length, tssFt); } } // If the back translation doesn't have text, we don't want to create verse // segment labels. This prevents the problem where the book thinks it has a // back translation because of automatically generated verse labels (TE-8283). if (!haveBtText) { // This check might not be needed, but it shouldn't hurt anything. if (originalBT != null) { if (originalBT.Translation.GetAlternative(ws).Length > 0) { string origStatus = originalBT.Status.GetAlternative(ws); if (!String.IsNullOrEmpty(origStatus) && origStatus != sUnfinished) originalBT.Status.SetAlternative(sUnfinished, ws); } } continue; } ITsString newFt = bldr.GetString(); ICmTranslation trans; if (newFt.Length == 0) { trans = para.GetBT(); if (trans == null) return; // don't bother creating one to store an empty translation! } else { trans = para.GetOrCreateBT(); } // Don't write unless it changed...PropChanged can be expensive. if (!trans.Translation.GetAlternative(ws).UnderlyingTsString.Equals(newFt)) { trans.Translation.SetAlternative(newFt, ws); trans.Status.SetAlternative(sUnfinished, ws); } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Helper method verifies that the copy was sufficiently "deep": /// copied paragraphs are different objects, and that owner and owned objects /// are different. /// </summary> /// <param name="srcPara">The para rev.</param> /// <param name="newPara">The new para.</param> /// ------------------------------------------------------------------------------------ private static void VerifyParagraphsAreDifferentObjects(StTxtPara srcPara, StTxtPara newPara) { Assert.AreNotEqual(srcPara.Hvo, newPara.Hvo); // owned by different StTexts Assert.AreNotEqual(srcPara.OwnerHVO, newPara.OwnerHVO); // owning different back translations Assert.AreNotEqual(srcPara.GetBT().Hvo, newPara.GetBT().Hvo); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Helper method: /// Verify the given copied paragraph, including footnotes and back translation, /// plus any other fields deemed necessary. /// </summary> /// ------------------------------------------------------------------------------------ private void VerifyCopiedPara(StTxtPara newPara) { // Verify the para StyleRules Assert.AreEqual("Line 1", newPara.StyleRules.GetStrPropValue((int)FwTextPropType.ktptNamedStyle)); // Verify the para Contents Assert.AreEqual("11This" + StringUtils.kchObject + " is" + StringUtils.kchObject + " the previous version of the text.", newPara.Contents.Text); ITsString tssNewParaContents = newPara.Contents.UnderlyingTsString; Assert.AreEqual(7, tssNewParaContents.RunCount); AssertEx.RunIsCorrect(tssNewParaContents, 0, "1", "CharacterStyle1", Cache.DefaultVernWs, true); AssertEx.RunIsCorrect(tssNewParaContents, 1, "1", "CharacterStyle2", Cache.DefaultVernWs, true); AssertEx.RunIsCorrect(tssNewParaContents, 2, "This", null, Cache.DefaultVernWs, true); // Run #3 is ORC for footnote, checked below... AssertEx.RunIsCorrect(tssNewParaContents, 4, " is", null, Cache.DefaultVernWs, true); // Run #5 is ORC for footnote, checked below... AssertEx.RunIsCorrect(tssNewParaContents, 6, " the previous version of the text.", null, Cache.DefaultVernWs, true); // note: At this point, having done the Copyxx() but not CreateOwnedObjects(), // the ORCs still refer to footnote objects owned by m_archivedText... StFootnote footnote1 = (StFootnote)m_archivedFootnotesOS.FirstItem; VerifyFootnote(footnote1, newPara, 6); Assert.AreEqual("Footnote1", ((StTxtPara)footnote1.ParagraphsOS[0]).Contents.Text); StFootnote footnote2 = (StFootnote)m_archivedFootnotesOS[1]; VerifyFootnote(footnote2, newPara, 10); Assert.AreEqual("Footnote2", ((StTxtPara)footnote2.ParagraphsOS[0]).Contents.Text); // ...thus the footnotes are not yet in m_currentFootnotesOS. Assert.AreEqual(0, m_currentFootnotesOS.Count); // Verify the para translations Assert.AreEqual(1, newPara.TranslationsOC.Count); //only 1 translation, the BT ICmTranslation paraTrans = newPara.GetBT(); // verify each alternate translation int[] wsBt = new int[] { InMemoryFdoCache.s_wsHvos.En, InMemoryFdoCache.s_wsHvos.De }; foreach (int ws in wsBt) { ITsString tssBtParaContents = paraTrans.Translation.GetAlternativeTss(ws); Assert.AreEqual("BT" + StringUtils.kchObject + " of" + StringUtils.kchObject + " test paragraph" + ws.ToString(), tssBtParaContents.Text); Assert.AreEqual(5, tssBtParaContents.RunCount); // could check every run too, but we'll skip that Assert.AreEqual(BackTranslationStatus.Finished.ToString(), paraTrans.Status.GetAlternative(ws)); } // Verify the footnote translations, their ORCs, and their status foreach (int ws in wsBt) { VerifyBtFootnote(footnote1, newPara, ws, 2); ICmTranslation footnoteTrans = ((StTxtPara)footnote1.ParagraphsOS[0]).GetBT(); Assert.AreEqual("BT of footnote1 " + ws.ToString(), footnoteTrans.Translation.GetAlternativeTss(ws).Text); Assert.AreEqual(BackTranslationStatus.Checked.ToString(), footnoteTrans.Status.GetAlternative(ws)); VerifyBtFootnote(footnote2, newPara, ws, 6); footnoteTrans = ((StTxtPara)footnote2.ParagraphsOS[0]).GetBT(); Assert.AreEqual("BT of footnote2 " + ws.ToString(), footnoteTrans.Translation.GetAlternativeTss(ws).Text); Assert.AreEqual(BackTranslationStatus.Finished.ToString(), footnoteTrans.Status.GetAlternative(ws)); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the text representation of the back translations for a footnote paragraph. /// </summary> /// <param name="footnotePara">The footnote paragraph.</param> /// <returns> /// text representation of all of the back translations for the footnote paragraph /// </returns> /// ------------------------------------------------------------------------------------ private string GetTextRepresentationOfTrans(StTxtPara footnotePara) { string transRepresentation = string.Empty; CmTranslation trans = (CmTranslation)footnotePara.GetBT(); if (trans == null) return transRepresentation; List<int> transWs = m_cache.GetUsedScriptureTransWsForPara(footnotePara.Hvo); foreach (int ws in transWs) { ITsString tss = trans.Translation.GetAlternativeTss(ws); if (tss != null && tss.Length > 0) { LgWritingSystem lgws = new LgWritingSystem(m_cache, ws); transRepresentation += "<TRANS WS='" + lgws.ICULocale + "'>"; transRepresentation += GetTextRepresentationOfTsString(tss); transRepresentation += "</TRANS>"; } } return transRepresentation; }