Package cli_fmw.utils.autocomplete

Source Code of cli_fmw.utils.autocomplete.JTextFieldAutoComplete$AutoDocument

package cli_fmw.utils.autocomplete;

import cli_fmw.utils.DefaultColors;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.*;

/**
* Класс текстового поля с автокомплитом, работает на основе модели комбобокса
* @author petr
*/
public class JTextFieldAutoComplete extends JTextField implements FocusListener, ActionListener {

    private ArrayList<ListSelectionListener> listeners;//листенеры смены выделения
    private ComboBoxModel dataModel;
    private boolean isCaseSensitive;
    private boolean isStrict;
    private boolean editable;
    private boolean selectOnFocusGained;//выделять ли весь текст при получении фокуса
    private Map<String, Integer> indexMap;//мап строковому значению элемента ставит его индекс в модели данных
    private Object selectedItem;

    /**
     * Хитрожопый документ на котором всё держится
     */
    private class AutoDocument extends PlainDocument {

        @Override
        public void replace(int i, int j, String s, AttributeSet attributeset)
                throws BadLocationException {
            super.remove(i, j);
            insertString(i, s, attributeset);
        }

        @Override
        public void insertString(int i, String s, AttributeSet attributeset)
                throws BadLocationException {
            if (s == null || "".equals(s)) {
                return;
            }
            int len = getLength();
            String s1 = getText(0, i);
            String sEnd = getText(i, len-i);
            String s2 = getMatch(s1 + s);
            int j = (i + s.length()) - 1;
            if (isStrict && s2 == null) {
                s2 = getMatch(s1);
                j--;
            } else if (!isStrict && s2 == null) {
                super.insertString(i, s, attributeset);
                return;
            }
            boolean newString = false;
            if (s2.equals(s1+s)){
                newString = true;
                s2+=sEnd;
            }
            fireSelecton(s2);
            super.remove(0, getLength());
            super.insertString(0, s2, attributeset);
            setSelectionStart(j + 1);
            if (newString){
                setSelectionEnd(j + 1);
            }else{
                setSelectionEnd(getLength());
            }
//            setCaretPosition(j);
        }

        @Override
        public void remove(int i, int j) throws BadLocationException {
            int k = getSelectionStart();
            if (k > 0) {
                k--;
            }
            String s = getMatch(getText(0, k));
            if (!isStrict && s == null) {
                super.remove(i, j);
            } else {
                super.remove(0, getLength());
                super.insertString(0, s, null);
            }
            fireSelecton(s);
            try {
                setSelectionStart(k);
                setSelectionEnd(getLength());
            } catch (Exception exception) {
                exception.printStackTrace();
            }
//            setCaretPosition(k);
        }

        private void fireSelecton(String s) {
            if (s != null) {
                Integer number = indexMap.get(s);
                if (number != null && dataModel.getElementAt(number) != null) {
                    fireChangeSelection(dataModel.getElementAt(number), number);
                } else if (editable) {
                    fireChangeSelection(s, -1);
                }
            }
        }

    }

    public JTextFieldAutoComplete() {
        this(new DefaultComboBoxModel());
    }

    public JTextFieldAutoComplete(Object[] items) {
        this(new DefaultComboBoxModel(items));
    }

    public JTextFieldAutoComplete(ComboBoxModel dataModel) {
        isCaseSensitive = false;
        isStrict = true;
        selectOnFocusGained = true;
        addFocusListener(this);
        addActionListener(this);
        if (dataModel == null) {
            throw new IllegalArgumentException("values can not be null");
        } else {
            setModel(dataModel);
            init();
            return;
        }
    }



    private void init() {
        AutoDocument autoDocument = new AutoDocument();
        setDocument(autoDocument);
        if (isStrict && dataModel.getSize() > 0) {
            setText(dataModel.getElementAt(0).toString());
        }
    }

    /**
     * поиск элемента в модели данных начало строкового значения которого совпадает
     * с входной строкой
     * так же происходит обработка класса <code>HasColors</code>
     * определяется цвет текста и фона
     * @param s входная строка
     * @return найденная строка (если найдена) или входная строка (если других нет)
     */
    private String getMatch(String s) {
        for (int i = 0; i < dataModel.getSize(); i++) {
            Object element = dataModel.getElementAt(i);
            String s1 = element.toString();
            if (s1 != null) {
                setBackground(DefaultColors.TEXT_FIELD_BACKGROUND);
                setForeground(DefaultColors.TEXT);
                if (!isCaseSensitive && s1.toLowerCase().startsWith(s.toLowerCase())) {
                    if (element instanceof HasColors){
                        HasColors hc = (HasColors) element;
                        if (hc.getBackground() != null){
                            setBackground(hc.getBackground());
                        }
                        if (hc.getForeground() != null){
                            setForeground(hc.getForeground());
                        }
                    }
                    return s1;
                }
                if (isCaseSensitive && s1.startsWith(s)) {
                    if (element instanceof HasColors){
                        HasColors hc = (HasColors) element;
                        if (hc.getBackground() != null){
                            setBackground(hc.getBackground());
                        }
                        if (hc.getForeground() != null){
                            setForeground(hc.getForeground());
                        }
                    }
                    return s1;
                }
            }
        }

        return s;
    }

    /**
     * выделяет часть текста которая вписана автокомплитером
     * (Внимание: иногда глючит)
     * @param s
     */
    @Override
    public void replaceSelection(String s) {
        AutoDocument _lb = (AutoDocument) getDocument();
        if (_lb != null) {
            try {
                int i = Math.min(getCaret().getDot(), getCaret().getMark());
                int j = Math.max(getCaret().getDot(), getCaret().getMark());
                _lb.replace(i, j - i, s, null);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    /**
     * Проверяет чувствительность к регистру символов
     * @return истина если различает
     */
    public boolean isCaseSensitive() {
        return isCaseSensitive;
    }

    /**
     * Устанавливает чувствительность  к регистру символов
     * @param flag
     */
    public void setCaseSensitive(boolean flag) {
        isCaseSensitive = flag;
    }

    public boolean isStrict() {
        return isStrict;
    }

    public void setStrict(boolean flag) {
        isStrict = flag;
    }

    /**
     * Вернёт используемую модель
     * (не  стоит менять модель через данную ссылку, т.к такая модель не будет проиндексирована)
     * @return
     */
    public ComboBoxModel getDataList() {
        return dataModel;
    }

    /**
     * Устанавливает и индексирует модель
     * @param dataModel
     */
    public void setModel(ComboBoxModel dataModel) {
        if (dataModel == null) {
            throw new IllegalArgumentException("values can not be null");
        } else {
            //идексация элементов (занесение в мап текст - номер)
            this.dataModel = dataModel;
            indexMap = new HashMap<String, Integer>();
            for (int i = 0; i < dataModel.getSize(); i++) {
                Object object = dataModel.getElementAt(i);
                if (object != null) {
                    indexMap.put(object.toString(), i);
                } else {
                    //??
                }
            }

            return;
        }
    }

//    public void setDataList(List list) {
//        if (list == null) {
//            throw new IllegalArgumentException("values can not be null");
//        } else {
//            dataList = new ArrayList(list);
//            dataToList = new HashMap<String, Integer>();
//            for (int i = 0; i < list.size(); i++) {
//                Object object = list.get(i);
//                if (object != null) {
//                    dataToList.put(object.toString(), i);
//                } else {
//                    //??
//                }
//            }
//
//            return;
//        }
//    }

    /**
     * Добавляет слушателя смены выделения
     * @param listener
     * @return
     */
    public final ListSelectionListener addSelectionListener(ListSelectionListener listener){
        if (listeners == null){
            listeners = new ArrayList<ListSelectionListener>();
        }
        listeners.add(listener);
        return listener;
    }

    /**
     * Удаляет слушателя смены выделения
     * @param listener
     */
    public final void removeSelectionListener(ListSelectionListener listener){
        if (listeners != null){
            listeners.remove(listener);
        }
    }

    /**
     * Пинает листенеров
     * @param selectedItem новый воделенный элемент
     * @param number его номер в списке
     */
    protected final void fireChangeSelection(Object selectedItem, int number){
        this.selectedItem = selectedItem;
        if (listeners != null){
            for (ListSelectionListener listener : listeners) {
                listener.valueChanged(new ListSelectionEvent(selectedItem, number, number, false));
            }
        }
    }

    @Override
    public boolean isEditable() {
        return editable;
    }

    @Override
    public void setEditable(boolean b) {
        editable = b;
    }

    public boolean isSelectOnFocusGained() {
        return selectOnFocusGained;
    }

    public void setSelectOnFocusGained(boolean selectOnFocusGained) {
        this.selectOnFocusGained = selectOnFocusGained;
    }

    @Override
    public void focusGained(FocusEvent e) {
        if (selectOnFocusGained){
            selectAll();
        }
    }

    @Override
    public void focusLost(FocusEvent e) {
        select(getText().length()-1, getText().length()-1);
        fireActionPerformed();
    }

    /**
     * по акшн перформед снятие выделения
     * @param e
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        select(getText().length(), getText().length());
    }

    public Object getSelectedItem(){
        return selectedItem;
    }

}
TOP

Related Classes of cli_fmw.utils.autocomplete.JTextFieldAutoComplete$AutoDocument

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.