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.

Formatting.cs 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. using System;
  2. using System.Linq;
  3. using System.Xml.Linq;
  4. using System.Drawing;
  5. using System.Globalization;
  6. namespace Novacode
  7. {
  8. /// <summary>
  9. /// A text formatting.
  10. /// </summary>
  11. public class Formatting : IComparable
  12. {
  13. private XElement rPr;
  14. private bool? hidden;
  15. private bool? bold;
  16. private bool? italic;
  17. private StrikeThrough? strikethrough;
  18. private Script? script;
  19. private Highlight? highlight;
  20. private double? size;
  21. private Color? fontColor;
  22. private Color? underlineColor;
  23. private UnderlineStyle? underlineStyle;
  24. private Misc? misc;
  25. private CapsStyle? capsStyle;
  26. private Font fontFamily;
  27. private int? percentageScale;
  28. private int? kerning;
  29. private int? position;
  30. private double? spacing;
  31. private CultureInfo language;
  32. /// <summary>
  33. /// A text formatting.
  34. /// </summary>
  35. public Formatting()
  36. {
  37. capsStyle = Novacode.CapsStyle.none;
  38. strikethrough = Novacode.StrikeThrough.none;
  39. script = Novacode.Script.none;
  40. highlight = Novacode.Highlight.none;
  41. underlineStyle = Novacode.UnderlineStyle.none;
  42. misc = Novacode.Misc.none;
  43. // Use current culture by default
  44. language = CultureInfo.CurrentCulture;
  45. rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName));
  46. }
  47. /// <summary>
  48. /// Text language
  49. /// </summary>
  50. public CultureInfo Language
  51. {
  52. get
  53. {
  54. return language;
  55. }
  56. set
  57. {
  58. language = value;
  59. }
  60. }
  61. /// <summary>
  62. /// Returns a new identical instance of Formatting.
  63. /// </summary>
  64. /// <returns></returns>
  65. public Formatting Clone()
  66. {
  67. Formatting newf = new Formatting();
  68. newf.Bold = bold;
  69. newf.CapsStyle = capsStyle;
  70. newf.FontColor = fontColor;
  71. newf.FontFamily = fontFamily;
  72. newf.Hidden = hidden;
  73. newf.Highlight = highlight;
  74. newf.Italic = italic;
  75. if (kerning.HasValue) { newf.Kerning = kerning; }
  76. newf.Language = language;
  77. newf.Misc = misc;
  78. if (percentageScale.HasValue) { newf.PercentageScale = percentageScale; }
  79. if (position.HasValue) { newf.Position = position; }
  80. newf.Script = script;
  81. if (size.HasValue) { newf.Size = size; }
  82. if (spacing.HasValue) { newf.Spacing = spacing; }
  83. newf.StrikeThrough = strikethrough;
  84. newf.UnderlineColor = underlineColor;
  85. newf.UnderlineStyle = underlineStyle;
  86. return newf;
  87. }
  88. public static Formatting Parse(XElement rPr)
  89. {
  90. Formatting formatting = new Formatting();
  91. // Build up the Formatting object.
  92. foreach (XElement option in rPr.Elements())
  93. {
  94. switch (option.Name.LocalName)
  95. {
  96. case "lang":
  97. formatting.Language = new CultureInfo(
  98. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null) ??
  99. option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), null) ??
  100. option.GetAttribute(XName.Get("bidi", DocX.w.NamespaceName)));
  101. break;
  102. case "spacing":
  103. formatting.Spacing = Double.Parse(
  104. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 20.0;
  105. break;
  106. case "position":
  107. formatting.Position = Int32.Parse(
  108. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2;
  109. break;
  110. case "kern":
  111. formatting.Position = Int32.Parse(
  112. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2;
  113. break;
  114. case "w":
  115. formatting.PercentageScale = Int32.Parse(
  116. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName)));
  117. break;
  118. // <w:sz w:val="20"/><w:szCs w:val="20"/>
  119. case "sz":
  120. formatting.Size = Int32.Parse(
  121. option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))) / 2;
  122. break;
  123. case "rFonts":
  124. formatting.FontFamily =
  125. new Font(
  126. option.GetAttribute(XName.Get("cs", DocX.w.NamespaceName), null) ??
  127. option.GetAttribute(XName.Get("ascii", DocX.w.NamespaceName), null) ??
  128. option.GetAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), null) ??
  129. option.GetAttribute(XName.Get("eastAsia", DocX.w.NamespaceName)));
  130. break;
  131. case "color" :
  132. try
  133. {
  134. string color = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName));
  135. formatting.FontColor = System.Drawing.ColorTranslator.FromHtml(string.Format("#{0}", color));
  136. }
  137. catch { }
  138. break;
  139. case "vanish": formatting.hidden = true; break;
  140. case "b": formatting.Bold = true; break;
  141. case "i": formatting.Italic = true; break;
  142. case "u": formatting.UnderlineStyle = HelperFunctions.GetUnderlineStyle(option.GetAttribute(XName.Get("val", DocX.w.NamespaceName))); break;
  143. case "vertAlign":
  144. var script = option.GetAttribute(XName.Get("val", DocX.w.NamespaceName), null);
  145. formatting.Script = (Script)Enum.Parse(typeof(Script), script);
  146. break;
  147. default: break;
  148. }
  149. }
  150. return formatting;
  151. }
  152. internal XElement Xml
  153. {
  154. get
  155. {
  156. rPr = new XElement(XName.Get("rPr", DocX.w.NamespaceName));
  157. if (language != null)
  158. rPr.Add(new XElement(XName.Get("lang", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), language.Name)));
  159. if(spacing.HasValue)
  160. rPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacing.Value * 20)));
  161. if(position.HasValue)
  162. rPr.Add(new XElement(XName.Get("position", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), position.Value * 2)));
  163. if (kerning.HasValue)
  164. rPr.Add(new XElement(XName.Get("kern", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), kerning.Value * 2)));
  165. if (percentageScale.HasValue)
  166. rPr.Add(new XElement(XName.Get("w", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), percentageScale)));
  167. if (fontFamily != null)
  168. {
  169. rPr.Add
  170. (
  171. new XElement
  172. (
  173. XName.Get("rFonts", DocX.w.NamespaceName),
  174. new XAttribute(XName.Get("ascii", DocX.w.NamespaceName), fontFamily.Name),
  175. new XAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865
  176. new XAttribute(XName.Get("cs", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865
  177. new XAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), fontFamily.Name) // DOCX in china #57
  178. )
  179. );
  180. }
  181. if (hidden.HasValue && hidden.Value)
  182. rPr.Add(new XElement(XName.Get("vanish", DocX.w.NamespaceName)));
  183. if (bold.HasValue && bold.Value)
  184. rPr.Add(new XElement(XName.Get("b", DocX.w.NamespaceName)));
  185. if (italic.HasValue && italic.Value)
  186. rPr.Add(new XElement(XName.Get("i", DocX.w.NamespaceName)));
  187. if (underlineStyle.HasValue)
  188. {
  189. switch (underlineStyle)
  190. {
  191. case Novacode.UnderlineStyle.none:
  192. break;
  193. case Novacode.UnderlineStyle.singleLine:
  194. rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single")));
  195. break;
  196. case Novacode.UnderlineStyle.doubleLine:
  197. rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "double")));
  198. break;
  199. default:
  200. rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), underlineStyle.ToString())));
  201. break;
  202. }
  203. }
  204. if(underlineColor.HasValue)
  205. {
  206. // If an underlineColor has been set but no underlineStyle has been set
  207. if (underlineStyle == Novacode.UnderlineStyle.none)
  208. {
  209. // Set the underlineStyle to the default
  210. underlineStyle = Novacode.UnderlineStyle.singleLine;
  211. rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single")));
  212. }
  213. rPr.Element(XName.Get("u", DocX.w.NamespaceName)).Add(new XAttribute(XName.Get("color", DocX.w.NamespaceName), underlineColor.Value.ToHex()));
  214. }
  215. if (strikethrough.HasValue)
  216. {
  217. switch (strikethrough)
  218. {
  219. case Novacode.StrikeThrough.none:
  220. break;
  221. case Novacode.StrikeThrough.strike:
  222. rPr.Add(new XElement(XName.Get("strike", DocX.w.NamespaceName)));
  223. break;
  224. case Novacode.StrikeThrough.doubleStrike:
  225. rPr.Add(new XElement(XName.Get("dstrike", DocX.w.NamespaceName)));
  226. break;
  227. default:
  228. break;
  229. }
  230. }
  231. if (script.HasValue)
  232. {
  233. switch (script)
  234. {
  235. case Novacode.Script.none:
  236. break;
  237. default:
  238. rPr.Add(new XElement(XName.Get("vertAlign", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString())));
  239. break;
  240. }
  241. }
  242. if (size.HasValue)
  243. {
  244. rPr.Add(new XElement(XName.Get("sz", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString())));
  245. rPr.Add(new XElement(XName.Get("szCs", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString())));
  246. }
  247. if(fontColor.HasValue)
  248. rPr.Add(new XElement(XName.Get("color", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontColor.Value.ToHex())));
  249. if (highlight.HasValue)
  250. {
  251. switch (highlight)
  252. {
  253. case Novacode.Highlight.none:
  254. break;
  255. default:
  256. rPr.Add(new XElement(XName.Get("highlight", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString())));
  257. break;
  258. }
  259. }
  260. if (capsStyle.HasValue)
  261. {
  262. switch (capsStyle)
  263. {
  264. case Novacode.CapsStyle.none:
  265. break;
  266. default:
  267. rPr.Add(new XElement(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName)));
  268. break;
  269. }
  270. }
  271. if (misc.HasValue)
  272. {
  273. switch (misc)
  274. {
  275. case Novacode.Misc.none:
  276. break;
  277. case Novacode.Misc.outlineShadow:
  278. rPr.Add(new XElement(XName.Get("outline", DocX.w.NamespaceName)));
  279. rPr.Add(new XElement(XName.Get("shadow", DocX.w.NamespaceName)));
  280. break;
  281. case Novacode.Misc.engrave:
  282. rPr.Add(new XElement(XName.Get("imprint", DocX.w.NamespaceName)));
  283. break;
  284. default:
  285. rPr.Add(new XElement(XName.Get(misc.ToString(), DocX.w.NamespaceName)));
  286. break;
  287. }
  288. }
  289. return rPr;
  290. }
  291. }
  292. /// <summary>
  293. /// This formatting will apply Bold.
  294. /// </summary>
  295. public bool? Bold { get { return bold; } set { bold = value;} }
  296. /// <summary>
  297. /// This formatting will apply Italic.
  298. /// </summary>
  299. public bool? Italic { get { return italic; } set { italic = value; } }
  300. /// <summary>
  301. /// This formatting will apply StrickThrough.
  302. /// </summary>
  303. public StrikeThrough? StrikeThrough { get { return strikethrough; } set { strikethrough = value; } }
  304. /// <summary>
  305. /// The script that this formatting should be, normal, superscript or subscript.
  306. /// </summary>
  307. public Script? Script { get { return script; } set { script = value; } }
  308. /// <summary>
  309. /// The Size of this text, must be between 0 and 1638.
  310. /// </summary>
  311. public double? Size
  312. {
  313. get { return size; }
  314. set
  315. {
  316. double? temp = value * 2;
  317. if (temp - (int)temp == 0)
  318. {
  319. if(value > 0 && value < 1639)
  320. size = value;
  321. else
  322. throw new ArgumentException("Size", "Value must be in the range 0 - 1638");
  323. }
  324. else
  325. throw new ArgumentException("Size", "Value must be either a whole or half number, examples: 32, 32.5");
  326. }
  327. }
  328. /// <summary>
  329. /// Percentage scale must be one of the following values 200, 150, 100, 90, 80, 66, 50 or 33.
  330. /// </summary>
  331. public int? PercentageScale
  332. {
  333. get { return percentageScale; }
  334. set
  335. {
  336. if ((new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 }).Contains(value))
  337. percentageScale = value;
  338. else
  339. throw new ArgumentOutOfRangeException("PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33");
  340. }
  341. }
  342. /// <summary>
  343. /// The Kerning to apply to this text must be one of the following values 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72.
  344. /// </summary>
  345. public int? Kerning
  346. {
  347. get { return kerning; }
  348. set
  349. {
  350. if(new int?[] {8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72}.Contains(value))
  351. kerning = value;
  352. else
  353. throw new ArgumentOutOfRangeException("Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72");
  354. }
  355. }
  356. /// <summary>
  357. /// Text position must be in the range (-1585 - 1585).
  358. /// </summary>
  359. public int? Position
  360. {
  361. get { return position; }
  362. set
  363. {
  364. if (value > -1585 && value < 1585)
  365. position = value;
  366. else
  367. throw new ArgumentOutOfRangeException("Position", "Value must be in the range -1585 - 1585");
  368. }
  369. }
  370. /// <summary>
  371. /// Text spacing must be in the range (-1585 - 1585).
  372. /// </summary>
  373. public double? Spacing
  374. {
  375. get { return spacing; }
  376. set
  377. {
  378. double? temp = value * 20;
  379. if (temp - (int)temp == 0)
  380. {
  381. if (value > -1585 && value < 1585)
  382. spacing = value;
  383. else
  384. throw new ArgumentException("Spacing", "Value must be in the range: -1584 - 1584");
  385. }
  386. else
  387. throw new ArgumentException("Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9");
  388. }
  389. }
  390. /// <summary>
  391. /// The colour of the text.
  392. /// </summary>
  393. public Color? FontColor { get { return fontColor; } set { fontColor = value; } }
  394. /// <summary>
  395. /// Highlight colour.
  396. /// </summary>
  397. public Highlight? Highlight { get { return highlight; } set { highlight = value; } }
  398. /// <summary>
  399. /// The Underline style that this formatting applies.
  400. /// </summary>
  401. public UnderlineStyle? UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } }
  402. /// <summary>
  403. /// The underline colour.
  404. /// </summary>
  405. public Color? UnderlineColor { get { return underlineColor; } set { underlineColor = value; } }
  406. /// <summary>
  407. /// Misc settings.
  408. /// </summary>
  409. public Misc? Misc { get { return misc; } set { misc = value; } }
  410. /// <summary>
  411. /// Is this text hidden or visible.
  412. /// </summary>
  413. public bool? Hidden { get { return hidden; } set { hidden = value; } }
  414. /// <summary>
  415. /// Capitalization style.
  416. /// </summary>
  417. public CapsStyle? CapsStyle { get { return capsStyle; } set { capsStyle = value; } }
  418. /// <summary>
  419. /// The font family of this formatting.
  420. /// </summary>
  421. /// <!--
  422. /// Bug found and fixed by krugs525 on August 12 2009.
  423. /// Use TFS compare to see exact code change.
  424. /// -->
  425. public Font FontFamily { get { return fontFamily; } set { fontFamily = value; } }
  426. public int CompareTo(object obj)
  427. {
  428. Formatting other = (Formatting)obj;
  429. if(other.hidden != this.hidden)
  430. return -1;
  431. if(other.bold != this.bold)
  432. return -1;
  433. if(other.italic != this.italic)
  434. return -1;
  435. if(other.strikethrough != this.strikethrough)
  436. return -1;
  437. if(other.script != this.script)
  438. return -1;
  439. if(other.highlight != this.highlight)
  440. return -1;
  441. if(other.size != this.size)
  442. return -1;
  443. if(other.fontColor != this.fontColor)
  444. return -1;
  445. if(other.underlineColor != this.underlineColor)
  446. return -1;
  447. if(other.underlineStyle != this.underlineStyle)
  448. return -1;
  449. if(other.misc != this.misc)
  450. return -1;
  451. if(other.capsStyle != this.capsStyle)
  452. return -1;
  453. if(other.fontFamily != this.fontFamily)
  454. return -1;
  455. if(other.percentageScale != this.percentageScale)
  456. return -1;
  457. if(other.kerning != this.kerning)
  458. return -1;
  459. if(other.position != this.position)
  460. return -1;
  461. if(other.spacing != this.spacing)
  462. return -1;
  463. if (!other.language.Equals(this.language))
  464. return -1;
  465. return 0;
  466. }
  467. }
  468. }