Monday, November 26, 2007

BIRT: Dynamic Adding Tables and Columns

I had a request from a co-worker the other day wanting to know how Columns could be Dynamically added to Tables in BIRT. The following example is a Initialize Event Handler used in a BIRT report to dynamically create a table, add a few columns, and a single row. Once added to the report, the script then finds the Table in the report, and adds a single column to the report.


//get a reference to the ElementFactory
elementFactory = reportContext.getReportRunnable().designHandle.getElementFactory();

//create a new table with 3 columns
dynamicTable = elementFactory.newTableItem("myNewTable", 3);
dynamicTable.setWidth("100%");

//set reference to the first detail row
myNewRow = dynamicTable.getDetail().get(0);

//get references to the first 3 cells
firstCell = myNewRow.getCells().get(0);
secondCell = myNewRow.getCells().get(1);
thirdCell = myNewRow.getCells().get(2);

//create the cells and add
label = elementFactory.newLabel("firstCellLabel");
label.setText("First Cell");
firstCell.getContent().add(label);

label = elementFactory.newLabel("secondCellLabel");
label.setText("Second Cell");
secondCell.getContent().add(label);

label = elementFactory.newLabel("thirdCellLabel");
label.setText("Third Cell");
thirdCell.getContent().add(label);

//although it is not in the autocomplete, getBody is a method of the ReportDesignHandle class
reportContext.getReportRunnable().designHandle.getBody().add(dynamicTable);

//now, to demonstrate, get a reference to the table fromt he report design, this automatically cast
//to a TableHandel type
dynamicTable = reportContext.getReportRunnable().designHandle.findElement("myNewTable");

//now insert the column to the right of the indicated column position. Column number is 1 based, not 0 based
dynamicTable.insertColumn(3, 1);

//get the first detail row and the 4th column. This is 0 based
myNewRow = dynamicTable.getDetail().get(0);
forthCell = myNewRow.getCells().get(3);

//create a new label
label = elementFactory.newLabel("forthCell");
label.setText("dynamic cell");
forthCell.getContent().add(label);

8 comments:

  1. Anonymous3:14 AM

    good and very helpfull...
    Thanks..

    ReplyDelete
  2. Anonymous6:00 AM

    I have given a TableEventHandler and in it's initialize() method I wrote following code to place a Label in Report.
    // get a reference to the ElementFactory
    ElementFactory elementFactory = reportContext.getReportRunnable().getDesignHandle().getElementFactory();

    LabelHandle label = elementFactory.newLabel( "firstCellLabel" );
    try {
    label.setText( "First Cell" );
    }
    catch ( SemanticException e ) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    try {
    reportContext.getReportRunnable().getDesignHandle().getContainerSlotHandle().add( label );
    }
    catch ( SemanticException e ) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    But I receives a NullPointer Exception @ reportContext.getReportRunnable().getDesignHandle().getContainerSlotHandle();

    Help me to solve this....

    ReplyDelete
  3. Vallabh,

    You need to cast the getDesignHandle as a report design handle. See the below example:

    public void initialize(IReportContext reportContext) {
    // get a reference to the ElementFactory
    ElementFactory elementFactory = reportContext.getReportRunnable().getDesignHandle().getElementFactory();

    LabelHandle label = elementFactory.newLabel( "firstCellLabel" );
    try {
    label.setText( "First Cell" );
    }
    catch ( SemanticException e ) {
    e.printStackTrace();
    }
    try {
    ReportDesignHandle rd = (ReportDesignHandle) reportContext.getReportRunnable().getDesignHandle();

    rd.getBody().add(label);
    }
    catch ( SemanticException e ) {
    e.printStackTrace();
    }

    }

    ReplyDelete
  4. Anonymous10:41 PM

    Hey Thanks man,
    It worked.

    ReplyDelete
  5. Hi there. I need help with birth and this particular subject. This is how my fecth method looks like:

    if(paymentPeriodIter.hasNext())
    {
    console.println("fetch method called.....");
    paymentPeriod = paymentPeriodIter.next();

    row["gradeName"] = "Classe";
    row["gradePrice"] = "MZM";
    row["matricPrice"] = "Teste";

    //1. get a reference to the ElementFactory
    elementFactory = reportContext.getReportRunnable().designHandle.getElementFactory();

    //2. criar uma nova tabela com numero de colunas equivalente ao numero de classes
    priceTable = elementFactory.newTableItem("priceTable", grades.size() + 1);
    priceTable.setWidth("100%");

    //3. pega a primeira coluna da tabela
    firstColumn = priceTable.getColumns().get(0);
    colLabel = elementFactory.newLabel("firstColumn");
    colLabel.setText("Classe");
    //TODO adicionar style
    //firstColumn.add(colLabel);

    //4. Pegar a primeira linha
    firstRow = priceTable.getDetail().get(0);

    //4.1 Pegar a primeira celula da primeira linha
    firstCell = firstRow.getCells().get(0);

    //4.2 Criar uma label para botar na celula
    cellLabel = elementFactory.newLabel("firstCellLabel");
    cellLabel.setText("MZM");//TODO adicionar cssStyle
    firstCell.getContent().add(cellLabel);
    console.println("Funciona 1");

    //5.Colocar os restantes dados no tabela
    //5.1 Preparar a posição das colunas e celulas da tabela
    currentPos = 1;
    while(currentPos <= grades.size())
    {
    //5.1.1 Pegar a classe
    grade = grades.get(currentPos - 1);

    //5.1.2 Criar a coluna com o detalhes da classe
    column = priceTable.getColumns().get(currentPos);

    //TODO addicio o label da coluna

    //5.1.3 Pegar a celula
    cell = firstRow.getCells().get(currentPos);
    label = elementFactory.newLabel("gradePrice");
    label.setText(String.valueOf(grade.getListPrice()));
    cell.getContent().add(label);

    console.println("Continuo a matar pretos");
    console.println("A classe agora é "+grade.getCode());
    console.println("O preço da classe é "+grade.getListPrice());
    currentPos++;
    }

    //Finalmente addiciona a tabela ao report
    grid = reportContext.getReportRunnable().designHandle.getBody().getContents().get(0);

    //Adicionar uma cell
    gridCell = elementFactory.newCell();
    gridCell.getContent().add(priceTable);
    grid.getRows().get(1).getCells().add(gridCell);

    //grid.getRows().get(1).getCells().get(0).add(paymentPeriod.get("contentId")+"Table",priceTable) ; //Pegar a segunda row da grid, pegar a celula e addicionar a tabela
    console.println("A classe completa é "+reportContext.getReportRunnable().designHandle.getBody());

    return true;
    }
    else
    {
    return false;
    }

    When I run the report it comes out empty. I am in the dark please HELP.

    Kindest Regards.

    Ivan

    ReplyDelete
  6. Is it possible to add this table to an already existing Grid in the report?

    Also, how can I control the number of table columns added based on a database query result?

    ReplyDelete
  7. Hi
    I need to know how to add aggregations dynamically.
    Can any one show me an example?
    I'm able to add columns dynamically, add sorts,etc.

    Thanks for your help

    BTW I bought the book Birt 2.6 and it is excellent start point to BIRT

    ReplyDelete
  8. Aggregations are added as Computed Columns. You create a computed column, setAggregationFunction, setExpression, then add to the column bindings.

    ReplyDelete