Montag, 14. September 2009

DragImagePainter or Getting Around isDragImageSupported() on Windows

Last week I had an interesting conversation with a project manager at a meeting of the Scrum User Group in Dresden. He asked me why so many common tasks need to be reprogrammed in every project. I tried to answer that question and argued that things need to be implemented in a different way for different purposes... But today I came to the conclusion the he's right. Reimplementing common tasks is expensive and it happens too often. "The customer wants to relayout some components on the fly using Drag and Drop. While dragging a small drag image of the dragged component should be visible near the mouse pointer." - Sounds like a common use case to me. But Drag and Drop (DnD) in Swing does not support this. Of course Swing supports Drag and Drop out of the box - but only for a small amount of components. I don't know why this feature is missing in a framework which is in use since a decade. On my way implementing this feature I stumble upon the method isDragImageSupported() of the class java.awt.dnd.DragSource. Windows does not support adding a DragImage to the mouse pointer. Google told me to look at Geertjan's Blog. He wrote a nice and informative article how to implement this feature. Nicely done! But doing it the way he did means doing it again and again and the poor customer needs to pay for this :) As I want customers of IT companies to be happy I tried to save the world. First of all I called my brother in arms rosh. With combined holy hand grenades we wrote a kewl class called DragImagePainter. It needs to be instantiated in the java.awt.dnd.DragSourceListener. In method dragOver of the java.awt.dnd.DragSourceListener a call to the function paintDragImage will do the magic. Feel free to use AND REUSE the following piece of code:
/**
* Utility class for painting a scaled and opaque image representation of a
* dragged component while it's being dragged.
*
* @author Richi
*
*/
public class DragImagePainter {
private final AlphaComposite ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
private final JComponent rootComponent;
private final JComponent draggableComponent;
private final int offsetY;
private final int imageWidth;

private Point lastKnownCursorPosition;

/**
 * @param rootComponent
 *            the root component of the current window
 * @param draggableComponent
 *            the component which is going to be dragged
 */
public DragImagePainter(JComponent rootComponent, JComponent draggableComponent) {
 this.rootComponent = rootComponent;
 this.draggableComponent = draggableComponent;
 this.offsetY = -15;
 this.imageWidth = 50;
}

/**
 * Paints a scaled and opaque image representation of the draggableComponent
 * provided in the constructor near the current mouse pointer position.
 *
 * @param currentCursorPositionX
 * @param currentCursorPositionY
 */
public void handleDragOver(int currentCursorPositionX, int currentCursorPositionY) {
 boolean imagePositionChanged = imagePositionChanged(currentCursorPositionX, currentCursorPositionY);
 if (imagePositionChanged) {
  double scaleFactor = calculateScaleFactor();
  int imageHeight = calculateImageHeight(scaleFactor);
  if (!isFirstRun())
   repaintLastKnownImageArea(imageHeight);
  Graphics2D rootComponentGraphics = (Graphics2D) rootComponent.getGraphics();
  paintDragImage(currentCursorPositionX, currentCursorPositionY, scaleFactor, rootComponentGraphics);
  lastKnownCursorPosition = new Point(currentCursorPositionX, currentCursorPositionY);
 }
}

/**
 * Needs to be called on {@link DragSourceListener}.dragEnd() to repaint the
 * area of the last painted drag image
 */
public void handleDropEnd() {
 double scaleFactor = calculateScaleFactor();
 int imageHeight = calculateImageHeight(scaleFactor);
 repaintLastKnownImageArea(imageHeight);
}

double calculateScaleFactor() {
 return (double) imageWidth / draggableComponent.getWidth();
}

private int calculateImageHeight(double scaleFactor) {
 return (int) Math.ceil(draggableComponent.getHeight() * scaleFactor);
}

boolean imagePositionChanged(int currentCursorPositionX, int currentCursorPositionY) {
 return isFirstRun() || lastKnownCursorPosition.x != currentCursorPositionX
   || lastKnownCursorPosition.y != currentCursorPositionY;
}

void repaintLastKnownImageArea(int height) {
 rootComponent.paintImmediately(lastKnownCursorPosition.x, lastKnownCursorPosition.y + offsetY, imageWidth,
   height);
}

boolean isFirstRun() {
 return lastKnownCursorPosition == null;
}

void paintDragImage(int currentCursorPositionX, int currentCursorPositionY, double scaleFactor,
  Graphics2D rootComponentGraphics) {
 Graphics2D dragPictureGraphics = (Graphics2D) rootComponentGraphics.create();

 dragPictureGraphics.translate(currentCursorPositionX, currentCursorPositionY + offsetY);
 dragPictureGraphics.scale(scaleFactor, scaleFactor);
 dragPictureGraphics.setComposite(ALPHA_COMPOSITE);

 draggableComponent.paint(dragPictureGraphics);
}

}
Use in this way:
@Override
public void dragDropEnd(DragSourceDropEvent dragSourceDropEvent) {
dragImagePainter.handleDropEnd();
}
@Override
public void dragOver(DragSourceDragEvent dragSourceDragEvent) {
dragImagePainter.handleDragOver(dragSourceDragEvent.getX(), dragSourceDragEvent.getY());
}

Freitag, 11. September 2009

Who is doing QA on selfhtml.org?

Not many words on this:
if (document.Testform.Art[0].checked == true) { ... }

Donnerstag, 3. September 2009

Sony Ericsson W995, Google Calendar and Google Sync

After a long time a shorty:
I'm using gmail and the google calendar. I was searching for a cell phone which is able to sync with my google accounts. I've chosen the W995 since its price is the half of a G-Phone/I-Phone or Palm Pre and it fits my needs. Its fast, has a good battery AND since today it's able to synchronize my google calendar items and mails. All you have to do is to go to menu>organizer>synchronisation and set up a new Exchange Active Sync account:
  • Server address : https://m.google.com
  • Domain : Empty - this means leave this field blank
  • Username : your.name@googlemail.com (your full email address)
  • Password : 31337

  © Blogger template 'Morning Drink' by Ourblogtemplates.com 2008

Back to TOP