/* * Copyright Neil Cochrane 2006 * @author neilcochrane * * Feel free to use the code without restriction * in open source projects. * There is no cost or warranty attached and the code is * provided as is. * * http://www.jroller.com/swinguistuff/entry/text_completion */ package com.jroller.completer; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.DocumentFilter; import javax.swing.text.JTextComponent; abstract public class AbstractCompleterFilter extends DocumentFilter { abstract public int getCompleterListSize(); abstract public Object getCompleterObjectAt(int i); abstract public JTextComponent getTextComponent(); private boolean performCompletion = false; public void setPerformCompletion(boolean perform) { performCompletion = perform; } public boolean isPerformCompletion() { return performCompletion; } public void replace(FilterBypass filterBypass, int offset, int length, String string, AttributeSet attributeSet) throws BadLocationException { super.replace(filterBypass, offset, length, string, attributeSet); if(!isPerformCompletion()) return; //Skip completion flag Document doc = filterBypass.getDocument(); _preText = doc.getText(0,doc.getLength()); _firstSelectedIndex = -1; for (int i=0; i< getCompleterListSize(); i++) { String objString = getCompleterObjectAt(i).toString(); if ((_case) ? objString.equals(_preText) : objString.equalsIgnoreCase(_preText)) { _firstSelectedIndex = i; if (_corrective) filterBypass.replace(0, _preText.length(), objString, attributeSet); break; } if (objString.length() <= _preText.length()) continue; String objStringStart = objString.substring(0, _preText.length()); if ((_case) ? objStringStart.equals(_preText) : objStringStart.equalsIgnoreCase(_preText)) { String objStringEnd = objString.substring(_preText.length()); if (_corrective) filterBypass.replace(0, _preText.length(), objString, attributeSet); else filterBypass.insertString(_preText.length(), objStringEnd, attributeSet); getTextComponent().select(_preText.length(), doc.getLength()); _firstSelectedIndex = i; break; } } } public void insertString(FilterBypass filterBypass, int offset, String string, AttributeSet attributeSet) throws BadLocationException { super.insertString(filterBypass, offset, string, attributeSet); } public void remove(FilterBypass filterBypass, int offset, int length) throws BadLocationException { super.remove(filterBypass, offset, length); } public void setCaseSensitive(boolean caseSensitive) { _case = caseSensitive; } public boolean isCaseSensitive() { return _case; } /** * Will change the user entered part of the string to match the case of the matched item. * * e.g. * "europe/lONdon" would be corrected to "Europe/London" * * This option only makes sense if case sensitive is turned off */ public void setCorrectCase(boolean correctCase) { _corrective = correctCase; } public boolean isCorrectingCase() { return _corrective; } /** * * @return the index of the first object in the object array that can match * the user entered string (-1 if no object is currently being used as a match) */ public int getLeadingSelectedIndex() { return _firstSelectedIndex; } protected String _preText; // The text in the input field before we started last looking for matches. protected boolean _case = false; protected boolean _corrective = true; protected int _firstSelectedIndex = -1; }