1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330 |
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.ComponentModel;
- using FastReport.Utils;
- namespace FastReport.Table
- {
- /// <summary>
- /// Specifies the layout that will be used when printing a big table.
- /// </summary>
- public enum TableLayout
- {
- /// <summary>
- /// The table is printed across a pages then down.
- /// </summary>
- AcrossThenDown,
- /// <summary>
- /// The table is printed down then across a pages.
- /// </summary>
- DownThenAcross,
- /// <summary>
- /// The table is wrapped.
- /// </summary>
- Wrapped
- }
- /// <summary>
- /// The base class for table-type controls such as <see cref="TableObject"/> and
- /// <see cref="FastReport.Matrix.MatrixObject"/>.
- /// </summary>
- public partial class TableBase : BreakableComponent, IParent
- {
- #region Fields
- private TableRowCollection rows;
- private TableColumnCollection columns;
- private TableStyleCollection styles;
- private int fixedRows;
- private int fixedColumns;
- private bool printOnParent;
- private float wrappedGap;
- private bool repeatHeaders;
- private bool repeatRowHeaders;
- private bool repeatColumnHeaders;
- private bool adjustSpannedCellsWidth;
- private bool lockCorrectSpans;
- private bool serializingToPreview;
- private bool lockColumnRowChange;
- private TableLayout layout;
- private List<Rectangle> spanList;
- private TableResult resultTable;
- private TableCellData printingCell;
- //private static float FLeftRtl;
- #endregion
- #region Properties
- /// <summary>
- /// Gets a collection of table rows.
- /// </summary>
- [Browsable(false)]
- public TableRowCollection Rows
- {
- get { return rows; }
- }
- /// <summary>
- /// Gets a collection of table columns.
- /// </summary>
- [Browsable(false)]
- public TableColumnCollection Columns
- {
- get { return columns; }
- }
- internal TableStyleCollection Styles
- {
- get { return styles; }
- }
- /// <summary>
- /// Gets or sets the number of fixed rows that will be repeated on each page.
- /// </summary>
- [DefaultValue(0)]
- [Category("Layout")]
- public int FixedRows
- {
- get
- {
- int value = fixedRows;
- if (value >= Rows.Count)
- value = Rows.Count - 1;
- if (value < 0)
- value = 0;
- return value;
- }
- set { fixedRows = value; }
- }
- /// <summary>
- /// Gets or sets the number of fixed columns that will be repeated on each page.
- /// </summary>
- [DefaultValue(0)]
- [Category("Layout")]
- public int FixedColumns
- {
- get
- {
- int value = fixedColumns;
- if (value >= Columns.Count)
- value = Columns.Count - 1;
- if (value < 0)
- value = 0;
- return value;
- }
- set { fixedColumns = value; }
- }
- /// <summary>
- /// Gets or sets the value that determines whether to print the dynamic table (or matrix) on its parent band directly.
- /// </summary>
- /// <remarks>
- /// By default the dynamic table (matrix) is printed on its own band and is splitted on pages if necessary.
- /// </remarks>
- [DefaultValue(false)]
- [Category("Layout")]
- public bool PrintOnParent
- {
- get { return printOnParent; }
- set { printOnParent = value; }
- }
- /// <summary>
- /// Gets or sets a value that determines whether is necessary to repeat table header on each page.
- /// </summary>
- /// <remarks>
- /// To define a table header, set the <see cref="FixedRows"/> and <see cref="FixedColumns"/>
- /// properties.
- /// </remarks>
- [DefaultValue(true)]
- [Category("Behavior")]
- public bool RepeatHeaders
- {
- get { return repeatHeaders; }
- set { repeatHeaders = value; }
- }
- /// <summary>
- /// Gets or sets a value that determines whether is necessary to repeat table Row header on each page.
- /// </summary>
- /// <remarks>
- /// To define a table Row header, set the <see cref="FixedRows"/>
- /// properties.
- /// </remarks>
- [Browsable(false)]
- [DefaultValue(false)]
- [Category("Behavior")]
- public virtual bool RepeatRowHeaders
- {
- get { return repeatRowHeaders; }
- set { repeatRowHeaders = value; }
- }
- /// <summary>
- /// Gets or sets a value that determines whether is necessary to repeat table Column header on each page.
- /// </summary>
- /// <remarks>
- /// To define a table Column header, set the <see cref="FixedColumns"/>
- /// properties.
- /// </remarks>
- [Browsable(false)]
- [DefaultValue(false)]
- [Category("Behavior")]
- public virtual bool RepeatColumnHeaders
- {
- get { return repeatColumnHeaders; }
- set { repeatColumnHeaders = value; }
- }
- /// <summary>
- /// Gets or sets the table layout.
- /// </summary>
- /// <remarks>
- /// This property affects printing the big table that breaks across pages.
- /// </remarks>
- [DefaultValue(TableLayout.AcrossThenDown)]
- [Category("Behavior")]
- public TableLayout Layout
- {
- get { return layout; }
- set { layout = value; }
- }
- /// <summary>
- /// Gets or sets gap between parts of the table in wrapped layout mode.
- /// </summary>
- /// <remarks>
- /// This property is used if you set the <see cref="Layout"/> property to <b>Wrapped</b>.
- /// </remarks>
- [DefaultValue(0f)]
- [Category("Behavior")]
- [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
- public float WrappedGap
- {
- get { return wrappedGap; }
- set { wrappedGap = value; }
- }
- /// <summary>
- /// Gets or sets a value that determines whether to adjust the spanned cell's width when breaking the table across pages.
- /// </summary>
- /// <remarks>
- /// If set to <b>true</b>, the spanned cell's width will be adjusted to accomodate all contained text.
- /// </remarks>
- [DefaultValue(false)]
- [Category("Behavior")]
- public bool AdjustSpannedCellsWidth
- {
- get { return adjustSpannedCellsWidth; }
- set { adjustSpannedCellsWidth = value; }
- }
- /// <summary>
- /// Gets or sets the table cell.
- /// </summary>
- /// <param name="col">Column index.</param>
- /// <param name="row">Row index.</param>
- /// <returns>The <b>TableCell</b> object that represents a cell.</returns>
- [Browsable(false)]
- public TableCell this[int col, int row]
- {
- get
- {
- if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
- return null;
- return rows[row][col];
- }
- set
- {
- if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
- return;
- rows[row][col] = value;
- }
- }
- /// <summary>
- /// Gets or sets a number of columns in the table.
- /// </summary>
- [Category("Appearance")]
- public virtual int ColumnCount
- {
- get { return Columns.Count; }
- set
- {
- int n = value - Columns.Count;
- for (int i = 0; i < n; i++)
- {
- TableColumn column = new TableColumn();
- Columns.Add(column);
- }
- while (value < Columns.Count)
- Columns.RemoveAt(Columns.Count - 1);
- }
- }
- /// <summary>
- /// Gets or sets a number of rows in the table.
- /// </summary>
- [Category("Appearance")]
- public virtual int RowCount
- {
- get { return Rows.Count; }
- set
- {
- int n = value - Rows.Count;
- for (int i = 0; i < n; i++)
- {
- TableRow row = new TableRow();
- Rows.Add(row);
- }
- while (value < Rows.Count)
- Rows.RemoveAt(Rows.Count - 1);
- }
- }
- internal bool IsResultTable
- {
- get { return this is TableResult; }
- }
- /// <summary>
- /// Gets a table which contains the result of rendering dynamic table.
- /// </summary>
- /// <remarks>
- /// Use this property to access the result of rendering your table in dynamic mode.
- /// It may be useful if you want to center or right-align the result table on a page.
- /// In this case, you need to add the following code at the end of your ManualBuild event handler:
- /// <code>
- /// // right-align the table
- /// Table1.ResultTable.Left = Engine.PageWidth - Table1.ResultTable.CalcWidth() - 1;
- /// </code>
- /// </remarks>
- [Browsable(false)]
- public TableResult ResultTable
- {
- get { return resultTable; }
- }
- internal TableCellData PrintingCell
- {
- get { return printingCell; }
- set { printingCell = value; }
- }
- internal bool LockCorrectSpans
- {
- get { return lockCorrectSpans; }
- set { lockCorrectSpans = value; }
- }
- #endregion
- #region Private Methods
- private delegate void DrawCellProc(FRPaintEventArgs e, TableCell cell);
- private void DrawCells(FRPaintEventArgs e, DrawCellProc proc)
- {
- float top = 0;
- for (int y = 0; y < Rows.Count; y++)
- {
- float left = 0;
- float height = Rows[y].Height;
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCell cell = this[x, y];
- float width = Columns[x].Width;
- cell.Left = left;
- cell.Top = top;
- if (!IsInsideSpan(cell) && (!IsPrinting || cell.Printable))
- {
- cell.SetPrinting(IsPrinting);
- #if !MONO || (WPF || AVALONIA)
- if (cell.IsVisible(e))
- #endif
- proc(e, cell);
- }
- left += width;
- }
- top += height;
- }
- }
- private void DrawCellsRtl(FRPaintEventArgs e, DrawCellProc proc)
- {
- float top = 0;
- for (int y = 0; y < Rows.Count; y++)
- {
- float left = 0;
- float height = Rows[y].Height;
- //bool thereIsColSpan = false;
- //for (int i = Columns.Count - 1; i >= 0; i--)
- //{
- // TableCell cell = this[i, y];
- // if (cell.ColSpan > 1)
- // {
- // thereIsColSpan = true;
- // }
- //}
- for (int x = Columns.Count - 1; x >= 0; x--)
- {
- TableCell cell = this[x, y];
- bool thereIsColSpan = false;
- if (cell.ColSpan > 1)
- {
- thereIsColSpan = true;
- }
- float width = Columns[x].Width;
- //if (thereIsColSpan)
- //{
- // width *= cell.ColSpan - 1;
- // left -= width;
- //}
- if (!IsInsideSpan(cell) && (!IsPrinting || cell.Printable))
- {
- cell.Left = left;
- cell.Top = top;
- cell.SetPrinting(IsPrinting);
- proc(e, cell);
- if (thereIsColSpan)
- width *= cell.ColSpan;
- left += width;
- }
- //if (!thereIsColSpan)
- // left += width;
- //else
- // left -= width;
- }
- top += height;
- }
- }
- private void DrawFill(FRPaintEventArgs e, TableCell cell)
- {
- cell.DrawBackground(e);
- }
- private void DrawText(FRPaintEventArgs e, TableCell cell)
- {
- cell.DrawText(e);
- }
- private void DrawBorders(FRPaintEventArgs e, TableCell cell)
- {
- cell.Border.Draw(e, cell.AbsBounds);
- }
- private void DrawTable(FRPaintEventArgs e)
- {
- DrawCells(e, DrawFill);
- DrawCells(e, DrawText);
- DrawDesign_Borders(e);
- DrawCells(e, DrawBorders);
- DrawDesign_SelectedCells(e);
- }
- private void DrawTableRtl(FRPaintEventArgs e)
- {
- DrawCellsRtl(e, DrawFill);
- DrawCellsRtl(e, DrawText);
- DrawDesign_BordersRtl(e);
- DrawCellsRtl(e, DrawBorders);
- DrawDesign_SelectedCellsRtl(e);
- }
- #endregion
- #region Public Methods
- /// <inheritdoc/>
- public override void Assign(Base source)
- {
- base.Assign(source);
- TableBase src = source as TableBase;
- FixedRows = src.FixedRows;
- FixedColumns = src.FixedColumns;
- PrintOnParent = src.PrintOnParent;
- RepeatHeaders = src.RepeatHeaders;
- RepeatRowHeaders = src.RepeatRowHeaders;
- RepeatColumnHeaders = src.RepeatColumnHeaders;
- Layout = src.Layout;
- WrappedGap = src.WrappedGap;
- AdjustSpannedCellsWidth = src.AdjustSpannedCellsWidth;
- }
- /// <inheritdoc/>
- public override void Draw(FRPaintEventArgs e)
- {
- if (ColumnCount == 0 || RowCount == 0)
- return;
- lockColumnRowChange = true;
- Width = Columns[Columns.Count - 1].Right;
- Height = Rows[Rows.Count - 1].Bottom;
- lockColumnRowChange = false;
- base.Draw(e);
- // draw table Right to Left if needed
- if (Config.RightToLeft)
- {
- DrawTableRtl(e);
- }
- else
- {
- DrawTable(e);
- }
- Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
- DrawDesign(e);
- }
- /// <inheritdoc/>
- public override bool IsVisible(FRPaintEventArgs e)
- {
- if (RowCount == 0 || ColumnCount == 0)
- return false;
- Width = Columns[Columns.Count - 1].Right;
- Height = Rows[Rows.Count - 1].Bottom;
- RectangleF objRect = new RectangleF(AbsLeft * e.ScaleX, AbsTop * e.ScaleY,
- Width * e.ScaleX + 1, Height * e.ScaleY + 1);
- return e.Graphics.IsVisible(objRect);
- }
- internal void SetResultTable(TableResult table)
- {
- resultTable = table;
- }
- /// <summary>
- /// Gets data of the table cell with specified column and row numbers.
- /// </summary>
- /// <param name="col">The column number.</param>
- /// <param name="row">The row number.</param>
- /// <returns>TableCellData instance containing data of the table cell.</returns>
- public TableCellData GetCellData(int col, int row)
- {
- if (col < 0 || col >= columns.Count || row < 0 || row >= rows.Count)
- return null;
- return rows[row].CellData(col);
- }
- internal List<Rectangle> GetSpanList()
- {
- if (spanList == null)
- {
- spanList = new List<Rectangle>();
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCellData cell = GetCellData(x, y);
- if (cell.ColSpan > 1 || cell.RowSpan > 1)
- spanList.Add(new Rectangle(x, y, cell.ColSpan, cell.RowSpan));
- }
- }
- }
- return spanList;
- }
- internal void ResetSpanList()
- {
- spanList = null;
- }
- internal void CorrectSpansOnRowChange(int rowIndex, int correct)
- {
- if (lockCorrectSpans || (correct == 1 && rowIndex >= Rows.Count))
- return;
- for (int y = 0; y < rowIndex; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCellData cell = GetCellData(x, y);
- if (rowIndex < y + cell.RowSpan)
- cell.RowSpan += correct;
- }
- }
- ResetSpanList();
- }
- internal void CorrectSpansOnColumnChange(int columnIndex, int correct)
- {
- if (lockCorrectSpans || (correct == 1 && columnIndex >= Columns.Count))
- return;
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < columnIndex; x++)
- {
- TableCellData cell = GetCellData(x, y);
- if (columnIndex < x + cell.ColSpan)
- cell.ColSpan += correct;
- }
- // correct cells
- Rows[y].CorrectCellsOnColumnChange(columnIndex, correct);
- }
- ResetSpanList();
- }
- public bool IsInsideSpan(TableCell cell)
- {
- Point address = cell.Address;
- List<Rectangle> spans = GetSpanList();
- foreach (Rectangle span in spans)
- {
- if (span.Contains(address) && span.Location != address)
- return true;
- }
- return false;
- }
- /// <summary>
- /// Creates unique names for all table elements such as rows, columns, cells.
- /// </summary>
- public void CreateUniqueNames()
- {
- if (Report == null)
- return;
- FastNameCreator nameCreator = new FastNameCreator(Report.AllNamedObjects);
- foreach (TableRow row in Rows)
- {
- if (String.IsNullOrEmpty(row.Name))
- nameCreator.CreateUniqueName(row);
- }
- foreach (TableColumn column in Columns)
- {
- if (String.IsNullOrEmpty(column.Name))
- nameCreator.CreateUniqueName(column);
- }
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCell cell = this[x, y];
- if (String.IsNullOrEmpty(cell.Name))
- {
- nameCreator.CreateUniqueName(cell);
- cell.Font = DrawUtils.DefaultReportFont;
- }
- if (cell.Objects != null)
- {
- foreach (ReportComponentBase obj in cell.Objects)
- {
- if (String.IsNullOrEmpty(obj.Name))
- nameCreator.CreateUniqueName(obj);
- }
- }
- }
- }
- }
- /// <inheritdoc/>
- public override void Serialize(FRWriter writer)
- {
- TableBase c = writer.DiffObject as TableBase;
- serializingToPreview = writer.SerializeTo == SerializeTo.Preview;
- base.Serialize(writer);
- if (FixedRows != c.FixedRows)
- writer.WriteInt("FixedRows", FixedRows);
- if (FixedColumns != c.FixedColumns)
- writer.WriteInt("FixedColumns", FixedColumns);
- if (PrintOnParent != c.PrintOnParent)
- writer.WriteBool("PrintOnParent", PrintOnParent);
- if (RepeatHeaders != c.RepeatHeaders)
- writer.WriteBool("RepeatHeaders", RepeatHeaders);
- if (RepeatRowHeaders != c.RepeatRowHeaders)
- writer.WriteBool("RepeatRowHeaders", RepeatRowHeaders);
- if (RepeatColumnHeaders != c.RepeatColumnHeaders)
- writer.WriteBool("RepeatColumnHeaders", RepeatColumnHeaders);
- if (Layout != c.Layout)
- writer.WriteValue("Layout", Layout);
- if (WrappedGap != c.WrappedGap)
- writer.WriteFloat("WrappedGap", WrappedGap);
- if (AdjustSpannedCellsWidth != c.AdjustSpannedCellsWidth)
- writer.WriteBool("AdjustSpannedCellsWidth", AdjustSpannedCellsWidth);
- }
- internal void EmulateOuterBorder()
- {
- for (int y = 0; y < RowCount; y++)
- {
- for (int x = 0; x < ColumnCount; x++)
- {
- TableCell cell = this[x, y];
- if (x == 0 && (Border.Lines & BorderLines.Left) != 0)
- {
- cell.Border.LeftLine.Assign(Border.LeftLine);
- cell.Border.Lines |= BorderLines.Left;
- }
- if (x + cell.ColSpan == ColumnCount && (Border.Lines & BorderLines.Right) != 0)
- {
- cell.Border.RightLine.Assign(Border.RightLine);
- cell.Border.Lines |= BorderLines.Right;
- }
- if (y == 0 && (Border.Lines & BorderLines.Top) != 0)
- {
- cell.Border.TopLine.Assign(Border.TopLine);
- cell.Border.Lines |= BorderLines.Top;
- }
- if (y + cell.RowSpan == RowCount && (Border.Lines & BorderLines.Bottom) != 0)
- {
- cell.Border.BottomLine.Assign(Border.BottomLine);
- cell.Border.Lines |= BorderLines.Bottom;
- }
- }
- }
- }
- #endregion
- #region IParent Members
- /// <inheritdoc/>
- public bool CanContain(Base child)
- {
- return child is TableRow || child is TableColumn || child is TableCell;
- }
- /// <inheritdoc/>
- public virtual void GetChildObjects(ObjectCollection list)
- {
- foreach (TableColumn column in Columns)
- {
- // Apply visible expression if needed.
- if (serializingToPreview && !String.IsNullOrEmpty(column.VisibleExpression))
- column.Visible = CalcVisibleExpression(column.VisibleExpression);
- if (!serializingToPreview || column.Visible)
- list.Add(column);
- }
- foreach (TableRow row in Rows)
- {
- // Apply visible expression if needed.
- if (serializingToPreview && !String.IsNullOrEmpty(row.VisibleExpression))
- row.Visible = CalcVisibleExpression(row.VisibleExpression);
- if (!serializingToPreview || row.Visible)
- list.Add(row);
- }
- }
- /// <inheritdoc/>
- public void AddChild(Base child)
- {
- if (child is TableRow)
- Rows.Add(child as TableRow);
- else if (child is TableColumn)
- Columns.Add(child as TableColumn);
- }
- /// <inheritdoc/>
- public void RemoveChild(Base child)
- {
- if (child is TableRow)
- Rows.Remove(child as TableRow);
- else if (child is TableColumn)
- Columns.Remove(child as TableColumn);
- }
- /// <inheritdoc/>
- public int GetChildOrder(Base child)
- {
- if (child is TableColumn)
- return Columns.IndexOf(child as TableColumn);
- else if (child is TableRow)
- return Rows.IndexOf(child as TableRow);
- return 0;
- }
- /// <inheritdoc/>
- public void SetChildOrder(Base child, int order)
- {
- lockCorrectSpans = true;
- int oldOrder = child.ZOrder;
- if (oldOrder != -1 && order != -1 && oldOrder != order)
- {
- if (child is TableColumn)
- {
- if (order > Columns.Count)
- order = Columns.Count;
- if (oldOrder <= order)
- order--;
- Columns.Remove(child as TableColumn);
- Columns.Insert(order, child as TableColumn);
- }
- else if (child is TableRow)
- {
- if (order > Rows.Count)
- order = Rows.Count;
- if (oldOrder <= order)
- order--;
- Rows.Remove(child as TableRow);
- Rows.Insert(order, child as TableRow);
- }
- }
- lockCorrectSpans = false;
- }
- /// <inheritdoc/>
- public void UpdateLayout(float dx, float dy)
- {
- }
- #endregion
- #region Report Engine
- /// <inheritdoc/>
- public override void SaveState()
- {
- base.SaveState();
- foreach (TableRow row in Rows)
- {
- row.SaveState();
- }
- foreach (TableColumn column in Columns)
- {
- column.SaveState();
- }
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- this[x, y].SaveState();
- }
- }
- CanGrow = true;
- CanShrink = true;
- }
- /// <inheritdoc/>
- public override void RestoreState()
- {
- base.RestoreState();
- foreach (TableRow row in Rows)
- {
- row.RestoreState();
- }
- foreach (TableColumn column in Columns)
- {
- column.RestoreState();
- }
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- this[x, y].RestoreState();
- }
- }
- }
- /// <summary>
- /// Calculates and returns the table width, in pixels.
- /// </summary>
- public float CalcWidth()
- {
- // first pass, calc non-spanned cells
- for (int x = 0; x < Columns.Count; x++)
- {
- TableColumn column = Columns[x];
- if (!column.AutoSize)
- continue;
- float columnWidth = IsDesigning ? 16 : -1;
- // calc the max column width
- for (int y = 0; y < Rows.Count; y++)
- {
- TableCellData cell = GetCellData(x, y);
- if (cell.ColSpan == 1)
- {
- float cellWidth = cell.CalcWidth();
- if (cellWidth > columnWidth)
- columnWidth = cellWidth;
- }
- }
- // update column width
- if (columnWidth != -1)
- column.Width = columnWidth;
- }
- // second pass, calc spanned cells
- for (int x = 0; x < Columns.Count; x++)
- {
- Columns[x].MinimumBreakWidth = 0;
- for (int y = 0; y < Rows.Count; y++)
- {
- TableCellData cell = GetCellData(x, y);
- if (cell.ColSpan > 1)
- {
- float cellWidth = cell.CalcWidth();
- if (AdjustSpannedCellsWidth && cellWidth > Columns[x].MinimumBreakWidth)
- Columns[x].MinimumBreakWidth = cellWidth;
- // check that spanned columns have enough width
- float columnsWidth = 0;
- for (int i = 0; i < cell.ColSpan; i++)
- {
- columnsWidth += Columns[Math.Min(Columns.Count-1,x + i)].Width;
- }
- // if cell is bigger than sum of column width, increase the last column width
- TableColumn lastColumn = Columns[Math.Min(Columns.Count-1,x + cell.ColSpan - 1)];
- if (columnsWidth < cellWidth && lastColumn.AutoSize)
- lastColumn.Width += cellWidth - columnsWidth;
- }
- }
- }
- // finally, calculate the table width
- float width = 0;
- for (int i = 0; i < Columns.Count; i++)
- {
- width += Columns[i].Width;
- }
- lockColumnRowChange = true;
- Width = width;
- lockColumnRowChange = false;
- return width;
- }
- /// <inheritdoc/>
- public override float CalcHeight()
- {
- if (ColumnCount * RowCount > 1000)
- Config.ReportSettings.OnProgress(Report, Res.Get("ComponentsMisc,Table,CalcBounds"), 0, 0);
- // calc width
- CalcWidth();
- // first pass, calc non-spanned cells
- for (int y = 0; y < Rows.Count; y++)
- {
- TableRow row = Rows[y];
- if (!row.AutoSize)
- continue;
- float rowHeight = IsDesigning ? 16 : -1;
- // calc the max row height
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCellData cell = GetCellData(x, y);
- if (cell.RowSpan == 1)
- {
- float cellHeight = cell.CalcHeight(cell.Width);
- if (cellHeight > rowHeight)
- rowHeight = cellHeight;
- }
- }
- // update row height
- if (rowHeight != -1)
- row.Height = rowHeight;
- }
- // second pass, calc spanned cells
- for (int y = 0; y < Rows.Count; y++)
- {
- for (int x = 0; x < Columns.Count; x++)
- {
- TableCellData cell = GetCellData(x, y);
- if (cell.RowSpan > 1)
- {
- float cellHeight = cell.CalcHeight(cell.Width);
- // check that spanned rows have enough height
- float rowsHeight = 0;
- for (int i = 0; i < cell.RowSpan; i++)
- {
- if (y + i < Rows.Count)
- rowsHeight += Rows[y + i].Height;
- else
- {
- // Error, we don't have row, rowSpan has incorrect
- cell.RowSpan--;
- }
- }
- // if cell is bigger than sum of row heights, increase the last row height
- if (y + cell.RowSpan - 1 < Rows.Count)
- {
- TableRow lastRow = Rows[y + cell.RowSpan - 1];
- if (rowsHeight < cellHeight && lastRow.AutoSize)
- lastRow.Height += cellHeight - rowsHeight;
- }
- }
- }
- }
- // finally, calculate the table height
- float height = 0;
- for (int i = 0; i < Rows.Count; i++)
- {
- height += Rows[i].Visible ? Rows[i].Height : 0;
- }
- return height;
- }
- private bool CanBreakRow(int rowIndex, float rowHeight)
- {
- if (!Rows[rowIndex].CanBreak)
- return false;
- // check each cell in the row
- for (int i = 0; i < ColumnCount; i++)
- {
- TableCell breakable = this[i, rowIndex];
- // use clone object because Break method will modify the Text property
- using (TableCell clone = new TableCell())
- {
- clone.AssignAll(breakable);
- clone.Height = rowHeight;
- clone.SetReport(Report);
- if (!clone.Break(null))
- return false;
- }
- }
- return true;
- }
- private void BreakRow(TableBase breakTo, int rowIndex, float rowHeight, float newRowHeight)
- {
- // set rows height
- TableRow rowTo = breakTo.Rows[rowIndex];
- Rows[rowIndex].Height = rowHeight;
- rowTo.Height = newRowHeight;
- // break each cell in the row
- for (int i = 0; i < ColumnCount; i++)
- {
- TableCell cell = this[i, rowIndex];
- TableCell cellTo = breakTo[i, rowIndex];
- cell.Height = rowHeight;
- cell.Break(cellTo);
- // fix height if row is not autosized
- if (!rowTo.AutoSize)
- {
- float h = cellTo.CalcHeight();
- if (h > rowTo.Height)
- rowTo.Height = h;
- }
- }
- }
- /// <inheritdoc/>
- public override bool Break(BreakableComponent breakTo)
- {
- if (Rows.Count == 0)
- return true;
- if (Height < Rows[0].Height && !Rows[0].CanBreak)
- return false;
- TableBase tableTo = breakTo as TableBase;
- if (tableTo == null)
- return true;
- // find the break row index
- int breakRowIndex = 0;
- int breakRowIndexAdd = 0;
- bool rowBroken = false;
- float rowsHeight = 0;
- while (breakRowIndex < Rows.Count)
- {
- rowsHeight += Rows[breakRowIndex].Height;
- if (rowsHeight > Height)
- {
- float breakRowHeight = Rows[breakRowIndex].Height - (rowsHeight - Height);
- if (CanBreakRow(breakRowIndex, breakRowHeight))
- {
- BreakRow(tableTo, breakRowIndex, breakRowHeight, rowsHeight - Height);
- breakRowIndexAdd = 1;
- rowBroken = true;
- }
- break;
- }
- breakRowIndex++;
- }
- // get the span list
- List<Rectangle> spans = GetSpanList();
- // break the spans
- foreach (Rectangle span in spans)
- {
- if (span.Top < breakRowIndex + breakRowIndexAdd && span.Bottom > breakRowIndex)
- {
- TableCell cell = this[span.Left, span.Top];
- TableCell cellTo = tableTo[span.Left, span.Top];
- // update cell spans
- cell.RowSpan = breakRowIndex + breakRowIndexAdd - span.Top;
- cellTo.RowSpan = span.Bottom - breakRowIndex;
- // break the cell
- if (!rowBroken && !cell.Break(cellTo))
- cell.Text = "";
- // set the top span cell to the correct place
- tableTo[span.Left, span.Top] = new TableCell();
- tableTo[span.Left, breakRowIndex] = cellTo;
- }
- }
- // remove unused rows from source (this table)
- while (breakRowIndex + breakRowIndexAdd < Rows.Count)
- {
- this.Rows.RemoveAt(Rows.Count - 1);
- }
- // remove unused rows from copy (tableTo)
- for (int i = 0; i < breakRowIndex; i++)
- {
- tableTo.Rows.RemoveAt(0);
- }
- return true;
- }
- private List<TableCellData> GetAggregateCells(TableCell aggregateCell)
- {
- List<TableCellData> list = new List<TableCellData>();
- // columnIndex, rowIndex is a place where we will print a result.
- // To collect aggregate values that will be used to calculate a result, we need to go
- // to the left and top from this point and collect every cell which OriginalCell is equal to
- // the aggregateCell value. We have to stop when we meet the same row or column.
- int columnIndex = PrintingCell.Address.X;
- int rowIndex = PrintingCell.Address.Y;
- TableColumn startColumn = ResultTable.Columns[columnIndex];
- TableRow startRow = ResultTable.Rows[rowIndex];
- TableColumn aggregateColumn = Columns[aggregateCell.Address.X];
- TableRow aggregateRow = Rows[aggregateCell.Address.Y];
- // check if result is in the same row/column as aggregate cell
- bool sameRow = startRow.OriginalComponent == aggregateRow.OriginalComponent;
- bool sameColumn = startColumn.OriginalComponent == aggregateColumn.OriginalComponent;
- for (int y = rowIndex; y >= 0; y--)
- {
- if (y != rowIndex && ResultTable.Rows[y].OriginalComponent == startRow.OriginalComponent)
- break;
- for (int x = columnIndex; x >= 0; x--)
- {
- if (x != columnIndex && ResultTable.Columns[x].OriginalComponent == startColumn.OriginalComponent)
- break;
- TableCellData cell = ResultTable.GetCellData(x, y);
- if (cell.OriginalCell == aggregateCell)
- list.Add(cell);
- if (sameColumn)
- break;
- }
- if (sameRow)
- break;
- }
- return list;
- }
- /// <summary>
- /// Calculates a sum of values in a specified cell.
- /// </summary>
- /// <param name="aggregateCell">The cell.</param>
- /// <returns>The <b>object</b> that contains calculated value.</returns>
- /// <remarks>
- /// This method can be called from the <b>ManualBuild</b> event handler only.
- /// </remarks>
- public object Sum(TableCell aggregateCell)
- {
- List<TableCellData> list = GetAggregateCells(aggregateCell);
- Variant result = 0;
- bool firstTime = true;
- foreach (TableCellData cell in list)
- {
- if (cell.Value != null)
- {
- Variant varValue = new Variant(cell.Value);
- if (firstTime)
- result = varValue;
- else
- result += varValue;
- firstTime = false;
- }
- }
- return result.Value;
- }
- /// <summary>
- /// Calculates a minimum of values in a specified cell.
- /// </summary>
- /// <param name="aggregateCell">The cell.</param>
- /// <returns>The <b>object</b> that contains calculated value.</returns>
- /// <remarks>
- /// This method can be called from the <b>ManualBuild</b> event handler only.
- /// </remarks>
- public object Min(TableCell aggregateCell)
- {
- List<TableCellData> list = GetAggregateCells(aggregateCell);
- Variant result = float.PositiveInfinity;
- bool firstTime = true;
- foreach (TableCellData cell in list)
- {
- if (cell.Value != null)
- {
- Variant varValue = new Variant(cell.Value);
- if (firstTime || varValue < result)
- result = varValue;
- firstTime = false;
- }
- }
- return result.Value;
- }
- /// <summary>
- /// Calculates a maximum of values in a specified cell.
- /// </summary>
- /// <param name="aggregateCell">The cell.</param>
- /// <returns>The <b>object</b> that contains calculated value.</returns>
- /// <remarks>
- /// This method can be called from the <b>ManualBuild</b> event handler only.
- /// </remarks>
- public object Max(TableCell aggregateCell)
- {
- List<TableCellData> list = GetAggregateCells(aggregateCell);
- Variant result = float.NegativeInfinity;
- bool firstTime = true;
- foreach (TableCellData cell in list)
- {
- if (cell.Value != null)
- {
- Variant varValue = new Variant(cell.Value);
- if (firstTime || varValue > result)
- result = varValue;
- firstTime = false;
- }
- }
- return result.Value;
- }
- /// <summary>
- /// Calculates an average of values in a specified cell.
- /// </summary>
- /// <param name="aggregateCell">The cell.</param>
- /// <returns>The <b>object</b> that contains calculated value.</returns>
- /// <remarks>
- /// This method can be called from the <b>ManualBuild</b> event handler only.
- /// </remarks>
- public object Avg(TableCell aggregateCell)
- {
- List<TableCellData> list = GetAggregateCells(aggregateCell);
- Variant result = 0;
- int count = 0;
- bool firstTime = true;
- foreach (TableCellData cell in list)
- {
- if (cell.Value != null)
- {
- Variant varValue = new Variant(cell.Value);
- if (firstTime)
- result = varValue;
- else
- result += varValue;
- count++;
- firstTime = false;
- }
- }
- return result / (count == 0 ? 1 : count);
- }
- /// <summary>
- /// Calculates number of repeats of a specified cell.
- /// </summary>
- /// <param name="aggregateCell">The cell.</param>
- /// <returns>The <b>object</b> that contains calculated value.</returns>
- /// <remarks>
- /// This method can be called from the <b>ManualBuild</b> event handler only.
- /// </remarks>
- public object Count(TableCell aggregateCell)
- {
- List<TableCellData> list = GetAggregateCells(aggregateCell);
- int count = 0;
- foreach (TableCellData cell in list)
- {
- if (cell.Value != null)
- count++;
- }
- return count;
- }
- #endregion
- /// <summary>
- /// Initializes a new instance of the <see cref="TableBase"/> class.
- /// </summary>
- public TableBase()
- {
- rows = new TableRowCollection(this);
- columns = new TableColumnCollection(this);
- styles = new TableStyleCollection();
- repeatHeaders = true;
- repeatRowHeaders = false;
- repeatColumnHeaders = false;
- CanGrow = true;
- CanShrink = true;
- }
- }
- }
|