KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > demo > TextAreaReadline


1 package org.jruby.demo;
2
3 import java.awt.Color JavaDoc;
4 import java.awt.Point JavaDoc;
5 import java.awt.event.KeyEvent JavaDoc;
6 import java.awt.event.KeyListener JavaDoc;
7 import java.io.IOException JavaDoc;
8 import java.io.OutputStream JavaDoc;
9 import java.util.Iterator JavaDoc;
10 import java.util.LinkedList JavaDoc;
11 import java.util.List JavaDoc;
12
13 import javax.swing.DefaultListCellRenderer JavaDoc;
14 import javax.swing.JComboBox JavaDoc;
15 import javax.swing.SwingUtilities JavaDoc;
16 import javax.swing.plaf.basic.BasicComboPopup JavaDoc;
17 import javax.swing.text.AbstractDocument JavaDoc;
18 import javax.swing.text.AttributeSet JavaDoc;
19 import javax.swing.text.BadLocationException JavaDoc;
20 import javax.swing.text.DocumentFilter JavaDoc;
21 import javax.swing.text.JTextComponent JavaDoc;
22 import javax.swing.text.MutableAttributeSet JavaDoc;
23 import javax.swing.text.SimpleAttributeSet JavaDoc;
24 import javax.swing.text.StyleConstants JavaDoc;
25
26 import org.jruby.Ruby;
27 import org.jruby.RubyModule;
28 import org.jruby.ext.Readline;
29 import org.jruby.runtime.Arity;
30 import org.jruby.runtime.Block;
31 import org.jruby.runtime.builtin.IRubyObject;
32 import org.jruby.runtime.callback.Callback;
33
34 public class TextAreaReadline extends OutputStream JavaDoc implements KeyListener JavaDoc {
35     
36     JTextComponent JavaDoc area;
37     private int startPos;
38     private String JavaDoc currentLine;
39     
40     private Object JavaDoc amEditing = new Object JavaDoc();
41     
42     public MutableAttributeSet JavaDoc promptStyle;
43     public MutableAttributeSet JavaDoc inputStyle;
44     public MutableAttributeSet JavaDoc outputStyle;
45     public MutableAttributeSet JavaDoc resultStyle;
46     
47     private JComboBox JavaDoc completeCombo;
48     private BasicComboPopup JavaDoc completePopup;
49     private int start;
50     private int end;
51     
52     public TextAreaReadline(JTextComponent JavaDoc area) {
53         this(area, null);
54     }
55     
56     public TextAreaReadline(JTextComponent JavaDoc area, final String JavaDoc message) {
57         this.area = area;
58         
59         area.addKeyListener(this);
60         
61         // No editing before startPos
62
if (area.getDocument() instanceof AbstractDocument JavaDoc)
63             ((AbstractDocument JavaDoc) area.getDocument()).setDocumentFilter(
64                 new DocumentFilter JavaDoc() {
65                     public void insertString(DocumentFilter.FilterBypass JavaDoc fb, int offset, String JavaDoc string, AttributeSet JavaDoc attr) throws BadLocationException JavaDoc {
66                         if (offset >= startPos) super.insertString(fb, offset, string, attr);
67                     }
68                     
69                     public void remove(DocumentFilter.FilterBypass JavaDoc fb, int offset, int length) throws BadLocationException JavaDoc {
70                         if (offset >= startPos) super.remove(fb, offset, length);
71                     }
72                     
73                     public void replace(DocumentFilter.FilterBypass JavaDoc fb, int offset, int length, String JavaDoc text, AttributeSet JavaDoc attrs) throws BadLocationException JavaDoc {
74                         if (offset >= startPos) super.replace(fb, offset, length, text, attrs);
75                     }
76                 }
77             );
78         
79         promptStyle = new SimpleAttributeSet JavaDoc();
80         StyleConstants.setForeground(promptStyle, new Color JavaDoc(0xa4, 0x00, 0x00));
81         
82         inputStyle = new SimpleAttributeSet JavaDoc();
83         StyleConstants.setForeground(inputStyle, new Color JavaDoc(0x20, 0x4a, 0x87));
84         
85         outputStyle = new SimpleAttributeSet JavaDoc();
86         StyleConstants.setForeground(outputStyle, Color.darkGray);
87         
88         resultStyle = new SimpleAttributeSet JavaDoc();
89         StyleConstants.setItalic(resultStyle, true);
90         StyleConstants.setForeground(resultStyle, new Color JavaDoc(0x20, 0x4a, 0x87));
91         
92         completeCombo = new JComboBox JavaDoc();
93         completeCombo.setRenderer(new DefaultListCellRenderer JavaDoc()); // no silly ticks!
94
completePopup = new BasicComboPopup JavaDoc(completeCombo);
95         
96         if (message != null) {
97             final MutableAttributeSet JavaDoc messageStyle = new SimpleAttributeSet JavaDoc();
98             StyleConstants.setBackground(messageStyle, area.getForeground());
99             StyleConstants.setForeground(messageStyle, area.getBackground());
100             SwingUtilities.invokeLater( new Runnable JavaDoc() {
101                 public void run() {
102                     append(message, messageStyle);
103                 }
104             });
105         }
106     }
107     
108     public void hookIntoRuntime(final Ruby runtime) {
109         /* Hack in to replace usual readline with this */
110         runtime.getLoadService().require("readline");
111         RubyModule readlineM = runtime.getModule("Readline");
112         
113         readlineM.defineModuleFunction("readline", new Callback() {
114             public IRubyObject execute(IRubyObject recv, IRubyObject[] args, Block block) {
115                 return runtime.newString(readLine(args[0].toString()));
116             }
117             public Arity getArity() { return Arity.twoArguments(); }
118         });
119     }
120     
121     protected void completeAction(KeyEvent JavaDoc event) {
122         if (Readline.getCompletor() == null) return;
123         
124         event.consume();
125         
126         if (completePopup.isVisible()) return;
127         
128         List JavaDoc candidates = new LinkedList JavaDoc();
129         String JavaDoc bufstr = null;
130         try {
131             bufstr = area.getText(startPos, area.getCaretPosition() - startPos);
132         } catch (BadLocationException JavaDoc e) {
133             return;
134         }
135         
136         int cursor = area.getCaretPosition() - startPos;
137         
138         int position = Readline.getCompletor().complete(bufstr, cursor, candidates);
139         
140         // no candidates? Fail.
141
if (candidates.isEmpty())
142             return;
143         
144         if (candidates.size() == 1) {
145             replaceText(startPos + position, area.getCaretPosition(), (String JavaDoc) candidates.get(0));
146             return;
147         }
148         
149         start = startPos + position;
150         end = area.getCaretPosition();
151         
152         Point JavaDoc pos = area.getCaret().getMagicCaretPosition();
153
154         // bit risky if someone changes completor, but useful for method calls
155
int cutoff = bufstr.substring(position).lastIndexOf('.') + 1;
156         start += cutoff;
157
158         if (candidates.size() < 10)
159             completePopup.getList().setVisibleRowCount(candidates.size());
160         else
161             completePopup.getList().setVisibleRowCount(10);
162
163         completeCombo.removeAllItems();
164         for (Iterator JavaDoc i = candidates.iterator(); i.hasNext();) {
165             String JavaDoc item = (String JavaDoc) i.next();
166             if (cutoff != 0) item = item.substring(cutoff);
167             completeCombo.addItem(item);
168         }
169
170         completePopup.show(area, pos.x, pos.y + area.getFontMetrics(area.getFont()).getHeight());
171     }
172     
173     protected void backAction(KeyEvent JavaDoc event) {
174         if (area.getCaretPosition() <= startPos)
175             event.consume();
176     }
177     
178     protected void upAction(KeyEvent JavaDoc event) {
179         event.consume();
180         
181         if (completePopup.isVisible()) {
182             int selected = completeCombo.getSelectedIndex() - 1;
183             if (selected < 0) return;
184             completeCombo.setSelectedIndex(selected);
185             return;
186         }
187         
188         if (!Readline.getHistory().next()) // at end
189
currentLine = getLine();
190         else
191             Readline.getHistory().previous(); // undo check
192

193         if (!Readline.getHistory().previous()) return;
194         
195         String JavaDoc oldLine = Readline.getHistory().current().trim();
196         replaceText(startPos, area.getDocument().getLength(), oldLine);
197     }
198     
199     protected void downAction(KeyEvent JavaDoc event) {
200         event.consume();
201         
202         if (completePopup.isVisible()) {
203             int selected = completeCombo.getSelectedIndex() + 1;
204             if (selected == completeCombo.getItemCount()) return;
205             completeCombo.setSelectedIndex(selected);
206             return;
207         }
208         
209         if (!Readline.getHistory().next()) return;
210         
211         String JavaDoc oldLine;
212         if (!Readline.getHistory().next()) // at end
213
oldLine = currentLine;
214         else {
215             Readline.getHistory().previous(); // undo check
216
oldLine = Readline.getHistory().current().trim();
217         }
218         
219         replaceText(startPos, area.getDocument().getLength(), oldLine);
220     }
221     
222     protected void replaceText(int start, int end, String JavaDoc replacement) {
223         try {
224             area.getDocument().remove(start, end - start);
225             area.getDocument().insertString(start, replacement, inputStyle);
226         } catch (BadLocationException JavaDoc e) {
227             e.printStackTrace();
228         }
229     }
230     
231     protected String JavaDoc getLine() {
232         try {
233             return area.getText(startPos, area.getDocument().getLength() - startPos);
234         } catch (BadLocationException JavaDoc e) {
235             e.printStackTrace();
236         }
237         return null;
238     }
239     
240     protected void enterAction(KeyEvent JavaDoc event) {
241         event.consume();
242         
243         if (completePopup.isVisible()) {
244             if (completeCombo.getSelectedItem() != null)
245                 replaceText(start, end, (String JavaDoc) completeCombo.getSelectedItem());
246             completePopup.setVisible(false);
247             return;
248         }
249         
250         append("\n", null);
251         synchronized (amEditing) {
252             amEditing.notify();
253         }
254     }
255     
256     public String JavaDoc readLine(final String JavaDoc prompt)
257     {
258         SwingUtilities.invokeLater( new Runnable JavaDoc() {
259             public void run() {
260                 append(prompt.trim(), promptStyle);
261                 append(" ", inputStyle); // hack to get right style for input
262
area.setCaretPosition(area.getDocument().getLength());
263                 startPos = area.getDocument().getLength();
264             }
265         });
266         
267         Readline.getHistory().moveToEnd();
268         
269         synchronized (amEditing) {
270             try {
271                 amEditing.wait();
272             } catch (InterruptedException JavaDoc e) { }
273         }
274         String JavaDoc result = getLine().trim();
275         return result;
276     }
277     
278     public void keyPressed(KeyEvent JavaDoc event) {
279         int code = event.getKeyCode();
280         switch (code) {
281         case KeyEvent.VK_TAB: completeAction(event); break;
282         case KeyEvent.VK_LEFT:
283         case KeyEvent.VK_BACK_SPACE:
284             backAction(event); break;
285         case KeyEvent.VK_UP: upAction(event); break;
286         case KeyEvent.VK_DOWN: downAction(event); break;
287         case KeyEvent.VK_ENTER: enterAction(event); break;
288         case KeyEvent.VK_HOME: event.consume(); area.setCaretPosition(startPos); break;
289         }
290         
291         if (completePopup.isVisible() &&
292                 code != KeyEvent.VK_TAB &&
293                 code != KeyEvent.VK_UP &&
294                 code != KeyEvent.VK_DOWN )
295             completePopup.setVisible(false);
296     }
297
298     public void keyReleased(KeyEvent JavaDoc arg0) { }
299
300     public void keyTyped(KeyEvent JavaDoc arg0) { }
301     
302     /** Output methods **/
303     
304     protected void append(String JavaDoc toAppend, AttributeSet JavaDoc style) {
305        try {
306            area.getDocument().insertString(area.getDocument().getLength(), toAppend, style);
307        } catch (BadLocationException JavaDoc e) { }
308     }
309     
310     public void writeLine(final String JavaDoc line) {
311         SwingUtilities.invokeLater( new Runnable JavaDoc() {
312             public void run() {
313                 if (line.startsWith("=>"))
314                     append(line, resultStyle);
315                 else
316                     append(line, outputStyle);
317             }
318         });
319     }
320     
321     public void write(int b) throws IOException JavaDoc {
322         writeLine("" + b);
323     }
324     
325     public void write(byte[] b, int off, int len) {
326         writeLine(new String JavaDoc(b, off, len));
327     }
328     
329     public void write(byte[] b) {
330         writeLine(new String JavaDoc(b));
331     }
332 }
333
Popular Tags