FastReport
497 строк · 16.3 Кб
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Text;
5using System.Drawing;
6using System.ComponentModel;
7using System.Drawing.Drawing2D;
8using FastReport.Utils;
9using FastReport.Data;
10
11namespace FastReport.Table
12{
13/// <summary>
14/// Represents a table object that consists of several rows and columns.
15/// </summary>
16/// <remarks>
17/// <para/>To add/remove columns, use the <see cref="TableBase.Columns"/> collection. To add/remove
18/// rows, use the <see cref="TableBase.Rows"/> collection. To initialize a table with specified number of
19/// columns and rows, use <see cref="ColumnCount"/> and <see cref="RowCount"/> properties.
20/// <para/>To print a table in code, use the <see cref="ManualBuild"/> event. In the manual build
21/// mode, you can use aggregate functions. The following functions available:
22/// <list type="table">
23/// <listheader>
24/// <term>Aggregate function</term>
25/// <description>Description</description>
26/// </listheader>
27/// <item>
28/// <term>Sum(cell)</term>
29/// <description>Calculates the sum of values in specified table cell.</description>
30/// </item>
31/// <item>
32/// <term>Min(cell)</term>
33/// <description>Calculates the minimum of values in specified table cell.</description>
34/// </item>
35/// <item>
36/// <term>Max(cell)</term>
37/// <description>Calculates the maximum of values in specified table cell.</description>
38/// </item>
39/// <item>
40/// <term>Avg(cell)</term>
41/// <description>Calculates the average of values in specified table cell.</description>
42/// </item>
43/// <item>
44/// <term>Count(cell)</term>
45/// <description>Calculates the number of repeats of a specified table cell.</description>
46/// </item>
47/// </list>
48/// <para/>To print aggregate value, place the aggregate function call in the table cell:
49/// <c>[Count(Cell2)]</c>.
50/// </remarks>
51public partial class TableObject : TableBase
52{
53#region Fields
54private string manualBuildEvent;
55private TableHelper helper;
56private bool saveVisible;
57private bool saveStateSkipped;
58private bool manualBuildAutoSpans;
59#endregion
60
61#region Properties
62/// <summary>
63/// Allows to print table rows/columns dynamically.
64/// </summary>
65/// <remarks>
66/// This event is used to handle the table print process in a code. Using special methods
67/// like <see cref="PrintRow"/>, <see cref="PrintColumn"/> you can print specified rows/columns.
68///
69/// <para/>First way is to repeat specified row(s) to get a table that will grow downwards.
70/// To do this, you have to call the <b>PrintRow</b> method followed by the <b>PrintColumns</b> method.
71///
72/// <para/>Another way is to repeat the specified column(s) to get a table that grows sidewards.
73/// To do this, call the <b>PrintColumn</b> method followed by the <b>PrintRows</b> method.
74///
75/// <para/>Finally, the third way is to repeat rows and columns. The table will grow downwards and
76/// sidewards. To do this, call the <b>PrintRow</b> method followed by the <b>PrintColumn</b>
77/// method (or vice versa).
78///
79/// <para/>
80/// <note type="caution">
81/// When you print a table row-by-row, you must call one of the <b>PrintColumn</b>,
82/// <b>PrintColumns</b> methods right after the <b>PrintRow</b> method.
83/// In the same manner, when you print a table column-by-column, call one of the
84/// <b>PrintRow</b>, <b>PrintRows</b> methods right after the <b>PrintColumn</b> method.
85/// If you ignore this rule you will get an exception.
86/// </note>
87/// </remarks>
88/// <example>
89/// In this example, we will consider all three ways to print a table which has 3 rows and 3 columns.
90/// <para/>Case 1: print a table downwards.
91/// <code>
92/// // print table header (the first row)
93/// Table1.PrintRow(0);
94/// Table1.PrintColumns();
95/// // print table body (the second row)
96/// for (int i = 0; i < 10; i++)
97/// {
98/// Table1.PrintRow(1);
99/// Table1.PrintColumns();
100/// }
101/// // print table footer (the third row)
102/// Table1.PrintRow(2);
103/// Table1.PrintColumns();
104/// </code>
105///
106/// <para/>Case 2: print a table sidewards.
107/// <code>
108/// // print table header (the first column)
109/// Table1.PrintColumn(0);
110/// Table1.PrintRows();
111/// // print table body (the second column)
112/// for (int i = 0; i < 10; i++)
113/// {
114/// Table1.PrintColumn(1);
115/// Table1.PrintRows();
116/// }
117/// // print table footer (the third column)
118/// Table1.PrintColumn(2);
119/// Table1.PrintRows();
120/// </code>
121///
122/// <para/>Case 3: print a table downwards and sidewards.
123/// <code>
124/// // print the first row with all its columns
125/// Table1.PrintRow(0);
126/// // print header column
127/// Table1.PrintColumn(0);
128/// // print 10 data columns
129/// for (int i = 0; i < 10; i++)
130/// {
131/// Table1.PrintColumn(1);
132/// }
133/// // print footer column
134/// Table1.PrintColumn(2);
135///
136/// // print table body (the second row)
137/// for (int i = 0; i < 10; i++)
138/// {
139/// // print data row with all its columns
140/// Table1.PrintRow(1);
141/// Table1.PrintColumn(0);
142/// for (int j = 0; j < 10; j++)
143/// {
144/// Table1.PrintColumn(1);
145/// }
146/// Table1.PrintColumn(2);
147/// }
148///
149/// // print table footer (the third row)
150/// Table1.PrintRow(2);
151/// // again print all columns in the table footer
152/// Table1.PrintColumn(0);
153/// for (int i = 0; i < 10; i++)
154/// {
155/// Table1.PrintColumn(1);
156/// }
157/// Table1.PrintColumn(2);
158/// </code>
159/// </example>
160public event EventHandler ManualBuild;
161
162/// <summary>
163/// Gets or sets a script method name that will be used to handle the
164/// <see cref="ManualBuild"/> event.
165/// </summary>
166/// <remarks>
167/// If you use this event, you must handle the table print process manually.
168/// See the <see cref="ManualBuild"/> event for details.
169/// </remarks>
170[Category("Build")]
171public string ManualBuildEvent
172{
173get { return manualBuildEvent; }
174set { manualBuildEvent = value; }
175}
176
177/// <summary>
178/// Determines whether to manage cell spans automatically during manual build.
179/// </summary>
180/// <remarks>
181/// The default value for this property is <b>true</b>. If you set it to <b>false</b>, you need to manage
182/// spans in your ManualBuild event handler.
183/// </remarks>
184[Category("Build")]
185[DefaultValue(true)]
186public bool ManualBuildAutoSpans
187{
188get { return manualBuildAutoSpans; }
189set { manualBuildAutoSpans = value; }
190}
191
192/// <inheritdoc/>
193public override int ColumnCount
194{
195get { return base.ColumnCount; }
196set
197{
198base.ColumnCount = value;
199CreateUniqueNames();
200}
201}
202
203/// <inheritdoc/>
204public override int RowCount
205{
206get { return base.RowCount; }
207set
208{
209base.RowCount = value;
210CreateUniqueNames();
211}
212}
213
214internal bool IsManualBuild
215{
216get { return !String.IsNullOrEmpty(ManualBuildEvent) || ManualBuild != null; }
217}
218#endregion
219
220#region Private Methods
221partial void InitTag();
222#endregion
223
224#region Public Methods
225/// <inheritdoc/>
226public override void Assign(Base source)
227{
228base.Assign(source);
229
230TableObject src = source as TableObject;
231ManualBuildEvent = src.ManualBuildEvent;
232ManualBuildAutoSpans = src.ManualBuildAutoSpans;
233}
234
235/// <inheritdoc/>
236public override void Serialize(FRWriter writer)
237{
238TableObject c = writer.DiffObject as TableObject;
239base.Serialize(writer);
240
241if (ManualBuildEvent != c.ManualBuildEvent)
242writer.WriteStr("ManualBuildEvent", ManualBuildEvent);
243if (ManualBuildAutoSpans != c.ManualBuildAutoSpans)
244writer.WriteBool("ManualBuildAutoSpans", ManualBuildAutoSpans);
245}
246#endregion
247
248#region Report Engine
249private string GetFunctionCode(string function)
250{
251string result = "";
252
253switch (Report.ScriptLanguage)
254{
255case Language.CSharp:
256result =
257" private object " + function + "(TableCell cell)\r\n" +
258" {\r\n" +
259" return cell.Table." + function + "(cell);\r\n" +
260" }\r\n\r\n";
261break;
262
263case Language.Vb:
264result =
265" Private Function " + function + "(ByVal cell As TableCell) As Object\r\n" +
266" Return cell.Table." + function + "(cell)\r\n" +
267" End Function\r\n\r\n";
268break;
269}
270
271return result;
272}
273
274/// <inheritdoc/>
275public override string GetCustomScript()
276{
277string result = "";
278string[] functions = new string[] { "Sum", "Min", "Max", "Avg", "Count" };
279
280foreach (string function in functions)
281{
282result += GetFunctionCode(function);
283}
284
285return result;
286}
287
288/// <inheritdoc/>
289public override void SaveState()
290{
291saveVisible = Visible;
292BandBase parent = Parent as BandBase;
293saveStateSkipped = !Visible || (parent != null && !parent.Visible);
294if (saveStateSkipped)
295return;
296
297if (!IsManualBuild)
298{
299base.SaveState();
300}
301else
302{
303// create the result table that will be rendered in the preview
304SetResultTable(new TableResult());
305ResultTable.Assign(this);
306ResultTable.SetReport(Report);
307helper = new TableHelper(this, ResultTable);
308
309Visible = false;
310
311if (parent != null && !PrintOnParent)
312{
313parent.Height = Top;
314parent.CanGrow = false;
315parent.CanShrink = false;
316parent.AfterPrint += ResultTable.GeneratePages;
317}
318
319OnManualBuild(EventArgs.Empty);
320}
321}
322
323/// <inheritdoc/>
324public override void RestoreState()
325{
326BandBase parent = Parent as BandBase;
327// SaveState was skipped, there is nothing to restore
328if (saveStateSkipped)
329return;
330
331if (!IsManualBuild)
332{
333base.RestoreState();
334}
335else
336{
337if (parent != null && !PrintOnParent)
338parent.AfterPrint -= ResultTable.GeneratePages;
339
340helper = null;
341ResultTable.Dispose();
342SetResultTable(null);
343Visible = saveVisible;
344}
345}
346
347/// <inheritdoc/>
348public override void GetData()
349{
350base.GetData();
351
352if (!IsManualBuild)
353{
354for (int y = 0; y < Rows.Count; y++)
355{
356for (int x = 0; x < Columns.Count; x++)
357{
358this[x, y].GetData();
359}
360}
361}
362}
363
364/// <inheritdoc/>
365public override void OnAfterData(EventArgs e)
366{
367base.OnAfterData(e);
368
369if (IsManualBuild && PrintOnParent)
370ResultTable.AddToParent(Parent);
371}
372
373/// <summary>
374/// This method fires the <b>ManualBuild</b> event and the script code connected to the <b>ManualBuildEvent</b>.
375/// </summary>
376/// <param name="e">Event data.</param>
377public void OnManualBuild(EventArgs e)
378{
379if (ManualBuild != null)
380ManualBuild(this, e);
381InvokeEvent(ManualBuildEvent, e);
382}
383
384/// <summary>
385/// Prints a row with specified index.
386/// </summary>
387/// <param name="index">Index of a row to print.</param>
388/// <remarks>
389/// See the <see cref="ManualBuild"/> event for more details.
390/// </remarks>
391public void PrintRow(int index)
392{
393if (!IsManualBuild)
394throw new TableManualBuildException();
395helper.PrintRow(index);
396}
397
398/// <summary>
399/// Prints rows with specified indices.
400/// </summary>
401/// <param name="indices">Indices of rows to print.</param>
402/// <remarks>
403/// See the <see cref="ManualBuild"/> event for more details.
404/// </remarks>
405public void PrintRows(int[] indices)
406{
407foreach (int index in indices)
408{
409PrintRow(index);
410}
411}
412
413/// <summary>
414/// Prints all rows.
415/// </summary>
416/// <remarks>
417/// See the <see cref="ManualBuild"/> event for more details.
418/// </remarks>
419public void PrintRows()
420{
421for (int i = 0; i < Rows.Count; i++)
422{
423PrintRow(i);
424}
425}
426
427/// <summary>
428/// Prints a column with specified index.
429/// </summary>
430/// <param name="index">Index of a column to print.</param>
431/// <remarks>
432/// See the <see cref="ManualBuild"/> event for more details.
433/// </remarks>
434public void PrintColumn(int index)
435{
436if (!IsManualBuild)
437throw new TableManualBuildException();
438helper.PrintColumn(index);
439}
440
441/// <summary>
442/// Prints columns with specified indices.
443/// </summary>
444/// <param name="indices">Indices of columns to print.</param>
445/// <remarks>
446/// See the <see cref="ManualBuild"/> event for more details.
447/// </remarks>
448public void PrintColumns(int[] indices)
449{
450foreach (int index in indices)
451{
452PrintColumn(index);
453}
454}
455
456/// <summary>
457/// Prints all columns.
458/// </summary>
459/// <remarks>
460/// See the <see cref="ManualBuild"/> event for more details.
461/// </remarks>
462public void PrintColumns()
463{
464for (int i = 0; i < Columns.Count; i++)
465{
466PrintColumn(i);
467}
468}
469
470/// <summary>
471/// Adds a page before rows or columns.
472/// </summary>
473/// <remarks>
474/// Call this method to insert a page break before the next row or column that you intend to print
475/// using <b>PrintRow(s)</b> or <b>PrintColumn(s)</b> methods.
476/// See the <see cref="ManualBuild"/> event for more details.
477/// </remarks>
478public void PageBreak()
479{
480if (!IsManualBuild)
481throw new TableManualBuildException();
482if (!Report.Engine.UnlimitedHeight && !Report.Engine.UnlimitedWidth)
483helper.PageBreak();
484}
485#endregion
486
487/// <summary>
488/// Initializes a new instance of the <see cref="TableObject"/> class.
489/// </summary>
490public TableObject()
491{
492manualBuildEvent = "";
493manualBuildAutoSpans = true;
494InitTag();
495}
496}
497}
498