001 /* 002 * Copyright 2002-2005 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.richclient.list; 017 018 import java.awt.event.FocusEvent; 019 import java.awt.event.FocusListener; 020 import java.awt.event.KeyAdapter; 021 import java.awt.event.KeyEvent; 022 023 import javax.swing.JComboBox; 024 import javax.swing.JTextField; 025 026 /** 027 * Provides auto-completion for an editable combobox. Based on public domain postings. 028 * Original author unknown. Also copied some code from {@link ComboBoxAutoCompletion} 029 * to deal with focus loss. 030 * 031 * @author Larry Streepy 032 * 033 */ 034 public class EditableComboBoxAutoCompletion extends KeyAdapter { 035 036 private final FocusHandler focusHandler = new FocusHandler(); 037 038 private final JComboBox comboBox; 039 040 private final JTextField editor; 041 042 /** 043 * Adds autocompletion support to the given <code>combobox</code>. 044 * 045 * @param comboBox the combobox to augment 046 */ 047 public EditableComboBoxAutoCompletion(JComboBox comboBox) { 048 this.comboBox = comboBox; 049 editor = (JTextField)comboBox.getEditor().getEditorComponent(); 050 editor.addKeyListener(this); 051 editor.addFocusListener(focusHandler); 052 } 053 054 /** 055 * Handle a key release event. See if what they've type so far matches anything in the 056 * selectable items list. If so, then show the popup and select the item. If not, then 057 * hide the popup. 058 * 059 * @param e key event 060 */ 061 public void keyReleased(KeyEvent e) { 062 char ch = e.getKeyChar(); 063 if (ch == KeyEvent.CHAR_UNDEFINED || Character.isISOControl(ch)) 064 return; 065 int pos = editor.getCaretPosition(); 066 String str = editor.getText(); 067 if (str.length() == 0) 068 return; 069 070 boolean matchFound = false; 071 for (int k = 0; k < comboBox.getItemCount(); k++) { 072 String item = comboBox.getItemAt(k).toString(); 073 if (startsWithIgnoreCase(item, str)) { 074 comboBox.setSelectedIndex(k); 075 editor.setText(item); 076 editor.setCaretPosition(item.length()); 077 editor.moveCaretPosition(pos); 078 079 // show popup when the user types 080 if (comboBox.isDisplayable()) 081 comboBox.setPopupVisible(true); 082 083 matchFound = true; 084 break; 085 } 086 } 087 if (!matchFound) { 088 // hide popup when there is no match 089 comboBox.setPopupVisible(false); 090 } 091 } 092 093 /** 094 * See if one string begins with another, ignoring case. 095 * 096 * @param str1 The string to test 097 * @param str2 The prefix to test for 098 * @return true if str1 starts with str2, ingnoring case 099 */ 100 private boolean startsWithIgnoreCase(String str1, String str2) { 101 return str1 != null && str2 != null && str1.toUpperCase().startsWith(str2.toUpperCase()); 102 } 103 104 /** 105 * Highlight the text from the given start location to the end of the text. 106 * 107 * @param start Starting location to highlight 108 */ 109 private void highlightText(int start) { 110 editor.setCaretPosition(editor.getText().length()); 111 editor.moveCaretPosition(start); 112 } 113 114 /** 115 * This class handles focus events to provide a work-around for a java 1.5 bug. 116 */ 117 private final class FocusHandler implements FocusListener { 118 119 // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when 120 // tabbing out 121 private boolean hidePopupOnFocusLoss = System.getProperty("java.version").startsWith("1.5"); 122 123 public void focusGained(FocusEvent e) { 124 // Highlight whole text when gaining focus 125 highlightText(0); 126 } 127 128 public void focusLost(FocusEvent e) { 129 // Workaround for Bug 5100422 - Hide Popup on focus loss 130 if (hidePopupOnFocusLoss) 131 comboBox.setPopupVisible(false); 132 } 133 } 134 }