org.nuiton.widget.JComboBoxAutoCompletionKit Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nuiton-widgets Show documentation
Show all versions of nuiton-widgets Show documentation
Widgets graphiques utiles pour tous les développements.
/* *##% Graphical Widget
* Copyright (C) 2004 - 2008 CodeLutin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* . ##%*/
/* *
* JComboBoxAutoCompletionKit.java
*
* Created: Nov 12, 2004
*
* @author Cédric Pineau
* @version $Revision: 254 $
*
* Last update : $Date: 2010-04-10 01:13:11 +0200 (sam., 10 avril 2010) $
* by : $Author: tchemit $
*/
package org.nuiton.widget;
import java.awt.Component;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
/**
*
*/
public class JComboBoxAutoCompletionKit {
public static void main(String[] args) {
JFrame frame = new JFrame();
String[] petStrings = { "Bird", "Cat", "Cot", "Dog", "Dog", "Dog1",
"Dog2", "Dog3", "Dog4", "Dog5", "Dog6", "Dog7", "Dog", "Dog8",
"Dog9", "Dog10", "Rabbit", "Pig" };
JComboBox combo = new JComboBox(petStrings);
combo.setRenderer(new TestCellRenderer());
JComboBoxAutoCompletionKit.setAutoCompleted(combo);
frame.getContentPane().add(combo);
frame.setSize(800, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void setAutoCompleted(JComboBox comboBox) {
AutoCompletionManager autoCompletionManager = new AutoCompletionManager(
comboBox);
AutoCompletionModelListener autoCompletionModelListener = new AutoCompletionModelListener(
autoCompletionManager);
AutoCompletionCellRenderer autoCompletionCellRenderer = new AutoCompletionCellRenderer(
autoCompletionManager, comboBox.getRenderer());
comboBox.setKeySelectionManager(autoCompletionManager);
comboBox.getModel().addListDataListener(autoCompletionModelListener);
comboBox.setRenderer(autoCompletionCellRenderer);
}
private static class AutoCompletionManager implements
JComboBox.KeySelectionManager {
private static String EMPTY_PREFIX = "";
private static int NO_SELECTION = -1;
private JComboBox _comboBox = null;
private int _currentSelection = NO_SELECTION;
private String _prefix = EMPTY_PREFIX;
public AutoCompletionManager(JComboBox comboBox) {
setComboBox(comboBox);
}
@Override
public int selectionForKey(char key, ComboBoxModel model) {
// TODO change allowed chars to include *, -, ...
System.out.println("" + Integer.toString(key)); // TODO remove this
if (((key == 8) && (getPrefix().length() > 0))
|| (Character.isLetterOrDigit(key))) {
// Build the new prefix and set it
String prefix = getPrefix();
if ((key == 8) && (prefix.length() > 0)) {
prefix = prefix.substring(0, prefix.length() - 1);
} else {
prefix = getPrefix() + key;
}
setPrefix(prefix);
// Look for the first model item with given prefix
boolean prefixedItemFound = false;
for (int i = 0; i < model.getSize(); i++) {
Object element = model.getElementAt(i);
if (element.toString().startsWith(prefix)) {
// Found it, this is the newly selected item
setCurrentSelection(i);
prefixedItemFound = true;
break;
}
}
// Reset AutoCompletion if prefix can't be found
if (!prefixedItemFound) {
reset();
}
// Ensure popup is shown
getComboBox().showPopup();
// Force a repaint
model.setSelectedItem(null);
}
return getCurrentSelection();
}
public void reset() {
setPrefix(EMPTY_PREFIX);
setCurrentSelection(NO_SELECTION);
}
/**
* Called by the model listener when model has changed.
*/
public void modelChanged() {
// reset();
}
protected JComboBox getComboBox() {
return _comboBox;
}
protected void setComboBox(JComboBox comboBox) {
_comboBox = comboBox;
}
protected int getCurrentSelection() {
return _currentSelection;
}
protected void setCurrentSelection(int currentSelection) {
_currentSelection = currentSelection;
}
protected String getPrefix() {
return _prefix;
}
protected void setPrefix(String prefix) {
this._prefix = prefix;
}
}
private static class TestCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
// Ask to default renderer to do the job for us
Component component = super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
if (value != null) {
// Can we trick the rendered thing to reflect current prefix ?
if (component instanceof JLabel) {
// Everything's fine. Let's have a closer look.
JLabel label = (JLabel) component;
String text = label.getText();
text = "J" + text;
label.setText(text);
}
}
return component;
}
}
private static class AutoCompletionCellRenderer extends
DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
private ListCellRenderer _existingRenderer = null;
private AutoCompletionManager _manager = null;
public AutoCompletionCellRenderer(AutoCompletionManager manager,
ListCellRenderer existingRenderer) {
setManager(manager);
setExistingRenderer(existingRenderer);
}
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
// Ask to default renderer to do the job for us
Component component = getExistingRenderer()
.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
if (value != null) {
// Can we trick the rendered thing to reflect current prefix ?
String prefix = getManager().getPrefix();
if ((prefix != null) && (component instanceof JLabel)) {
// Everything's fine. Let's have a closer look.
JLabel label = (JLabel) component;
if (value.toString().startsWith(prefix)) {
// We're going trick the label a little bit
String text = label.getText();
text = "" + prefix
+ "" + text.substring(prefix.length())
+ "";
label.setText(text);
}
}
}
return component;
}
protected AutoCompletionManager getManager() {
return this._manager;
}
protected void setManager(AutoCompletionManager manager) {
this._manager = manager;
}
/**
* @return Returns the _existingRenderer.
*/
protected ListCellRenderer getExistingRenderer() {
return this._existingRenderer;
}
/**
* @param renderer The _existingRenderer to set.
*/
protected void setExistingRenderer(ListCellRenderer existingRenderer) {
this._existingRenderer = existingRenderer;
}
}
private static class AutoCompletionModelListener implements
ListDataListener {
private AutoCompletionManager _manager = null;
public AutoCompletionModelListener(AutoCompletionManager manager) {
setManager(manager);
}
@Override
public void intervalAdded(ListDataEvent e) {
// To be optimized...
getManager().modelChanged();
}
@Override
public void intervalRemoved(ListDataEvent e) {
// To be optimized...
getManager().modelChanged();
}
@Override
public void contentsChanged(ListDataEvent e) {
// To be optimized...
getManager().modelChanged();
}
protected AutoCompletionManager getManager() {
return _manager;
}
protected void setManager(AutoCompletionManager manager) {
this._manager = manager;
}
}
}