// SearchWidget
package org.javamoney.examples.ez.common.gui;
import static org.javamoney.examples.ez.common.CommonIconKeys.SEARCH;
import static org.javamoney.examples.ez.common.CommonIconKeys.SEARCH_CLEAR;
import static org.javamoney.examples.ez.common.CommonIconKeys.SEARCH_CLEAR_PRESSED;
import static org.javamoney.examples.ez.common.CommonIconKeys.SEARCH_NO_TEXT;
import static org.javamoney.examples.ez.common.CommonIconKeys.SEARCH_WITH_MENU;
import static java.awt.event.InputEvent.CTRL_DOWN_MASK;
import static java.awt.event.KeyEvent.CHAR_UNDEFINED;
import static java.awt.event.KeyEvent.VK_BACK_SPACE;
import static java.awt.event.KeyEvent.VK_DOWN;
import static java.awt.event.KeyEvent.VK_LEFT;
import static java.awt.event.KeyEvent.VK_RIGHT;
import static java.awt.event.KeyEvent.VK_UP;
import static java.awt.event.MouseEvent.BUTTON1;
import static java.lang.Character.isISOControl;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.SoftBevelBorder;
import org.javamoney.examples.ez.common.utility.ActionSignaler;
import org.javamoney.examples.ez.common.utility.ClipboardMenuController;
/**
* This class facilitates providing a basic search tool to be used in the UI.
*/
public
final
class
SearchWidget
extends Panel
{
/**
* Constructs a new search widget.
*/
public
SearchWidget()
{
this(null);
}
/**
* Constructs a new search widget.
*
* @param menu The menu that will handle the mouse clicks on the menu icon.
*/
public
SearchWidget(PopupMenu menu)
{
setActionSignaler(new ActionSignaler());
setField(new SearchField());
createLabels();
buildPanel(menu != null);
// Add listeners.
new ClipboardMenuController(getField());
getField().addFocusListener(new FocusHandler());
getField().addKeyListener(new KeyHandler());
getLabels()[LEFT_LABEL].addMouseListener(new MouseHandler());
getLabels()[RIGHT_LABEL].addMouseListener(new MouseHandler());
if(menu != null)
{
getLabels()[LEFT_LABEL].addMouseListener(menu);
}
}
/**
* This method adds the action listener to the widget.
*
* @param listener The action listener to add.
*/
public
void
addActionListener(ActionListener listener)
{
getActionSignaler().addListener(listener);
}
/**
* This method returns the text in the search field.
*
* @return The text in the search field.
*/
public
String
getSearchText()
{
return getField().getText();
}
/**
* This method returns true if the widget has focus, otherwise false.
*
* @return true or false.
*/
@Override
public
boolean
hasFocus()
{
return getField().hasFocus();
}
/**
* This method requests that the search field gets the input focus.
*/
@Override
public
void
requestFocus()
{
getField().requestFocus();
}
/**
* This method sets the text displayed in the search field.
*
* @param text The text displayed in the search field.
*/
public
void
setSearchText(String text)
{
getField().setText(text);
setRightIcon();
sendSignal();
}
/**
* This method sets the tool tip for the widget.
*
* @param tip The message to display.
*/
@Override
public
void
setToolTipText(String tip)
{
getField().setToolTipText(tip);
getLabels()[LEFT_LABEL].setToolTipText(tip);
getLabels()[RIGHT_LABEL].setToolTipText(tip);
}
//////////////////////////////////////////////////////////////////////////////
// Start of private methods.
//////////////////////////////////////////////////////////////////////////////
private
void
buildPanel(boolean useMenu)
{
// Build panel.
setFill(GridBagConstraints.HORIZONTAL);
add(getLabels()[LEFT_LABEL], 0, 0, 1, 1, 0, 100);
add(getField(), 1, 0, 1, 1, 100, 0);
add(getLabels()[RIGHT_LABEL], 2, 0, 1, 1, 0, 0);
setBackground(getField().getBackground());
setBorder(NORMAL);
getField().setBorder(null);
getField().setColumns(12);
if(useMenu == true)
{
getLabels()[LEFT_LABEL].setIcon(SEARCH_WITH_MENU.getIcon());
}
else
{
getLabels()[LEFT_LABEL].setIcon(SEARCH.getIcon());
}
getLabels()[RIGHT_LABEL].setIcon(SEARCH_NO_TEXT.getIcon());
}
private
void
createLabels()
{
itsLabels = new JLabel[2];
getLabels()[LEFT_LABEL] = new JLabel();
getLabels()[RIGHT_LABEL] = new JLabel();
}
private
ActionSignaler
getActionSignaler()
{
return itsActionSignaler;
}
private
JTextField
getField()
{
return itsField;
}
private
JLabel[]
getLabels()
{
return itsLabels;
}
private
static
boolean
isValidKey(int key)
{
boolean result = false;
// Control keys (except the back space) and arrow keys are invalid.
if(key != CHAR_UNDEFINED)
{
if(isISOControl(key) == false || key == VK_BACK_SPACE)
{
if(key != VK_LEFT && key != VK_RIGHT && key != VK_UP && key != VK_DOWN)
{
result = true;
}
}
}
return result;
}
private
void
setActionSignaler(ActionSignaler signaler)
{
itsActionSignaler = signaler;
}
private
void
sendSignal()
{
getActionSignaler().sendSignal(this, ACTION_COMMAND);
}
private
void
setField(SearchField field)
{
itsField = field;
}
private
void
setRightIcon()
{
// Set the right icon according to the text in the field.
if(getField().getText().length() == 0)
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_NO_TEXT.getIcon());
}
else
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_CLEAR.getIcon());
}
}
//////////////////////////////////////////////////////////////////////////////
// Start of inner classes.
//////////////////////////////////////////////////////////////////////////////
private
class
FocusHandler
implements FocusListener
{
public
void
focusGained(FocusEvent event)
{
setRightIcon();
setBorder(FOCUS);
}
public
void
focusLost(FocusEvent event)
{
// The clear icon is not visible when the text field does not have focus.
if(getLabels()[RIGHT_LABEL].getIcon() != SEARCH_NO_TEXT.getIcon())
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_NO_TEXT.getIcon());
}
setBorder(NORMAL);
}
}
private
class
KeyHandler
extends KeyAdapter
{
@Override
public
void
keyReleased(KeyEvent event)
{
int key = event.getKeyCode();
if(isValidKey(key) == true)
{
setRightIcon();
sendSignal();
}
}
}
private
class
MouseHandler
extends MouseAdapter
{
@Override
public
void
mouseClicked(MouseEvent event)
{
if(event.getSource() == getLabels()[RIGHT_LABEL])
{
if(event.getModifiersEx() != CTRL_DOWN_MASK && event.getButton() == BUTTON1)
{
// Clear the search field.
if(getField().hasFocus() == true)
{
setSearchText("");
}
}
}
else
{
getField().requestFocus();
}
}
@Override
public
void
mousePressed(MouseEvent event)
{
if(event.getSource() == getLabels()[RIGHT_LABEL] && event.getButton() == BUTTON1)
{
// Icons are only displayed on the right when the text field has focus.
if(getField().hasFocus() == true)
{
if(getLabels()[RIGHT_LABEL].getIcon() == SEARCH_CLEAR.getIcon())
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_CLEAR_PRESSED.getIcon());
}
}
}
}
@Override
public
void
mouseReleased(MouseEvent event)
{
if(event.getSource() == getLabels()[RIGHT_LABEL] && event.getButton() == BUTTON1)
{
// Icons are only displayed on the right when the text field has focus.
if(getField().hasFocus() == true)
{
// The user clicked the clear button, but released the mouse elsewhere.
if(getField().getBounds().contains(event.getPoint()) == false)
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_CLEAR.getIcon());
}
}
}
}
}
private
class
SearchField
extends JTextField
{
@Override
public
void
cut()
{
super.cut();
setRightIcon();
sendSignal();
}
@Override
public
void
paste()
{
super.paste();
// Its safe to assume a paste action will require the clear icon.
if(getLabels()[RIGHT_LABEL].getIcon() != SEARCH_CLEAR.getIcon())
{
getLabels()[RIGHT_LABEL].setIcon(SEARCH_CLEAR.getIcon());
}
sendSignal();
}
}
//////////////////////////////////////////////////////////////////////////////
// Start of class members.
//////////////////////////////////////////////////////////////////////////////
private ActionSignaler itsActionSignaler;
private SearchField itsField;
private JLabel[] itsLabels;
private static final int LEFT_LABEL = 0;
private static final int RIGHT_LABEL = 1;
private static final String ACTION_COMMAND = SearchWidget.class.getSimpleName();
// Borders used for widget.
private static Border BEVEL_FOCUS = new SoftBevelBorder(BevelBorder.LOWERED,
new Color(185, 211, 234),
new Color(220, 233, 244),
new Color(158, 184, 207),
new Color(220, 233, 244));
private static Border FOCUS = new CompoundBorder(
new LineBorder(new Color(144, 183, 217), 1, true),
BEVEL_FOCUS);
private static Border NORMAL = new CompoundBorder(
new LineBorder(new Panel().getBackground(), 1, true),
new SoftBevelBorder(BevelBorder.LOWERED));
}