package chatty.gui.components; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * A TextField that supports auto-completion and a history of entered text. * * @author tduva */ public class ChannelEditBox extends JTextField implements KeyListener, ActionListener, DocumentListener { // History Vector<String> history = new Vector<>(); int historyPosition = 0; boolean historyTextEdited = false; // Auto completion private final AutoCompletion autoCompletion; public ChannelEditBox(int size) { super(size); autoCompletion = new AutoCompletion(this); this.addKeyListener(this); this.addActionListener(this); this.setFocusTraversalKeysEnabled(false); getDocument().addDocumentListener(this); // Prevent automatic selection of text when tabbing back into the window addFocusListener(new FocusListener() { private boolean selection; @Override public void focusGained(FocusEvent e) { if (!selection) { setCaretPosition(getCaretPosition()); } } @Override public void focusLost(FocusEvent e) { selection = getSelectedText() != null; } }); } @Override public Point getLocationOnScreen() { synchronized (getTreeLock()) { if (isShowing()) { return super.getLocationOnScreen(); } // Workaround that probably breaks ALL the things, since I can't // figure out what actually causes this error return new Point(0,0); } } public void setCompletionMaxItemsShown(int max) { autoCompletion.setMaxResultsShown(max); } public void setCompletionShowPopup(boolean show) { autoCompletion.setShowPopup(show); } public void setCompleteToCommonPrefix(boolean value) { autoCompletion.setCompleteToCommonPrefix(value); } /** * Inserts the given text at the current caret position, adding a space in * front and after the inserted text, if {@code withSpace} is true and if * there is actually other text in front/after respectively. * * Sets the caret position to after the inserted text (after the space, if * one was added). * * @param text The text to insert * @param withSpace Whether to add spaces */ public void insertAtCaret(String text, boolean withSpace) { int pos = getCaretPosition(); String current = getText(); String before = current.substring(0, pos); String after = current.substring(pos); // Add space before and after inserted text, if requested if (withSpace) { if (!before.isEmpty() && !before.endsWith(" ")) { text = " "+text; } if (!after.isEmpty() && !after.startsWith(" ")) { text = text+" "; } } setText(before+text+after); // Set caret to position after inserted text setCaretPosition(pos+text.length()); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_UP) { historyBack(); } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { historyForward(); } } @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_TAB) { if (e.isControlDown() || e.isAltDown() || e.isAltGraphDown()) { return; } if (e.isShiftDown()) { if (autoCompletion.inCompletion()) { autoCompletion.doAutoCompletion(null, false); } else { autoCompletion.doAutoCompletion("special", true); } } else { autoCompletion.doAutoCompletion(null, true); } } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { autoCompletion.cancelAutoCompletion(); } } //############### //### History ### //############### /** * Move back in the history, changing the text. */ private void historyBack() { if (historyPosition > 0 && historyPosition <= history.size()) { historyPosition--; String text = history.get(historyPosition); if (text != null) { setText(text); historyTextEdited = false; } } } private void historyForward() { historyAddChanged(); historyPosition++; if (historyPosition >= history.size()) { // If further than the latest history entry, clear input setText(""); historyTextEdited = false; historyPosition = history.size(); } else if (historyPosition >= 0) { // If still in the history range set to next history position String text = history.get(historyPosition); if (text != null) { setText(text); historyTextEdited = false; } } } /** * Adds the current text to the history, if it was changed. */ private void historyAddChanged() { if (historyTextEdited) { historyAdd(getText()); historyTextEdited = false; historyPosition = history.size(); } } /** * Adds the given text to the history. Mainly used when text is send. The * text is removed first, so it only occurs once. Only text that is not * empty is added. * * @param text */ private void historyAdd(String text) { if (!text.isEmpty()) { history.remove(text); history.add(text); } } /** * Adds sent text to the history, sets history position and clears the * input field. * * @param e */ @Override public void actionPerformed(ActionEvent e) { historyAdd(getText()); historyPosition = history.size(); setText(""); historyTextEdited = false; } @Override public void insertUpdate(DocumentEvent e) { historyTextEdited = true; //hideCompletionInfoWindow(); } @Override public void removeUpdate(DocumentEvent e) { historyTextEdited = true; //hideCompletionInfoWindow(); } @Override public void changedUpdate(DocumentEvent e) { //hideCompletionInfoWindow(); } public void setCompletionServer(AutoCompletionServer server) { autoCompletion.setCompletionServer(server); } public void cleanUp() { autoCompletion.cleanUp(); } public static void main(String[] args) { List<String> l = new ArrayList<>(); l.add("joshimuz"); l.add("joshua"); l.add("josh"); l.add("jo"); //System.out.println(findStartCommonToAll(l)); } }