123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using FastReport.Table;
- namespace FastReport.AdvMatrix
- {
- internal class CellData
- {
- private AdvMatrixObject matrix;
- private List<CellDescriptor> descriptors;
- private ExpressionCache expressionCache;
- private Hashtable processedIndices;
- public AggregateExpressionPairList SharedAggregates { get; private set; }
- private void BeforeProcess()
- {
- expressionCache.Clear();
- processedIndices.Clear();
- }
- private void ProcessDataRow(int columnIndex, int rowIndex)
- {
- // filter out repeated calculation with the same indices. It may occur if a cell has reference to column/row totals,
- // and a header has nested items. Repeated calculation will lead to doubling the total values.
- long compoundIndex = ((long)columnIndex << 32) + rowIndex;
- if (processedIndices.ContainsKey(compoundIndex))
- return;
- processedIndices[compoundIndex] = 1;
- // process all aggregates
- foreach (AggregateExpressionPair item in SharedAggregates)
- {
- item.ProcessDataRow(columnIndex, rowIndex, expressionCache.Calc(item.Expression));
- }
- }
- // searches for existing aggregate and returns it if any; otherwise returns null
- public AggregateExpressionPair FindAggregate(AggregateExpressionPair aggr)
- {
- if (aggr == null)
- return null;
- foreach (CellDescriptor d in descriptors)
- {
- AggregateExpressionPair result = d.Aggregates.Find(aggr.AggregateName, aggr.Expression);
- if (result != null)
- return result;
- }
- return null;
- }
- public void InitDescriptors()
- {
- descriptors.Clear();
- ExpressionParser parser = new ExpressionParser(matrix);
- SharedAggregates = new AggregateExpressionPairList(matrix);
- int offsetX = matrix.Data.Rows.Size;
- int offsetY = matrix.Data.Columns.Size;
- for (int x = offsetX; x < matrix.Columns.Count; x++)
- {
- for (int y = offsetY; y < matrix.Rows.Count; y++)
- {
- TableCell cell = matrix[x, y];
- CellDescriptor d = parser.ProcessCell(cell);
- descriptors.Add(d);
- // share aggregates among cell descriptors
- for (int i = 0; i < d.Aggregates.Count; i++)
- {
- d.Aggregates[i] = SharedAggregates.AddUnique(d.Aggregates[i]);
- }
- // forbid cell to process its expressions
- cell.AllowExpressions = false;
- }
- }
- }
- public void GetExpressions(List<string> expressions)
- {
- foreach (CellDescriptor d in descriptors)
- {
- d.GetExpressions(expressions);
- }
- }
- public void ClearData()
- {
- foreach (CellDescriptor descr in descriptors)
- {
- descr.ClearData();
- }
- }
- public void Init()
- {
- ClearData();
- foreach (CellDescriptor d in descriptors)
- {
- d.ColumnIndex = matrix.Data.Columns.NextIndex;
- d.RowIndex = matrix.Data.Rows.NextIndex;
- }
- }
- public void ProcessDataRow(List<HeaderData> columnItems, List<HeaderData> rowItems)
- {
- BeforeProcess();
- foreach (HeaderData columnItem in columnItems)
- {
- foreach (HeaderData rowItem in rowItems)
- {
- if (columnItem.Descriptor.IsTopNItem || rowItem.Descriptor.IsTopNItem)
- continue;
- TableCell cell = matrix[columnItem.Descriptor.TemplateColumn.Index, rowItem.Descriptor.TemplateRow.Index];
- CellDescriptor descr = cell.GetDescriptor();
- ProcessDataRow(columnItem.Index, rowItem.Index);
- // calculate column total, row total and grand total for the given cell
- if (descr.HasColumnTotal)
- ProcessDataRow(columnItem.Index, descr.RowIndex);
- if (descr.HasRowTotal)
- ProcessDataRow(descr.ColumnIndex, rowItem.Index);
- if (descr.HasGrandTotal)
- ProcessDataRow(descr.ColumnIndex, descr.RowIndex);
- }
- }
- }
- public CellData(AdvMatrixObject matrix)
- {
- this.matrix = matrix;
- descriptors = new List<CellDescriptor>();
- expressionCache = new ExpressionCache(matrix);
- processedIndices = new Hashtable();
- }
- // expression cache is used to store expression values between ProcessDataRow calls. It saves a lot of time if several cells share the same expression.
- private class ExpressionCache
- {
- private Dictionary<string, object> cache;
- private AdvMatrixObject matrix;
- public void Clear()
- {
- cache.Clear();
- }
- public object Calc(string expression)
- {
- Report report = matrix.Report;
- if (String.IsNullOrEmpty(expression) || report == null)
- return null;
- object value;
- if (!cache.TryGetValue(expression, out value))
- {
- value = report.Calc(expression);
- cache[expression] = value;
- }
- return value;
- }
- public ExpressionCache(AdvMatrixObject matrix)
- {
- cache = new Dictionary<string, object>();
- this.matrix = matrix;
- }
- }
- }
- }
|