IBM® Rational® ProjectConsole, part of the IBM Rational Team Unifying Platform, is a Web-based project management tool that automates reporting on project status and progress. It gathers data from a variety of sources and automatically generates HTML reports containing charts that display trends or distributions. Its interactive Dashboard lets users create charts for inclusion in the HTML reports and dynamically analyze these charts through drill-downs. When creating graphs, however, a default font is used for all chart labels and axis. While this suits the need of most users, some may need a different font to emphasize certain trends or simply to conform to the culture or standard of one's company.
Consider being assigned the task of creating charts that really grab the attention of the audience, say in a marketing department. The defaults for the ProjectConsole Dashboard are ideal for progress charting but sometimes a sales pitch requires something less professional and more appealing.
Figure 1. The standard graph
The growth shown on Figure 1 is, in this scenario, a positive trend of the progress of the report. The goal of this article is to illustrate how to change the text of this chart to suit your needs.
First and foremost, you will need a Java 2 SDK installed on your system. The author used the Sun distribution of Java 2 SDK, SE v1.4.2_07 on Windows XP Professional, but you may use another version as long as you have a Java compiler available (javac) and the Java Archive application (JAR). After installing a version of Java 2 SDK, it is important to check that the executables are in the PATH environment variable. To do this, right-click on the My Computer icon and select Properties. On the Advanced tab of the System Properties dialog box, click Environment Variables. Under System variables, verify that the path to the Java 2 SDK is present. The actual directory will vary with the different versions of Java 2 SDK. Figure 2 shows the directory in the PATH environment variable on the author's system.
Figure 2. The PATH environment variable
At this point, you should perform a quick test. Open the Microsoft Windows Command Prompt and issue the command javac without any parameters. If successful, issue the command jar without any parameters. If either of the commands return an error indicating that the executable could not be found, there are two possible causes: Either an incorrect PATH environment variable or missing executables. If the PATH is incorrectly set, you can manually correct it in the dialog box shown in Figure 2. If you cannot find the Java 2 SDK executables, download them once more and reinstall them.
The generation of the graphs on the Dashboard is done through two JAR files. One is called analyzer.jar and the other is publisher.jar, analyzer.jar handles how the graphs are displayed within the Dashboard while publisher.jar handles the publication of graphs to other supported file formats (like PNG, PCL, PS, etc.). Both of these JARs contain a Java class called Chart. Full description of this class is listed in the next section. It is important to only make the suggested changes as described or the Dashboard will not work properly. Depending on your particular needs you may only need to modify one of the two JAR files. For instance, if in your implementation of the ProjectConsole, you only use the Dashboard to generate the graphs and these are never published to other formats, you may only want to modify the analyzer.jar file. In this case, it is not worth the additional effort to also modify the publisher.jar file. Note that if that is what you decide to do, subsequent publish actions from the graphs will result in files with the original default font.
There is an additional file that will be needed but not modified. It is called klg45.jar but we only need to reference it at compile time. It is recommended to create a directory at the root level to store these JAR files while we modify them. Once we are done, we can place our modified files at the original location (though they must have the same name, of course). The author created a folder titled "PjC" at the root level, which is where the three JAR files are stored. The analyzer.jar and klg45.jar are both located at <Install_Dir>\Common\rwp\webapps\projectconsole\pjc while publisher.jar is located at <Install_Dir>\ProjectConsole\bin. <Install_Dir> is C:\Program Files\Rational by default. Once these three files are in the same location, another environment variable must be modified, CLASSPATH. We'll have to append the full path and filename of these JARs to the end of the present value of this environment variable. This is to ensure that all classes can find one another at compile time. In this example, the directory is C:\PjC so we will append C:\PjC\klg45.jar;C:\PjC\analyzer.jar;C:\PjC\publisher.jar Figure 3 displays this modification.
Figure 3. The CLASSPATH environment variable
Before we decide what font to use, we need to determine what fonts we have available. As expected, well-known fonts Times New Roman, Courier New and Helvetica could be used, but what other fonts are available? It is fairly easy to get a complete list so you may choose one that is more to your liking. To obtain a list of the available fonts, we can run a simple Java program and use the output to choose the font name. This code is presented for a good reason, if you have a different version of Java SDK, your output may vary. The Java program here is aptly named FontNames and is presented in Listing 1, below.
Listing 1. The FontNames program
import java.awt.Font;
import java.awt.GraphicsEnvironment;
class FontNames {
public static void main(String args[]){
String[] fontNames =
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (int i = 0; i < fontNames.length; i++)
{
System.out.println(fontNames[i]);
}
}
}
|
To run this program, it must first be compiled. Save this text to a file called FontNames.java Be sure to include all characters as they appear, especially the soft brackets, or the program will not compile. Open the Command Prompt and change to the directory that contains this file. Then issue the command javac FontNames.java. As a result, a file called FontNames.class should appear. We are now ready to run the command java FontNames. Note that we are running the java command with the parameter <FontNames> and not <FontNames.class>. Listing 2 displays the output received by the author. Again, depending on which version of Java SDK you use, other fonts may be available.
Listing 2. The FontNames output
Arial Arial Black Arial Narrow Baskerville Batang BatangChe Binner Gothic Book Antiqua Bookman Old Style Botanical Brush Script Centaur Century Century Gothic Comic Sans MS Courier New Default Dialog DialogInput Dotum DotumChe Estrangelo Edessa Franklin Gothic Medium Garamond Gautami Georgia Gill Sans Gill Sans Condensed Gill Sans Ultra Bold Gulim GulimChe Gungsuh GungsuhChe Haettenschweiler Impact Latha Letter Gothic Lotus Postal Barcode LotusWP Box LotusWP Icon LotusWP Int A LotusWP Int B LotusWP Type Lucida Bright Lucida Console Lucida Sans Lucida Sans Typewriter Lucida Sans Unicode Lydian Mangal Map Symbols MapInfo Cartographic Marlett Math A Math B Math C Microsoft Sans Serif MingLiU Monospaced Monotype Corsiva Monotype Sorts MS Gothic MS Mincho MS Outlook MS PGothic MS PMincho MS UI Gothic MV Boli News Gothic News Gothic Condensed Nimrod NSimSun Onyx Palatino Linotype Perpetua Photina Casual Black PMingLiU Raavi Rockwell Rockwell Condensed Rockwell Light SansSerif Serif Shruti SimHei SimSun Sylfaen Symbol Tahoma Times New Roman Trebuchet MS Tunga Verdana Webdings Wingdings Wingdings 2 Wingdings 3 |
Beside the well-known fonts mentioned before, we also have personal favorites such as Impact, Nimrod, and Onyx. In the examples following, the Impact font will be used.
We can now look at the code that defines the Chart class that controls the charts that are displayed in the Dashboard. Listing 3 displays the Chart class definition.
Listing 3. The Chart class definition
package com.rational.dashboard.thirdpartycontrols;
import com.klg.jclass.chart.ChartDataModel;
import com.klg.jclass.chart.ChartDataView;
import com.klg.jclass.chart.ChartDataViewSeries;
import com.klg.jclass.chart.ChartText;
import com.klg.jclass.chart.EventTrigger;
import com.klg.jclass.chart.JCAxis;
import com.klg.jclass.chart.JCAxisTitle;
import com.klg.jclass.chart.JCChart;
import com.klg.jclass.chart.JCChartArea;
import com.klg.jclass.chart.JCChartStyle;
import com.klg.jclass.chart.JCDataIndex;
import com.klg.jclass.chart.JCPickEvent;
import com.klg.jclass.chart.JCPickListener;
import com.rational.dashboard.utilities.ColorUtil;
import java.awt.Color;
import java.util.Iterator;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.border.BevelBorder;
public class Chart extends JCChart
{
class SymPick
implements JCPickListener
{
public void pick(JCPickEvent jcpickevent)
{
JCDataIndex jcdataindex = jcpickevent.getPickResult();
boolean flag = false;
if(jcdataindex != null)
{
Object obj = jcdataindex.getObject();
ChartDataView chartdataview = jcdataindex.getDataView();
int i = jcdataindex.getSeriesIndex();
int j = jcdataindex.getPoint();
if(chartdataview != null && (obj instanceof JCChartArea))
{
String s = chartdataview.getPointLabel(j);
setPickedValue(s);
} else
{
setPickedValue(null);
}
}
}
SymPick()
{
}
}
public Chart()
{
mShowValueLabels = false;
colors = (new Color[] {
ColorUtil.BLUE, ColorUtil.RED, ColorUtil.YELLOW, ColorUtil.ORANGE, ColorUtil.MAGENTA,
ColorUtil.GREEN, ColorUtil.CYAN, ColorUtil.BLACK, ColorUtil.PINK, ColorUtil.AQUAMARINE,
ColorUtil.BEIGE, ColorUtil.DARK_TURQUOISE, ColorUtil.NAVY_BLUE, ColorUtil.ROSY_BROWN,
ColorUtil.BLANCHED_ALMOND, ColorUtil.SANDYBROWN, ColorUtil.DARK_GREEN,
ColorUtil.DARK_ORANGE, ColorUtil.MEDIUM_PURPLE, ColorUtil.ALICE_BLUE,
ColorUtil.DODGER_BLUE, ColorUtil.DARK_TURQUOISE, ColorUtil.THISTLE, ColorUtil.PLUM,
ColorUtil.HOT_PINK, ColorUtil.TOMATO, ColorUtil.BISQUE, ColorUtil.MIDNIGHT_BLUE,
ColorUtil.DARK_GOLDENROD, ColorUtil.SEA_GREEN, ColorUtil.BURLYWOOD, ColorUtil.VIOLET,
ColorUtil.PALE_VIOLET_RED, ColorUtil.SALMON, ColorUtil.PURPLE, ColorUtil.OLIVE_GREEN,
ColorUtil.ALICE_BLUE, ColorUtil.CHOCOLATE, ColorUtil.LIGHT_YELLOW, ColorUtil.LAVENDER_BLUSH
});
SymPick sympick = new SymPick();
addPickListener(sympick);
((JLabel)getHeader()).setText("Untitled");
getLegend().setVisible(true);
getDataView(0).setAutoLabel(true);
getDataView(0).setPickFocus(1);
setTrigger(0, new EventTrigger(0, 4));
setTrigger(0, new EventTrigger(4, 4));
setFillColorIndex(2);
setLineColorIndex(2);
setSymbolColorIndex(2);
getLegend().setBorder(new BevelBorder(0));
getChartArea().setBorder(new BevelBorder(0));
}
public void setPickedValue(String s)
{
mszPickedValue = s;
}
public String getPickedValue()
{
return mszPickedValue;
}
public int getPickedIndex(String s)
{
if(s != null)
{
java.util.List list = mChartDataView.getPointLabels();
Iterator iterator = list.iterator();
for(int i = 0; iterator.hasNext(); i++)
{
String s1 = (String)iterator.next();
if(s1.equals(s))
return i;
}
return -1;
} else
{
return -1;
}
}
public void setModel(ChartDataModel chartdatamodel)
{
mChartDataView = addDataView(0);
mChartDataView.setDataSource(chartdatamodel);
mChartDataView.setAutoLabel(true);
getDataView(0).setPickFocus(1);
mChartDataView.getYAxis().getTitle().setPlacement(2);
mChartDataView.getYAxis().getTitle().setRotation(1);
mChartDataView.setHoleValue(0.0D);
setSeriesColor();
}
public boolean getShowValueLabelsStatus()
{
return mShowValueLabels;
}
public void setShowValueLabelsStatus(boolean flag)
{
mShowValueLabels = flag;
}
public void setSeriesColor()
{
if(mChartDataView != null)
{
if(mChartDataView.getNumSeries() > 0)
{
java.util.List list = mChartDataView.getSeries();
Iterator iterator = list.iterator();
int i = 0;
for(int j = colors.length; iterator.hasNext() && i < j; i++)
{
ChartDataViewSeries chartdataviewseries = (ChartDataViewSeries)iterator.next();
chartdataviewseries.getStyle().setFillColor(colors[i]);
chartdataviewseries.getStyle().setLineColor(colors[i]);
chartdataviewseries.getStyle().setSymbolColor(colors[i]);
}
}
setBatched(false);
update();
}
}
boolean mShowValueLabels;
Color colors[];
protected ChartDataView mChartDataView;
protected String mszPickedValue;
}
|
The easiest way to get started is to copy the entire text of Listing 3 into a text file and save it as Chart.java. The suggested place to keep these files is the same directory where the three JAR files are stored. All commands given in this procedure assume this location C:\PjC is the directory. There are only two lines that must be inserted to get the effect we desire. One is in the import section. We need to include the following: import java.awt.Font; A good place to put it is after the import java.awt.Color; line. The other line is in the public constructor of the Chart class. The line is of the form setFont(new Font("<Name of Font>",Font.<Style>,<Size>)); where <Name of Font> is one of the names in the FontNames output, <Style> is either PLAIN, BOLD, ITALIC, or BOLD+ITALIC and <Size> is an integer. In our example, the line I will insert is setFont(new Font("Impact", Font.PLAIN, 10)); A good place to insert it is before the line setFillColorIndex(2);
In order for the modified JARs to function as the originals, certain information must be added to the manifest file of each file. Specifically, we will need to create two text files with certain information so different components of the ProjectConsole can continue to communicate correctly. In the directory that contains the three JAR files as well as your modified Java files, create a text file called "manifest.analyzer" consisting only of the following line:
Main-Class: com.rational.dashboard.analyzer.AnalyzerMain |
Then, create another text file, "manifest.publisher" consisting of the following lines:
Main-Class: com.rational.dashboard.displayserver.publisher.Publisher Class-Path: ..\\Classes\\klg45.jar |
Once all changes are made, the classes can be once more compiled. The best way to do this is to start the Command Prompt and change the directory to the location of the JARs and the created directory structure ("C:\PjC" in the example given). It is then a simple matter of compiling the classes with the javac executable. The most important thing to note is that compiling the Chart.java file will result in two class files, since Chart contains an inner class. The command to compile the Chart.java class is javac Chart.java As a result of this command, two class files are created, Chart.class and Chart$SymPick.class Though we made no changes to the SymPick inner class, we will update the JAR files with this file also. Remember that you may only want to update analyzer.jar if you only use the Dashboard to display graphs. This example assumes graphs are published to PNG files for inclusion in ProjectConsole Web reports. To update the contents of the analyzer JAR, we must first extract its contents with this command: jar xvf analyzer.jar. This will take a few seconds and will create several directories and files under the present directory, including "com", "sun", "images", "netscape", and "symantec". We should now copy the compiled Chart.class and Chart$SymPick.class files to the location of the original files with this command: copy /Y Chart*.class com\rational\dashboard\thirdpartycontrols
Next, we can delete the now obsolete analyzer.jar with del analyzer.jar
We can now recreate the analyzer.jar file so it has the new font definitions with the command: jar cvfm analyzer.jar manifest.analyzer com images netscape sun symantec Finally, we can delete the directories of analyzer.jar, since some of the same directory names are used by publisher.jar. That command is:
rmdir /q /s com netscape images sun symantec To update the publisher.jar file, the series of commands is:
jar xvf publisher.jar copy /Y Chart*.class com\rational\dashboard\thirdpartycontrols del publisher.jar jar cvfm publisher.jar manifest.publisher com images netscape sun rmdir /q /s com images netscape sun |
The JAR files are now updated with all of the necessary changes. Before copying the files to the original location, check one more time that you have a backup copy of each JAR file. I cannot stress enough the importance of this since we are making multiple changes and it is much faster to restore the original files than to try to roll back each change. Once you have verified that your backup copies are safely stored somewhere, you may copy analyzer.jar to <Install_Dir>\Common\rwp\webapps\projectconsole\pjc and publisher.jar to <Install_Dir>\ProjectConsole\bin where <Install_Dir> is C:\Program Files\Rational by default. Note that making changes to the installed ProjectConsole files isn't supported, so keep the files in an accessible location should you ever need to restore them. In addition, if you install a new Service Release, you will need to recreate your changes so save your java source files.
Before the changes can take effect, it is necessary to stop six Windows services, then start them again. These are: 1) Rational ProjectConsole Collection Server, 2) Rational ProjectConsole Dashboard Server, 3) Rational ProjectConsole Report Server, 4) Rational Web Platform, HTTP server, 5) Rational Web Platform, servlet engine, and 6) Rational Web Platform, ReqWeb servlet engine.
You may need to clear your browser's cache since the now obsolete Java archive files may still be stored there.
Finally, you can do some cleanup. Delete the directory you used to hold the three JAR files ("C:\PjC", in this example). You can also remove the entries from the CLASSPATH environment variable.
The graphs you have previously created and future graphs will have the font you selected. The legend also has the same font. Since this is a small and easy change, you can experiment with different fonts, styles and sizes until you find the one that best suits your needs.
- Participate in the discussion forum.
- Share your questions and views on this article with the author and
other readers in the Rational discussion forum.
- To learn more about ProjectConsole, visit the developerWorks ProjectConsole
zone. You'll find technical documentation, how-to articles,
education, downloads, product information, and more.
- Learn about the IBM Software Development Platform and why Rational products are an important component of it..
- Browse for books on these and other technical topics.
Comments (Undergoing maintenance)






