Binding the report item to data
BIRT report items access data only through column bindings. Column bindings form an intermediate layer between data set data and report items that display data. Column bindings can also access data derived from functions or user‑defined formulas.
To support data bindings, the RotatedText property must be binding-aware, so the text value can change dynamically. The implementation involves changes in the model, the presentation, and the user interface of the RotatedText report item. The user interface modifications include changes in the RotatedText item builder and the property editor.
Changes in the model definition
To support data binding for the text property, change the model extension definition. The property type of the text is an expression; ensure that there are quotation marks around the default value, as shown in Figure 23‑37. This indicates that the property supports expressions and has valid JavaScript literal string syntax.
Figure 23‑37 Setting the text property definition to an expression
Changes in the report item presentation
To support expressions, the code of the onRowSets( ) method of RotatedTextPresentationImpl class must be changed, as shown in Listing 23‑25. The new code adds logic to handle the text property as an expression. The code evaluates the text value under the current engine context to get the final string result.
Listing 23‑25 onRowSets method of the RotatedTextPresentationImpl class
public Object onRowSets( IBaseResultSet[] results )
throws BirtException
{
if ( textItem == null )
{
return null;
}
 
int angle = textItem.getRotationAngle( );
String text = textItem.getText( );
// XXX added to support expression
if ( results != null && results.length > 0 )
{
if ( results[0] instanceof IQueryResultSet
&& ( (IQueryResultSet) results[0] ).isBeforeFirst( ) )
{
( (IQueryResultSet) results[0] ).next( );
}
text = String.valueOf( results[0].evaluate( text ) );
} else
{
text = String.valueOf( context.evaluate( text ) );
}
// end new code
BufferedImage rotatedImage =
SwingGraphicsUtil.createRotatedTextImage( text, angle,
new Font( "Default", 0, 12 ) ); //$NON-NLS-1$
ByteArrayInputStream bis = null;
try {
ImageIO.setUseCache( false );
ByteArrayOutputStream baos = new ByteArrayOutputStream( );
ImageOutputStream ios =
ImageIO.createImageOutputStream( baos );
ImageIO.write( rotatedImage, "png", ios ); //$NON-NLS-1$
ios.flush( );
ios.close( );
bis = new ByteArrayInputStream( baos.toByteArray( ) );
}
catch ( IOException e ) {
e.printStackTrace( );
}
return bis;
}
Changing the report item UI to support expressions
To update the user interface you must make changes in two places—the builder and the property page.
Adding data binding to the builder
To enable report developers to use the standard BIRT expression builder to construct a data-binding expression, the report item builder must provide a button to launch the expression builder. Place the button beside the text control, as shown in Figure 23‑38.
Figure 23‑38 RotatedText builder
The standard BIRT expression builder, shown in Figure 23‑39, provides JavaScript support and access to any data sets defined for the report design.
Figure 23‑39 The standard BIRT expression builder
The code of the RotatedTextBuilder class changes, as shown in Listing 23‑26. The newly created RotatedTextEditor2 class overwrites the UI creation logic for the new expression button. It also calls a new getModelHandle( ) method from the RotatedTextItem class.
Listing 23‑26 RotatedTextBuilder class
public class RotatedTextBuilder extends ReportItemBuilderUI
{
public int open( ExtendedItemHandle handle )
{
try {
IReportItem item = handle.getReportItem( );
 
if ( item instanceof RotatedTextItem )
{
RotatedTextEditor editor = new RotatedTextEditor2(
Display.getCurrent( ).getActiveShell( ),
(RotatedTextItem) item );
return editor.open( );
}
}
catch ( Exception e ) {
e.printStackTrace( );
}
return Window.CANCEL;
}
}
 
class RotatedTextEditor2 extends RotatedTextEditor
{
protected RotatedTextEditor2( Shell shell,
RotatedTextItem textItem )
{
super( shell, textItem );
}
 
protected void createTextArea( Composite parent )
{
Label lb = new Label( parent, SWT.None );
lb.setText( "Text Content:" ); //$NON-NLS-1$
 
txtText = new Text( parent, SWT.BORDER );
GridData gd = new GridData( GridData.FILL_HORIZONTAL );
txtText.setLayoutData( gd );
 
Button btnExp = new Button( parent, SWT.PUSH );
btnExp.setText( "..." ); //$NON-NLS-1$
btnExp.setToolTipText( "Invoke Expression Builder" );
//$NON-NLS-1$
btnExp.addSelectionListener( new SelectionAdapter( ) {
public void widgetSelected( SelectionEvent event )
{
openExpression( txtText );
}
} );
}
 
private void openExpression( Text textControl )
{
String oldValue = textControl.getText( );
 
ExpressionBuilder eb = new ExpressionBuilder(
textControl.getShell( ), oldValue );
eb.setExpressionProvider( new ExpressionProvider(
textItem.getModelHandle( ) ) );
String result = oldValue;
if ( eb.open( ) == Window.OK )
{
result = eb.getResult( );
}
if ( !oldValue.equals( result ) )
{
textControl.setText( result );
}
}
}
Adding data binding to the property page
A similar change must be made to the property page. The General category property page needs a button, beside the text control, that calls the expression builder. The code implementing the change to the RotatedTextGeneralPage class is shown in Listing 23‑27.
Listing 23‑27 RotatedTextGeneralPage class
public class RotatedTextGeneralPage
extends AttributesUtil.PageWrapper
{
//.........
public void buildUI( Composite parent )
{
if ( toolkit == null )
{
toolkit = new FormToolkit( Display.getCurrent( ) );
toolkit.setBorderStyle( SWT.NULL );
}
Control[] children = parent.getChildren( );
if ( children != null && children.length > 0 )
{
contentpane = (Composite) children[children.length - 1];
GridLayout layout = new GridLayout( 3, false );
layout.marginLeft = 8;
layout.verticalSpacing = 12;
contentpane.setLayout( layout );
toolkit.createLabel( contentpane, "Text Content:" );
//$NON-NLS-1$
txtText = toolkit.createText( contentpane, "" );
//$NON-NLS-1$
GridData gd = new GridData( );
gd.widthHint = 200;
txtText.setLayoutData( gd );
txtText.addFocusListener( new FocusAdapter( ) {
public void focusLost(
org.eclipse.swt.events.FocusEvent e )
{
updateModel( RotatedTextItem.TEXT_PROP );
};
} );
 
Button btnExp = toolkit.createButton( contentpane, "...",
SWT.PUSH ); //$NON-NLS-1$
btnExp.setToolTipText( "Invoke Expression Builder" );
//$NON-NLS-1$
btnExp.addSelectionListener( new SelectionAdapter( ) {
public void widgetSelected( SelectionEvent e )
{
openExpression( txtText );
}
} );
 
toolkit.createLabel( contentpane, "Rotation Angle:" );
//$NON-NLS-1$
txtAngle = toolkit.createText( contentpane, "" );
//$NON-NLS-1$
gd = new GridData( );
gd.widthHint = 200;
gd.horizontalSpan = 2;
txtAngle.setLayoutData( gd );
txtAngle.addFocusListener( new FocusAdapter( ) {
public void focusLost(
org.eclipse.swt.events.FocusEvent e )
{
updateModel( RotatedTextItem.ROTATION_ANGLE_PROP );
};
} );
}
}
 
private void openExpression( Text textControl )
{
RotatedTextItem item = getItem( );
if ( item != null )
{
String oldValue = textControl.getText( );
ExpressionBuilder eb = new ExpressionBuilder(
textControl.getShell( ), oldValue );
eb.setExpressionProvider( new ExpressionProvider(
item.getModelHandle( ) ) );
 
String result = oldValue;
if ( eb.open( ) == Window.OK )
{
result = eb.getResult( );
}
if ( !oldValue.equals( result ) )
{
textControl.setText( result );
updateModel( RotatedTextItem.TEXT_PROP );
}
}
}
//..........
}
The General category property page now appears as shown in Figure 23‑40.
Figure 23‑40 Final appearance of the RotatedText item’s General category property page
To test the implementation, run a new report designer instance and create a new report, as explained earlier in this section in Deploying and testing the rotated label report item plug-in. Insert a Classic Models data source and data set. Create a table having two columns, and bind the table to the data set. Insert a group and replace the group value with the RotatedText report item in the group header row.
Specify the expression of the RotatedText item using Expression Builder. For example, select or type:
row["COUNTRY"]
Add a border around the RotatedText report item. The design should look like Figure 23‑41.
Figure 23‑41 Report layout showing the final RotatedText item
The preview in the report designer, shown in Figure 23‑42, displays values from the database for the RotatedText report item. The text data comes from the column bindings and automatically changes per row or, in this case, per group.
Figure 23‑42 Report preview showing data values in RotatedText items