/** * $RCSfile: ,v $ * $Revision: $ * $Date: $ * * Copyright (C) 2004-2011 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.spark.component; import org.jivesoftware.resource.SparkRes; import org.jivesoftware.spark.ui.ContactItem; import org.jivesoftware.spark.util.ModelUtil; import javax.swing.DefaultListModel; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JWindow; import javax.swing.ListCellRenderer; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Point; 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 java.util.ArrayList; import java.util.List; /** * Implementation of a popup field from a TextField. * * @author Derek DeMoro */ public class JContactItemField extends JPanel { private static final long serialVersionUID = -8556694682789891531L; private JTextField textField = new JTextField(); private DefaultListModel model = new DefaultListModel(); private JList list; private JWindow popup; private List<ContactItem> items; public JContactItemField(List<ContactItem> items) { setLayout(new BorderLayout()); list = new JList(model) { private static final long serialVersionUID = -9031169221430835595L; public String getToolTipText(MouseEvent e) { int row = locationToIndex(e.getPoint()); if (row >= 0) { final ContactItem item = (ContactItem)getModel().getElementAt(row); if (item != null) { return item.getJID(); } } return null; } }; this.items = items; add(textField, BorderLayout.CENTER); textField.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent keyEvent) { char ch = keyEvent.getKeyChar(); if (validateChar(ch)) { showPopupMenu(); } if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) { int index = list.getSelectedIndex(); if (index >= 0) { ContactItem selection = (ContactItem)list.getSelectedValue(); textField.setText(selection.getDisplayName()); popup.setVisible(false); } } if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE) { popup.setVisible(false); } dispatchEvent(keyEvent); } public void keyPressed(KeyEvent e) { if (isArrowKey(e)) { list.dispatchEvent(e); } } }); textField.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { } public void focusLost(FocusEvent e) { textField.requestFocusInWindow(); } }); popup = new JWindow(); popup.getContentPane().add(new JScrollPane(list)); popup.setAlwaysOnTop(true); list.setCellRenderer(new PopupRenderer()); list.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { int index = list.getSelectedIndex(); if (index >= 0) { ContactItem selection = (ContactItem)list.getSelectedValue(); textField.setText(selection.getDisplayName()); popup.setVisible(false); } } } }); } public void dispose() { popup.dispose(); } public void setItems(List<ContactItem> list) { this.items = list; } public JList getList() { return list; } private void showPopupMenu() { model.removeAllElements(); String typedItem = textField.getText(); final List<ContactItem> validItems = new ArrayList<ContactItem>(); for (ContactItem contactItem : items) { String nickname = contactItem.getDisplayName().toLowerCase(); if (nickname.startsWith(typedItem.toLowerCase())) { validItems.add(contactItem); } else if (typedItem.length() > 2 && nickname.contains(typedItem.toLowerCase())) { validItems.add(contactItem); } } if (validItems.size() > 0) { for (final ContactItem label : validItems) { model.addElement(label); } } if (validItems.size() != 0 && !popup.isVisible()) { popup.pack(); popup.setSize(textField.getWidth(), 200); Point pt = textField.getLocationOnScreen(); pt.translate(0, textField.getHeight()); popup.setLocation(pt); popup.toFront(); popup.setVisible(true); } // set initial selection if (validItems.size() > 0) { list.setSelectedIndex(0); } } /** * Validate the given text - to pass it must contain letters, digits, '@', '-', '_', '.', ',' * or a space character. * * @param text the text to check * @return true if the given text is valid, false otherwise. */ public boolean validateChars(String text) { if (!ModelUtil.hasLength(text)) { return false; } for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); if (!Character.isLetterOrDigit(ch) && ch != '@' && ch != '-' && ch != '_' && ch != '.' && ch != ',' && ch != ' ') { return false; } } return true; } /** * Validate the given text - to pass it must contain letters, digits, '@', '-', '_', '.', ',' * or a space character. * * @param ch the character * @return true if the given text is valid, false otherwise. */ public boolean validateChar(char ch) { if (!Character.isLetterOrDigit(ch) && ch != '@' && ch != '-' && ch != '_' && ch != '.' && ch != ',' && ch != ' ' && ch != KeyEvent.VK_BACK_SPACE && ch != KeyEvent.CTRL_DOWN_MASK && ch != KeyEvent.CTRL_MASK) { return false; } return true; } public boolean isArrowKey(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) { return true; } return false; } public String getText() { return textField.getText(); } public ContactItem getSelectedContactItem() { return (ContactItem)list.getSelectedValue(); } public void setText(String text) { textField.setText(text); } public void focus() { textField.requestFocus(); } public JTextField getTextField() { return textField; } public JWindow getPopup() { return popup; } class PopupRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 239608430590852355L; /** * Construct Default JLabelIconRenderer. */ public PopupRenderer() { setOpaque(true); this.setHorizontalTextPosition(JLabel.RIGHT); this.setHorizontalAlignment(JLabel.LEFT); } public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } ContactItem contactItem = (ContactItem)value; setText(contactItem.getDisplayName()); if (contactItem.getIcon() == null) { setIcon(SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON)); } else { setIcon(contactItem.getIcon()); } setFont(contactItem.getNicknameLabel().getFont()); setForeground(contactItem.getForeground()); return this; } } public boolean canClose() { return !textField.hasFocus(); } /** * sets the selected Index using the Point of a given {@link MouseEvent} * @param mouseevent - {@link MouseEvent} to get The {@link Point} from */ public void setSelectetIndex(MouseEvent mouseevent) { list.setSelectedIndex(list.locationToIndex(mouseevent.getPoint())); } }