Using a report item in a report design
A report item is a visual element in the report design. Typically, a report developer uses BIRT Report Designer to add a report item to the design by dragging an item from the palette to the layout editor. Sometimes a reporting application must change the properties of certain report items in the design before running the report. The application uses methods on the ReportDesignHandle class to access a report item either by name or from a list of items in a slot in a container report item. These methods return a DesignElementHandle object. All report items derive from this class.
A slot is a logical component of a container report item. A slot holds zero or more members of the appropriate report item type. For example, a table element has four slots: Header, Detail, Footer, and Groups. Each of these slots is a container for further slots. The Header, Detail, and Footer slots all contain elements of type RowHandle. RowHandle has a Cell slot that contains all the cells in the row. The Outline view in BIRT Report Designer provides a visual representation of the slots in an individual report item.
Accessing a report item by iterating through a slot
To access a report item through the report design’s structure, first get the slot handle of the report body by calling the ReportDesignHandle.getBody( ) method. This slot handle holds the top-level report items in the report design. For example, consider a simple report structure that has a table with a header detail row, and footer, with two named groups called ProductLineGroup and ProductNameGroup. Figure 5‑3 shows its Outline view in BIRT Report Designer.
Figure 5‑3 Slots in a report design
To access the top-level items in this report design, iterate over the contents of the body slot handle. To access the iterator for a slot handle, call SlotHandle.iterator( ). Each call to Iterator.getNext( ) returns ReportDesignHandle object, which is a handle to a report item or another slot. Alternatively, to access a report item at a known slot index, call SlotHandle.get( ). The slot index number is zero-based.
Accessing a report item by name
To make a report item accessible by name, the item must have a name. Either a report developer sets the name in BIRT Report Designer or an application sets the name programmatically by using the item’s setName( ) method. To find a report item by name, use ReportDesignHandle.findElement( ).
Examining a report item
To examine a report item, check the class of the report item and cast the object to its actual class. Then, call methods appropriate to that class. For example, the class of a label element handle is LabelHandle. To get the text that the label displays, call LabelHandle.getText( ).
Some report items, such as a label or a text element, are simple items. Other items, such as a grid or a table element, are structured items. Access properties for the whole of a structured item in the same way as for a simple item.
To examine the contents of a structured item, iterate over its slots. Use this technique to determine the contents of a cell in a table. First, call a method to retrieve a slot handle for the table’s rows. Next, iterate over the contents of the slot to access the cells. For example, to access the RowHandle objects that make up a table element’s footer, call TableHandle.getFooter( ). Table and list elements also have a slot for groups.
Accessing the properties of a report item
To provide information about report items, each class has getter methods specific to the report item type. For example, an image element handle, ImageHandle, has the getURI( ) method. This method returns the URI of an image referenced by URL or file path. The DesignElementHandle class and other ancestor classes in the hierarchy also provide generic getter methods, such as getName( ).
Some properties of a report item are simple properties of a Java type or type wrapper class. An example of a simple property is the name property, which is a String object. Some simple properties, like name, have an arbitrary value. Other simple properties have restricted values from a set of BIRT String constants. The interface, DesignChoiceConstants in the package, org.eclipse.birt.report.model.api.elements, defines these constants. For example, the image source property of an image element can have one of the following values: IMAGE_REF_TYPE_EMBED, IMAGE_REF_TYPE_EXPR, IMAGE_REF_TYPE_FILE, IMAGE_REF_TYPE_NONE, or IMAGE_REF_TYPE_URL.
Other properties are complex properties and the getter method returns a handle object. For example, the DesignElementHandle.getStyle( ) method returns a SharedStyleHandle object and ReportItemHandle.getWidth( ) returns a DimensionHandle object. The handle classes provide access to complex properties of a report item, as described later in this chapter. These classes provide getter methods for attributes of the complex properties. For example, StyleHandle classes provide access to background color, font, and highlights.
How to access a report item by name
The code sample in Listing 5‑17 finds an image item by name, checks its type, and examines its URI. The variable, design, is a ReportDesignHandle object.
Listing 5‑17 Finding a report item having a given name
DesignElementHandle logoImage =
design.findElement( "Company Logo" );
// Check for the existence of the report item.
if ( logoImage == null) {
return null;
}
// Check that the report item has the expected class.
if ( !( logoImage instanceof ImageHandle ) ) {
return null;
}
// Retrieve the URI of the image.
String imageURI = ( (ImageHandle ) logoImage ).getURI( );
return imageURI;
How to use the report structure to access a report item
The code sample in Listing 5‑18 finds an image item in a grid, checks its type, and examines its URI. Use this technique for generic code to navigate a report design structure or if to find an item that does not have a name. The variable, design, is a ReportDesignHandle object.
Listing 5‑18 Navigating the report structure to access a report item
// Instantiate a slot handle and iterator for the body slot.
SlotHandle shBody = design.getBody( );
Iterator slotIterator = shBody.iterator( );
 
// To retrieve top-level report items, iterate over the body.
while (slotIterator.hasNext( )) {
Object shContents = slotIterator.next( );
// To get the contents of the top-level report items,
// instantiate slot handles.
if ( shContents instanceof GridHandle ) {
GridHandle grid = ( GridHandle ) shContents;
SlotHandle grRows = grid.getRows( );
Iterator rowIterator = grRows.iterator( );
while ( rowIterator.hasNext( )) {
// Get RowHandle objects.
Object rowSlotContents = rowIterator.next( );
// To find the image element, iterate over the grid.
SlotHandle cellSlot =
( ( RowHandle ) rowSlotContents ).getCells( );
Iterator cellIterator = cellSlot.iterator( );
 
while ( cellIterator.hasNext( )) {
// Get a CellHandle object.
Object cellSlotContents = cellIterator.next( );
SlotHandle cellContentSlot =
( ( CellHandle) cellSlotContents ).getContent( );
Iterator cellContentIterator =
cellContentSlot.iterator( );
 
while ( cellContentIterator.hasNext( )) {
// Get a DesignElementHandle object.
Object cellContents =
cellContentIterator.next( );
// Check that the element is an image.
if (cellContents instanceof ImageHandle) {
String is = ( ( ImageHandle ) cellContents )
.getSource( );
// Check that the image has a URI.
if ( ( is.equals( DesignChoiceConstants.IMAGE_REF_TYPE_URL ))
|| ( is.equals( DesignChoiceConstants.IMAGE_REF_TYPE_FILE ))) {
// Retrieve the URI of the image.
String imageURI = ( ( ImageHandle ) cellContents ).getURI( );
}
}
}
}
}
}
}
Modifying a report item in a report design
To set the simple properties of report items, each class has setter methods specific to the report item type. For example, an image element handle, ImageHandle, has the setURI( ) method. This method sets the URI of an image referenced by URL or file path. The DesignElementHandle class and other ancestor classes in the hierarchy provide generic setter methods, such as setName( ). Setter methods throw exceptions, such as NameException, SemanticException, and StyleException.
To set attributes of a complex property, such as a style, call methods on a handle object, as described later in this chapter. These classes provide setter methods for related properties. For example, StyleHandle classes provide access to style properties, such as font and background color.
How to change a simple property of a report item
The code sample in Listing 5‑19 uses a method on LabelHandle to change the text in a label. The variable, design, is a ReportDesignHandle object. This sample accesses the label by name. Alternatively, access a report item by navigating the report structure.
Listing 5‑19 Changing the text property of a label report item
// Access the label by name.
LabelHandle headerLabel =
( LabelHandle ) design.findElement( "Header Label" );
try {
headerLabel.setText( "Updated " + headerLabel.getText( ));
} catch ( Exception e ) {
// Handle the exception
}
Accessing and setting complex properties
Complex properties use BIRT handle objects to access data structures. For example, a DimensionHandle object provides access to size and position properties, such as the absolute value and the units of the width of a report item. Some String properties on a handle object, such as font style and text alignment on a style handle, have restricted values defined by constants in the org.eclipse.birt.report.model.api.elements.DesignChoiceConstants interface. For example, the font style property can have one of only the values, FONT_STYLE_ITALIC, FONT_STYLE_NORMAL, or FONT_STYLE_OBLIQUE.
Using a BIRT property handle
To access complex properties, use getter methods on the report item. For example, to access the width of a report item, call the method ReportItemHandle.getWidth( ). This method returns a DimensionHandle object. To work with complex properties, use getter and setter methods on the property handle object. For example, to get and set the size of a dimension, use the DimensionHandle methods getMeasure( ) and setAbsolute( ), respectively. Calling a method on a property handle object to set a value on a complex property affects the report item straight away. You do not call another setter method on the report item itself.
Using styles on a report item
The StyleHandle class provides access to many fundamental properties of a report item, such as margin size, text alignment, background color, borders, font, and so on. StyleHandle provides a full set of getter methods for each style property. For simple properties, StyleHandle provides setter methods. To modify complex properties, use setter methods on the property handle object, not on the style handle itself.
A report item can use two styles; a private style and a shared style. The handle classes for these styles are PrivateStyleHandle and SharedStyleHandle, respectively. Both classes derive from StyleHandle.
A private style contains the settings that the report developer chose in the property editor when designing the report using BIRT Report Designer. Shared styles appear in the Outline view in BIRT Report Designer. Use shared styles to apply the same appearance to multiple items in a report design. Changes to a shared style affect all report items that use the style. Style settings in a private style override the settings in a shared style.
How to change a complex property of a report item
The code sample in Listing 5‑20 shows how to use PrivateStyleHandle and ColorHandle objects to change the background color of a label. The variable, design, is a ReportDesignHandle object. This sample accesses the label by name. Alternatively, access a report item by navigating the report structure.
Listing 5‑20 Changing a complex property of a report item
// Access the label by name.
LabelHandle headerLabel =
( LabelHandle ) design.findElement( "Header Label" );
try {
// To prepare to change a style property, get a StyleHandle.
StyleHandle labelStyle = headerLabel.getPrivateStyle();
// Update the background color.
ColorHandle bgColor = labelStyle.getBackgroundColor();
bgColor.setRGB( 0xFF8888 );
} catch ( Exception e ) {
// Handle the exception
}
Understanding property structure objects
Complex property structures represent many optional report element features within BIRT. For example, computed columns, highlight rules, sort keys, and table of contents entries are all optional complex properties of report elements. The classes for these properties all derive directly or indirectly from org.eclipse.birt.report.model.core.Structure. An application can access existing structure property objects on a report element or create new ones.
Using an existing property structure object
Use the property handle, which is an object of class PropertyHandle, to apply a new structure object to a report element’s property or to modify an existing property structure. To access the property handle call the method, DesignElementHandle.getPropertyHandle( ), which is available on all report elements. This method takes a String argument that defines the property to access. Class fields having names of the form XXX_PROP define the available property structures for a report element class. The property handle object provides access to one or more property structure objects. Use the PropertyHandle getter methods to access settings on existing property structures.
Typically, the property structure class provides setter methods only for a few key values. Set other values by calling the property structure object’s setProperty( ) method. This method takes two arguments: a String that identifies the property and an object that specifies the value. Class fields defined on the property structure class or on the DesignChoiceConstants class provide the values for the property identifier.
How to set values on an existing property structure object
The code sample in Listing 5‑21 shows how to change the sort direction value on a table item’s first sort key.
Listing 5‑21 Changing the sort direction on a table
void modSortKey( TableHandle th ) {
try {
SortKeyHandle sk;
PropertyHandle ph =
th.getPropertyHandle( TableHandle.SORT_PROP );
if ( ph.isSet( ) ) {
sk = ( SortKeyHandle ) ph.get( 0 );
sk.setDirection
( DesignChoiceConstants.SORT_DIRECTION_DESC );
}
} catch ( Exception e ) {
e.printStackTrace( );
}
}
Creating a property structure object
The design engine class, StructureFactory, provides static methods for creating property structure objects. Most StructureFactory methods take the form createXXX, where XXX is the structure to create. After creating a new structure object, set its simple or complex properties using its setter methods. Report element handles provide methods to add key structure properties to their property handles. For example, add a filter condition to a data set object by using the addFilter( ) method. To add other properties to a report element, use the method, PropertyHandle.addItem( ).
How to create a complex property object
The code sample in Listing 5‑22 shows how to create a highlight rule object and apply that rule to a row handle. The variable, rh, is a RowHandle object. Because RowHandle does not have a specific method to add a highlight rule property, the code uses the PropertyHandle.addItem( ) method.
Listing 5‑22 Adding a highlight rule to a table or grid row
try {
HighlightRule hr = StructureFactory.createHighlightRule( );
hr.setOperator( DesignChoiceConstants.MAP_OPERATOR_GT );
hr.setTestExpression( "row[\"CustomerCreditLimit\"]" );
hr.setValue1( "100000" );
hr.setProperty
( HighlightRule.BACKGROUND_COLOR_MEMBER, "blue" );
 
PropertyHandle ph =
rh.getPropertyHandle( StyleHandle.HIGHLIGHT_RULES_PROP );
ph.addItem( hr );
} catch ( Exception e ){ e.printStackTrace(); }
The code samples in Listing 5‑23 provide further examples of using the structure factory to create complex properties.
Listing 5‑23 Various structure factory examples
// Use the structure factory to add a sort key to a table.
void addSortKey( TableHandle th ) {
try {
SortKey sk = StructureFactory.createSortKey( );
sk.setKey( "row[\"CustomerName\"]" );
sk.setDirection
( DesignChoiceConstants.SORT_DIRECTION_ASC );
 
PropertyHandle ph =
th.getPropertyHandle( TableHandle.SORT_PROP );
ph.addItem( sk );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add a column binding to a table.
void addColumnBinding( TableHandle th ) {
try {
ComputedColumn cs1;
cs1 = StructureFactory.createComputedColumn( );
cs1.setName( "CustomerName" );
cs1.setExpression( "dataSetRow[\"CUSTOMERNAME\"]" );
th.addColumnBinding( cs1, false );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add a filter condition to a table.
void addFilterCondition( TableHandle th ) {
try {
FilterCondition fc = StructureFactory.createFilterCond();
fc.setExpr( "row[\"CustomerCountry\"]" );
fc.setOperator(DesignChoiceConstants.MAP_OPERATOR_EQ);
fc.setValue1("'USA'");
PropertyHandle ph =
th.getPropertyHandle( TableHandle.FILTER_PROP );
ph.addItem( fc );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add a filter condition to a data set.
void addFilterCondition( OdaDataSetHandle dh ) {
try {
FilterCondition fc = StructureFactory.createFilterCond();
fc.setExpr( "row[\"COUNTRY\"]" );
fc.setOperator( DesignChoiceConstants.MAP_OPERATOR_EQ );
fc.setValue1( "'USA'" );
// Add the filter to the data set.
dh.addFilter( fc );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add a hyperlink to a label.
void addHyperlink( LabelHandle lh ) {
try {
Action ac = StructureFactory.createAction( );
ActionHandle actionHandle = lh.setAction( ac );
actionHandle.setURI( "'http://www.google.com'" );
actionHandle.setLinkType
( DesignChoiceConstants.ACTION_LINK_TYPE_HYPERLINK );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add a table of contents entry to a data item.
void addToc( DataItemHandle dh ) {
try {
TOC myToc = StructureFactory.createTOC
( "row[\"CustomerName\"]" );
dh.addTOC( myToc );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Add an embedded image to the report design.
void addImage( ) {
try {
EmbeddedImage image =
StructureFactory.createEmbeddedImage( );
image.setType
( DesignChoiceConstants.IMAGE_TYPE_IMAGE_JPEG );
image.setData( load( "logo3.jpg" ));
image.setName( "mylogo" );
designHandle.addImage( image );
} catch ( Exception e ) { e.printStackTrace( ); }
}
 
// Load the embedded image from a file on disk.
public byte[ ] load( String fileName ) throws IOException
{
InputStream is = null;
is = new BufferedInputStream
( this.getClass( ).getResourceAsStream( fileName ));
byte data[ ] = null;
if ( is != null ) {
try {
data = new byte[is.available( )];
is.read( data );
}
catch ( IOException e1 ) {
throw e1;
}
}
return data;
}
Adding a report item to a report design
A reporting application can use a simple report design or a template to create more complex designs. The application can add extra report items to the design’s structure based on external conditions. For example, based on the user name of the user requesting generation of a report, the application can add extra information to the report for that category of user. To create a design entirely with the API, use the same techniques to add content to the design.
The class that creates new elements, such as report items, in a report design is ElementFactory. This class provides methods of the form, newXXX( ), where XXX is the type of report element to create. The method newElement( ) is a generic method that creates an element of any type. To access the element factory, call the ReportDesign.getElementFactory( ) method.
Place new report items directly in the body slot, within containers such as a cell in a table or grid, or on the master page. The model API supports adding a simple item, such as a label, or complex items, such as a table with contents in its cells. The location of the new report item is a slot, such as the body slot of the report design or a cell slot in a row in a table. To add a report item to a slot, use one of the SlotHandle.add( ) methods. The method has two signatures that support adding the report item to the end of a slot, or to a particular position in a slot.
Table and list elements iterate over the rows that a data set provides. To support access to the data rows for these report item types, bind the item to a data set. The table or list element provides data rows to the report items that it contains. For this reason, bind only the container item to a data set, as described later in this chapter.
How to add a grid item and label item to a report design
The code sample in Listing 5‑24 creates a grid item and adds a label item to one of the cells in the grid. An application can create any other report item in a similar manner. The variable, design, is a ReportDesignHandle object.
Listing 5‑24 Adding a container item to the body slot
// Instantiate an element factory.
ElementFactory factory = design.getElementFactory( );
try {
// Create a grid element with 2 columns and 1 row.
GridHandle grid = factory.newGridItem( "New grid", 2, 1 );
// Set a simple property on the grid, the width.
grid.setWidth( "50%" );
// Create a new label and set its properties.
LabelHandle label = factory.newLabel( "Hello Label" );
label.setText( "Hello, world!" );
 
// Get the first row of the grid.
RowHandle row = ( RowHandle ) grid.getRows( ).get( 0 );
// Add the label to the second cell in the row.
CellHandle cell = ( CellHandle ) row.getCells( ).get( 1 );
cell.getContent( ).add( label );
 
// Get the body slot. Add the grid to the end of the slot.
design.getBody( ).add( grid );
} catch ( Exception e ) {
// Handle any exception
}