TableCellData.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. namespace FastReport.Table
  5. {
  6. /// <summary>
  7. /// Represents data of the table cell.
  8. /// </summary>
  9. public class TableCellData : IDisposable
  10. {
  11. #region Fields
  12. private string text;
  13. private object value;
  14. private string hyperlinkValue;
  15. private int colSpan;
  16. private int rowSpan;
  17. private ReportComponentCollection objects;
  18. private TableCell style;
  19. private TableCell cell;
  20. private TableBase table;
  21. private Point address;
  22. private bool updatingLayout;
  23. #endregion // Fields
  24. #region Properties
  25. /// <summary>
  26. /// Gets or sets parent table of the cell.
  27. /// </summary>
  28. public TableBase Table
  29. {
  30. get { return table; }
  31. set { table = value; }
  32. }
  33. /// <summary>
  34. /// Gets or sets objects collection of the cell.
  35. /// </summary>
  36. public ReportComponentCollection Objects
  37. {
  38. get { return objects; }
  39. set { objects = value; }
  40. }
  41. /// <summary>
  42. /// Gets or sets text of the table cell.
  43. /// </summary>
  44. public string Text
  45. {
  46. get { return text; }
  47. set { text = value; }
  48. }
  49. /// <summary>
  50. /// Gets or sets value of the table cell.
  51. /// </summary>
  52. public object Value
  53. {
  54. get { return value; }
  55. set { this.value = value; }
  56. }
  57. /// <summary>
  58. /// Gets or sets hyperlink value of the table cell.
  59. /// </summary>
  60. public string HyperlinkValue
  61. {
  62. get { return hyperlinkValue; }
  63. set { hyperlinkValue = value; }
  64. }
  65. /// <summary>
  66. /// Gets or sets column span of the table cell.
  67. /// </summary>
  68. public int ColSpan
  69. {
  70. get { return colSpan; }
  71. set
  72. {
  73. if (colSpan != value)
  74. {
  75. float oldWidth = Width;
  76. colSpan = value;
  77. if (Table != null)
  78. {
  79. Table.ResetSpanList();
  80. UpdateLayout(oldWidth, Height, Width - oldWidth, 0);
  81. }
  82. }
  83. }
  84. }
  85. /// <summary>
  86. /// Gets or sets row span of the table cell.
  87. /// </summary>
  88. public int RowSpan
  89. {
  90. get { return rowSpan; }
  91. set
  92. {
  93. if (rowSpan != value)
  94. {
  95. float oldHeight = Height;
  96. rowSpan = value;
  97. if (Table != null)
  98. {
  99. Table.ResetSpanList();
  100. UpdateLayout(Width, oldHeight, 0, Height - oldHeight);
  101. }
  102. }
  103. }
  104. }
  105. /// <summary>
  106. /// Gets or sets the address of the table cell.
  107. /// </summary>
  108. public Point Address
  109. {
  110. get { return address; }
  111. set { address = value; }
  112. }
  113. /// <summary>
  114. /// Gets the table cell.
  115. /// </summary>
  116. public TableCell Cell
  117. {
  118. get
  119. {
  120. if (Table.IsResultTable)
  121. {
  122. TableCell cell0 = style;
  123. if (cell0 == null)
  124. cell0 = Table.Styles.DefaultStyle;
  125. if (this.cell != null)
  126. {
  127. cell0.Alias = this.cell.Alias;
  128. cell0.OriginalComponent = this.cell.OriginalComponent;
  129. }
  130. // handling dock/anchor of cell objects correctly: detach old celldata, update size, attach new one.
  131. cell0.CellData = null;
  132. cell0.Width = Width;
  133. cell0.Height = Height;
  134. cell0.CellData = this;
  135. cell0.Hyperlink.Value = HyperlinkValue;
  136. return cell0;
  137. }
  138. if (cell == null)
  139. {
  140. cell = new TableCell();
  141. cell.CellData = this;
  142. }
  143. return cell;
  144. }
  145. }
  146. /// <summary>
  147. /// Gets style of table cell.
  148. /// </summary>
  149. public TableCell Style
  150. {
  151. get { return style; }
  152. }
  153. /// <summary>
  154. /// Gets original the table cell.
  155. /// </summary>
  156. public TableCell OriginalCell
  157. {
  158. get { return cell; }
  159. }
  160. /// <summary>
  161. /// Gets width of the table cell.
  162. /// </summary>
  163. public float Width
  164. {
  165. get
  166. {
  167. if (Table == null)
  168. return 0;
  169. float result = 0;
  170. for (int i = 0; i < ColSpan; i++)
  171. {
  172. if (Address.X + i < Table.Columns.Count)
  173. result += Table.Columns[Address.X + i].Width;
  174. }
  175. return result;
  176. }
  177. }
  178. /// <summary>
  179. /// Gets height of the table cell.
  180. /// </summary>
  181. public float Height
  182. {
  183. get
  184. {
  185. if (Table == null)
  186. return 0;
  187. float result = 0;
  188. for (int i = 0; i < RowSpan; i++)
  189. {
  190. if (Address.Y + i < Table.Rows.Count)
  191. result += Table.Rows[Address.Y + i].Height;
  192. }
  193. return result;
  194. }
  195. }
  196. #endregion // Properties
  197. #region Constructors
  198. /// <summary>
  199. /// Initializes a new instance of the <see cref="TableCellData"/> class.
  200. /// </summary>
  201. public TableCellData()
  202. {
  203. colSpan = 1;
  204. rowSpan = 1;
  205. text = "";
  206. hyperlinkValue = "";
  207. }
  208. #endregion // Constructors
  209. #region Public Methods
  210. /// <summary>
  211. /// Attaches the specified table cell.
  212. /// </summary>
  213. /// <param name="cell">The table cell instance.</param>
  214. /// <remarks>This method is called when we load the table.</remarks>
  215. public void AttachCell(TableCell cell)
  216. {
  217. if (this.cell != null)
  218. {
  219. this.cell.CellData = null;
  220. this.cell.Dispose();
  221. }
  222. Text = cell.Text;
  223. ColSpan = cell.ColSpan;
  224. RowSpan = cell.RowSpan;
  225. objects = cell.Objects;
  226. style = null;
  227. this.cell = cell;
  228. cell.CellData = this;
  229. }
  230. /// <summary>
  231. /// Assigns another <see cref="TableCellData"/> instance.
  232. /// </summary>
  233. /// <param name="source">The table cell data that used as a source.</param>
  234. /// <remarks>This method is called when we copy cells or clone columns/rows in a designer.</remarks>
  235. public void Assign(TableCellData source)
  236. {
  237. AttachCell(source.Cell);
  238. }
  239. /// <summary>
  240. /// Assigns another <see cref="TableCellData"/> instance at run time.
  241. /// </summary>
  242. /// <param name="cell">The table cell data that used as a source.</param>
  243. /// <param name="copyChildren">This flag shows should children be copied or not.</param>
  244. /// <remarks>This method is called when we print a table. We should create a copy of the cell and set the style.</remarks>
  245. public void RunTimeAssign(TableCell cell, bool copyChildren)
  246. {
  247. Text = cell.Text;
  248. Value = cell.Value;
  249. HyperlinkValue = cell.Hyperlink.Value;
  250. // don't copy ColSpan, RowSpan - they will be handled in the TableHelper.
  251. //ColSpan = cell.ColSpan;
  252. //RowSpan = cell.RowSpan;
  253. // clone objects
  254. objects = null;
  255. if (cell.Objects != null && copyChildren)
  256. {
  257. objects = new ReportComponentCollection();
  258. foreach (ReportComponentBase obj in cell.Objects)
  259. {
  260. if (obj.Visible)
  261. {
  262. ReportComponentBase cloneObj = Activator.CreateInstance(obj.GetType()) as ReportComponentBase;
  263. cloneObj.AssignAll(obj);
  264. cloneObj.Name = obj.Name;
  265. objects.Add(cloneObj);
  266. }
  267. }
  268. }
  269. // add the cell to the style list. If the list contains such style,
  270. // return the existing style; in other case, create new style based
  271. // on the given cell.
  272. SetStyle(cell);
  273. // cell is used to reference the original cell. It is necessary to use Alias, OriginalComponent
  274. this.cell = cell;
  275. // reset object's size as if we set ColSpan and RowSpan to 1.
  276. // It is nesessary when printing spanned cells because the span of such cells will be corrected
  277. // when print new rows/columns and thus will move cell objects.
  278. if (objects != null)
  279. UpdateLayout(cell.Width, cell.Height, Width - cell.Width, Height - cell.Height);
  280. }
  281. /// <summary>
  282. /// Sets style of the table cell.
  283. /// </summary>
  284. /// <param name="style">The new style of the table cell.</param>
  285. public void SetStyle(TableCell style)
  286. {
  287. this.style = Table.Styles.Add(style);
  288. }
  289. /// <summary>
  290. /// Disposes the <see cref="TableCellData"/> instance.
  291. /// </summary>
  292. public void Dispose()
  293. {
  294. if (style == null && cell != null)
  295. cell.Dispose();
  296. cell = null;
  297. style = null;
  298. }
  299. /// <summary>
  300. /// Calculates width of the table cell.
  301. /// </summary>
  302. /// <returns>The value of the table cell width.</returns>
  303. public float CalcWidth()
  304. {
  305. TableCell cell = Cell;
  306. cell.SetReport(Table.Report);
  307. return cell.CalcWidth();
  308. }
  309. /// <summary>
  310. /// Calculates height of the table cell.
  311. /// </summary>
  312. /// <param name="width">The width of the table cell.</param>
  313. /// <returns>The value of the table cell height.</returns>
  314. public float CalcHeight(float width)
  315. {
  316. TableCell cell = Cell;
  317. cell.SetReport(Table.Report);
  318. cell.Width = width;
  319. float cellHeight = cell.CalcHeight();
  320. if (objects != null)
  321. {
  322. // pasted from BandBase.cs
  323. // sort objects by Top
  324. ReportComponentCollection sortedObjects = objects.SortByTop();
  325. // calc height of each object
  326. float[] heights = new float[sortedObjects.Count];
  327. for (int i = 0; i < sortedObjects.Count; i++)
  328. {
  329. ReportComponentBase obj = sortedObjects[i];
  330. float height = obj.Height;
  331. if (obj.CanGrow || obj.CanShrink)
  332. {
  333. float height1 = obj.CalcHeight();
  334. if ((obj.CanGrow && height1 > height) || (obj.CanShrink && height1 < height))
  335. height = height1;
  336. }
  337. heights[i] = height;
  338. }
  339. // calc shift amounts
  340. float[] shifts = new float[sortedObjects.Count];
  341. for (int i = 0; i < sortedObjects.Count; i++)
  342. {
  343. ReportComponentBase parent = sortedObjects[i];
  344. float shift = heights[i] - parent.Height;
  345. if (shift == 0)
  346. continue;
  347. for (int j = i + 1; j < sortedObjects.Count; j++)
  348. {
  349. ReportComponentBase child = sortedObjects[j];
  350. if (child.ShiftMode == ShiftMode.Never)
  351. continue;
  352. if (child.Top >= parent.Bottom - 1e-4)
  353. {
  354. if (child.ShiftMode == ShiftMode.WhenOverlapped &&
  355. (child.Left > parent.Right - 1e-4 || parent.Left > child.Right - 1e-4))
  356. continue;
  357. float parentShift = shifts[i];
  358. float childShift = shifts[j];
  359. if (shift > 0)
  360. childShift = Math.Max(shift + parentShift, childShift);
  361. else
  362. childShift = Math.Min(shift + parentShift, childShift);
  363. shifts[j] = childShift;
  364. }
  365. }
  366. }
  367. // update location and size of each component, calc max height
  368. float maxHeight = 0;
  369. for (int i = 0; i < sortedObjects.Count; i++)
  370. {
  371. ReportComponentBase obj = sortedObjects[i];
  372. obj.Height = heights[i];
  373. obj.Top += shifts[i];
  374. if (obj.Bottom > maxHeight)
  375. maxHeight = obj.Bottom;
  376. }
  377. if (cellHeight < maxHeight)
  378. cellHeight = maxHeight;
  379. // perform grow to bottom
  380. foreach (ReportComponentBase obj in objects)
  381. {
  382. if (obj.GrowToBottom)
  383. obj.Height = cellHeight - obj.Top;
  384. }
  385. // -----------------------
  386. }
  387. return cellHeight;
  388. }
  389. internal void UpdateLayout(float dx, float dy)
  390. {
  391. UpdateLayout(Width, Height, dx, dy);
  392. }
  393. internal void UpdateLayout(float width, float height, float dx, float dy)
  394. {
  395. if (updatingLayout || Objects == null)
  396. return;
  397. updatingLayout = true;
  398. try
  399. {
  400. RectangleF remainingBounds = new RectangleF(0, 0, width, height);
  401. remainingBounds.Width += dx;
  402. remainingBounds.Height += dy;
  403. foreach (ReportComponentBase c in Objects)
  404. {
  405. if ((c.Anchor & AnchorStyles.Right) != 0)
  406. {
  407. if ((c.Anchor & AnchorStyles.Left) != 0)
  408. c.Width += dx;
  409. else
  410. c.Left += dx;
  411. }
  412. else if ((c.Anchor & AnchorStyles.Left) == 0)
  413. {
  414. c.Left += dx / 2;
  415. }
  416. if ((c.Anchor & AnchorStyles.Bottom) != 0)
  417. {
  418. if ((c.Anchor & AnchorStyles.Top) != 0)
  419. c.Height += dy;
  420. else
  421. c.Top += dy;
  422. }
  423. else if ((c.Anchor & AnchorStyles.Top) == 0)
  424. {
  425. c.Top += dy / 2;
  426. }
  427. switch (c.Dock)
  428. {
  429. case DockStyle.Left:
  430. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Top, c.Width, remainingBounds.Height);
  431. remainingBounds.X += c.Width;
  432. remainingBounds.Width -= c.Width;
  433. break;
  434. case DockStyle.Top:
  435. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Top, remainingBounds.Width, c.Height);
  436. remainingBounds.Y += c.Height;
  437. remainingBounds.Height -= c.Height;
  438. break;
  439. case DockStyle.Right:
  440. c.Bounds = new RectangleF(remainingBounds.Right - c.Width, remainingBounds.Top, c.Width, remainingBounds.Height);
  441. remainingBounds.Width -= c.Width;
  442. break;
  443. case DockStyle.Bottom:
  444. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Bottom - c.Height, remainingBounds.Width, c.Height);
  445. remainingBounds.Height -= c.Height;
  446. break;
  447. case DockStyle.Fill:
  448. c.Bounds = remainingBounds;
  449. remainingBounds.Width = 0;
  450. remainingBounds.Height = 0;
  451. break;
  452. }
  453. }
  454. }
  455. finally
  456. {
  457. updatingLayout = false;
  458. }
  459. }
  460. #endregion // Public Methods
  461. }
  462. }