using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Drawing; using System.ComponentModel; using System.Drawing.Drawing2D; using FastReport.Utils; using FastReport.Data; namespace FastReport.Table { /// /// Represents a table object that consists of several rows and columns. /// /// /// To add/remove columns, use the collection. To add/remove /// rows, use the collection. To initialize a table with specified number of /// columns and rows, use and properties. /// To print a table in code, use the event. In the manual build /// mode, you can use aggregate functions. The following functions available: /// /// /// Aggregate function /// Description /// /// /// Sum(cell) /// Calculates the sum of values in specified table cell. /// /// /// Min(cell) /// Calculates the minimum of values in specified table cell. /// /// /// Max(cell) /// Calculates the maximum of values in specified table cell. /// /// /// Avg(cell) /// Calculates the average of values in specified table cell. /// /// /// Count(cell) /// Calculates the number of repeats of a specified table cell. /// /// /// To print aggregate value, place the aggregate function call in the table cell: /// [Count(Cell2)]. /// public partial class TableObject : TableBase { #region Fields private string manualBuildEvent; private TableHelper helper; private bool saveVisible; private bool saveStateSkipped; private bool manualBuildAutoSpans; #endregion #region Properties /// /// Allows to print table rows/columns dynamically. /// /// /// This event is used to handle the table print process in a code. Using special methods /// like , you can print specified rows/columns. /// /// First way is to repeat specified row(s) to get a table that will grow downwards. /// To do this, you have to call the PrintRow method followed by the PrintColumns method. /// /// Another way is to repeat the specified column(s) to get a table that grows sidewards. /// To do this, call the PrintColumn method followed by the PrintRows method. /// /// Finally, the third way is to repeat rows and columns. The table will grow downwards and /// sidewards. To do this, call the PrintRow method followed by the PrintColumn /// method (or vice versa). /// /// /// /// When you print a table row-by-row, you must call one of the PrintColumn, /// PrintColumns methods right after the PrintRow method. /// In the same manner, when you print a table column-by-column, call one of the /// PrintRow, PrintRows methods right after the PrintColumn method. /// If you ignore this rule you will get an exception. /// /// /// /// In this example, we will consider all three ways to print a table which has 3 rows and 3 columns. /// Case 1: print a table downwards. /// /// // print table header (the first row) /// Table1.PrintRow(0); /// Table1.PrintColumns(); /// // print table body (the second row) /// for (int i = 0; i < 10; i++) /// { /// Table1.PrintRow(1); /// Table1.PrintColumns(); /// } /// // print table footer (the third row) /// Table1.PrintRow(2); /// Table1.PrintColumns(); /// /// /// Case 2: print a table sidewards. /// /// // print table header (the first column) /// Table1.PrintColumn(0); /// Table1.PrintRows(); /// // print table body (the second column) /// for (int i = 0; i < 10; i++) /// { /// Table1.PrintColumn(1); /// Table1.PrintRows(); /// } /// // print table footer (the third column) /// Table1.PrintColumn(2); /// Table1.PrintRows(); /// /// /// Case 3: print a table downwards and sidewards. /// /// // print the first row with all its columns /// Table1.PrintRow(0); /// // print header column /// Table1.PrintColumn(0); /// // print 10 data columns /// for (int i = 0; i < 10; i++) /// { /// Table1.PrintColumn(1); /// } /// // print footer column /// Table1.PrintColumn(2); /// /// // print table body (the second row) /// for (int i = 0; i < 10; i++) /// { /// // print data row with all its columns /// Table1.PrintRow(1); /// Table1.PrintColumn(0); /// for (int j = 0; j < 10; j++) /// { /// Table1.PrintColumn(1); /// } /// Table1.PrintColumn(2); /// } /// /// // print table footer (the third row) /// Table1.PrintRow(2); /// // again print all columns in the table footer /// Table1.PrintColumn(0); /// for (int i = 0; i < 10; i++) /// { /// Table1.PrintColumn(1); /// } /// Table1.PrintColumn(2); /// /// public event EventHandler ManualBuild; /// /// Gets or sets a script method name that will be used to handle the /// event. /// /// /// If you use this event, you must handle the table print process manually. /// See the event for details. /// [Category("Build")] public string ManualBuildEvent { get { return manualBuildEvent; } set { manualBuildEvent = value; } } /// /// Determines whether to manage cell spans automatically during manual build. /// /// /// The default value for this property is true. If you set it to false, you need to manage /// spans in your ManualBuild event handler. /// [Category("Build")] [DefaultValue(true)] public bool ManualBuildAutoSpans { get { return manualBuildAutoSpans; } set { manualBuildAutoSpans = value; } } /// public override int ColumnCount { get { return base.ColumnCount; } set { base.ColumnCount = value; CreateUniqueNames(); } } /// public override int RowCount { get { return base.RowCount; } set { base.RowCount = value; CreateUniqueNames(); } } internal bool IsManualBuild { get { return !String.IsNullOrEmpty(ManualBuildEvent) || ManualBuild != null; } } #endregion #region Public Methods /// public override void Assign(Base source) { base.Assign(source); TableObject src = source as TableObject; ManualBuildEvent = src.ManualBuildEvent; ManualBuildAutoSpans = src.ManualBuildAutoSpans; } /// public override void Serialize(FRWriter writer) { TableObject c = writer.DiffObject as TableObject; base.Serialize(writer); if (ManualBuildEvent != c.ManualBuildEvent) writer.WriteStr("ManualBuildEvent", ManualBuildEvent); if (ManualBuildAutoSpans != c.ManualBuildAutoSpans) writer.WriteBool("ManualBuildAutoSpans", ManualBuildAutoSpans); } #endregion #region Report Engine private string GetFunctionCode(string function) { string result = ""; switch (Report.ScriptLanguage) { case Language.CSharp: result = " private object " + function + "(TableCell cell)\r\n" + " {\r\n" + " return cell.Table." + function + "(cell);\r\n" + " }\r\n\r\n"; break; case Language.Vb: result = " Private Function " + function + "(ByVal cell As TableCell) As Object\r\n" + " Return cell.Table." + function + "(cell)\r\n" + " End Function\r\n\r\n"; break; } return result; } /// public override string GetCustomScript() { string result = ""; string[] functions = new string[] { "Sum", "Min", "Max", "Avg", "Count" }; foreach (string function in functions) { result += GetFunctionCode(function); } return result; } /// public override void SaveState() { saveVisible = Visible; BandBase parent = Parent as BandBase; saveStateSkipped = !Visible || (parent != null && !parent.Visible); if (saveStateSkipped) return; if (!IsManualBuild) { base.SaveState(); } else { // create the result table that will be rendered in the preview SetResultTable(new TableResult()); ResultTable.Assign(this); ResultTable.SetReport(Report); helper = new TableHelper(this, ResultTable); Visible = false; if (parent != null && !PrintOnParent) { parent.Height = Top; parent.CanGrow = false; parent.CanShrink = false; parent.AfterPrint += ResultTable.GeneratePages; } OnManualBuild(EventArgs.Empty); } } /// public override void RestoreState() { BandBase parent = Parent as BandBase; // SaveState was skipped, there is nothing to restore if (saveStateSkipped) return; if (!IsManualBuild) { base.RestoreState(); } else { if (parent != null && !PrintOnParent) parent.AfterPrint -= ResultTable.GeneratePages; helper = null; ResultTable.Dispose(); SetResultTable(null); Visible = saveVisible; } } /// public override void GetData() { base.GetData(); if (!IsManualBuild) { for (int y = 0; y < Rows.Count; y++) { for (int x = 0; x < Columns.Count; x++) { this[x, y].GetData(); } } } } /// public override void OnAfterData(EventArgs e) { base.OnAfterData(e); if (IsManualBuild && PrintOnParent) ResultTable.AddToParent(Parent); } /// /// This method fires the ManualBuild event and the script code connected to the ManualBuildEvent. /// /// Event data. public void OnManualBuild(EventArgs e) { if (ManualBuild != null) ManualBuild(this, e); InvokeEvent(ManualBuildEvent, e); } /// /// Prints a row with specified index. /// /// Index of a row to print. /// /// See the event for more details. /// public void PrintRow(int index) { if (!IsManualBuild) throw new TableManualBuildException(); helper.PrintRow(index); } /// /// Prints rows with specified indices. /// /// Indices of rows to print. /// /// See the event for more details. /// public void PrintRows(int[] indices) { foreach (int index in indices) { PrintRow(index); } } /// /// Prints all rows. /// /// /// See the event for more details. /// public void PrintRows() { for (int i = 0; i < Rows.Count; i++) { PrintRow(i); } } /// /// Prints a column with specified index. /// /// Index of a column to print. /// /// See the event for more details. /// public void PrintColumn(int index) { if (!IsManualBuild) throw new TableManualBuildException(); helper.PrintColumn(index); } /// /// Prints columns with specified indices. /// /// Indices of columns to print. /// /// See the event for more details. /// public void PrintColumns(int[] indices) { foreach (int index in indices) { PrintColumn(index); } } /// /// Prints all columns. /// /// /// See the event for more details. /// public void PrintColumns() { for (int i = 0; i < Columns.Count; i++) { PrintColumn(i); } } /// /// Adds a page before rows or columns. /// /// /// Call this method to insert a page break before the next row or column that you intend to print /// using PrintRow(s) or PrintColumn(s) methods. /// See the event for more details. /// public void PageBreak() { if (!IsManualBuild) throw new TableManualBuildException(); if (!Report.Engine.UnlimitedHeight && !Report.Engine.UnlimitedWidth) helper.PageBreak(); } #endregion /// /// Initializes a new instance of the class. /// public TableObject() { manualBuildEvent = ""; manualBuildAutoSpans = true; } } }