You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Run.cs 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml.Linq;
  6. namespace Novacode
  7. {
  8. internal class Run
  9. {
  10. // A lookup for the text elements in this paragraph
  11. Dictionary<int, Text> textLookup = new Dictionary<int, Text>();
  12. private int startIndex;
  13. private int endIndex;
  14. private string text;
  15. internal XElement xml;
  16. /// <summary>
  17. /// Gets the start index of this Text (text length before this text)
  18. /// </summary>
  19. public int StartIndex { get { return startIndex; } }
  20. /// <summary>
  21. /// Gets the end index of this Text (text length before this text + this texts length)
  22. /// </summary>
  23. public int EndIndex { get { return endIndex; } }
  24. /// <summary>
  25. /// The text value of this text element
  26. /// </summary>
  27. private string Value { set { value = text; } get { return text; } }
  28. internal Run(int startIndex, XElement xml)
  29. {
  30. this.startIndex = startIndex;
  31. this.xml = xml;
  32. // Get the text elements in this run
  33. IEnumerable<XElement> texts = xml.Descendants();
  34. int start = startIndex;
  35. // Loop through each text in this run
  36. foreach (XElement te in texts)
  37. {
  38. switch (te.Name.LocalName)
  39. {
  40. case "tab":
  41. {
  42. textLookup.Add(start + 1, new Text(start, te));
  43. text += "\t";
  44. start++;
  45. break;
  46. }
  47. case "br":
  48. {
  49. textLookup.Add(start + 1, new Text(start, te));
  50. text += "\n";
  51. start++;
  52. break;
  53. }
  54. case "t": goto case "delText";
  55. case "delText":
  56. {
  57. // Only add strings which are not empty
  58. if (te.Value.Length > 0)
  59. {
  60. textLookup.Add(start + te.Value.Length, new Text(start, te));
  61. text += te.Value;
  62. start += te.Value.Length;
  63. }
  64. break;
  65. }
  66. default: break;
  67. }
  68. }
  69. endIndex = start;
  70. }
  71. static internal XElement[] SplitRun(Run r, int index)
  72. {
  73. Text t = r.GetFirstTextEffectedByEdit(index);
  74. XElement[] splitText = Text.SplitText(t, index);
  75. XElement splitLeft = new XElement(r.xml.Name, r.xml.Attributes(), r.xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]);
  76. if(Paragraph.GetElementTextLength(splitLeft) == 0)
  77. splitLeft = null;
  78. XElement splitRight = new XElement(r.xml.Name, r.xml.Attributes(), r.xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), splitText[1], t.xml.ElementsAfterSelf().Where(n => n.Name.LocalName != "rPr"));
  79. if(Paragraph.GetElementTextLength(splitRight) == 0)
  80. splitRight = null;
  81. return
  82. (
  83. new XElement[]
  84. {
  85. splitLeft,
  86. splitRight
  87. }
  88. );
  89. }
  90. internal Text GetFirstTextEffectedByEdit(int index)
  91. {
  92. foreach (int textEndIndex in textLookup.Keys)
  93. {
  94. if (textEndIndex > index)
  95. return textLookup[textEndIndex];
  96. }
  97. if (textLookup.Last().Value.EndIndex == index)
  98. return textLookup.Last().Value;
  99. throw new ArgumentOutOfRangeException();
  100. }
  101. }
  102. }