001: package snow.utils.gui;
002:
003: import java.awt.BorderLayout;
004: import java.awt.EventQueue;
005: import javax.swing.text.*;
006: import java.util.*;
007: import java.awt.event.*;
008: import javax.swing.*;
009:
010: public final class CompletionUtils {
011: private CompletionUtils() {
012: }
013:
014: public static interface CompletionListener<T> {
015: public void itemSelected(T item);
016: }
017:
018: /** Adds the possible completions to the component.
019: */
020: public static <T> void addCompletions(final JTextComponent tf,
021: final CompletionListener<T> cl, final T... comps) {
022: //More precise: tf.getDocument().addDocumentListener();
023:
024: tf.addKeyListener(new KeyAdapter() // call order: P T R
025: {
026: JPopupMenu previousPop = null;
027:
028: public JMenuItem getSelected() {
029: for (MenuElement mi : previousPop
030: .getSubElements()) {
031: JMenuItem mei = (JMenuItem) mi;
032: if (mei.isSelected()) {
033: System.out.println("Selected: "
034: + mei.getText());
035: return mei;
036: }
037: }
038: System.out.println("No menu selected !");
039: return null;
040: }
041:
042: @Override
043: public void keyPressed(KeyEvent ke) {
044: System.out.println("P");
045: }
046:
047: @Override
048: public void keyTyped(KeyEvent ke) {
049: System.out.println("T");
050: }
051:
052: @Override
053: public void keyReleased(KeyEvent ke) {
054: System.out.println("R");
055: if (previousPop != null) {
056: int sel = previousPop.getSelectionModel()
057: .getSelectedIndex();
058: System.out.println("sel = " + sel);
059:
060: if (ke.getKeyCode() == KeyEvent.VK_UP) {
061: sel++;
062: if (sel >= previousPop
063: .getComponentCount()) {
064: sel = previousPop
065: .getComponentCount() - 1;
066: }
067: previousPop.getSelectionModel()
068: .setSelectedIndex(sel);
069: return;
070: } else if (ke.getKeyCode() == KeyEvent.VK_DOWN) {
071: sel--;
072: if (sel < 0)
073: sel = 0;
074: previousPop.getSelectionModel()
075: .setSelectedIndex(sel);
076: return;
077: } else if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
078: // DON'T WORK !!
079: JMenuItem mei = getSelected();
080: if (mei != null) {
081: mei.doClick();
082: return;
083: }
084: return;
085: /* // strange: sel and ind have REVERSE order
086: int ind = previousPop.getComponentCount() - sel-1;
087:
088: // select.
089: if(ind>=0)
090: {
091:
092: JMenuItem mi = (JMenuItem) previousPop.getComponent(ind);
093: //System.out.println("click on "+sel+": "+mi.getText());
094:
095: mi.doClick();
096: return;
097: //mi.processKeyEvent(ke, previousPop.getSubElements(), null);
098: }*/
099: } else if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) {
100: return;
101: }
102: }
103:
104: update();
105: }
106:
107: void update() {
108: String s = tf.getText().toLowerCase();
109: List<T> cand = new ArrayList<T>();
110: for (T ci : comps) {
111: if (("" + ci).toLowerCase().contains(s)) {
112: cand.add(ci);
113: }
114: }
115:
116: if (previousPop != null
117: && previousPop.isVisible()) {
118: System.out.println("disable");
119: previousPop.setVisible(false);
120: }
121:
122: if (cand.size() > 0 && cand.size() < 10) {
123: JPopupMenu pop = new JPopupMenu();
124: previousPop = pop;
125: for (final T ci : cand) {
126: JMenuItem mi = new JMenuItem("" + ci);
127: pop.add(mi);
128: mi
129: .addActionListener(new ActionListener() {
130: public void actionPerformed(
131: ActionEvent ae) {
132: if (cl != null) {
133: cl.itemSelected(ci);
134: }
135: tf.setText("" + ci);
136: }
137: });
138: }
139:
140: EventQueue.invokeLater(new Runnable() {
141: public void run() {
142: tf.requestFocus();
143: }
144: });
145: pop.show(tf, 0, tf.getHeight());
146: }
147: }
148: });
149: }
150:
151: public static void main(String[] args) {
152: EventQueue.invokeLater(new Runnable() {
153: public void run() {
154:
155: JFrame test = new JFrame("test");
156: test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
157:
158: JTextField tt = new JTextField(12);
159: addCompletions(tt, new CompletionListener<String>() {
160: public void itemSelected(String s) {
161: System.out.println("Selected: " + s);
162: }
163: }, "aaa", "bbb", "vvv", "aaaa", "aaaaaaa", "aaaaa",
164: "v", "vv");
165: test.add(tt, BorderLayout.CENTER);
166: //test.add(tt, BorderLayout.SOUTH);
167:
168: test.pack();
169: test.setLocationRelativeTo(null);
170: test.setVisible(true);
171: }
172: });
173:
174: }
175:
176: }
|