001/* 002 * $Id: AutoComplete.java 4051 2011-07-19 20:17:05Z kschaefe $ 003 * 004 * Copyright 2010 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.autocomplete; 022 023import static org.jdesktop.swingx.autocomplete.AutoCompleteDecorator.createAutoCompleteDocument; 024import static org.jdesktop.swingx.autocomplete.AutoCompleteDecorator.decorate; 025import static org.jdesktop.swingx.autocomplete.AutoCompleteDecorator.undecorate; 026 027import java.awt.event.ActionEvent; 028import java.awt.event.FocusEvent; 029import java.awt.event.KeyEvent; 030import java.awt.event.KeyListener; 031import java.beans.PropertyChangeEvent; 032 033import javax.swing.Action; 034import javax.swing.JComboBox; 035import javax.swing.text.JTextComponent; 036 037/** 038 * 039 * @author kschaefer 040 */ 041final class AutoComplete { 042 static class InputMap extends javax.swing.InputMap { 043 private static final long serialVersionUID = 1L; 044 } 045 046 static class FocusAdapter extends java.awt.event.FocusAdapter { 047 private AbstractAutoCompleteAdaptor adaptor; 048 049 public FocusAdapter(AbstractAutoCompleteAdaptor adaptor) { 050 this.adaptor = adaptor; 051 } 052 053 @Override 054 public void focusGained(FocusEvent e) { 055 adaptor.markEntireText(); 056 } 057 } 058 059 static class KeyAdapter extends java.awt.event.KeyAdapter { 060 private JComboBox comboBox; 061 062 public KeyAdapter(JComboBox comboBox) { 063 this.comboBox = comboBox; 064 } 065 066 @Override 067 public void keyPressed(KeyEvent keyEvent) { 068 // don't popup on action keys (cursor movements, etc...) 069 if (keyEvent.isActionKey()) { 070 return; 071 } 072 073 // don't popup if the combobox isn't visible anyway 074 if (comboBox.isDisplayable() && !comboBox.isPopupVisible()) { 075 int keyCode = keyEvent.getKeyCode(); 076 // don't popup when the user hits shift,ctrl or alt 077 if (keyCode==KeyEvent.VK_SHIFT || keyCode==KeyEvent.VK_CONTROL || keyCode==KeyEvent.VK_ALT) return; 078 // don't popup when the user hits escape (see issue #311) 079 if (keyCode==KeyEvent.VK_ENTER || keyCode==KeyEvent.VK_ESCAPE) return; 080 comboBox.setPopupVisible(true); 081 } 082 } 083 } 084 085 static class PropertyChangeListener implements java.beans.PropertyChangeListener { 086 private JComboBox comboBox; 087 088 public PropertyChangeListener(JComboBox comboBox) { 089 this.comboBox = comboBox; 090 } 091 092 /** 093 * {@inheritDoc} 094 */ 095 @Override 096 @SuppressWarnings("nls") 097 public void propertyChange(PropertyChangeEvent evt) { 098 if ("editor".equals(evt.getPropertyName())) { 099 handleEditor(evt); 100 } else if ("enabled".equals(evt.getPropertyName())) { 101 handleEnabled(evt); 102 } 103 } 104 105 private void handleEnabled(PropertyChangeEvent evt) { 106 if (Boolean.TRUE.equals(evt.getNewValue())) { 107 comboBox.setEditable(true); 108 } else { 109 JTextComponent textComponent = (JTextComponent) comboBox.getEditor().getEditorComponent(); 110 boolean strictMatching = ((AutoCompleteDocument) textComponent.getDocument()).strictMatching; 111 112 comboBox.setEditable(!strictMatching); 113 } 114 } 115 116 private void handleEditor(PropertyChangeEvent evt) { 117 if (evt.getNewValue() instanceof AutoCompleteComboBoxEditor) { 118 return; 119 } 120 121 AutoCompleteComboBoxEditor acEditor = (AutoCompleteComboBoxEditor) evt.getOldValue(); 122 boolean strictMatching = false; 123 124 if (acEditor.getEditorComponent() != null) { 125 JTextComponent textComponent = (JTextComponent) acEditor.getEditorComponent(); 126 strictMatching = ((AutoCompleteDocument) textComponent.getDocument()).strictMatching; 127 128 undecorate(textComponent); 129 130 for (KeyListener l : textComponent.getKeyListeners()) { 131 if (l instanceof KeyAdapter) { 132 textComponent.removeKeyListener(l); 133 break; 134 } 135 } 136 } 137 138 JTextComponent editorComponent = (JTextComponent) comboBox.getEditor().getEditorComponent(); 139 AbstractAutoCompleteAdaptor adaptor = new ComboBoxAdaptor(comboBox); 140 AutoCompleteDocument document = createAutoCompleteDocument(adaptor, strictMatching, 141 acEditor.stringConverter, editorComponent.getDocument()); 142 decorate(editorComponent, document, adaptor); 143 144 editorComponent.addKeyListener(new AutoComplete.KeyAdapter(comboBox)); 145 146 //set before adding the listener for the editor 147 comboBox.setEditor(new AutoCompleteComboBoxEditor(comboBox.getEditor(), document.stringConverter)); 148 } 149 } 150 151 static class SelectionAction implements Action { 152 private Action delegate; 153 154 public SelectionAction(Action delegate) { 155 this.delegate = delegate; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override 162 public void actionPerformed(ActionEvent e) { 163 JComboBox comboBox = (JComboBox) e.getSource(); 164 JTextComponent textComponent = (JTextComponent) comboBox.getEditor().getEditorComponent(); 165 AutoCompleteDocument doc = (AutoCompleteDocument) textComponent.getDocument(); 166 167 // doing this prevents the updating of the selected item to "" during the remove prior 168 // to the insert in JTextComponent.setText 169 doc.strictMatching = true; 170 try { 171 delegate.actionPerformed(e); 172 } finally { 173 doc.strictMatching = false; 174 } 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) { 182 delegate.addPropertyChangeListener(listener); 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) { 190 delegate.removePropertyChangeListener(listener); 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override 197 public Object getValue(String key) { 198 return delegate.getValue(key); 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override 205 public void putValue(String key, Object value) { 206 delegate.putValue(key, value); 207 } 208 209 /** 210 * {@inheritDoc} 211 */ 212 @Override 213 public boolean isEnabled() { 214 return delegate.isEnabled(); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public void setEnabled(boolean b) { 222 delegate.setEnabled(b); 223 } 224 } 225 226 private AutoComplete() { 227 // prevent instantiation 228 } 229}