package org.chartsy.main;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
import org.chartsy.main.chart.Annotation;
import org.chartsy.main.chart.Indicator;
import org.chartsy.main.chart.Overlay;
import org.chartsy.main.data.ChartData;
import org.chartsy.main.data.Dataset;
import org.chartsy.main.dialogs.AnnotationProperties;
import org.chartsy.main.managers.AnnotationManager;
import org.chartsy.main.utils.GraphicsUtils;
import org.chartsy.main.utils.Range;
import org.chartsy.main.utils.SerialVersion;
/**
*
* @author viorel.gheba
*/
public class AnnotationPanel extends JPanel
implements MouseListener, MouseMotionListener, KeyListener, Serializable
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
public static final int NONE = 0;
public static final int NEWANNOTATION = 1;
public static final int RESIZE = 2;
public static final int MOVE = 3;
private int state;
private ChartFrame chartFrame;
private List<Annotation> annotations;
private Annotation current = null;
private ToolTipManager toolTipManager;
public AnnotationPanel(ChartFrame frame)
{
state = NONE;
chartFrame = frame;
toolTipManager = ToolTipManager.sharedInstance();
toolTipManager.setLightWeightPopupEnabled(true);
toolTipManager.registerComponent(this);
annotations = new ArrayList<Annotation>();
setOpaque(false);
setDoubleBuffered(true);
addMouseListener((MouseListener) this);
addMouseMotionListener((MouseMotionListener) this);
addKeyListener((KeyListener) this);
}
public ChartFrame getChartFrame()
{ return chartFrame; }
public int getState()
{ return state; }
public void setState(int i)
{ state = i; }
@Override
public void paint(Graphics g)
{
Graphics2D g2 = GraphicsUtils.prepareGraphics(g);
for (Annotation annotation : annotations)
annotation.paint(g2);
}
@Override
public void update(Graphics g)
{
paint(g);
}
public Range getRange()
{
Container parent = getParent();
if (parent instanceof ChartPanel)
{
return ((ChartPanel)parent).getRange();
}
else
{
return ((IndicatorPanel)parent).getIndicator().getRange(chartFrame);
}
}
public void setAnnotationsList(List<Annotation> list)
{
for (Annotation a : list)
{
a.setChartFrame(chartFrame);
a.setAnnotationPanel(this);
annotations.add(a);
}
repaint();
}
public List<Annotation> getAnnotationsList()
{ return annotations; }
public Annotation[] getAnnotations()
{ return annotations.toArray(new Annotation[annotations.size()]); }
public void addAnnotation(Annotation a)
{ annotations.add(a); }
public boolean hasCurrent()
{ return current != null; }
public boolean isCurrentNull()
{ return current == null; }
public Annotation getCurrent()
{ return current ; }
public void setCurrent(Annotation a)
{ current = a; }
public void deselectAll()
{
for (Annotation annotation : annotations)
annotation.setSelected(false);
current = null;
}
public void removeAllAnnotations()
{
try
{
current = null;
annotations.clear();
validate();
repaint();
}
catch (Exception ex)
{
ChartFrame.LOG.log(Level.SEVERE, null, ex);
}
}
public void removeAnnotation()
{
if (!isCurrentNull() && getCurrent().isSelected())
{
current.setSelected(false);
annotations.remove(getCurrent());
current = null;
repaint();
}
}
private boolean isAnnotation(int x, int y)
{
for (Annotation a : annotations)
{
boolean b = a.pointIntersects(x, y);
if (b)
{
current = a;
current.setActive(true);
current.setSelected(true);
return b;
}
}
return false;
}
public void mouseClicked(MouseEvent e)
{}
public void mousePressed(MouseEvent e)
{
requestFocus();
if (e.isConsumed())
return;
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 1)
{
if (getCursor().equals(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)))
getParent().requestFocus();
if (AnnotationManager.getDefault().hasNew())
setState(NEWANNOTATION);
switch (getState())
{
case NONE:
chartFrame.deselectAll();
if (!isAnnotation(e.getX(), e.getY()))
{
if (!getCursor().equals(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)))
{
if (chartFrame.getChartProperties().getMarkerVisibility())
{
Rectangle rect = getBounds();
rect.grow(-2, -2);
int i = chartFrame.getChartData().getIndex(e.getPoint(), rect);
if (i != -1)
{
chartFrame.getSplitPanel().setIndex(i);
chartFrame.getSplitPanel().labelText();
chartFrame.getSplitPanel().repaint();
}
}
else
{
chartFrame.getSplitPanel().setIndex(-1);
}
}
}
else
{
if (!isCurrentNull())
getCurrent().mousePressed(e);
}
break;
case RESIZE:
if (!isCurrentNull())
getCurrent().mousePressed(e);
break;
case MOVE:
if (!isCurrentNull())
getCurrent().mousePressed(e);
break;
case NEWANNOTATION:
chartFrame.deselectAll();
Annotation a = AnnotationManager.getDefault().getNewAnnotation(chartFrame);
a.setAnnotationPanel(this);
setCurrent(a);
if (!isCurrentNull())
{
getCurrent().mousePressed(e);
}
else
{
setState(NONE);
mousePressed(e);
}
break;
}
}
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2)
{
if (!isCurrentNull())
{
AnnotationProperties dialog = new AnnotationProperties(new JFrame(), true);
dialog.initializeForm(getCurrent());
dialog.setLocationRelativeTo(chartFrame);
dialog.setVisible(true);
}
}
if (e.getButton() == MouseEvent.BUTTON3)
{
switch (getState())
{
case NONE:
chartFrame.getMenu().show(this, e.getX(), e.getY());
break;
}
}
}
public void mouseReleased(MouseEvent e)
{
if (e.isConsumed())
return;
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK)
{
if (!isCurrentNull())
getCurrent().mouseReleased(e);
}
}
public void mouseEntered(MouseEvent e)
{
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
//tooltipHandler(e);
}
public void mouseExited(MouseEvent e)
{}
public void mouseDragged(MouseEvent e)
{
if (e.isConsumed())
return;
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK)
{
if (!isCurrentNull())
getCurrent().mouseDragged(e);
else
{
if (chartFrame.getChartProperties().getMarkerVisibility())
{
Rectangle rect = getBounds();
rect.grow(-2, -2);
int i = chartFrame.getChartData().getIndex(e.getPoint(), rect);
if (i != -1)
{
chartFrame.getSplitPanel().setIndex(i);
chartFrame.getSplitPanel().labelText();
chartFrame.getSplitPanel().repaint();
}
}
else
{
chartFrame.getSplitPanel().setIndex(-1);
}
}
}
}
public void mouseMoved(MouseEvent e)
{
//tooltipHandler(e);
}
public void keyTyped(KeyEvent e)
{}
public void keyPressed(KeyEvent e)
{
if (e.isConsumed())
return;
requestFocus();
switch (e.getKeyCode())
{
case KeyEvent.VK_MINUS:
chartFrame.zoomOut();
break;
case KeyEvent.VK_SUBTRACT:
chartFrame.zoomOut();
break;
case KeyEvent.VK_ADD:
chartFrame.zoomIn();
break;
}
switch (e.getModifiers())
{
case KeyEvent.SHIFT_MASK:
if (e.getKeyCode() == KeyEvent.VK_EQUALS)
chartFrame.zoomIn();
break;
}
if (hasCurrent() && getCurrent().isSelected())
{
switch (e.getKeyCode())
{
case KeyEvent.VK_DELETE:
removeAnnotation();
break;
case KeyEvent.VK_UP:
getCurrent().moveUp();
break;
case KeyEvent.VK_DOWN:
getCurrent().moveDown();
break;
case KeyEvent.VK_LEFT:
getCurrent().moveLeft();
break;
case KeyEvent.VK_RIGHT:
getCurrent().moveRight();
break;
}
}
else
{
if (chartFrame.getChartProperties().getMarkerVisibility())
{
switch (e.getKeyCode())
{
case KeyEvent.VK_LEFT:
chartFrame.getSplitPanel().moveLeft();
break;
case KeyEvent.VK_RIGHT:
chartFrame.getSplitPanel().moveRight();
break;
}
}
}
}
public void keyReleased(KeyEvent e)
{}
public void tooltipHandler(MouseEvent e)
{
ChartData chartData = chartFrame.getChartData();
Dataset dataset = chartData.getVisible();
DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");
String newLine = "<br>";
Rectangle rect = getBounds();
rect.grow(-2, -2);
int index = chartData.getIndex(e.getPoint(), rect);
if (index != -1)
{
StringBuilder builder = new StringBuilder();
Container parent = getParent();
if (parent instanceof ChartPanel)
{
ChartPanel chartPanel = (ChartPanel) parent;
long time = dataset.getTimeAt(index);
double open = dataset.getOpenAt(index);
double high = dataset.getHighAt(index);
double low = dataset.getLowAt(index);
double close = dataset.getLowAt(index);
double volume = dataset.getVolumeAt(index);
builder.append("<html>");
builder.append("Date: ")
.append(chartData.getInterval().getMarkerString(time))
.append(newLine).append(newLine);
builder.append("Open: ")
.append(decimalFormat.format(open))
.append(newLine);
builder.append("High: ")
.append(decimalFormat.format(high))
.append(newLine);
builder.append("Low: ")
.append(decimalFormat.format(low))
.append(newLine);
builder.append("Close: ")
.append(decimalFormat.format(close))
.append(newLine);
builder.append("Volume: ")
.append(decimalFormat.format(volume))
.append(newLine);
if (chartPanel.hasOverlays())
{
for (Overlay overlay : chartPanel.getOverlays())
{
LinkedHashMap map = overlay.getHTML(chartFrame, index);
Iterator it = map.keySet().iterator();
while (it.hasNext())
{
String key = it.next().toString();
String value = map.get(key).toString();
if (value.equals(" "))
{
builder.append(newLine);
builder.append(key).append(newLine);
} else
{
builder.append(key).append(" ")
.append(value).append(newLine);
}
}
}
}
builder.append("</html>");
}
else
{
IndicatorPanel indicatorPanel = (IndicatorPanel) parent;
Indicator indicator = indicatorPanel.getIndicator();
long time = dataset.getTimeAt(index);
builder.append("<html>");
builder.append("Date: ")
.append(chartData.getInterval().getMarkerString(time))
.append(newLine).append(newLine);
LinkedHashMap map = indicator.getHTML(chartFrame, index);
Iterator it = map.keySet().iterator();
while (it.hasNext())
{
String key = it.next().toString();
String value = map.get(key).toString();
if (value.equals(" "))
{
builder.append(key).append(newLine);
} else
{
builder.append(key).append(" ")
.append(value).append(newLine);
}
}
builder.append("</html>");
}
setToolTipText(builder.toString());
}
}
}