/*
* AnnotationPanel.java, a moveable panel containing annotations. Copyright (C) Achim Westermann.
*
* Copyright (C) 2002 - 2011, Achim Westermann, created on 13.02.2009
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* If you modify or optimize the code in a useful way please let me know.
* Achim.Westermann@gmx.de
*
*
* File : $Source: /cvsroot/jchart2d/jchart2d/src/info/monitorenter/gui/chart/annotations/bubble/AnnotationBubble.java,v $
* Date : $Date: 2011/01/14 08:36:11 $
* Version: $Revision: 1.9 $
*/
package info.monitorenter.gui.chart.annotations.bubble;
import info.monitorenter.gui.chart.annotations.AAnnotationContentComponent;
import info.monitorenter.gui.chart.views.ChartPanel;
import info.monitorenter.util.UIUtil;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.UIManager;
/**
* A movable container for annotations.
* <p>
*
*/
public class AnnotationBubble extends JPanel {
/**
* Title Bar of <code>{@link AnnotationBubble}</code>.
* <p>
*
*/
public class AnnotationTitleBar extends JPanel {
/** Generated <code>serialVersionUID</code>. **/
private static final long serialVersionUID = 4182197132940971837L;
/** close button in upper right (icon). **/
private JButton m_closeButton;
/**
* Defcon.
* <p>
*/
public AnnotationTitleBar() {
super();
this.setOpaque(true);
this.setBackground(AnnotationBubble.this.getBackground());
// Dimension heightLimit = new Dimension(Integer.MAX_VALUE, 20);
// this.setMaximumSize(heightLimit);
// this.setPreferredSize(new Dimension(200, 20));
// this.setMinimumSize(new Dimension(20, 20));
DragListener dragListener = AnnotationBubble.this.m_dragListener;
this.addMouseListener(dragListener);
this.addMouseMotionListener(dragListener);
// this.setBorder(BorderFactory.createLineBorder(Color.black, 1));
Action closeAction = new AbstractAction() {
/** Generated <code>serialVersionUID</code>. **/
private static final long serialVersionUID = 800535446184152788L;
/**
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(final ActionEvent e) {
AnnotationBubble.this.setVisible(false);
AnnotationBubble.this.m_chartPanel.remove(AnnotationBubble.this);
}
};
Icon closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
// TODO: this is since 1.6 only, add backward compatibility
closeAction.putValue(Action.SMALL_ICON, closeIcon);
this.m_closeButton = new JButton(closeAction);
this.m_closeButton.setContentAreaFilled(false);
this.m_closeButton.setBorderPainted(false);
this.m_closeButton.setFocusable(false);
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.add(Box.createHorizontalGlue());
this.add(this.m_closeButton);
}
/**
* @see javax.swing.JComponent#getPreferredSize()
*/
@Override
public Dimension getPreferredSize() {
Dimension result = null;
if (this.isPreferredSizeSet()) {
result = super.getPreferredSize();
} else {
Dimension closeButtonDim = this.m_closeButton.getPreferredSize();
Font font = this.getFont();
FontMetrics fontMetrics = this.getFontMetrics(font);
int fontHeight = fontMetrics.getHeight();
int closeButtonHeight = (int) closeButtonDim.getHeight();
int height = Math.max(fontHeight, closeButtonHeight);
result = new Dimension((int) closeButtonDim.getWidth(), height);
}
return result;
}
/**
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
@Override
public final void paint(final Graphics g) {
super.paint(g);
}
/**
* @see javax.swing.JComponent#paintBorder(java.awt.Graphics)
*/
@Override
protected final void paintBorder(final Graphics g) {
super.paintBorder(g);
}
/**
* @see javax.swing.JComponent#paintChildren(java.awt.Graphics)
*/
@Override
protected final void paintChildren(final Graphics g) {
super.paintChildren(g);
}
/**
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
*/
@Override
protected void paintComponent(final Graphics g) {
Color backupColor = g.getColor();
g.setColor(Color.BLACK);
Dimension size = this.getSize();
// paint into clip (y) to only have the upper part of the border painted:
g.drawRoundRect(0, 0, size.width - 1, size.height + 10, 10, 10);
if (!AnnotationBubble.this.isDragged() || !AnnotationBubble.this.isOutlineDragMode()) {
g.setColor(this.getBackground());
g.fillRoundRect(1, 1, size.width - 2, size.height + 10, 10, 10);
}
g.setColor(backupColor);
// super.paintComponent(g);
}
}
/**
* Listens for drag events on the chart to move the annotation panel.
*/
public class DragListener implements MouseMotionListener, MouseListener {
/** Needed to track relative dragments. */
protected Point m_lastDragPosition;
/**
* Defcon.
*/
protected DragListener() {
// nop
}
/**
* @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
public void mouseClicked(final MouseEvent e) {
// nop
}
/**
* @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
*/
public void mouseDragged(final MouseEvent e) {
if (this.m_lastDragPosition != null) {
// TODO: replace this with e.getLocationOnScreen(e) in 1.6:
// this is the 1.5 alternative:
Point pointNow = UIUtil.getLocationOnScreen(e);
double deltaX = pointNow.getX() - this.m_lastDragPosition.getX();
double deltaY = pointNow.getY() - this.m_lastDragPosition.getY();
Point panelPos = AnnotationBubble.this.getLocation();
panelPos.x += deltaX;
panelPos.y += deltaY;
AnnotationBubble.this.setLocation(panelPos);
this.m_lastDragPosition = pointNow;
}
}
/**
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
public void mouseEntered(final MouseEvent e) {
// nop
}
/**
* @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
public void mouseExited(final MouseEvent e) {
// nop
}
/**
* @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
*/
public void mouseMoved(final MouseEvent e) {
// nop
}
/**
* @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
public void mousePressed(final MouseEvent e) {
// TODO: replace this with e.getLocationOnScreen(e) in 1.6:
// this is the 1.5 alternative:
this.m_lastDragPosition = UIUtil.getLocationOnScreen(e);
}
/**
* @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
*/
public void mouseReleased(final MouseEvent e) {
this.m_lastDragPosition = null;
AnnotationBubble.this.repaint();
}
}
/** Internal padding for content box. */
public static final int PADDING = 8;
/** Only held here to know whether annotation is dragged. */
private DragListener m_dragListener;
/** If true, only the outline will be painted when dragging. */
private boolean m_outlineDragMode = true;
/** Generated <code>serialVersionUID</code>. **/
private static final long serialVersionUID = -3668420139916533725L;
/** The chart listening on. */
protected ChartPanel m_chartPanel;
/** Content area ref. */
protected AAnnotationContentComponent m_content;
/** Title bar ref or null, if no title bar is used. */
protected JComponent m_titleBar;
/**
* Creates an instance for the given chart.
* <p>
*
* @param chartPanel
* the chart panel this instance is added to as an annotation.
*
* @param annotationContent
* the content area (information container) of the visible annotation information.
*
* @param useDragListenerOnAnnotationContent
* if true the content area that contains the information of the annotation will support drag and drop as well as a basic
* right click popup menu.
*
* @param useTitleBar
* if true, a title bar with close button for the annotation will be shown.
*/
public AnnotationBubble(final ChartPanel chartPanel, final AAnnotationContentComponent annotationContent,
final boolean useDragListenerOnAnnotationContent, final boolean useTitleBar) {
super();
this.m_chartPanel = chartPanel;
this.m_content = annotationContent;
this.setBackground(new Color(0xff, 0xfe, 0xe9, 0x88));
this.m_dragListener = new DragListener();
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
if (useTitleBar) {
this.m_titleBar = new AnnotationTitleBar();
// dragPanel.setBackground(this.getBackground());
this.add(this.m_titleBar);
}
this.calculateSize();
if (useDragListenerOnAnnotationContent) {
annotationContent.addMouseMotionListener(this.m_dragListener);
annotationContent.addMouseListener(this.m_dragListener);
annotationContent.setBackground(this.getBackground());
}
this.add(annotationContent);
this.add(Box.createVerticalStrut(PADDING));
}
/**
* Internal size adaption to the content components preferred dimension.
*/
private void calculateSize() {
Dimension d = this.m_content.getPreferredSize();
double width = d.getWidth() + 4;
double height = d.getHeight() + 4;
if (this.m_titleBar != null) {
height += this.m_titleBar.getPreferredSize().getHeight();
}
this.setSize(new Dimension((int) width, (int) height));
}
/**
* Check whether this annotation is currently draggged.
* <p>
*
* @return true if this annotation is currently dragged.
*/
public boolean isDragged() {
boolean result = null != this.m_dragListener.m_lastDragPosition;
return result;
}
/**
* Returns the outlineDragMode.
* <p>
*
* @return the outlineDragMode
*/
public final boolean isOutlineDragMode() {
return this.m_outlineDragMode;
}
/**
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
@Override
public final void paint(final Graphics g) {
super.paint(g);
}
/**
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
*/
@Override
protected void paintComponent(final Graphics g) {
Color backupColor = g.getColor();
g.setColor(Color.BLACK);
Dimension size = this.getSize();
g.drawRoundRect(0, 0, size.width - 1, size.height - 1, 10, 10);
if (!AnnotationBubble.this.isDragged() || !AnnotationBubble.this.isOutlineDragMode()) {
g.setColor(this.getBackground());
g.fillRoundRect(1, 1, size.width - 2, size.height - 2, 8, 8);
}
g.setColor(backupColor);
// super.paintComponent(g);
}
/**
* Sets the outlineDragMode.
* <p>
*
* @param outlineDragMode
* the outlineDragMode to set
*/
public final void setOutlineDragMode(final boolean outlineDragMode) {
this.m_outlineDragMode = outlineDragMode;
}
/**
* Sets the transparency of the annotation.
* <p>
* Caution: When using a value greater 0 dragging the annotation may cost a multiple cpu load and dragging speed! In this case consider
* setting the paintOnDragging property to false;
*
* @param zeroToOneAlpha
* a transparency value between 0.0 and 1.0.
*/
public void setTransparency(final double zeroToOneAlpha) {
assert (zeroToOneAlpha >= 0.0 && zeroToOneAlpha < 1.0);
Color bgColor = this.getBackground();
synchronized (this) {
// avoid alpha channel as dragging transparent annotations is very
// expensive:
if (zeroToOneAlpha != 0) {
int alphaInt = (int) zeroToOneAlpha * 255;
if (bgColor.getAlpha() != alphaInt) {
this.setBackground(new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), alphaInt));
}
} else {
if (bgColor.getAlpha() > 0) {
this.setBackground(new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue()));
}
}
}
}
}