Pentaho Reporting: Building Interactive Reports in Swing

Will Gorman

September 2009

Registering event callbacks

The three Java interfaces for retrieving event callbacks from within a report are ReportHyperlinkListener, ReportActionListener, and ReportMouseListener. The ReportHyperlinkListener and ReportActionListener require special properties defined in your report definition, while the ReportMouseListener is a lower level event that is always called within the report PreviewDialog.

All the codes used in this article can be accessed from here.


The org.pentaho.reporting.engine.classic.core.modules.gui.base.event.ReportHyperlinkListener interface defines the following API callback method:

void hyperlinkActivated(ReportHyperlinkEvent event);

This method is called whenever someone clicks on an element within a report that has defined the link url style attribute. The ReportHyperlinkEvent provides additional metadata about the click, including the source node in the report, the hyperlink target definition, as well as the window and title hyperlink definition:

// The PreviewPane object
public Object getSource();
// The reporting node object
public RenderNode getSourceNode();
// The defined style attribute url
public String getTarget();
// The defined style attribute window
public String getWindow();
// The defined style attribute title
public String getTitle();

ReportHyperlinkListener implementations are registered by calling PreviewPane.addReportHyperlinkListener(listener). The PreviewPane object is accessible after defining a PreviewDialog by calling PreviewDialog.getPreviewPane().

One use case for implementing ReportHyperlinkListener is to allow report linking from one high level report to more detailed reports within a Java application.

Hyperlinks may appear differently when rendering in HTML and Swing. Make sure to preview your report to verify that it renders correctly.


In addition to receiving ReportHyperlinkListener events, the Swing PreviewDialog may also receive special events triggered only in the Swing environment. This is done by specifying the swing action attribute on an element. The swing action attribute type is a string. When an element within a report defines the action attribute, and a user clicks on that element, an event is fired and all registered ReportActionListener instances receive an event notification with the specified swing action attribute value.

The org.pentaho.reporting.engine.classic.core.modules.gui.base.event.ReportActionListener interface defines the following API callback method:

public void reportActionPerformed(final ReportActionEvent event);

The ReportActionEvent object returned in the callback provides the following information:

// The PreviewPane object
public Object getSource();
// The reporting node object
public RenderNode getNode();
// The action parameter specified in the report.
public Object getActionParameter();

To register a ReportActionListener, you must call PreviewDrawablePanel.addReportActionListener(listener). The PreviewDrawablePanel is accessible using the PreviewPane.getReportPreviewArea() API call.


The org.pentaho.reporting.engine.classic.core.modules.gui.base.event.ReportMouseListener interface provides the following callbacks:

public void reportMouseClicked(ReportMouseEvent event);
public void reportMousePressed(ReportMouseEvent event);
public void reportMouseReleased(ReportMouseEvent event);

These are triggered when a user has clicked, pressed, or released their mouse within a report. Each listener registered is called for every element found at the specific x, y location within the report. If there are two or more elements overlapping, multiple event calls will be made, one for each of the report elements. The ReportMouseEvent provides the following information when a callback occurs:

// The PreviewPane object
public Object getSource();
// The reporting node object
public RenderNode getSourceNode();
// The original java.awt.event.MouseEvent
public MouseEvent getSourceEvent();

To register a ReportMouseListener, you must call PreviewDrawablePanel.addReportMouseListener(listener). The PreviewDrawablePanel is accessible using the PreviewPane.getReportPreviewArea() API call.

By combining these callbacks with additional API calls using the PageDrawable API, you can resolve the elements at any particular x, y location within a report. The PageDrawable API defines the following methods:

// Retrieves ReportNodes based on x and y location.
// A namespace and name filter may be applied to only
// retrieve nodes that define a certain attribute.
public RenderNode[] getNodesAt (final double x,
final double y, final String namespace, final String name);
// Retrieves nodes within a window, starting at an x,y
// location and stretching out to the defined pixel width
// and height. A namespace and name filter may be applied
// to only retrieve nodes that define a certain attribute.
public RenderNode[] getNodesAt (final double x,
final double y, final double width, final double height,
final String namespace, final String name);

The PageDrawable object is accessible using the PreviewDrawablePanel.getPageDrawable() API call.

Interactive Swing example

In this example, you'll combine the three listener interfaces into a simple report that demonstrates the various callbacks. To begin, you need to set up your environment. First, you need to create a new folder called chapter9, and copy the JAR files from the chapter3/lib folder into chapter9/lib. Also, copy the chapter3/data folder to chapter9/data so that you may reuse the already configured ElectroBarn data source. Finally, copy the chapter3/build.xml file into the chapter9 folder so that you can build the example.

You'll reuse the Chapter2SwingApp class as a shell to build from. Copy chapter2/src/ to chapter9/src/, and rename the class to Chapter9SwingApp. Now that you've created the Chapter9SwingApp class, you're ready to begin designing the report, along with adding the various Swing event listeners to your Swing PreviewDialog. Launch Pentaho Report Designer and create a new report. For the master report, define the following ElectroBarn SQL query:


In the Details band of the master report, place two labels with the text Session ID and Employee ID, along with dragging and dropping the SESSIONID and EMPLOYEEID fields into the band. For the SESSIONID field, also specify the following formula for the Swing action attribute:


Later in this example, you'll register a ReportActionListener, which will receive the SESSIONID as an input parameter, when clicked on the SESSIONID field. Also, enable row banding by adding a background rectangle and setting its visible style formula to the following:


Now, place an inline sub-report element below the content within the Details band. Set the sub-report visible style attribute to the following formula:


This will evaluate to true if the parameter REPORT_PARAM_SESSIONID matches the currently selected session. This parameter will be passed into the report when a user clicks on the SESSIONID field.

The Details band of the master report should look similar to this:

Pentaho Reporting 3.5 for Java Developers

You're now ready to begin editing the sub-report. Double-click on the sub-report element or right-click and select the Edit sub-report menu option to bring up the sub-report for editing.

The first step to setting up the sub-report is to create a new data source query. Create the following ElectroBarn SQL query as part of the sub-report:


This query selects details only for the current SESSIONID. You must customize the parameters that are available to the sub-report. You can do this by bringing up the Sub-report Parameters dialog by right-clicking on the sub-report's Parameters tree item under the Data tab and selecting the Edit Sub-report Parameters… menu item. The following dialog will appear:

Pentaho Reporting 3.5 for Java Developers

Now that you've defined the sub-report query, place a chart element in the report header of the sub-report. Select the Pie chart type. Edit the chart element, setting the value-column to QUANTITY and the series-by-field to PURCHASEID.

Pentaho Reporting 3.5 for Java Developers

Next to the chart, place two rectangle elements, along with two label elements titled Action 1 and Action 2 within the rectangles. Set the name attribute of the rectangles to Action1 and Action2—the names of the rectangles will be used by a ReportMouseListener later in this example. Also, add a label below the rectangles titled Google Reference. Set the url style formula of this label to a Google query, which will search for the first item in the dataset:

="" & [ITEMNAME]

The & symbol concatenates the ITEMNAME to the end of the query string. You'll use this label to demonstrate the ReportHyperlinkListener. The sub-report should look similar to this:

Pentaho Reporting 3.5 for Java Developers

Save the master report as chapter9/data/interactive_swing.prpt. You're now ready to update the Chapter9SwingApp class with event listeners.

First, update the example to render the interactive_swing.prpt report in a separate method:

public MasterReport createReport() throws IOException,
ResourceException {
ResourceManager manager = new ResourceManager();
Resource res = manager.createDirectly(
new URL("file:data/interactive_swing.prpt"),
MasterReport report = (MasterReport) res.getResource();
return report;

Replace the loading of the report in the onPreview method with the following code:

MasterReport report = createReport();

Now, you'll define three event listeners. The first event listener to be added is a ReportActionListener. This listener will re-render the report, displaying the details of the clicked selection. You must first set up a mechanism to pass the current Session ID. Define a class member of type String called sessionId:

Integer sessionId = null;

Add the following code at the end of the createReport method, which sets the sessionId as an input parameter if it's available:

if (sessionId != null) {
report.getParameterValues().put("REPORT_PARAM_SESSIONID", sessionId);

Now, add the following code right after the preview.addWindowListener() call:

addReportActionListener(new ReportActionListener() {
public void reportActionPerformed(ReportActionEvent event) {
Integer newSessionId = ((Number)event.getActionParameter()).
if (!newSessionId.equals(sessionId)) {
sessionId = newSessionId;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
} catch (Exception e) {

Note that this example uses SwingUtilities to update the report once the current event processing is complete.

The second listener to be added is the hyperlink listener. This listener will display a message dialog. In a real application, this might launch a browser window. Add the following code after the previously defined report action listener:

ReportHyperlinkListener() {
public void hyperlinkActivated(final ReportHyperlinkEvent event)
SwingUtilities.invokeLater(new Runnable()
{public void run() {JOptionPane.showMessageDialog(null,
"Link Clicked: " + event.getTarget());}

The final listener will determine which rectangle was clicked.

addReportMouseListener(new ReportMouseListener() {
public void reportMouseClicked(ReportMouseEvent event) {
if (event.getSourceNode() !=
null && event.getSourceNode().getName().equals("Action1")) {
JOptionPane.showMessageDialog(null, "Action 1 Rectangle Clicked");
} else if (event.getSourceNode() !=
null && event.getSourceNode().getName().equals("Action2")) {
JOptionPane.showMessageDialog(null, "Action 2 Rectangle Clicked");
public void reportMousePressed(ReportMouseEvent event) {}
public void reportMouseReleased(ReportMouseEvent event) {}

Remember, the mouse listener is called for every element that you clicked on. In this case, you may have clicked on the label and the rectangle, a scenario which would result in the event handler being called twice.

Also, make sure to add the following imports to the beginning of the class file:

import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import org.pentaho.reporting.engine.classic.core.modules.gui.base.
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;

Now that you've added the event listeners, you're ready to build and run the report. Add the following Ant target to the build.xml file:

<target name="runswinginteractive" depends="compile">
<java fork="true" classpathref="runtime_classpath" classname="Chap

Type ant runswinginteractive on the command line to verify the results. The report should look similar to this:

Pentaho Reporting 3.5 for Java Developers

Click on the Session ID row to view the details of each session, and click on the action rectangles and Google Reference label to view the alerts, triggered by the report listeners.


In this article you learned how to build interactive reports using Swing. You built from the ground up a Swing demonstration that selectively shows details of sales sessions from the ElectroBarn data source, along with demonstrating feedback using the ReportMouseListenter API. You also learned how to modify report definitions to generate hyperlink events and swing action events.

You've been reading an excerpt of:

Pentaho Reporting 3.5 for Java Developers

Explore Title