TextObjectBase.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. using System;
  2. using System.ComponentModel;
  3. using FastReport.Utils;
  4. using FastReport.Format;
  5. using System.Windows.Forms;
  6. using System.Drawing.Design;
  7. namespace FastReport
  8. {
  9. /// <summary>
  10. /// Specifies how to display the duplicate values.
  11. /// </summary>
  12. public enum Duplicates
  13. {
  14. /// <summary>
  15. /// The <b>TextObject</b> can show duplicate values.
  16. /// </summary>
  17. Show,
  18. /// <summary>
  19. /// The <b>TextObject</b> with duplicate value will be hidden.
  20. /// </summary>
  21. Hide,
  22. /// <summary>
  23. /// The <b>TextObject</b> with duplicate value will be shown but with no text.
  24. /// </summary>
  25. Clear,
  26. /// <summary>
  27. /// Several <b>TextObject</b> objects with the same value will be merged into one <b>TextObject</b> object.
  28. /// </summary>
  29. Merge
  30. }
  31. /// <summary>
  32. /// Specifies how the report engine processes the text objects.
  33. /// </summary>
  34. public enum ProcessAt
  35. {
  36. /// <summary>
  37. /// Specifies the default process mode. The text object is processed just-in-time.
  38. /// </summary>
  39. Default,
  40. /// <summary>
  41. /// Specifies that the text object must be processed when the entire report is finished. This mode
  42. /// can be used to print grand total value (which is normally calculated at the end of report) in the
  43. /// report title band.
  44. /// </summary>
  45. ReportFinished,
  46. /// <summary>
  47. /// Specifies that the text object must be processed when the entire report page is finished. This mode
  48. /// can be used if the report template consists of several report pages.
  49. /// </summary>
  50. ReportPageFinished,
  51. /// <summary>
  52. /// Specifies that the text object must be processed when any report page is finished. This mode
  53. /// can be used to print the page total (which is normally calculated at the page footer) in the
  54. /// page header band.
  55. /// </summary>
  56. PageFinished,
  57. /// <summary>
  58. /// Specifies that the text object must be processed when the column is finished. This mode
  59. /// can be used to print the column total (which is normally calculated at the column footer) in the
  60. /// column header band.
  61. /// </summary>
  62. ColumnFinished,
  63. /// <summary>
  64. /// Specifies that the text object must be processed when the data block is finished. This mode can be
  65. /// used to print a total value in the data header (which is normally available
  66. /// in the data footer only).
  67. /// </summary>
  68. DataFinished,
  69. /// <summary>
  70. /// Specifies that the text object must be processed when the group is finished. This mode can be
  71. /// used to print a total value in the group header (which is normally available
  72. /// in the group footer only).
  73. /// </summary>
  74. GroupFinished,
  75. /// <summary>
  76. /// Specifies that the text object is processed manually when you call the <b>Engine.ProcessObject</b>
  77. /// method in the report script.
  78. /// </summary>
  79. Custom
  80. }
  81. /// <summary>
  82. /// Base class for text objects such as <see cref="TextObject"/> and <see cref="RichObject"/>.
  83. /// </summary>
  84. /// <remarks>
  85. /// This class implements common functionality of the text objects.
  86. /// </remarks>
  87. public partial class TextObjectBase : BreakableComponent
  88. {
  89. #region Fields
  90. private string text;
  91. private object value;
  92. private bool allowExpressions;
  93. private string brackets;
  94. private Padding padding;
  95. private bool hideZeros;
  96. private string hideValue;
  97. private string nullValue;
  98. private FormatCollection formats;
  99. private ProcessAt processAt;
  100. private Duplicates duplicates;
  101. private bool editable;
  102. #endregion
  103. #region Properties
  104. /// <summary>
  105. /// Gets or sets a value indicating that the object's text may contain expressions.
  106. /// </summary>
  107. [DefaultValue(true)]
  108. [Category("Data")]
  109. public bool AllowExpressions
  110. {
  111. get { return allowExpressions; }
  112. set { allowExpressions = value; }
  113. }
  114. /// <summary>
  115. /// Gets or sets the symbols that will be used to find expressions in the object's text.
  116. /// </summary>
  117. /// <remarks>
  118. /// The default property value is "[,]". As you can see, the open and close symbols are
  119. /// separated by the comma. You may use another symbols, for example: "&lt;,&gt;" or "&lt;%,%&gt;".
  120. /// You should use different open and close symbols.
  121. /// </remarks>
  122. [Category("Data")]
  123. public string Brackets
  124. {
  125. get { return brackets; }
  126. set { brackets = value; }
  127. }
  128. /// <summary>
  129. /// Gets or sets the object's text.
  130. /// </summary>
  131. /// <remarks>
  132. /// Text may contain expressions and data items, for example: "Today is [Date]".
  133. /// When report is running, all expressions are calculated and replaced with actual
  134. /// values, so the text would be "Today is 01.01.2008".
  135. /// </remarks>
  136. [Category("Data")]
  137. public virtual string Text
  138. {
  139. get { return text; }
  140. set { text = value; }
  141. }
  142. /// <summary>
  143. /// Gets or sets padding within the text object.
  144. /// </summary>
  145. [Category("Layout")]
  146. public Padding Padding
  147. {
  148. get { return padding; }
  149. set { padding = value; }
  150. }
  151. /// <summary>
  152. /// Gets or sets a value indicating that zero values must be hidden.
  153. /// </summary>
  154. [Category("Behavior")]
  155. [DefaultValue(false)]
  156. public bool HideZeros
  157. {
  158. get { return hideZeros; }
  159. set { hideZeros = value; }
  160. }
  161. /// <summary>
  162. /// Gets or sets a value that will be hidden.
  163. /// </summary>
  164. /// <remarks>
  165. /// Use this property to specify a value that you would like to hide. For example, specify "0"
  166. /// if you want to hide zero values, or use <see cref="HideZeros"/> property to do this.
  167. /// <para/>You also may use this property to hide default DateTime values (such as 1/1/1900).
  168. /// In this case you need to specify a string containing both date and time, for example:
  169. /// "1/1/1900 0:00:00".
  170. /// <note type="caution">
  171. /// FastReport uses the <b>ToString</b> conversion to compare the expression value with this property.
  172. /// This conversion depends on regional settings selected in the Control Panel, so be aware of this
  173. /// if you going to distribute your report worldwide.
  174. /// </note>
  175. /// </remarks>
  176. [Category("Behavior")]
  177. public string HideValue
  178. {
  179. get { return hideValue; }
  180. set { hideValue = value; }
  181. }
  182. /// <summary>
  183. /// Gets or sets a string that will be displayed instead of a null value.
  184. /// </summary>
  185. [Category("Behavior")]
  186. public string NullValue
  187. {
  188. get { return nullValue; }
  189. set { nullValue = value; }
  190. }
  191. /// <summary>
  192. /// Gets or sets the formatter that will be used to format data in the Text object.
  193. /// </summary>
  194. /// <remarks>
  195. /// The default formatter does nothing, i.e. it shows expression values with no formatting.
  196. /// To set another formatting, create a new formatter and assign it to this property.
  197. /// <para/>If there are several expressions in the text, use the <see cref="Formats"/> property
  198. /// to format each expression value.
  199. /// </remarks>
  200. /// <example>This example shows how to set currency formatter.
  201. /// <code>
  202. /// TextObject text1;
  203. /// text1.Format = new CurrencyFormat();
  204. /// </code>
  205. /// </example>
  206. [Category("Data")]
  207. [Editor("FastReport.TypeEditors.FormatEditor, FastReport", typeof(UITypeEditor))]
  208. public FormatBase Format
  209. {
  210. get { return formats.Count == 0 ? new GeneralFormat() : formats[0]; }
  211. set
  212. {
  213. if (value == null)
  214. value = new GeneralFormat();
  215. if (formats.Count == 0)
  216. formats.Add(value);
  217. else
  218. formats[0] = value;
  219. }
  220. }
  221. /// <summary>
  222. /// Gets or sets a value that specifies how the report engine processes this text object.
  223. /// </summary>
  224. /// <remarks>
  225. /// Use this property to perform such task as "print a total value in the group header". Normally,
  226. /// all total values are calculated in the footers (for example, in a group footer). If you try to print
  227. /// a total value in the group header, you will get 0. If you set this property to
  228. /// <b>ProcessAt.DataFinished</b>, FastReport will do the following:
  229. /// <list type="bullet">
  230. /// <item>
  231. /// <description>print the object (with wrong value);</description>
  232. /// </item>
  233. /// <item>
  234. /// <description>print all related data rows;</description>
  235. /// </item>
  236. /// <item>
  237. /// <description>calculate the correct object's value and replace old (wrong) value with the new one.</description>
  238. /// </item>
  239. /// </list>
  240. /// <note type="caution">
  241. /// This option will not work if you set the <see cref="Report.UseFileCache"/> to <b>true</b>.
  242. /// </note>
  243. /// </remarks>
  244. [Category("Behavior")]
  245. [DefaultValue(ProcessAt.Default)]
  246. public ProcessAt ProcessAt
  247. {
  248. get { return processAt; }
  249. set { processAt = value; }
  250. }
  251. /// <summary>
  252. /// Gets the collection of formatters.
  253. /// </summary>
  254. /// <remarks>
  255. /// This property is used to set format for each expression contained in the text.
  256. /// For example, if the <b>TextObject</b> contains two expressions:
  257. /// <para/><i>Today is [Date]; Page [PageN]</i>
  258. /// <para/>you can use the following code to format these expressions separately:
  259. /// <code>
  260. /// text1.Formats.Clear();
  261. /// text1.Formats.Add(new DateFormat());
  262. /// text1.Formats.Add(new NumberFormat());
  263. /// </code>
  264. /// </remarks>
  265. [Browsable(false)]
  266. public FormatCollection Formats
  267. {
  268. get { return formats; }
  269. }
  270. /// <summary>
  271. /// Gets or sets a value that determines how to display duplicate values.
  272. /// </summary>
  273. [DefaultValue(Duplicates.Show)]
  274. [Category("Behavior")]
  275. public Duplicates Duplicates
  276. {
  277. get { return duplicates; }
  278. set { duplicates = value; }
  279. }
  280. /// <summary>
  281. /// Gets a value of expression contained in the object's text.
  282. /// </summary>
  283. [Browsable(false)]
  284. public object Value
  285. {
  286. get { return value; }
  287. }
  288. /// <summary>
  289. /// Gets or sets editable for pdf export
  290. /// </summary>
  291. [Category("Behavior")]
  292. [DefaultValue(false)]
  293. public bool Editable
  294. {
  295. get { return editable; }
  296. set { editable = value; }
  297. }
  298. #endregion
  299. #region Protected Methods
  300. /// <inheritdoc/>
  301. protected override void DeserializeSubItems(FRReader reader)
  302. {
  303. if (String.Compare(reader.ItemName, "Formats", true) == 0)
  304. reader.Read(Formats);
  305. else
  306. base.DeserializeSubItems(reader);
  307. }
  308. #endregion
  309. #region Public Methods
  310. /// <inheritdoc/>
  311. public override void Assign(Base source)
  312. {
  313. base.Assign(source);
  314. TextObjectBase src = source as TextObjectBase;
  315. Text = src.Text;
  316. Padding = src.Padding;
  317. AllowExpressions = src.AllowExpressions;
  318. Brackets = src.Brackets;
  319. HideZeros = src.HideZeros;
  320. HideValue = src.HideValue;
  321. NullValue = src.NullValue;
  322. ProcessAt = src.ProcessAt;
  323. Formats.Assign(src.Formats);
  324. Duplicates = src.Duplicates;
  325. Editable = src.Editable;
  326. }
  327. /// <inheritdoc/>
  328. public override void Serialize(FRWriter writer)
  329. {
  330. TextObjectBase c = writer.DiffObject as TextObjectBase;
  331. base.Serialize(writer);
  332. if (Text != c.Text)
  333. writer.WriteStr("Text", Text);
  334. if (Padding != c.Padding)
  335. writer.WriteValue("Padding", Padding);
  336. if (writer.SerializeTo != SerializeTo.Preview)
  337. {
  338. if (AllowExpressions != c.AllowExpressions)
  339. writer.WriteBool("AllowExpressions", AllowExpressions);
  340. if (Brackets != c.Brackets)
  341. writer.WriteStr("Brackets", Brackets);
  342. if (HideZeros != c.HideZeros)
  343. writer.WriteBool("HideZeros", HideZeros);
  344. if (HideValue != c.HideValue)
  345. writer.WriteStr("HideValue", HideValue);
  346. if (NullValue != c.NullValue)
  347. writer.WriteStr("NullValue", NullValue);
  348. if (ProcessAt != c.ProcessAt)
  349. writer.WriteValue("ProcessAt", ProcessAt);
  350. if (Duplicates != c.Duplicates)
  351. writer.WriteValue("Duplicates", Duplicates);
  352. }
  353. if (Editable)
  354. writer.WriteBool("Editable", Editable);
  355. if (Formats.Count > 1)
  356. writer.Write(Formats);
  357. else
  358. Format.Serialize(writer, "Format.", c.Format);
  359. }
  360. /// <inheritdoc/>
  361. public override void ExtractMacros()
  362. {
  363. Text = ExtractDefaultMacros(Text);
  364. }
  365. internal void SetValue(object value)
  366. {
  367. this.value = value;
  368. }
  369. internal string GetTextWithBrackets(string text)
  370. {
  371. string[] brackets = Brackets.Split(',');
  372. return brackets[0] + text + brackets[1];
  373. }
  374. internal string GetTextWithoutBrackets(string text)
  375. {
  376. string[] brackets = Brackets.Split(',');
  377. if (text.StartsWith(brackets[0]))
  378. text = text.Remove(0, brackets[0].Length);
  379. if (text.EndsWith(brackets[1]))
  380. text = text.Remove(text.Length - brackets[1].Length);
  381. return text;
  382. }
  383. internal string FormatValue(object value)
  384. {
  385. return FormatValue(value, 0);
  386. }
  387. internal string FormatValue(object value, int formatIndex)
  388. {
  389. this.value = value;
  390. string formattedValue = "";
  391. if (value == null || value is DBNull)
  392. {
  393. formattedValue = NullValue;
  394. }
  395. else
  396. {
  397. if (formatIndex < Formats.Count)
  398. formattedValue = Formats[formatIndex].FormatValue(value);
  399. else
  400. formattedValue = Format.FormatValue(value);
  401. if (!String.IsNullOrEmpty(HideValue))
  402. {
  403. if (value.ToString() == HideValue)
  404. formattedValue = "";
  405. }
  406. if (HideZeros)
  407. {
  408. Variant v = new Variant(value);
  409. if ((v.IsNumeric && v == 0) || (v.IsDate && v.ToDateTime() == DateTime.MinValue))
  410. formattedValue = "";
  411. }
  412. }
  413. return formattedValue;
  414. }
  415. internal string CalcAndFormatExpression(string expression, int expressionIndex)
  416. {
  417. try
  418. {
  419. return FormatValue(Report.Calc(expression), expressionIndex);
  420. }
  421. catch (Exception e)
  422. {
  423. throw new Exception(Name + ": " + Res.Get("Messages,ErrorInExpression") + ": " + expression,
  424. e.InnerException == null ? e : e.InnerException);
  425. }
  426. }
  427. /// <summary>
  428. /// Returns the text to display.
  429. /// </summary>
  430. /// <returns>The text to display.</returns>
  431. /// <remarks>This method is used to display simplified DB field names in the designer. In runtime, it returns the Text property value.</remarks>
  432. public virtual string GetDisplayText()
  433. {
  434. return Text;
  435. }
  436. #endregion
  437. /// <summary>
  438. /// Initializes a new instance of the <see cref="TextObjectBase"/> class with default settings.
  439. /// </summary>
  440. public TextObjectBase()
  441. {
  442. allowExpressions = true;
  443. brackets = "[,]";
  444. padding = new Padding(2, 0, 2, 0);
  445. hideValue = "";
  446. nullValue = "";
  447. text = "";
  448. formats = new FormatCollection();
  449. formats.Add(new GeneralFormat());
  450. }
  451. }
  452. }