Mega Code Archive

 
Categories / Java / Swing Components
 

Auto Complete ComboBox 2

//package util.autocomplete; import java.awt.Color; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; import javax.swing.JComboBox; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicComboBoxEditor; /**  * This class uses AutoCompleteComboBoxEditor and AutoCompleteTextField to  * offer and Auto Completion to typed text based on the Objects added to the  * ComboBox.  * ** IMPORTANT **  * Since this is a text-based utility any Object added to this ComboBox (even  * those that you create) MUST, I repeat MUST have a valid toString method that  * returns the portion text representation of your  * @author Brandon Buck  * @version 1.0  */ public class AutoCompleteComboBox<E> extends JComboBox {     private AutoCompleteTextField editorComp;     public AutoCompleteComboBox() {         super();         AutoCompleteComboBoxEditor cbe = new AutoCompleteComboBoxEditor();         this.editorComp = (AutoCompleteTextField)(cbe.getEditorComponent());         this.setEditor(cbe);         this.setEditable(true);     }     @Override     public void addItem(Object anObject) {         super.addItem(anObject);         editorComp.addPossibility(anObject.toString());     }     @Override     public void removeAllItems() {         super.removeAllItems();         editorComp.removeAllPossibilities();     }          public AutoCompleteTextField getEditorComponent() {         return editorComp;     }     @Override     public void removeItemAt(int index) {         E anObject = getItemAt(index);         super.removeItemAt(index);         editorComp.removePossibility(anObject.toString());     }     @Override     public E getItemAt(int index) {         return (E)super.getItemAt(index);     }     @Override     public E getSelectedItem() {         return (E)super.getSelectedItem();     } } /**  * A JTextField that will display a whole word as the user types a portion of  * it. A better example would be, as the user types the first letter in the  * word "text" the AutoCompleteTextField will display the letter "t" in the  * components current foreground color and display the rest of the word "ext"  * in the specified incomplete color (default is Color.GRAY.brighter()). The  * displayed text changes as the user types "e" so now getText() would return  * the string "te" and the incomplete portion displayed by the editor will be  * "xt." If Enter is pressed while an incomplete word is being processes, then  * the AutoCompleteTextField will replace what he user has typed with the  * completed word and consider itself "finished," and if Enter is pressed a  * second time, then it will fire a KeyEvent normally.  * @author Brandon Buck  * @version 1.0  */  class AutoCompleteTextField extends JTextField implements KeyListener,             DocumentListener {     private ArrayList<String> possibilities;     private int currentGuess;     private Color incompleteColor;     private boolean areGuessing;     private boolean caseSensitive;     /**      * Constructs a new AutoCompleteTextField with the 5 columns by default and      * no case sensitivity on comparisons of guesses to entered text.      */     public AutoCompleteTextField() {         this(5, false);     }     /**      * Constructs a new AutoCompleteTextField with the specified number of      * columns with no case sensitivity when comparing the current guess to the      * text entered.      * @param columns The number of columns you wish for the width of this AutoCompleteTextField.      */     public AutoCompleteTextField(int columns) {         this(columns, false);     }     /**      * Creates a new AutoCompleteTextField with the given number of columns in      * width and the setting for case sensitivity when comparing the current      * guess to the entered text.      * @param columns The number of columns of text for this component.      * @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not.      */     public AutoCompleteTextField(int columns, boolean caseSensitive) {         super.setColumns(columns);         this.possibilities = new ArrayList<String>();         this.incompleteColor = Color.GRAY.brighter();         this.currentGuess = -1;         this.areGuessing = false;         this.caseSensitive = caseSensitive;         this.addKeyListener(this);         this.getDocument().addDocumentListener(this);     }     /** Add a new possibility to the list of possibilities.      * Add a new possibility to the list of possibilities for the      * AutoCommpleteTextField to process.      * @param possibility The new possibility to add.      */     public void addPossibility(String possibility) {         this.possibilities.add(possibility);         Collections.sort(possibilities);     }     /** Removes a possibility from the list of possibilities.      * Removes the given possibility from the list of possibilities so that it      * will no longer be matched.      * @param possibility The possibility to remove.      */     public void removePossibility(String possibility) {         this.possibilities.remove(possibility);     }     /** Removes all possibilities in the list.      * Removes every possibility in the list and starts over with an empty list      * ready for new possibilities to be added.      */     public void removeAllPossibilities() {         this.possibilities = new ArrayList<String>();     }     /** Sets the color to draw the incomplete guess in.      * This sets the color that the incomplete guess text is drawn in.      * @param incompleteColor The new color to draw the incomplete guess with.      */     public void setIncompleteColor(Color incompleteColor) {         this.incompleteColor = incompleteColor;     }     /** Returns the current guess from the list of possibilities.      * Returns the string at the location of the current guess in the list of       * possibilities.      * @return The current guess as a String.      */     private String getCurrentGuess() {         if (this.currentGuess != -1)             return this.possibilities.get(this.currentGuess);         return this.getText();     }     /**      * Changes the current case sensitive setting to the given setting.      * @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not.      */     public void setCaseSensitive(boolean caseSensitive) {         this.caseSensitive = caseSensitive;     }     private void findCurrentGuess() {         String entered = this.getText();         if (!this.caseSensitive)             entered = entered.toLowerCase();         for (int i = 0; i < this.possibilities.size(); i++) {             currentGuess = -1;             String possibility = this.possibilities.get(i);             if (!this.caseSensitive)                 possibility = possibility.toLowerCase();             if (possibility.startsWith(entered)) {                 this.currentGuess = i;                 break;             }         }     }     @Override     public void setText(String text) {         super.setText(text);         this.areGuessing = false;         this.currentGuess = -1;     }     @Override     public void paintComponent(Graphics g) {         String guess = this.getCurrentGuess();         String drawGuess = guess;         super.paintComponent(g);         String entered = this.getText();         Rectangle2D enteredBounds = g.getFontMetrics().getStringBounds(entered, g);         if (!(this.caseSensitive)) {             entered = entered.toLowerCase();             guess = guess.toLowerCase();         }                  if (!(guess.startsWith(entered)))             this.areGuessing = false;         if (entered != null && !(entered.equals(""))                  && this.areGuessing) {             String subGuess = drawGuess.substring(entered.length(), drawGuess.length());             Rectangle2D subGuessBounds = g.getFontMetrics().getStringBounds(drawGuess, g);             int centeredY = ((getHeight() / 2) + (int)(subGuessBounds.getHeight() / 2));             g.setColor(this.incompleteColor);             g.drawString(subGuess + "   press ENTER to send or \u2192 to fill", (int)(enteredBounds.getWidth()) + 2, centeredY - 2);         }     }     public void keyTyped(KeyEvent e) { }     public void keyPressed(KeyEvent e) {          if (e.getKeyCode() == KeyEvent.VK_ENTER) {             if (this.areGuessing) {                 this.setText(this.getCurrentGuess());                 this.areGuessing = false;             }         }         if (e.getKeyCode() == KeyEvent.VK_RIGHT) {             if (this.areGuessing) {                 this.setText(this.getCurrentGuess());                 this.areGuessing = false;                 e.consume();             }         }     }          public void keyReleased(KeyEvent e) { }     public void insertUpdate(DocumentEvent e) {         String temp = this.getText();         if (temp.length() == 1)             this.areGuessing = true;         if (this.areGuessing)             this.findCurrentGuess();     }     public void removeUpdate(DocumentEvent e) {         String temp = this.getText();         if (!(this.areGuessing))             this.areGuessing = true;         if (temp.length() == 0)             this.areGuessing = false;         else if (this.areGuessing) {             this.findCurrentGuess();         }     }     public void changedUpdate(DocumentEvent e) { } }  class AutoCompleteComboBoxEditor extends BasicComboBoxEditor {       public AutoCompleteComboBoxEditor() {           editor = createEditorComponent();       }       @Override       protected AutoCompleteTextField createEditorComponent() {           AutoCompleteTextField acEditor = new AutoCompleteTextField(9);           acEditor.setBorder(null);           return acEditor;       }   }