Tabulation Script for setting inline style to Table Chart

From Catglobe Wiki
Revision as of 08:30, 30 July 2009 by Catglobe (talk | contribs) (add breadscrump)
Jump to: navigation, search

New Report Design - 2009 => Tabulation Script for setting inline style to Table Chart

Introduction

Customer sometimes need to highlight some fields in a table chart using CGScript, thus a couple of methods have been defined for this need. It's part of the Tabulation Script

StyleSheet Review

StyleSheet defines the layout of chart (both table and image charts). There are 2 kinds of stylesheets: external and internal. External stylesheet is stylesheet that is defined separately and can be reused through out many reports/diagrams. Inline stylesheet, in the other hand, is specific to a diagram only.

The order of applying stylesheet is as below:

  Report        Diagram            Diagram
    |      =>      |      =>          |  
StyleSheet     StyleSheet     Inline StyleSheet

The inline stylesheet is as a higher priority than the external one.

TableChart's CellTypes

Each cell in table chart must belong to at least a cell type. The full list of cell types is below:

   public enum StyleType
   {
      TableDiagram_AllTable,                      // All cell
      TableDiagram_ColumnHeader,                  // All column header
      TableDiagram_ColumnHeaderLevel1,            // Only column header level 1 
      TableDiagram_ColumnHeaderLevel2,            // Only column header level 2 
      TableDiagram_ColumnHeaderLevel3,            // Only column header level 3 
      TableDiagram_RowHeader,                     // All row header 
      TableDiagram_RowHeaderLevel1,               // Only row header level 1 
      TableDiagram_RowHeaderLevel2,               // Only row header level 2 
      TableDiagram_RowHeaderLevel3,               // Only row header level 3 
      TableDiagram_AbsoluteColumn,                // All cells of column that contains absolute value
      TableDiagram_AbsoluteColumnHeader,          // Column header cells of column that contains absolute value
      TableDiagram_AbsoluteColumnValue,           // Column data cells of column that contains absolute value
      TableDiagram_PercentageColumn,              // All cells of column that contains percentage value
      TableDiagram_PercentageColumnHeader,        // Column header cells of column that contains percentage value
      TableDiagram_PercentageColumnValue,         // Column data cells of column that contains percentage value 
      TableDiagram_TotalColumn,                   // All cells of column that contains total value
      TableDiagram_TotalColumnHeader,             // Column header cells of column that contains total value
      TableDiagram_TotalColumnValue,              // Column data cells of column that contains total value 
      TableDiagram_TotalRow,                      // All cells of row that contains total value 
      TableDiagram_TotalRowHeader,                // Row header cells of row that contains total value
      TableDiagram_TotalRowValue,                 // Row data cells of row that contains total value  
      TableDiagram_AnswerRow,                     // All cells that is on even rows
      TableDiagram_AnswerRowAlternate,            // All cells that is on odd rows
      TableDiagram_VarianceRow,                   // All cells of Variance row
      TableDiagram_VarianceRowHeader,             // Row header cells of Variance row
      TableDiagram_VarianceRowValue,              // Row data cells of Variance row 
      TableDiagram_AverageRow,
      TableDiagram_AverageRowHeader,
      TableDiagram_AverageRowValue,
      TableDiagram_StdDevRow,
      TableDiagram_StdDevRowHeader,
      TableDiagram_StdDevRowValue,
      TableDiagram_StdErrorRow,
      TableDiagram_StdErrorRowHeader,
      TableDiagram_StdErrorRowValue,
      TableDiagram_MedianRow,
      TableDiagram_MedianRowHeader,
      TableDiagram_MedianRowValue,
      TableDiagram_QuantilesRow,
      TableDiagram_QuantilesRowHeader,
      TableDiagram_QuantilesRowValue,
      TableDiagram_PercentileRow, 
      TableDiagram_PercentileRowHeader,
      TableDiagram_PercentileRowValue,
      TableDiagram_SignificanceRow,
      TableDiagram_SignificanceRowHeader, 
      TableDiagram_SignificanceRowValue,
      // You could add the other style types of other diaram types here.   
   }

Sample Scripts

Set External Style

    setReportStyleSheetId(1);

Set Internal Style

Set style for cells that belong to TableDiagram_AllTable type:

    array bgcolor = Color_getByName("Olive");    
    array font = DiagramFontStyle_getDefault();    
    font[DIAGRAM_FONT_STYLE_FACE] = "Tahoma";    
    font[DIAGRAM_FONT_STYLE_SIZE] = 10 ;    
    font[DIAGRAM_FONT_STYLE_BOLD] = false;    
    array fill_style = DiagramFillStyle_getDefault();    
    fill_style[DIAGRAM_FILL_STYLE_COLOR] = bgcolor;    
    fill_style[DIAGRAM_FILL_STYLE_TYPE] = Diagram_Fill_Style_SolidFill;    

    array style = Tabulation_getDefaultDiagramStyle(Diagram_Type_Table);    
    style[TABLE_DIAGRAM_STYLE_FILL] = fill_style;    
    style[TABLE_DIAGRAM_STYLE_FONT] = font;    
    Tabulation_setDiagramStyle(TableDiagram_AllTable, style);    

    createCrossDiagram({"Test_Single"},{});

Design

See this link for a detail of report/diagram generation. As a reminder, table chart are not converted to usable presentation type right after calling to CatGlobe.Framework.Report.Diagrams.Builder.ChartBuilder.BuildChart method, instead the returned result is an IEnumerable<ChartTable>. And framework's user must call CopyTo method of ChartTable to convert to concrete presentation table like PDF, HTML, PPT tables.

During the processing of CopyTo the external stylesheet is applied, developers even has a chance to put in inline stylesheet also. The copy method is as below:

      public static T CopyTo<T>(this ChartTable sourceTable, T targetTable)
      {
         return sourceTable.CopyTo(targetTable, null);
      }

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

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

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

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

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

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

         // Apply external style
         targetChartTable.ApplyStyle(sourceTable.Style);

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

         return (T)targetChartTable.InnerTable;
      }

As you might see, the processing is straight forward:

  1. Create a ChartTable wrapper for correspondence presentation type. For example: System.Web.UI.HtmlTable has a wrapper type HtmlChartTable which inherits from ChartTable
  2. Copy cells from source ChartTable to another ChartTable
  3. Then apply the external stylesheet
  4. After all, apply the inline stylesheet (because in this case, the 2 stylesheets can not be merged)
  5. Return the inner table of wrapper ChartTable which is the same object that has been passed to the method

ChartTable(s)

Diagram - Table adaptors 1.gif

The overall idea is hiding the detail of presentation's table implementation behind a ChartTable. Thus, for each kind of presentation table implementation (html/pdf/ppt) there is a correspondence ChartTable's sub class (HtmlChartTable, PdfChartTable, PptChartTable). The same rule is also applied to ChartTableCell which wrap the the presentation cell implementation.

Table Style Applier

ChartTable provides 2 entry methods for applying external and inline stylesheet. Both methods, in anyway, must delegate the applying to its all ChartTableCell(s) with custom processing as required. See the code below:

      public void ApplyStyle(IDictionary<StyleType, StyleBase> inlineStyles)
      {
         if (inlineStyles == null || inlineStyles.Count == 0) return;

         IDictionary<StyleType, ICollection<ChartTableCell>> typesMapping = CreateStyleMapping(inlineStyles.Keys);
         Debug.Assert(typesMapping != null);
         Debug.Assert(typesMapping.Count == inlineStyles.Count);
         
         // Apply using the order in given list
         foreach (KeyValuePair<StyleType, StyleBase> pair in inlineStyles)
            foreach (ChartTableCell cell in typesMapping[pair.Key])
               if (pair.Value is TableDiagramStyle)
                  cell.ApplyStyle((TableDiagramStyle) pair.Value);
               else
                  throw new ApplicationException("Accept only TableDiagramStyle.");
      }

      public void ApplyStyle(TableChartStyle externalStyle)
      {
         if (externalStyle == null) return; // Do nothing if there is no externalStyle
         ForEachCell(c => c.ApplyStyle(externalStyle));
      }

Method CreateStyleMapping create a dictionary whose entry's key is a StyleType and entry's value is a collection of ChartTableCell that belongs to key StyleType. The code come below:

      public IDictionary<StyleType, ICollection<ChartTableCell>> CreateStyleMapping(IEnumerable<StyleType> types)
      {
         IDictionary<StyleType, ICollection<ChartTableCell>> mapping = new Dictionary<StyleType, ICollection<ChartTableCell>>();

         // Init the mapping
         foreach (StyleType type in types)
            mapping[type] = new List<ChartTableCell>();

         // Populate mapping content
         ForEachCell(
            cell =>
            {
               foreach (var type in cell.Types)
                  if (mapping.Keys.Contains(type))
                     mapping[type].Add(cell);
            });

         return mapping;
      }

Cell Style Applier

Diagram - Table stylesheet applier.gif

Using the same idea of hiding detail presentation's implementation of stylesheet, each presentation's table must introduce a new class which implements ICellStyleApplier. In the above diagram, only HtmlTableChartCellStyleApplier is drawn, but in reality there must be the same classes for pdf and ppt presentation types. The implementation of such class is very specific to the presentation's implementation and below is implementation for html presentation type.

      internal class HtmlChartTableCellStyleApplier : ICellStyleApplier
      {
         private readonly HtmlTableCell _cell;

         public HtmlChartTableCellStyleApplier(HtmlTableCell cell)
         {
            if (cell == null) throw new ArgumentNullException("cell");
            _cell = cell;
         }

         public void Apply(FillProperty fillStyle)
         {
            if (fillStyle == null) return;

            switch (fillStyle.StyleSheetFillType)
            {
               case FillProperty.FillType.NoFill:
               case FillProperty.FillType.GradientFill:
                  break;
               case FillProperty.FillType.SolidFill:
                  _cell.BgColor = StyleUtilities.ToHexColor(fillStyle.BackGroundColor);
                  break;
               default:
                  throw new ArgumentOutOfRangeException();
            }
         }

         ... 
     }

Document revisions

Version No. Date Changed By Description
0.1 21.07.2009 Nguyen Trung Chinh Create the first version