package jas.hist;
import jas.plot.CoordinateTransformation;
import jas.plot.DateCoordinateTransformation;
import jas.plot.DoubleCoordinateTransformation;
import jas.plot.Overlay;
import jas.plot.OverlayContainer;
import jas.plot.PlotGraphics;
import jas.plot.PrintHelper;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public abstract class OverlayWithHandles implements Overlay, MouseListener, MouseMotionListener
{
private Cursor defaultCursor = null;
private static MouseEvent mouseEvent = null;
private static boolean changeCursor;
private boolean handlesPainted = false;
protected OverlayWithHandles(DataSource ds)
{
if (ds instanceof HasHandles)
{
hasHandles = (HasHandles) ds;
}
}
public void paint(PlotGraphics g)
{
if (handles != null && !PrintHelper.isPrinting())
{
CoordinateTransformation xt = container.getXTransformation();
CoordinateTransformation yt = container.getYTransformation();
g.clearTransformation();
for (int i=0; i<handles.length; i++)
{
handles[i].paint(g,xt,yt);
}
}
}
void paintHandles(MouseEvent e) {
handlesPainted = true;
DoubleCoordinateTransformation xp;
DoubleCoordinateTransformation yp;
CoordinateTransformation xt = container.getXTransformation();
if ( xt instanceof DateCoordinateTransformation )
xp = new DateTransformationConverter( (DateCoordinateTransformation) xt );
else
xp = (DoubleCoordinateTransformation) xt;
CoordinateTransformation yt = container.getYTransformation();
if ( yt instanceof DateCoordinateTransformation )
yp = new DateTransformationConverter( (DateCoordinateTransformation) yt );
else
yp = (DoubleCoordinateTransformation) yt;
Handle[] temp = hasHandles.getHandles(xp.getPlotMin(),xp.getPlotMax(),yp.getPlotMin(),yp.getPlotMax());
handles = new HandleWrapper[temp.length];
for (int i=0; i<handles.length; i++) handles[i] = new HandleWrapper(temp[i]);
container.repaint(); // Could just paint the handles
}
public void mouseEntered(MouseEvent e)
{
paintHandles(e);
}
public void mouseExited(MouseEvent e)
{
handles = null;
container.repaint();
handlesPainted = false;
}
public void mouseMoved(MouseEvent event)
{
// If the cursor is already inside the plot area, the method mouseEntered
// is not invoked and the Handles are not painted. This below is to avoid that.
if ( ! handlesPainted )
paintHandles(event);
// Given that there is an OverlayWithHandles for each function
// this method (mouseMoved) is invoked n times, where n is the number of
// functions. The static variables "mouseEvent" and "changeCursor" ensure
// that only one OverlayWithHandles is allowed to change the cursor and
// to have an active handle.
if ( mouseEvent == null || mouseEvent != event ) {
mouseEvent = event;
changeCursor = true;
}
if ( defaultCursor == null )
defaultCursor = event.getComponent().getCursor();
Point p = event.getPoint();
if ( handles != null ) {
for (int i=0; i<handles.length; i++)
{
if (handles[i].contains(p))
{
Cursor cursor = handles[i].cursor();
if ( cursor != null ) {
event.getComponent().setCursor( cursor );
changeCursor = false;
}
setCurrentHandle(handles[i]);
return;
}
}
if ( event.getComponent().getCursor() != defaultCursor && changeCursor ) {
event.getComponent().setCursor(defaultCursor);
}
}
setCurrentHandle(null);
}
public void mousePressed(MouseEvent event)
{
if (currentHandle != null) captureHandle(currentHandle);
}
public void mouseReleased(MouseEvent event)
{
captureHandle(null);
}
public void mouseClicked(MouseEvent event)
{
}
public void mouseDragged(MouseEvent event)
{
if (capturedHandle != null)
{
capturedHandle.moveTo(event.getPoint());
container.repaint();
}
}
public void containerNotify(OverlayContainer c)
{
if (container != null)
{
container.removeMouseListener(this);
container.removeMouseMotionListener(this);
}
this.container = c;
if (c != null && hasHandles != null)
{
c.addMouseListener(this);
c.addMouseMotionListener(this);
}
}
private void setCurrentHandle(HandleWrapper h)
{
if (currentHandle != h)
{
currentHandle = h;
container.repaint();
}
}
private void captureHandle(HandleWrapper h)
{
if (capturedHandle != h)
{
capturedHandle = h;
container.repaint();
}
}
private class HandleWrapper
{
HandleWrapper(Handle h)
{
this.handle = h;
}
void paint(PlotGraphics g, CoordinateTransformation xt, CoordinateTransformation yt)
{
DoubleCoordinateTransformation xp;
DoubleCoordinateTransformation yp;
if ( xt instanceof DateCoordinateTransformation )
xp = new DateTransformationConverter( (DateCoordinateTransformation) xt );
else
xp = (DoubleCoordinateTransformation) xt;
if ( yt instanceof DateCoordinateTransformation )
yp = new DateTransformationConverter( (DateCoordinateTransformation) yt );
else
yp = (DoubleCoordinateTransformation) yt;
double x = xp.convert(handle.getX());
double y = yp.convert(handle.getY());
g.setColor(this == currentHandle ? Color.red : Color.black);
g.fillRect(x-handleSize,y-handleSize, x+handleSize,y+handleSize);
}
boolean contains(Point p)
{
CoordinateTransformation xt = (CoordinateTransformation) container.getXTransformation();
CoordinateTransformation yt = (CoordinateTransformation) container.getYTransformation();
DoubleCoordinateTransformation xp;
DoubleCoordinateTransformation yp;
if ( xt instanceof DateCoordinateTransformation )
xp = new DateTransformationConverter( (DateCoordinateTransformation) xt );
else
xp = (DoubleCoordinateTransformation) xt;
if ( yt instanceof DateCoordinateTransformation )
yp = new DateTransformationConverter( (DateCoordinateTransformation) yt );
else
yp = (DoubleCoordinateTransformation) yt;
double x = xp.convert(handle.getX())-handleSize;
double y = yp.convert(handle.getY())-handleSize;
return (p.x >= x && p.x <= x+2*handleSize && p.y >= y && p.y > y && p.y <= y+2*handleSize);
}
void moveTo(Point p)
{
CoordinateTransformation xt = (CoordinateTransformation) container.getXTransformation();
CoordinateTransformation yt = (CoordinateTransformation) container.getYTransformation();
DoubleCoordinateTransformation xp;
DoubleCoordinateTransformation yp;
if ( xt instanceof DateCoordinateTransformation )
xp = new DateTransformationConverter( (DateCoordinateTransformation) xt );
else
xp = (DoubleCoordinateTransformation) xt;
if ( yt instanceof DateCoordinateTransformation )
yp = new DateTransformationConverter( (DateCoordinateTransformation) yt );
else
yp = (DoubleCoordinateTransformation) yt;
handle.moveTo(xp.unConvert(p.x),yp.unConvert(p.y));
}
Cursor cursor() {
return handle.cursor();
}
private Handle handle;
}
private static final double handleSize = 2.5;
private HandleWrapper[] handles = null;
private HandleWrapper currentHandle = null;
private HandleWrapper capturedHandle = null;
private HasHandles hasHandles;
protected OverlayContainer container;
}