View Javadoc

1   /*
2    *  File: ConsoleControl.java 
3    *  Copyright (c) 2004-2007  Peter Kliem (Peter.Kliem@jaret.de)
4    *  A commercial license is available, see http://www.jaret.de.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Common Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/cpl-v10.html
10   */
11  package de.jaret.util.ui.console;
12  
13  import java.io.IOException;
14  import java.io.OutputStream;
15  import java.io.PrintStream;
16  import java.util.ArrayList;
17  import java.util.Iterator;
18  import java.util.List;
19  
20  import org.eclipse.swt.SWT;
21  import org.eclipse.swt.custom.StyledText;
22  import org.eclipse.swt.custom.VerifyKeyListener;
23  import org.eclipse.swt.events.VerifyEvent;
24  import org.eclipse.swt.layout.FillLayout;
25  import org.eclipse.swt.widgets.Composite;
26  
27  /**
28   * Simple widget that acts like a shell window. Entered lines are reported to attched <code>ConsoleListeners</code>.
29   * A simple history allows reusing previously entered lines. Technically the widget wraps a <code>StyledText</code>.
30   * 
31   * @author Peter Kliem
32   * @version $Id: ConsoleControl.java 242 2007-02-11 21:05:07Z olk $ ddd
33   */
34  public class ConsoleControl extends Composite implements VerifyKeyListener {
35      private List _enteredLines = new ArrayList();
36      private int _currentEnteredLineIdx = -1;
37      private List _listeners;
38      private String _prompt;
39      private int _promptEndIdx;
40      private int _promptEndOffset;
41      private StyledText _styledText;
42  
43      /**
44       * Contructor
45       * 
46       * @param parent parent composite
47       * @param style style
48       * @param prompt prompt to be displayed
49       * @param message startup message (<code>null</code> for no message)
50       */
51      public ConsoleControl(Composite parent, int style, String prompt, String message) {
52          super(parent, style);
53          _prompt = prompt;
54          createControls();
55          if (message != null && message.length() > 0) {
56              _styledText.append(message);
57              _styledText.setCaretOffset(_styledText.getCharCount());
58              writePrompt(true);
59          } else {
60              writePrompt(false);
61          }
62      }
63  
64      /**
65       * Create the controls
66       */
67      private void createControls() {
68          setLayout(new FillLayout());
69          _styledText = new StyledText(this, SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
70          _styledText.addVerifyKeyListener(this);
71      }
72  
73      /**
74       * Write the prompt and store the end index of the prompt.
75       * 
76       * @param newLine if <code>true</code> prepend a newline
77       */
78      private void writePrompt(boolean newLine) {
79          if (newLine) {
80              _styledText.append(_styledText.getLineDelimiter());
81          }
82          _styledText.append(_prompt + " ");
83          _promptEndIdx = _prompt.length() + 1;
84          _promptEndOffset = _styledText.getCaretOffset() + _promptEndIdx + _styledText.getLineDelimiter().length();
85          _styledText.setCaretOffset(_promptEndOffset);
86          _styledText.showSelection();
87      }
88  
89      /**
90       * Retrieve the caret offset in the line it is in.
91       * 
92       * @return caret ofsfet in the current line
93       */
94      private int offsetInLine() {
95          int caretOffset = _styledText.getCaretOffset();
96          int lineidx = _styledText.getLineAtOffset(caretOffset);
97          int lineoffset = _styledText.getOffsetAtLine(lineidx);
98          int posInLine = caretOffset - lineoffset;
99          return posInLine;
100     }
101 
102     /**
103      * Get the last line without the prompt.
104      * 
105      * @return last line without prompt or <code>null</code> if the line is empty.
106      */
107     private String getEnteredLine() {
108         if (_promptEndOffset <= _styledText.getCharCount() - 1) {
109             return _styledText.getText(_promptEndOffset, _styledText.getCharCount() - 1);
110         } else {
111             return null;
112         }
113     }
114 
115     /**
116      * Set the prompt to be used.
117      * 
118      * @param prompt the new prompt
119      */
120     public void setPrompt(String prompt) {
121         _prompt = prompt;
122     }
123 
124     /**
125      * Get the prompt
126      * 
127      * @return currently set prompt
128      */
129     public String getPrompt() {
130         return _prompt;
131     }
132 
133     /**
134      * Add a <code>ConsoleListener</code> to be informed about entered lines.
135      * 
136      * @param listener listener to be added
137      */
138     public void addConsoleListener(ConsoleListener listener) {
139         if (_listeners == null) {
140             _listeners = new ArrayList();
141         }
142         _listeners.add(listener);
143     }
144 
145     /**
146      * Remove a <code>ConsoleListener</code>.
147      * 
148      * @param listener listener to be removed
149      */
150     public void remConsoleListener(ConsoleListener listener) {
151         if (_listeners != null) {
152             _listeners.remove(listener);
153         }
154     }
155 
156     /**
157      * Inform all registered listeners about an entered line. The resulting Strings are concatenated to form the output
158      * of the listeners.
159      * 
160      * @param line line entered
161      * @return concatenated results from the listeners or <code>null/code> if no listener did respond with a String
162      */
163     protected String fireLineEntered(String line) {
164         if (_listeners != null) {
165             StringBuffer result = new StringBuffer();
166             Iterator it = _listeners.iterator();
167             while (it.hasNext()) {
168                 ConsoleListener listener = (ConsoleListener) it.next();
169                 String r = listener.lineEntered(this, line);
170                 if (r != null) {
171                     result.append(r);
172                 }
173             }
174             return result.toString();
175         } else {
176             return null;
177         }
178     }
179 
180     /*
181      * (non-Javadoc)
182      * 
183      * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
184      */
185     public void verifyKey(VerifyEvent verifyEvent) {
186         switch (verifyEvent.keyCode) {
187         case SWT.ARROW_LEFT:
188         case SWT.BS:
189             System.out.println("left " + _promptEndIdx + " " + offsetInLine());
190             if (offsetInLine() <= _promptEndIdx) {
191                 System.out.println("ignore");
192                 verifyEvent.doit = false;
193             }
194             break;
195         case SWT.ARROW_UP:
196             int idx = _currentEnteredLineIdx - 1;
197             if (idx >= 0) {
198                 replaceEnteredLineWith((String) _enteredLines.get(idx));
199                 _currentEnteredLineIdx = idx;
200             }
201             verifyEvent.doit = false;
202             break;
203         case SWT.ARROW_DOWN:
204             int idx2 = _currentEnteredLineIdx + 1;
205             if (idx2 <= _enteredLines.size() - 1) {
206                 replaceEnteredLineWith((String) _enteredLines.get(idx2));
207                 _currentEnteredLineIdx = idx2;
208             }
209             verifyEvent.doit = false;
210             break;
211         case SWT.CR:
212             String line = getEnteredLine();
213             _styledText.setCaretOffset(_styledText.getCharCount());
214             if (line != null) {
215                 _enteredLines.add(line);
216                 _currentEnteredLineIdx = _enteredLines.size();
217                 String result = fireLineEntered(line);
218                 if (result != null && result.length() > 0) {
219                     _styledText.append(_styledText.getLineDelimiter());
220                     _styledText.append(result);
221                     _styledText.setCaretOffset(_styledText.getCharCount());
222                 }
223             } else {
224                 // entered line was empty
225             }
226             writePrompt(true);
227             verifyEvent.doit = false;
228             break;
229 
230         default:
231             break;
232         }
233     }
234 
235     /**
236      * Append the given text to the console output
237      * 
238      * @param text text to be appended
239      */
240     public void output(String text) {
241         _styledText.append(text);
242         _styledText.setCaretOffset(_styledText.getCaretOffset() + text.length());
243         _styledText.showSelection();
244     }
245 
246     /**
247      * Get a <code>PrintStream</code> that prints to the console.
248      * 
249      * @return a PrintStream printing to the console
250      */
251     public PrintStream getPrintStream() {
252         return new PrintStream(new ConsoleOutStream(this));
253     }
254 
255     /**
256      * Replace the currently entered line with the given string
257      * 
258      * @param string text to be set in the current line
259      */
260     private void replaceEnteredLineWith(String string) {
261         _styledText.replaceTextRange(_promptEndOffset, _styledText.getCharCount() - _promptEndOffset, string);
262         _styledText.setCaretOffset(_styledText.getCharCount());
263     }
264 
265     /**
266      * An implemenation of an <code>OutputStream</code> writing to the console.
267      * 
268      * @author Peter Kliem
269      */
270     public class ConsoleOutStream extends OutputStream {
271         ConsoleControl _consoleControl;
272 
273         /**
274          * @param control ConsoleControl to write to
275          */
276         public ConsoleOutStream(ConsoleControl control) {
277             super();
278             _consoleControl = control;
279         }
280 
281         /*
282          * (non-Javadoc)
283          * 
284          * @see java.io.OutputStream#write(int)
285          */
286         public void write(int b) throws IOException {
287             _consoleControl.output("" + (char) b);
288         }
289     }
290 
291 }