TableBase.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.ComponentModel;
  5. using FastReport.Utils;
  6. namespace FastReport.Table
  7. {
  8. /// <summary>
  9. /// Specifies the layout that will be used when printing a big table.
  10. /// </summary>
  11. public enum TableLayout
  12. {
  13. /// <summary>
  14. /// The table is printed across a pages then down.
  15. /// </summary>
  16. AcrossThenDown,
  17. /// <summary>
  18. /// The table is printed down then across a pages.
  19. /// </summary>
  20. DownThenAcross,
  21. /// <summary>
  22. /// The table is wrapped.
  23. /// </summary>
  24. Wrapped
  25. }
  26. /// <summary>
  27. /// The base class for table-type controls such as <see cref="TableObject"/> and
  28. /// <see cref="FastReport.Matrix.MatrixObject"/>.
  29. /// </summary>
  30. public partial class TableBase : BreakableComponent, IParent
  31. {
  32. #region Fields
  33. private TableRowCollection rows;
  34. private TableColumnCollection columns;
  35. private TableStyleCollection styles;
  36. private int fixedRows;
  37. private int fixedColumns;
  38. private bool printOnParent;
  39. private float wrappedGap;
  40. private bool repeatHeaders;
  41. private bool repeatRowHeaders;
  42. private bool repeatColumnHeaders;
  43. private bool adjustSpannedCellsWidth;
  44. private bool lockCorrectSpans;
  45. private bool serializingToPreview;
  46. private bool lockColumnRowChange;
  47. private TableLayout layout;
  48. private List<Rectangle> spanList;
  49. private TableResult resultTable;
  50. private TableCellData printingCell;
  51. //private static float FLeftRtl;
  52. #endregion
  53. #region Properties
  54. /// <summary>
  55. /// Gets a collection of table rows.
  56. /// </summary>
  57. [Browsable(false)]
  58. public TableRowCollection Rows
  59. {
  60. get { return rows; }
  61. }
  62. /// <summary>
  63. /// Gets a collection of table columns.
  64. /// </summary>
  65. [Browsable(false)]
  66. public TableColumnCollection Columns
  67. {
  68. get { return columns; }
  69. }
  70. internal TableStyleCollection Styles
  71. {
  72. get { return styles; }
  73. }
  74. /// <summary>
  75. /// Gets or sets the number of fixed rows that will be repeated on each page.
  76. /// </summary>
  77. [DefaultValue(0)]
  78. [Category("Layout")]
  79. public int FixedRows
  80. {
  81. get
  82. {
  83. int value = fixedRows;
  84. if (value >= Rows.Count)
  85. value = Rows.Count - 1;
  86. if (value < 0)
  87. value = 0;
  88. return value;
  89. }
  90. set { fixedRows = value; }
  91. }
  92. /// <summary>
  93. /// Gets or sets the number of fixed columns that will be repeated on each page.
  94. /// </summary>
  95. [DefaultValue(0)]
  96. [Category("Layout")]
  97. public int FixedColumns
  98. {
  99. get
  100. {
  101. int value = fixedColumns;
  102. if (value >= Columns.Count)
  103. value = Columns.Count - 1;
  104. if (value < 0)
  105. value = 0;
  106. return value;
  107. }
  108. set { fixedColumns = value; }
  109. }
  110. /// <summary>
  111. /// Gets or sets the value that determines whether to print the dynamic table (or matrix) on its parent band directly.
  112. /// </summary>
  113. /// <remarks>
  114. /// By default the dynamic table (matrix) is printed on its own band and is splitted on pages if necessary.
  115. /// </remarks>
  116. [DefaultValue(false)]
  117. [Category("Layout")]
  118. public bool PrintOnParent
  119. {
  120. get { return printOnParent; }
  121. set { printOnParent = value; }
  122. }
  123. /// <summary>
  124. /// Gets or sets a value that determines whether is necessary to repeat table header on each page.
  125. /// </summary>
  126. /// <remarks>
  127. /// To define a table header, set the <see cref="FixedRows"/> and <see cref="FixedColumns"/>
  128. /// properties.
  129. /// </remarks>
  130. [DefaultValue(true)]
  131. [Category("Behavior")]
  132. public bool RepeatHeaders
  133. {
  134. get { return repeatHeaders; }
  135. set { repeatHeaders = value; }
  136. }
  137. /// <summary>
  138. /// Gets or sets a value that determines whether is necessary to repeat table Row header on each page.
  139. /// </summary>
  140. /// <remarks>
  141. /// To define a table Row header, set the <see cref="FixedRows"/>
  142. /// properties.
  143. /// </remarks>
  144. [Browsable(false)]
  145. [DefaultValue(false)]
  146. [Category("Behavior")]
  147. public virtual bool RepeatRowHeaders
  148. {
  149. get { return repeatRowHeaders; }
  150. set { repeatRowHeaders = value; }
  151. }
  152. /// <summary>
  153. /// Gets or sets a value that determines whether is necessary to repeat table Column header on each page.
  154. /// </summary>
  155. /// <remarks>
  156. /// To define a table Column header, set the <see cref="FixedColumns"/>
  157. /// properties.
  158. /// </remarks>
  159. [Browsable(false)]
  160. [DefaultValue(false)]
  161. [Category("Behavior")]
  162. public virtual bool RepeatColumnHeaders
  163. {
  164. get { return repeatColumnHeaders; }
  165. set { repeatColumnHeaders = value; }
  166. }
  167. /// <summary>
  168. /// Gets or sets the table layout.
  169. /// </summary>
  170. /// <remarks>
  171. /// This property affects printing the big table that breaks across pages.
  172. /// </remarks>
  173. [DefaultValue(TableLayout.AcrossThenDown)]
  174. [Category("Behavior")]
  175. public TableLayout Layout
  176. {
  177. get { return layout; }
  178. set { layout = value; }
  179. }
  180. /// <summary>
  181. /// Gets or sets gap between parts of the table in wrapped layout mode.
  182. /// </summary>
  183. /// <remarks>
  184. /// This property is used if you set the <see cref="Layout"/> property to <b>Wrapped</b>.
  185. /// </remarks>
  186. [DefaultValue(0f)]
  187. [Category("Behavior")]
  188. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  189. public float WrappedGap
  190. {
  191. get { return wrappedGap; }
  192. set { wrappedGap = value; }
  193. }
  194. /// <summary>
  195. /// Gets or sets a value that determines whether to adjust the spanned cell's width when breaking the table across pages.
  196. /// </summary>
  197. /// <remarks>
  198. /// If set to <b>true</b>, the spanned cell's width will be adjusted to accomodate all contained text.
  199. /// </remarks>
  200. [DefaultValue(false)]
  201. [Category("Behavior")]
  202. public bool AdjustSpannedCellsWidth
  203. {
  204. get { return adjustSpannedCellsWidth; }
  205. set { adjustSpannedCellsWidth = value; }
  206. }
  207. /// <summary>
  208. /// Gets or sets the table cell.
  209. /// </summary>
  210. /// <param name="col">Column index.</param>
  211. /// <param name="row">Row index.</param>
  212. /// <returns>The <b>TableCell</b> object that represents a cell.</returns>
  213. [Browsable(false)]
  214. public TableCell this[int col, int row]
  215. {
  216. get
  217. {
  218. if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
  219. return null;
  220. return rows[row][col];
  221. }
  222. set
  223. {
  224. if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
  225. return;
  226. rows[row][col] = value;
  227. }
  228. }
  229. /// <summary>
  230. /// Gets or sets a number of columns in the table.
  231. /// </summary>
  232. [Category("Appearance")]
  233. public virtual int ColumnCount
  234. {
  235. get { return Columns.Count; }
  236. set
  237. {
  238. int n = value - Columns.Count;
  239. for (int i = 0; i < n; i++)
  240. {
  241. TableColumn column = new TableColumn();
  242. Columns.Add(column);
  243. }
  244. while (value < Columns.Count)
  245. Columns.RemoveAt(Columns.Count - 1);
  246. }
  247. }
  248. /// <summary>
  249. /// Gets or sets a number of rows in the table.
  250. /// </summary>
  251. [Category("Appearance")]
  252. public virtual int RowCount
  253. {
  254. get { return Rows.Count; }
  255. set
  256. {
  257. int n = value - Rows.Count;
  258. for (int i = 0; i < n; i++)
  259. {
  260. TableRow row = new TableRow();
  261. Rows.Add(row);
  262. }
  263. while (value < Rows.Count)
  264. Rows.RemoveAt(Rows.Count - 1);
  265. }
  266. }
  267. internal bool IsResultTable
  268. {
  269. get { return this is TableResult; }
  270. }
  271. /// <summary>
  272. /// Gets a table which contains the result of rendering dynamic table.
  273. /// </summary>
  274. /// <remarks>
  275. /// Use this property to access the result of rendering your table in dynamic mode.
  276. /// It may be useful if you want to center or right-align the result table on a page.
  277. /// In this case, you need to add the following code at the end of your ManualBuild event handler:
  278. /// <code>
  279. /// // right-align the table
  280. /// Table1.ResultTable.Left = Engine.PageWidth - Table1.ResultTable.CalcWidth() - 1;
  281. /// </code>
  282. /// </remarks>
  283. [Browsable(false)]
  284. public TableResult ResultTable
  285. {
  286. get { return resultTable; }
  287. }
  288. internal TableCellData PrintingCell
  289. {
  290. get { return printingCell; }
  291. set { printingCell = value; }
  292. }
  293. internal bool LockCorrectSpans
  294. {
  295. get { return lockCorrectSpans; }
  296. set { lockCorrectSpans = value; }
  297. }
  298. #endregion
  299. #region Private Methods
  300. private delegate void DrawCellProc(FRPaintEventArgs e, TableCell cell);
  301. private void DrawCells(FRPaintEventArgs e, DrawCellProc proc)
  302. {
  303. float top = 0;
  304. for (int y = 0; y < Rows.Count; y++)
  305. {
  306. float left = 0;
  307. float height = Rows[y].Height;
  308. for (int x = 0; x < Columns.Count; x++)
  309. {
  310. TableCell cell = this[x, y];
  311. float width = Columns[x].Width;
  312. cell.Left = left;
  313. cell.Top = top;
  314. if (!IsInsideSpan(cell) && (!IsPrinting || cell.Printable))
  315. {
  316. cell.SetPrinting(IsPrinting);
  317. #if !MONO || (WPF || AVALONIA)
  318. if (cell.IsVisible(e))
  319. #endif
  320. proc(e, cell);
  321. }
  322. left += width;
  323. }
  324. top += height;
  325. }
  326. }
  327. private void DrawCellsRtl(FRPaintEventArgs e, DrawCellProc proc)
  328. {
  329. float top = 0;
  330. for (int y = 0; y < Rows.Count; y++)
  331. {
  332. float left = 0;
  333. float height = Rows[y].Height;
  334. //bool thereIsColSpan = false;
  335. //for (int i = Columns.Count - 1; i >= 0; i--)
  336. //{
  337. // TableCell cell = this[i, y];
  338. // if (cell.ColSpan > 1)
  339. // {
  340. // thereIsColSpan = true;
  341. // }
  342. //}
  343. for (int x = Columns.Count - 1; x >= 0; x--)
  344. {
  345. TableCell cell = this[x, y];
  346. bool thereIsColSpan = false;
  347. if (cell.ColSpan > 1)
  348. {
  349. thereIsColSpan = true;
  350. }
  351. float width = Columns[x].Width;
  352. //if (thereIsColSpan)
  353. //{
  354. // width *= cell.ColSpan - 1;
  355. // left -= width;
  356. //}
  357. if (!IsInsideSpan(cell) && (!IsPrinting || cell.Printable))
  358. {
  359. cell.Left = left;
  360. cell.Top = top;
  361. cell.SetPrinting(IsPrinting);
  362. proc(e, cell);
  363. if (thereIsColSpan)
  364. width *= cell.ColSpan;
  365. left += width;
  366. }
  367. //if (!thereIsColSpan)
  368. // left += width;
  369. //else
  370. // left -= width;
  371. }
  372. top += height;
  373. }
  374. }
  375. private void DrawFill(FRPaintEventArgs e, TableCell cell)
  376. {
  377. cell.DrawBackground(e);
  378. }
  379. private void DrawText(FRPaintEventArgs e, TableCell cell)
  380. {
  381. cell.DrawText(e);
  382. }
  383. private void DrawBorders(FRPaintEventArgs e, TableCell cell)
  384. {
  385. cell.Border.Draw(e, cell.AbsBounds);
  386. }
  387. private void DrawTable(FRPaintEventArgs e)
  388. {
  389. DrawCells(e, DrawFill);
  390. DrawCells(e, DrawText);
  391. DrawDesign_Borders(e);
  392. DrawCells(e, DrawBorders);
  393. DrawDesign_SelectedCells(e);
  394. }
  395. private void DrawTableRtl(FRPaintEventArgs e)
  396. {
  397. DrawCellsRtl(e, DrawFill);
  398. DrawCellsRtl(e, DrawText);
  399. DrawDesign_BordersRtl(e);
  400. DrawCellsRtl(e, DrawBorders);
  401. DrawDesign_SelectedCellsRtl(e);
  402. }
  403. #endregion
  404. #region Public Methods
  405. /// <inheritdoc/>
  406. public override void Assign(Base source)
  407. {
  408. base.Assign(source);
  409. TableBase src = source as TableBase;
  410. FixedRows = src.FixedRows;
  411. FixedColumns = src.FixedColumns;
  412. PrintOnParent = src.PrintOnParent;
  413. RepeatHeaders = src.RepeatHeaders;
  414. RepeatRowHeaders = src.RepeatRowHeaders;
  415. RepeatColumnHeaders = src.RepeatColumnHeaders;
  416. Layout = src.Layout;
  417. WrappedGap = src.WrappedGap;
  418. AdjustSpannedCellsWidth = src.AdjustSpannedCellsWidth;
  419. }
  420. /// <inheritdoc/>
  421. public override void Draw(FRPaintEventArgs e)
  422. {
  423. if (ColumnCount == 0 || RowCount == 0)
  424. return;
  425. lockColumnRowChange = true;
  426. Width = Columns[Columns.Count - 1].Right;
  427. Height = Rows[Rows.Count - 1].Bottom;
  428. lockColumnRowChange = false;
  429. base.Draw(e);
  430. // draw table Right to Left if needed
  431. if (Config.RightToLeft)
  432. {
  433. DrawTableRtl(e);
  434. }
  435. else
  436. {
  437. DrawTable(e);
  438. }
  439. Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
  440. DrawDesign(e);
  441. }
  442. /// <inheritdoc/>
  443. public override bool IsVisible(FRPaintEventArgs e)
  444. {
  445. if (RowCount == 0 || ColumnCount == 0)
  446. return false;
  447. Width = Columns[Columns.Count - 1].Right;
  448. Height = Rows[Rows.Count - 1].Bottom;
  449. RectangleF objRect = new RectangleF(AbsLeft * e.ScaleX, AbsTop * e.ScaleY,
  450. Width * e.ScaleX + 1, Height * e.ScaleY + 1);
  451. return e.Graphics.IsVisible(objRect);
  452. }
  453. internal void SetResultTable(TableResult table)
  454. {
  455. resultTable = table;
  456. }
  457. /// <summary>
  458. /// Gets data of the table cell with specified column and row numbers.
  459. /// </summary>
  460. /// <param name="col">The column number.</param>
  461. /// <param name="row">The row number.</param>
  462. /// <returns>TableCellData instance containing data of the table cell.</returns>
  463. public TableCellData GetCellData(int col, int row)
  464. {
  465. if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
  466. return null;
  467. return rows[row].CellData(col);
  468. }
  469. internal List<Rectangle> GetSpanList()
  470. {
  471. if (spanList == null)
  472. {
  473. spanList = new List<Rectangle>();
  474. for (int y = 0; y < Rows.Count; y++)
  475. {
  476. for (int x = 0; x < Columns.Count; x++)
  477. {
  478. TableCellData cell = GetCellData(x, y);
  479. if (cell.ColSpan > 1 || cell.RowSpan > 1)
  480. spanList.Add(new Rectangle(x, y, cell.ColSpan, cell.RowSpan));
  481. }
  482. }
  483. }
  484. return spanList;
  485. }
  486. internal void ResetSpanList()
  487. {
  488. spanList = null;
  489. }
  490. internal void CorrectSpansOnRowChange(int rowIndex, int correct)
  491. {
  492. if (lockCorrectSpans || (correct == 1 && rowIndex >= Rows.Count))
  493. return;
  494. for (int y = 0; y < rowIndex; y++)
  495. {
  496. for (int x = 0; x < Columns.Count; x++)
  497. {
  498. TableCellData cell = GetCellData(x, y);
  499. if (rowIndex < y + cell.RowSpan)
  500. cell.RowSpan += correct;
  501. }
  502. }
  503. ResetSpanList();
  504. }
  505. internal void CorrectSpansOnColumnChange(int columnIndex, int correct)
  506. {
  507. if (lockCorrectSpans || (correct == 1 && columnIndex >= Columns.Count))
  508. return;
  509. for (int y = 0; y < Rows.Count; y++)
  510. {
  511. for (int x = 0; x < columnIndex; x++)
  512. {
  513. TableCellData cell = GetCellData(x, y);
  514. if (columnIndex < x + cell.ColSpan)
  515. cell.ColSpan += correct;
  516. }
  517. // correct cells
  518. Rows[y].CorrectCellsOnColumnChange(columnIndex, correct);
  519. }
  520. ResetSpanList();
  521. }
  522. public bool IsInsideSpan(TableCell cell)
  523. {
  524. Point address = cell.Address;
  525. List<Rectangle> spans = GetSpanList();
  526. foreach (Rectangle span in spans)
  527. {
  528. if (span.Contains(address) && span.Location != address)
  529. return true;
  530. }
  531. return false;
  532. }
  533. /// <summary>
  534. /// Creates unique names for all table elements such as rows, columns, cells.
  535. /// </summary>
  536. public void CreateUniqueNames()
  537. {
  538. if (Report == null)
  539. return;
  540. FastNameCreator nameCreator = new FastNameCreator(Report.AllNamedObjects);
  541. foreach (TableRow row in Rows)
  542. {
  543. if (String.IsNullOrEmpty(row.Name))
  544. nameCreator.CreateUniqueName(row);
  545. }
  546. foreach (TableColumn column in Columns)
  547. {
  548. if (String.IsNullOrEmpty(column.Name))
  549. nameCreator.CreateUniqueName(column);
  550. }
  551. for (int y = 0; y < Rows.Count; y++)
  552. {
  553. for (int x = 0; x < Columns.Count; x++)
  554. {
  555. TableCell cell = this[x, y];
  556. if (String.IsNullOrEmpty(cell.Name))
  557. {
  558. nameCreator.CreateUniqueName(cell);
  559. cell.Font = DrawUtils.DefaultReportFont;
  560. }
  561. if (cell.Objects != null)
  562. {
  563. foreach (ReportComponentBase obj in cell.Objects)
  564. {
  565. if (String.IsNullOrEmpty(obj.Name))
  566. nameCreator.CreateUniqueName(obj);
  567. }
  568. }
  569. }
  570. }
  571. }
  572. /// <inheritdoc/>
  573. public override void Serialize(FRWriter writer)
  574. {
  575. TableBase c = writer.DiffObject as TableBase;
  576. serializingToPreview = writer.SerializeTo == SerializeTo.Preview;
  577. base.Serialize(writer);
  578. if (FixedRows != c.FixedRows)
  579. writer.WriteInt("FixedRows", FixedRows);
  580. if (FixedColumns != c.FixedColumns)
  581. writer.WriteInt("FixedColumns", FixedColumns);
  582. if (PrintOnParent != c.PrintOnParent)
  583. writer.WriteBool("PrintOnParent", PrintOnParent);
  584. if (RepeatHeaders != c.RepeatHeaders)
  585. writer.WriteBool("RepeatHeaders", RepeatHeaders);
  586. if (RepeatRowHeaders != c.RepeatRowHeaders)
  587. writer.WriteBool("RepeatRowHeaders", RepeatRowHeaders);
  588. if (RepeatColumnHeaders != c.RepeatColumnHeaders)
  589. writer.WriteBool("RepeatColumnHeaders", RepeatColumnHeaders);
  590. if (Layout != c.Layout)
  591. writer.WriteValue("Layout", Layout);
  592. if (WrappedGap != c.WrappedGap)
  593. writer.WriteFloat("WrappedGap", WrappedGap);
  594. if (AdjustSpannedCellsWidth != c.AdjustSpannedCellsWidth)
  595. writer.WriteBool("AdjustSpannedCellsWidth", AdjustSpannedCellsWidth);
  596. }
  597. internal void EmulateOuterBorder()
  598. {
  599. for (int y = 0; y < RowCount; y++)
  600. {
  601. for (int x = 0; x < ColumnCount; x++)
  602. {
  603. TableCell cell = this[x, y];
  604. if (x == 0 && (Border.Lines & BorderLines.Left) != 0)
  605. {
  606. cell.Border.LeftLine.Assign(Border.LeftLine);
  607. cell.Border.Lines |= BorderLines.Left;
  608. }
  609. if (x + cell.ColSpan == ColumnCount && (Border.Lines & BorderLines.Right) != 0)
  610. {
  611. cell.Border.RightLine.Assign(Border.RightLine);
  612. cell.Border.Lines |= BorderLines.Right;
  613. }
  614. if (y == 0 && (Border.Lines & BorderLines.Top) != 0)
  615. {
  616. cell.Border.TopLine.Assign(Border.TopLine);
  617. cell.Border.Lines |= BorderLines.Top;
  618. }
  619. if (y + cell.RowSpan == RowCount && (Border.Lines & BorderLines.Bottom) != 0)
  620. {
  621. cell.Border.BottomLine.Assign(Border.BottomLine);
  622. cell.Border.Lines |= BorderLines.Bottom;
  623. }
  624. }
  625. }
  626. }
  627. #endregion
  628. #region IParent Members
  629. /// <inheritdoc/>
  630. public bool CanContain(Base child)
  631. {
  632. return child is TableRow || child is TableColumn || child is TableCell;
  633. }
  634. /// <inheritdoc/>
  635. public virtual void GetChildObjects(ObjectCollection list)
  636. {
  637. foreach (TableColumn column in Columns)
  638. {
  639. // Apply visible expression if needed.
  640. if (serializingToPreview && !String.IsNullOrEmpty(column.VisibleExpression))
  641. column.Visible = CalcVisibleExpression(column.VisibleExpression);
  642. if (!serializingToPreview || column.Visible)
  643. list.Add(column);
  644. }
  645. foreach (TableRow row in Rows)
  646. {
  647. // Apply visible expression if needed.
  648. if (serializingToPreview && !String.IsNullOrEmpty(row.VisibleExpression))
  649. row.Visible = CalcVisibleExpression(row.VisibleExpression);
  650. if (!serializingToPreview || row.Visible)
  651. list.Add(row);
  652. }
  653. }
  654. /// <inheritdoc/>
  655. public void AddChild(Base child)
  656. {
  657. if (child is TableRow)
  658. Rows.Add(child as TableRow);
  659. else if (child is TableColumn)
  660. Columns.Add(child as TableColumn);
  661. }
  662. /// <inheritdoc/>
  663. public void RemoveChild(Base child)
  664. {
  665. if (child is TableRow)
  666. Rows.Remove(child as TableRow);
  667. else if (child is TableColumn)
  668. Columns.Remove(child as TableColumn);
  669. }
  670. /// <inheritdoc/>
  671. public int GetChildOrder(Base child)
  672. {
  673. if (child is TableColumn)
  674. return Columns.IndexOf(child as TableColumn);
  675. else if (child is TableRow)
  676. return Rows.IndexOf(child as TableRow);
  677. return 0;
  678. }
  679. /// <inheritdoc/>
  680. public void SetChildOrder(Base child, int order)
  681. {
  682. lockCorrectSpans = true;
  683. int oldOrder = child.ZOrder;
  684. if (oldOrder != -1 && order != -1 && oldOrder != order)
  685. {
  686. if (child is TableColumn)
  687. {
  688. if (order > Columns.Count)
  689. order = Columns.Count;
  690. if (oldOrder <= order)
  691. order--;
  692. Columns.Remove(child as TableColumn);
  693. Columns.Insert(order, child as TableColumn);
  694. }
  695. else if (child is TableRow)
  696. {
  697. if (order > Rows.Count)
  698. order = Rows.Count;
  699. if (oldOrder <= order)
  700. order--;
  701. Rows.Remove(child as TableRow);
  702. Rows.Insert(order, child as TableRow);
  703. }
  704. }
  705. lockCorrectSpans = false;
  706. }
  707. /// <inheritdoc/>
  708. public void UpdateLayout(float dx, float dy)
  709. {
  710. }
  711. #endregion
  712. #region Report Engine
  713. /// <inheritdoc/>
  714. public override void SaveState()
  715. {
  716. base.SaveState();
  717. foreach (TableRow row in Rows)
  718. {
  719. row.SaveState();
  720. }
  721. foreach (TableColumn column in Columns)
  722. {
  723. column.SaveState();
  724. }
  725. for (int y = 0; y < Rows.Count; y++)
  726. {
  727. for (int x = 0; x < Columns.Count; x++)
  728. {
  729. this[x, y].SaveState();
  730. }
  731. }
  732. CanGrow = true;
  733. CanShrink = true;
  734. }
  735. /// <inheritdoc/>
  736. public override void RestoreState()
  737. {
  738. base.RestoreState();
  739. foreach (TableRow row in Rows)
  740. {
  741. row.RestoreState();
  742. }
  743. foreach (TableColumn column in Columns)
  744. {
  745. column.RestoreState();
  746. }
  747. for (int y = 0; y < Rows.Count; y++)
  748. {
  749. for (int x = 0; x < Columns.Count; x++)
  750. {
  751. this[x, y].RestoreState();
  752. }
  753. }
  754. }
  755. /// <summary>
  756. /// Calculates and returns the table width, in pixels.
  757. /// </summary>
  758. public float CalcWidth()
  759. {
  760. // first pass, calc non-spanned cells
  761. for (int x = 0; x < Columns.Count; x++)
  762. {
  763. TableColumn column = Columns[x];
  764. if (!column.AutoSize)
  765. continue;
  766. float columnWidth = IsDesigning ? 16 : -1;
  767. // calc the max column width
  768. for (int y = 0; y < Rows.Count; y++)
  769. {
  770. TableCellData cell = GetCellData(x, y);
  771. if (cell.ColSpan == 1)
  772. {
  773. float cellWidth = cell.CalcWidth();
  774. if (cellWidth > columnWidth)
  775. columnWidth = cellWidth;
  776. }
  777. }
  778. // update column width
  779. if (columnWidth != -1)
  780. column.Width = columnWidth;
  781. }
  782. // second pass, calc spanned cells
  783. for (int x = 0; x < Columns.Count; x++)
  784. {
  785. Columns[x].MinimumBreakWidth = 0;
  786. for (int y = 0; y < Rows.Count; y++)
  787. {
  788. TableCellData cell = GetCellData(x, y);
  789. if (cell.ColSpan > 1)
  790. {
  791. float cellWidth = cell.CalcWidth();
  792. if (AdjustSpannedCellsWidth && cellWidth > Columns[x].MinimumBreakWidth)
  793. Columns[x].MinimumBreakWidth = cellWidth;
  794. // check that spanned columns have enough width
  795. float columnsWidth = 0;
  796. for (int i = 0; i < cell.ColSpan; i++)
  797. {
  798. columnsWidth += Columns[Math.Min(Columns.Count-1,x + i)].Width;
  799. }
  800. // if cell is bigger than sum of column width, increase the last column width
  801. TableColumn lastColumn = Columns[Math.Min(Columns.Count-1,x + cell.ColSpan - 1)];
  802. if (columnsWidth < cellWidth && lastColumn.AutoSize)
  803. lastColumn.Width += cellWidth - columnsWidth;
  804. }
  805. }
  806. }
  807. // finally, calculate the table width
  808. float width = 0;
  809. for (int i = 0; i < Columns.Count; i++)
  810. {
  811. width += Columns[i].Width;
  812. }
  813. lockColumnRowChange = true;
  814. Width = width;
  815. lockColumnRowChange = false;
  816. return width;
  817. }
  818. /// <inheritdoc/>
  819. public override float CalcHeight()
  820. {
  821. if (ColumnCount * RowCount > 1000)
  822. Config.ReportSettings.OnProgress(Report, Res.Get("ComponentsMisc,Table,CalcBounds"), 0, 0);
  823. // calc width
  824. CalcWidth();
  825. // first pass, calc non-spanned cells
  826. for (int y = 0; y < Rows.Count; y++)
  827. {
  828. TableRow row = Rows[y];
  829. if (!row.AutoSize)
  830. continue;
  831. float rowHeight = IsDesigning ? 16 : -1;
  832. // calc the max row height
  833. for (int x = 0; x < Columns.Count; x++)
  834. {
  835. TableCellData cell = GetCellData(x, y);
  836. if (cell.RowSpan == 1)
  837. {
  838. float cellHeight = cell.CalcHeight(cell.Width);
  839. if (cellHeight > rowHeight)
  840. rowHeight = cellHeight;
  841. }
  842. }
  843. // update row height
  844. if (rowHeight != -1)
  845. row.Height = rowHeight;
  846. }
  847. // second pass, calc spanned cells
  848. for (int y = 0; y < Rows.Count; y++)
  849. {
  850. for (int x = 0; x < Columns.Count; x++)
  851. {
  852. TableCellData cell = GetCellData(x, y);
  853. if (cell.RowSpan > 1)
  854. {
  855. float cellHeight = cell.CalcHeight(cell.Width);
  856. // check that spanned rows have enough height
  857. float rowsHeight = 0;
  858. for (int i = 0; i < cell.RowSpan; i++)
  859. {
  860. if (y + i < Rows.Count)
  861. rowsHeight += Rows[y + i].Height;
  862. else
  863. {
  864. // Error, we don't have row, rowSpan has incorrect
  865. cell.RowSpan--;
  866. }
  867. }
  868. // if cell is bigger than sum of row heights, increase the last row height
  869. if (y + cell.RowSpan - 1 < Rows.Count)
  870. {
  871. TableRow lastRow = Rows[y + cell.RowSpan - 1];
  872. if (rowsHeight < cellHeight && lastRow.AutoSize)
  873. lastRow.Height += cellHeight - rowsHeight;
  874. }
  875. }
  876. }
  877. }
  878. // finally, calculate the table height
  879. float height = 0;
  880. for (int i = 0; i < Rows.Count; i++)
  881. {
  882. height += Rows[i].Visible ? Rows[i].Height : 0;
  883. }
  884. return height;
  885. }
  886. private bool CanBreakRow(int rowIndex, float rowHeight)
  887. {
  888. if (!Rows[rowIndex].CanBreak)
  889. return false;
  890. // check each cell in the row
  891. for (int i = 0; i < ColumnCount; i++)
  892. {
  893. TableCell breakable = this[i, rowIndex];
  894. // use clone object because Break method will modify the Text property
  895. using (TableCell clone = new TableCell())
  896. {
  897. clone.AssignAll(breakable);
  898. clone.Height = rowHeight;
  899. clone.SetReport(Report);
  900. if (!clone.Break(null))
  901. return false;
  902. }
  903. }
  904. return true;
  905. }
  906. private void BreakRow(TableBase breakTo, int rowIndex, float rowHeight, float newRowHeight)
  907. {
  908. // set rows height
  909. TableRow rowTo = breakTo.Rows[rowIndex];
  910. Rows[rowIndex].Height = rowHeight;
  911. rowTo.Height = newRowHeight;
  912. // break each cell in the row
  913. for (int i = 0; i < ColumnCount; i++)
  914. {
  915. TableCell cell = this[i, rowIndex];
  916. TableCell cellTo = breakTo[i, rowIndex];
  917. cell.Height = rowHeight;
  918. cell.Break(cellTo);
  919. // fix height if row is not autosized
  920. if (!rowTo.AutoSize)
  921. {
  922. float h = cellTo.CalcHeight();
  923. if (h > rowTo.Height)
  924. rowTo.Height = h;
  925. }
  926. }
  927. }
  928. /// <inheritdoc/>
  929. public override bool Break(BreakableComponent breakTo)
  930. {
  931. if (Rows.Count == 0)
  932. return true;
  933. if (Height < Rows[0].Height && !Rows[0].CanBreak)
  934. return false;
  935. TableBase tableTo = breakTo as TableBase;
  936. if (tableTo == null)
  937. return true;
  938. // find the break row index
  939. int breakRowIndex = 0;
  940. int breakRowIndexAdd = 0;
  941. bool rowBroken = false;
  942. float rowsHeight = 0;
  943. while (breakRowIndex < Rows.Count)
  944. {
  945. rowsHeight += Rows[breakRowIndex].Height;
  946. if (rowsHeight > Height)
  947. {
  948. float breakRowHeight = Rows[breakRowIndex].Height - (rowsHeight - Height);
  949. if (CanBreakRow(breakRowIndex, breakRowHeight))
  950. {
  951. BreakRow(tableTo, breakRowIndex, breakRowHeight, rowsHeight - Height);
  952. breakRowIndexAdd = 1;
  953. rowBroken = true;
  954. }
  955. break;
  956. }
  957. breakRowIndex++;
  958. }
  959. // get the span list
  960. List<Rectangle> spans = GetSpanList();
  961. // break the spans
  962. foreach (Rectangle span in spans)
  963. {
  964. if (span.Top < breakRowIndex + breakRowIndexAdd && span.Bottom > breakRowIndex)
  965. {
  966. TableCell cell = this[span.Left, span.Top];
  967. TableCell cellTo = tableTo[span.Left, span.Top];
  968. // update cell spans
  969. cell.RowSpan = breakRowIndex + breakRowIndexAdd - span.Top;
  970. cellTo.RowSpan = span.Bottom - breakRowIndex;
  971. // break the cell
  972. if (!rowBroken && !cell.Break(cellTo))
  973. cell.Text = "";
  974. // set the top span cell to the correct place
  975. tableTo[span.Left, span.Top] = new TableCell();
  976. tableTo[span.Left, breakRowIndex] = cellTo;
  977. }
  978. }
  979. // remove unused rows from source (this table)
  980. while (breakRowIndex + breakRowIndexAdd < Rows.Count)
  981. {
  982. this.Rows.RemoveAt(Rows.Count - 1);
  983. }
  984. // remove unused rows from copy (tableTo)
  985. for (int i = 0; i < breakRowIndex; i++)
  986. {
  987. tableTo.Rows.RemoveAt(0);
  988. }
  989. return true;
  990. }
  991. private List<TableCellData> GetAggregateCells(TableCell aggregateCell)
  992. {
  993. List<TableCellData> list = new List<TableCellData>();
  994. // columnIndex, rowIndex is a place where we will print a result.
  995. // To collect aggregate values that will be used to calculate a result, we need to go
  996. // to the left and top from this point and collect every cell which OriginalCell is equal to
  997. // the aggregateCell value. We have to stop when we meet the same row or column.
  998. int columnIndex = PrintingCell.Address.X;
  999. int rowIndex = PrintingCell.Address.Y;
  1000. TableColumn startColumn = ResultTable.Columns[columnIndex];
  1001. TableRow startRow = ResultTable.Rows[rowIndex];
  1002. TableColumn aggregateColumn = Columns[aggregateCell.Address.X];
  1003. TableRow aggregateRow = Rows[aggregateCell.Address.Y];
  1004. // check if result is in the same row/column as aggregate cell
  1005. bool sameRow = startRow.OriginalComponent == aggregateRow.OriginalComponent;
  1006. bool sameColumn = startColumn.OriginalComponent == aggregateColumn.OriginalComponent;
  1007. for (int y = rowIndex; y >= 0; y--)
  1008. {
  1009. if (y != rowIndex && ResultTable.Rows[y].OriginalComponent == startRow.OriginalComponent)
  1010. break;
  1011. for (int x = columnIndex; x >= 0; x--)
  1012. {
  1013. if (x != columnIndex && ResultTable.Columns[x].OriginalComponent == startColumn.OriginalComponent)
  1014. break;
  1015. TableCellData cell = ResultTable.GetCellData(x, y);
  1016. if (cell.OriginalCell == aggregateCell)
  1017. list.Add(cell);
  1018. if (sameColumn)
  1019. break;
  1020. }
  1021. if (sameRow)
  1022. break;
  1023. }
  1024. return list;
  1025. }
  1026. /// <summary>
  1027. /// Calculates a sum of values in a specified cell.
  1028. /// </summary>
  1029. /// <param name="aggregateCell">The cell.</param>
  1030. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1031. /// <remarks>
  1032. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1033. /// </remarks>
  1034. public object Sum(TableCell aggregateCell)
  1035. {
  1036. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1037. Variant result = 0;
  1038. bool firstTime = true;
  1039. foreach (TableCellData cell in list)
  1040. {
  1041. if (cell.Value != null)
  1042. {
  1043. Variant varValue = new Variant(cell.Value);
  1044. if (firstTime)
  1045. result = varValue;
  1046. else
  1047. result += varValue;
  1048. firstTime = false;
  1049. }
  1050. }
  1051. return result.Value;
  1052. }
  1053. /// <summary>
  1054. /// Calculates a minimum of values in a specified cell.
  1055. /// </summary>
  1056. /// <param name="aggregateCell">The cell.</param>
  1057. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1058. /// <remarks>
  1059. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1060. /// </remarks>
  1061. public object Min(TableCell aggregateCell)
  1062. {
  1063. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1064. Variant result = float.PositiveInfinity;
  1065. bool firstTime = true;
  1066. foreach (TableCellData cell in list)
  1067. {
  1068. if (cell.Value != null)
  1069. {
  1070. Variant varValue = new Variant(cell.Value);
  1071. if (firstTime || varValue < result)
  1072. result = varValue;
  1073. firstTime = false;
  1074. }
  1075. }
  1076. return result.Value;
  1077. }
  1078. /// <summary>
  1079. /// Calculates a maximum of values in a specified cell.
  1080. /// </summary>
  1081. /// <param name="aggregateCell">The cell.</param>
  1082. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1083. /// <remarks>
  1084. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1085. /// </remarks>
  1086. public object Max(TableCell aggregateCell)
  1087. {
  1088. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1089. Variant result = float.NegativeInfinity;
  1090. bool firstTime = true;
  1091. foreach (TableCellData cell in list)
  1092. {
  1093. if (cell.Value != null)
  1094. {
  1095. Variant varValue = new Variant(cell.Value);
  1096. if (firstTime || varValue > result)
  1097. result = varValue;
  1098. firstTime = false;
  1099. }
  1100. }
  1101. return result.Value;
  1102. }
  1103. /// <summary>
  1104. /// Calculates an average of values in a specified cell.
  1105. /// </summary>
  1106. /// <param name="aggregateCell">The cell.</param>
  1107. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1108. /// <remarks>
  1109. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1110. /// </remarks>
  1111. public object Avg(TableCell aggregateCell)
  1112. {
  1113. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1114. Variant result = 0;
  1115. int count = 0;
  1116. bool firstTime = true;
  1117. foreach (TableCellData cell in list)
  1118. {
  1119. if (cell.Value != null)
  1120. {
  1121. Variant varValue = new Variant(cell.Value);
  1122. if (firstTime)
  1123. result = varValue;
  1124. else
  1125. result += varValue;
  1126. count++;
  1127. firstTime = false;
  1128. }
  1129. }
  1130. return result / (count == 0 ? 1 : count);
  1131. }
  1132. /// <summary>
  1133. /// Calculates number of repeats of a specified cell.
  1134. /// </summary>
  1135. /// <param name="aggregateCell">The cell.</param>
  1136. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1137. /// <remarks>
  1138. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1139. /// </remarks>
  1140. public object Count(TableCell aggregateCell)
  1141. {
  1142. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1143. int count = 0;
  1144. foreach (TableCellData cell in list)
  1145. {
  1146. if (cell.Value != null)
  1147. count++;
  1148. }
  1149. return count;
  1150. }
  1151. #endregion
  1152. /// <summary>
  1153. /// Initializes a new instance of the <see cref="TableBase"/> class.
  1154. /// </summary>
  1155. public TableBase()
  1156. {
  1157. rows = new TableRowCollection(this);
  1158. columns = new TableColumnCollection(this);
  1159. styles = new TableStyleCollection();
  1160. repeatHeaders = true;
  1161. repeatRowHeaders = false;
  1162. repeatColumnHeaders = false;
  1163. CanGrow = true;
  1164. CanShrink = true;
  1165. }
  1166. }
  1167. }