package com.limegroup.gnutella.gui;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.plaf.basic.BasicToolTipUI;
/**
* A new class to allow mulitple lines to be displayed in a tool tip
* @author Sumeet Thadani
*/
public class MultilineToolTipUI extends BasicToolTipUI {
/**
* The default width of a tooltip.
*/
private static final int MAX_WIDTH = 400;
/**
* The blank space between a border & text of a tooltip.
*/
private static final int BLANK_SPACE = 4;
/**
* The shared instance.
*/
private static final MultilineToolTipUI instance =
new MultilineToolTipUI();
/**
* Whether or not the current tip extends beyond the default width
*/
private boolean extendedWidth = false;
/**
* The JTextArea with the texts.
*/
private final JTextArea TEXT = new JTextArea();
/**
* The cell renderer pane used to draw the text over the component.
*/
private final CellRendererPane PANE = new CellRendererPane();
public static MultilineToolTipUI instance(){
return instance;
}
//private constructor
private MultilineToolTipUI() {
TEXT.setLineWrap(true);
TEXT.setWrapStyleWord(true);
TEXT.setEditable(false);
TEXT.setOpaque(false);
}
/**
* Determines the size of this tooltip.
*/
public Dimension getPreferredSize(JComponent c) {
extendedWidth = false;
Font font = c.getFont();
FontMetrics fontMetrics = c.getFontMetrics(font);
int fontHeight = fontMetrics.getHeight();
String[] lines = ((JMultilineToolTip)c).getTipArray();
if(lines == null)
return new Dimension(0,0);
int num_lines = lines.length;
int height = num_lines * fontHeight;
if (height==0)
return new Dimension(0,0);
int width = 0;
for (int i = 0; i < num_lines; i++) {
int line_width = fontMetrics.stringWidth(lines[i]);
width = Math.max(line_width, width);
if(width > MAX_WIDTH) {
extendedWidth = true;
break;
}
}
Dimension preferredSize;
if(extendedWidth) {
TEXT.setFont(font);
TEXT.setText(lines[0]);
for(int i = 1; i < num_lines; i++)
TEXT.append("\n" + lines[i]);
Dimension pref = preferredSize(fontMetrics, TEXT);
width = pref.width;
height = pref.height;
}
return new Dimension(width + BLANK_SPACE * 2,
height + BLANK_SPACE * 2);
}
public Dimension getMinimumSize(JComponent c) {
return getPreferredSize(c);
}
public Dimension getMaximumSize(JComponent c) {
return getPreferredSize(c);
}
/**
* Gets the preferred size of a JTextArea.
*/
private Dimension preferredSize(final FontMetrics fm, JTextArea area) {
// Iterate through the text, determining how large we want it to be.
int fullWidth = 0;
int rows = 1;
int carriage = -1;
int nextCarriage = -1;
int width = 0;
final String text = area.getText();
String current;
nextCarriage = text.indexOf("\n");
while(nextCarriage != -1) {
current = text.substring(carriage+1, nextCarriage);
width = fm.stringWidth(current);
if(width > MAX_WIDTH) {
rows += (int)Math.ceil((double)width / (double)MAX_WIDTH);
fullWidth = MAX_WIDTH;
} else {
fullWidth = Math.max(width, fullWidth);
rows++;
}
carriage = nextCarriage;
nextCarriage = text.indexOf("\n", carriage+1);
}
// last run...
current = text.substring(carriage + 1);
width = fm.stringWidth(current);
if(width > MAX_WIDTH) {
rows += (int)Math.ceil((double)width / (double)MAX_WIDTH);
fullWidth = MAX_WIDTH;
} else {
fullWidth = Math.max(width, fullWidth);
rows++;
}
return new Dimension(fullWidth, rows * fm.getHeight());
}
/**
* Paints this tooltip. If 'extendedWidth' is true, uses a JTextArea
* in order to paint the tooltip.
*/
public void paint(Graphics g, JComponent c) {
Dimension dimension = c.getSize();
Font font = c.getFont();
if(extendedWidth) {
g.setColor(c.getBackground());
g.fillRect(0, 0, dimension.width, dimension.height);
TEXT.setForeground(c.getForeground());
PANE.paintComponent(g, TEXT, c,
BLANK_SPACE, BLANK_SPACE,
dimension.width - BLANK_SPACE*2,
dimension.height - BLANK_SPACE*2,
true);
return;
}
FontMetrics fontMetrics =
Toolkit.getDefaultToolkit().getFontMetrics(font);
int fontHeight = fontMetrics.getHeight();
int fontAscent = fontMetrics.getAscent();
String[] lines = ((JMultilineToolTip)c).getTipArray();
// possible NPE
if (lines == null) return;
int num_lines = lines.length;
int height;
int i;
g.setColor(c.getBackground());
g.fillRect(0, 0, dimension.width, dimension.height);
g.setColor(c.getForeground());
for(i=0, height = BLANK_SPACE + fontAscent;
i < num_lines; i++, height += fontHeight)
g.drawString(lines[i], BLANK_SPACE, height);
}
}