Articles
Application Development Framework
by Lucas Jellema 
Help your end-users digest information by implementing cell highlighting in your JavaServer Faces app.
Published November 2008
Data-oriented applications tend to swamp the end user with information. Rows and rows of data, although neatly organized in columns and cells, can be somewhat overwhelming. The significance of certain data records can frequently be made clearer by color highlighting cells. Different colors indicate different statuses for the records. The colors can make records that deserve special attention for whatever reason clearly stand out.
Tools such as Oracle Discoverer, Microsoft Excel, and Oracle Application Express provide facilities that allow the end user to specify filter criteria, which are then used for the color highlighting. This includes, for example, threshold highlighting where various value ranges are identified by specific colors: salaries less than 2000, between 2000 and 3000, and greater than 3000 have their own color assigned. Another type of highlighting is based on filter expressions: expressions such as JOB <> 'MANAGER and SAL > 3000 or JOB = 'CLERK' or SAL < 1500. Every filter expression can be associated with a color.
In this first in a series of two articles, you will see how such highlighting can be implemented in a JavaServer Faces (JSF) application, more specifically in Oracle Application Development Framework (ADF) Faces table components. You will learn, using Oracle ADF 11g Rich Faces as the JSF implementation, how to add user-controlled threshold or traffic light highlighting. The user specifies for each column that supports highlighting the threshold values as well as the colors to be used. Such settings are retained when requerying data and sorting the records. When data is changed, the highlighting is adjusted accordingly.
The second article in the series adds even more power for the end user: it describes how to add end-user functionality to dynamically add, update, and remove thresholds—supporting up to as many thresholds as could possibly be desired. It then goes beyond the simple threshold pattern to also provide expression-based filtering. The end user can set up one or multiple expressions that can refer to all attributes in the data records. The first expression a record satisfies will determine the color for the cell.
You will use a simple Oracle ADF Faces table page in this article. You can easily create it yourself, or download the ZIP file with the start situation. The latter approach has the advantage of not needing a database from which to retrieve the data.
Start Oracle JDeveloper. Create a new application using the Create Application dialog that you start by selecting File, New and selecting the Application item under category General. Choose the Web Application (JSF, ADF BC) template. The wizard will automatically create a Model and a ViewController project.
From the New Gallery, select the option (Business Tier, ADF Business Components) Business Components from Tables. Select, and if necessary first create, a database connection to the SCOTT schema in some database. Create an Entity Object Emp for table EMP and a default ViewObject EmpView for the Emp Entity. Call the application module HrmManager.
The default datatype used in Oracle ADF Business Components for columns with datatype NUMBER is oracle.jbo.domain.Number. This highly flexible, functionally rich type is not recognized by the EL engine in JSF. We therefore go to edit the Emp Entity Object and change the Type for the Sal attribute from Number to Double. Do the same thing for the Comm attribute. Finally, set the Deptno attribute's type to Integer.
When you look at the Data Control palette, you will see the EmpView collection in the HrmManager data control—exactly what we need to get started with your Web application.
Somewhat easier and equally instructive is to approach cell highlighting using the provided Oracle JDeveloper Application ADFCellHighlighting_StartingPoint. It contains a Model and ViewController project. The latter is empty; the former contains three classes: HrmManager, EmpManager (a singleton), and Emp. The Emp and EmpManager classes have been generated from the EMP table to produce an offline (no database) datasource. This blog entry explains in detail how this is done and also provides the code for generating such disconnected datasources from database tables.
The HrmManager class has been published as a DataControl. As a result, the empscollection is available on the Data Control palette.
Let's first create the JSF page to which weyouare going to apply cell highlighting. In the ViewController project, select (Web Tier, JSF) JSF JSP in the New Gallery. Call the new file EmpTable.jspx and click Finish.
An empty page is now displayed in the page editor. From the Data Control palette, drag either the EmpView collection (based on ADF BC and database) or the emps collection (under empManager, based on disconnected beans) and drop it as an ADF Table. In the Edit Table Columns dialog, specify the column order and prompt definitions seen in the following figure and enable sorting:
Figure 1 Edit Table Columns dialog
Click OK. The page editor displays. From the right mouse button menu, select Go to Page Definition. Change the rangeSize attribute on the EmpView iterator (ADF BC based) or the empsIterator accessorIterator (bean based) from 10 to -1 (in order to have all records displayed in the page).
Select Run from the right mouse button menu to see the page in action. At this point, you should see this page running in your browser. (Note: you might need to fiddle with the columns attribute for some of the inputText elements to get the proper width for all columns.):
Figure 2 Page with all records displayed
Your first step will be to add static cell highlighting to the EmpTable page. Focus on Salary cells. To quickly get insight into the distribution of salaries, you want to highlight salaries less than 1000 in green, greater than 3000 in red, and the others in light gray.
The easiest way of assigning colors to cells is through the contentStyle attribute on the inputText Sal element as follows:
contentStyle="background-color:#{(row.sal lt 1000)?'green':(row.sal gt 3000?'red':'lightgray')};"
Using a ternary expression inside the EL expression used for setting the CSS property background color, now specify that when row.sal—the value displayed in the current cell—is less than 1000, the expression should evaluate to green. Otherwise, the result should be the outcome of the nested expression that tests whether row.sal is greater than 3000. If it is, the result is red, or else the outcome is light gray.
Figure 3 Salary value highlighting
If you based your Data Control on the EmpView collection, rather than on the offline HrmManager bean, you need to change row.sal to row.Sal—with a capital S.
You can run the page and see the highlighting for the salaries. If you change salary values and then sort by clicking any column header, you will see the highlighting adjusted to the updated values:
Figure 4 Adjustments to the Salary values
The first step provided cell highlighting. However, the highlighting is very static—based on the hard-coded values 1000 and 3000 somewhere in the JSF page. Clearly not the most dynamic way to go about it. Let's replace those hard-coded threshold values with references to managed bean properties, which you can then allow our end user to manipulate.
First of all, change the contentStyle attribute in the inputText for Sal to
contentStyle="background-color:#{(row.Sal lt EmpThresholdHighlighter.lowThreshold)
?EmpThresholdHighlighter.lowAreaColor:
(( row.Sal gt EmpThresholdHighlighter.highThreshold)
?EmpThresholdHighlighter.highAreaColor:EmpThresholdHighlighter.middleAreaColor)};"
Note: Use row.sal (lowercase S) when you are using a bean based data control.
You will notice that you have not only replaced the hard-coded threshold values with bean references, but you did the same for the colors. Instead of red and green, the expression now refers to EmpThresholdHighlighter.lowAreaColor and EmpThresholdHighlighter.highAreaColor.
The managed bean EmpThresholdHighlighter is configured in the adfc config.xml like this:
<managed-bean>
<managed-bean-name>EmpThresholdHighlighter</managed-bean-name>
<managed-bean-class>otn.cellhighlighting.jsf.ThreshholdHighlightBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
package otn.cellhighlighting.jsf;
public class ThreshholdHighlightBean {
private Long lowThreshold = new Long(1000);
private Long highThreshold = new Long(3000);
private String lowAreaColor ="green";
private String middleAreaColor ="lightgray";
private String highAreaColor ="red";
public ThreshholdHighlightBean() {
}
... accessor methods (getters and setters) for all properties
}
You need to add a panel to the page where the user can specify these values. Add the following showDetailHeader to the page, inserting it just below the table:
<af:showDetailHeader text="Highlight Settings for Employees Table"
disclosed="true"
inlineStyle="border-color:Gray; border-style:double; width:367px;">
<af:panelFormLayout>
<af:inputText label="Lower Threshold"
value="#{EmpThresholdHighlighter.lowThreshold}"/>
<af:inputText label="High Threshold"
value="#{EmpThresholdHighlighter.highThreshold}"/>
<af:objectSpacer width="10" height="10"/>
<af:inputText label="Low Area Color"
value="#{EmpThresholdHighlighter.lowAreaColor}"/>
<af:inputText label="Medium Area Color"
value="#{EmpThresholdHighlighter.middleAreaColor}"/>
<af:inputText label="High Area Color"
value="#{EmpThresholdHighlighter.highAreaColor}"/>
</af:panelForm>
</af:panelHeader>
<af:commandButton text="Apply Highlighting" partialSubmit="true"
id="doHighlight"/>
</af:showDetailHeader>
The commandButton doHighlight has the partialSubmit attribute set to "true". When the button is clicked, the settings in this panel are to be applied immediately. A partial page refresh can update the highlight settings in the table, if the table responds to the button press. That is the case when you add the button's ID to the partialTriggers attribute of the table:
<af:table value="#{bindings.EmpManageremps.collectionModel}" var="row"
partialTriggers="doHighlight"
...
Now when you run the page, you can manipulate the threshold settings as well as the colors associated with the three areas: low, medium, and high.
Figure 5 Manipulating threshold settings and colors
It seems somewhat strange to set the color by typing in the color name as specified in CSS terms, especially when Oracle ADF Faces has a color picker component. So let's now use that component for setting the colors in a more user-friendly way.
The value set by the color picker component is of type java.awt.Color. You need to modify the ThreshholdHighlightBean to cater to this. First, remove the existing color properties—lowAreaColor, middleAreaColor, highAreaColor—and their setter methods.
Then add these properties and generate their associated accessors:
private Color lowColor = new Color(153, 255, 153); // greenish
private Color middleColor = new Color(255, 255, 150); // yellow
private Color highColor = new Color(255, 190, 190); // red
public String getLowAreaColor() {
return this.lowAreaColor == null ? "" :
"rgb(" + this.lowColor.getRed() + "," +
this.lowColor.getGreen() + "," +
this.lowColor.getBlue() + ")";
}
<af:panelLabelAndMessage label="Low Area Color">
<af:inputColor id="lowAreaColor" chooseId="chooseLow"
value="#{EmpThresholdHighlighter.lowColor}"
compact="true"/>
<af:chooseColor id="chooseLow" defaultVisible="false"
lastUsedVisible="false"/>
</af:panelLabelAndMessage>
Now also add the color pickers for Medium Area Color and High Area Color. You could somewhat reorganize the Highlight Settings panel to cater for the size of the Choose Color components. One way of doing that is through the use of \ .
<af:panelGroupLayout layout="horizontal" valign="top">
<af:panelFormLayout rows="2">
... the two inputText elements ...
</af:panelFormLayout>
the three panelLabelAndMessage components with the inputColor & chooseColor
</af:panelGroupLayout>
Figure 6 Color picker panel
It is undeniably convenient for end users to be able to set up cell highlighting in their tables. However, the panel for highlighting settings takes up an awful lot of real estate on the page—and that is just for a single column. At the very least, we would like to be able to only bring up this panel when you need to inspect it or make changes to it, and have it otherwise not take up so much space. In this last step, you will introduce a pop-up panel that can be invoked from the Sal column header. This also prepares the way for cell highlighting for multiple columns. Multicolumn highlighting is a topic for the second part of this series, along with expression-based highlighting.
ADF 11g Rich Faces, among many other interesting things, gives us a real popup component. We will use this component to contain the cell highlighting controls in a panelWindow that is only displayed when explicitly invoked.
We add an icon to the Salary column header that can be clicked to bring up the popup. To achieve this, remove the headerText attribute on the column, add the header facet inside the column, and configure its contents as follows:
<af:column sortProperty="sal" sortable="true">
<f:facet name="header">
<af:panelGroupLayout layout="horizontal">
<af:outputText value="#{bindings.emps.hints.sal.label}"/>
<af:image shortDesc="Open Cell Highlight Settings Window"
source="/highlightIcon.gif">
<af:showPopupBehavior popupId=":CellHighlightThresholdSettings"
triggerType="click"/>
</af:image>
</af:panelGroupLayout>
</f:facet>
<af:popup id="CellHighlightThresholdSettings">
<af:panelWindow title="Highlight Settings for Employees Table">
... same contents as before
</af:panelWindow>
</af:popup>
When you now run the page, it will look like a very ordinary table page, except for the little icon in the Sal column header:
Figure 7 "Highlight" icon in Sal column header
Move the mouse over the highlight icon, and now the highlight settings panel will appear:
Figure 8 Highlight settings panel
The user can make the desired changes, and then click Apply Highlighting to make the table redisplay with all changes applied.
In this first of a two-part series on Oracle ADF cell highlighting, you have seen how we can rapidly add static highlighting to Oracle ADF Faces data tables. Using EL expressions, getting the highlighting to work was easy. You then extended the functionality with more end-user control: backed by a managed bean we made both the threshold values and the associated colors dynamic and provided the user with a panel to manipulate those settings. In the last step, you embedded this panel in the column itself. The panel will now only be displayed when the user needs it, making for a much better usable user interface.
Part 2 extends the highlight functionality in several ways. You will add support for multicolumn highlighting in the same table, enabling the Hiredate column to be highlighted based on experience (green being less experienced obviously) and the Salary column indicating the income category for the employee. You will also allow for dynamic threshold definitions: users can add as many thresholds as they see fit, instead of the two supported in this installment. Finally, and most interestingly, is the addition of expression-based highlighting. Cells can be highlighted based on formulas that can refer to all attributes in a record (even nondisplayed ones).
Read Part 2 of this series