package org.limewire.ui.swing.painter;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import org.jdesktop.application.Resource;
import org.jdesktop.swingx.painter.RectanglePainter;
import org.limewire.ui.swing.components.PromptTextField;
import org.limewire.ui.swing.util.GuiUtils;
/**
* An area painter intended for use on the filter input field. When text is
* entered, FilterPainter paints a background color in the field and displays
* a "reset" icon on the right edge. Clicking on the reset icon deletes all
* text in the field.
*
* <p>FilterPainter is installed on an instance of LimePromptTextField by
* calling the method <code>install(LimePromptTextField)</code>.</p>
*/
public class FilterPainter<T> extends RectanglePainter<T>
implements DocumentListener {
@Resource private Color fillColor;
@Resource private Icon activeResetIcon;
@Resource private Icon inactiveResetIcon;
private final MouseAdapter resetListener;
private Cursor defaultCursor;
private Icon resetIcon;
private boolean showIcon;
/**
* Constructs a FilterPainter with the specified arc width and arc height.
*/
public FilterPainter(int arcWidth, int arcHeight) {
GuiUtils.assignResources(this);
this.resetListener = new ResetMouseListener();
// Set painter properties.
setRounded(true);
setFillPaint(Color.WHITE);
setRoundWidth(arcWidth);
setRoundHeight(arcHeight);
setInsets(new Insets(2,2,2,2));
setBorderPaint(null);
setFillVertical(true);
setFillHorizontal(true);
setAntialiasing(true);
setCacheable(true);
setResetIcon(inactiveResetIcon);
}
/**
* Installs this painter on the specified text field.
*/
public void install(PromptTextField textField) {
// Set default cursor.
defaultCursor = textField.getCursor();
// Set border to increase right margin.
textField.setBorder(BorderFactory.createEmptyBorder(2, 10, 2,
12 + resetIcon.getIconWidth()));
// Install mouse listener.
textField.addMouseListener(resetListener);
textField.addMouseMotionListener(resetListener);
// Install document listener to update fill color.
textField.getDocument().addDocumentListener(this);
}
@Override
public void doPaint(Graphics2D g, T component, int width, int height) {
super.doPaint(g, component, width, height);
// Draw reset icon if enabled.
if (showIcon) {
Point iconLocation = getIconLocation(width, height);
resetIcon.paintIcon((Component) component, g, iconLocation.x, iconLocation.y);
}
}
@Override
public void changedUpdate(DocumentEvent e) {
// Do nothing.
}
/**
* Handles insert text event to update fill color and reset icon.
*/
@Override
public void insertUpdate(DocumentEvent e) {
updatePainter(e.getDocument());
}
/**
* Handles remove text event to update fill color and reset icon.
*/
@Override
public void removeUpdate(DocumentEvent e) {
updatePainter(e.getDocument());
}
/**
* Returns the position of the reset icon for the specified text field
* width and height.
*/
private Point getIconLocation(int width, int height) {
// Get icon size.
int iconWidth = resetIcon.getIconWidth();
int iconHeight = resetIcon.getIconHeight();
// Return icon position. This is indented from the right-side of the
// text field, and vertically centered.
return new Point(width - iconWidth - 6, (height - iconHeight) / 2);
}
/**
* Returns true if the specified mouse event is positioned over the reset
* icon.
*/
private boolean isIconLocation(MouseEvent e) {
// Get mouse and icon locations.
Point mouseLocation = e.getPoint();
Point iconLocation = getIconLocation(e.getComponent().getWidth(), e.getComponent().getHeight());
int iconWidth = resetIcon.getIconWidth();
int iconHeight = resetIcon.getIconHeight();
// Return true if mouse is within icon boundaries.
if ((mouseLocation.x >= iconLocation.x) &&
(mouseLocation.x <= iconLocation.x + iconWidth) &&
(mouseLocation.y >= iconLocation.y) &&
(mouseLocation.y <= iconLocation.y + iconHeight)) {
return true;
} else {
return false;
}
}
/**
* Sets the reset icon. If the icon is changed, then the painter is
* marked dirty so it will be repainted.
*/
private void setResetIcon(Icon resetIcon) {
if (this.resetIcon != resetIcon) {
this.resetIcon = resetIcon;
setDirty(true);
}
}
/**
* Updates the painter based on the content in the specified document.
*/
private void updatePainter(Document document) {
setFillPaint((document.getLength() == 0) ? Color.WHITE : fillColor);
showIcon = (document.getLength() != 0);
// Restore inactive icon when text cleared.
if (!showIcon) {
setResetIcon(inactiveResetIcon);
}
}
/**
* Listener to handle mouse events on the text field.
*/
private class ResetMouseListener extends MouseAdapter {
/**
* Handles mouse moved event to update the mouse cursor and reset icon.
*/
@Override
public void mouseMoved(MouseEvent e) {
JTextField textField = (JTextField) e.getSource();
if (showIcon) {
// Update cursor and icon based on mouse position.
if (isIconLocation(e)) {
textField.setCursor(Cursor.getDefaultCursor());
setResetIcon(activeResetIcon);
} else {
textField.setCursor(defaultCursor);
setResetIcon(inactiveResetIcon);
}
// Request repaint to draw icon.
textField.repaint();
} else if (textField.getCursor() != defaultCursor) {
textField.setCursor(defaultCursor);
}
}
/**
* Handles mouse clicked event to clear filter text.
*/
@Override
public void mouseClicked(MouseEvent e) {
if (showIcon && isIconLocation(e)) {
((JTextField) e.getSource()).setText(null);
}
}
}
}