TableResult.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using FastReport.Engine;
  5. using FastReport.Preview;
  6. using System.Drawing;
  7. using FastReport.Utils;
  8. namespace FastReport.Table
  9. {
  10. /// <summary>
  11. /// Represents a result table.
  12. /// </summary>
  13. /// <remarks>
  14. /// Do not use this class directly. It is used by the <see cref="TableObject"/> and
  15. /// <see cref="FastReport.Matrix.MatrixObject"/> objects to render a result.
  16. /// </remarks>
  17. public class TableResult : TableBase
  18. {
  19. private bool skip;
  20. private List<TableRow> rowsToSerialize;
  21. private List<TableColumn> columnsToSerialize;
  22. private bool isFirstRow;
  23. /// <summary>
  24. /// Occurs after calculation of table bounds.
  25. /// </summary>
  26. /// <remarks>
  27. /// You may use this event to change automatically calculated rows/column sizes. It may be useful
  28. /// if you need to fit dynamically printed table on a page.
  29. /// </remarks>
  30. public event EventHandler AfterCalcBounds;
  31. internal bool Skip
  32. {
  33. get { return skip; }
  34. set { skip = value; }
  35. }
  36. internal List<TableRow> RowsToSerialize
  37. {
  38. get { return rowsToSerialize; }
  39. }
  40. internal List<TableColumn> ColumnsToSerialize
  41. {
  42. get { return columnsToSerialize; }
  43. }
  44. private float GetRowsHeight(int startRow, int count)
  45. {
  46. float height = 0;
  47. // include row header
  48. if (startRow != 0 && (RepeatHeaders || RepeatColumnHeaders))
  49. {
  50. for (int i = 0; i < FixedRows; i++)
  51. {
  52. height += Rows[i].Height;
  53. }
  54. }
  55. for (int i = 0; i < count; i++)
  56. {
  57. height += Rows[startRow + i].Height;
  58. }
  59. return height;
  60. }
  61. private float GetColumnsWidth(int startColumn, int count)
  62. {
  63. float width = 0;
  64. // include column header
  65. if (startColumn != 0 && (RepeatHeaders || RepeatRowHeaders))
  66. {
  67. for (int i = 0; i < FixedColumns; i++)
  68. {
  69. width += Columns[i].Width;
  70. }
  71. }
  72. for (int i = 0; i < count; i++)
  73. {
  74. if (i == count - 1)
  75. width += Math.Max(Columns[startColumn + i].Width, Columns[startColumn + i].MinimumBreakWidth);
  76. else
  77. width += Columns[startColumn + i].Width;
  78. }
  79. return width;
  80. }
  81. private int GetRowsFit(int startRow, float freeSpace)
  82. {
  83. int rowsFit = 0;
  84. int rowsToKeep = 0;
  85. int rowsKept = 0;
  86. int saveRowsFit = 0;
  87. bool keeping = false;
  88. while (startRow + rowsFit < Rows.Count &&
  89. (rowsFit == 0 || !Rows[startRow + rowsFit].PageBreak) &&
  90. (!this.CanBreak | GetRowsHeight(startRow, rowsFit + 1) <= freeSpace + 0.1f))
  91. {
  92. if (keeping)
  93. {
  94. rowsKept++;
  95. if (rowsKept >= rowsToKeep)
  96. keeping = false;
  97. }
  98. else if (Rows[startRow + rowsFit].KeepRows > 1)
  99. {
  100. rowsToKeep = Rows[startRow + rowsFit].KeepRows;
  101. rowsKept = 1;
  102. saveRowsFit = rowsFit;
  103. keeping = true;
  104. }
  105. rowsFit++;
  106. }
  107. if (keeping)
  108. rowsFit = saveRowsFit;
  109. // case if the row header does not fit on a page (at the start of table)
  110. if (startRow == 0 && rowsFit < FixedRows)
  111. rowsFit = 0;
  112. return rowsFit;
  113. }
  114. private int GetColumnsFit(int startColumn, float freeSpace)
  115. {
  116. int columnsFit = 0;
  117. int columnsToKeep = 0;
  118. int columnsKept = 0;
  119. int saveColumnsFit = 0;
  120. bool keeping = false;
  121. while (startColumn + columnsFit < Columns.Count &&
  122. (columnsFit == 0 || !Columns[startColumn + columnsFit].PageBreak) &&
  123. GetColumnsWidth(startColumn, columnsFit + 1) <= freeSpace + 0.1f)
  124. {
  125. if (keeping)
  126. {
  127. columnsKept++;
  128. if (columnsKept >= columnsToKeep)
  129. keeping = false;
  130. }
  131. else if (Columns[startColumn + columnsFit].KeepColumns > 1)
  132. {
  133. columnsToKeep = Columns[startColumn + columnsFit].KeepColumns;
  134. columnsKept = 1;
  135. saveColumnsFit = columnsFit;
  136. keeping = true;
  137. }
  138. columnsFit++;
  139. }
  140. if (keeping)
  141. columnsFit = saveColumnsFit;
  142. return columnsFit;
  143. }
  144. private void ProcessDuplicates(TableCell cell, int startX, int startY, List<Rectangle> list)
  145. {
  146. string cellAlias = cell.Alias;
  147. TableCellData cellData = cell.CellData;
  148. string cellText = cell.Text;
  149. CellDuplicates cellDuplicates = cell.CellDuplicates;
  150. Func<int, int> func = (row) =>
  151. {
  152. int span = 0;
  153. for (int x = startX; x < ColumnCount; x++)
  154. {
  155. TableCell c = this[x, row];
  156. if (IsInsideSpan(c, list))
  157. break;
  158. if (c.Alias == cellAlias)
  159. {
  160. if (c.Text == cellText)
  161. span++;
  162. else
  163. break;
  164. }
  165. else
  166. break;
  167. }
  168. return span;
  169. };
  170. int colSpan = func(startY);
  171. int rowSpan = 1;
  172. for (int y = startY + 1; y < RowCount; y++)
  173. {
  174. int span = func(y);
  175. if (span < cellData.ColSpan)
  176. break;
  177. rowSpan++;
  178. }
  179. if (cellDuplicates == CellDuplicates.Clear)
  180. {
  181. for (int x = 0; x < colSpan; x++)
  182. for (int y = 0; y < rowSpan; y++)
  183. if (!(x == 0 && y == 0))
  184. GetCellData(x + startX, y + startY).Text = "";
  185. }
  186. else if (cellDuplicates == CellDuplicates.Merge ||
  187. (cellDuplicates == CellDuplicates.MergeNonEmpty && !String.IsNullOrEmpty(cellText)))
  188. {
  189. cellData.ColSpan = colSpan;
  190. cellData.RowSpan = rowSpan;
  191. }
  192. list.Add(new Rectangle(startX, startY, colSpan, rowSpan));
  193. }
  194. private bool IsInsideSpan(TableCell cell, List<Rectangle> list)
  195. {
  196. Point address = cell.Address;
  197. foreach (Rectangle span in list)
  198. {
  199. if (span.Contains(address))
  200. return true;
  201. }
  202. return false;
  203. }
  204. private void ProcessDuplicates()
  205. {
  206. List<Rectangle> list = new List<Rectangle>();
  207. for (int x = 0; x < ColumnCount; x++)
  208. {
  209. for (int y = 0; y < RowCount; y++)
  210. {
  211. TableCell cell = this[x, y];
  212. if (cell.CellDuplicates != CellDuplicates.Show && !IsInsideSpan(cell, list))
  213. {
  214. ProcessDuplicates(cell, x, y, list);
  215. }
  216. }
  217. }
  218. }
  219. internal void GeneratePages(object sender, EventArgs e)
  220. {
  221. isFirstRow = false;
  222. if (Skip)
  223. {
  224. Skip = false;
  225. return;
  226. }
  227. // check if band contains several tables
  228. if (sender is BandBase)
  229. {
  230. BandBase senderBand = sender as BandBase;
  231. isFirstRow = senderBand.IsFirstRow;
  232. SortedList<float, TableBase> tables = new SortedList<float, TableBase>();
  233. foreach (Base obj in senderBand.Objects)
  234. {
  235. TableBase table = obj as TableBase;
  236. if (table != null && table.ResultTable != null)
  237. try
  238. {
  239. tables.Add(table.Left, table);
  240. }
  241. catch (ArgumentException)
  242. {
  243. throw new ArgumentException(Res.Get("Messages,MatrixLayoutError"));
  244. }
  245. }
  246. // render tables side-by-side
  247. if (tables.Count > 1)
  248. {
  249. ReportEngine engine = Report.Engine;
  250. TableLayoutInfo info = new TableLayoutInfo();
  251. info.startPage = engine.CurPage;
  252. info.tableSize = new Size(1, 1);
  253. info.startX = tables.Values[0].Left;
  254. int startPage = info.startPage;
  255. float saveCurY = engine.CurY;
  256. int maxPage = 0;
  257. float maxCurY = 0;
  258. for (int i = 0; i < tables.Count; i++)
  259. {
  260. TableBase table = tables.Values[i];
  261. // do not allow table to render itself in the band.AfterPrint event
  262. table.ResultTable.Skip = true;
  263. // render using the down-then-across mode
  264. table.Layout = TableLayout.DownThenAcross;
  265. engine.CurPage = info.startPage + (info.tableSize.Width - 1) * info.tableSize.Height;
  266. engine.CurY = saveCurY;
  267. float addLeft = 0;
  268. if (i > 0)
  269. addLeft = table.Left - tables.Values[i - 1].Right;
  270. table.ResultTable.Left = info.startX + addLeft;
  271. // calculate cells' bounds
  272. table.ResultTable.CalcBounds();
  273. // generate pages
  274. Report.PreparedPages.AddPageAction = AddPageAction.WriteOver;
  275. info = table.ResultTable.GeneratePagesDownThenAcross();
  276. if (engine.CurPage > maxPage)
  277. {
  278. maxPage = engine.CurPage;
  279. maxCurY = engine.CurY;
  280. }
  281. else if (engine.CurPage == maxPage && engine.CurY > maxCurY)
  282. {
  283. maxCurY = engine.CurY;
  284. }
  285. }
  286. engine.CurPage = maxPage;
  287. engine.CurY = maxCurY;
  288. Skip = false;
  289. return;
  290. }
  291. }
  292. // calculate cells' bounds
  293. CalcBounds();
  294. // manage duplicates
  295. ProcessDuplicates();
  296. if (Report.Engine.UnlimitedHeight || Report.Engine.UnlimitedWidth)
  297. {
  298. if (!Report.Engine.UnlimitedWidth)
  299. GeneratePagesWrapped();
  300. else if (!Report.Engine.UnlimitedHeight)
  301. GeneratePagesDownThenAcross();
  302. else
  303. GeneratePagesAcrossThenDown();
  304. }
  305. else if (Layout == TableLayout.AcrossThenDown)
  306. GeneratePagesAcrossThenDown();
  307. else if (Layout == TableLayout.DownThenAcross)
  308. GeneratePagesDownThenAcross();
  309. else
  310. GeneratePagesWrapped();
  311. }
  312. internal void AddToParent(Base parent)
  313. {
  314. // calculate cells' bounds
  315. CalcBounds();
  316. // manage duplicates
  317. ProcessDuplicates();
  318. // copy everything to regular table because TableResult is not suitable for this
  319. TableBase cloneTable = new TableBase();
  320. cloneTable.Assign(this);
  321. foreach (TableColumn c in Columns)
  322. {
  323. TableColumn cloneColumn = new TableColumn();
  324. cloneColumn.Assign(c);
  325. cloneTable.Columns.Add(cloneColumn);
  326. }
  327. foreach (TableRow r in Rows)
  328. {
  329. TableRow cloneRow = new TableRow();
  330. cloneRow.Assign(r);
  331. cloneTable.Rows.Add(cloneRow);
  332. for (int columnIndex = 0; columnIndex < ColumnCount; columnIndex++)
  333. {
  334. TableCell cloneCell = new TableCell();
  335. // this is the point why we have to do the cloning manually. r[columnIndex] may return shared instance of TableCell.
  336. cloneCell.AssignAll(r[columnIndex]);
  337. cloneCell.Parent = cloneRow;
  338. }
  339. }
  340. cloneTable.Parent = parent;
  341. }
  342. internal void CalcBounds()
  343. {
  344. // allow row/column manipulation from a script
  345. LockCorrectSpans = false;
  346. // fire AfterData event
  347. OnAfterData();
  348. // calculate cells' bounds
  349. Height = CalcHeight();
  350. // fire AfterCalcBounds event
  351. OnAfterCalcBounds();
  352. }
  353. private void OnAfterCalcBounds()
  354. {
  355. if (AfterCalcBounds != null)
  356. AfterCalcBounds(this, EventArgs.Empty);
  357. }
  358. private void GeneratePagesAcrossThenDown()
  359. {
  360. ReportEngine engine = Report.Engine;
  361. PreparedPages preparedPages = Report.PreparedPages;
  362. preparedPages.CanUploadToCache = false;
  363. preparedPages.AddPageAction = AddPageAction.WriteOver;
  364. List<Rectangle> spans = GetSpanList();
  365. int startRow = 0;
  366. bool addNewPage = false;
  367. float freeSpace = engine.FreeSpace;
  368. Top = 0;
  369. while (startRow < Rows.Count)
  370. {
  371. if (addNewPage)
  372. {
  373. engine.StartNewPage();
  374. freeSpace = engine.FreeSpace;
  375. }
  376. int startColumn = 0;
  377. int rowsFit = GetRowsFit(startRow, freeSpace);
  378. if (startRow == 0 && engine.IsKeeping && rowsFit < RowCount && isFirstRow && engine.KeepCurY > 0)
  379. {
  380. engine.EndColumn();
  381. freeSpace = engine.FreeSpace;
  382. rowsFit = GetRowsFit(startRow, freeSpace);
  383. }
  384. // avoid the infinite loop if there is not enough space for one row
  385. if (rowsFit == 0)
  386. rowsFit = 1;
  387. int saveCurPage = engine.CurPage;
  388. float saveLeft = Left;
  389. float saveCurY = engine.CurY;
  390. float curY = engine.CurY;
  391. if (rowsFit != 0)
  392. {
  393. while (startColumn < Columns.Count)
  394. {
  395. int columnsFit = GetColumnsFit(startColumn, engine.PageWidth - Left);
  396. // avoid the infinite loop if there is not enough space for one column
  397. if (startColumn > 0 && columnsFit == 0)
  398. columnsFit = 1;
  399. engine.CurY = saveCurY;
  400. curY = GeneratePage(startColumn, startRow, columnsFit, rowsFit,
  401. new RectangleF(0, 0, engine.PageWidth, CanBreak ? freeSpace : Height), spans) + saveCurY;
  402. Left = 0;
  403. startColumn += columnsFit;
  404. if (startColumn < Columns.Count)
  405. {
  406. // if we have something to print, start a new page
  407. engine.StartNewPage();
  408. }
  409. else if (engine.CurPage > saveCurPage)
  410. {
  411. // finish the last printed page in case it is not the start page
  412. engine.EndPage(false);
  413. }
  414. if (Report.Aborted)
  415. break;
  416. }
  417. }
  418. startRow += rowsFit;
  419. Left = saveLeft;
  420. engine.CurPage = saveCurPage;
  421. engine.CurY = curY;
  422. preparedPages.AddPageAction = AddPageAction.Add;
  423. addNewPage = true;
  424. if (Report.Aborted)
  425. break;
  426. }
  427. }
  428. private TableLayoutInfo GeneratePagesDownThenAcross()
  429. {
  430. ReportEngine engine = Report.Engine;
  431. PreparedPages preparedPages = Report.PreparedPages;
  432. preparedPages.CanUploadToCache = false;
  433. TableLayoutInfo info = new TableLayoutInfo();
  434. info.startPage = engine.CurPage;
  435. List<Rectangle> spans = GetSpanList();
  436. int startColumn = 0;
  437. bool addNewPage = false;
  438. float saveCurY = engine.CurY;
  439. float lastCurY = 0;
  440. int lastPage = 0;
  441. Top = 0;
  442. while (startColumn < Columns.Count)
  443. {
  444. if (addNewPage)
  445. engine.StartNewPage();
  446. int startRow = 0;
  447. int columnsFit = GetColumnsFit(startColumn, engine.PageWidth - Left);
  448. // avoid the infinite loop if there is not enough space for one column
  449. if (startColumn > 0 && columnsFit == 0)
  450. columnsFit = 1;
  451. engine.CurY = saveCurY;
  452. info.tableSize.Width++;
  453. info.tableSize.Height = 0;
  454. if (columnsFit > 0)
  455. {
  456. while (startRow < Rows.Count)
  457. {
  458. int rowsFit = GetRowsFit(startRow, engine.FreeSpace);
  459. if (startRow == 0 && engine.IsKeeping && rowsFit < RowCount && isFirstRow && engine.KeepCurY > 0)
  460. {
  461. engine.EndColumn();
  462. rowsFit = GetRowsFit(startRow, engine.FreeSpace);
  463. }
  464. // avoid the infinite loop if there is not enough space for one row
  465. if (startRow > 0 && rowsFit == 0)
  466. rowsFit = 1;
  467. engine.CurY += GeneratePage(startColumn, startRow, columnsFit, rowsFit,
  468. new RectangleF(0, 0, engine.PageWidth, engine.FreeSpace), spans);
  469. info.tableSize.Height++;
  470. startRow += rowsFit;
  471. if (startRow < Rows.Count)
  472. {
  473. // if we have something to print, start a new page
  474. engine.StartNewPage();
  475. }
  476. else if (startColumn > 0)
  477. {
  478. // finish the last printed page in case it is not a start page
  479. engine.EndPage(false);
  480. }
  481. if (Report.Aborted)
  482. break;
  483. }
  484. }
  485. info.startX = Left + GetColumnsWidth(startColumn, columnsFit);
  486. startColumn += columnsFit;
  487. Left = 0;
  488. preparedPages.AddPageAction = AddPageAction.Add;
  489. addNewPage = true;
  490. if (lastPage == 0)
  491. {
  492. lastPage = engine.CurPage;
  493. lastCurY = engine.CurY;
  494. }
  495. if (Report.Aborted)
  496. break;
  497. }
  498. engine.CurPage = lastPage;
  499. engine.CurY = lastCurY;
  500. return info;
  501. }
  502. private void GeneratePagesWrapped()
  503. {
  504. ReportEngine engine = Report.Engine;
  505. PreparedPages preparedPages = Report.PreparedPages;
  506. preparedPages.CanUploadToCache = false;
  507. List<Rectangle> spans = GetSpanList();
  508. int startColumn = 0;
  509. Top = 0;
  510. while (startColumn < Columns.Count)
  511. {
  512. int startRow = 0;
  513. int columnsFit = GetColumnsFit(startColumn, engine.PageWidth - Left);
  514. // avoid the infinite loop if there is not enough space for one column
  515. if (startColumn > 0 && columnsFit == 0)
  516. columnsFit = 1;
  517. while (startRow < Rows.Count)
  518. {
  519. int rowsFit = GetRowsFit(startRow, engine.FreeSpace);
  520. if (startRow == 0 && engine.IsKeeping && rowsFit < RowCount && isFirstRow && engine.KeepCurY > 0)
  521. {
  522. engine.EndColumn();
  523. rowsFit = GetRowsFit(startRow, engine.FreeSpace);
  524. }
  525. if (rowsFit == 0)
  526. {
  527. engine.StartNewPage();
  528. rowsFit = GetRowsFit(startRow, engine.FreeSpace);
  529. }
  530. engine.CurY += GeneratePage(startColumn, startRow, columnsFit, rowsFit,
  531. new RectangleF(0, 0, engine.PageWidth, engine.FreeSpace), spans);
  532. startRow += rowsFit;
  533. if (Report.Aborted)
  534. break;
  535. }
  536. startColumn += columnsFit;
  537. if (startColumn < Columns.Count)
  538. engine.CurY += WrappedGap;
  539. if (Report.Aborted)
  540. break;
  541. }
  542. }
  543. private void AdjustSpannedCellWidth(TableCellData cell)
  544. {
  545. if (!AdjustSpannedCellsWidth)
  546. return;
  547. // check that spanned cell has enough width
  548. float columnsWidth = 0;
  549. for (int i = 0; i < cell.ColSpan; i++)
  550. {
  551. columnsWidth += Columns[cell.Address.X + i].Width;
  552. }
  553. // if cell is bigger than sum of column width, increase the last column width
  554. float cellWidth = cell.CalcWidth();
  555. if (columnsWidth < cellWidth)
  556. Columns[cell.Address.X + cell.ColSpan - 1].Width += cellWidth - columnsWidth;
  557. }
  558. private float GeneratePage(int startColumn, int startRow, int columnsFit, int rowsFit,
  559. RectangleF bounds, List<Rectangle> spans)
  560. {
  561. // break spans
  562. foreach (Rectangle span in spans)
  563. {
  564. TableCellData spannedCell = GetCellData(span.Left, span.Top);
  565. TableCellData newSpannedCell = null;
  566. if (span.Left < startColumn && span.Right > startColumn)
  567. {
  568. if ((RepeatHeaders || RepeatRowHeaders) && span.Left < FixedColumns)
  569. {
  570. spannedCell.ColSpan = Math.Min(span.Right, startColumn + columnsFit) - startColumn + FixedColumns;
  571. }
  572. else
  573. {
  574. newSpannedCell = GetCellData(startColumn, span.Top);
  575. newSpannedCell.RunTimeAssign(spannedCell.Cell, true);
  576. newSpannedCell.ColSpan = Math.Min(span.Right, startColumn + columnsFit) - startColumn;
  577. newSpannedCell.RowSpan = spannedCell.RowSpan;
  578. AdjustSpannedCellWidth(newSpannedCell);
  579. }
  580. }
  581. if (span.Left < startColumn + columnsFit && span.Right > startColumn + columnsFit)
  582. {
  583. spannedCell.ColSpan = startColumn + columnsFit - span.Left;
  584. AdjustSpannedCellWidth(spannedCell);
  585. }
  586. if (span.Top < startRow && span.Bottom > startRow)
  587. {
  588. if ((RepeatHeaders || RepeatColumnHeaders) && span.Top < FixedRows)
  589. spannedCell.RowSpan = Math.Min(span.Bottom, startRow + rowsFit) - startRow + FixedRows;
  590. }
  591. if (span.Top < startRow + rowsFit && span.Bottom > startRow + rowsFit)
  592. {
  593. spannedCell.RowSpan = startRow + rowsFit - span.Top;
  594. newSpannedCell = GetCellData(span.Left, startRow + rowsFit);
  595. newSpannedCell.RunTimeAssign(spannedCell.Cell, true);
  596. newSpannedCell.ColSpan = spannedCell.ColSpan;
  597. newSpannedCell.RowSpan = span.Bottom - (startRow + rowsFit);
  598. // break the cell text
  599. TableCell cell = spannedCell.Cell;
  600. using (TextObject tempObject = new TextObject())
  601. {
  602. if (!cell.Break(tempObject))
  603. cell.Text = "";
  604. if (cell.CanBreak)
  605. newSpannedCell.Text = tempObject.Text;
  606. }
  607. // fix the row height
  608. float textHeight = newSpannedCell.Cell.CalcHeight();
  609. float rowsHeight = 0;
  610. for (int i = 0; i < newSpannedCell.RowSpan; i++)
  611. {
  612. rowsHeight += Rows[i + startRow + rowsFit].Height;
  613. }
  614. if (rowsHeight < textHeight)
  615. {
  616. // fix the last row's height
  617. Rows[startRow + rowsFit + newSpannedCell.RowSpan - 1].Height += textHeight - rowsHeight;
  618. }
  619. }
  620. }
  621. // set visible columns
  622. ColumnsToSerialize.Clear();
  623. if (RepeatHeaders || RepeatRowHeaders)
  624. {
  625. for (int i = 0; i < FixedColumns; i++)
  626. {
  627. // Apply visible expression if needed.
  628. if (!String.IsNullOrEmpty(Columns[i].VisibleExpression))
  629. Columns[i].Visible = CalcVisibleExpression(Columns[i].VisibleExpression);
  630. if (Columns[i].Visible)
  631. ColumnsToSerialize.Add(Columns[i]);
  632. }
  633. if (startColumn < FixedColumns)
  634. {
  635. columnsFit -= FixedColumns - startColumn;
  636. startColumn = FixedColumns;
  637. }
  638. }
  639. // calc visible columns and last X coordinate of table for unlimited page width
  640. float tableEndX = Columns[0].Width;
  641. for (int i = startColumn; i < startColumn + columnsFit; i++)
  642. {
  643. // Apply visible expression if needed.
  644. if (!String.IsNullOrEmpty(Columns[i].VisibleExpression))
  645. Columns[i].Visible = CalcVisibleExpression(Columns[i].VisibleExpression);
  646. if (Columns[i].Visible)
  647. {
  648. ColumnsToSerialize.Add(Columns[i]);
  649. tableEndX += Columns[i].Width;
  650. }
  651. }
  652. // set visible rows
  653. RowsToSerialize.Clear();
  654. if (RepeatHeaders || RepeatColumnHeaders)
  655. {
  656. for (int i = 0; i < FixedRows; i++)
  657. {
  658. // Apply visible expression if needed.
  659. if (!String.IsNullOrEmpty(Rows[i].VisibleExpression))
  660. Rows[i].Visible = CalcVisibleExpression(Rows[i].VisibleExpression);
  661. if (Rows[i].Visible)
  662. RowsToSerialize.Add(Rows[i]);
  663. }
  664. if (startRow < FixedRows)
  665. {
  666. rowsFit -= FixedRows - startRow;
  667. startRow = FixedRows;
  668. }
  669. }
  670. // calc visible rows and last Y coordinate of table for unlimited page height
  671. float tableEndY = Rows[0].Top;
  672. for (int i = startRow; i < startRow + rowsFit; i++)
  673. {
  674. // Apply visible expression if needed.
  675. if (!String.IsNullOrEmpty(Rows[i].VisibleExpression))
  676. Rows[i].Visible = CalcVisibleExpression(Rows[i].VisibleExpression);
  677. if (Rows[i].Visible)
  678. {
  679. RowsToSerialize.Add(Rows[i]);
  680. tableEndY += Rows[i].Height;
  681. }
  682. }
  683. // include row header
  684. if (startRow != 0 && (RepeatHeaders || RepeatColumnHeaders))
  685. {
  686. for (int i = 0; i < FixedRows; i++)
  687. {
  688. tableEndY += Rows[i].Height;
  689. }
  690. }
  691. // generate unlimited page
  692. if (Report.Engine.UnlimitedHeight || Report.Engine.UnlimitedWidth)
  693. {
  694. if (Report.Engine.UnlimitedHeight)
  695. {
  696. bounds.Height = tableEndY;
  697. }
  698. if (Report.Engine.UnlimitedWidth)
  699. {
  700. bounds.Width = tableEndX;
  701. }
  702. }
  703. DataBand band = new DataBand();
  704. band.Bounds = bounds;
  705. band.Objects.Add(this);
  706. Report.Engine.AddToPreparedPages(band);
  707. return GetRowsHeight(startRow, rowsFit);
  708. }
  709. /// <inheritdoc/>
  710. protected override void Dispose(bool disposing)
  711. {
  712. LockCorrectSpans = true;
  713. base.Dispose(disposing);
  714. }
  715. /// <inheritdoc/>
  716. public override void GetChildObjects(ObjectCollection list)
  717. {
  718. foreach (TableColumn column in ColumnsToSerialize)
  719. {
  720. list.Add(column);
  721. }
  722. foreach (TableRow row in RowsToSerialize)
  723. {
  724. list.Add(row);
  725. }
  726. }
  727. /// <summary>
  728. /// Creates a new instance of the <see cref="TableResult"/> class.
  729. /// </summary>
  730. public TableResult()
  731. {
  732. LockCorrectSpans = true;
  733. rowsToSerialize = new List<TableRow>();
  734. columnsToSerialize = new List<TableColumn>();
  735. }
  736. private class TableLayoutInfo
  737. {
  738. public int startPage;
  739. public Size tableSize;
  740. public float startX;
  741. }
  742. }
  743. }