package org.chartsy.main;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.LinkedHashMap;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import org.chartsy.main.chart.Indicator;
import org.chartsy.main.chart.Overlay;
import org.chartsy.main.data.ChartData;
import org.chartsy.main.utils.ColorGenerator;
import org.chartsy.main.utils.CoordCalc;
import org.chartsy.main.utils.GraphicsUtils;
import org.chartsy.main.utils.HtmlRendererImpl;
import org.chartsy.main.utils.SerialVersion;
import org.openide.util.NbBundle;
/**
*
* @author viorel.gheba
*/
public class ChartSplitPanel extends JLayeredPane implements Serializable
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
private ChartFrame chartFrame;
private ChartPanel chartPanel;
private IndicatorsPanel indicatorsPanel;
private MarkerLabel label;
private int index = -1;
private static int width = 200;
private static int height;
private int lines = 5;
private Color lineColor = new Color(0xef2929);
private Color color = new Color(0x1C2331);
private Color backgroundColor = ColorGenerator.getTransparentColor(color, 100);
private Color fontColor = new Color(0xffffff);
private static Font font;
static
{
font = new Font("Dialog", Font.PLAIN, 10);
height = 14;
}
public ChartSplitPanel(ChartFrame frame)
{
chartFrame = frame;
chartPanel = new ChartPanel(chartFrame);
indicatorsPanel = new IndicatorsPanel(chartFrame);
label = new MarkerLabel();
setOpaque(false);
setDoubleBuffered(true);
setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
setLayout(new LayoutManager()
{
public void addLayoutComponent(String name, Component comp)
{}
public void removeLayoutComponent(Component comp)
{}
public Dimension preferredLayoutSize(Container parent)
{return new Dimension(0, 0);}
public Dimension minimumLayoutSize(Container parent)
{return new Dimension(0, 0);}
public void layoutContainer(Container parent)
{
Insets insets = parent.getInsets();
int x = insets.left;
int y = insets.top;
int w = parent.getWidth() - insets.left - insets.right;
int h = parent.getHeight() - insets.top - insets.bottom;
int indicatorsHeight = indicatorsPanel.getPanelHeight();
int chartHeight = h - indicatorsHeight;
indicatorsPanel.setBounds(x, y + chartHeight, w, indicatorsHeight);
chartPanel.setBounds(x, y, w, chartHeight);
Point dp = new Point(0, 50);
Point p = label.getLocation();
if (!dp.equals(p))
label.setBounds(p.x, p.y, width + 2, height * lines + 2);
else
label.setBounds(dp.x, dp.y, width + 2, height * lines + 2);
}
});
add(label);
add(indicatorsPanel);
add(chartPanel);
label.setLocation(0, 50);
}
public ChartFrame getChartFrame()
{ return chartFrame; }
public void setChartFrame(ChartFrame frame)
{ chartFrame = frame; }
public ChartPanel getChartPanel()
{ return chartPanel; }
public void setChartPanel(ChartPanel panel)
{ chartPanel = panel; }
public IndicatorsPanel getIndicatorsPanel()
{ return indicatorsPanel; }
public void setIndicatorsPanel(IndicatorsPanel panel)
{ indicatorsPanel = panel; }
public void setIndex(int i)
{ index = i; }
public int getIndex()
{ return index; }
@Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = GraphicsUtils.prepareGraphics(g);
if (chartFrame.getChartProperties().getMarkerVisibility())
{
if (index != -1)
{
labelText();
paintMarkerLine(g2);
label.setVisible(true);
}
}
else
{
label.setVisible(false);
}
g2.dispose();
}
@Override
public void update(Graphics g)
{
paint(g);
}
private void paintMarkerLine(Graphics2D g)
{
Rectangle bounds = chartPanel.getBounds();
bounds.grow(-2, -2);
long time = chartFrame.getChartData().getVisible().getTimeAt(index);
String s = chartFrame.getChartData().getInterval().getMarkerString(time);
double dx = chartFrame.getChartData().getX(index, bounds);
g.setFont(font);
FontMetrics fm = g.getFontMetrics(font);
int w = fm.stringWidth(s) + 2;
int h = fm.getHeight() + 2;
boolean inv = (getWidth() - dx < w);
// paint line
g.setPaint(lineColor);
g.draw(CoordCalc.line(dx, 0, dx, getHeight()));
// paint background
g.fill(CoordCalc.rectangle(inv ? dx - w : dx, 0, w, h));
// paint rectangle and string
g.draw(CoordCalc.rectangle(inv ? dx - w : dx, 0, w, h));
g.setPaint(fontColor);
g.drawString(s, inv ? (float) (dx - w + 1) : (float) (dx + 1), (float) (fm.getAscent() + 1));
bounds.grow(2, 2);
}
private String addLine(String left, String right)
{
if (!right.equals(" "))
return NbBundle.getMessage(
ChartSplitPanel.class,
"HTML_Line",
new String[] {String.valueOf(width/2), left, right});
else
return NbBundle.getMessage(
ChartSplitPanel.class,
"HTML_EmptyLine",
new String[] {String.valueOf(width), left});
}
public void labelText()
{
if (index != -1)
{
ChartData cd = chartFrame.getChartData();
DecimalFormat df = new DecimalFormat("#,##0.00");
long time = cd.getVisible().getTimeAt(index);
String date = chartFrame.getChartData().getInterval().getMarkerString(time);
StringBuilder sb = new StringBuilder();
// Date
sb.append(addLine("Date:", date));
// Open
sb.append(addLine("Open:", df.format(cd.getVisible().getOpenAt(index))));
// High
sb.append(addLine("High:", df.format(cd.getVisible().getHighAt(index))));
// Low
sb.append(addLine("Low:", df.format(cd.getVisible().getLowAt(index))));
// Close
sb.append(addLine("Close:", df.format(cd.getVisible().getCloseAt(index))));
lines = 5;
boolean hasOverlays = chartPanel.getOverlaysCount() > 0;
boolean hasIndicators = indicatorsPanel.getIndicatorsCount() > 0;
if (hasOverlays || hasIndicators)
{
sb.append(addLine(" ", " "));
lines++;
}
if (hasOverlays)
{
for (Overlay overlay : chartPanel.getOverlays())
{
LinkedHashMap map = overlay.getHTML(chartFrame, index);
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
sb.append(addLine(key.toString(), map.get(key).toString()));
lines++;
}
}
}
if (hasIndicators)
{
if (hasOverlays)
{
sb.append(addLine(" ", " "));
lines++;
}
for (Indicator indicator : indicatorsPanel.getIndicators())
{
LinkedHashMap map = indicator.getHTML(chartFrame, index);
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
sb.append(addLine(key.toString(), map.get(key).toString()));
lines++;
}
}
}
String labelText = NbBundle.getMessage(
ChartSplitPanel.class,
"HTML_Marker",
new String[] {String.valueOf(width), sb.toString()});
if (!label.getText().equals(labelText))
label.setText(labelText);
Dimension dimension = new Dimension(width, height * lines);
if (!label.getPreferredSize().equals(dimension))
label.setPreferredSize(dimension);
}
else
{
label.setVisible(false);
}
}
public void moveLeft()
{
ChartData cd = chartFrame.getChartData();
int last = cd.getLast();
int items = cd.getPeriod() - 1;
int i = index - 1;
if (i < 0)
{
if (last - 1 > items)
{
cd.setLast(last - 1);
}
}
else
{
index = i;
}
labelText();
cd.calculate(chartFrame);
chartFrame.repaint();
}
public void moveRight()
{
ChartData cd = chartFrame.getChartData();
int all = cd.getDataset().getItemsCount();
int last = cd.getLast();
int items = cd.getPeriod() - 1;
int i = index + 1;
if (i > items)
{
if (last < all)
{
cd.setLast(last + 1);
}
}
else
{
index = i;
}
labelText();
cd.calculate(chartFrame);
chartFrame.repaint();
}
public static class Draggable extends MouseAdapter implements MouseMotionListener
{
Point lastP;
Component cDraggable;
public Draggable(Component comp)
{
comp.setLocation(0, 0);
cDraggable = comp;
}
private void setCursorType(Point p)
{
Point loc = cDraggable.getLocation();
Dimension size = cDraggable.getSize();
if ((p.y + 4 < loc.y + size.height) && (p.x + 4 < p.x + size.width))
{
cDraggable.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
}
@Override
public void mousePressed(MouseEvent e)
{
if (cDraggable.getCursor().equals(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)))
{
lastP = e.getPoint();
}
else
{
lastP = null;
}
}
@Override
public void mouseReleased(MouseEvent e)
{
lastP = null;
}
@Override
public void mouseMoved(MouseEvent e)
{
setCursorType(e.getPoint());
}
@Override
public void mouseDragged(MouseEvent e)
{
int x, y;
if (lastP != null)
{
x = cDraggable.getX() + (e.getX() - (int)lastP.getX());
y = cDraggable.getY() + (e.getY() - (int)lastP.getY());
cDraggable.setLocation(x, y);
}
}
}
private class MarkerLabel extends HtmlRendererImpl
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
private MarkerLabel()
{
setOpaque(false);
setFont(font);
setForeground(fontColor);
setVisible(index != -1);
setPreferredSize(new Dimension(width, height));
Draggable draggable = new Draggable(this);
addMouseListener(draggable);
addMouseMotionListener(draggable);
}
@Override protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setColor(backgroundColor);
g2.fillRect(0, 0, width + 2, height * lines + 2);
g2.setColor(color);
g2.drawRect(0, 0, width + 1, height * lines + 1);
super.paintComponent(g);
}
}
}