00001 package GuiComponents.Console;
00002
00003 import javax.swing.*;
00004 import javax.swing.event.*;
00005 import javax.swing.text.*;
00006 import java.util.*;
00007 import java.awt.Font;
00008 import java.awt.Insets;
00009 import java.awt.Component;
00010 import java.awt.event.*;
00011 import java.beans.PropertyChangeListener;
00012 import java.beans.PropertyChangeEvent;
00013 import java.io.*;
00014
00025 public class JConsole extends JEditorPane
00026 implements KeyListener, ActionListener, PropertyChangeListener, MouseListener, CaretListener {
00027
00028
00029 protected JPopupMenu mPopup;
00030 protected String sPrompt;
00031 protected String sPostPrompt;
00032 protected char cEnterChar= '\n';
00033 private int lineStartPos = 0;
00034 private int startPos = 0;
00035 private int currPos = 0;
00036 protected Vector vListeners = new Vector();
00037 protected Vector nameListeners = new Vector();
00038 protected Vector vHistory = new Vector();
00039 private int historyPos = 0;
00040 private String curCmd;
00041 protected AbstractDocument doc;
00042
00043
00044 private final static String CUT = "Cut";
00045 private final static String COPY = "Copy";
00046 private final static String PASTE = "Paste";
00047
00049 public JConsole() {
00050 initComponents();
00051 requestFocus();
00052 }
00053
00054 protected void initComponents() {
00055
00056
00057 doc = new PlainDocument() {
00058 public void remove(int offs, int len) throws BadLocationException {
00059 if (offs>=startPos) super.remove(offs, len);
00060 }
00061 };
00062 doc.setAsynchronousLoadPriority(1);
00063
00064 setDocument(doc);
00065 Font font = new Font("Monospaced",Font.PLAIN,14);
00066 setText("");
00067 setFont( font );
00068 setMargin( new Insets(7,5,7,5) );
00069 addKeyListener(this);
00070 setDoubleBuffered(true);
00071
00072
00073 mPopup = new JPopupMenu("JConsole Menu");
00074 mPopup.add(new JMenuItem(CUT)).addActionListener(this);
00075 mPopup.add(new JMenuItem(COPY)).addActionListener(this);
00076 mPopup.add(new JMenuItem(PASTE)).addActionListener(this);
00077
00078 addMouseListener(this);
00079 addCaretListener(this);
00080
00081
00082 UIManager.addPropertyChangeListener(this);
00083 }
00084
00085 public void initialize() {
00086 resetCommandStart();
00087 }
00088
00089 public InputStream getInputStream() {
00090 return new ActionStream(this);
00091 }
00092
00093 public void cut() {
00094 if (getCaretPosition() < startPos) {
00095 super.copy();
00096 } else {
00097 super.cut();
00098 }
00099 }
00100
00101 public void paste() {
00102
00103 ensureCaretPosition();
00104 super.paste();
00105 }
00106
00107 public void setCaretPosition(int position) {
00108
00109 if (position < startPos) return;
00110 super.setCaretPosition(position);
00111 }
00112
00113
00114
00115
00116
00117
00121 public void actionPerformed(ActionEvent e) {
00122 String cmd = e.getActionCommand();
00123 if (cmd.equals(CUT)) {
00124 cut();
00125 } else if (cmd.equals(COPY)) {
00126 copy();
00127 } else if (cmd.equals(PASTE)) {
00128 paste();
00129 }
00130 }
00131
00137 public void keyPressed(KeyEvent e) {
00138 switch ( e.getKeyCode() ) {
00139 case ( KeyEvent.VK_UP ):
00140 if (e.getID() == KeyEvent.KEY_PRESSED) {
00141 historyUp();
00142 }
00143 e.consume();
00144 break;
00145
00146 case ( KeyEvent.VK_DOWN ):
00147 if (e.getID() == KeyEvent.KEY_PRESSED) {
00148 historyDown();
00149 }
00150 e.consume();
00151 break;
00152
00153
00154 case ( KeyEvent.VK_LEFT ):
00155 case ( KeyEvent.VK_BACK_SPACE ):
00156 case ( KeyEvent.VK_DELETE ):
00157 if (getCaretPosition() <= startPos) e.consume();
00158 break;
00159
00160 case (KeyEvent.VK_END):
00161 setCaretPosition(doc.getLength());
00162 e.consume();
00163 break;
00164
00165 case ( KeyEvent.VK_HOME ):
00166 setCaretPosition(startPos);
00167 e.consume();
00168 break;
00169
00170 case (KeyEvent.VK_TAB):
00171 case (KeyEvent.VK_ENTER):
00172 e.consume();
00173 break;
00174
00175 }
00176
00177 }
00178
00179
00185 public void keyReleased(KeyEvent e) {
00186 }
00187
00193 public void keyTyped(KeyEvent e) {
00194 if (e.getKeyChar() == cEnterChar) {
00195 enter();
00196 e.consume();
00197 }
00198
00199 if (e.getKeyChar() == '\t') {
00200 nameCompletionEvent();
00201 e.consume();
00202 }
00203
00204 ensureCaretPosition();
00205 }
00206
00210 public void caretUpdate(CaretEvent e) {
00211
00212 if (e.getDot() == e.getMark()) {
00213 if (e.getDot() < startPos) {
00214 setCaretPosition(currPos);
00215 } else {
00216
00217 currPos = e.getDot();
00218
00219 }
00220 }
00221 }
00222
00223 protected void ensureCaretPosition() {
00224 if (getCaretPosition() != currPos) setCaretPosition(currPos);
00225 }
00226
00231 public void mouseClicked(MouseEvent e) {
00232 }
00233
00237 public void mouseEntered(MouseEvent e) {
00238 }
00239
00243 public void mouseExited(MouseEvent e) {
00244 }
00245
00249 public void mousePressed(MouseEvent e) {
00250 showMenu(e);
00251 }
00252
00256 public void mouseReleased(MouseEvent e) {
00257 showMenu(e);
00258 }
00259
00260 private void showMenu(MouseEvent e) {
00261 if (e.isPopupTrigger()) {
00262 mPopup.show((Component)e.getSource(), e.getX(), e.getY());
00263 }
00264 }
00265
00271 public void propertyChange(PropertyChangeEvent evt) {
00272 if (evt.getPropertyName().equals("lookAndFeel")) {
00273 SwingUtilities.updateComponentTreeUI(mPopup);
00274 }
00275 }
00276
00277
00278 public void addActionListener(ActionListener al) {
00279 vListeners.add(al);
00280 }
00281
00282 public void removeActionListener(ActionListener al) {
00283 vListeners.remove(al);
00284 }
00285
00286
00287 public void addNameCompletionListener(NameCompletionListener tl) {
00288 nameListeners.add(tl);
00289 }
00290
00291 public void removeNameCompletionListener(NameCompletionListener tl) {
00292 nameListeners.remove(tl);
00293 }
00294
00295
00296
00297 protected void nameCompletionEvent() {
00298 ArrayList allCompletions = new ArrayList();
00299 String cmd = getCmd();
00300 for (int i=0; i<nameListeners.size(); i++) {
00301 List l = ((NameCompletionListener)nameListeners.get(i)).completeName(cmd);
00302 if (l!= null) allCompletions.addAll(l);
00303 }
00304
00305
00306 if (allCompletions.size() == 0) return;
00307
00308 String complete = completeInline(cmd, allCompletions);
00309
00310 if (allCompletions.size() == 1) {
00311 complete = complete.substring(cmd.length());
00312 append(complete);
00313 } else {
00314 println();
00315 append("\n");
00316 Iterator i = allCompletions.iterator();
00317 while (i.hasNext()) {
00318 append(i.next() + "\n");
00319 }
00320 resetCommandStart();
00321 append(complete);
00322 }
00323
00324 }
00325
00329 protected String completeInline(String part, List l) {
00330
00331 if (l.size() == 0) return part;
00332 if (l.size() == 1) return l.get(0).toString();
00333
00334
00335
00336
00337
00338 String complete = part;
00339 String temp;
00340 boolean retVal = true;
00341 int index = part.length() + 1;
00342 while (index <= ((String)l.get(0)).length()) {
00343 temp = ((String)l.get(0)).substring(0, index);
00344 for (int j=1; j<l.size(); j++) {
00345 retVal &= ((String)l.get(j)).startsWith(temp);
00346 }
00347 if (!retVal) break;
00348 index++;
00349 complete = temp;
00350 }
00351
00352 return complete;
00353 }
00354
00355
00356
00357
00358
00363 public void resetCommandStart() {
00364
00365 int pos = doc.getLength();
00366 append(sPrompt);
00367 lineStartPos = pos;
00368 pos = doc.getLength();
00369 append(sPostPrompt);
00370 startPos = pos;
00371 currPos = doc.getLength();
00372
00373 }
00374
00375 public void append(String string) {
00376 insert(string, doc.getLength());
00377 }
00378
00379 private void insert(String string, int pos) {
00380 String s = (string==null) ? string = "" : string;
00381 try {
00382
00383 doc.insertString(pos, s, null);
00384 if (pos < lineStartPos) lineStartPos += s.length();
00385 if (pos < startPos) startPos += s.length();
00386
00387
00388 } catch(javax.swing.text.BadLocationException ble) {
00389
00390 ble.printStackTrace();
00391 }
00392 }
00393
00394 String replaceRange(Object s, int start, int end) {
00395 String st = s.toString();
00396 select(start, end);
00397 replaceSelection(st);
00398
00399 return st;
00400 }
00401
00402
00403 protected void enter() {
00404 String s = getCmd();
00405
00406 if (s.length() == 0) s = "\n";
00407 else {
00408 vHistory.addElement(s);
00409 s = s +"\n";
00410 }
00411
00412 append("\n");
00413 historyPos = 0;
00414 resetCommandStart();
00415 dispatchEvent(s);
00416 }
00417
00418 private String getCmd() {
00419 String s = "";
00420 try {
00421 s = getText(startPos, getText().length() - startPos);
00422 } catch (BadLocationException e) {
00423
00424 System.out.println("Internal Error: JConsole getCmd: "+e);
00425 }
00426 return s;
00427 }
00428
00429 protected void dispatchEvent(String cmd) {
00430 ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_FIRST, cmd);
00431 for (int i=0; i<vListeners.size(); i++) {
00432 ((ActionListener)vListeners.get(i)).actionPerformed(e);
00433 }
00434 }
00435
00436
00437
00438 public String getPrompt() {
00439 return sPrompt;
00440 }
00441
00442 public void setPrompt(String prompt) {
00443 sPrompt = prompt;
00444 }
00445
00446 public String getPostPrompt() {
00447 return sPostPrompt;
00448 }
00449
00450 public void setPostPrompt(String postPrompt) {
00451 sPostPrompt = postPrompt;
00452 }
00453
00454
00455
00456
00457 protected void historyUp() {
00458 if (vHistory.size() == 0) return;
00459 if (historyPos == 0) curCmd = getCmd();
00460 if (historyPos < vHistory.size()) {
00461 historyPos++;
00462 showHistoryLine();
00463 }
00464 }
00465
00466 protected void historyDown() {
00467 if (historyPos == 0) return;
00468
00469 historyPos--;
00470 showHistoryLine();
00471 }
00472
00473 protected void showHistoryLine() {
00474 String line;
00475 if (historyPos == 0) line = curCmd;
00476 else line = (String)vHistory.elementAt(vHistory.size() - historyPos);
00477
00478 replaceRange(line, startPos, getText().length() );
00479
00480 repaint();
00481 }
00482
00483 public String toString() {
00484 return "JConsole";
00485 }
00486
00487
00488
00489
00490 public void println(String string) {
00491 print( string + "\n" );
00492 }
00493
00494 public void print(String string) {
00495 insert(string, lineStartPos );
00496
00497 }
00498
00499 public void println() {
00500 print("\n");
00501 }
00502
00503 public void println(Object object) {
00504 print(new StringBuffer(String.valueOf(object)).append("\n"));
00505 }
00506
00507 public void print(Object object) {
00508 print(String.valueOf(object));
00509 }
00510
00511
00512 class ActionStream extends InputStream implements ActionListener {
00513 protected JConsole console;
00514 protected java.util.List list;
00515 private byte[] current;
00516 private int pos;
00517
00518 public ActionStream(JConsole console) {
00519 this.console = console;
00520 console.addActionListener(this);
00521 list = Collections.synchronizedList(new LinkedList());
00522 }
00523
00527 public synchronized void actionPerformed(ActionEvent e) {
00528 list.add(e.getActionCommand());
00529 }
00530
00538 public void close() throws IOException {
00539 console.removeActionListener(this);
00540 }
00541
00542
00557 public int read() throws IOException {
00558 if (current == null || pos == current.length) {
00559 if (list.size() > 0) {
00560 current = ((String)list.get(0)).getBytes();
00561 pos = 0;
00562 } else {
00563 while (list.size() == 0) {
00564 try {
00565 Thread.currentThread().sleep(100);
00566 } catch (java.lang.InterruptedException e){}
00567 }
00568 }
00569 }
00570 return current[pos++];
00571 }
00572
00573 }
00574 }