/// <summary> /// Replaces the specified range of characters with the specified string. /// This method is only used by Views. /// </summary> public void ReplaceRgch(int ichMin, int ichLim, string rgchIns, int cchIns, ITsTextProps ttp) { ThrowIfCharOffsetOutOfRange("ichMin", ichMin, ichLim); ThrowIfCharOffsetOutOfRange("ichLim", ichLim, Length); ThrowIfCharOffsetOutOfRange("cchIns", cchIns, rgchIns == null ? 0 : rgchIns.Length); // Don't do anything if there is nothing to insert or delete and we are not empty. if (cchIns == 0 && ichMin == ichLim && Length > 0) { return; } TsTextProps textProps; if (ttp == null) { // If ichMin equals ichLim, use the previous characters properties. int charIndex = ichMin == ichLim && ichMin > 0 ? ichMin - 1 : ichMin; textProps = m_runs[get_RunAt(charIndex)].TextProps; } else { textProps = ttp as TsTextProps; if (textProps == null && ttp != null) { // if it came from C++, could be wrapped in a way that prevents a simple cast. textProps = ((TsPropsFactory)TsStringUtils.TsPropsFactory).FromITsTextProps(ttp); } } TsRun run = new TsRun(cchIns, textProps); ReplaceInternal(ichMin, ichLim, rgchIns == null ? string.Empty : rgchIns.Substring(0, cchIns), new[] { run }); }
/// <summary> /// Sets the text properties for the specified range of characters. /// </summary> public void SetProperties(int ichMin, int ichLim, ITsTextProps ttp) { ThrowIfCharOffsetOutOfRange("ichMin", ichMin, ichLim); ThrowIfCharOffsetOutOfRange("ichLim", ichLim, Length); ThrowIfParamNull("ttp", ttp); var textProps = ttp as TsTextProps; if (textProps == null) { // if it came from C++, could be wrapped in a way that prevents a simple cast. textProps = ((TsPropsFactory)TsStringUtils.TsPropsFactory).FromITsTextProps(ttp); } if (ichMin == ichLim) { if (Length == 0) { m_runs[0] = new TsRun(0, textProps); } return; } int minRunIndex = get_RunAt(ichMin); int limRunIndex = get_RunAt(ichLim); TsRun run = new TsRun(ichLim - ichMin, textProps); SetPropertiesInternal(ichMin, ichLim, minRunIndex, limRunIndex, 0, new[] { run }); }
private void ReplaceInternal(int ichMin, int ichLim, string insertText, IList <TsRun> insertRuns) { // This is the only case where we can end up with an empty run. if (insertText.Length == 0) { // If we're deleting everything and we were passed a run, use it. if (ichMin == 0 && ichLim == Length) { m_text.Clear(); // If we were given some run properties, let them become those of the empty string. TsTextProps props = insertRuns.Count > 0 ? insertRuns[0].TextProps : m_runs[0].TextProps; m_runs.Clear(); m_runs.Add(new TsRun(0, props)); return; } // We're not deleting everything, therefore any run we were passed describes // no characters and should be ignored. if (insertRuns.Count > 0) { insertRuns = new TsRun[0]; } } int minRunIndex = get_RunAt(ichMin); int limRunIndex = get_RunAt(ichLim); m_text.Remove(ichMin, ichLim - ichMin); m_text.Insert(ichMin, insertText); // dich is the amount that indices >= ichLim should be adjusted by after the replace. int dich = insertText.Length - ichLim + ichMin; SetPropertiesInternal(ichMin, ichLim, minRunIndex, limRunIndex, dich, insertRuns); }
/// <summary> /// Gets the substring for the specified range returned as an <see cref="ITsString"/>. /// </summary> public ITsString GetSubstring(int ichMin, int ichLim) { ThrowIfCharOffsetOutOfRange("ichMin", ichMin, ichLim); ThrowIfCharOffsetOutOfRange("ichLim", ichLim, Length); if (ichMin == 0 && ichLim == Length) { return(this); } string newText = GetChars(ichMin, ichLim); var newRuns = new List <TsRun>(); int irun = get_RunAt(ichMin); for (int i = irun; i < m_runs.Length; i++) { TsRun run = m_runs[i]; bool lastRun = ichLim <= run.IchLim; newRuns.Add(new TsRun((lastRun ? ichLim : run.IchLim) - ichMin, run.TextProps)); if (lastRun) { break; } } return(new TsString(newText, newRuns.ToArray())); }
/// <summary> /// Replaces the specified range of characters with the specified string. /// This method is only used by Views. /// </summary> public void ReplaceRgch(int ichMin, int ichLim, string rgchIns, int cchIns, ITsTextProps ttp) { ThrowIfCharOffsetOutOfRange("ichMin", ichMin, ichLim); ThrowIfCharOffsetOutOfRange("ichLim", ichLim, Length); ThrowIfCharOffsetOutOfRange("cchIns", cchIns, rgchIns == null ? 0 : rgchIns.Length); // Don't do anything if there is nothing to insert or delete and we are not empty. if (cchIns == 0 && ichMin == ichLim && Length > 0) { return; } TsTextProps textProps; if (ttp == null) { // If ichMin equals ichLim, use the previous characters properties. int charIndex = ichMin == ichLim && ichMin > 0 ? ichMin - 1 : ichMin; textProps = m_runs[get_RunAt(charIndex)].TextProps; } else { textProps = (TsTextProps)ttp; } TsRun run = new TsRun(cchIns, textProps); ReplaceInternal(ichMin, ichLim, rgchIns == null ? string.Empty : rgchIns.Substring(0, cchIns), new[] { run }); }
/// <summary> /// Fetches the information for the specified run. /// </summary> public ITsTextProps FetchRunInfo(int irun, out TsRunInfo tri) { ThrowIfRunIndexOutOfRange("irun", irun); TsRun run = Runs[irun]; tri = new TsRunInfo { ichMin = GetRunIchMin(irun), ichLim = run.IchLim, irun = irun }; return(run.TextProps); }
/// <summary> /// Appends the specified string to end of the current text. /// </summary> public void Append(string bstrIns) { if (string.IsNullOrEmpty(bstrIns)) { return; } m_text.Append(bstrIns); var newRun = new TsRun(m_text.Length, (TsTextProps)m_propsBldr.GetTextProps()); if (m_runs.Count > 0 && m_runs[m_runs.Count - 1].TextProps.Equals(newRun.TextProps)) { m_runs[m_runs.Count - 1] = newRun; } else { m_runs.Add(newRun); } }
private void SetPropertyValue(int ichMin, int ichLim, Func <TsTextProps, TsTextProps> editTextPropsFunc) { if (ichMin == ichLim) { if (Length == 0) { m_runs[0] = new TsRun(0, editTextPropsFunc(m_runs[0].TextProps)); } return; } int minRunIndex = get_RunAt(ichMin); if (GetRunIchMin(minRunIndex) < ichMin) { m_runs.Insert(minRunIndex, new TsRun(ichMin, m_runs[minRunIndex].TextProps)); minRunIndex++; } int limRunIndex = get_RunAt(ichLim - 1); if (ichLim < m_runs[limRunIndex].IchLim) { m_runs.Insert(limRunIndex, new TsRun(ichLim, m_runs[limRunIndex].TextProps)); } for (int i = limRunIndex; i >= minRunIndex; i--) { m_runs[i] = new TsRun(m_runs[i].IchLim, editTextPropsFunc(m_runs[i].TextProps)); if (i < m_runs.Count - 1 && m_runs[i].TextProps.Equals(m_runs[i + 1].TextProps)) { m_runs.RemoveAt(i); } } if (minRunIndex > 0 && m_runs[minRunIndex].TextProps.Equals(m_runs[minRunIndex - 1].TextProps)) { m_runs.RemoveAt(minRunIndex - 1); } }
/// <summary> /// Sets the text properties for the specified range of characters. /// </summary> public void SetProperties(int ichMin, int ichLim, ITsTextProps ttp) { ThrowIfCharOffsetOutOfRange("ichMin", ichMin, ichLim); ThrowIfCharOffsetOutOfRange("ichLim", ichLim, Length); ThrowIfParamNull("ttp", ttp); var textProps = (TsTextProps)ttp; if (ichMin == ichLim) { if (Length == 0) { m_runs[0] = new TsRun(0, textProps); } return; } int minRunIndex = get_RunAt(ichMin); int limRunIndex = get_RunAt(ichLim); TsRun run = new TsRun(ichLim - ichMin, textProps); SetPropertiesInternal(ichMin, ichLim, minRunIndex, limRunIndex, 0, new[] { run }); }
private void SetPropertiesInternal(int ichMin, int ichLim, int minRunIndex, int limRunIndex, int dich, IList <TsRun> insertRuns) { // Ensure ichMin is on a run boundary. if (ichMin > GetRunIchMin(minRunIndex)) { // Insertion is within a single run. if (minRunIndex == limRunIndex) { // Split the run. m_runs.Insert(minRunIndex, new TsRun(ichMin, m_runs[limRunIndex].TextProps)); limRunIndex++; } else { // Adjust the boundary, even when not splitting. m_runs[minRunIndex] = new TsRun(ichMin, m_runs[minRunIndex].TextProps); } minRunIndex++; } m_runs.RemoveRange(minRunIndex, limRunIndex - minRunIndex); m_runs.InsertRange(minRunIndex, insertRuns); limRunIndex = minRunIndex + insertRuns.Count; if (ichMin > 0) { for (int i = minRunIndex; i < limRunIndex; i++) { m_runs[i] = new TsRun(m_runs[i].IchLim + ichMin, m_runs[i].TextProps); } } if (dich != 0) { for (int i = limRunIndex; i < m_runs.Count; i++) { m_runs[i] = new TsRun(m_runs[i].IchLim + dich, m_runs[i].TextProps); } } // See if we can combine on the left. if (minRunIndex > 0) { if (m_runs[minRunIndex].TextProps.Equals(m_runs[minRunIndex - 1].TextProps)) { m_runs.RemoveAt(minRunIndex - 1); limRunIndex--; } } // See if we can combine on the right. if (limRunIndex > 0) { // Empty right run, delete. if (m_runs[limRunIndex].IchLim == m_runs[limRunIndex - 1].IchLim) { m_runs.RemoveAt(limRunIndex); } else if (m_runs[limRunIndex - 1].TextProps.Equals(m_runs[limRunIndex].TextProps)) { m_runs.RemoveAt(limRunIndex - 1); // limRunIndex is no longer valid after the above delete. } } }