Ejemplo n.º 1
0
		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;
			}
		}
Ejemplo n.º 2
0
		/// <summary>
		/// Handles the PropChange for relevant paragraph changes in order to adjust annotations effected by the edit.
		/// </summary>
		/// <param name="hvo"></param>
		/// <param name="ivMin"></param>
		/// <param name="cvIns"></param>
		/// <param name="cvDel"></param>
		internal void AdjustTextAnnotationsForEdit(int hvo, int ivMin, int cvIns, int cvDel)
		{
			if (m_anchorTextInfo == null)
				return;
			StTxtPara para = new StTxtPara(m_cache, hvo);
			// First collect segment break information before before and after the edit was done.
			List<int> segBreakBeginOffsetsBeforeEdit;
			List<int> segBreakBeginOffsetsAfterEdit;
			// collection of dummy segment annotations for edited paragraph.
			List<TsStringSegment> segmentsAfterEdit;
			using (ParagraphParserForEditMonitoring ppfem = new ParagraphParserForEditMonitoring(para as IStTxtPara))
			{
				// collect segment break info for BEFORE the edit
				List<TsStringSegment> segmentsBeforeEdit = ppfem.CollectTempSegmentAnnotations(m_anchorTextInfo.ParaText,
					out segBreakBeginOffsetsBeforeEdit);
				// collect segment break info AFTER the edit.
				segmentsAfterEdit = ppfem.CollectTempSegmentAnnotations(para.Contents.UnderlyingTsString,
																	out segBreakBeginOffsetsAfterEdit);
				if (segmentsBeforeEdit.Count != segmentsAfterEdit.Count)
					m_fSegSeqChanged = true;
			}
			WordMaker wm = new WordMaker(para.Contents.UnderlyingTsString,
										 m_cache.LanguageWritingSystemFactoryAccessor);

			Set<int> cbasToDel = new Set<int>();
			int[] cbaHvosAffectedByEdit = GetCbasPotentiallyAffectedByTextEdit(hvo, ivMin);
			ICmBaseAnnotation segToMerge = null;
			foreach (
				ICmBaseAnnotation cba in
					new FdoObjectSet<ICmBaseAnnotation>(m_cache, cbaHvosAffectedByEdit, false, typeof (CmBaseAnnotation)))
			{
				if (m_annsToMoveFromDeletedParagraph.Contains(cba.Hvo) || m_movedAnnsFromAfterInsertBreak.Contains(cba.Hvo))
				{
					// make sure we don't adjust the offsets a second time.
					continue;
				}
				// 1.0) Determine any substantial changes for CmBaseAnnotations or CmIndirectAnnotations, including
				// whether or not an annotation needs to be deleted as a result of the edit.
				// NOTE: The assumption is that the annotations were in the "correct" state before the edit we're monitoring.
				// We are trying to enforce this state of affairs by ParseText in RawTextPane.SetRoot, but
				// since the annotations may have gotten out of sync before we started monitoring, it's possible
				// the parser would guess wrongly on how to adjust things. oh well, that's the best we can do for now.
				Debug.Assert(cba.EndOffset >= ivMin,
							 "expect to be handling only cbas that come at or after the beginning of an edit");

				// All our patching up is based on comparing the current text of the paragraph with the original paragraph.
				// Don't try to patch up any CBAs that are not currently associated with that paragraph, it just produces
				// crashs. These cases are relatively rare (typically multi-paragraph deletes), and the process of reparsing
				// the paragraphs will fix things pretty well.
				// It is not worth saving the text of the LAST paragraph selected before we start the edit,
				// because all the special code in this class is only intended to optimize matching things up
				// for single-line edits.
				if (cba.BeginObjectRAHvo != m_anchorTextInfo.HvoPara)
					continue;

				if (cba.AnnotationTypeRAHvo == m_hvoAnnDefnTwfic)
				{
					AnnotationAdjuster.HandleAnySubstantialTwficChange(cba, wm, ivMin, cvIns, cvDel, ref cbasToDel);
				}
				else if (cba.AnnotationTypeRAHvo == m_hvoSegDefn)
				{
					if (HandleAnySubstantialSegmentChange(cba, segBreakBeginOffsetsBeforeEdit, segBreakBeginOffsetsAfterEdit,
						segmentsAfterEdit, ivMin, cvIns, cvDel, ref cbasToDel, ref segToMerge))
					{
						continue; // skip default offset adjusting. it's already been handled.
					}
				}
				else if (cba.AnnotationTypeRAHvo == m_hvoPunctDefn)
				{
					AnnotationAdjuster.HandleAnySubstantialPunctuationChange(cba, wm, ivMin, cvIns, cvDel, ref cbasToDel);
				}
				else if (m_cache.IsValidObject(cba.Hvo, ScrScriptureNote.kClassId) &&
					ScrScriptureNote.GetAnnotationType(cba.AnnotationTypeRA) == NoteType.CheckingError)
				{
					// We don't want to adjust for checking error annotations. These will get
					// cleaned up later if the check is run again (TE-8051)
					continue;
				}

				// 2.0 Handle any remaining nonsubstantial offset changes (simply adjust remaining offsets)
				// calculate the total change in annotation offsets after ivMin
				if (!cbasToDel.Contains(cba.Hvo))
				{
					int cbaLengthOrig = cba.EndOffset - cba.BeginOffset;
					// special case: skip zerolengthed annotations at the beginning of the paragraph (e.g. ProcessTime)
					if (cba.BeginOffset == 0 && cba.EndOffset == 0)
						continue;
					AdjustOffsets(cba, cvIns, cvDel, ivMin, cba.AnnotationTypeRAHvo != m_hvoAnnDefnTwfic);
					if (cba.AnnotationTypeRAHvo == m_hvoAnnDefnTwfic && (cba.EndOffset - cba.BeginOffset) != cbaLengthOrig)
					{
						string msg = "We currently don't support changing the size of twfic.";
						Debug.Fail(msg);
						throw new ArgumentException(msg);
					}
				}
			}
			if (segToMerge != null)
			{
				// we didn't find an adjacent real segment to merge with, so
				// we need to adjust endoffset of segToMerge
				AdjustSegmentToNewSegmentBounds(segToMerge, segmentsAfterEdit);
				segToMerge = null;
			}

			// delete any cbas that are no longer valid.
			if (cbasToDel.Count > 0)
			{
				// TODO: possibly need to invalidate virtual properties (Segments/Segforms)?
				DeleteCalculatedAnnotations(cbasToDel);
			}
		}
Ejemplo n.º 3
0
		/// <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;
				}
			}
		}
Ejemplo n.º 4
0
		/// <summary>
		/// Scan the texts for pictures with captions.
		/// </summary>
		/// <param name="texts"></param>
		private void GetCaptionWfics(int[] texts, IWfiWordform wf)
		{
			int flidCaptions = DummyVirtualHandler.InstallDummyHandler(m_cache.VwCacheDaAccessor,
				"WfiWordform", "OccurrencesInCaptions",
				(int)CellarModuleDefns.kcptReferenceSequence).Tag;
			List<int> occurrencesInCaptions = new List<int>();
			string wordform = wf.Form.VernacularDefaultWritingSystem;
			if (string.IsNullOrEmpty(wordform))
				return; // paranoia.
			Set<FwObjDataTypes> desiredType = new Set<FwObjDataTypes>(1);
			desiredType.Add(FwObjDataTypes.kodtGuidMoveableObjDisp);
			int hvoAnnType = CmAnnotationDefn.Twfic(m_cache).Hvo;
			IVwCacheDa cda = m_cache.VwCacheDaAccessor;
			foreach (int hvoText in texts)
			{
				int chvoPara = m_cache.GetVectorSize(hvoText, kflidParagraphs);
				for (int ipara = 0; ipara < chvoPara; ipara++)
				{
					int hvoPara = m_cache.GetVectorItem(hvoText, kflidParagraphs, ipara);
					ITsString tssContents = m_cache.GetTsStringProperty(hvoPara, kflidContents);
					int crun = tssContents.RunCount;
					for (int irun = 0; irun < crun; irun++)
					{
						// See if the run is a picture ORC
						TsRunInfo tri;
						FwObjDataTypes odt;
						ITsTextProps props;
						Guid guid = StringUtils.GetGuidFromRun(tssContents, irun, out odt, out tri, out props, desiredType);
						if (guid == Guid.Empty)
							continue;
						// See if its caption contains our wordform
						int hvoPicture = m_cache.GetIdFromGuid(guid);
						int clsid = m_cache.GetClassOfObject(hvoPicture);
						if (clsid != (int)CmPicture.kclsidCmPicture)
							continue; // bizarre, just for defensiveness.
						ITsString tssCaption = m_cache.GetMultiStringAlt(hvoPicture,
							(int)CmPicture.CmPictureTags.kflidCaption, m_cache.DefaultVernWs);
						WordMaker wordMaker = new WordMaker(tssCaption, m_cache.LanguageWritingSystemFactoryAccessor);
						for (; ; )
						{
							int ichMin;
							int ichLim;
							ITsString tssTxtWord = wordMaker.NextWord(out ichMin, out ichLim);
							if (tssTxtWord == null)
								break;
							if (tssTxtWord.Text != wordform)
								continue;
							int hvoAnn = CmBaseAnnotation.CreateDummyAnnotation(m_cache, hvoPicture,
								hvoAnnType, ichMin, ichLim, wf.Hvo);
							cda.CacheIntProp(hvoAnn, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidFlid,
								(int)CmPicture.CmPictureTags.kflidCaption);
							cda.CacheObjProp(hvoAnn, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidWritingSystem,
								m_cache.DefaultVernWs);
							occurrencesInCaptions.Add(hvoAnn);
						}
					}
				}
			}
			// Make the list the value of the occurrencesInCaptions property.
			cda.CacheVecProp(wf.Hvo, flidCaptions, occurrencesInCaptions.ToArray(), occurrencesInCaptions.Count);
		}
Ejemplo n.º 5
0
		/// <summary>
		/// Executes in two distinct scenarios.
		///
		/// 1. If disposing is true, the method has been called directly
		/// or indirectly by a user's code via the Dispose method.
		/// Both managed and unmanaged resources can be disposed.
		///
		/// 2. If disposing is false, the method has been called by the
		/// runtime from inside the finalizer and you should not reference (access)
		/// other managed objects, as they already have been garbage collected.
		/// Only unmanaged resources can be disposed.
		/// </summary>
		/// <param name="disposing"></param>
		/// <remarks>
		/// If any exceptions are thrown, that is fine.
		/// If the method is being done in a finalizer, it will be ignored.
		/// If it is thrown by client code calling Dispose,
		/// it needs to be handled by fixing the bug.
		///
		/// If subclasses override this method, they should call the base implementation.
		/// </remarks>
		protected virtual void Dispose(bool disposing)
		{
			//Debug.WriteLineIf(!disposing, "****************** " + GetType().Name + " 'disposing' is false. ******************");
			// Must not be run more than once.
			if (m_isDisposed)
				return;

			if (disposing)
			{
				if (RebuildingConcordanceWordforms)
					RebuildingConcordanceWordforms = false;	// don't get rid of m_wfi until we do this.
			}
			// Bad idea to do this here, since one can't access C# objects in this context,
			// which is what the property will try to do.
			//if (RebuildingConcordanceWordforms)
			//	RebuildingConcordanceWordforms = false;	// don't get rid of m_wfi until we do this.
			m_cadTwfic = null;
			m_cadPunct = null;
			m_punctAnnotations = null;
			m_wordforms = null;
			m_wordformAnnotationPossibilities = null;
			m_paragraphTextScanner = null;
			m_paraRealAnnIds = null;
			m_paraRealWfIds = null;
			m_paraRealTwfics = null;
			m_unusedPunctuationAnnotations = null;
			m_unusedTwficAnnotations = null;
			m_unusedSegmentAnnotations = null;
			m_realParagraphSegmentAnnotations = null;
			m_realParagraphPunctuationAnnotations = null;
			m_realParagraphWordforms = null;
			m_realParagraphTwficAnnotations = null;
			m_annotations = null;
			m_paraIdsParsed = null;
			m_wfi = null;
			m_lp = null;
			m_wordMaker = null;
			m_tssPara = null;
			m_para = null;
			m_hvosStText = null;
			m_hvosStTxtPara = null;
			m_cache = null;

			m_isDisposed = true;
		}
Ejemplo n.º 6
0
		/// <summary>
		/// Returns the first word in the given tssWordAnn and its lower case form.
		/// </summary>
		/// <param name="tssWordAnn"></param>
		/// <param name="cpe"></param>
		/// <param name="firstFormLowered"></param>
		/// <returns>null if we couldn't find a word in the given tssWordAnn</returns>
		static private ITsString FirstWord(ITsString tssWordAnn, ILgWritingSystemFactory wsf, out string firstFormLowered)
		{
			WordMaker wordScanner = new WordMaker(tssWordAnn, wsf);
			int ichMinFirstWord;
			int ichLimFirstWord;
			ITsString firstWord = wordScanner.NextWord(out ichMinFirstWord, out ichLimFirstWord);
			// Handle null values without crashing.  See LT-6309 for how this can happen.
			if (firstWord != null)
				firstFormLowered = wordScanner.ToLower(firstWord);
			else
				firstFormLowered = null;
			return firstWord;
		}
Ejemplo n.º 7
0
		private void Setup(IStTxtPara para, IMatcher matcher, ConcordanceControl.ConcordanceLines line)
		{
			m_para = para;
			m_tssPara = para.Contents.UnderlyingTsString;
			m_paraWs = StringUtils.GetWsAtOffset(m_tssPara, 0);
			m_wordMaker = new WordMaker(m_tssPara, para.Cache.LanguageWritingSystemFactoryAccessor);
			m_paragraphTextScanner.Tss = m_tssPara;
			m_matcher = matcher;
			m_line = line;
		}
Ejemplo n.º 8
0
		private void Init(FdoCache cache)
		{
			m_cache = cache;
			kflidOccurrences = WfiWordform.OccurrencesFlid(m_cache);
			kflidConcordanceWordforms = WordformInventory.ConcordanceWordformsFlid(m_cache);
			m_lp = Cache.LangProject;
			m_paragraphTextScanner = new WordMaker(null, cache.LanguageWritingSystemFactoryAccessor);
			m_wfi = m_lp.WordformInventoryOA;
			// Identify the tag used for the virtual property that is the form of a punctuation
			// annotation.
			m_tagPunct = CmBaseAnnotation.StringValuePropId(m_cache);
			m_cadPunct = CmAnnotationDefn.Punctuation(m_cache);
			m_cadTwfic = CmAnnotationDefn.Twfic(m_cache);
			m_tagRealForm = InterlinVc.TwficRealFormTag(cache);
			m_tagLowercaseForm = InterlinVc.MatchingLowercaseWordForm(cache);
		}