1/*
2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.ui;
26
27import java.awt.*;
28import java.awt.event.*;
29import javax.swing.*;
30import javax.swing.event.*;
31import javax.swing.text.*;
32
33import sun.jvm.hotspot.debugger.*;
34import sun.jvm.hotspot.utilities.*;
35
36/** A JPanel subclass containing a scrollable text area displaying the
37    debugger's console, if it has one. This should not be created for
38    a debugger which does not have a console. */
39
40public class DebuggerConsolePanel extends JPanel {
41  private Debugger debugger;
42  private JTextComponent editor;
43  private boolean updating;
44  private int     mark;
45  private String  curText;  // handles multi-line input via '\'
46  // Don't run the "main" method of this class unless this flag is set to true first
47  private static final boolean DEBUGGING = false;
48
49  public DebuggerConsolePanel(Debugger debugger) {
50    this.debugger = debugger;
51    if (!DEBUGGING) {
52      if (Assert.ASSERTS_ENABLED) {
53        Assert.that(debugger.hasConsole(), "should not create a DebuggerConsolePanel for non-console debuggers");
54      }
55    }
56
57    setLayout(new BorderLayout());
58
59    editor = new JTextArea();
60    editor.setDocument(new EditableAtEndDocument());
61    editor.setFont(GraphicsUtilities.lookupFont("Courier"));
62    JScrollPane scroller = new JScrollPane();
63    scroller.getViewport().add(editor);
64    add(scroller, BorderLayout.CENTER);
65
66    editor.getDocument().addDocumentListener(new DocumentListener() {
67        public void changedUpdate(DocumentEvent e) {
68        }
69
70        public void insertUpdate(DocumentEvent e) {
71          if (updating) return;
72          beginUpdate();
73          editor.setCaretPosition(editor.getDocument().getLength());
74          if (insertContains(e, '\n')) {
75            String cmd = getMarkedText();
76            // Handle multi-line input
77            if ((cmd.length() == 0) || (cmd.charAt(cmd.length() - 1) != '\\')) {
78              // Trim "\\n" combinations
79              cmd = trimContinuations(cmd);
80              final String result;
81              if (DEBUGGING) {
82                System.err.println("Entered command: \"" + cmd + "\"");
83                result = "";
84              } else {
85                result = DebuggerConsolePanel.this.debugger.consoleExecuteCommand(cmd);
86              }
87
88              SwingUtilities.invokeLater(new Runnable() {
89                  public void run() {
90                    print(result);
91                    printPrompt();
92                    setMark();
93                    endUpdate();
94                  }
95                });
96            }
97          } else {
98            endUpdate();
99          }
100        }
101
102        public void removeUpdate(DocumentEvent e) {
103        }
104      });
105
106    // This is a bit of a hack but is probably better than relying on
107    // the JEditorPane to update the caret's position precisely the
108    // size of the insertion
109    editor.addCaretListener(new CaretListener() {
110        public void caretUpdate(CaretEvent e) {
111          int len = editor.getDocument().getLength();
112          if (e.getDot() > len) {
113            editor.setCaretPosition(len);
114          }
115        }
116      });
117
118    Box hbox = Box.createHorizontalBox();
119    hbox.add(Box.createGlue());
120    JButton button = new JButton("Clear Saved Text");
121    button.addActionListener(new ActionListener() {
122        public void actionPerformed(ActionEvent e) {
123          clear();
124        }
125      });
126    hbox.add(button);
127    hbox.add(Box.createGlue());
128    add(hbox, BorderLayout.SOUTH);
129
130    clear();
131  }
132
133  public void requestFocus() {
134    editor.requestFocus();
135  }
136
137  public void clear() {
138    EditableAtEndDocument d = (EditableAtEndDocument) editor.getDocument();
139    d.clear();
140    printPrompt();
141    setMark();
142    editor.requestFocus();
143  }
144
145  public void setMark() {
146    ((EditableAtEndDocument) editor.getDocument()).setMark();
147  }
148
149  public String getMarkedText() {
150    try {
151      String s = ((EditableAtEndDocument) editor.getDocument()).getMarkedText();
152      int i = s.length();
153      while ((i > 0) && (s.charAt(i - 1) == '\n')) {
154        i--;
155      }
156      return s.substring(0, i);
157    }
158    catch (BadLocationException e) {
159      e.printStackTrace();
160      return null;
161    }
162  }
163
164  //--------------------------------------------------------------------------------
165  // Internals only below this point
166  //
167
168  private void beginUpdate() {
169    updating = true;
170  }
171
172  private void endUpdate() {
173    updating = false;
174  }
175
176  private void print(String s) {
177    Document d = editor.getDocument();
178    try {
179      d.insertString(d.getLength(), s, null);
180    }
181    catch (BadLocationException e) {
182      e.printStackTrace();
183    }
184  }
185
186  private void printPrompt() {
187    if (DEBUGGING) {
188      print("foo> ");
189    } else {
190      print(debugger.getConsolePrompt());
191    }
192  }
193
194  private boolean insertContains(DocumentEvent e, char c) {
195    String s = null;
196    try {
197      s = editor.getText(e.getOffset(), e.getLength());
198      for (int i = 0; i < e.getLength(); i++) {
199        if (s.charAt(i) == c) {
200          return true;
201        }
202      }
203    }
204    catch (BadLocationException ex) {
205      ex.printStackTrace();
206    }
207    return false;
208  }
209
210  private String trimContinuations(String text) {
211    int i;
212    while ((i = text.indexOf("\\\n")) >= 0) {
213      text = text.substring(0, i) + text.substring(i+2, text.length());
214    }
215    return text;
216  }
217
218  public static void main(String[] args) {
219    JFrame frame = new JFrame();
220    frame.getContentPane().setLayout(new BorderLayout());
221    DebuggerConsolePanel panel = new DebuggerConsolePanel(null);
222    frame.getContentPane().add(panel, BorderLayout.CENTER);
223    frame.addWindowListener(new WindowAdapter() {
224        public void windowClosing(WindowEvent e) {
225          System.exit(0);
226        }
227      });
228    frame.setSize(500, 500);
229    frame.setVisible(true);
230    panel.requestFocus();
231  }
232}
233