TableBase.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324
  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. proc(e, cell);
  318. }
  319. left += width;
  320. }
  321. top += height;
  322. }
  323. }
  324. private void DrawCellsRtl(FRPaintEventArgs e, DrawCellProc proc)
  325. {
  326. float top = 0;
  327. for (int y = 0; y < Rows.Count; y++)
  328. {
  329. float left = 0;
  330. float height = Rows[y].Height;
  331. //bool thereIsColSpan = false;
  332. //for (int i = Columns.Count - 1; i >= 0; i--)
  333. //{
  334. // TableCell cell = this[i, y];
  335. // if (cell.ColSpan > 1)
  336. // {
  337. // thereIsColSpan = true;
  338. // }
  339. //}
  340. for (int x = Columns.Count - 1; x >= 0; x--)
  341. {
  342. TableCell cell = this[x, y];
  343. bool thereIsColSpan = false;
  344. if (cell.ColSpan > 1)
  345. {
  346. thereIsColSpan = true;
  347. }
  348. float width = Columns[x].Width;
  349. //if (thereIsColSpan)
  350. //{
  351. // width *= cell.ColSpan - 1;
  352. // left -= width;
  353. //}
  354. if (!IsInsideSpan(cell) && (!IsPrinting || cell.Printable))
  355. {
  356. cell.Left = left;
  357. cell.Top = top;
  358. cell.SetPrinting(IsPrinting);
  359. proc(e, cell);
  360. if (thereIsColSpan)
  361. width *= cell.ColSpan;
  362. left += width;
  363. }
  364. //if (!thereIsColSpan)
  365. // left += width;
  366. //else
  367. // left -= width;
  368. }
  369. top += height;
  370. }
  371. }
  372. private void DrawFill(FRPaintEventArgs e, TableCell cell)
  373. {
  374. cell.DrawBackground(e);
  375. }
  376. private void DrawText(FRPaintEventArgs e, TableCell cell)
  377. {
  378. cell.DrawText(e);
  379. }
  380. private void DrawBorders(FRPaintEventArgs e, TableCell cell)
  381. {
  382. cell.Border.Draw(e, cell.AbsBounds);
  383. }
  384. private void DrawTable(FRPaintEventArgs e)
  385. {
  386. DrawCells(e, DrawFill);
  387. DrawCells(e, DrawText);
  388. DrawDesign_Borders(e);
  389. DrawCells(e, DrawBorders);
  390. DrawDesign_SelectedCells(e);
  391. }
  392. private void DrawTableRtl(FRPaintEventArgs e)
  393. {
  394. DrawCellsRtl(e, DrawFill);
  395. DrawCellsRtl(e, DrawText);
  396. DrawDesign_BordersRtl(e);
  397. DrawCellsRtl(e, DrawBorders);
  398. DrawDesign_SelectedCellsRtl(e);
  399. }
  400. #endregion
  401. #region Public Methods
  402. /// <inheritdoc/>
  403. public override void Assign(Base source)
  404. {
  405. base.Assign(source);
  406. TableBase src = source as TableBase;
  407. FixedRows = src.FixedRows;
  408. FixedColumns = src.FixedColumns;
  409. PrintOnParent = src.PrintOnParent;
  410. RepeatHeaders = src.RepeatHeaders;
  411. RepeatRowHeaders = src.RepeatRowHeaders;
  412. RepeatColumnHeaders = src.RepeatColumnHeaders;
  413. Layout = src.Layout;
  414. WrappedGap = src.WrappedGap;
  415. AdjustSpannedCellsWidth = src.AdjustSpannedCellsWidth;
  416. }
  417. /// <inheritdoc/>
  418. public override void Draw(FRPaintEventArgs e)
  419. {
  420. if (ColumnCount == 0 || RowCount == 0)
  421. return;
  422. lockColumnRowChange = true;
  423. Width = Columns[Columns.Count - 1].Right;
  424. Height = Rows[Rows.Count - 1].Bottom;
  425. lockColumnRowChange = false;
  426. base.Draw(e);
  427. // draw table Right to Left if needed
  428. if (Config.RightToLeft)
  429. {
  430. DrawTableRtl(e);
  431. // !! ����������� ������ !!
  432. //Border.Draw(e, new RectangleF(FLeftRtl - Width + AbsLeft, AbsTop, Width, Height));
  433. Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
  434. }
  435. else
  436. {
  437. DrawTable(e);
  438. Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
  439. }
  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. if (!serializingToPreview || column.Visible)
  640. list.Add(column);
  641. }
  642. foreach (TableRow row in Rows)
  643. {
  644. if (!serializingToPreview || row.Visible)
  645. list.Add(row);
  646. }
  647. }
  648. /// <inheritdoc/>
  649. public void AddChild(Base child)
  650. {
  651. if (child is TableRow)
  652. Rows.Add(child as TableRow);
  653. else if (child is TableColumn)
  654. Columns.Add(child as TableColumn);
  655. }
  656. /// <inheritdoc/>
  657. public void RemoveChild(Base child)
  658. {
  659. if (child is TableRow)
  660. Rows.Remove(child as TableRow);
  661. else if (child is TableColumn)
  662. Columns.Remove(child as TableColumn);
  663. }
  664. /// <inheritdoc/>
  665. public int GetChildOrder(Base child)
  666. {
  667. if (child is TableColumn)
  668. return Columns.IndexOf(child as TableColumn);
  669. else if (child is TableRow)
  670. return Rows.IndexOf(child as TableRow);
  671. return 0;
  672. }
  673. /// <inheritdoc/>
  674. public void SetChildOrder(Base child, int order)
  675. {
  676. lockCorrectSpans = true;
  677. int oldOrder = child.ZOrder;
  678. if (oldOrder != -1 && order != -1 && oldOrder != order)
  679. {
  680. if (child is TableColumn)
  681. {
  682. if (order > Columns.Count)
  683. order = Columns.Count;
  684. if (oldOrder <= order)
  685. order--;
  686. Columns.Remove(child as TableColumn);
  687. Columns.Insert(order, child as TableColumn);
  688. }
  689. else if (child is TableRow)
  690. {
  691. if (order > Rows.Count)
  692. order = Rows.Count;
  693. if (oldOrder <= order)
  694. order--;
  695. Rows.Remove(child as TableRow);
  696. Rows.Insert(order, child as TableRow);
  697. }
  698. }
  699. lockCorrectSpans = false;
  700. }
  701. /// <inheritdoc/>
  702. public void UpdateLayout(float dx, float dy)
  703. {
  704. }
  705. #endregion
  706. #region Report Engine
  707. /// <inheritdoc/>
  708. public override void SaveState()
  709. {
  710. base.SaveState();
  711. foreach (TableRow row in Rows)
  712. {
  713. row.SaveState();
  714. }
  715. foreach (TableColumn column in Columns)
  716. {
  717. column.SaveState();
  718. }
  719. for (int y = 0; y < Rows.Count; y++)
  720. {
  721. for (int x = 0; x < Columns.Count; x++)
  722. {
  723. this[x, y].SaveState();
  724. }
  725. }
  726. CanGrow = true;
  727. CanShrink = true;
  728. }
  729. /// <inheritdoc/>
  730. public override void RestoreState()
  731. {
  732. base.RestoreState();
  733. foreach (TableRow row in Rows)
  734. {
  735. row.RestoreState();
  736. }
  737. foreach (TableColumn column in Columns)
  738. {
  739. column.RestoreState();
  740. }
  741. for (int y = 0; y < Rows.Count; y++)
  742. {
  743. for (int x = 0; x < Columns.Count; x++)
  744. {
  745. this[x, y].RestoreState();
  746. }
  747. }
  748. }
  749. /// <summary>
  750. /// Calculates and returns the table width, in pixels.
  751. /// </summary>
  752. public float CalcWidth()
  753. {
  754. // first pass, calc non-spanned cells
  755. for (int x = 0; x < Columns.Count; x++)
  756. {
  757. TableColumn column = Columns[x];
  758. if (!column.AutoSize)
  759. continue;
  760. float columnWidth = IsDesigning ? 16 : -1;
  761. // calc the max column width
  762. for (int y = 0; y < Rows.Count; y++)
  763. {
  764. TableCellData cell = GetCellData(x, y);
  765. if (cell.ColSpan == 1)
  766. {
  767. float cellWidth = cell.CalcWidth();
  768. if (cellWidth > columnWidth)
  769. columnWidth = cellWidth;
  770. }
  771. }
  772. // update column width
  773. if (columnWidth != -1)
  774. column.Width = columnWidth;
  775. }
  776. // second pass, calc spanned cells
  777. for (int x = 0; x < Columns.Count; x++)
  778. {
  779. Columns[x].MinimumBreakWidth = 0;
  780. for (int y = 0; y < Rows.Count; y++)
  781. {
  782. TableCellData cell = GetCellData(x, y);
  783. if (cell.ColSpan > 1)
  784. {
  785. float cellWidth = cell.CalcWidth();
  786. if (AdjustSpannedCellsWidth && cellWidth > Columns[x].MinimumBreakWidth)
  787. Columns[x].MinimumBreakWidth = cellWidth;
  788. // check that spanned columns have enough width
  789. float columnsWidth = 0;
  790. for (int i = 0; i < cell.ColSpan; i++)
  791. {
  792. columnsWidth += Columns[x + i].Width;
  793. }
  794. // if cell is bigger than sum of column width, increase the last column width
  795. TableColumn lastColumn = Columns[x + cell.ColSpan - 1];
  796. if (columnsWidth < cellWidth && lastColumn.AutoSize)
  797. lastColumn.Width += cellWidth - columnsWidth;
  798. }
  799. }
  800. }
  801. // finally, calculate the table width
  802. float width = 0;
  803. for (int i = 0; i < Columns.Count; i++)
  804. {
  805. width += Columns[i].Width;
  806. }
  807. lockColumnRowChange = true;
  808. Width = width;
  809. lockColumnRowChange = false;
  810. return width;
  811. }
  812. /// <inheritdoc/>
  813. public override float CalcHeight()
  814. {
  815. if (ColumnCount * RowCount > 1000)
  816. Config.ReportSettings.OnProgress(Report, Res.Get("ComponentsMisc,Table,CalcBounds"), 0, 0);
  817. // calc width
  818. CalcWidth();
  819. // first pass, calc non-spanned cells
  820. for (int y = 0; y < Rows.Count; y++)
  821. {
  822. TableRow row = Rows[y];
  823. if (!row.AutoSize)
  824. continue;
  825. float rowHeight = IsDesigning ? 16 : -1;
  826. // calc the max row height
  827. for (int x = 0; x < Columns.Count; x++)
  828. {
  829. TableCellData cell = GetCellData(x, y);
  830. if (cell.RowSpan == 1)
  831. {
  832. float cellHeight = cell.CalcHeight(cell.Width);
  833. if (cellHeight > rowHeight)
  834. rowHeight = cellHeight;
  835. }
  836. }
  837. // update row height
  838. if (rowHeight != -1)
  839. row.Height = rowHeight;
  840. }
  841. // second pass, calc spanned cells
  842. for (int y = 0; y < Rows.Count; y++)
  843. {
  844. for (int x = 0; x < Columns.Count; x++)
  845. {
  846. TableCellData cell = GetCellData(x, y);
  847. if (cell.RowSpan > 1)
  848. {
  849. float cellHeight = cell.CalcHeight(cell.Width);
  850. // check that spanned rows have enough height
  851. float rowsHeight = 0;
  852. for (int i = 0; i < cell.RowSpan; i++)
  853. {
  854. if (y + i < Rows.Count)
  855. rowsHeight += Rows[y + i].Height;
  856. else
  857. {
  858. // Error, we don't have row, rowSpan has incorrect
  859. cell.RowSpan--;
  860. }
  861. }
  862. // if cell is bigger than sum of row heights, increase the last row height
  863. if (y + cell.RowSpan - 1 < Rows.Count)
  864. {
  865. TableRow lastRow = Rows[y + cell.RowSpan - 1];
  866. if (rowsHeight < cellHeight && lastRow.AutoSize)
  867. lastRow.Height += cellHeight - rowsHeight;
  868. }
  869. }
  870. }
  871. }
  872. // finally, calculate the table height
  873. float height = 0;
  874. for (int i = 0; i < Rows.Count; i++)
  875. {
  876. height += Rows[i].Visible ? Rows[i].Height : 0;
  877. }
  878. return height;
  879. }
  880. private bool CanBreakRow(int rowIndex, float rowHeight)
  881. {
  882. if (!Rows[rowIndex].CanBreak)
  883. return false;
  884. // check each cell in the row
  885. for (int i = 0; i < ColumnCount; i++)
  886. {
  887. TableCell breakable = this[i, rowIndex];
  888. // use clone object because Break method will modify the Text property
  889. using (TableCell clone = new TableCell())
  890. {
  891. clone.AssignAll(breakable);
  892. clone.Height = rowHeight;
  893. clone.SetReport(Report);
  894. if (!clone.Break(null))
  895. return false;
  896. }
  897. }
  898. return true;
  899. }
  900. private void BreakRow(TableBase breakTo, int rowIndex, float rowHeight, float newRowHeight)
  901. {
  902. // set rows height
  903. TableRow rowTo = breakTo.Rows[rowIndex];
  904. Rows[rowIndex].Height = rowHeight;
  905. rowTo.Height = newRowHeight;
  906. // break each cell in the row
  907. for (int i = 0; i < ColumnCount; i++)
  908. {
  909. TableCell cell = this[i, rowIndex];
  910. TableCell cellTo = breakTo[i, rowIndex];
  911. cell.Height = rowHeight;
  912. cell.Break(cellTo);
  913. // fix height if row is not autosized
  914. if (!rowTo.AutoSize)
  915. {
  916. float h = cellTo.CalcHeight();
  917. if (h > rowTo.Height)
  918. rowTo.Height = h;
  919. }
  920. }
  921. }
  922. /// <inheritdoc/>
  923. public override bool Break(BreakableComponent breakTo)
  924. {
  925. if (Rows.Count == 0)
  926. return true;
  927. if (Height < Rows[0].Height && !Rows[0].CanBreak)
  928. return false;
  929. TableBase tableTo = breakTo as TableBase;
  930. if (tableTo == null)
  931. return true;
  932. // find the break row index
  933. int breakRowIndex = 0;
  934. int breakRowIndexAdd = 0;
  935. bool rowBroken = false;
  936. float rowsHeight = 0;
  937. while (breakRowIndex < Rows.Count)
  938. {
  939. rowsHeight += Rows[breakRowIndex].Height;
  940. if (rowsHeight > Height)
  941. {
  942. float breakRowHeight = Rows[breakRowIndex].Height - (rowsHeight - Height);
  943. if (CanBreakRow(breakRowIndex, breakRowHeight))
  944. {
  945. BreakRow(tableTo, breakRowIndex, breakRowHeight, rowsHeight - Height);
  946. breakRowIndexAdd = 1;
  947. rowBroken = true;
  948. }
  949. break;
  950. }
  951. breakRowIndex++;
  952. }
  953. // get the span list
  954. List<Rectangle> spans = GetSpanList();
  955. // break the spans
  956. foreach (Rectangle span in spans)
  957. {
  958. if (span.Top < breakRowIndex + breakRowIndexAdd && span.Bottom > breakRowIndex)
  959. {
  960. TableCell cell = this[span.Left, span.Top];
  961. TableCell cellTo = tableTo[span.Left, span.Top];
  962. // update cell spans
  963. cell.RowSpan = breakRowIndex + breakRowIndexAdd - span.Top;
  964. cellTo.RowSpan = span.Bottom - breakRowIndex;
  965. // break the cell
  966. if (!rowBroken && !cell.Break(cellTo))
  967. cell.Text = "";
  968. // set the top span cell to the correct place
  969. tableTo[span.Left, span.Top] = new TableCell();
  970. tableTo[span.Left, breakRowIndex] = cellTo;
  971. }
  972. }
  973. // remove unused rows from source (this table)
  974. while (breakRowIndex + breakRowIndexAdd < Rows.Count)
  975. {
  976. this.Rows.RemoveAt(Rows.Count - 1);
  977. }
  978. // remove unused rows from copy (tableTo)
  979. for (int i = 0; i < breakRowIndex; i++)
  980. {
  981. tableTo.Rows.RemoveAt(0);
  982. }
  983. return true;
  984. }
  985. private List<TableCellData> GetAggregateCells(TableCell aggregateCell)
  986. {
  987. List<TableCellData> list = new List<TableCellData>();
  988. // columnIndex, rowIndex is a place where we will print a result.
  989. // To collect aggregate values that will be used to calculate a result, we need to go
  990. // to the left and top from this point and collect every cell which OriginalCell is equal to
  991. // the aggregateCell value. We have to stop when we meet the same row or column.
  992. int columnIndex = PrintingCell.Address.X;
  993. int rowIndex = PrintingCell.Address.Y;
  994. TableColumn startColumn = ResultTable.Columns[columnIndex];
  995. TableRow startRow = ResultTable.Rows[rowIndex];
  996. TableColumn aggregateColumn = Columns[aggregateCell.Address.X];
  997. TableRow aggregateRow = Rows[aggregateCell.Address.Y];
  998. // check if result is in the same row/column as aggregate cell
  999. bool sameRow = startRow.OriginalComponent == aggregateRow.OriginalComponent;
  1000. bool sameColumn = startColumn.OriginalComponent == aggregateColumn.OriginalComponent;
  1001. for (int y = rowIndex; y >= 0; y--)
  1002. {
  1003. if (y != rowIndex && ResultTable.Rows[y].OriginalComponent == startRow.OriginalComponent)
  1004. break;
  1005. for (int x = columnIndex; x >= 0; x--)
  1006. {
  1007. if (x != columnIndex && ResultTable.Columns[x].OriginalComponent == startColumn.OriginalComponent)
  1008. break;
  1009. TableCellData cell = ResultTable.GetCellData(x, y);
  1010. if (cell.OriginalCell == aggregateCell)
  1011. list.Add(cell);
  1012. if (sameColumn)
  1013. break;
  1014. }
  1015. if (sameRow)
  1016. break;
  1017. }
  1018. return list;
  1019. }
  1020. /// <summary>
  1021. /// Calculates a sum of values in a specified cell.
  1022. /// </summary>
  1023. /// <param name="aggregateCell">The cell.</param>
  1024. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1025. /// <remarks>
  1026. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1027. /// </remarks>
  1028. public object Sum(TableCell aggregateCell)
  1029. {
  1030. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1031. Variant result = 0;
  1032. bool firstTime = true;
  1033. foreach (TableCellData cell in list)
  1034. {
  1035. if (cell.Value != null)
  1036. {
  1037. Variant varValue = new Variant(cell.Value);
  1038. if (firstTime)
  1039. result = varValue;
  1040. else
  1041. result += varValue;
  1042. firstTime = false;
  1043. }
  1044. }
  1045. return result.Value;
  1046. }
  1047. /// <summary>
  1048. /// Calculates a minimum of values in a specified cell.
  1049. /// </summary>
  1050. /// <param name="aggregateCell">The cell.</param>
  1051. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1052. /// <remarks>
  1053. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1054. /// </remarks>
  1055. public object Min(TableCell aggregateCell)
  1056. {
  1057. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1058. Variant result = float.PositiveInfinity;
  1059. bool firstTime = true;
  1060. foreach (TableCellData cell in list)
  1061. {
  1062. if (cell.Value != null)
  1063. {
  1064. Variant varValue = new Variant(cell.Value);
  1065. if (firstTime || varValue < result)
  1066. result = varValue;
  1067. firstTime = false;
  1068. }
  1069. }
  1070. return result.Value;
  1071. }
  1072. /// <summary>
  1073. /// Calculates a maximum of values in a specified cell.
  1074. /// </summary>
  1075. /// <param name="aggregateCell">The cell.</param>
  1076. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1077. /// <remarks>
  1078. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1079. /// </remarks>
  1080. public object Max(TableCell aggregateCell)
  1081. {
  1082. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1083. Variant result = float.NegativeInfinity;
  1084. bool firstTime = true;
  1085. foreach (TableCellData cell in list)
  1086. {
  1087. if (cell.Value != null)
  1088. {
  1089. Variant varValue = new Variant(cell.Value);
  1090. if (firstTime || varValue > result)
  1091. result = varValue;
  1092. firstTime = false;
  1093. }
  1094. }
  1095. return result.Value;
  1096. }
  1097. /// <summary>
  1098. /// Calculates an average of values in a specified cell.
  1099. /// </summary>
  1100. /// <param name="aggregateCell">The cell.</param>
  1101. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1102. /// <remarks>
  1103. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1104. /// </remarks>
  1105. public object Avg(TableCell aggregateCell)
  1106. {
  1107. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1108. Variant result = 0;
  1109. int count = 0;
  1110. bool firstTime = true;
  1111. foreach (TableCellData cell in list)
  1112. {
  1113. if (cell.Value != null)
  1114. {
  1115. Variant varValue = new Variant(cell.Value);
  1116. if (firstTime)
  1117. result = varValue;
  1118. else
  1119. result += varValue;
  1120. count++;
  1121. firstTime = false;
  1122. }
  1123. }
  1124. return result / (count == 0 ? 1 : count);
  1125. }
  1126. /// <summary>
  1127. /// Calculates number of repeats of a specified cell.
  1128. /// </summary>
  1129. /// <param name="aggregateCell">The cell.</param>
  1130. /// <returns>The <b>object</b> that contains calculated value.</returns>
  1131. /// <remarks>
  1132. /// This method can be called from the <b>ManualBuild</b> event handler only.
  1133. /// </remarks>
  1134. public object Count(TableCell aggregateCell)
  1135. {
  1136. List<TableCellData> list = GetAggregateCells(aggregateCell);
  1137. int count = 0;
  1138. foreach (TableCellData cell in list)
  1139. {
  1140. if (cell.Value != null)
  1141. count++;
  1142. }
  1143. return count;
  1144. }
  1145. #endregion
  1146. /// <summary>
  1147. /// Initializes a new instance of the <see cref="TableBase"/> class.
  1148. /// </summary>
  1149. public TableBase()
  1150. {
  1151. rows = new TableRowCollection(this);
  1152. columns = new TableColumnCollection(this);
  1153. styles = new TableStyleCollection();
  1154. repeatHeaders = true;
  1155. repeatRowHeaders = false;
  1156. repeatColumnHeaders = false;
  1157. CanGrow = true;
  1158. CanShrink = true;
  1159. }
  1160. }
  1161. }