HeaderDescriptor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. using System;
  2. using System.Collections.Generic;
  3. using FastReport.Table;
  4. using FastReport.Utils;
  5. namespace FastReport.AdvMatrix
  6. {
  7. /// <summary>
  8. /// The descriptor that is used to describe one element of the matrix header.
  9. /// </summary>
  10. /// <remarks>
  11. /// The class is used to define one header element of the matrix
  12. /// (either the column element or row element). The key properties are
  13. /// <see cref="Expression"/> and <see cref="Sort"/>.
  14. /// <para/>The collection of descriptors used to represent the matrix header is stored
  15. /// in the <b>AdvMatrixObject.Data.Columns</b> and <b>AdvMatrixObject.Data.Rows</b> properties.
  16. /// </remarks>
  17. public class HeaderDescriptor : IFRSerializable
  18. {
  19. /// <summary>
  20. /// Gets or sets the name of this descriptor.
  21. /// </summary>
  22. /// <remarks>
  23. /// This property is used by the TopN engine to find linked items such as TopNTotal, Others, OtherTotal.
  24. /// All others descriptors have empty name.
  25. /// </remarks>
  26. public string Name { get; set; }
  27. /// <summary>
  28. /// Gets the parent descriptor of this descriptor.
  29. /// </summary>
  30. public HeaderDescriptor Parent { get; private set; }
  31. /// <summary>
  32. /// Gets child items of this descriptor.
  33. /// </summary>
  34. public List<HeaderDescriptor> Items { get; }
  35. /// <summary>
  36. /// Gets or sets an expression which value will be used to fill the matrix.
  37. /// </summary>
  38. /// <remarks>
  39. /// <b>Expression</b> may be any valid expression. Usually it's a data column:
  40. /// <c>[DataSource.Column]</c>.
  41. /// </remarks>
  42. public string Expression { get; set; }
  43. /// <summary>
  44. /// Gets or sets a text which will be displayed in this item.
  45. /// </summary>
  46. /// <remarks>
  47. /// <b>DisplayText</b> may contain text mixed with expressions just like in the TextObject, e.g. "Some text: [expr]".
  48. /// The default property value is empty for group descriptors.
  49. /// In this case the group value returned by the <see cref="Expression"/> property will be displayed in this item.
  50. /// </remarks>
  51. public string DisplayText { get; set; }
  52. /// <summary>
  53. /// Gets or sets the filter expression.
  54. /// </summary>
  55. public string Filter { get; set; }
  56. /// <summary>
  57. /// Gets or sets the sort order of header values.
  58. /// </summary>
  59. /// <remarks>
  60. /// This property determines how the values displayed in this element are sorted. The default sort is ascending.
  61. /// </remarks>
  62. public SortOrder Sort { get; set; }
  63. /// <summary>
  64. /// Gets or sets the sort button name which toggles the sort order of this item.
  65. /// </summary>
  66. public string SortToggledBy { get; set; }
  67. /// <summary>
  68. /// Gets or sets an expression which value will be used to sort the header values.
  69. /// </summary>
  70. /// <remarks>This expression is used to sort header by its total value. The expression must contain single aggregate, e.g. "Sum([Table1.Field1])".
  71. /// The empty expression (by default) indicates that the header should be sorted by its value.
  72. /// </remarks>
  73. public string SortByTotal { get; set; }
  74. /// <summary>
  75. /// Gets or sets a value indicating that this item can be sorted interactively.
  76. /// </summary>
  77. public bool InteractiveSort { get; set; }
  78. /// <summary>
  79. /// Gets or sets an expression which value will be used to sort the header values interactively.
  80. /// </summary>
  81. /// <remarks>This expression is used to sort header values when interactive sorting is on.
  82. /// The expression must contain single aggregate, e.g. "Sum([Table1.Field1])".
  83. /// The empty expression (by default) indicates automatic mode.
  84. /// </remarks>
  85. public string InteractiveSortBy { get; set; }
  86. /// <summary>
  87. /// Gets or sets the visibility of this item.
  88. /// </summary>
  89. public bool Visible { get; set; }
  90. /// <summary>
  91. /// Gets or sets the expression that returns the visibility of this item.
  92. /// </summary>
  93. public string VisibleExpression { get; set; }
  94. /// <summary>
  95. /// Gets or sets the collapse button name which toggles the visibility of this item.
  96. /// </summary>
  97. public string VisibleToggledBy { get; set; }
  98. /// <summary>
  99. /// Gets or sets a value indicating that the page break must be printed before this element.
  100. /// </summary>
  101. /// <remarks>
  102. /// Page break is not printed before the very first element.
  103. /// </remarks>
  104. public bool PageBreak { get; set; }
  105. /// <summary>
  106. /// Determines whether the item should merge itself with single subitem.
  107. /// </summary>
  108. public bool MergeSingleItem { get; set; }
  109. /// <summary>
  110. /// Determines whether this item and its subitems will be displayed stepped.
  111. /// </summary>
  112. public bool Stepped { get; set; }
  113. /// <summary>
  114. /// Gets TopN settings for this item.
  115. /// </summary>
  116. public TopNInfo TopN { get; private set; }
  117. /// <summary>
  118. /// Gets or sets column span of this item. 0 means span is set automatically.
  119. /// </summary>
  120. public int ColSpan { get; set; }
  121. /// <summary>
  122. /// Gets or sets row span of this item. 0 means span is set automatically.
  123. /// </summary>
  124. public int RowSpan { get; set; }
  125. // these items set by TemplateBuilder.UpdateDescriptors
  126. internal AdvMatrixObject Matrix { get; set; }
  127. internal bool IsColumn { get; set; }
  128. internal TableColumn TemplateColumn { get; set; }
  129. internal TableRow TemplateRow { get; set; }
  130. internal TableCell TemplateCell { get; set; }
  131. // Aggregate is used if "sort by total" is on
  132. internal AggregateExpressionPair SortAggregate { get; set; }
  133. // Aggregate is used if interactive sort is on
  134. internal AggregateExpressionPair InteractiveSortAggregate { get; set; }
  135. internal bool IsGroup { get { return !String.IsNullOrEmpty(Expression); } }
  136. internal bool IsTopNItem { get { return !String.IsNullOrEmpty(Name); } }
  137. internal HeaderDescriptor Root
  138. {
  139. get
  140. {
  141. HeaderDescriptor item = this;
  142. while (item.Parent != null)
  143. {
  144. item = item.Parent;
  145. }
  146. return item;
  147. }
  148. }
  149. internal int Span
  150. {
  151. get
  152. {
  153. if (Stepped)
  154. return 1;
  155. int count = TerminalItems.Count;
  156. return count > 0 ? count : 1;
  157. }
  158. }
  159. internal List<HeaderDescriptor> AllItems
  160. {
  161. get
  162. {
  163. List<HeaderDescriptor> list = new List<HeaderDescriptor>();
  164. GetAllItems(this, list);
  165. return list;
  166. }
  167. }
  168. internal List<HeaderDescriptor> TerminalItems
  169. {
  170. get
  171. {
  172. List<HeaderDescriptor> list = new List<HeaderDescriptor>();
  173. GetTerminalItems(this, list);
  174. return list;
  175. }
  176. }
  177. private void GetAllItems(HeaderDescriptor root, List<HeaderDescriptor> list)
  178. {
  179. foreach (HeaderDescriptor d in root.Items)
  180. {
  181. list.Add(d);
  182. GetAllItems(d, list);
  183. }
  184. }
  185. private void GetTerminalItems(HeaderDescriptor root, List<HeaderDescriptor> list)
  186. {
  187. if (root.Items.Count == 0 || root.Stepped)
  188. list.Add(root);
  189. foreach (HeaderDescriptor d in root.Items)
  190. {
  191. GetTerminalItems(d, list);
  192. }
  193. }
  194. internal void SetParent(HeaderDescriptor parent)
  195. {
  196. Parent = parent;
  197. }
  198. internal void InitAggregates()
  199. {
  200. ExpressionParser parser = new ExpressionParser(Matrix);
  201. if (!String.IsNullOrEmpty(SortByTotal))
  202. {
  203. SortAggregate = parser.Parse(SortByTotal);
  204. }
  205. if (InteractiveSort && !String.IsNullOrEmpty(InteractiveSortBy))
  206. {
  207. // use existing cell aggregate here
  208. InteractiveSortAggregate = Matrix.Data.CellData.FindAggregate(parser.Parse(InteractiveSortBy));
  209. }
  210. }
  211. internal object CalcValue()
  212. {
  213. if (String.IsNullOrEmpty(Expression))
  214. return null;
  215. return Matrix.Report.Calc(Expression);
  216. }
  217. /// <summary>
  218. /// Adds new child descriptor.
  219. /// </summary>
  220. /// <returns>The new descriptor.</returns>
  221. public HeaderDescriptor Add()
  222. {
  223. return Add(new HeaderDescriptor());
  224. }
  225. /// <summary>
  226. /// Adds a child descriptor.
  227. /// </summary>
  228. /// <param name="descr">The new descriptor.</param>
  229. /// <returns>The new descriptor.</returns>
  230. public HeaderDescriptor Add(HeaderDescriptor descr)
  231. {
  232. Items.Add(descr);
  233. descr.Parent = this;
  234. return descr;
  235. }
  236. /// <inheritdoc/>
  237. public void Serialize(FRWriter writer)
  238. {
  239. writer.ItemName = "Descriptor";
  240. HeaderDescriptor c = writer.DiffObject as HeaderDescriptor;
  241. if (Name != c.Name)
  242. writer.WriteStr("Name", Name);
  243. if (Expression != c.Expression)
  244. writer.WriteStr("Expression", Expression);
  245. if (DisplayText != c.DisplayText)
  246. writer.WriteStr("DisplayText", DisplayText);
  247. if (Filter != c.Filter)
  248. writer.WriteStr("Filter", Filter);
  249. if (Sort != c.Sort)
  250. writer.WriteValue("Sort", Sort);
  251. if (SortToggledBy != c.SortToggledBy)
  252. writer.WriteStr("SortToggledBy", SortToggledBy);
  253. if (SortByTotal != c.SortByTotal)
  254. writer.WriteStr("SortByTotal", SortByTotal);
  255. if (InteractiveSort != c.InteractiveSort)
  256. writer.WriteBool("InteractiveSort", InteractiveSort);
  257. if (InteractiveSortBy != c.InteractiveSortBy)
  258. writer.WriteStr("InteractiveSortBy", InteractiveSortBy);
  259. if (Visible != c.Visible)
  260. writer.WriteBool("Visible", Visible);
  261. if (VisibleExpression != c.VisibleExpression)
  262. writer.WriteStr("VisibleExpression", VisibleExpression);
  263. if (VisibleToggledBy != c.VisibleToggledBy)
  264. writer.WriteStr("VisibleToggledBy", VisibleToggledBy);
  265. TopN.Serialize(writer, "TopN", c.TopN);
  266. if (Stepped != c.Stepped)
  267. writer.WriteBool("Stepped", Stepped);
  268. if (PageBreak != c.PageBreak)
  269. writer.WriteBool("PageBreak", PageBreak);
  270. if (MergeSingleItem != c.MergeSingleItem)
  271. writer.WriteBool("MergeSingleItem", MergeSingleItem);
  272. if (ColSpan != c.ColSpan)
  273. writer.WriteInt("ColSpan", ColSpan);
  274. if (RowSpan != c.RowSpan)
  275. writer.WriteInt("RowSpan", RowSpan);
  276. foreach (HeaderDescriptor d in Items)
  277. {
  278. writer.Write(d);
  279. }
  280. }
  281. /// <inheritdoc/>
  282. public void Deserialize(FRReader reader)
  283. {
  284. reader.ReadProperties(this);
  285. Items.Clear();
  286. while (reader.NextItem())
  287. {
  288. reader.Read(Add());
  289. }
  290. }
  291. /// <summary>
  292. /// Initializes a new instance of the <see cref="HeaderDescriptor"/> class.
  293. /// </summary>
  294. public HeaderDescriptor()
  295. {
  296. Name = "";
  297. Items = new List<HeaderDescriptor>();
  298. Expression = "";
  299. DisplayText = "";
  300. Filter = "";
  301. Sort = SortOrder.Ascending;
  302. SortToggledBy = "";
  303. SortByTotal = "";
  304. InteractiveSort = true;
  305. InteractiveSortBy = "";
  306. Visible = true;
  307. VisibleExpression = "";
  308. VisibleToggledBy = "";
  309. TopN = new TopNInfo(this);
  310. }
  311. /// <summary>
  312. /// Initializes a new instance of the <see cref="HeaderDescriptor"/> class with the group expression specified.
  313. /// </summary>
  314. public HeaderDescriptor(string expression) : this()
  315. {
  316. Expression = expression;
  317. }
  318. }
  319. }