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:

Anonymous said...

good and very helpfull...
Thanks..

Vallabh Vaidya said...

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....

John Ward said...

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();
}

}

Vallabh Vaidya said...

Hey Thanks man,
It worked.

Ivan said...

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

mail2eldo said...

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?

Julioc said...

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

John Ward said...

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