Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2005-2006 Laf-Widget Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Laf-Widget Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jvnet.lafwidget.combo;
import java.awt.Component;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.text.*;
import org.jvnet.lafwidget.LafWidgetAdapter;
import org.jvnet.lafwidget.LafWidgetUtilities;
/**
* Adds auto-completion on editable combo boxes.
*
* @author Kirill Grouchnikov
* @author Thomas Bierhance http://www.orbital-computer.de/JComboBox/
* @author inostock
* @author Daniel Kjellin http://www.daik.se/
*/
public class ComboboxAutoCompletionWidget extends LafWidgetAdapter {
protected JComboBox comboBox;
/**
* Property change handler on enabled property.
*/
protected ComboBoxPropertyChangeHandler changeHandler;
protected ComboBoxModel model;
protected Component editor;
// flag to indicate if setSelectedItem has been called
// subsequent calls to remove/insertString should be ignored
protected boolean selecting = false;
protected boolean hidePopupOnFocusLoss;
protected boolean hitBackspace = false;
protected boolean hitBackspaceOnSelection;
protected ActionListener completionActionListener;
protected PropertyChangeListener completionPropertyListener;
protected KeyListener editorKeyListener;
protected FocusListener editorFocusListener;
protected CompletionPlainDocument completionDocument;
protected ActionMap oldActionMap;
/**
* Code contributed by Thomas Bierhance from
* http://www.orbital-computer.de/JComboBox/
*/
protected class CompletionPlainDocument extends PlainDocument {
protected JComboBox comboBox;
protected ComboBoxModel model;
public CompletionPlainDocument(JComboBox combo) {
super();
this.comboBox = combo;
this.model = this.comboBox.getModel();
}
public void remove(int offs, int len) throws BadLocationException {
// return immediately when selecting an item
if (ComboboxAutoCompletionWidget.this.selecting)
return;
if (ComboboxAutoCompletionWidget.this.hitBackspace) {
// user hit backspace => move the selection backwards
// old item keeps being selected
if (offs > 0) {
if (ComboboxAutoCompletionWidget.this.hitBackspaceOnSelection)
offs--;
} else {
// User hit backspace with the cursor positioned on the
// start => beep
this.comboBox.getToolkit().beep(); // when available use:
// UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
}
this.highlightCompletedText(offs);
} else {
super.remove(offs, len);
}
}
public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
// return immediately when selecting an item
if (ComboboxAutoCompletionWidget.this.selecting)
return;
// insert the string into the document
super.insertString(offs, str, a);
// lookup and select a matching item
Object item = this.lookupItem(this.getText(0, this.getLength()));
if (LafWidgetUtilities.hasUseModelOnlyProperty(this.comboBox)) {
if (item != null) {
this.setSelectedItem(item);
} else {
// keep old item selected if there is no match
item = this.comboBox.getSelectedItem();
// imitate no insert (later on offs will be incremented by
// str.length(): selection won't move forward)
offs = offs - str.length();
// provide feedback to the user that his input has been
// received but can not be accepted
this.comboBox.getToolkit().beep();
}
this.setText(item.toString());
// select the completed part
this.highlightCompletedText(offs + str.length());
} else {
if (item != null) {
this.setSelectedItem(item);
this.setText(item.toString());
// select the completed part
this.highlightCompletedText(offs + str.length());
} else {
offs = offs - str.length();
}
}
}
private void setText(String text) {
try {
// remove all text and insert the completed string
super.remove(0, this.getLength());
super.insertString(0, text, null);
} catch (BadLocationException e) {
throw new RuntimeException(e.toString());
}
}
private void highlightCompletedText(int start) {
if (ComboboxAutoCompletionWidget.this.editor instanceof JTextComponent) {
JTextComponent textEditor = (JTextComponent) ComboboxAutoCompletionWidget.this.editor;
// Fix for defect 2 (defect 151 on Substance) by Daniel Kjellin
textEditor.setCaretPosition(textEditor.getDocument()
.getLength());
textEditor.moveCaretPosition(start);
}
}
private void setSelectedItem(Object item) {
ComboboxAutoCompletionWidget.this.selecting = true;
this.model.setSelectedItem(item);
ComboboxAutoCompletionWidget.this.selecting = false;
}
private Object lookupItem(String pattern) {
Object selectedItem = this.model.getSelectedItem();
// only search for a different item if the currently selected does
// not match
if ((selectedItem != null)
&& this.startsWithIgnoreCase(selectedItem.toString(),
pattern)) {
return selectedItem;
} else {
// iterate over all items
for (int i = 0, n = this.model.getSize(); i < n; i++) {
Object currentItem = this.model.getElementAt(i);
// current item starts with the pattern?
if ((currentItem != null)
&& this.startsWithIgnoreCase(
currentItem.toString(), pattern)) {
return currentItem;
}
}
}
// no item starts with the pattern => return null
return null;
}
// checks if str1 starts with str2 - ignores case
private boolean startsWithIgnoreCase(String str1, String str2) {
return str1.toUpperCase().startsWith(str2.toUpperCase());
}
}
public boolean isSimple() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.jvnet.lafwidget.LafWidgetAdapter#setComponent(javax.swing.JComponent)
*/
public void setComponent(JComponent jcomp) {
super.setComponent(jcomp);
this.comboBox = (JComboBox) jcomp;
}
/*
* (non-Javadoc)
*
* @see org.jvnet.lafwidget.LafWidgetAdapter#installUI()
*/
public void installUI() {
final ComboBoxEditor cbe = this.comboBox.getEditor();
final Component cbc = cbe.getEditorComponent();
if (cbc instanceof JTextComponent) {
this.installTextEditor((JTextComponent) cbc);
} else {
this.installEditor(cbc);
}
}
/*
* (non-Javadoc)
*
* @see org.jvnet.lafwidget.LafWidgetAdapter#installListeners()
*/
public void installListeners() {
this.changeHandler = new ComboBoxPropertyChangeHandler();
this.comboBox.addPropertyChangeListener(this.changeHandler);
}
protected void installTextEditor(final JTextComponent c) {
// Code contributed by Thomas Bierhance from
// http://www.orbital-computer.de/JComboBox/
if (this.comboBox.isEditable()) {
this.completionDocument = new CompletionPlainDocument(this.comboBox);
c.setDocument(this.completionDocument);
this.model = this.comboBox.getModel();
this.completionActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if ((!ComboboxAutoCompletionWidget.this.selecting)
&& (ComboboxAutoCompletionWidget.this.completionDocument != null))
ComboboxAutoCompletionWidget.this.completionDocument
.highlightCompletedText(0);
}
};
this.comboBox.addActionListener(this.completionActionListener);
this.completionPropertyListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
// if (e.getPropertyName().equals("editor"))
// configureEditor((ComboBoxEditor) e.getNewValue());
if (e.getPropertyName().equals("model"))
ComboboxAutoCompletionWidget.this.model = (ComboBoxModel) e
.getNewValue();
}
};
this.comboBox
.addPropertyChangeListener(this.completionPropertyListener);
this.editorKeyListener = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
// BasicComboBoxUI ui = null;
// if (comboBox.getUI() instanceof BasicComboBoxUI)
// ui = (BasicComboBoxUI) comboBox.getUI();
// boolean wasPopupVisible = ComboboxAutoCompletionWidget.this.comboBox
// .isPopupVisible();
if (ComboboxAutoCompletionWidget.this.comboBox
.isDisplayable()
&& (e.getKeyCode() != KeyEvent.VK_ENTER)) {
ComboboxAutoCompletionWidget.this.comboBox
.setPopupVisible(true);
}
ComboboxAutoCompletionWidget.this.hitBackspace = false;
switch (e.getKeyCode()) {
// determine if the pressed key is backspace (needed by the
// remove method)
case KeyEvent.VK_BACK_SPACE:
ComboboxAutoCompletionWidget.this.hitBackspace = true;
ComboboxAutoCompletionWidget.this.hitBackspaceOnSelection = ((JTextField) ComboboxAutoCompletionWidget.this.editor)
.getSelectionStart() != ((JTextField) ComboboxAutoCompletionWidget.this.editor)
.getSelectionEnd();
break;
case KeyEvent.VK_DELETE:
if (LafWidgetUtilities
.hasUseModelOnlyProperty(ComboboxAutoCompletionWidget.this.comboBox)) {
// ignore delete key on model-only combos
e.consume();
ComboboxAutoCompletionWidget.this.comboBox
.getToolkit().beep();
} else {
((JTextField) ComboboxAutoCompletionWidget.this.editor)
.replaceSelection("");
}
break;
// case KeyEvent.VK_PAGE_UP:
// case KeyEvent.VK_PAGE_DOWN:
// int index = getNextIndex(comboBox, e.getKeyCode());
// if (index >= 0 && index < comboBox.getItemCount()) {
// comboBox.setSelectedIndex(index);
// }
// break;
// case KeyEvent.VK_UP:
// if (comboBox.isShowing()) {
// if (wasPopupVisible) {
// int prevIndex = comboBox.getSelectedIndex() - 1;
// if (prevIndex >= 0)
// comboBox.setSelectedIndex(prevIndex);
// }
// }
// break;
// case KeyEvent.VK_DOWN:
// if (comboBox.isShowing()) {
// if (wasPopupVisible) {
// int nextIndex = comboBox.getSelectedIndex() + 1;
// if (nextIndex < comboBox.getItemCount())
// comboBox.setSelectedIndex(nextIndex);
// }
// }
// break;
case KeyEvent.VK_ESCAPE:
// forward to the parent - allows closing dialogs
// with editable combos having focus.
ComboboxAutoCompletionWidget.this.comboBox.getParent()
.dispatchEvent(e);
}
}
};
// Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when
// tabbing out
this.hidePopupOnFocusLoss = System.getProperty("java.version")
.startsWith("1.5");
// Highlight whole text when gaining focus
this.editorFocusListener = new FocusAdapter() {
public void focusGained(FocusEvent e) {
if (ComboboxAutoCompletionWidget.this.completionDocument != null)
ComboboxAutoCompletionWidget.this.completionDocument
.highlightCompletedText(0);
}
public void focusLost(FocusEvent e) {
// Workaround for Bug 5100422 - Hide Popup on focus loss
if (ComboboxAutoCompletionWidget.this.hidePopupOnFocusLoss
&& (ComboboxAutoCompletionWidget.this.comboBox != null))
ComboboxAutoCompletionWidget.this.comboBox
.setPopupVisible(false);
}
};
// configureEditor(comboBox.getEditor());
this.installEditor(c);
// Handle initially selected object
Object selected = this.comboBox.getSelectedItem();
if (this.completionDocument != null) {
if (selected != null)
this.completionDocument.setText(selected.toString());
this.completionDocument.highlightCompletedText(0);
}
}
}
/*
* (non-Javadoc)
*
* @see org.jvnet.lafwidget.LafWidgetAdapter#uninstallListeners()
*/
public void uninstallListeners() {
this.comboBox.removePropertyChangeListener(this.changeHandler);
this.changeHandler = null;
if (this.comboBox.isEditable()) {
this.uninstallTextEditor(null);
}
super.uninstallListeners();
}
protected void uninstallTextEditor(final JTextComponent e) {
this.completionDocument = null;
this.comboBox.removeActionListener(this.completionActionListener);
this.completionActionListener = null;
this.comboBox
.removePropertyChangeListener(this.completionPropertyListener);
this.completionPropertyListener = null;
if (e == null)
return;
if (this.editorKeyListener != null) {
e.removeKeyListener(this.editorKeyListener);
this.editorKeyListener = null;
}
if (this.editorFocusListener != null) {
e.removeFocusListener(this.editorFocusListener);
this.editorFocusListener = null;
}
if (this.oldActionMap != null) {
this.comboBox.setActionMap(this.oldActionMap);
this.oldActionMap = null;
}
}
protected void installEditor(final Component c) {
if ((c == null) || (this.editor == c))
return;
final Component last = this.editor;
if (last != null) {
last.removeKeyListener(this.editorKeyListener);
last.removeFocusListener(this.editorFocusListener);
}
this.editor = c;
this.editor.addKeyListener(this.editorKeyListener);
this.editor.addFocusListener(this.editorFocusListener);
if (this.oldActionMap == null) {
// due to the implementation in BasicComboBoxUI (the
// same action map for all combos) we need to
// create a new action map
this.oldActionMap = this.comboBox.getActionMap();
ActionMap newActionMap = new ActionMap();
Object[] keys = this.oldActionMap.allKeys();
for (int i = 0; i < keys.length; i++) {
if ("enterPressed".equals(keys[i]))
continue;
newActionMap.put(keys[i], this.oldActionMap.get(keys[i]));
}
this.comboBox.setActionMap(newActionMap);
}
}
public class ComboBoxPropertyChangeHandler implements
PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if (propertyName.equals("editable")) {
final boolean oldValue = ((Boolean) e.getOldValue())
.booleanValue();
final boolean newValue = ((Boolean) e.getNewValue())
.booleanValue();
if (!oldValue && newValue) {
final ComboBoxEditor cbe = ComboboxAutoCompletionWidget.this.comboBox
.getEditor();
final Component cbc = cbe.getEditorComponent();
if (cbc instanceof JTextComponent) {
ComboboxAutoCompletionWidget.this
.installTextEditor((JTextComponent) cbc);
} else {
ComboboxAutoCompletionWidget.this.installEditor(cbc);
}
} else if (oldValue && !newValue) {
ComboboxAutoCompletionWidget.this.uninstallTextEditor(null);
}
}
// fix for defect 131 in 2.2_01
if (propertyName.equals("editor")) {
final ComboBoxEditor oldValue = (ComboBoxEditor) e
.getOldValue();
final ComboBoxEditor newValue = (ComboBoxEditor) e
.getNewValue();
if ((newValue != null) && (newValue != oldValue)) {
final Component old = (oldValue != null) ? oldValue
.getEditorComponent() : null;
if (old instanceof JTextComponent) {
ComboboxAutoCompletionWidget.this
.uninstallTextEditor((JTextComponent) old);
}
final Component pending = newValue.getEditorComponent();
if (pending instanceof JTextComponent) {
ComboboxAutoCompletionWidget.this
.installTextEditor((JTextComponent) pending);
} else {
ComboboxAutoCompletionWidget.this
.installEditor(pending);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ComboboxAutoCompletionWidget.this.comboBox
.doLayout();
}
});
}
}
// fix for defect 6 - changing model on editable combo doesn't
// track changes to the model
if (propertyName.equals("model")) {
if (ComboboxAutoCompletionWidget.this.comboBox.isEditable()) {
ComboboxAutoCompletionWidget.this.uninstallTextEditor(null);
final ComboBoxEditor cbe = ComboboxAutoCompletionWidget.this.comboBox
.getEditor();
final Component cbc = cbe.getEditorComponent();
if (cbc instanceof JTextComponent) {
ComboboxAutoCompletionWidget.this
.installTextEditor((JTextComponent) cbc);
} else {
ComboboxAutoCompletionWidget.this.installEditor(cbc);
}
}
}
// Do not call super - fix for bug 63
}
}
/*
* (non-Javadoc)
*
* @see org.jvnet.lafwidget.LafWidget#requiresCustomLafSupport()
*/
public boolean requiresCustomLafSupport() {
return false;
}
//
// private int getNextIndex(JComboBox comboBox, int keyIndex) {
// if (keyIndex == KeyEvent.VK_PAGE_UP) {
// int listHeight = comboBox.getMaximumRowCount();
// int index = comboBox.getSelectedIndex() - listHeight;
// return (index < 0 ? 0 : index);
// } else if (keyIndex == KeyEvent.VK_PAGE_DOWN) {
// int listHeight = comboBox.getMaximumRowCount();
// int index = comboBox.getSelectedIndex() + listHeight;
// int max = comboBox.getItemCount();
// return (index < max ? index : max - 1);
// }
// return comboBox.getSelectedIndex();
// }
}