Exemple #1
0
		internal static void MarkToRemove(ICmBaseAnnotation cbaToRemove, IList<ReusableCbaItem> reusableItems)
		{
			foreach (ReusableCbaItem item in reusableItems)
			{
				if (item == cbaToRemove)
				{
					item.MarkedToRemove = true;
					return;
				}
			}

		}
Exemple #2
0
		/// <summary>
		/// Given a segment which points into your paragraph, return the string that should correspond to it in the BT.
		/// </summary>
		/// <param name="seg"></param>
		/// <returns></returns>
		string ConvertedBtLabel(ICmBaseAnnotation seg)
		{
			ITsString tssResult = m_scr.ConvertCVNumbersInStringForBT((seg as CmBaseAnnotation).TextAnnotated, m_wsBt);
			if (tssResult == null)
				return null; // paranoia.
			return tssResult.Text;
		}
		ICmBaseAnnotation MakeWfic(StTxtPara para, ICmBaseAnnotation previous)
		{
			return MakeAnnotation(para, previous, CmAnnotationDefn.Twfic(Cache));
		}
		ICmBaseAnnotation MakeAnnotation(StTxtPara para, ICmBaseAnnotation previous, ICmAnnotationDefn type)
		{
			using (new UndoRedoTaskHelper(Cache, "ConstituentChartDatabaseTests - MakeAnnotation()", "ConstituentChartDatabaseTests - MakeAnnotation()"))
			{
				ICmBaseAnnotation result = (ICmBaseAnnotation)Cache.LangProject.AnnotationsOC.Add(new CmBaseAnnotation());
				result.BeginObjectRA = para;
				int prevOffset = 0;
				if (previous != null)
					prevOffset = previous.EndOffset;
				result.BeginOffset = prevOffset + 1;
				result.EndOffset = prevOffset + 2;
				result.AnnotationTypeRA = type;
				return result;
			}
		}
		/// <summary>
		///
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="segBreakBeginOffsetsBeforeEdit"></param>
		/// <param name="segBreakBeginOffsetsAfterEdit"></param>
		/// <param name="segmentsAfterEdit"></param>
		/// <param name="ichEditMin"></param>
		/// <param name="cvIns"></param>
		/// <param name="cvDel"></param>
		/// <param name="segsToDel"></param>
		/// <param name="segToMerge"> This starts as null on the first segment we handle. It is changed to cba (the current segment) when we
		/// handle the (one and only, if any) segment that has lost the trailing punctuation that separated it from the next segment.
		/// Subsequently, that segment continues as segToMerge until we come to one that is not completely deleted and so can merge with it.
		/// if we cant find a segment in the right place to merge it with, we set its end offset according to what was computed in segmentsAfterEdit.
		/// </param>
		/// <returns>true if we handled it (caller should make no further adjustments to this CBA)</returns>
		private bool HandleAnySubstantialSegmentChange(ICmBaseAnnotation cba,
			List<int> segBreakBeginOffsetsBeforeEdit, List<int> segBreakBeginOffsetsAfterEdit,
			List<TsStringSegment> segmentsAfterEdit, int ichEditMin, int cvIns, int cvDel, ref Set<int> segsToDel, ref ICmBaseAnnotation segToMerge)
		{
			// determine whether we deleted across a segment break character.
			int ichEditLim = ichEditMin + cvDel;
			int ichMinSegBreakBeforeEdit = AnnotationAdjuster.GetSegmentBreakInCbaRange(cba, segBreakBeginOffsetsBeforeEdit);
			// find the endpoint of the paragraph, since it may be the last segments endmarker.
			int ichLimParaBeforeEdit = m_anchorTextInfo.ParaText.Length;

			// If the edit range entirely contains the segment, clobber it. The following cases were originally designed
			// to handle this as a subcase, but don't do so adequately for verse number and similar segments that
			// don't actually have closing punctuation. Since this code is very tricky, it seemed safer to put in a
			// new case rather than try to patch up the old ones.
			if (cvDel > 0 && ichEditMin <= cba.BeginOffset && OnlyWhiteSpaceFollowsEditLimit(cba, ichEditLim, ichEditMin + cvIns))
			{
				AnnotationAdjuster.MarkCbaAndLinkedObjsForDeletion(cba, ref segsToDel);
				return true;
			}

			// 1.2) detect deletions that occur across segment annotations
			//	1.2.1) merge adjacent indirect annotations
			//		- TODO: mark indirect annotations as needing verification.
			//	1.2.2) delete first annotation
			if (segToMerge != null && ichEditLim <= ichMinSegBreakBeforeEdit)
			{
				// There's a previous segment to merge, and at least part of this one will survive
				// (the edit ended before its terminating punctuation). Typically we will merge the two.
				// The decisive thing is whether the re-segmenting of the paragraph requires one segment or
				// two. Since the beginning of segToMerge survived, and the end of this one, we should
				// typically find a new desired segment that matches.
				if (ThereIsAMatchingSegment(segmentsAfterEdit, segToMerge.BeginOffset, cba.EndOffset + cvIns - cvDel))
				//if (ichEditLim > cba.BeginOffset || cba.BeginOffset == segToMerge.EndOffset)
				{
					m_fSegSeqChanged = true;
					// They are (or have become by the deletion) adjacent; merge them.
					// get the Indirect Annotations for SegToMerge
					FdoObjectSet<ICmIndirectAnnotation> targetFreeformAnns = AnnotationAdjuster.GetFreeformAnnotations(segToMerge);
					FdoObjectSet<ICmIndirectAnnotation> srcFreeformAnns = AnnotationAdjuster.GetFreeformAnnotations(cba);
					// make a dictionary for type of freeform annotation to freeform annotation.
					Dictionary<int, List<ICmIndirectAnnotation>> targetTypeToAnn = AnnotationAdjuster.MakeAnnTypeToAnnDictionary(targetFreeformAnns);
					// foreach freeform annotation in the src, merge them into the (first) of same type of annotation on the target.
					// if it's not found on the target, then just move the AppliesToRC item the target.
					foreach (ICmIndirectAnnotation srcFreeformAnn in srcFreeformAnns)
					{
						List<ICmIndirectAnnotation> targetAnns;
						// Exception: don't merge note annotations, just move their instanceOf.
						if (srcFreeformAnn.AnnotationTypeRAHvo != m_segDefn_note &&
							targetTypeToAnn.TryGetValue(srcFreeformAnn.AnnotationTypeRAHvo, out targetAnns))
						{
							targetAnns[0].Comment.MergeAlternatives(srcFreeformAnn.Comment, true);
						}
						else
						{
							// it's a note or not found on the target, just move the AppliesToRC item to the target.
							srcFreeformAnn.AppliesToRS.Remove(cba.Hvo);
							srcFreeformAnn.AppliesToRS.Append(segToMerge.Hvo);
						}
					}
					// finished with the merge, so change the end offset and mark the merged cba for deletion.
					segToMerge.EndOffset = cba.EndOffset;
					AnnotationAdjuster.MarkCbaAndLinkedObjsForDeletion(cba, ref segsToDel);
					AdjustOffsets(segToMerge, cvIns, cvDel, ichEditMin, true);
				}
				else
				{
					// We didn't find an output segment to confirm that we want to merge these two,
					// so try to adjust them for reasonable survival. Eventually re-parsing the paragraph
					// will straighten things out somehow.
					AdjustSegmentToNewSegmentBounds(segToMerge, segmentsAfterEdit);
					// make sure we adjust the current cba.
					AdjustOffsets(cba, cvIns, cvDel, ichEditMin, true);
				}
				segToMerge = null;
				return true;
			}

			// We get here if either there's no previous segment needing merging, or if the edit extends beyond
			// our closing punctuation.
			if (cvDel > 0 && (ichEditLim > ichMinSegBreakBeforeEdit || ichEditLim == ichLimParaBeforeEdit))
			{
				// user deleted(and possibly inserted) across a segment boundary
				//  0123456789
				// "sample. sentence"
				// "sample!? sentence"
				m_fSegSeqChanged = true;
				if (ichEditMin <= cba.BeginOffset)
				{
					// (Case 1) the user deleted across the beginning of the sentence, in addition to the end
					// just delete the segment annotation.
					AnnotationAdjuster.MarkCbaAndLinkedObjsForDeletion(cba, ref segsToDel);
					return true;
				}
				// since the user didn't delete across the begin offset of this cba,
				// we can be fairly certain we can find a dummy segment corresponding to its begin offset.
				TsStringSegment closestSegAfterEdit;
				int ichMinSegBreakAfterEdit;
				AnnotationAdjuster.GetClosestSegmentInfoAfterEdit(cba, segBreakBeginOffsetsAfterEdit, segmentsAfterEdit, out closestSegAfterEdit, out ichMinSegBreakAfterEdit);
				if (ichMinSegBreakAfterEdit < 0)
				{
					// There is no following segment break...possibly we're deleting the final punctuation,
					// or inserted a paragraph break within this segment. Since there is no following segment,
					// this one should extend to the end of the paragraph.
					cba.EndOffset = ((cba.BeginObjectRA) as StTxtPara).Contents.Length;
					return true;
				}
				if ((ichEditMin + cvIns) > ichMinSegBreakAfterEdit)
				{
					// (Case 2) The user inserted a new segment break within this segment,
					// So adjust the end offset accordingly. (Dont merge with subsequent annotation.)

					// Example 1 - simple replacement of segment break char.
					// 0123456789012345678901234567890
					//			 >!<
					// segment one. seg two.
					// segment one! seg two.
					// (ichEditMin(11) + cvIns(1)) > ichMinSegBreakAfterEdit(11)

					// Example 2 - deletion includes twfics but insertion has a seg break char.
					// 0123456789012345678901234567890
					//   > three. -----<
					// segment one. seg two.
					// seg three. two.
					// (ichEditMin(3) + cvIns(8)) > ichMinSegBreakAfterEdit(9)
					AnnotationAdjuster.AdjustSegmentToNewSegmentBounds(cba, closestSegAfterEdit);
				}
				else
				{
					// (Case 3) The user just deleted the segment break marker, merging it with an existing segment.
					//	Rationale:
					//      since we are inside the branch for deleting the old segment boundary (ie. ichEditLim > ichMinSegBreakBeforeEdit)
					//		and the selection deletion didn't delete the whole segment (Case 1)
					//		and the user didn't insert a new segment break character (Case 2)
					//		So the user must have just deleted the segment marker so that it extends into an existing segment.
					segToMerge = cba;
				}
				return true;
			}

			// we didn't delete the old segment boundary, but we still may need to adjust our offsets.
			if (cvIns > 0 && ichEditMin >= cba.BeginOffset && ichEditMin <= cba.EndOffset)
			{
				// There was an insertion in the segment, and there was no deletion (or it didn't delete our segment break character)
				// Adjust the end offset accordingly.
				TsStringSegment closestSegAfterEdit;
				int ichMinSegBreakAfterEdit;
				AnnotationAdjuster.GetClosestSegmentInfoAfterEdit(cba, segBreakBeginOffsetsAfterEdit, segmentsAfterEdit, out closestSegAfterEdit, out ichMinSegBreakAfterEdit);

				// Handle the special case of a complete segment (e.g., a verse number, or pasting a sentence) right before this segment.
				if (cba.BeginOffset == ichEditMin && closestSegAfterEdit != null
					&& closestSegAfterEdit.EndOffset == cba.BeginOffset + cvIns - cvDel)
				{
					// We were about to change this segment's offsets to point at the newly inserted segment!
					// Instead, just adjust it as a segment that follows the edit.
					AdjustOffsets(cba, cvIns, cvDel, ichEditMin, false);
					return true;
				}

				// TODO: Special case: if the user inserted at the beginning of the sentence.
				// just move the whole segment, and depend upon the parser to adjust the rest when
				// the user switches to Interlinear.
				// The impact upon current tests is too drastic
				//if (ichEditMin == cba.BeginOffset)
				//{
				//    AdjustOffsets(cba, cvIns, cvDel, ichEditMin, false);
				//    return true;
				//}
				AnnotationAdjuster.AdjustSegmentToNewSegmentBounds(cba, closestSegAfterEdit);
				return true;
			}
			// otherwise, we expect the change can be handled by the caller in AdjustOffsets.
			// probably just an insertion or deletion contained within the segment.
			return false;
		}
		/// <summary>
		/// given a real cbaToAdjust, adjust its offsets to the closest matching dummy segment
		/// in a list of segsAfterEdit.
		/// </summary>
		/// <param name="cbaToAdjust"></param>
		/// <param name="segsAfterEdit"></param>
		private void AdjustSegmentToNewSegmentBounds(ICmBaseAnnotation cbaToAdjust, List<TsStringSegment> segsAfterEdit)
		{
			TsStringSegment newSeg = AnnotationAdjuster.GetClosestSegment(cbaToAdjust, segsAfterEdit);
			AnnotationAdjuster.AdjustSegmentToNewSegmentBounds(cbaToAdjust, newSeg);
		}
		private static void AdjustSegmentToNewSegmentBounds(ICmBaseAnnotation cbaToAdjust, TsStringSegment newSeg)
		{
			if (newSeg == null)
				return; // or Assert.Fail? should not happen, but be defensive.
			if (cbaToAdjust.BeginOffset != newSeg.BeginOffset)
				cbaToAdjust.BeginOffset = newSeg.BeginOffset;
			if (cbaToAdjust.EndOffset != newSeg.EndOffset)
				cbaToAdjust.EndOffset = newSeg.EndOffset;
		}
		/// <summary>
		/// given the bounds of cba, return the offset of the first character of the first segment break.
		/// If none was found, we return the EndOffset of the given cba.
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="ichMinSegBreaksInPara"></param>
		/// <returns> the ichMin of the segment break marker falling within the offsets of cba.
		/// -1 if cba is null, but will return cba.EndOffset if it couldn't find a segment break in the cba range.</returns>
		private static int GetSegmentBreakInCbaRange(ICmBaseAnnotation cba, List<int> ichMinSegBreaksInPara)
		{
			if (cba == null)
				return -1;
			int ichMin = cba.BeginOffset;
			int ichLim = cba.EndOffset;
			return GetSegmentBreakInRange(ichMin, ichLim, ichMinSegBreaksInPara);
		}
Exemple #9
0
		/// <summary>
		///
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="ichMin"></param>
		/// <param name="tssWordAnn"></param>
		protected void AdjustCbaFields(ICmBaseAnnotation cba, int ichMin, ITsString tssWordAnn)
		{
			AdjustCbaFields(cba, ichMin, ichMin + tssWordAnn.Length);
		}
Exemple #10
0
		/// <summary>
		/// Returns the tss of the given annotation.
		/// </summary>
		/// <param name="cba">a paragraph annotation.</param>
		/// <returns></returns>
		static public ITsString TssSubstring(ICmBaseAnnotation cba)
		{
			IStTxtPara paragraph = cba.BeginObjectRA as IStTxtPara;
			Debug.Assert(paragraph != null, String.Format("We expect cba{0} to be a paragraph annotation.", cba.Hvo));
			if (paragraph == null)
				return null;
			FdoCache cache = cba.Cache;
			return cache.MainCacheAccessor.get_StringProp(cba.Hvo, CmBaseAnnotation.StringValuePropId(cache));
		}
Exemple #11
0
		private void GetAdjacentWficInfo(int hvoStartingAnnotation, out int hvoSeg, out int iSegForm, out ICmBaseAnnotation currentAnnotation, out ICmBaseAnnotation nextAnnotation, out int hvoOldWordform1, out int hvoOldWordform2)
		{
			TwficInfo twficInfo = new TwficInfo(Cache, hvoStartingAnnotation);
			hvoSeg = twficInfo.SegmentHvo;
			iSegForm = twficInfo.SegmentFormIndex;
			List<int> segForms = this.SegmentForms(hvoSeg);
			if (iSegForm < 0 || iSegForm + 1 >= segForms.Count)
				throw new ArgumentException(String.Format("Can't find adjacent annotation to merge with {0}.", hvoStartingAnnotation));
			int hvoNextAnnotation = segForms[iSegForm + 1];
			currentAnnotation = CmBaseAnnotation.CreateFromDBObject(Cache, hvoStartingAnnotation, false) as CmBaseAnnotation;
			nextAnnotation = CmBaseAnnotation.CreateFromDBObject(Cache, hvoNextAnnotation, false) as CmBaseAnnotation;
			int twficType = CmAnnotationDefn.Twfic(Cache).Hvo;
			if (currentAnnotation.AnnotationTypeRAHvo != twficType ||
				nextAnnotation.AnnotationTypeRAHvo != twficType)
			{
				throw new ArgumentException(String.Format("Can only support merging annotations of twfic type{0}.\nAnnotation({1}).Type({2}) Annotation({3}).Type({4})",
						twficType, currentAnnotation.Hvo, currentAnnotation.AnnotationTypeRAHvo, nextAnnotation.Hvo, nextAnnotation.AnnotationTypeRAHvo));
			}
			hvoOldWordform1 = WfiWordform.GetWfiWordformFromInstanceOf(Cache, currentAnnotation.Hvo);
			hvoOldWordform2 = WfiWordform.GetWfiWordformFromInstanceOf(Cache, nextAnnotation.Hvo);
		}
Exemple #12
0
		/// <summary>
		/// given a wfic annotation, return information about the current wfic and the adjacent wfic
		/// </summary>
		/// <param name="hvoWfic"></param>
		/// <param name="nextWfic"></param>
		/// <param name="hvoOldWordform1">the wordform of the given wfic</param>
		/// <param name="hvoOldWordform2">the wordform of the adjacent wfic</param>
		public void GetAdjacentWficInfo(int hvoWfic, out ICmBaseAnnotation nextWfic, out int hvoOldWordform1, out int hvoOldWordform2)
		{
			int hvoSeg = 0;
			int iSegForm = 0;
			ICmBaseAnnotation currentWfic = null;
			GetAdjacentWficInfo(hvoWfic, out hvoSeg, out iSegForm, out currentWfic, out nextWfic, out hvoOldWordform1, out hvoOldWordform2);
		}
			protected virtual void CompareCbaInstanceOf(string context, ICmBaseAnnotation expectedCba, ICmBaseAnnotation actualCba, string msg)
			{
				// we expect these analyses to be identical.
				Assert.AreEqual(expectedCba.InstanceOfRAHvo, actualCba.InstanceOfRAHvo,
				   String.Format(msg, "InstanceOf", context));
			}
Exemple #14
0
		protected void CreateTestData()
		{
			// Create required virtual properties
			XmlDocument doc = new XmlDocument();
			// Subset of Flex virtuals required for parsing paragraphs etc.
			doc.LoadXml(
			"<virtuals>"
				+"<virtual modelclass=\"StTxtPara\" virtualfield=\"Segments\">"
				+"<dynamicloaderinfo assemblyPath=\"ITextDll.dll\" class=\"SIL.FieldWorks.IText.ParagraphSegmentsVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"OccurrencesInTexts\" destinationClass=\"CmBaseAnnotation\">"
				+"<dynamicloaderinfo assemblyPath=\"ITextDll.dll\" class=\"SIL.FieldWorks.IText.OccurrencesInTextsVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"HumanApprovedAnalyses\" computeeverytime=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.FDOSequencePropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"HumanNoOpinionParses\" computeeverytime=\"true\" requiresRealParserGeneratedData=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.FDOSequencePropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"HumanDisapprovedParses\" computeeverytime=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.FDOSequencePropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"FullConcordanceCount\" depends=\"OccurrencesInTexts\" computeeverytime=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.IntegerPropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"UserCount\" bulkLoadMethod=\"LoadAllUserCounts\" computeeverytime=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.IntegerPropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"ParserCount\" bulkLoadMethod=\"LoadAllParserCounts\" computeeverytime=\"true\" requiresRealParserGeneratedData=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.IntegerPropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WfiWordform\" virtualfield=\"ConflictCount\" computeeverytime=\"true\" requiresRealParserGeneratedData=\"true\">"
				+"<dynamicloaderinfo assemblyPath=\"FDO.dll\" class=\"SIL.FieldWorks.FDO.IntegerPropertyVirtualHandler\"/>"
				+"</virtual>"
				+"<virtual modelclass=\"WordformInventory\" virtualfield=\"ConcordanceWords\" destinationClass=\"WfiWordform\">"
				+"<dynamicloaderinfo assemblyPath=\"ITextDll.dll\" class=\"SIL.FieldWorks.IText.ConcordanceWordsVirtualHandler\"/>"
				+"</virtual>"
			+"</virtuals>");
			BaseVirtualHandler.InstallVirtuals(doc.DocumentElement, Cache);

			m_text = new Text();
			Cache.LangProject.TextsOC.Add(m_text);
			string para1 = "Axx simplexx testxx withxx axx lotxx ofxx wordsxx endingxx inxx xx";
			string para2 = "axx sentencexx axx havingxx axx lotxx ofxx axx";
			m_para1 = new StTxtPara();
			m_stText = new StText();
			m_text.ContentsOA = m_stText;
			m_para1 = MakePara(para1);
			m_para2 = MakePara(para2);
			m_wfAxx = WfiWordform.CreateFromDBObject(Cache,
				WfiWordform.FindOrCreateWordform(Cache, "axx", Cache.DefaultVernWs, true));
			// Make one real annotation, which also serves to link the Axx to this.
			m_cbaAxx = CmBaseAnnotation.CreateUnownedCba(Cache);
			m_cbaAxx.InstanceOfRA = m_wfAxx;
			m_cbaAxx.BeginObjectRA = m_para1;
			m_cbaAxx.BeginOffset = 0;
			m_cbaAxx.EndOffset = 3;
			m_cbaAxx.Flid = (int)StTxtPara.StTxtParaTags.kflidContents;
			m_cbaAxx.AnnotationTypeRA = CmAnnotationDefn.Twfic(Cache);

			// Make another real annotation, which should get updated during Apply.
			IWfiWordform wf2 = WfiWordform.CreateFromDBObject(Cache,
				WfiWordform.FindOrCreateWordform(Cache, "lotxx", Cache.DefaultVernWs, true));
			m_cba2 = CmBaseAnnotation.CreateUnownedCba(Cache);
			m_cba2.InstanceOfRA = wf2;
			m_cba2.BeginObjectRA = m_para2;
			m_cba2.BeginOffset = "axx sentencexx axx havingxx axx ".Length;
			m_cba2.EndOffset = m_cba2.BeginOffset + "lotxx".Length;
			m_cba2.AnnotationTypeRA = CmAnnotationDefn.Twfic(Cache);
			m_cba2.Flid = (int)StTxtPara.StTxtParaTags.kflidContents;

			ParagraphParser.ConcordTexts(Cache, new int[] { m_stText.Hvo }, new NullProgressState());
			m_axxOccurrences = m_wfAxx.ConcordanceIds;
			m_para1Occurrences = OccurrencesInPara(m_para1.Hvo, m_axxOccurrences);
			m_para2Occurrences = OccurrencesInPara(m_para2.Hvo, m_axxOccurrences);

			// to improve test isolation, be sure to null things not always initialized.
			m_wfaAxe = m_wfaCut = m_wfaCutIt = m_wfaNotRude = null;
			m_cAnalyses = 0;
		}
Exemple #15
0
		private bool IsLabelSeg(ICmBaseAnnotation seg)
		{
			return SegmentBreaker.HasLabelText(m_para.Contents.UnderlyingTsString, seg.BeginOffset, seg.EndOffset);
		}
		/// <summary>
		///
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="segBreakBeginOffsetsAfterEdit"></param>
		/// <param name="segmentsAfterEdit"></param>
		/// <param name="closestSegAfterEdit">the dummy segment corresponding to cba in a list of dummy segments marking the bounds after the edit.</param>
		/// <param name="ichMinSegBreakAfterEdit">the ichMin of the segment break marker falling within the offsets of cba.
		/// -1 if cba is null, but will return cba.EndOffset if it couldn't find a segment break in the cba range.</param>
		private static void GetClosestSegmentInfoAfterEdit(ICmBaseAnnotation cba, List<int> segBreakBeginOffsetsAfterEdit, List<TsStringSegment> segmentsAfterEdit, out TsStringSegment closestSegAfterEdit, out int ichMinSegBreakAfterEdit)
		{
			closestSegAfterEdit = GetClosestSegment(cba, segmentsAfterEdit);
			ichMinSegBreakAfterEdit = GetSegmentBreakInCbaRange(closestSegAfterEdit, segBreakBeginOffsetsAfterEdit);
		}
		private static FdoObjectSet<ICmIndirectAnnotation> GetFreeformAnnotations(ICmBaseAnnotation cba)
		{
			List<int> freeformAnnHvos = new List<int>();
			foreach (LinkedObjectInfo loi in cba.LinkedObjects)
			{
				if (loi.RelObjClass == CmIndirectAnnotation.kClassId)
				{
					freeformAnnHvos.Add(loi.RelObjId);
				}
			}
			FdoObjectSet<ICmIndirectAnnotation> freeformAnns = new FdoObjectSet<ICmIndirectAnnotation>(cba.Cache,
																									   freeformAnnHvos.ToArray(), false, typeof(CmIndirectAnnotation));
			return freeformAnns;
		}
Exemple #18
0
		/// <summary>
		///
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="ichMin"></param>
		/// <param name="ichLim"></param>
		protected virtual void AdjustCbaFields(ICmBaseAnnotation cba, int ichMin, int ichLim)
		{
			SegmentServices.SetCbaFields(cba, m_para, ichMin, ichLim);
		}
		/// <summary>
		/// given cbaOrig, find the corresponding dummy segment in a list of dummy segments marking the bounds after the edit.
		/// </summary>
		/// <param name="cbaOrig"></param>
		/// <param name="segsAfterEdit">list of dummy segments marking bounds of segments after edit. we assume this is in order.</param>
		/// <returns>the dummy segment nearest to cbaOrig</returns>
		private static TsStringSegment GetClosestSegment(ICmBaseAnnotation cbaOrig, List<TsStringSegment> segsAfterEdit)
		{
			FdoCache cache = cbaOrig.Cache;
			int ichMin = cbaOrig.BeginOffset;
			foreach (TsStringSegment seg in segsAfterEdit)
			{
				// we stop after we find a segment that equals or is greater than cbaOrig's offset.
				// (this assumes segsAfterEdit list is in order.)
				if (seg.BeginOffset >= ichMin)
					return seg;
			}
			return null;
		}
Exemple #20
0
		internal ReusableCbaItem(ICmBaseAnnotation cba)
		{
			Item = cba;
		}
		private static void HandleAnySubstantialPunctuationChange(ICmBaseAnnotation cba, WordMaker wm, int ichEditMin, int cvIns, int cvDel,
																  ref Set<int> punctsToDel)
		{
			int ichEditLim = ichEditMin + cvDel;
			// 1.2) detect deletions that occur across segment annotations
			//	1.2.1) merge adjacent indirect annotations
			//		- TODO: mark indirect annotations as needing verification.
			//	1.2.2) delete first annotation
			if (cvDel > 0 && ichEditMin <= cba.BeginOffset && ichEditLim >= cba.EndOffset)
			{
				// user deleted entire punctuation cba
				//  0123456789
				// "sample. sentence"
				// "sample sentence"
				punctsToDel.Add(cba.Hvo);
				return;
			}
			else if (cvIns > 0 && ichEditMin >= cba.BeginOffset)
			{
				// user inserted something inside the punctuation
				punctsToDel.Add(cba.Hvo);
				return;
			}
		}
Exemple #22
0
		/// <summary>
		///
		/// </summary>
		/// <param name="reusableCbaItems"></param>
		/// <param name="ichMin">begin offset in actual text</param>
		/// <param name="ichLim">end offset in actual text</param>
		/// <param name="cbaFirstUnused">the first unused cba, whether or not we could reuse it.</param>
		/// <returns>true if we reused it.</returns>
		internal bool TryReuseFirstUnusedCbaMatchingText(IList<ReusableCbaItem> reusableCbaItems, int ichMin, int ichLim,
														  out ICmBaseAnnotation cbaFirstUnused)
		{
			cbaFirstUnused = null;
			ReusableCbaItem unusedCbaItem = UnusedCbaItems(reusableCbaItems).FirstOrDefault();
			if (unusedCbaItem != null)
			{
				ICmBaseAnnotation unusedCba = unusedCbaItem.Item;
				if (unusedCba.BeginOffset == ichMin && unusedCba.EndOffset == ichLim)
				{
					cbaFirstUnused = unusedCba;
					unusedCbaItem.Reuse();
					return true;
				}
			}
			return false;
		}
		/// <summary>
		/// Handle the general case for adjusting the offsets of an annotation based on the
		/// position of the edit and the number of chars inserted and deleted.
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="cvIns"></param>
		/// <param name="cvDel"></param>
		/// <param name="ichBeginEdit"></param>
		/// <param name="fGrowAtBounds">if false, treat the insertion at the boundary as exterior rather than
		/// changing the character count between BeginOffset and EndOffset</param>
		void AdjustOffsets(ICmBaseAnnotation cba, int cvIns, int cvDel, int ichBeginEdit, bool fGrowAtBounds)
		{
			if (m_annsToMoveFromDeletedParagraph.Contains(cba.Hvo) || m_movedAnnsFromAfterInsertBreak.Contains(cba.Hvo))
			{
				// make sure we don't adjust the offsets a second time.
				return;
			}
			int ichEndEdit = ichBeginEdit + cvDel;
			if (ichBeginEdit > cba.EndOffset)
				return;	// no change in offsets needed.
			if (ichBeginEdit <= cba.BeginOffset && ichEndEdit >= cba.EndOffset)
			{
				int hvoType = cba.AnnotationTypeRAHvo;
				if (hvoType == m_hvoAnnDefnTwfic || hvoType == m_hvoPunctDefn || hvoType == m_hvoSegDefn)
					throw new ArgumentException("this cba has been replaced by the edit. can't adjust its offsets");
				// Some other kind of annotation which we don't attempt to delete earlier, for example,
				// a TE check annotation (see TE-7747). The best we can do is make it an empty annotation
				// at the place where the contents were deleted.
				cba.BeginOffset = cba.EndOffset = ichBeginEdit;
				return;
			}
			// the cba needs to change in size, if the edit began within the cba
			int ichMinNew = cba.BeginOffset;
			int ichLimNew = cba.EndOffset;
			// if the entire edit occurred at/before our begin offset, shift both offsets the same amount
			if (ichEndEdit <= cba.BeginOffset && !(fGrowAtBounds && (cvDel == 0 && ichBeginEdit == cba.BeginOffset)))
			{
				// 0123456
				// abc def
				// ----def
				// def
				ichMinNew += (cvIns - cvDel);
				ichLimNew += (cvIns - cvDel);
			}
			else
			{
				// edit occurred within the cba, so change its size
				// 0123456
				// abc def
				// ab---ef
				// abef
				if (ichBeginEdit >= cba.BeginOffset)
				{
					if (ichBeginEdit == cba.EndOffset && !fGrowAtBounds)
					{
						// don't try to change this cba size, if the edit starts at its end offset
					}
					else if (ichEndEdit > cba.EndOffset)
					{
						// the end of the edit crosses the bounds of the cba
						// so we need to truncate the adjustment by its end offset.
						ichLimNew += (cvIns - (cba.EndOffset - ichBeginEdit));
					}
					else
					{
						// edit is contained within the cba
						ichLimNew += (cvIns - cvDel);
					}
				}
				else if (ichEndEdit > cba.BeginOffset)
				{
					// if the end of the edit occurs within the cba
					// then we need to truncate the adjustment by its begin offset.
					// the end of the edit and the begin offset.
					ichMinNew += (cvIns - cvDel + ichEndEdit - cba.BeginOffset);
					ichLimNew += (cvIns - cvDel);
				}
			}
			int max = ((cba.BeginObjectRA) as StTxtPara).Contents.Length;
			// Make sure we don't do anything totally unreasonable in cases we didn't anticipate.
			if (ichMinNew < 0 || ichLimNew > max || ichLimNew < ichMinNew)
				return;
			// Review: would this be better?
			//ichMinNew = Math.Min(Math.Max(ichMinNew, 0), max);
			//ichLimNew = Math.Min(Math.Max(ichLimNew, 0), max);
			//if (ichLimNew < ichMinNew)
			//    ichLimNew = ichMinNew;
			CmBaseAnnotation.SetCbaFields(cba.Cache, cba.Hvo, ichMinNew, ichLimNew, cba.BeginObjectRAHvo, false);
		}
Exemple #24
0
		/// <summary>
		///
		/// </summary>
		/// <param name="reusableCbas"></param>
		/// <param name="ichMin"></param>
		/// <param name="ichLim"></param>
		/// <param name="cbaUsed"></param>
		/// <returns></returns>
		internal virtual bool TryReuseFirstUnusedAnnotation(IList<ReusableCbaItem> reusableCbas, int ichMin, int ichLim, out ICmBaseAnnotation cbaUsed)
		{
			cbaUsed = null;
			// see if we can reuse an annotation from the current paragraph.
			ReusableCbaItem rci = UnusedCbaItems(reusableCbas).FirstOrDefault();
			if (rci != null)
			{
				rci.Reuse();
				cbaUsed = rci.Item;
			}
			return cbaUsed != null;
		}
		// We want to be able to test whether all the significant text in cba has been deleted. However,
		// label segments (verse numbers, footnotes, and the like) include following white space.
		// This routine is called only when we know that the start of the range deleted is at or
		// before CBA. ichEditLimOld is the end of the edit (in the original string); if cba ends
		// before that, it is certainly deleted. However, if it ends after that, but all the rest of it
		// is white space, also answer true.
		// That involves testing characters in the NEW version of the paragraph, so we are passed the
		// position in the new contents that corresponds to ichEditLimOld in the old.
		private bool OnlyWhiteSpaceFollowsEditLimit(ICmBaseAnnotation cba, int ichEditLimOld, int ichEditLimNew)
		{
			if (ichEditLimOld >= cba.EndOffset)
				return true;
			StTxtPara para = cba.BeginObjectRA as StTxtPara;
			if (para == null)
				return false; // paranoia
			string contents = para.Contents.Text;
			if (contents == null)
				return false; // paranoia.
			int len = cba.EndOffset - ichEditLimOld; // To succeed, this many characters (or all) must be white.
			for (int i = ichEditLimNew; i < ichEditLimNew + len && i < contents.Length; i++)
				if (!Char.IsWhiteSpace(contents[i]))
					return false;
			return true;
		}
		/// <summary>
		/// find and delete affected real twfics (let the paragraph parser recompute virtual twfics?)
		/// 1.1) deletions & insertions that occur within or across twfic annotations.
		///	1.1.1) delete affected twfic(s)
		/// 1.1.2) adjust offsets
		/// </summary>
		/// <param name="cba"></param>
		/// <param name="wm"></param>
		/// <param name="ichEditMin">the beginning offset of the selection used for editing.</param>
		/// <param name="cvIns"></param>
		/// <param name="cvDel"></param>
		/// <param name="twficsToDel"></param>
		private static void HandleAnySubstantialTwficChange(ICmBaseAnnotation cba, WordMaker wm, int ichEditMin, int cvIns, int cvDel, ref Set<int> twficsToDel)
		{
			int ichEditLim = ichEditMin + cvDel;

			// Determine whether this could possibly be a substantial change in a twfic
			if (ichEditMin < cba.EndOffset && ichEditLim > cba.BeginOffset)
			{
				// the selection used to edit the text overlaps this twfic.
				//  0123456789
				// "sample sentence"
				// "sample ???tence"
				MarkCbaAndLinkedObjsForDeletion(cba, ref twficsToDel);
				return;
			}
			else if (cvIns > 0 && ichEditMin > cba.BeginOffset && ichEditMin < cba.EndOffset)
			{
				// user changed or broke up this twfic
				//  0123456789
				// "sample sentence"
				// "sample sen?tence"
				MarkCbaAndLinkedObjsForDeletion(cba, ref twficsToDel);
				return;
			}
			else if (cvIns > 0 && ichEditMin == cba.BeginOffset)
			{
				// user has prepended characters.
				// delete twfic if insertion ends with a wordforming character.
				//  0123456789
				// "sample sentence"
				// "sample ?sentence"

				// make sure the last character before this twfic
				// is a wordforming (non-whitespace) character before
				// we consider it to warrant deleting the twfic.
				if (wm.IsWordforming(ichEditMin + cvIns - 1))
				{
					MarkCbaAndLinkedObjsForDeletion(cba, ref twficsToDel);
					return;
				}
			}
			else if (cvIns > 0 && ichEditMin == cba.EndOffset)
			{
				// user has appended characters.
				// if it begins with a wordbreaking character, don't delete the twfic
				//  0123456789
				// "sample sentence"
				// "sample?xx sentence"

				// make sure the character after this twfic
				// is a wordforming (non-whitespace) character before
				// we consider it to warrant deleting the twfic.
				if (wm.IsWordforming(ichEditMin))
				{
					MarkCbaAndLinkedObjsForDeletion(cba, ref twficsToDel);
					return;
				}
			}
		}
		List<int> MakeNWfics(StTxtPara para, ICmBaseAnnotation previous, int n)
		{
			ICmBaseAnnotation current = previous;
			List<int> result = new List<int>(n);
			for (int i = 0; i < n; i++)
			{
				current = MakeWfic(para, current);
				result.Add(current.Hvo);
			}
			return result;
		}
		private static void MarkCbaAndLinkedObjsForDeletion(ICmBaseAnnotation cba, ref Set<int> cbasToDel)
		{
			(cba as CmBaseAnnotation).CollectLinkedItemsForDeletion(ref cbasToDel, true);
		}
Exemple #29
0
		private int AssignMissingAnnotationWritingSystem(ICmBaseAnnotation cba)
		{
			return CmBaseAnnotation.GetAnnotationWritingSystem(m_cache, cba.BeginObjectRAHvo,
				cba.BeginOffset, cba.Flid);
		}
Exemple #30
0
		/// <summary>
		/// Get the segments of the paragraph.  This is public static to allow others to use
		/// the same code.  This will actually parse the text of the paragraph, create any
		/// segments that do not yet exist, and create any needed free translation annotations
		/// to go with them.  It also sets the kflidSegments (virtual) property of the paragraph,
		/// and the kflidFT (virtual) property of the segments.
		/// </summary>
		/// <returns>array of ICmBaseAnnotation objects for the segments</returns>
		public static ICmBaseAnnotation[] GetMainParaSegments(IStTxtPara para, int wsBt, out int[] paraSegs)
		{
			FdoCache cache = EnsureMainParaSegments(para, wsBt);
			int kflidSegments = StTxtPara.SegmentsFlid(cache);
			paraSegs = cache.GetVectorProperty(para.Hvo, kflidSegments, true);
			ICmBaseAnnotation[] segments = new ICmBaseAnnotation[paraSegs.Length];
			for (int i = 0; i < paraSegs.Length; i++)
			{
				// This prevents trying to really load it from the database, which is typically not
				// useful and actully causes failures of some tests when using a memory cache that considers all
				// objects to be non-dummies.
				cache.VwCacheDaAccessor.CacheIntProp(paraSegs[i], (int)CmObjectFields.kflidCmObject_Class,
					(int)CmBaseAnnotation.kclsidCmBaseAnnotation);
				segments[i] = new CmBaseAnnotation(cache, paraSegs[i]);
			}
			return segments;
		}