MatrixHeader.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Collections;
  5. using FastReport.Utils;
  6. namespace FastReport.Matrix
  7. {
  8. /// <summary>
  9. /// Represents a collection of matrix header descriptors used in the <see cref="MatrixObject"/>.
  10. /// </summary>
  11. public class MatrixHeader : CollectionBase, IFRSerializable
  12. {
  13. private MatrixHeaderItem rootItem;
  14. private int nextIndex;
  15. private string name;
  16. /// <summary>
  17. /// Gets or sets the element at the specified index.
  18. /// </summary>
  19. /// <param name="index">Index of an element.</param>
  20. /// <returns>The element at the specified index.</returns>
  21. public MatrixHeaderDescriptor this[int index]
  22. {
  23. get { return List[index] as MatrixHeaderDescriptor; }
  24. set { List[index] = value; }
  25. }
  26. internal MatrixHeaderItem RootItem
  27. {
  28. get { return rootItem; }
  29. }
  30. internal string Name
  31. {
  32. get { return name; }
  33. set { name = value; }
  34. }
  35. /// <summary>
  36. /// Adds the specified descriptors to the end of this collection.
  37. /// </summary>
  38. /// <param name="range">Array of descriptors to add.</param>
  39. public void AddRange(MatrixHeaderDescriptor[] range)
  40. {
  41. foreach (MatrixHeaderDescriptor s in range)
  42. {
  43. Add(s);
  44. }
  45. }
  46. /// <summary>
  47. /// Adds a descriptor to the end of this collection.
  48. /// </summary>
  49. /// <param name="value">Descriptor to add.</param>
  50. /// <returns>Index of the added descriptor.</returns>
  51. public int Add(MatrixHeaderDescriptor value)
  52. {
  53. return List.Add(value);
  54. }
  55. /// <summary>
  56. /// Inserts a descriptor into this collection at the specified index.
  57. /// </summary>
  58. /// <param name="index">The zero-based index at which value should be inserted.</param>
  59. /// <param name="value">The descriptor to insert.</param>
  60. public void Insert(int index, MatrixHeaderDescriptor value)
  61. {
  62. List.Insert(index, value);
  63. }
  64. /// <summary>
  65. /// Removes the specified descriptor from the collection.
  66. /// </summary>
  67. /// <param name="value">Descriptor to remove.</param>
  68. public void Remove(MatrixHeaderDescriptor value)
  69. {
  70. int i = IndexOf(value);
  71. if (i != -1)
  72. List.RemoveAt(i);
  73. }
  74. /// <summary>
  75. /// Returns the zero-based index of the first occurrence of a descriptor.
  76. /// </summary>
  77. /// <param name="value">The descriptor to locate in the collection.</param>
  78. /// <returns>The zero-based index of the first occurrence of descriptor within
  79. /// the entire collection, if found; otherwise, -1.</returns>
  80. public int IndexOf(MatrixHeaderDescriptor value)
  81. {
  82. return List.IndexOf(value);
  83. }
  84. /// <summary>
  85. /// Determines whether a descriptor is in the collection.
  86. /// </summary>
  87. /// <param name="value">The descriptor to locate in the collection.</param>
  88. /// <returns><b>true</b> if descriptor is found in the collection; otherwise, <b>false</b>.</returns>
  89. public bool Contains(MatrixHeaderDescriptor value)
  90. {
  91. return List.Contains(value);
  92. }
  93. /// <summary>
  94. /// Copies the elements of this collection to a new array.
  95. /// </summary>
  96. /// <returns>An array containing copies of this collection elements. </returns>
  97. public MatrixHeaderDescriptor[] ToArray()
  98. {
  99. MatrixHeaderDescriptor[] result = new MatrixHeaderDescriptor[Count];
  100. for (int i = 0; i < Count; i++)
  101. {
  102. result[i] = this[i];
  103. }
  104. return result;
  105. }
  106. /// <summary>
  107. /// Gets the list of indices of terminal items of this header.
  108. /// </summary>
  109. /// <returns>The list of indices.</returns>
  110. public int[] GetTerminalIndices()
  111. {
  112. return GetTerminalIndices(rootItem);
  113. }
  114. /// <summary>
  115. /// Gets the list of indices of terminal items of the header with specified address.
  116. /// </summary>
  117. /// <param name="address">The address of a header.</param>
  118. /// <returns>The list of indices.</returns>
  119. public int[] GetTerminalIndices(object[] address)
  120. {
  121. MatrixHeaderItem rootItem = Find(address, false, 0);
  122. return GetTerminalIndices(rootItem);
  123. }
  124. private int[] GetTerminalIndices(MatrixHeaderItem rootItem)
  125. {
  126. List<MatrixHeaderItem> terminalItems = rootItem.GetTerminalItems();
  127. int[] result = new int[terminalItems.Count];
  128. for (int i = 0; i < result.Length; i++)
  129. result[i] = terminalItems[i].Index;
  130. return result;
  131. }
  132. /// <summary>
  133. /// Removes a header item with the address specified.
  134. /// </summary>
  135. /// <param name="address">The address of a header.</param>
  136. public void RemoveItem(object[] address)
  137. {
  138. MatrixHeaderItem item = Find(address, false, 0);
  139. if (item != null)
  140. item.Parent.Items.Remove(item);
  141. }
  142. /// <summary>
  143. /// Gets an index of header with the address specified.
  144. /// </summary>
  145. /// <param name="address">The address of a header.</param>
  146. /// <returns>The index of header.</returns>
  147. public int Find(object[] address)
  148. {
  149. MatrixHeaderItem item = Find(address, false, 0);
  150. if (item != null)
  151. return item.Index;
  152. return -1;
  153. }
  154. /// <summary>
  155. /// Gets an index of header with the address specified. If there is no such header item, it will be created.
  156. /// </summary>
  157. /// <param name="address">The address of a header.</param>
  158. /// <returns>The index of header.</returns>
  159. public int FindOrCreate(object[] address)
  160. {
  161. MatrixHeaderItem item = Find(address, true, 0);
  162. if (item != null)
  163. return item.Index;
  164. return -1;
  165. }
  166. internal MatrixHeaderItem Find(object[] address, bool create, int dataRowNo)
  167. {
  168. // Note that the top header itself does not contain a value.
  169. // It is used as a list of first-level headers only.
  170. MatrixHeaderItem rootItem = RootItem;
  171. for (int i = 0; i < address.Length; i++)
  172. {
  173. int index = rootItem.Find(address[i], this[i].Sort);
  174. if (index >= 0)
  175. rootItem = rootItem.Items[index];
  176. else if (create)
  177. {
  178. // create new item if necessary.
  179. MatrixHeaderItem newItem = new MatrixHeaderItem(rootItem);
  180. newItem.Value = address[i];
  181. newItem.TemplateColumn = this[i].TemplateColumn;
  182. newItem.TemplateRow = this[i].TemplateRow;
  183. newItem.TemplateCell = this[i].TemplateCell;
  184. newItem.DataRowNo = dataRowNo;
  185. newItem.PageBreak = this[i].PageBreak;
  186. // index is used as a cell address in a matrix
  187. if (i == address.Length - 1)
  188. {
  189. // create index for bottom-level header
  190. newItem.Index = nextIndex;
  191. nextIndex++;
  192. }
  193. rootItem.Items.Insert(~index, newItem);
  194. rootItem = newItem;
  195. }
  196. else
  197. return null;
  198. }
  199. return rootItem;
  200. }
  201. private void AddTotalItems(MatrixHeaderItem rootItem, int descriptorIndex, bool isTemplate)
  202. {
  203. if (descriptorIndex >= Count)
  204. return;
  205. foreach (MatrixHeaderItem item in rootItem.Items)
  206. {
  207. AddTotalItems(item, descriptorIndex + 1, isTemplate);
  208. }
  209. if (this[descriptorIndex].Totals &&
  210. (isTemplate || !this[descriptorIndex].SuppressTotals || rootItem.Items.Count > 1))
  211. {
  212. MatrixHeaderItem totalItem = new MatrixHeaderItem(rootItem);
  213. totalItem.IsTotal = true;
  214. totalItem.Value = rootItem.Value;
  215. totalItem.DataRowNo = rootItem.DataRowNo;
  216. totalItem.TemplateColumn = this[descriptorIndex].TemplateTotalColumn;
  217. totalItem.TemplateRow = this[descriptorIndex].TemplateTotalRow;
  218. totalItem.TemplateCell = this[descriptorIndex].TemplateTotalCell;
  219. totalItem.Index = nextIndex;
  220. nextIndex++;
  221. if (this[descriptorIndex].TotalsFirst && !isTemplate)
  222. rootItem.Items.Insert(0, totalItem);
  223. else
  224. rootItem.Items.Add(totalItem);
  225. }
  226. }
  227. internal void AddTotalItems(bool isTemplate)
  228. {
  229. AddTotalItems(RootItem, 0, isTemplate);
  230. }
  231. internal void Reset()
  232. {
  233. RootItem.Clear();
  234. nextIndex = 0;
  235. }
  236. /// <inheritdoc/>
  237. public void Serialize(FRWriter writer)
  238. {
  239. writer.ItemName = Name;
  240. foreach (MatrixHeaderDescriptor d in this)
  241. {
  242. writer.Write(d);
  243. }
  244. }
  245. /// <inheritdoc/>
  246. public void Deserialize(FRReader reader)
  247. {
  248. Clear();
  249. while (reader.NextItem())
  250. {
  251. MatrixHeaderDescriptor d = new MatrixHeaderDescriptor();
  252. reader.Read(d);
  253. Add(d);
  254. }
  255. }
  256. internal MatrixHeader()
  257. {
  258. rootItem = new MatrixHeaderItem(null);
  259. }
  260. }
  261. }