Table chart builder

From Catglobe Wiki
Jump to: navigation, search

<accesscontrol>Main:MyGroup</accesscontrol> New Report Design - 2009 => Diagram generation process => Table chart builder

Introduction

Nevron chart has the simplicity in term of format, because after all processing it just returns an image which is supported through all formats (html, pdf, ppt, excel). However, this is not the same for table. Each library that we are using provide different API for handling tables. Thus, we need different approach.

Luckily, despite of differences in API of libraries, they still share common processing of a table. So, I decided to make common table interface and adapters to different API. Doing like this allow me to focus on the common table interface only when dealing with CatGlobe business like populating table's data, apply style sheet. And later on, when come to a specific format, I can now only focus on table processing of the correspondence library.

Class Diagram

Diagram - Table adaptors 1.gif

  • ChartTable and ChartTableCell are generic table/cell classes that are used inside CatGlobe.Report
  • xxxChartTable and xxxChartTableCell are adapters for specific implementation of tables and cells. Each adapter contains an instance of concrete table/cell.

Adapters contain similar processing, so to demonstrate the implementation, only HtmlChartTable is described in this document

ChartTable

ChartTable

Common properties

This class contains the most common behaviors of a table like

  • RowCount, CellCount
  • Rows and cells can be accessed using index as: this[rowIndex] or this[rowIndex, columnIndex]

LINQ methods

This class also support LINQ methods for looping through the table:

      public void ForEachRow(Action<int, ChartTableCell[]> action);
      public void ForEachCell(Action<ChartTableCell> action);

Copy methods

There are also method co copy data from ChartTable to another ChartTable, this feature is the core functionality of ChartTable and will be explained later.

Style methods

There are 2 methods correspond to 2 kinds of stylesheet (external and inline):

      public void ApplyStyle(IDictionary<StyleType, StyleBase> inlineStyles);

      public void ApplyStyle(TableChartStyle externalStyle)

ChartTableCell

Besides common table cell properties (RowIndex, ColumnIndex, ColumnSpan, RowSpan, Merged, Value) it also contains some CatGlobe specific information:

  • Cell types: a list of types that this cell belong to, possible values are column header, row header, even row value, odd row value etc. See Tabulation Script for setting inline style to Table Chart for more explanation
  • Copy method to copy data between 2 ChatTableCell => will be explained later
  • Apply style method for apply external and inline stylesheet:
      public void ApplyStyle(TableDiagramStyle inlineStyle)

      public void ApplyStyle(TableChartStyle externalStyle)

HtmlChartTable

HtmlChartTable

   public sealed class HtmlChartTable : ChartTable
   {
      private readonly HtmlTable _table;

      public override object InnerTable
      {
         get { return _table; }
      }

      protected override ChartTableCell CreateNewCell(int rowIndex, int columnIndex)
      {
         var realCell = new HtmlTableCell {InnerHtml = "&nbsp;"};
         _table.Rows[rowIndex].Cells.Add(realCell);

         return new HtmlChartTableCell(realCell) {RowIndex = rowIndex, ColumnIndex = columnIndex};
      }

      protected override void OnRowAdded()
      {
         _table.Rows.Add((new HtmlTableRow()));
      }
   }
  • The real table that contain data is HtmlTable whose instance is _table variable
  • The adapter responds to events like new row added, new cell added by inserting into the REAL table

HtmlTableChartCell

      internal class HtmlChartTableCell : ChartTableCell
      {
         private readonly HtmlTableCell _cell;

         public override object InnerCell
         {
            get { return _cell; }
         }

         public override int ColumnSpan
         {
            get { return base.ColumnSpan; }
            set
            {
               base.ColumnSpan = value;
               _cell.ColSpan = value;
            }
         }

         public override int RowSpan
         {
            get { return base.RowSpan; }
            set
            {
               base.RowSpan = value;
               _cell.RowSpan = value;
            }
         }

         public override bool Merged
         {
            get { return base.Merged; }
            protected set
            {
               base.Merged = value;
               _cell.Visible = !value;
            }
         }

         public override string Value
         {
            get { return base.Value; }
            set
            {
               base.Value = value;
               _cell.InnerText = HttpUtility.HtmlEncode(value);
            }
         }
      }

Basically, cell adapter contains a REAL cell and common properties of ChartTableCell would have same properties in the REAL cell. And the implementation is rather simple, passing value to the REAL cell.

Copy data between 2 ChartTable

Why do we need to copy data ?

The root cause is the REAL table that is wrapped inside a ChartTable's adapter. The only problem is that, with some framework like Aspose.Slides we could not instantiate a instance of table, but instead table must be created by calling parent container's CreateTable method.

If we can create any table using its constructor then this constructor

      internal class HtmlChartTableCell : ChartTableCell
      {
         public HtmlChartTableCell(HtmlTableCell innerCell);
      }

is not needed anymore, because we can simply create an instance of REAL table and populate data into it. However, that is not always the case, and we need to pass the REAL table over the constructor of adapter for building up.

So, the steps of building ChartTable can be considered as:

  1. Build data into a generic ChartTable
  2. Copy data from ChartTable into required adapter which is also a ChartTable

In term of performance, this 2 phases process is not good but it has to be like that.

Implementation

      public T CopyTo<T>(T targetTable, IDictionary<StyleType, StyleBase> inlineStyles)
      {
         ChartTable targetChartTable;

         if (targetTable is HtmlTable)
            targetChartTable = new HtmlChartTable(targetTable as HtmlTable, RowCount, ColumnCount);

         else if (targetTable is Aspose.Pdf.Table)
            targetChartTable = new PdfChartTable(targetTable as Aspose.Pdf.Table, RowCount, ColumnCount);

         else if (targetTable is Aspose.Slides.Table)
            targetChartTable = new PptChartTable(targetTable as Aspose.Slides.Table, RowCount, ColumnCount);

         else
            throw new NotSupportedException(targetTable.GetType() + " is not supported for creating a ChartTable.");

         // Copy data for all cells
         ForEachCell(cell => targetChartTable[cell.RowIndex, cell.ColumnIndex].CopyData(cell));

         // Apply style
         targetChartTable.ApplyStyle(Style);

         // Apply inline styles
         if (inlineStyles != null && inlineStyles.Count > 0)
            targetChartTable.ApplyStyle(inlineStyles);

         return (T)targetChartTable.InnerTable;
      }
  • Inputs:
    • A REAL table instance which must be either of types: System.Web.UI.Controls.HtmlTable, Aspose.Pdf.Table or Aspose.Slides.Table
    • Inline stylesheet that need to be applied
  • Output
    • The given REAL table filling with data and stylesheet settings
  • Processing:
    • First of all, create an adapter for the REAL table base on its type
    • For each cell, copy data from ChartTable to adapter. Copy data between cells is as simple as copying common properties
    • Implement post processing if required
    • Apply external stylesheet
    • Apply inline stylesheet if one is given

Document revisions

Version No. Date Changed By Description Svn revision
0.1 04.08.2009 Nguyen Trung Chinh Create first version 54885