Tabulation Script for setting inline style to Table Chart

From Catglobe Wiki
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.

Style Applier

Diagram - Table stylesheet applier.gif

At the top of the style applying process is the StyleManager class which provide input method ApplyTableStyle which accepts both external stylesheet and inline stylesheet as parameter. The method then determine table specific and cell specific styles, then apply them to table level and cell level by calling ApplyStyle method.

A little lower in the diagram is the interface IStyleApplicable which is implemented by both TableChart and TableChartStyle, implementing this interface indicates that the class is style realizable. By default, the generic TableChart/TableChartCell provide an empty implementation of GetStyleApplier method and leave that to concrete implementation to return the custom StyleApplier.

Concrete TableChart/TableChartCell must implement GetStyleApplier by returning classes that implement TableStyleApplier/CellStyleApplier respectively. The 2 classes in turn inherit from StyleApplier which implement VisitMethodImpl.

Thus, the process of applying style can be done using Generic object visitor pattern. There is only one thing to stay focus on is that, all Apply style method must conform to type Action<T, VisitContext> and must be registered as visit method. See code below:

internal abstract class StyleApplier : VisitMethodImpl
{
      protected StyleApplier()
      {
         AddVisitMethod<TableBorderLineStyle>(Apply);
         AddVisitMethod<PaddingProperty>(Apply);
         AddVisitMethod<object>(Apply);
      }

      public void Apply(TableBorderLineStyle borderLineStyle, VisitContext context) { }
     
      public void Apply(PaddingProperty padding, VisitContext context) { }
    
      public void Apply(object genericStyle, VisitContext context) { } 
   }
}

Another thing to be careful of is that in project ReportLayout2006 there are 2 base classes of all stylesheet setting (why not just one???!!!) are StyleBase and StylePropertyBase. Because there is no common class for all style classes, then we MUST implement a generic Apply method which received object as parameter and in this method we limit the types that are accepted. See code below:

      public void Apply(object genericStyle, VisitContext context)
      {
         if (genericStyle == null) return;

         // Get target object's type
         Type type = genericStyle.GetType();

         // Accept only types of StyleBase or StylePropertyBase
         if (!type.IsSubclassOf(typeof(StylePropertyBase)) &&
             !type.IsSubclassOf(typeof(StyleBase)))
            return;

         // Now let's visit child properties
         foreach (PropertyInfoWrapper info in GetStyleProperties(type))
            Visitor.Visit(info.GetValue(genericStyle),
               new VisitContext { ObjectName = info.PropertyInfo.Name });

         return;
      }
  • Method GetStyleProperties returns all instance public properties whose type inherit from either StyleBase or StylePropertyBase.

NOTE: till now, all table specific stylesheet are applicable to cell stylesheet also, so the implementation is moved to a higher level in hierarchy and leave this class blank for forward compatible (in case we would have more specific settings for table)

Document revisions

Version No. Date Changed By Description Revision
0.1 21.07.2009 Nguyen Trung Chinh Create the first version NA
0.1 21.07.2009 Nguyen Trung Chinh Update according to new design 56374