Java Experiences

Friday, August 18, 2006

Java Printing

After days and days of working on the same 20 lines of code I finally managed to get printing support for FlexGantt up and running. Why did it take so long? Because printing is one of the worst documented features of Java. I was not able to find any books on the topic (O'Reilly where are you?) and even web searches were not fruitful. The pages that I did find would never cover more than the most basic features. But printing a Gantt chart is a non-trivial task and multi-page printing only makes it harder. Anyway, I did manage to get it all together. The snapshot below shows what it looks like now.

Some of the code needed for realizing this preview dialog is listed below. This is only the implementation of the Printable interface, which is implemented by the Gantt chart. The code renders the content of the individual pages, so for example a page in row 2 and column 3. The number of horizontal and vertical pages gets determined by two helper methods (getVerticalPages(), getHorizontalPages()).

public int print(Graphics g, PageFormat pageFormat, int pageIndex)
throws PrinterException {
int horizontalPages = getHorizontalPages();
int verticalPages = getVerticalPages();
int pageCount = horizontalPages * verticalPages;
if (pageIndex <> pageCount - 1) {
return NO_SUCH_PAGE;
}

Graphics2D g2d = (Graphics2D) g;

double iw = pageFormat.getImageableWidth();
double ih = pageFormat.getImageableHeight();
double ix = pageFormat.getImageableX();
double iy = pageFormat.getImageableY();

if (iw <= 0) {
throw new PrinterException("Width of printable area is too small.");
}
if (ih <= 0) {
throw new PrinterException("Height of printable area is too small.");
}

double sfWidth = iw / getWidth() * horizontalPages;
double sfHeight = ih / getHeight() * verticalPages;
double sf = Math.min(sfWidth, sfHeight);

//
// Store current transformation
//
AffineTransform oldTransform = g2d.getTransform();

//
// Print the Gantt chart.
//
int column = pageIndex % horizontalPages;
int row = pageIndex / horizontalPages;
int tx = column * (int) iw;
int ty = row * (int) ih;
g2d.translate(ix, iy);
g2d.translate(-tx, -ty);
if (previewDialog.isFillPage()) {
g2d.scale(sfWidth, sfHeight);
} else {
g2d.scale(sf, sf);
}
print(g2d);

//
// Restore old settings
//
g2d.setTransform(oldTransform);

return PAGE_EXISTS;
}

Java 5 Generics

I guess that the most prominent feature of Java 5 is Generics. I must admit that I love them. The type safety you gain outweighs the additional complexity by far. Most examples on the web show you how Generics are used in the context of Collections.

Another ideal application of Generics are policy providers, which store and return implementations of policy interfaces and the lookup of the implementation is done via the interface. Policies are used for customizing application behaviour. They are classes with small complexity and high specialization. A policy could for example be used to determine whether an object in a graphical editor supports drag & drop. Additionally the policy could return the correct command object to perform the necessary changes after a drop event.

The code below uses Generics to define the interface of a policy provider that ensures type safety. Type safety in this case means, that it is not possible to register an implementation for a policy if the implementation does not implement the policy interface.

public interface IPolicyProvider {

/**
* Registers a policy implementation for the given policy type (policy
* interface).
*/
public void setPolicy(Class<T> policyType, T policyImpl);

/**
* Registers a policy implementation for the given policy type (policy
* interface) and object type / context.
*/
public void setPolicy(Class
<T> policyType, Class objectType, T policyImpl);

/**
* Returns a policy implementation for the given policy type (policy
* interface).
*/
public T getPolicy(Class
<T> policyType);

/**
* Returns a policy implementation for the given policy type (policy
* interface) and object type / context.
*/
public T getPolicy(Class
<T> policyType, Class objectType);

}

Java 5

I had the pleasure of switching to Java 5 a couple of months ago. Due to various technical restrictions I could neither switch to it for my consulting job nor for the DJT Gantt chart development. I initially planned to use Java 2 (1.4.2) for the next-gen Gantt chart FlexGantt so that its market potential is larger.

I started using Java 5 "by accident" because I forgot to configure my Eclipse IDE correctly. I had Java 5 installed on my machine but didn't change the Eclipse settings in such a way that it would use the Java 1.4 compatability mode. I ended up using Drag & Drop API that wasn't available in Java 2. Once I noticed my mistake I didn't feel like switching back anymore because I liked what I could do with Java 5. I then looked into all the other features of Java 5 and decided to not go back anymore. I never regreted that decision.

Finally!

I think it has been years already since I setup this blog so that I could publish interesting observations and experiences I made while working with Java, but I either never had the time to post anything or when I did have the time I just didn't run into anything that I thought would be of interest to anyone else (or I couldn't remember it, after all it is the computer's job to replace my long term memory).

So what changed? I guess it is the amount of interesting work that I am doing right now that made sure I would remember some of it. My work is currently split up into two items.

The first one, which takes up around 60% of my time, is my consulting job for a company called Qnamic in Switzerland. They developed a railroad scheduling application that can be extremely well tailored to individual customer requirements. It is my job at Qnamic to develop a rich client application (RCA) based on the Eclipse Rich Client Platform (RCP) that is equally customizable.

The second item is my work on FlexGantt, which is a Swing-based library for creating Gantt charts. FlexGantt will be the successor to the very successful DJT library, which I had developed between 1996 and1999 when I worked inside the Intelligent Coordinaten and Logistics Laboratory (ICLL) at the Robotics Institute (RI) at Carnegie Mellon (CMU) in Pittsburgh.

These two tasks constantly produce interesting experiences with Java and I hope that I will find the time from now on to write about it. Any feedback from your side is more than welcome.