2.3. EspressReport Report API

2.3.1. Introduction and Setup

EspressReport provides an easy-to-use application programming interface (API) that enables users to create and customize reports within their own applications (and applets) on either server side or client side. It is written in 100% pure Java and thus can be run on any platform with little or no changes. Any and every part of the report is customizable using the API. You can use as little as a single line of code to generate a report.

The main class, QbReport, extends java.awt.Component. Associated with this component is a set of auxiliary classes consisting of 5 packages: quadbase.reportdesigner.ReportAPI, quadbase.reportdesigner.ReportElements, quadbase.reportdesigner.ReportViewer, (and its swing counterpart quadbase.reportdesigner.ReportViewer.swing), quadbase.reportdesigner.lang and quadbase.reportdesigner.util. The remainder of this document explains the constituents of the API and their usage. Please note that the complete API documentation is located at help/apidocs/index.html.

To use the API, add ReportAPIWithChart.jar and qblicense.jar (located in EspressReport/lib directory) to your CLASSPATH. Please note that if you are using a SOAP data source or XML file to read or write data, you will also need to add xercesImpl.jar and xml-apis.jar (also located in the same directory) in that order to the CLASSPATH. If you are exporting the charts or images to PNG format, you will also need to include ExportLib.jar to your CLASSPATH. To export the report to Excel file (i.e. .xls file), you must include poi.jar into your CLASSPATH. If you want to use parameterized database queries as your data sources, add jsqlparser.jar to your CLASSPATH. If you want to export to MS Excel 2007 format (OOXML - extension .xlsx), you must also include these files to your CLASSPATH: poi-ooxml.jar, poi-ooxml-schemas.jar, commons-codec.jar, commons-collections.jar, commons-compress.jar, commons-io.jar, commons-math3.jar, log4j-api.jar, SparseBitSet.jar, xmlbeans.jar. If your application is on Windows or Solaris machine, you will have to add the following environment variable (depending on the platform):

For Windows) set PATH=%PATH%;<path to EspressReport root directory>\lib
For Solaris) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<path to EspressReport root directory>/lib

Please note that third-party jar files may also be required, depending on what your application does. For example, if you create a JDBC connection to database, you will need to include the JDBC jar files to the CLASSPATH as well.

2.3.2. Recommended Approach for using Report API

EspressReport provides API through which reports can be generated programmatically from scratch. However, this generally involves a significant amount of code. We recommend using Report Designer and creating a Report File (.rpt file) first, which can function as a template. This template can then be passed in the QbReport constructor and the template's look and feel can be applied to the newly created report object. Thus, at the time of the report generation, a major portion of the look and feel would have been already set. You can also open a Report File (either a .RPT or a .PAK file) using the API. Using either approach, you can then write code to modify, add, or remove the properties. This approach will save you coding time and will also improve performance.

You have the option of connecting to EspressManager when using EspressReport Report API. While a connection is required when using the Report Designer, you do not need to connect to EspressManager when running any application that utilizes EspressReport Report API. We generally recommend that you do not connect to EspressManager and thereby avoid another layer in your architecture. For more details, please refer to the next section.

All examples and code given in the manual follow the above two recommendations: a template based approach and no connection to EspressManager. Unless otherwise noted, all code examples will use a template (templates can be downloaded from corresponding chapters) and will not connect to EspressManager.

Also note that if you have applets that use EspressReport Report API, the browser must have at least 1.5 JVM plugin.

2.3.3. Interaction with EspressManager

Before we go into details of how to create and use reports, let's explore the options of using EspressManager in an application. EspressReport is generally used in conjunction with EspressManager. The report component connects to EspressManager in order to read and write files to access databases and perform data pre-processing required for certain advanced features (such as aggregation). However, the report component can also be used in a stand-alone mode, in which it performs file I/O and database access directly, without the use of EspressManager.

For instance, the applet or application may be running on machine Client and may require data from a database on machine DbMachine. However, machine DbMachine may be behind a firewall or a direct connection may not be allowed to machine DbMachine from machine Client due to security restrictions. EspressManager can be run on machine Server and the applet/application can connect to EspressManager on machine Server. JDBC can then be used to connect to machine DbMachine from machine Server and get the data. The data is then delivered to machine Client and the report generated. This is useful when you want to keep the data secure and non-accessible from your client machines and make all connections come through a server machine (a machine running EspressManager). You can also utilize this option to keep a log of all the clients accessing the data through EspressReport (you can have a log file created when starting EspressManager. The log file is called espressmanager.log). Note that this functionality comes at a cost. You will face a slight performance decrease because your code is connecting to the data through EspressManager (i.e. another layer has been added).

By default, a report component requires the presence of EspressManager. To change the mode, use the QbReport class static method at the beginning of your applet/application (before any QbReport objects are created):

static public void setEspressManagerUsed(boolean b)

Both applications and applets can be run with or without accessing EspressManager. Communication is done using the http protocol. The location of the server is determined by an IP address and port number passed in the API code. The instructions on how to connect to the EspressManager are as follows:

2.3.4. Connecting to EspressManager

2.3.4.1. EspressManager Running as Application

EspressManager primarily runs as an application. If you wish to use the ReportAPI to connect to EspressManager running as an application, you can use API methods to specify the IP address/machine name where EspressManager is located and the port number that EspressManager is listening on.

You can use the following two API methods to set the connection information:

static void setServerAddress(java.lang.String address);
static void setServerPortNumber(int port);

For example, the following lines of code:

QbReport.setServerAddress("Machine");
QbReport.setServerPortNumber(PortNumber);

will connect to EspressManager running on Machine and listening on PortNumber.

Please note that if EspressManager connection information is not specified, the code will attempt to connect to EspressManager on the local machine and listening to the default port number (22071).

Please note that these methods exist in QbReport, QbChart, QbReportDesigner and QbScheduler classes.

2.3.4.2. EspressManager Running as Servlet

EspressManager can also be run as a servlet. If you wish to use Report API to connect to EspressManager running as a servlet, you will have to use the following methods:

public static void useServlet(boolean b);
public static void setServletRunner(String comm_URL);
public static void setServletContext(String context);

For example, the following lines of code:

QbReport.useServlet(true);
QbReport.setServletRunner("http://Machine:PortNumber");
QbReport.setServletContext("EspressReport/servlet");

will connect to EspressManager running at http://Machine:PortNumber/EspressReport/servlet.

Please note that these methods exist in QbReport, QbChart, QbReportDesigner and QbScheduler classes.

2.3.5. Using the API

The following section details how to utilize the API. Again, the API examples and code is designed using the above recommendation (template based and no EspressManager).

Unless otherwise noted, all examples use the Woodview HSQL database, which is located in <ERInstall>/help/examples/DataSources/database directory. In order to run the examples, you will need to add database HSQL JDBC driver (hsqldb.jar) to your classpath. The driver is located in <ERInstall>/lib directory.

Also, all the API examples will show the core code in the manual. To compile the examples, make sure the CLASSPATH includes ReportAPIWithChart.jar and qblicense.jar.

For more information on the API methods, please refer to the API documentation.

2.3.5.1. Loading a Report

Reports can be saved to a file using the RPT format (a proprietary format) or XML format. A RPT/XML file stores all report information except actual data (although an option exists to save the entire data within a RPT file). This format can be used to reconstruct a report object. The data is automatically reloaded from the original data source each time the RPT/XML file is opened.

It is important to note that the RPT/XML file does NOT contain the data by default. It contains the specified data source along with the report template information (i.e. the look and feel of the report). Therefore, the data for the report is obtained by querying the data source when loading a RPT/XML file. This format can be obtained by using the Report Designer or the export method provided in the QbReport class. You can also choose to include the complete data in the RPT file (along with the data source information).

The following example, which can run as an applet or application, reads a RPT file and reconstructs a report:

Component doOpeningTemplate(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template
	QbReport report = new QbReport(parent, // container 
			"OpeningTemplate.rpt"); // template

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

The constructor in this example is:

public QbReport(Object parent, String file);

where parent is the container and file is a RPT/XML file name.

[Note]Note

File names may be specified either as URL strings or using relative/absolute paths.

Path names are interpreted as being relative to the current directory of EspressManager or to the current application if EspressManager is not used.

2.3.5.1.1. Sub-Reports, Charts, and Drill-Down Reports

A report template may contain charts, sub-reports and/or drill-down reports. These ancillary templates are saved separately from the main report template. Chart templates are saved in the chart directory, sub-report templates in the SubReport directory, and drill-down templates in the DrillDown directory. A relative URL (relative to the EspressReport installation directory) and the template name is then specified and put in the main report template.

The following example, which can run as an applet or application, reads a RPT file and sets the Chart Path:

Component doSetChartPath(Object parent)  {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template
	QbReport report = new QbReport (parent,					// container 
									"setChartPath.rpt");	// template
		
	// Set Chart Path
	report.setChartPath(".");

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

The above code sets the location of the chart template file, thus avoiding the need to have a Chart subdirectory under the working directory of your class file.

The following methods work similarly:

QbReport.setDrillDownPath(String directory);
QbReport.setSubReportPath(String directory);
QbReport.setImagePath(String directory);
2.3.5.1.2. PAK File

You can also pack your report in PAK format and deploy it as a PAK file. This alternative simplifies the deployment procedures by including all the chart, sub-report, drill-down, and image files that are associated with your main report into one .pak file. Your code can uses the .pak file name (instead of the .rpt/.xml) and creates the report. With the .pak file approach, you do not need to specify the directories where the chart, sub-report, and/or drill-down templates are located.

2.3.5.1.3. Backup Data

By default, report templates are always saved with two rows of backup data. This is to ensure that any template can be used to create the QbReport object, even if the data source is not present. When you create a QbReport object based on an existing template, it looks for the data source specified in the template. If the data source is not found, the backup data is used. However, you can force the API to use the backup data instead of searching for the data source using the following constructor:

public QbReport(Object parent, String file, boolean isEnterpriseServer,
                boolean optimizeMemory, boolean multiPageExp,
                boolean useBackupData);

To force the API to use the backup data, only the last argument in the above constructor has to be set to true. The values of the other boolean arguments do not matter.

2.3.5.1.4. Parameterized Reports

Reports can also contain parameters to either limit the data in some form or to provide additional information. Typically, query (or IN) parameters are used by the data source to limit the data while parameterized formula are used to include more data within the report.

Query parameters can be both single-value and multi-value parameter types while formula parameters are single-value only.

When a parameterized template is opened using following constructor:

QbReport(Object parent, String templateName);

a dialog box appears, asking for the value(s) of the parameter(s). This dialog box is the same as the one that appears in Designer when the report is previewed.

2.3.5.1.4.1. Object Array

A parameterized report can also be opened without the dialog box prompting for any value(s). This can be done by passing in two object arrays, one for the query parameters and another for the formula parameters. Each element in the array represents the value for that particular parameter.

The order of the array must match the order in which the parameters were created in Designer. For correct results, the data type of the value must also match the data type of the parameter.

Query parameters can also be multi-value parameter types. For multi-value parameters, a vector is passed to the object array. The vector contains all the values for the multi-value parameter.

The following example, which can run as an applet or application, passes in the parameter values when opening a template:

Component doObjectArray(Object parent) {

	// Do not use ERES Server
	QbReport.setEspressManagerUsed(false);

	// Object array for Query Parameters
	Vector vec = new Vector();
	vec.add("CA");
	vec.add("NY");

	GregorianCalendar beginDate = new GregorianCalendar(2001, 0, 4);
	GregorianCalendar endDate = new GregorianCalendar(2003, 1, 12);

	long beginLong = beginDate.getTimeInMillis();
	long endLong = endDate.getTimeInMillis();

	Date beginDateTime = new Date(beginLong);
	Date endDateTime = new Date(endLong);

	Object queryParams[] = new Object[3];
	queryParams[0] = vec;
	queryParams[1] = beginDateTime;
	queryParams[2] = endDateTime;

	// Object array for Formula Parameter
	Object formulaParams[] = new Object[1];
	formulaParams[0] = "Sarat";

	// Open the template
	QbReport report = new QbReport(parent, // container 
			"ObjectArray.rpt", // template
			queryParams, // Query Parameters
			formulaParams); // Formula Parameters

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}
2.3.5.1.4.2. getAllParameters method

In addition to the above, you can also pass in the parameters using the getAllParameters method. The getAllParameters method returns a list of all parameters in the report (this includes any parameters from the sub-report that are not shared). Each parameter is obtained and the value is then set.

The following example, which can be run as an applet or application, take the same report as above and passes in the parameters using the getAllParameters method:

Component doGetAllParameters(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Object array for Query Parameters
	Vector vec = new Vector();
	vec.addElement("CA");
	vec.addElement("NY");

	GregorianCalendar beginDate = new GregorianCalendar(2001, 0, 4);
	GregorianCalendar endDate = new GregorianCalendar(2003, 1, 12);

	long beginLong = beginDate.getTimeInMillis();
	long endLong = endDate.getTimeInMillis();

	Date beginDateTime = new Date(beginLong);
	Date endDateTime = new Date(endLong);

	Object queryParams[] = new Object[3];
	queryParams[0] = vec;
	queryParams[1] = beginDateTime;
	queryParams[2] = endDateTime;

	// Object array for Formula Parameter
	Object formulaParams[] = new Object[1];
	formulaParams[0] = "Sarat";

	// Open the template with backup data
	QbReport report = new QbReport(parent, // container 
			"ObjectArray.rpt", // template
			false, false, false, true);

	// Pass in parameters using getAllParameters
	report.getAllParameters().get(0).setValues((Vector) queryParams[0]);
	report.getAllParameters().get(1).setValue(queryParams[1]);
	report.getAllParameters().get(2).setValue(queryParams[2]);
	report.getAllParameters().get(3).setValue(formulaParams[0]);

	try {
		// Get the data for the report
		report.refreshWithOriginalData();
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

The parameter prompt dialogs in Report Designer, Page Viewer, and Menu Page will display the parameters in ordered sequence. Use the overloaded method with the parameter value set to true to get a list of ordered parameters.

report.getAllParameters(boolean ordered)

The results of this method will maintain two qualities. First, formula parameters will always be return first. Second, cascading parameter ordering will be maintained. For more information regarding cascading parameters, please see Section 1.3.2.2.2.3 - Cascading Parameters.

2.3.5.1.5. Secure Reports

Information on the report can be changed by passing in a Security parameter when creating the report. The security levels are created in Designer and the appropriate security level is passed by using the API.

The following example, which can be run as an applet or application, opens a secure report that shows sales information for every region except West:

Component doSecurity(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template
	QbReport report = new QbReport(parent, // container 
			"Security.rpt"); // template

	try {
		// Set Security Level
		report.setSecurityLevel("NoWest");
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

You can also pass in the security level using a Properties object. This is especially useful when query/formula parameters are secure.

The following example, which can be run as an applet or application, opens a secure report that shows sales information for every region except West:

Component doSecurityProperties(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Set up Properties
	Properties props = new Properties();
	props.put("security level", "NoWest");

	// Open the template
	QbReport report = new QbReport(parent, // container 
			"Security.rpt", // template
			props); // properties

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

2.3.5.2. Applying a Report Template

When a QbReport object is created from scratch (see Appendix 2.C - Creating the Report), the report is created using default attributes. However, you can use a report template (either .rpt or .xml) to specify user defined attributes during report construction. Almost all the attributes (except for data source and report type) are extracted from the template and applied to the QbReport object. The template name usually appears as the last argument in the QbReport constructors.

You can also specify the template name using the applyTemplate(String fileName) method in the QbReport class.

The following example, which can be run as an applet or application, applies a template onto the QbReport object:

Component doApplyingTemplate(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    String templateLocation = "..";

    // Apply the template
    QbReport report = new QbReport (parent, // container
                    QbReport.SUMMARY, // report type
                    data, // data
                    columnMapping, // column mapping
                    templateLocation); // template

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

You can also take the column mapping from the template and have it applied on the QbReport object being created. This is done by passing in null (without the double quotes) instead of a ColInfo[] object.

In addition to the column mapping, you also obtain the database connection information from the template (assuming the template uses a database as the datasource). This is done by passing in null (without the double quotes) for any of the DBInfo or SimpleQueryFileInfo parameters.

By default, when you apply templates, formulas in the table data section are not applied. To apply formulas and/or scripts from the template .rpt/.xml file to the QbReport object, you will need to use the following method:

QbReport.applyTemplate(String templateName, boolean applyFormula);

2.3.5.3. Modifying Data Source

You can create report templates in Designer and open those templates using the API. The QbReport object created uses the same data source as the template and attempts to fetch the data. However, it may be that while the template has all the look and feel needed, the data source may be an incorrect one. The following sections show how to open the template with backup data and switch the data source, without recreating the entire report.

Please note that for best results, the number of columns and the data type of each column must match between the two data sources (i.e., the one used to create the template in Designer and the new data source).

After switching the data source, the QbReport object must be forced to fetch the new data. This can be done by calling the refresh method in the QbReport class.

2.3.5.3.1. Data from a Database

Switching the data source to point to a database is simple. All you would need to do is provide the database connection information as well as the query to be used and pass that to the QbReport object. You can provide the database connection information (as well as the query) in a DBInfo object (for more information on creating a DBInfo object, please refer to Appendix 2.B.1 - Data from a Database).

The following example, which can be run as an applet or application, switches the data source of the QbReport object to a database:

Component doSwitchToDatabase(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "SwitchToDatabase.rpt", // template
                    false, false, false, true);

    // New database connection information
    DBInfo newDatabaseInfo = new DBInfo(.....);

    try {
        // Switch data source
        report.getInputData().setDatabaseInfo(newDatabaseInfo);

        // Refresh the report
        report.refresh();

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

The above approach changes the data source for the current report level only (it can be either the main report or the sub-report).

If your report template has any sub-reports, drill-down reports, or independent charts (i.e., charts that do not use the report data as the data source) and you wish to change the data sources for all of them, then you can use the setAllDatabaseInfo method under the IInputData interface. Please note that with this approach, a new query cannot be specified and the original query will be used. Only the database connection information will be changed.

The following example, which can be run as an applet or application, uses the setAllDatabaseInfo method to switch the data source:

Component doSwitchToDatabaseSetAll(Object parent) {

		// Do not use EspressManager
		QbReport.setEspressManagerUsed(false);

		// Open the template with backup data
		QbReport report = new QbReport(parent, // container 
				"SwitchToDatabase.rpt", // template
				false, false, false, true);

		try {
			// Switch data source
			report.getInputData().setAllDatabaseInfo("jdbc:hsqldb:woodview",
					"org.hsqldb.jdbcDriver", "sa", "");

			// Refresh report
			report.refresh();
		} catch (Exception ex)
		{
			ex.printStackTrace();

		}

		// Show report in Viewer
		return (new Viewer().getComponent(report));
	}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

2.3.5.3.1.1. Parameterized

Just as with a regular query, you can switch the data source to a parameterized query. With a parameterized query, the parameter(s) properties as well as the database connection information and the query, must be specified.

The following example, which can be run as an applet or application, switches the data source of the QbReport object to a parameterized query:

Component doSwitchToDatabaseParam(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "SwitchToDatabaseParam.rpt", // template
                    false, false, false, true);

    // New database connection and parameter information
    SimpleQueryFileInfo newDatabaseInfo = new SimpleQueryFileInfo(.....);

    try {
        // Switch data source
        report.getInputData().setDatabaseInfo(newDatabaseInfo);

        // Refresh the report
        report.refresh();

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

Again, just like with regular queries, you can use the setAllDatabaseInfo method to switch to the new data source. In this approach, the original query and parameter information is used while the database connection information is altered. After switching the database information, the parameter value(s) must be specified before refreshing the report.

The following example, which can be run as an applet or application, uses the setAllDatabaseInfo method to switch the data source:

Component doSwitchToDatabaseParamSetAll(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "SwitchToDatabaseParam.rpt", // template
                    false, false, false, true);

    try {
        // Switch data source
        report.getInputData().setAllDatabaseInfo(...);

        // Pass in parameter value
        report.getAllParameters().get(0).setValue("TRD");

        // Refresh the report
        report.refresh();

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

2.3.5.3.1.2. JNDI

You can also change the data source to a JNDI data source. This is done by specifying the JNDI connection information in a DBInfo object and then passing it to the QbReport object.

The following example, which can be run as an applet or application, switches the data source of the QbReport object to a JNDI database:

Component doSwitchToDatabaseJNDI(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Data Source.  Replace comp with computer and env with environment.
	// The environment hashtable is empty for tomcat.
	// If other application server is used, need to set INITIAL_CONTEXT_FACTORY and PROVIDER_URL. 
	DBInfo newDatabaseInfo = new DBInfo(
			"java:comp/env/jdbc/Woodview",
			"SELECT Categories.CategoryName, Products.ProductName, Products.UnitPrice, Products.StainPrice, Products.UnitsInStock FROM Products, Categories WHERE (Products.CategoryID = Categories.CategoryID)",
			new Hashtable());

	// Open the template with backup data
	QbReport report = new QbReport(parent, // container 
			"SwitchToDatabaseJNDI.rpt", // template
			false, false, false, true);

	try {
		// Switch data source
		report.getInputData().setDatabaseInfo(newDatabaseInfo);

		// Refresh report
		report.refresh();
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run. Note that for the application code to run, the Woodview database needs to be set up as a JNDI data source in the Tomcat environment and the application code changed to match the connection information.

2.3.5.3.2. Data from a Data File (TXT/DAT/XML)

You can switch the data source to a text file as long as the text file follows the Quadbase guidelines (for more details, please refer to Section 2.3.5.3.2 - Data from a Data File (TXT/DAT/XML)).

The following example, which can be run as an applet or application, switches the data source of the QbReport object to a text file:

Component doSwitchToDataFile(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template with backup data
	QbReport report = new QbReport(parent, // container 
			"SwitchToDataFile.rpt", // template
			false, false, false, true);

	try {
		// Switch data source
		report.getInputData().setDataFile("sample.dat");

		// Refresh report
		report.refresh();
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

You can also specify whether the data is sorted (this improves performance) and/or the encoding for the text file. This can be done using the following method in IInputData:

setDataFile(String dataFile, boolean sortedData, String encoding);
2.3.5.3.3. Data from an XML Data Source

You can switch the data source to your custom XML data as long as there is a .dtd or .xml schema accompanying your data. The XML data information is specified (for more details, please refer to Section 2.3.5.3.3 - Data from an XML Data Source) and then passed to the QbReport object.

The following example, which can be run as an applet or application, switches the data source of the QbReport object to XML data:

Component doSwitchToXMLData(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "SwitchToXMLData.rpt", // template
                    false, false, false, true);

    // XML data source information

    XMLFileQueryInfo newData = new XMLFileQueryInfo(...);

    try {
        // Switch data source
        report.getInputData().setXMLFileQueryInfo(newData);

        // Refresh the report
        report.refresh();

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

You can also specify whether the data is sorted (this improves performance) by using the following method in IInputData:

setXMLFileQueryInfo(XMLFileQueryInfo xmlInfo, boolean sortedData);
2.3.5.3.4. Data from Custom Implementation

In addition to the regular data sources, you can also pass in your own custom data. The custom data is passed to the QbReport object using either the IDataSource or IParameterizedDataSource interfaces. For more details, please refer to Appendix 2.B.5 - Data passed in a Custom Implementation.

The following example, which can be run as an applet or application, switches the data source to a custom implementation:

Component doSwitchToCustomData(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template with backup data
	QbReport report = new QbReport(parent, // container 
			"SwitchToCustomData.rpt", // template
			false, false, false, true);

	try {
		// Switch data source
		report.getInputData().setClassFile("Furniture_Report");

		// Refresh report
		report.refresh();
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

You can also specify whether the data is sorted (this improves performance) and/or to prompt the parameter dialog by using the following method in IInputData:

setClassFile(String classname, boolean sortedData, boolean showPromptDialog);
2.3.5.3.4.1. Parameterized

You can have a custom implementation that requires parameter values, to be the new data source. In this scenario, the custom implementation must use the IParameterizedDataSource interface. For more details, please refer to Appendix 2.B.5 - Data passed in a Custom Implementation. After switching the data source information, the parameter value(s) must be specified before refreshing the report.

The following example, which can be run as an applet or application, switches the data source to a parameterized custom implementation:

Component doSwitchToCustomDataParam(Object parent) {

	// Do not use EspressManager
	QbReport.setEspressManagerUsed(false);

	// Open the template with backup data
	QbReport report = new QbReport(parent, // container 
			"SwitchToCustomDataParam.rpt", // template
			false, false, false, true);

	try {
		// Switch data source
		report.getInputData().setClassFile("ProductParamInfo", false, false);

		report.getAllParameters().get(0).setValue(new Integer(25));

		// Refresh report
		report.refresh();
	} catch (Exception ex)
	{
		ex.printStackTrace();
	}

	// Show report in Viewer
	return (new Viewer().getComponent(report));
}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

2.3.5.3.5. Data passed in an Array in Memory

You can also pass in data using arrays. The array data is usually stored in memory and passed to the QbReport object (for more details, please refer to Appendix 2.B.4 - Data passed in an Array in Memory).

The following example, which can be run as an applet or application, switches the data source to an array in memory:

Component doSwitchToArrayData(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "SwitchToArrayData.rpt", // template
                    false, false, false, true);

    // Create array data
    DbData newData = new DbData(...);

    try {
        // Switch data source
        report.getInputData().setData(newData);

        // Refresh the report
        report.refresh();

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

You can also specify whether the data is sorted, which improves performance, by using the following method in IInputData:

setData(IResultSet rs, boolean sortedData);
2.3.5.3.6. Drill-Down with DrillDownReportServlet

When changing the data source for a Drill-Down report, you use the setAllDatabaseInfo method in IInputData. However, if you are exporting the report and using the DrillDownReportServlet (for more details, please see Section 2.3.5.7.10.2 - DrillDownReportServlet), you need to get a handle to the session and use the method setDrillDownDatabaseInfo in QbReport so that the drill-down layers will know what the new data source is.

The following example, which can be run as an applet or application, switches the data source of a drill-down report:

public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,
	IOException
{
	HttpSession session = req.getSession(true);

	// Set the "content type" header of the response
	res.setContentType("text/html");

	// Get the response's OutputStream to return content to the client.
	OutputStream toClient = res.getOutputStream();

	try
	{
		// Do not use EspressManager
		QbReport.setEspressManagerUsed(false);

		// Open report with backup data (data source will be switched later)
		QbReport report = new QbReport(null, "SwitchDrillDownServlet.pak",
				false, false, false, true);

		// New database connection information
		String newDatabaseURL = "jdbc:hsqldb:woodview";
		String newDatabaseDriver = "org.hsqldb.jdbcDriver";
		String newDatabaseUID = "sa";
		String newDatabasePassword = "";

		// Switch data source
		report.getInputData().setAllDatabaseInfo(newDatabaseURL, newDatabaseDriver,
				newDatabaseUID, newDatabasePassword);

		// Put new data source information in session for DrillDownReportServlet
		report.setDrillDownDatabaseInfo(session, newDatabaseURL, newDatabaseDriver,
				newDatabaseUID, newDatabasePassword);

		report.setDynamicExport(true, "localhost", 8080);

		ByteArrayOutputStream tempStream = new ByteArrayOutputStream();

		report.refresh();

		// Export the report to DHTML
		report.export(QbReport.DHTML, tempStream);

		tempStream.writeTo(toClient);
	} catch (Exception e) {
		e.printStackTrace();
	}

	// Flush the outputStream
	toClient.flush();

	// Close the writer; the response is done.
	toClient.close();
}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run. You would have to change the location of the template and deploy the servlet in order to run the code successfully.

You can also specify a connection object for the database by using the following method in QbReport.

setDrillDownConnection(Object session, Connection conn);

2.3.5.4. Modifying Column Mapping

Just as the data source of a report can be changed, the column mapping can be modified using the API as well. However, this is not recommended as the report may have formulas and/or scripts that are data dependent. If the number of columns and/or the data of the columns do not match the original mapping, certain formulas and/or scripts may not work. While this section shows how to switch the mapping, it is recommended that in such a scenario a new QbReport object be created (see Appendix 2.C - Creating the Report) and a template applied on it.

The following example, which can be run as an applet or application, modifies the column mapping of the report:

Component doModifyColumnMapping(Object parent) {

    // Do not use EspressManager
    QbReport.setEspressManagerUsed(false);

    // Open the template with backup data
    QbReport report = new QbReport (parent, // container
                    "ModifyColumnMapping.rpt", // template
                    false, false, false, true);

    // Create new column mapping
    ColInfo[] newColumnMapping = new ColInfo[..];

    try {
        // Switch mapping
        report.getInputData().setMapping(newColumnMapping);

        // Refresh the report
        report.refreshWithOriginalData();

        // Reapply template
        report.applyTemplate("ModifyColumnMapping.rpt");

    } catch (Exception ex)
    {
        ex.printStackTrace();

    }

    // Show report in Viewer
    return (new Viewer().getComponent(report));

}

Please note that the above code is not complete and is there as a guide. However, the link contains a complete application code that can be run.

2.3.5.5. Report Components

An EspressReport report is made of different segments. Each segment can be set and modified independently from the others. Listed below are the various parts of the report :

2.3.5.5.1. ReportElement

A ReportElement object forms the core of objects in Report API. A ReportElement object provides a way to manipulate the contents as well as the look and feel of the individual elements. All the other report objects (such as ReportCell, ReportSection, ReportColumn etc.) extend the ReportElement class. Every part of the report is comprised of a ReportElement object, or an extension of it. Within each ReportElement object, properties such as font, color, data format, etc can be manipulated. You can also copy ReportElement objects or just apply the template of one ReportElement object to another. When a template is applied, the data of the object does not change. Only the look and feel of the ReportElement object is modified.

When modifying it, you do not get a handle to the ReportElement, but rather use the methods of the subclass (ReportCell, ReportSection, ReportColumn etc.)

2.3.5.5.2. ReportCell

A ReportCell object is used to insert labels, formulas, text, charts, or even images into different sections of the report (i.e., in the ReportSection(s) of the report). You can also use ReportCell objects to help with the formatting of the cells in the various parts of the report.

You can get a handle to a cell by using its numeric index (i.e., the position of the cell in the section), its ID (which is a string), or its custom ID (assuming the cell has one). You can use the following methods, in ReportSection, to get the desired cell:

getData(int i);
getData(String ID);

You can also get all the report cells, in a given section, by using the following method in ReportSection:

getData();
2.3.5.5.3. ReportSection

A report is divided into many sections. The following shows the different sections of a report:

Page Header :-

This section serves as a header to the page. It appears at the top of everypage of the report.

Table Header :-

This section serves as a header to the detail or data section of the report. By default it only appears once in the report.

Group Header:-

This section appears in reports with grouped data (i.e. Master & Details report), or data with row breaks inserted (i.e. Summary Break report). It repeats at the top of each grouping within the report.

Table Data:-

This is the main section of the report that contains most of the data. Data columns that have been selected for the report are placed in this section, and repeated for each entry in the column.

Group Footer:-

This section appears on reports with grouped data (i.e. Master & Details report), or data with row breaks inserted (i.e. Summary Break report). It repeats at the bottom of each grouping within the report.

Table Footer:-

This section serves as the footer to the detail or data section of the report. By default it appears only once in the report.

Page Footer:-

This section serves as a footer to the page. It appears at the bottom of every page of the report.

Report Footer:-

This is the last summary or footer section of the report. It only appears once at the end of the report.

You can get a handle to the Page Footer, Page Header, Report Footer, Report Header, and Report Table sections using the following methods in QbReport:

getPageFooter();
getPageHeader();
getReportFooter();
getReportHeader();
getTable();

and you can get a handle to the Group Footer, Group Header, Table Header, and Table Footer sections using the following methods in Report Table:

getRowBreakFooter(int breakLevel);
getRowBreakHeader(int breakLevel);
getFooter();
getHeader();
2.3.5.5.4. ReportColumn

A ReportColumn object is an array of ReportCell objects that appears in the column selected. Using ReportColumn objects, formatting can be done through the entire column once, instead of applying the formatting one cell at a time.

You can get a handle to a ReportColumn by using the following method in ReportTable:

getColumn(int index);
2.3.5.5.5. ReportTable

This is the main part of the report. This is the section that contains the data columns that have been selected for the report. This section contains the data that is used for the Group Footers and for the various summaries.

You can get a handle to the ReportTable section by using the following method in QbReport:

getTable();
2.3.5.5.6. ReportImage

ReportImage objects are used to add images to the report. The formats supported by EspressReport are GIF, JPEG, and PNG. The ReportImage object can be considered as a cell that contains a image. Care is to be taken to define the dimensions of the cell so that the image is clearly visible and is not truncated.

You can get a handle to all the ReportImage objects by using the following method in QbReport:

getReportImages();
2.3.5.5.7. ReportChartObject

ReportChartObjects are used to add charts of type TPL or CHT (Quadbase's proprietary formats) to the report. Adding in the ReportChartObject is different from adding in a ReportImage object. Here, the location of the TPL or template file is given. EspressReport then takes the template and creates a chart using the data from the relevant section. Thus, using the same template, you can have different charts at different points of the report, all of which share the same look and feel, even though the data might be different.

The chart template files are first created in Report Designer. Thus, the mapping of the chart is based on the mapping of the data in the report. We recommend using chart templates from the same type of report containing similar data mapping (i.e., the same kind of data and data type) as the report being generated using the API.

ReportChartObjects can also be used to add stand-alone charts (i.e., charts whose data is not from the report). Stand-alone charts are created from the API and the data source for the chart can be independent from the report.

Again, a ReportChartObject object can be considered as a cell that contains a chart. Similar care should be taken to define the dimensions of the cell so that the chart is clearly visible and not truncated.

You can get a handle to all the ReportChart objects by using the following method in QbReport:

getReportChartObjects();
2.3.5.5.8. ChartObject

ChartObjects are intermediate objects created before adding a chart, created completely through the API, to the report. The chart obtains its data from the report and the mapping for the chart is based on the columns of the report. These charts are different from stand-alone charts as the data for these charts is the report itself whereas the data for stand-alone charts can be independent from the report. Other chart properties such as dimension, chart type and mapping are also specified and the ChartObject created.

The ChartObject is then added to a ReportChartObject. This ReportChartObject is then added to the report.

For more details on how to use ChartObject, please refer to the Chapter 3 - Charting Guide.

2.3.5.5.9. ReportDocument

ReportDocument is used to represent a clob (character large object) when adding a clob to the report. Depending on the length of the clob, it is either stored as a string in the ReportDocument or is stored in a file and the filename is stored in the ReportDocument.

Again, a ReportDocument object can be considered as a cell that contains a clob. Similar care should be taken to define the dimensions of the cell so that the content is clearly visible and not truncated.

We recommend that the ReportDocument object not be modified using the API and that all changes be done in the template.

2.3.5.5.10. ReportRTFObject

ReportRTFObject is used to add content from a RTF file to the report. The file content is streamed to a ReportRTFObject and this object is later added to the report.

Again, a ReportRTFObject object can be considered as a cell that contains RTF content. Similar care should be taken to define the dimensions of the cell so that the content is clearly visible and not truncated.

We recommend that the ReportRTFObject object is not be modified by using the API and that all changes be done in the template.

2.3.5.5.11. SubReportObject

SubReportObject is used to add sub-reports to the report. The sub-report content can either be from a file or created completely from the API.

Again, a SubReportObject object can be considered as a cell that contains a subreport. Similar care should be taken to define the dimensions of the cell so that the content is clearly visible and not truncated.

You can get a handle to all the SubReportObject objects by using the following method in QbReport:

getSubReports();

You can also get a handle to the subreport from the SubReportObject by using the following method in SubReportObject:

getSubReport(IReport qbReport);

The SubReport object obtained can then be casted to QbReport.

2.3.5.5.12. ReportGrid

ReportGrid objects are used to draw grids within different sections of the table. The grid will encompass each row and each column (and each cell in the section, if applicable). Currently, the line styles available are dash, double, and solid line styles.

We recommend that the ReportGrid object not be modified using the API and that all changes be done in the template.

2.3.5.5.13. ReportLine

ReportLine objects are used to draw a line, or lines, in different sections of a table. Lines can be inserted in any part of a report. As with ReportGrid objects, ReportLine objects have a choice of three styles; dash, double, and solid line styles

We recommend that the ReportLine object not be modified using the API and that all changes be done in the template.

2.3.5.6. Modifying Report Attributes

EspressReport has hundreds of properties, which provide a fine control over the various elements of a report. As a developer, you can customize the look and feel of a report dynamically at run-time. In order to facilitate ease-of-use, most properties have been categorized into groups and exposed in the form of interfaces. An application first obtains a handle to a group interface using a getXXX method and then manipulates the report's properties directly by calling methods on that interface. Most interfaces are contained in the package quadbase.reportdesigner.util.

2.3.5.6.1. Adding New Cells

EspressReport allows you to create new cells and position them where you want them in the report.

To add a cell to the report, you will need to create a ReportCell object (though it does not have to be a ReportCell object. It can also be a ReportImage object, a ReportChartObject, a ReportLine object or a ReportGrid object depending on the type of information you are adding). After creating and specifying the ReportCell properties, you can add it to any part of the report.

In the following example, a cell is added as the Page Footer:

ReportCell cell = new ReportCell("Inventory Report");
cell.setWidth(7);
cell.setAlign(IAlignConstants.ALIGN_RIGHT);
report.getPageFooter().addData(cell);

You can also apply another cell's look and feel onto the newly created ReportCell object by using the following method in ReportCell:

applyTemplate(ReportCell templateCell, boolean applyScript);
2.3.5.6.2. Adding Images/Charts

Both images and charts can be included in practically any part of the report. Images of type GIF, JPEG, PNG, and charts of type TPL (Quadbase's proprietary format) are supported by EspressReport. Adding charts/images to a report generally allows for better presentation and imparts more information and makes the report easier to read and understand.

To add an image, you will need to define a ReportImage object. Within the ReportImage object, you will have to pass in the URL for the image, either as an http:// or a file:// URL. It is recommended that you use an http:// URL so that if the report is exported to an DHTML format because the DHTML report picks up the image consistently. You can also specify the image type, dimensions, and alignment of the ReportImage object and then add it to the location desired in the report.

In the following example, an image called logo3 of type gif is added to the Page Header:

ReportImage reportImage = new ReportImage();
try {

    reportImage.setImageType(IExportConstants.GIF);
    java.net.URL imageLocation =
            new java.net.URL ("http://someMachineName/Gifs/logo3.gif");
    reportImage.setImageURL(imageLocation);
    reportImage.setWidth(7);
    reportImage.setHeight(1);
    reportImage.setAlign(IAlignConstants.ALIGN_LEFT);

} catch (Exception ex)  {

    ex.printStackTrace();

}

report.getPageHeader().addData(reportImage);

You can also specify a relative link to be used instead of the complete URL specified in the code (or in Report Designer). This can be done by passing in the relative path in the following method in ReportImage:

public void setImagePath(String path);

For example, passing ../../logo3.gif in the above method would result in the DHTML export having a relative link in the <img src> tag rather than the absolute URL.

To add a chart, please refer to Appendix 3.C.15 - Adding a Chart to a Report.

2.3.5.6.3. Adding Hyperlinks

You can also add hyperlinks to a cell or several cells in the report and have different hyperlinks for different cells. Hints to the link and targets can be set up in the cell and the link is then preserved when the report is exported. Note that links to RPT files can also be inserted in a report. However, the link to such files will not work outside of an applet environment. To view RPT files in DHTML format, we recommend you to create separate DHTML files and link to those files instead.

In the following example, a cell is created which contains a link to a page and is added to the Page Header:

ReportCell cell = new ReportCell("ABC Incorporated);
cell.setLink(new String("http://www.quadbase.com"));
cell.setHint(new String("Click here to go to Quadbase's Homepage"));
cell.setTarget(new String("ABC Home Page"));
report.getPageHeader().addData(cell);
2.3.5.6.4. Adding Grid Lines and Lines

While you can add a ReportGrid and ReportLine to a report using the API, we recommend that all grids and lines be inserted into a report using the Designer. To add grid lines to a report, you must define a ReportGrid object. Within the ReportGrid object, you can define various properties such as color, line style, thickness, width etc. before specifying a section to be encompassed by the grid.

In the following example, a blue grid line is added around the Report Table:

ReportGrid reportGrid = new ReportGrid();
reportGrid.setBorderColor(Color.blue);
reportGrid.setGridStyle(ReportGrid.DOUBLE);
reportGrid.setBorder(1);
reportGrid.setWidth(7);
report.getTable().addImage(reportGrid);

To add lines to the report, you must define a ReportLine object. Here, you can also define its various properties such as color, line style, thickness, width... etc before specifying the section it is added to.

In the following example, a line is added to the Page Header:

ReportLine reportLine = new ReportLine(false);
reportLine.setBorderColor(Color.red);
reportLine.setLineStyle(ReportLine.DOUBLE);
reportLine.setBorder(1);
reportLine.setWidth(7);
report.getPageHeader().addData(reportLine);
2.3.5.6.5. Adding Rich Text Field Objects

To add rich text fields to a report, you must define a ReportRTFObject object. Within the ReportRTFObject object, you can specify the location of the .rtf file and then specify the other properties of the cell before specifying a section to add the object to. Please note that a .rtf file must exist in order to add a ReportRTFObject to the report.

We recommend, however, that you do not include RTF content using this approach but rather add it to the template in the Designer.

In the following example, the content of the file RText1.rtf is added to the table data section:

ByteArrayOutputStream fileOne = new ByteArrayOutputStream();
FileInputStream fileIn = new FileInputStream("RText1.rtf");

int b = fileIn.read();
while (b != -1) {

    fileOne.write(b);
    b = fileIn.read();

}

ReportRTFObject rtfObjectOne = new ReportRTFObject(fileOne.toByteArray());
rtfObjectOne.setWidth(1);
rtfObjectOne.setHeight(.3);
rtfObjectOne.setResizeToFitContent(true);
rtfObjectOne.setX(report.getTable().getColumn(0).getWidth() + report.getTable().getColumn(1).getWidth() +
      report.getTable().getColumn(2).getWidth());    // Set Object at the end of table data

report.getTable().addRTFObject(rtfObjectOne);   
// report is an object of type QbReport

The RTF file content can also be displayed in multiple column format. Thus, instead of the default column count of 1, you can show the content in 2 or more columns. The column count and the spacing between the columns can be set using the following methods:

ReportRTFObject.setColumnCount(int columnC);
ReportRTFObject.setColumnSpacing(double space);

For example, in the above example, if the following lines of code were added:

rtfObjectOne.setColumnCount(3);
rtfObjectOne.setColumnSpacing(.3);

before adding the ReportRTFObject to the report, the report would now show the RTF portion in a three column format with .3 inches separating two adjacent columns.

For more details on rich text field content, please refer to the Section 1.5.7.7 - Rich Text Fields.

2.3.5.6.6. Adding Nested Sections

To add in a nested section (nested sections) in a report, you must get a handle to the parent section and created a child section. Nested sections are extremely useful when using in conjunction with any cell or object that need resizing without the overlapping any objects below. Please note that nested sections inherit most of the section options from their parent sections except the page-breaking option.

In the following example, two nested sections are being created within the Table Header section and a ReportCell object (reportCell) is being added to one of the sections:

ReportSection tableHeader = report.getTable().getHeader();
tableHeader.addSection();
tableHeader.insertSection(0);
tableHeader.getSection(0).setHeight(.5);
tableHeader.getSection(1).setHeight(.5);
tableHeader.getSection(0).addData(new ReportCell("Test Cell"));

The index used for nested sections follows a vector index. Please note that a section will not appear even if the height is set, if there are no cells within the section.

2.3.5.6.7. Modifying Background Color, Font .....

Properties for any section of the report can be modified by getting the appropriate handle and calling the methods. Since all parts of the report extends ReportElement, almost all the properties (which can be applied to a single ReportElement object) are here and can be applied one at a time, onto a group, or in groups.

For instance, the code below will set the background color of the ReportCell object to red:

ReportCell cell;
cell.setBgColor(Color.red);

The code fragment below would set the background color of the first column of the report to be blue:

ReportTable table = report.getTable();
table.getColumn(0).setBgColor(Color.blue);

To set all the columns of the table to blue, you need to run through a for-loop, such as one given below:

for (int i = 0; i < table.getColumnCount() ; i++)
    table.getColumn(i).setBgColor(Color.blue);

Note that writing the following code

table.setBgColor(Color.blue);

does NOT set the columns in the table to have the color blue. It merely sets the color of the table section (i.e., the area behind the cells in the column) to be blue.

Similarly, the code below:

ReportCell cell;
cell.setFont(new Font("Arial", Font.BOLD, 14);
table.getColumn(0).setFont(new Font(table.getFont().getName(), Font.BOLD, 16));

sets the font for the cell and for the first column of the report. Note that setting the font for any part of the report other than a ReportCell or a ReportColumn object (such as a ReportTable or a ReportSection) involves setting the font for each individual cell in the section. You can create your own method, which sets the font for any section of the report. For instance, the code below:

void setFont(Font font, ReportElement elts[]) {

    if (elts == null) return;

    for (int i = 0; i < elts.length; i++) {
        elts[i].setFont(font); 

}

setFont(new Font(table.getFont().getName(), Font.BOLD, 16), rowBreakHeaderZero.getData());
setFont(new Font(table.getFont().getName(), Font.BOLD, 18), tableHeader.getData());

creates your own method and uses it to set the font for the Row Break Zero Header and for the Table Header.

If you are planning to export your report in PDF format, True Type Fonts can also be mapped and used with the following method:

report.setFontMapping(String fontName, int style, String ttf);

where fontName is the name of the font, style is a QbReport FONT constant, and ttf is the path and filename to the installed .ttf font. For example:

report.setFontMapping("Dialog", QbReport.BOLDITALIC, "C:/EspressReport/help/examples/fonts/bookosbi.ttf");

For a more detailed description of PDF Font Mapping, please see the Section 1.7.2.1 - PDF Font Mapping.

Similarly, other properties can be set using the methods in the interfaces.

2.3.5.6.8. Modifying the Format

You can also change the format of any data (be it Numeric, boolean, or String) to conform to your requirements. The format can be set for individual ReportCell objects or for ReportColumn objects.

For example, the code below:

NumericFormat contentFormat = new NumericFormat();
contentFormat.decimal = 2;
contentFormat.currencySymbol = '$';

for (int i = table.getStartOfColumnBreakColumn(); i < table.getColumnCount(); i++ )
    table.getColumn(i).setDataFormat(contentFormat);

sets the format of the numeric data of the column break columns in the cross tab report. It adds a $ symbol and sets the cells to show two decimal places.

Similarly, the properties for string or boolean data can also be modified to fit your requirements.

2.3.5.6.9. Modifying a Column to Show Bar Codes

You can also represent the data (string and numeric) in a column as bar codes. This is helpful as most data sources do not have the capacity to store bar codes. And as such, only the information imprinted on the bar codes is saved, either as string or numeric data. This data can be added to the report as a column and then the data format modified to show bar codes. The format can be set for individual ReportCell objects or for ReportColumn objects. The bar code symbologies supported are Code 39, UPC A, EAN 13, Interleaved 2 of 5 and Codabar.

For example, the code below:

BarcodeFormat barCode = new BarcodeFormat(BarcodeFormat.UPCA);
table.getColumn(0).setDataFormat(barCode);

encodes the data in Column 0 as bar codes using the UPC A symbology.

2.3.5.6.10. Modifying a Report to be a Top N report

You can modify the report to show a set of the highest values or the lowest values within the group. This is helpful when you want to show a report with the highest revenues or the lowest incidences of errors.

The number of records as well as the ordering is specified using the following method:

QbReport.createTopNReport(int colIndex, int topN, boolean ascending);

The colIndex argument refers to the column in the report, the topN argument specifies the number of records and the ascending argument specifies whether to show the highest or the lowest records.

For example, the code below:

report.createTopNReport(3, 20, true);

takes the highest 20 records within Column 3 (depending on the grouping of the report) and displays them in order.

Note that only Columnar, Summary Break, and Master & Details reports can be modified to a Top N report.

2.3.5.6.11. Cell Scripts

You can also develop your custom cell scripts. These scripts can be assigned to the cells or columns and can be run when certain conditions or requirements are met. These scripts can change the format of the cell(s) so that it looks different from its surrounding cells. Please note that cell scripting using the API is different from cell scripting in Report Designer.

The following example, which can be run as an application or as an applet, sets up a script that changes the font of any data that is less than 0:

public class myScript implements ICellScript  {

    // Format the cells according to the specified parameters
    public ReportCell formatCell(int rowIndex, ReportCell cell, Object originalData, IFormat dataFormat) throws Exception {
        if (originalData instanceof Double)
            if (((Double)originalData).intValue() < 0)
                cell.setFontColor(java.awt.Color.red); 

        return cell;

    }

}

You can use the following method in ReportColumn to apply the script to a particular column:

setCellScript(ICellScript script);

Note that you can have different scripts on different columns although a column can have only one script.

2.3.5.7. Exporting the Report

EspressReport API has the capability to export reports in a variety of formats. These include PDF, DHTML, TXT, and CSV formats etc. In addition, any charts included in the report can be exported into JPEG, GIF, and PNG formats as well; although by default, the charts in the report are exported as JPEGs. The format for the chart can be changed, when creating the ReportChartObject object, by specifying the image type (use the method setImageType(int)).

A report may also be exported to the proprietary PAK format. An PAK file stores all information, except actual data. The PAK file can then be used to construct a report object. For an PAK file, the data is automatically loaded from the original data source at the time the report object is constructed. (Note PAK files can be directly viewed using a Report Viewer applet.)

To export the report, use the following method:

public export(int format, String filename)

In the above method, format is one of the format constants listed below and filename is the output filename (with or without an extension).

The following list shows the format constants available for exporting the report components:

QbReport.CSV

Comma delimited text file

QbReport.TXT

Delimited text file

QbReport.DHTML

Dynamic Hyper Text Markup Language (DHTML)

QbReport.HTML

Hyper Text Markup Language (HTML)

QbReport.PDF

Portable Document Format, with password protection option (PDF)

QbReport.RPT

Report File Format (RPT)

QbReport.RPT_DATA

Report File Format (RPT) With Data

QbReport.PAK

Pack Format (PAK)

QbReport.XML_DATA_AND_FORMAT

Extensible Markup Language, Data and Report Template (XML)

QbReport.XML_PURE_DATA

Extensible Markup Language, Data Only (XML)

QbReport.XML_TEMPLATE

Extensible Markup Language, Report Template Only (XML)

QbReport.EXCEL

Excel Format (XLS)

QbReport.EXCEL_OOXML

xcel 2007 Format (XLSX)

QbReport.RTF

Rich Text Format (RTF)

QbReport.VIEW

View File (VIEW)

In addition, any charts included in the report can be exported to one of the following image formats (format given with its corresponding constant):

QbReport.GIF

GIF

QbReport.JPEG

JPEG

QbReport.PNG

PNG

The following code, which can be run as an applet or application, shows how to construct and export a report:

Component doExportReport(Object parent) {
	QbReport.setEspressManagerUsed(false);
	ColInfo colInfo[] = new ColInfo[4];
	for (int i = 0; i < colInfo.length; i++) {
		//			Map data column to the Report column
		colInfo[i] = new ColInfo(i);
	}

	QbReport report = null;
	try {
		report = new QbReport
				(parent, // applet 
						"ExportReport.rpt"); // template
			ReportChartObject chartObject = new ReportChartObject();
		String chartLocation0 = new String("ExportReport0.tpl");
		chartObject.setText(chartLocation0);
		chartObject.setWidth(7);
		chartObject.setHeight(3);
		chartObject.setImageType(QbReport.JPEG);

		report.getReportFooter().addData(chartObject);

		report.export(QbReport.DHTML, "ExportReport");

	} catch (Exception ex) {
		System.out.println("Cannot create the report");
		ex.printStackTrace();
	}

	return (new Viewer().getComponent(report));
}

Please note that when you export the report to a text file, the default delimiter is a tab space. However, you can set another delimiter (available delimiters are ,, ; and ) by using the following code:

report.setExportDelimiter(IDelimiterConstants.COMMA);    // where report is an Object of type QbReport

When exporting the report to an Excel or Excel 2007 file, you can also set a method so that each numeric value only occupies one cell. This may be helpful if the end user intends to use Excel functions on the exported report. To use this feature, set the following method to true before exporting the report.

QbReport.setExcelExportFitCell(boolean b) 

You can also export the QbReport object to a byte array using the method

public byte[] exportReportToByteArray();

This will give the .rpt equivalent in the form of a byte array. This is useful if you need to serialize the QbReport object. Please note that you will still need to specify the directories for any sub-reports, drill-down, and/or charts (if you are not using EspressManager) when recreating the QbReport object from the byte array.

2.3.5.7.1. Multiple Page Exporting

You can also export the report into several pages, instead of a single page i.e., the report can be exported to various files and then shown piecemeal. This option is only available for HTML, DHTML, and XML (Data + Format) export.

The following code is used to export the report into multiple files:

report.setExportToMultiPages(true);

When using this option, several files are generated (the number of files generated is equal to the number of pages in the report). The first file has the same name as the filename specified in the export method. The subsequent files have the corresponding page number attached at the end of the filename, with the file containing the last page having LAST in the filename instead of the page number. For example, if a three page report is exported to SalesSummary. The resulting files that are created are SalesSummary.html (contains the first page), SalesSummary_2.html (contains the second page), and SalesSummary_LAST.html (contains the last page).

You can also export a specific page at a time (instead of the complete report) and export the page to a specific file. This is done using the method:

export(int format, OutputStream out, int pageNumber);

For example, to export page 3 of a report into the html file ThirdPage, the following code is used:

FileOutpuStream dout3 = new FileOutputStream("ThirdPage.html");
report.export(QbReport.DHTML, dout3, 3);
dout3.close();

Note that you can pass in -1 (without the double quotes) as the argument for the pageNumber to export the last page. You also do not need to setExportToMultiPages to true in order to export a specific page.

2.3.5.7.2. PDF Exporting Options

In certain constructors of the QbReport class, the parameters userPass, ownerPass, and permissions are available. These parameters are used to set the user password, owner password, and permissions for the user of the PDF document, respectively. All permissions will be granted to the owner of the PDF document (who uses the owner password to open the PDF document) while only the specified permissions in the permissions argument will be available to the user (who uses the user password to open the PDF document). Please refer to the EspressReport Java API Documentation for more detail about exporting to PDF with options.

The export method that sets PDF options is listed here for the reader's convenience.

public void export(int format,
                   java.io.OutputStream out,
                   int exportPage,
                   java.lang.String userPass,
                   java.lang.String ownerPass,
                   int permissions);

Additionally, you can also pass embed java scripts in the PDF export so that when the PDF content is streamed to a client browser, the java script is run. The following method allows java script to be embedded to a PDF content

public void export(int format,
                   java.io.OutputStream out, // Or java.lang.String specifying the file Name
                   java.lang.String userPass,
                   java.lang.String ownerPass,
                   int permissions,
                   java.lang.String javaScript);

For example, the following method sets the PDF to automatically print when it is viewed in a client browser.

QbReport report = new QbReport(......);
.......
.......
String javaScript = "this.print(true);\r";
report.export(QbReport.PDF, someOutputStream, null, null, QbReport.AllowAll, javaScript);

The above call would export the report as PDF content (with all permissions) to a stream (someOutputStream) passing data to a client browser. When the PDF is loaded on the client browser, the javascript is automatically run (which in this case, tells the browser to print the content).

2.3.5.7.2.1. PDF Font Mapping in API

In order to render Unicode in exported PDF, you need to do font mapping. In Report Designer, it can be done from the Font Mapping dialog: https://data.quadbase.com/Docs70/er/help/manual/SavingandExportingReports.html#DesignerPDFFontMapping

In API, the font mapping method is:

void setFontMapping(String fontName, int style, String ttf, String encoding, boolean embed)
          

Parameters:

fontName: the name of the font

style: one of the following. QbReport.PLAIN, BOLD, ITALIC, BOLDITALIC

ttf: the path of the .ttf file

encoding(CMAP): the encoding of this font

embed: whether to embed this font to the document. by default true.

[Note]Note

Embed is always true for encoding “Identity-H” and “Identity-V”, even if you specify embed to false. Identity-H: horizontal writing systems, Identity-V: vertical writing systems

The following example maps “Dialog” to font file NotoSansSC-Regular.ttf:

qbreport.setFontMapping("Dialog",QbReport.BOLD, "C:\\tmp\\testedFonts\\NotoSansSC-Regular.ttf", BaseFont.IDENTITY_H, true);

          

If you prefer a smaller file size, CJK fonts don’t need to be embedded. In directory ReportDesigner.jar\quadbase\common\util\output\pdf\regularfonts\cmaps\, there are a series of *.properties and *.cmap files. The file cjk_registry.properties states registry and CMAP(encoding) names, for example:

Adobe_GB1=Adobe-GB1-0 Adobe-GB1-1 Adobe-GB1-2 Adobe-GB1-3 Adobe-GB1-4 Adobe-GB1-5 GB-EUC-H GB-EUC-V GB-H GB-V GBK-EUC-H GBK-EUC-V GBK2K-H GBK2K-V GBKp-EUC-H GBKp-EUC-V GBpc-EUC-H GBpc-EUC-V GBT-EUC-H GBT-EUC-V GBT-H GBT-V GBTpc-EUC-H GBTpc-EUC-V UniGB-UCS2-H UniGB-UCS2-V UniGB-UTF16-H

          

And other properties files are font information, you can find font registry there, for example, in file STSongStd-Light.properties:

Registry=Adobe_GB1

Table: CJK fonts

LanguageFontCMap(encoding) name
Chinese (simplified)STSong-Light STSongStd-Light Adobe-GB1-0 UniGB-UCS2-H UniGB-UCS2-V and more ……
Chinese (traditional)MHei-Medium MSung-Light MSungStd-Light Adobe-CNS1-0 UniCNS-UCS2-H UniCNS-USC2-V and more ……
JapaneseHeiseiMin-W3 HeiseiKakuGo-W5 KozMinPro-Regular 90msp-RKSJ-H 90pv-RKSJ-H UniJIS-UCS2-H UniJIS-UCS2-V UniJIS-UCS2-HW-H UniJIS-UCS2-HW-V and more ……
KoreanHYGoThic-Medium HYSMyeongJo-Medium HYSMyeongJoStd-Medium Adobe-Korea1-2 UniKS-UCS2-H UniKS-UCS2-V and more ……
[Note]Note

If you open a file using CJK fonts in Adobe Reader, and those fonts are missing, a dialog will pop up asking if you want to update Adobe Reader. If you say yes, it will download and install the necessary fonts. These fonts can only be used in Adobe Reader and nowhere else, unless you have a special license from Adobe.

The following example is a font mapping to a CJK font "STSong-Light":

qbreport.setFontMapping("Dialog",QbReport.PLAIN, "STSong-Light", "Adobe-GB1-0", false);


          

If you want to use a CJKFont in a different style, you can add one of the following modifiers to the font name: Bold, Italic, or BoldItalic. For example:

qbreport.setFontMapping("Dialog",QbReport.BOLD, "STSong-Light,Bold", "Adobe-GB1-0", false);
          

The link Example contains a complete API example with Chinese Font mapping, Japanese Font mapping, and Korean Font mapping.

2.3.5.7.3. Exporting DHTML Content with Style Sheets

You can specify a style sheet to be used while exporting the report to DHTML or HTML format. You can specify an internal style sheet or an external style sheet before exporting the report.

To export the report using an internal style sheet, you would use the following method in QbReport:

public void setUseStyleSheet(boolean state); 

To export the report using an external style sheet, you first need to specify the style to be used for the specified ReportElement object by using the following method in ReportElement:

public void setStyleName(String newStyleName); 

You then specify the name of the external style sheet file using the following method in QbReport:

public void setExternalStyleSheetName(String css); 

For example, the following code:

report.getTable().getColumn(0).setStyleName("style_1"); // where report is an object of type QbReport
report.setExternalStleSheetName("http://someMachine/someDirectory/styles.css"); 

will set the first column of the report to use style_1 from the specified style sheet file (in this case, it is http://someMachine/someDirectory/styles.css).

2.3.5.7.4. HTML Block Export

You can export reports as a block of HTML code rather than a complete HTML file. This allows for custom content to be added to the generated HTML report.

The code given below:

report.setHeadTagIncluded(false);        // where report is an object of type QbReport

generates the report as an DHTML table when the report is exported. This block can then be included in another page with more content than just the report.

2.3.5.7.5. Custom Links for Multi-page DHTML/HTML Export

You can also create your own links at the top of the page or remove links generated at the top of the pages for single page and multi page exports. This allows custom links to be added to both HTML and DHTML reports.

Custom links can be generated by implementing IHTMLLinksProvider. interface. For example, the code below, which can be run as an application or an applet, demonstrates creating custom links:

Component doCustomLinks(Object parent) {
	QbReport.setEspressManagerUsed(false);
	QbReport report = new QbReport(parent, "CustomLinks.rpt");
	report.setHTMLLinksProvider(this);
	QbReport.setExportToMultiPages(true);

	try
	{
		report.export(IExportConstants.DHTML, "CustomLinks.html");
	} catch (Exception ex) {
		ex.printStackTrace();
	}

	return (new Viewer().getComponent(report));

}

public HTMLBlock getLinksForDHTML(int cPage, int tPage, String prefix, boolean top)
{

	String linksText = "<CENTER><font face=\\\"verdana\\\" size=\\\"2\\\">" +

			"<a href=\\\"" + HTMLBlock.getFirstFileName(prefix) + "\\\">FIRST</a> | ";
	if (cPage <= 2) {
		linksText += "<a href=\\\"" + HTMLBlock.getFirstFileName(prefix) + "\\\">PREV</a> | "
				+ "<a href=\\\"" + HTMLBlock.getNextFileName(cPage, tPage, prefix)
				+ "\\\">NEXT</a> | " + "<a href=\\\"" + HTMLBlock.getLastFileName(prefix)
				+ "\\\">LAST</a> [" + "<a href=\\\""
				+ HTMLBlock.getCurrentFileName(cPage, tPage, prefix)
				+ "?x=x\\\" target=\\\"print\\\">Print Version</a>]" + "</font></CENTER>";
	} else {
		linksText += "<a href=\\\"" + HTMLBlock.getPreviousFileName(cPage, tPage, prefix)
				+ "\\\">PREV</a> | " + "<a href=\\\""
				+ HTMLBlock.getNextFileName(cPage, tPage, prefix) + "\\\">NEXT</a> | "
				+ "<a href=\\\"" + HTMLBlock.getLastFileName(prefix) + "\\\">LAST</a> ["
				+ "<a href=\\\"" + HTMLBlock.getCurrentFileName(cPage, tPage, prefix)
				+ "?x=x\\\" target=\\\"print\\\">Print Version</a>]" + "</font></CENTER>";
	}

	String text = "<SCRIPT>\n" + "document.write(\"" + linksText + "\");\n" + "</SCRIPT>";
	return new HTMLBlock(text, 100);

}

public HTMLBlock getLinksForHTML(int cPage, int tPage, String prefix, boolean top)
{
	return getLinksForDHTML(cPage, tPage, prefix, top);
}

public HTMLBlock getTOCLinkForDHTML(int cPage, int tPage, String body) {
	return null;
}

Similarly other links can be generated and set to the report.

2.3.5.7.6. Setting the Pixels Per Inch Ratio for DHTML/HTML Export

EspressReport allows a pixels per inch ratio to be specified while exporting HTML or DHTML content. This is especially useful when you are moving and deploying reports between platforms or when exporting reports in a system without any graphics. You can specify the ratio using the following method in QbReport:

public void setPixelPerInchForExport(int pixelPerInchRatio); 
2.3.5.7.7. Pre-load charts

EspressReport allows charts with independent data sources to be pre-loaded before the report is exported. The pre-loading is simultaneous, so it improves export performance (especially if there are multiple charts in the report). You can specify to pre-load the charts by calling the following method before exporting the report:

public void preloadChartObjects(); 
2.3.5.7.8. IExportThreadListener for .view files

Reports can be exported to .view files. These files are used by Page Viewer to show the report a few pages at a time (as opposed to loading the entire report in Report Viewer). Exporting to .view files is similiar to exporting to multiple pages in that the one export method results in multiple pages (the more the number of pages in the report, the more files that are generated). However, Page Viewer cannot be started unless the .view file is generated (the pages of the report are generated as .page files). EspressReport provides an interface, IExportThreadListener, which you can implement to perform actions when the first page is exported and when the export is completed.

Given below is an example using the IExportThreadListener:

public class ExportView extends Applet implements IExportThreadListener {
	static final long serialVersionUID = 1;

	public static void main(java.lang.String[] args) {

		try {
			ExportView report = new ExportView();
			report.exportView(null);
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	//	creates report and return it
	void exportView(Object parent) throws Exception {

		//		Turn off ReportServer as it is not needed.
		QbReport.setEspressManagerUsed(false);

		//		Create the colinfo array to be used in the QbReport constructor
		QbReport report = new QbReport(parent, "ExportView.rpt");

		report.setMultiPageExp(true);
		report.export(QbReport.VIEW, "ExportView", new Properties(), this);
		System.out.println("DONE!");

	}

	public void endAction() {
		System.out.println("END ACTION");
	}

	public void firstPageFinishedAction() {
		System.out.println("FIRST PAGE FINISHED ACTION");
		quadbase.reportdesigner.PageViewer.Viewer.main(new String[] { "ExportView.view" });
	}

}
2.3.5.7.9. Virtual Memory / Paging

In addition to memory optimized exporting, EspressReport also has a paging feature to handle large amounts of data. With paging, you specify the amount of memory and a temp directory. When the amount of memory used exceeds the number specified, the data is compacted and then stored on disk in the temp directory specified.

The feature works with or without EspressManager. However, if using the EspressManager, it is recommended to use the same option values in both the client code and the EspressManager.

To use memory paging export, the following code must be added before calling the QbReport constructor:

QbReport.setTempDirectory
          (<specify the temp directory to store data.  Default is ./temp>);
QbReport.setMaxFieldSize(int fieldSize);
QbReport.setPagingThreshold(int pagingThreshold);
QbReport.setPageBufferSize(int bufferSize);
QbReport.setTotalPageBufferSize(int totalBufferSize); 
Max Field Size:

This argument specifies the expected maximum field size for large field types such as varchars. Fields that are larger than this value are not necessarily truncated. The behavior depends on the current memory usage in relation to the Total Paging Buffer Size allowed. As the amount of available memory decreases the amount of data stored for these large fields will decrease until it reaches this value. For example, a user is running a report with a field size that is larger than the specified Max Field Size value. When the server is not busy and there is ample memory available, the report will generate the full field without any truncation. However, when the server is heavily loaded and the available memory is near zero, the field in the report will be truncated to the Max Field Size. For numeric, boolean, date, time, and character data types, the data will never be truncated. For those database fields that are defined with a size limit smaller than the Max Field Size (e.g. Max Field Size = 500, but the field is defined as varchar(20)), the database limit will be used in place of the Max Field Size. This value is set in Bytes.

Paging Threshold:

This property specifies when the paging feature will be activated. Once this threshold is reached, the server will begin paging the data to temporary files on the system. If this argument is set to -1 then data will never be paged. This value is independent of Page Buffer Size option. If this value is larger than the Page Buffer Size, the system will not begin paging until the threshold is reached. Therefore, each report or chart might use more memory than the amount specified in the Page Buffer Size. This value is set in Megabytes and the default is -1.

Paging Buffer Size:

This argument allows you to set the amount of memory that each report or chart will use when the paging feature is invoked. The size of the buffer affects performance. The larger the buffer size, the faster the report or chart is generated, but the more memory is used. When the amount of total memory used by the paging system approaches the Total Paging Buffer Size, the amount of memory provided to new reports will begin to diminish in order to avoid exceeding the specified total amount. This value is set in Megabytes.

Total Paging Buffer Size:

This argument allows you to set the total amount of memory used by the paging feature across all reports and charts. The memory allocated to each report will diminish as the memory usage approaches this value. This value is set in Megabytes.

2.3.5.7.10. Streaming Reports

In addition to exporting to local drives, reports can also be exported as a byte stream and streamed directly to a web browser. However, in order for charts, drill-downs, and parameters to function correctly, this export method requires that several support servlets be available. The three servlets that does this are RPTImageGenerator, DrillDownReportServlet, and ParamReportGeneratorServlet. They are located in the <EspressReport>/WEB-INF/classes/ directory. The three files must be copied to the servlet directory of your servlet runner. Use the following code to connect to the servlets:

report.setDynamicExport(true, "Machine Name or IP Address", Port);
report.setServletDirectory("Servlet Directory"); 

These methods sees to it that any call to these servlets are pointing to the correct machine and port. The servlets get called using the URL, http://<MachineName:>:<Port:>/<ServletDirectory:>/<Servlet:>. You must set dynamic export when streaming your report, but setting the servlet directory is optional. If you do not specify which servlet directory to use, it will be automatically set to servlet/.

Given below is an example that exports a report to DHTML and streams it to the browser. In order to run the example, you will need to configure and compile the source code, then deploy the class file in the servlet directory of your servlet runner. Replace the reportTemplate variable with either an absolute path or a path relative to the working directory of your application server. Remember that the working directory is usually not the same as the servlet directory. In addition, make sure to add ReportAPIWithChart.jar and qblicense.jar to the classpath of your application server. Both jar files can be found in <EspressReport>/lib/.

public class StreamingReport extends HttpServlet {
	static final long serialVersionUID = 1;

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,
			IOException
	{
		// Do not use EspressManager
		QbReport.setEspressManagerUsed(false);

		// Location of report template
		String reportTemplate = "StreamingReport.rpt";

		// Create QbReport object
		QbReport report = new QbReport(null, reportTemplate);

		// Set up connection information for RPTImageGenerator and DrillDownReportServlet
		report.setDynamicExport(true, "localhost", 8080);
		report.setServletDirectory("servlet/");

		// Export the report to DHTML and stream the bytes
		ByteArrayOutputStream reportBytes = new ByteArrayOutputStream();

		try {
			report.export(QbReport.DHTML, reportBytes); // where report is an object of type QbReport
			//			report.export(QbReport.PDF, reportBytes); 		// where report is an object of type QbReport
		} catch (Exception ex)
		{
			ex.printStackTrace();
		}

		res.setContentType("text/html"); // where res is the HttpServletResponse
		//		res.setContentType("application/pdf"); 	// where res is the HttpServletResponse
		res.setContentLength(reportBytes.size());

		OutputStream toClient = res.getOutputStream();
		reportBytes.writeTo(toClient);
		toClient.flush();
		toClient.close();
	}
}

To run the example, make sure to copy the report templates to the location accessed by the code. If using a relative path (as shown in the example), remember that the current directory is the working directory of your application server. For example, since the working directory in Tomcat is <Tomcat>/bin, you will need to create the directory <Tomcat>/templates/ and copy the report templates there to run the code. The resulting report is shown below:

Streaming Report

2.3.5.7.10.1. RPTImageGenerator

The RPTImageGenerator is used when you export reports containing charts or BLOB images to either HTML or DHTML format. HTML and DHTML files are purely textual; therefore, charts and images must be stored separately. When you export a report locally, the chart is stored as an image file and the file path is appended to the IMG tag of the HTML page.

<IMG SRC="stream_0.jpg" ALIGN="CENTER" VALIGN="TOP"BORDER="0" HEIGHT="288" WIDTH="576"></IMG> 

Similarly, when you stream the DHTML file, only the textual component is sent to the browser. Charts are handled in the RPTImageGenerator servlet. Instead of pointing the IMG tag to the image file, the tag is set to the RPTImageGenerator servlet and appends the ID of the chart image as a parameters.

<IMG SRC="http://localhost:8080/servlet/RPTImageGenerator?ID=1166125348416_0" ALIGN="CENTER" VALIGN="TOP"BORDER="0" HEIGHT="288" WIDTH="576"></IMG> 

Reports containing images that are stored locally do not require the servlet. The IMG source will point directly to the image file. However, images retrieved from the datasource (BLOBs) are treated similar to charts and does require the aid of the RPTImageGenerator servlet.

2.3.5.7.10.2. DrillDownReportServlet

Regardless of if you are exporting the report to a byte stream or to a file, reports with drill-downs require that the DrillDownReportServlet be accessible in order to function properly. When you export drill-down reports to either DHTML or PDF format, you must have DrillDownReportServlet in the servlet directory of your servlet runner. This servlet provides the link to the next level.

<a href="http://localhost:8080/servlet/DrillDownReportServlet? FILENAME=DrillDown%2Fstream_lvl11.rpt&FORMAT=4&PARAM0=112+Ishtar+Chair" title="tt" alt="tt"> 
Ishtar Chair<BR></a>

Since drill-down levels must contain a parameterized query, you need to make sure that the ParamReportGeneratorServlet is in the servlet directory as well. More information on the ParamReportGeneratorServlet are available in the next several sections.

If you export the report to HTML or DHTML, the column linked to the drill-down report will display as a hypertext link. In PDF format, the linked column will not look any different from the others; however, when you hover the mouse over that column, the cursor will change to a hand.

Root Level

Depending on the link clicked, the servlet delivers the appropriate next level report.

The Drill-Down Level

Note that drill-down reports exported to formats other than DHTML or PDF will only show the current level.

2.3.5.7.10.3. Generating HTML Parameter Page

When streaming the report, a powerful alternative to setting parameter values using the API (discussed in Section 2.3.5.1.4 - Parameterized Reports) is to use an automatically generated HTML form that contains text or selection inputs. After the user submits the form, the parameter values are passed to the ParamReportGeneratorServlet that processes them and streams back a report initialized with these parameter values.

The main classes for this purpose are ParameterPage, ParameterPageWriter, HtmlParameterPageWriter, and CssHtmlParameterPageWriter. The typical method of generating the HTML Parameter Page involves the following code:

OutputStream out = ...; //response.getOutputStream();
ParameterPage paramPage = QbReport.getParameterPage();
Writer writer = new PrintWriter(out);
HtmlParameterPageWriter paramPageWriter = new HtmlParameterPageWriter(paramPage, writer);
paramPageWriter.writePage();
writer.flush();
writer.close(); 

When you use the above functionality, you must have the ParamReportGeneratorServlet in the servlet directory of your servlet runner. This servlet generates the report in the specified format using the parameters specified in the HTML page.

When you run the example, the following page is automatically generated:

Generated Parameter Page

Depending on the values you select, clicking on the submit button may result in the following report:

Parameterized Report

Although it is convenient to automatically generate the entire parameter page, there are times when you want more control over the appearance of the page. One way to achieve this is to only generate the main form, allowing you to design the contents around the main form to provide your own look and feel. Another way is to use CSS to set the desired format. A third way is to generate each component within the form individually giving you control over every element on the page. These various methods are discussed in greater detail in the next two sections.

2.3.5.7.10.3.1. Utilizing Cascading Style Sheets (CSS)

Two powerful ways to alter the HTML parameter page are to add content around the form and to utilize cascading style sheets. These methods allow you to maintain a consistent look and feel to your web application, without the necessity to write an excessive amount of code.

The example below shows how these methods can be used to present the parameter page using your predefined colors, fonts, style, and format. In order to run this example, you need to modify the template path. Keep in mind that if you use a relative path, it will be relative to the working directory of your application server. You will also be required to copy the CSS file to the root directory of your web application so that it can be accessible by the CSS link in the code (alternatively, you can position the CSS file elsewhere and modify the link). The examples require that both ParamReportGeneratorServlet and DrillDownReportServlet be available in the servlet directory since the example includes a Drill-Down report.

CssHtmlParameterPageWriter cssParamPageWriter =
                    new CssHtmlParameterPageWriter(paramPage, tempStringWriter);

// Specify the css file to be used
cssParamPageWriter.setCssFile("http://localhost:8080/CssExample.css");

// Create head of html page, adding title and css specification
cssParamPageWriter.write("<HEAD>\n" +
                 "<link REL=\"stylesheet\" TYPE=\"text/css\" " +
                 "href=\"" + cssParamPageWriter.getCssFile() + "\">" +
                 "\n<TITLE>Welcome to Woodview</TITLE>\n" +
                 "</HEAD>");

// Body section - Most of the formatting is done in the css file,
// very little is needed here
cssParamPageWriter.write("\n<body><p> 
");

// Add title and fieldset
cssParamPageWriter.write("<TABLE class=\"outer\"><TR><TD>" +
                 "<p class=\"heading2\">Welcome to the Order History Database." +
                 "</TD></TR><TR><TD>&nbsp;</TD></TR>" +
                 "<TR><TD><FIELDSET><LEGEND>Select</LEGEND>");
// Add the parameter forms
cssParamPageWriter.writeBodyBody();

// Finish it off
cssParamPageWriter.write("</FIELDSET></TD></TR>" +
                 "</TABLE></body>\n</html>");

In the above segment of code, the <HEAD> is written manually so that a title can be inserted. In the body section, only the form is generated. Using this method, users can add titles, images, and other components to maintain their own look and feel. Depending on the CSS file provided, the result might look like this:

Parameter Page using CSS

Depending on the parameter options you select, the result may look like the following:

Example Results

2.3.5.7.10.3.2. Customizing the Parameter Page

Another way to customize the parameter page is to write a java class that extends HtmlParameterPageWriter or CssHtmlParameterPageWriter.This approach gives you access to the protected methods available in these classes. For information on the full set of methods available in these classes, please see the APIDocs

The following is an example extending the HtmlParameterPageWriter class. To run this example, you will need to copy the two html pages to the root directory of your application server. The template and java class files must be copied to the working directory and servlet directory of your application server respectively. The example also requires that ParamReportGeneratorServlet and DrillDownReportServlet be placed in the servlet directory.

private class MyHtmlParameterPageWriter extends HtmlParameterPageWriter{

    public MyHtmlParameterPageWriter(ParameterPage pp, StringWriter sw) {
        super(pp,sw); }

    public void printCustom() {
        try {
            write("<BODY bgcolor=#FDFAED>");

            write("<FORM action = \"" + servletName +"\" target=\"main\" method = GET>\n");
            write("<TABLE ALIGN=\"CENTER\"><TR><TD><IMG src=http://www.quadbase.com/FurnitureImages/Woodview.gif></TD>");
            write("<TD WIDTH=50></TD><TD>");
            writeParamTable();

            write("</TD><TD WIDTH=50></TD><TD>");
            writeSubmitButton();
            write("</TD>");
            write("</TR></TABLE>");

            writeHiddenParamValue("ReportFilePath", reportLocation);
            write("\n");

            writeHiddenParamValue("ReportExportFormat", ""+format);
            write("\n");

            writeHiddenParamValue("ServerName", servletAddress);
            write("\n");
            writeHiddenParamValue("ServletRunnerPort", ""+servletPort);

            write("\n");
            writeHiddenParamValue("ServletDirectory", servletDirectory);

            write("\n</FORM>");
            html.bodyEnd();
            html.htmlEnd(); } catch (Exception e) {
            e.printStackTrace(); } } 

} 

Notice that by using the protected methods, you are required to add a number of details in your code, such as FORM tags and hidden parameters. However, this also grants you the ability to add other elements such as company logos into the form section of the page and arrange the elements to your preference. This approach also allows you to eliminate certain elements from the page such as the reset button.

Once the files have been copied to the correct locations, you can run the example by entering the following URL in your browser: http://<IP Address/localhost>:<Port>/CustomParamPage.html. You will see a page with two frames. The top frame is the parameter page and the bottom frame initially displays a simple message. To view the report, enter the full name of a customer (e.g. Francis Polk).

Order History Report

This example exports to PDF instead of DHTML. Although there are no links displayed in PDF format, if you hover the mouse over the Order ID column, you will see that the mouse pointer turns into a hand alerting you that you can drill-down from this column. Depending on the Order ID you selected, the follow report may be shown.

Order History Detail (Drill-Down)

2.3.5.7.11. Calling Report Designer from Report API

Report Designer can be called from Report API in either an application or an applet. Depending on the code, you can pass in parameters to open up Report Designer with a specified .rpt file or a specified data source or other parameters.

To call Report Designer from Report API, you must:

  • make sure that EspressManager is up and running;

  • add ReportAPIWithChart.jar, EspressManager.jar and qblicense.jar to the CLASSPATH;

  • make sure that the information to connect to EspressManager is specified using the relevant API calls (This is especially important if the EspressManager is on a different machine and/or if it started with a port number other than 22071);

  • copy the images, reportimages and backgroundimages directories to the working directory or use QbReportDesigner.setUseSysResourceImages(true) in your code to use the images from the jar files;

Depending on the -RequireLogin and -QbDesignerPassword flags for EspressManager, you may need to pass in a userid and/or password to connect to EspressManager. If the -RequireLogin flag is set for EspressManager, you need to add the following line of code before calling setVisible() or any getDesigner methods:

public login(String userName, String password); // Method found in QbReportDesigner class 

If the -QbDesignerPassword is specified for EspressManager, you will need to add the following line of code before calling setVisible() or any getDesigner methods:

public login(String password); // Method found in QbReportDesigner class 

You can also specify a look and feel to Report Designer (Report Designer will use the system's look and feel by default). This is done by using the following method in QbReportDesigner:

public static void setLookAndFeel(javax.swing.LookAndFeel newLookAndFeel);

Given below are the different ways Report Designer can be called via Report API. Note that if you are running the example code as an applet, you need to change the EspressManager machine from 127.0.0.1 (or localhost) to the EspressManager machine's name or IP address.

2.3.5.7.11.1. Specify a Report Template

You can open Report Designer with a specified report template file. This lets the end users create their own custom reports in Report Designer GUI and then view the finished report.

The following constructor is used:

QbReportDesigner(Object parent, String templateFileName);

Given below is an example of calling Report Designer with a specified .rpt file:

public void doReportDesignerApplet(Applet applet) throws Exception {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    // Create a new QbReportDesigner instance
    designer = new QbReportDesigner(applet,
           "RDWithTemplateFile.rpt");

    // Overwrites default saveFile method
    designer.setReportIO(this);

    // Start Designer
    designer.setVisible(true); 

}

// Save the file to a temp directory
public void saveFile(byte[] data, String fileLocation) {

    System.out.println("OLD LOCATION: " + fileLocation);
    String newLoc = fileLocation.replace('/', '\\');
    int idx = newLoc.lastIndexOf("\\");
    newLoc = "temp/" + newLoc.substring(idx+1);
    try {
        designer.writeFile(newLoc, data);
        System.out.println("NEW LOCATION: " + newLoc); 

    } catch (Exception ex) {
        ex.printStackTrace(); 

    }

    designer.getDesigner().setTitle(newLoc);
    designer.getDesigner().repaint(); 

}

Note that the above code can be used as both an application and an applet. The above code also changes the save functionality in Report Designer so that the .rpt file is always saved in the temp directory.

When the user runs this code, the Report Designer is launched with the report template you specified.

Report Designer with Template

The user can then customize the report and save the results.

End User Customization

You can also specify the registry to use when running the above code. This is achieved by adding in the following line of code before setting the designer visible:

designer.setDataRegistry("DataRegistry/Data_Registry.xml");

The above line specifies the Report Designer to use Data_Registry.xml as the Data Registry when choosing the data sources for a new report.

2.3.5.7.11.2. Specify a Data Registry

You can open Report Designer and have it starting with a Data Source Manager (with a specified .xml file for the Data Registry). This allows the end users to choose the data source and create their own custom reports in Report Designer GUI and then view the finished report.

The following constructor is used:

QbReportDesigner(Object parent, String nameOfXMLFile, boolean doNotStartWithOpenNewReportDialogWizard);

Given below is an example of calling Report Designer with a specified .xml file:

public void doReportDesignerWithDataRegApplet(Applet applet) throws Exception {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    // QbReportDesigner (component, name of XML file, boolean);
    // true = start from Data Source Manager false = start from Create a new report
    // or open existing report choice before going to Data Source Manager
    designer = new QbReportDesigner(applet, "DataRegistry/Sample.xml", true);

    designer.setVisible(true); 

}

Note that the above code can be used as both an application and an applet.

You can also control what the user does at the Data Registry by enabling or disabling the options available. For example, you can remove complete or parts of data sources in the Data Registry and you can disable the options for the adding, copying, editing, and deleting of data sources. Note that the nodes are not hidden, they are removed. Therefore, when the Data Registry is opened (without any restrictions), the content of the nodes that were removed is lost. You can create a backup of the Data Registry .xml file and use the backup to enable/disable options.

Given below is an example of calling Report Designer with a specified data registry and setting it up so that only the database data sources are available and no queries or data views can be added.

public void doReportDesignerWithDataRegOptionApplet(Applet applet) throws Exception {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    // QbReportDesigner (component, name of XML file, true = start from
    // Data Source Manager false = start from Create a new report or open
    // existing report choice before going to Data Source Manager
    designer = new QbReportDesigner(applet,
          "DataRegistry/Sample.xml", true);
    designer.addDataSourceManagerListener(this);
    designer.setVisible(true);

}

public JTree modifyDataSourceTree(JTree tree) {

    // The following code will remove all nodes from the tree except for
    // the database nodes.
    DefaultDataSourceNode root = (DefaultDataSourceNode)tree.getModel().getRoot();
    for (int i=root.getChildCount()-1; i>=1; i--)
    {
        // System.out.println("removing");
        root.remove(i); 

    }

    // The following code will prevent the user from adding any query or dataview.
    DefaultDataSourceNode databaseHeading = (DefaultDataSourceNode)root.getChildAt(0);
    for (int i=0; i<databaseHeading.getChildCount(); i++)
    {
        ((DefaultDataSourceNode)databaseHeading.getChildAt(i)
               .getChildAt(0)).setAddEnabled(false);
        ((DefaultDataSourceNode)databaseHeading.getChildAt(i)
               .getChildAt(1)).setAddEnabled(false); 

    }

    return tree; 

} 

Note that the above code can be used as both an application and an applet.

2.3.5.7.11.3. Specify a DBInfo Object (Database Information)

You can open Report Designer and have it starting at the Select Report Type Wizard window (with a specified DBInfo object). This allows the end users to create their own custom reports in Report Designer GUI and then view the finished report.

The following constructor is used:

QbReportDesigner(Object parent, DBInfo databaseInformation, boolean doNotStartWithOpenNewReportDialogWizard);

Given below is an example of calling Report Designer with a specified DBInfo object:

public QbReportDesigner designer;
String URL = "jdbc:hsqldb:help/examples/DataSources/database/woodview";
String driver = "org.hsqldb.jdbcDriver";
String username = "sa";
String password = "";
String query = "SELECT * FROM Order_Details";

public void doReportDesignerWithDBInfoApplet(Applet applet) throws Exception {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    // QbReportDesigner (component, Database Information, true = start from Data Source Manager
    // false = start from Create a new report or open existing report choice before
    // going to Data Source Manager
    DBInfo dbInfo = new DBInfo(URL, driver, username, password, query);
    designer = new QbReportDesigner(applet, dbInfo, true);

    designer.setVisible(true); 

}

Note that the above code can be used as both an application and an applet.

2.3.5.7.11.4. Open Query Builder with a Specified DBInfo Object (Database Information)

You can open Query Builder with a specified DBInfo object. This allows the end users to create and save their own custom SQL queries in Query Builder GUI.

Given below is an example of calling Query Builder with a specified DBInfo object:

public void doQueryBuilderApplet(Applet applet, String sqlName) {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    queryMain = new QbQueryBuilder(applet, this);
    if (sqlName != null) {
        // sqlName .qry file name (without extension)
        // System.out.println("OPEN QUERY - " + sqlName);
        queryMain.openQuery(sqlName, false, null, null, driver, URL, username, password); 

    } else {
        // System.out.println("NEW QUERY ");
        queryMain.newQuery("Setup Query", false, null, null, driver, URL, username, password); 

    }
    frame = queryMain.getBuilder();
    frame.setVisible(true);
    try { queryMain.showTablesWindow();
    } catch (Exception ex) {};

}

public void back() {};

public void cancel() {};

public void next() {

    queryMain.getBuilder().setVisible(false);
    DBInfo dbInfo = new DBInfo(URL, driver, username, password, queryMain.getSQL());
    designer = new QbReportDesigner(applet, dbInfo, queryMain.getInSet(), true);
    designer.setVisible(true); 

} 

Note that the above code can be used as both an application and an applet.

You can also open Query Builder by passing in the database connection (schema) as a java object, rather than as a DBInfo object. Given below is an example of calling Query Builder by passing in the schema information:

public QBWithDBInfo2() {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    try {
        Class.forName(driver);
        conn = DriverManager.getConnection(URL, username, password);
        metaData = conn.getMetaData(); 

    } catch (Exception ex) { ex.printStackTrace(); }

    queryMain = new QbQueryBuilder(null, this);
    queryMain.newQuery("Setup Query", this);
    queryMain.setVisible(true);

    try { queryMain.showTablesWindow();
    } catch (Exception ex) {}; 

}

public void back() {};
public void cancel() {};

public void next() {

    // System.out.println("EXIT"); 

}

public String getDatabaseProductName() throws Exception {

    return metaData.getDatabaseProductName(); 

}

public ResultSet getTables(String catalog, String schemPattern, String tableNamePattern,
String[] types) throws Exception {

    return metaData.getTables(catalog, schemPattern, tableNamePattern, types); 

}

public String getNumericFunctions() throws Exception {

    return metaData.getNumericFunctions(); 

}

public String getStringFunctions() throws Exception {

    return metaData.getStringFunctions(); 

}

public String getTimeDateFunctions() throws Exception {

    return metaData.getTimeDateFunctions(); 

}

public String getSystemFunctions() throws Exception {

    return metaData.getSystemFunctions(); 

}

public ResultSet executeQuery(String sql) throws Exception {

    Statement stmt = conn.createStatement();
    return stmt.executeQuery(sql); 

}

Note that the above code can be used as both an application and an applet.

2.3.5.7.11.5. Open Report Designer with a Specific Class File Data Source

You can open Report Designer with a specified class file data source. This allows the end users to create their own custom reports in Report Designer GUI and then view the finished reports. The class file data source can be non-parameterized or parameterized.

The following constructor is used:

QbReportDesigner(Object parent, String classFile, quadbase.common.paramquery.QueryInParamSet inset, boolean newReport, int displayRow, String[] imagesPath); 

Given below is an example of calling Report Designer with a specified class file data source:

public void doReportDesignerWithQueryApplet(Applet applet) {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    // QbReportDesigner (component, class file location, parameter information,
    // true = start from Data Source Manager false = start from Create a new
    // report or open existing report choice before going to Data Source
    // Manager, number of rows to display (-1 means show all rows), path to
    // Report Designer images
    designer = new QbReportDesigner(applet, "ParamClassFile",
         null, true, -1, null); // Parameterized class file

    designer.setVisible(true);

    JFrame frame = designer.getDesigner(); 

}

For more information on creating your custom class file data source, see Appendix 2.B.5 - Data passed in a Custom Implementation.

2.3.5.7.11.6. Open Report Designer with Custom Functions

You can also include your own functions with the Formula and Scripts dialog boxes that users can use when calling Report Designer from the API. You can in effect create functions that handle complex computations and allow any user to use that same function in Report Designer.

Given below is an example code that shows you how to customize Report Designer by assigning custom functions to the Formulas and Scripts dialog boxes. The code takes in a number and converts it to an IP address by appending the number at the end of 192.168.0.

public void doRDWithCustomFunctions(Applet applet) throws Exception {
	QbReportDesigner.setServerAddress("127.0.0.1");
	QbReportDesigner.setServerPortNumber(22071);

	QbReportDesigner.setUseSysResourceImages(true);

	designer = new QbReportDesigner(applet, "RDWithCustomFunctions.rpt");
	designer.setCustomDefinedFunctions(this);
	designer.setVisible(true);
}

public String[] getAllFunctionNames() {
	return new String[] { "inet_ntoa" };
}

public int getReturnType(String functionName) {
	if (functionName.equals("inet_ntoa")) {
		return STRING;
	}
	return -1;
}

public int[] getParamTypes(String functionName) {
	if (functionName.equals("inet_ntoa")) {
		return new int[] { NUMERIC };
	}
	return null;
}

public Object getValue(String functionName, Object[] args) throws Exception {
	if (functionName.equals("inet_ntoa")) {
		return "192.168.0." + ((Double) args[0]).intValue();
	}
	return null;
}

Note that the above code can be used as both an application and an applet.

The cell containing the function will initially display as Null since the function is not part of the core set. However, the function will compute correctly when previewing the data. The value will then be shown correctly thereafter.

2.3.5.7.11.7. Open Report Designer with Pre-set Directories

You can also set the directories that reports load from and save to. This feature will restrict users from navigating to any level above the specified directory, giving you the ability to control which files the user is able to see.

Given below is an example that shows you how to customize Report Designer by specifying different directories for the load folder and the save folder:

public void doCustomizeDesignerMenuApplet(Applet applet) throws Exception {
	QbReportDesigner.setServerAddress("127.0.0.1");
	QbReportDesigner.setServerPortNumber(22071);

	QbReportDesigner.setUseSysResourceImages(true);

	designer = new QbReportDesigner(applet, "RDWithModifiedBars.rpt");

	//	Add a new menu item
	JMenuBar menuBar = designer.getReportMenuBar();
	JMenu fileMenu = menuBar.getMenu(0);
	newItem = new JMenuItem("Hello World");
	newItem.addActionListener(this);
	fileMenu.insert(newItem, 7);

	//	Remove toolbar buttons
	JToolBar designBar = designer.getDesignerToolBar();
	designBar.remove(5); // Remove Separator
	designBar.remove(4); // Remove Apply Template Button
	designer.setSaveOnExitEnabled(false); // Do not prompt to save the report if unsaved on exiting Designer

	designer.setVisible(true);

}

public void actionPerformed(ActionEvent e) {

	/*** save report **********/
	designer.save("RDWithModifiedBars_Temp.rpt");
	/**** create new testing frame *********/
	JPanel contentPane = new JPanel();
	contentPane.setLayout(new BorderLayout());
	contentPane.add(new JLabel("Hello World!"), "Center");
	JFrame frame = new JFrame();
	frame.setContentPane(contentPane);
	frame.pack();
	frame.setVisible(true);

}

Note that the above code can be used as both an application and an applet. Also, in the above example, you can choose Save As and specify a directory to save the .rpt file. However, the .rpt file will always be saved in the temp directory.

In addition to the above approach, you can also use the following method to get the default directories used by Report Designer:

public BrowseDirectories getBrowseDirectories();

You can then use the methods in BrowseDirectories to get the default location of the directories for the different browse dialogs.

2.3.5.7.11.8. Open Report Designer with Modified Menubar and Toolbar

You can also add items to the menu and remove items from the toolbar. Given below is an example illustrating that:

public void doCustomizeDesignerMenuApplet(Applet applet) {

    // Connect to EspressManager
    QbReportDesigner.setServerAddress("127.0.0.1");
    QbReportDesigner.setServerPortNumber(22071);

    // Use images from jar file
    QbReportDesigner.setUseSysResourceImages(true);

    designer = new QbReportDesigner(applet, "help/manual/code/templates/RDWithModifiedBars.rpt");

    // Add a new menu item
    JMenuBar menuBar = designer.getReportMenuBar();
    JMenu fileMenu = menuBar.getMenu(0);
    newItem = new JMenuItem("Hello World");
    newItem.addActionListener(this);
    fileMenu.insert(newItem, 7);

    // Remove toolbar buttons
    JToolBar designBar = designer.getDesignerToolBar();
    designBar.remove(5); // Remove Separator
    designBar.remove(4); // Remove Apply Template Button
    // Do not prompt to save the report if unsaved on exiting Designer
    designer.setSaveOnExitEnabled(false);

    designer.setVisible(true); 

}

public void actionPerformed(ActionEvent e) {

    /*** save report **********/
    designer.save("RDWithModifiedBars_Temp.rpt");

    /**** create new testing frame *********/
    JPanel contentPane = new JPanel();
    contentPane.setLayout(new BorderLayout());
    contentPane.add(new JLabel("Hello World!"), "Center");
    JFrame frame = new JFrame();
    frame.setContentPane(contentPane);
    frame.pack();
    frame.setVisible(true); 
} 

Note that the above code can be used as both an application and an applet.

2.3.5.7.11.9. Open Report Designer with Skipped Wizard Steps

You can open Report Designer with some of the Wizard steps skipped. Simply call the following functions to skip the query result, multiple data source, and pre-defined templates steps:

qbReportDesigner.setSkipQueryResultStep(true);
qbReportDesigner.setSkipMultiDataSourceStep(true);
qbReportDesigner.setSkipPredefinedTemplatesStep(true); 
2.3.5.7.11.10. Open Report Designer with Customized Messages and Chart Designer

You can open Report Designer with customized warnings when navigating between sub-reports and drill-down report. In addition, you can also override the default Save As behavior for the Report Designer. The following example demonstrates ways to alter these various components. The example has been broken down into fragments to make it easier to read. The full source code can be found at the end of this section.

public class RDWithCustomMessage {

    public static void main(String[] args) {
        try {
            startDesigner(); } catch (Exception ex) {
            ex.printStackTrace(); } }

    static void startDesigner() {
        // Connect to EspressManager
        QbReportDesigner.setServerAddress("127.0.0.1");
        QbReportDesigner.setServerPortNumber(22071);

        // Use images from jar file
        QbReportDesigner.setUseSysResourceImages(true);

        QbReportDesigner designer = new QbReportDesigner((Frame)null);
        // modify warning message before adding drill-down layer
        designer.modifyWarningMessage(QbReportDesigner.SAVE_RPT_BEFORE_DRILLDOWN,
             "The report designer will save the current report for you, continue?");

        // modify warning message before inserting Sub-Report
        designer.modifyWarningMessage(QbReportDesigner.SAVE_RPT_BEFORE_SUBREPORT,
             "The report designer will save the current report for you, continue?");

        // by pass save as dialog when submitting save location
        designer.setReportIO(new ReportIO(designer));

        // by pass save as dialog when user try to navigate to next level
        designer.setByPassSaveAsIO(new ByPassSaveAsForReport());

        // modify chart designer from report
        designer.setChartDesignerHandle(new ChartDesignerHandle());

        // REMOVE "SAVE AS" option for Report Designer
        JMenu fileMenu = designer.getReportMenuBar().getMenu(0);
        fileMenu.remove(6);
        designer.setVisible(true); } 

} 

The above portion of the code modifies the warning message that is shown when adding a sub-report or a drill-down level. It also calls setReportIO , setByPassSaveAsIO, and setChartDesignerHandle to by pass the Save As dialogs (details are discussed below). The code also removes the Save As option from the menu bar in Report Designer.

public static class ReportIO implements IReportIO {

    String fileName = null;
    QbReportDesigner designer = null;

    public ReportIO(QbReportDesigner designer) { this.designer = designer; }

    public void saveFile(byte[] data, String fileName) {
        System.out.println("SAVE REPORT FILE - " + fileName);
        try {
            FileOutputStream fout = new FileOutputStream(fileName);
            fout.write(data, 0, data.length); } catch (Exception ex) {
            ex.printStackTrace(); }
        this.fileName = fileName; } 

} 

The above fragment implements the IReportIO interface. By setting the ReportIO in the previous code fragment, Report Designer will call the saveFile method here when the user tries to save the report. The file is passed to this method as a byte array and the filename as a string. This method creates an output stream using the filename and writes the report byte array to that stream.

public static class ByPassSaveAsForReport implements IByPassSaveAsForReport {

    public ByPassSaveAsForReport() {};

    public String getFileName(String originalFileName) {
        System.out.println("BY PASS REPORT SAVE AS OPTION...");
        if (originalFileName == null) return "TEMP_REPORT_FILE.rpt";
        else return originalFileName; }

    public Properties getSaveAsProperties(String originalFileName) {
        return new Properties(); } 

} 

When you by pass the Save As option, the saveFile method from the previous code fragment will obtain the filename from the getFileName method in the above class. Here, we are simplifying the process by hardcoding the name of the file. Typically, you will want to manipulate the filenames so that users do not overwrite each other's files. The getSaveAsProperties method returns a Properties instance containing any save options. Possible options include: CREATE_STL, SAVE_ALL_DATA, CREATE_HTML, USE_SWINGVIEWER, CREATE_XML, CREATE_PACK, and USE_PAGEVIEWER. Here, we choose to not use any.

public static class ChartDesignerHandle implements IChartHandle {

    public ChartDesignerHandle() {};

    public void processDesigner(QbChartDesigner designer) {
        System.out.println("PROCESS CHART....");
        // REMOVE "SAVE AS" option for Chart Designer
        JMenu fileMenu = designer.getChartMenuBar().getMenu(0);
        fileMenu.remove(6);
        designer.setChartIO(new ChartIO());
        designer.setByPassSaveAsIO(new ByPassSaveAsForChart()); } 

}

public static class ChartIO implements IChartIO {

    public ChartIO() {};

    public String saveChartFile(byte[] data, String fileName) {
        System.out.println("SAVE CHART FILE - " + fileName);
        try {
            FileOutputStream fout = new FileOutputStream(fileName);
            fout.write(data, 0, data.length);
            fout.close(); } catch (Exception ex) {
            ex.printStackTrace(); }
        return fileName; } 

}

public static class ByPassSaveAsForChart implements IByPassSaveAsForChart {

    public ByPassSaveAsForChart() {};

    public String getFileName(String originalFileName) {
        System.out.println("BY PASS CHART SAVE AS OPTION...");
        if (originalFileName == null) return "TEMP_CHART_FILE.cht";
        else return originalFileName; }

    public Properties getSaveAsProperties(String originalFileName) {
        return new Properties(); } 

} 

The above three classes makes the same changes to the Chart Designer side. The ChartDesignerHandler class removes the Save As option from the menu bar. The ChartIO class saves the file given the filename and byte array. And the ByPassSaveAsForChart class sets a fixed filename for the chart.

2.3.5.7.12. Changing Report/Page Viewer Options

At times, you may want to configure what users can or cannot do when they are viewing the report using the Report Viewer or Page Viewer.

When the user is using the Viewers to view the report, right clicking on the report causes a menu to pop up. Using this menu, the user can navigate through different pages of the report, as well as perforM other tasks on the report, such as exporting it as a DHTML or PDF file. This can easily be done using the Report Viewer and Page Viewer APIs. However, these powerful features of the Report Viewer can be too complicated for the average user. Therefore, a few API methods have been introduced to control what options are available in the pop-up menu of the Report/Page Viewer.

These API calls are:

viewer.setMenuVisible(boolean b);
viewer.setPageMenuVisible(boolean b);
viewer.setPageMenuItemVisible(String[] items, boolean b);
viewer.setOutputMenuVisible(boolean b);
viewer.setOutputMenuItemVisible(String[] items, boolean b);
viewer.setRefreshMenuItemVisible(boolean b);
viewer.setGoToMenuItemVisible(boolean b);
viewer.setSortMenuVisible(boolean b); 

For more detailed information on these API methods, please consult the APIDocs

2.3.5.8. Javadoc

Javadoc for the entire API is provided along with EspressReport. The API covers both Report and Charting API. It is located at Quadbase website.

2.3.5.9. Swing Version

1.1 JFC/Swing versions of Report API are also available. For more details, please refer to quadbase.reportdesigner.ReportViewer.swing

2.3.5.10. Summary

The EspressReport API provides an easy-to-use, yet powerful application programming interface for business applications. Combined with Report Designer, programming is as simple as adding one line of code to your applet. All of the attributes of a report may be set in a template file, which can be created with the Report Designer. The EspressReport API has been tested with Netscape's Communicator (4.06 and above), Microsoft's Internet Explorer (4.x and above), and Sun's Appletviewer (1.2 and above) on the Windows 95, Windows NT/2000/XP, Solaris, Linux, AIX, and HP platforms.