package abbot.editor.widgets;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.ref.*;
import java.util.*;
import abbot.Log;
/** Provide a method for consistently painting over a given component.
This implementation uses an invisible, added componenet in order to insert
code at the appropriate time in the painting process.
*/
// cf CellRendererPane
public abstract class AbstractComponentDecorator {
private Container component;
private Renderer renderer;
private boolean inViewport;
/** Create a decorator for the given component. */
public AbstractComponentDecorator(Container c) {
if (c instanceof JViewport
&& c.getComponentCount() != 0
&& c.getComponents()[0] instanceof Container) {
c = (Container)c.getComponents()[0];
// Viewports only support a single child, so instead add to the
// child, and use the viewport's graphics to paint any areas
// outside the child.
inViewport = true;
}
else if (c instanceof RootPaneContainer) {
c = ((RootPaneContainer)c).getLayeredPane();
}
else if (c instanceof JRootPane) {
c = ((JRootPane)c).getLayeredPane();
}
component = c;
renderer = new Renderer();
// FIXME never add anything to JViewport
component.add(renderer);
component.repaint();
// don't repaint the viewport here, or any custom painting
// will be wiped out.
}
protected Container getComponent() { return component; }
/** Stop decorating. */
public void dispose() {
Runnable action = new Runnable() {
public void run() {
component.remove(renderer);
component.repaint();
if (inViewport)
component.getParent().repaint();
synchronized(AbstractComponentDecorator.this) {
renderer = null;
component = null;
}
}
};
if (SwingUtilities.isEventDispatchThread()) {
action.run();
}
else {
SwingUtilities.invokeLater(action);
}
}
public abstract void paint(Graphics g);
private class Renderer extends JComponent {
public Renderer() {
setOpaque(false);
}
public void invalidate() { }
public boolean isVisible() { return true; }
public boolean isShowing() { return true; }
public Rectangle getBounds(Rectangle b) {
// Pretend to have the same bounds as the component
b = component.getBounds(b);
b.x = 0;
b.y = 0;
Log.debug("bounds: " + b);
return b;
}
// must use the paint method; paintComponent will not work here
public void paint(Graphics g) {
synchronized(AbstractComponentDecorator.this) {
if (inViewport) {
Log.debug("painting viewport");
Graphics g2 = component.getParent().getGraphics();
AbstractComponentDecorator.this.paint(g2);
}
Log.debug("painting component");
AbstractComponentDecorator.this.paint(g);
}
// NOTE: see paintComponent from CellRendererPane
// setBounds(-width,-height,0,0) to avoid getting any input
}
}
}