Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

JConsole.java

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     //Variables    
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     //Constants
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         //A slightly modified document to prevent deletions before the startPos
00056         //This is mostly to overcome the backspace not consumed issue.
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         // create popup menu
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         // make sure popup menu follows Look & Feel
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         //System.out.println("paste: " + getCaretPosition());        
00103         ensureCaretPosition();
00104         super.paste();
00105     }
00106 
00107     public void setCaretPosition(int position) {
00108         //System.out.println("setCaretPosition to : " + position + " from "+ getCaretPosition() + "  " + lineStartPos + "  " + startPos + "  " + currPos + "  " + doc.getLength());
00109         if (position < startPos) return;
00110         super.setCaretPosition(position);
00111     }
00112 
00113     //
00114     //Listeners
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             //Prevent moving before the prompt        
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         //Default behaviour:
00204         ensureCaretPosition();
00205     }
00206     
00210     public void caretUpdate(CaretEvent e) {
00211         //System.out.println("Caret: " + e.getDot() + "  " + e.getMark());
00212         if (e.getDot() == e.getMark()) {
00213             if (e.getDot() < startPos) {
00214                 setCaretPosition(currPos);
00215             } else {
00216                 //System.out.println("Caret update " + lineStartPos + "  " + startPos + "  " + currPos + "  " + doc.getLength());
00217                 currPos = e.getDot();
00218                 //System.out.println("Caret update " + lineStartPos + "  " + startPos + "  " + currPos + "  " + doc.getLength());
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     //ActionListener functions
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     //TextListener functions
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     //Called whenever the namec completion char is pressed
00296     //Generates TextEvents
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         //Now do something with the completions
00306         if (allCompletions.size() == 0) return;          //Didn't find anything
00307         
00308         String complete = completeInline(cmd, allCompletions);
00309         //System.out.println(complete);
00310         if (allCompletions.size() == 1) {                //Only found 1 thing - complete inline
00311             complete = complete.substring(cmd.length());
00312             append(complete);
00313         } else {                            //Show options to user
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         //System.out.println("Cmd:" + getCmd());
00324     }
00325     
00329     protected String completeInline(String part, List l) {
00330         //Trivial for List size 0 or 1.
00331         if (l.size() == 0) return part;
00332         if (l.size() == 1) return l.get(0).toString();
00333         
00334         //Non-trivial bit.  We know all the strings in l begin with part.
00335         //Algorithm is to take the first one and then add chars until startsWith on 
00336         //any of the others return false.
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     //Text functions
00358     
00363     public void resetCommandStart() {
00364         //System.out.println("Reset " + lineStartPos + "  " + startPos + "  " + currPos + "  " + doc.getLength());
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         //System.out.println("Reset " + lineStartPos + "  " + startPos + "  " + currPos + "  " + doc.getLength());
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             //System.out.println(lineStartPos + "  " + startPos + "  " + currPos + "  " + string.length() + "  " + doc.getLength());
00383             doc.insertString(pos, s, null);
00384             if (pos < lineStartPos) lineStartPos += s.length();
00385             if (pos < startPos) startPos += s.length();
00386             //if (pos <= currPos) currPos += s.length();  Not needed - set by caretUpdate
00387             //System.out.println(lineStartPos + "  " + startPos + "  " + currPos + "  " + string.length() + "  " + doc.getLength());
00388         } catch(javax.swing.text.BadLocationException ble) {
00389             //Should never get here, but still
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     //Command functions
00403     protected void enter() {
00404         String s = getCmd();
00405 
00406         if (s.length() == 0) s = "\n";     //Empty return...do we want this???
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             // should not happen
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     //Prompt functions
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     //History functions
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         //moveCaretToEnd();
00480         repaint();
00481     }
00482      
00483     public String toString() {
00484         return "JConsole";
00485     }     
00486      
00487     //
00488     //Millions of print routines
00489     //
00490     public void println(String string) {
00491         print( string + "\n" );       
00492     }
00493 
00494     public void print(String string) {
00495         insert(string, lineStartPos );
00496         //moveCaretToEnd();
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     //Provides a stream interface to the console commands
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 {    //Block until some input!
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 }

Generated on Thu Jul 15 09:55:45 2004 for SCT DAQ/DCS Software - Java by doxygen 1.3.5