Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 585   Methods: 34
NCLOC: 427   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ExternalProcessPanel.java 0% 0% 0% 0%
coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.ui;
 38   
 39    import java.awt.*;
 40    import java.awt.event.*;
 41    import java.io.*;
 42    import java.util.List;
 43    import java.util.ArrayList;
 44    import javax.swing.*;
 45   
 46    import edu.rice.cs.util.swing.Utilities;
 47    import edu.rice.cs.util.ProcessCreator;
 48    import edu.rice.cs.drjava.ui.predictive.*;
 49    import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
 50    import edu.rice.cs.plt.concurrent.CompletionMonitor;
 51    import edu.rice.cs.drjava.model.DrJavaFileUtils;
 52    import static edu.rice.cs.drjava.ui.MainFrameStatics.GoToFileListEntry;
 53   
 54    /** Panel for displaying some component with buttons, one of which is an "Abort" button.
 55    * This should be used to display the output of an external process.
 56    * This class is a swing class that should only be accessed from the event thread.
 57    * @version $Id: ExternalProcessPanel.java 5254 2010-05-19 17:04:42Z mgricken $
 58    */
 59    public class ExternalProcessPanel extends AbortablePanel {
 60    /** Size of the buffer read at once. */
 61    public final int BUFFER_SIZE = 10240;
 62    /** Number of buffer reads before the event thread is allowed to do something else. */
 63    public final int BUFFER_READS_PER_TIMER = 5;
 64    protected JTextArea _textArea;
 65    protected ProcessCreator _pc = null;
 66    protected Process _p = null;
 67    protected InputStreamReader _is = null;
 68    protected InputStreamReader _erris = null;
 69    protected JButton _updateNowButton;
 70    protected JButton _runAgainButton;
 71    protected Thread _updateThread;
 72    protected Thread _readThread;
 73    protected Thread _deathThread;
 74    protected StringBuilder _sb = new StringBuilder();
 75    protected volatile int _changeCount = 0;
 76    private char[] _buf = new char[BUFFER_SIZE];
 77    private int _red = -1;
 78    private char[] _errbuf = new char[BUFFER_SIZE];
 79    private int _errred = -1;
 80    private int _retVal;
 81    private String _header;
 82    protected CompletionMonitor _abortMonitor = new CompletionMonitor();
 83   
 84    /** Constructs a new "process" panel to watch process output.
 85    * This is swing view class and hence should only be accessed from the event thread.
 86    * @param frame the MainFrame
 87    * @param title title of the pane
 88    * @param pc the process creator to use
 89    */
 90  0 public ExternalProcessPanel(MainFrame frame, String title, ProcessCreator pc) {
 91  0 super(frame, title);
 92  0 _sb = new StringBuilder("Command line: ");
 93  0 _sb.append(pc.cmdline());
 94  0 _sb.append('\n');
 95  0 _header = _sb.toString();
 96  0 _textArea.setText(_header); // _textArea is non-null because makeLeftPanel() gets called in super constructor
 97  0 initThread(pc);
 98  0 _textArea.addMouseListener(new MouseListener() {
 99  0 public void mouseClicked(MouseEvent e) {
 100  0 if ((SwingUtilities.isLeftMouseButton(e)) &&
 101    (e.getClickCount() == 2)) {
 102  0 doubleClicked(e);
 103    }
 104    }
 105  0 public void mouseEntered(MouseEvent e) { }
 106  0 public void mouseExited(MouseEvent e) { }
 107  0 public void mousePressed(MouseEvent e) { }
 108  0 public void mouseReleased(MouseEvent e) { }
 109    });
 110  0 EventQueue.invokeLater(new Runnable() {
 111  0 public void run() { updateText(); } });
 112    // MainFrame.LOG.log("\tProcessPanel ctor done");
 113    }
 114   
 115  0 protected void initThread(ProcessCreator pc) {
 116  0 _abortMonitor.reset();
 117    // MainFrame.LOG.log("\tProcessPanel ctor");
 118  0 try {
 119  0 _pc = pc;
 120  0 _pc.getPropertyMaps().clearVariables();
 121  0 _readThread = new Thread(new Runnable() {
 122  0 public void run() {
 123  0 while((_is != null) || (_erris != null)) {
 124  0 readText(false);
 125    }
 126    }
 127    },"External Process Read Thread");
 128  0 _updateThread = new Thread(new Runnable() {
 129  0 public void run() {
 130  0 while((_is != null) || (_erris != null)) {
 131  0 try {
 132  0 Thread.sleep(edu.rice.cs.drjava.DrJava.getConfig().
 133    getSetting(edu.rice.cs.drjava.config.OptionConstants.FOLLOW_FILE_DELAY));
 134    }
 135    catch(InterruptedException ie) { /* ignore */ }
 136  0 updateText();
 137    }
 138    }
 139    },"External Process Update Thread");
 140  0 _p = _pc.start();
 141  0 _sb.append("Evaluated command line: ");
 142  0 _sb.append(_pc.evaluatedCommandLine());
 143  0 _sb.append('\n');
 144  0 _is = new InputStreamReader(_p.getInputStream());
 145  0 _erris = new InputStreamReader(_p.getErrorStream());
 146  0 _readThread.start();
 147  0 _updateThread.start();
 148  0 _updateNowButton.setEnabled(true);
 149  0 _deathThread = new Thread(new Runnable() {
 150  0 public void run() {
 151  0 try {
 152  0 _retVal = _p.waitFor();
 153  0 Utilities.invokeLater(new Runnable() {
 154  0 public void run() {
 155  0 _sb.append("\n\nProcess returned ");
 156  0 _sb.append(_retVal);
 157  0 _sb.append("\n");
 158  0 _textArea.setText(_sb.toString());
 159    }
 160    });
 161    }
 162    catch(InterruptedException e) {
 163  0 Utilities.invokeLater(new Runnable() {
 164  0 public void run() {
 165  0 _p.destroy();
 166  0 _sb.append("\n\nProcess returned ");
 167  0 _sb.append(_retVal);
 168  0 _sb.append("\n");
 169  0 _textArea.setText(_sb.toString());
 170    }
 171    });
 172    }
 173    finally {
 174  0 abortActionPerformed(null);
 175    }
 176    }
 177    },"External Process Death Thread");
 178  0 _deathThread.start();
 179    // MainFrame.LOG.log("\tUpdate thread started");
 180    }
 181    catch(Exception e) {
 182  0 _sb.append("\n\nException from process:\n" + e.toString());
 183  0 _textArea.setText(_sb.toString());
 184  0 edu.rice.cs.util.GeneralProcessCreator.LOG.log(_sb.toString());
 185  0 abortActionPerformed(null);
 186    }
 187    }
 188   
 189    /** Setup left panel. Must be overridden to return the component on the left side. */
 190  0 protected Component makeLeftPanel() {
 191  0 _textArea = new JTextArea();
 192  0 _textArea.setEditable(false);
 193  0 return _textArea;
 194    }
 195   
 196    /** Abort action was performed.
 197    * @param e action event performed by user, or null if aborted due to problem */
 198  0 protected void abortActionPerformed(ActionEvent e) {
 199  0 _abortButton.setEnabled(false);
 200  0 _updateNowButton.setEnabled(false);
 201  0 _runAgainButton.setEnabled(true);
 202    // spin this off in a separate thread so the event thread is free
 203  0 new Thread(new Runnable() {
 204  0 public void run() {
 205  0 if (_is != null) {
 206  0 try {
 207    // cannot close() an InputStreamReader from thread A while thread B is blocked in read()
 208    // close() will block as well, so we close the InputStream of the process first
 209  0 _p.getInputStream().close();
 210  0 _is.close();
 211    }
 212    catch(IOException ioe) { /* ignore, just stop polling */ }
 213  0 _is = null;
 214  0 Utilities.invokeLater(new Runnable() { public void run() { updateButtons(); } });
 215    }
 216  0 if (_erris != null) {
 217  0 try {
 218    // cannot close() an InputStreamReader from thread A while thread B is blocked in read()
 219    // close() will block as well, so we close the InputStream of the process first
 220  0 _p.getErrorStream().close();
 221  0 _erris.close();
 222    }
 223    catch(IOException ioe) { /* ignore, just stop polling */ }
 224  0 _erris = null;
 225  0 Utilities.invokeLater(new Runnable() { public void run() { updateButtons(); } });
 226    }
 227  0 if (_p != null) {
 228  0 _p.destroy();
 229  0 _p = null;
 230    }
 231  0 Utilities.invokeLater(new Runnable() { public void run() { updateText(); updateButtons(); } });
 232  0 _abortMonitor.signal();
 233    }
 234    }).start();
 235    }
 236   
 237    /** Run Again action was performed
 238    * @param e action event performed by user, or null if initiated programmatically */
 239  0 protected void runAgainActionPerformed(ActionEvent e) {
 240  0 abortActionPerformed(e);
 241  0 _abortButton.setEnabled(false);
 242  0 _updateNowButton.setEnabled(false);
 243  0 _runAgainButton.setEnabled(false);
 244    // spin this off in a separate thread so the event thread is free
 245  0 new Thread(new Runnable() {
 246  0 public void run() {
 247  0 _abortMonitor.attemptEnsureSignaled(); // wait for the abortActionPerformed() call to finish
 248  0 _abortMonitor.reset();
 249  0 _sb = new StringBuilder("Command line: ");
 250  0 _sb.append(_pc.cmdline());
 251  0 _sb.append('\n');
 252  0 _header = _sb.toString();
 253  0 initThread(_pc);
 254  0 EventQueue.invokeLater(new Runnable() {
 255  0 public void run() {
 256  0 updateText();
 257    } });
 258    }
 259    }).start();
 260    }
 261   
 262    // public static edu.rice.cs.util.Log LOG = new edu.rice.cs.util.Log("external.txt",true);
 263   
 264    /** Gets called when the user double-clicks on the text pane. */
 265  0 public void doubleClicked(MouseEvent e) {
 266    // LOG.log("doubleClicked");
 267   
 268  0 List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
 269  0 if ((docs == null) || (docs.size() == 0)) return; // do nothing
 270   
 271  0 final String t = _textArea.getText();
 272  0 int caret = _textArea.getCaretPosition();
 273  0 int start = caret;
 274  0 int end = start;
 275  0 while((start-1 > 0) && (t.charAt(start-1) != '\n')) { --start; }
 276  0 while((end >= 0) && (end < t.length()) && (t.charAt(end) != '\n')) { ++end; }
 277   
 278    // LOG.log("\tstart=" + start + "\n\tend=" + end);
 279  0 if ((start < 0) || (end < 0) || (start >= t.length()) || (end >= t.length())) return;
 280  0 final String line = t.substring(start,end);
 281    // LOG.log("\t'" + line + "'");
 282  0 caret -= start; // calculate caret position within the line
 283  0 if (caret>=line.length()) { caret = line.length()-1; }
 284  0 start = end = caret;
 285  0 char ch;
 286  0 while((end >= 0) && (end<line.length())) {
 287  0 ch = line.charAt(end);
 288  0 if (ch == ':') {
 289  0 if ((end + 1 < line.length()) && (Character.isDigit(line.charAt(end+1)))) {
 290    // perhaps a colon followed by a line number: Foo.java:10
 291    // advance to the end of the number, then break
 292  0 do {
 293  0 ++end;
 294  0 } while((end < line.length()) && (Character.isDigit(line.charAt(end))));
 295  0 break;
 296    }
 297    else {
 298    // colon without digit behind it, break here
 299  0 break;
 300    }
 301    }
 302  0 else if (Character.isJavaIdentifierPart(ch)) {
 303    // character is a Java identifier part, advance
 304  0 ++end;
 305    }
 306  0 else if ((ch=='.') || (ch == File.separatorChar)) {
 307    // allow the period and file separator, could be the part of file name; advance
 308  0 ++end;
 309    }
 310    else {
 311    // character should not be in a Java name, break here
 312  0 break;
 313    }
 314    }
 315   
 316  0 ArrayList<GoToFileListEntry> list;
 317  0 list = new ArrayList<GoToFileListEntry>(docs.size());
 318    // create a list with fully qualified class names
 319  0 for(OpenDefinitionsDocument d: docs) {
 320    // LOG.log("Doc: " + d);
 321  0 try {
 322  0 String fullyQualified = d.getPackageName() + "." + d.toString();
 323  0 if (fullyQualified.startsWith(".")) { fullyQualified = fullyQualified.substring(1); }
 324  0 list.add(new GoToFileListEntry(d, fullyQualified));
 325    // LOG.log("\tname: " + fullyQualified);
 326    }
 327    catch(IllegalStateException ex) { /* ignore */ }
 328    }
 329  0 PredictiveInputModel<GoToFileListEntry> pim =
 330    new PredictiveInputModel<GoToFileListEntry>(true, new PredictiveInputModel.PrefixLineNumStrategy<GoToFileListEntry>(), list);
 331   
 332  0 GoToFileListEntry uniqueMatch = null;
 333  0 String name, oldName = null, simpleName = null;
 334  0 while ((start >= 0) && (start < line.length()) && Character.isWhitespace(line.charAt(start))) {
 335  0 --start;
 336    }
 337  0 while(start > 0) {
 338  0 ch = line.charAt(start);
 339  0 while(start > 0) {
 340  0 ch = line.charAt(start);
 341  0 if ((ch == ':') || (ch == '.') || (Character.isJavaIdentifierPart(ch))) { --start; } else { break; }
 342    }
 343    // LOG.log("\tstart=" + start + "\n\tend=" + end);
 344  0 if ((start >= 0) && (end>=start) && (start<line.length()) && (end<line.length())) {
 345  0 name = line.substring(start,end).replace(File.separatorChar, '.');
 346  0 if ((name.length() > 0) && (! Character.isJavaIdentifierPart(name.charAt(0)))) { name = name.substring(1); }
 347  0 if (simpleName == null) { simpleName = name; }
 348  0 if (name.equals(oldName)) { break; }
 349  0 if (DrJavaFileUtils.isSourceFile(name)) {
 350    // LOG.log("\t--> '" + name + "'");
 351  0 uniqueMatch = getUniqueMatch(name, pim);
 352  0 if (uniqueMatch != null) {
 353    // unique match found, go there
 354    // LOG.log("\t ^^^^^^^^^^ unique match found");
 355  0 final OpenDefinitionsDocument newDoc = pim.getCurrentItem().getOpenDefinitionsDocument();
 356  0 if (newDoc != null) {
 357  0 final boolean docChanged = ! newDoc.equals(_model.getActiveDocument());
 358  0 final boolean docSwitch = _model.getActiveDocument() != newDoc;
 359  0 if (docSwitch) _model.setActiveDocument(newDoc);
 360  0 final int curLine = newDoc.getCurrentLine();
 361  0 final int last = name.lastIndexOf(':');
 362  0 if (last >= 0) {
 363  0 try {
 364  0 String nend = name.substring(last + 1);
 365  0 int val = Integer.parseInt(nend);
 366   
 367  0 final int lineNum = Math.max(1, val);
 368  0 Runnable command = new Runnable() {
 369  0 public void run() {
 370  0 try { _frame._jumpToLine(lineNum); } // adds this region to browser history
 371  0 catch (RuntimeException ex) { _frame._jumpToLine(curLine); }
 372    }
 373    };
 374  0 if (docSwitch) {
 375    // postpone running command until after document switch, which is pending in the event queue
 376  0 EventQueue.invokeLater(command);
 377    }
 378  0 else command.run();
 379    }
 380    catch(RuntimeException ex) { /* ignore */ }
 381    }
 382  0 else if (docChanged) {
 383    // defer executing this code until after active document switch (if any) is complete
 384  0 EventQueue.invokeLater(new Runnable() { public void run() { _frame.addToBrowserHistory(); } });
 385    }
 386    }
 387  0 break;
 388    }
 389    }
 390  0 oldName = name;
 391    }
 392    else {
 393  0 break;
 394    }
 395  0 if (ch==File.separatorChar) { --start; } // file separator ('/' or '\'), include preceding directory
 396    }
 397  0 if (uniqueMatch == null) {
 398    // couldn't find a unique match, even after gradually including the fully qualified name
 399  0 if (simpleName == null) { simpleName = ""; }
 400  0 _frame.gotoFileMatchingMask(simpleName);
 401    }
 402    }
 403   
 404    /** Return the unique match for the mask, or null if no match found or not unique.
 405    * @param mask word specifying the file to go to
 406    * @param pim predictive input model with possible matches
 407    * @return unique match, or null if no match found or not unique */
 408  0 GoToFileListEntry getUniqueMatch(String mask, PredictiveInputModel<GoToFileListEntry> pim) {
 409  0 pim.setMask(mask);
 410   
 411  0 if (pim.getMatchingItems().size() == 1) {
 412    // exactly one match, go to file
 413  0 if (pim.getCurrentItem() != null) { return pim.getCurrentItem(); }
 414    }
 415  0 return null;
 416    }
 417   
 418    /** Update button state and text. Should be overridden if additional buttons are added besides "Go To", "Remove" and "Remove All". */
 419  0 protected void updateButtons() {
 420  0 boolean ended = true;
 421  0 if (_p != null) {
 422  0 try {
 423    // try to get exitValue() to see if process has terminated; exit value is not otherwise important
 424  0 _p.exitValue();
 425    // if no exception is thrown, then the process has finished
 426  0 ended = true;
 427    }
 428    catch(IllegalThreadStateException e) {
 429    // process has NOT finished yet
 430  0 ended = false;
 431    }
 432    }
 433  0 _abortButton.setEnabled((_is != null) && (_erris != null) && (!ended));
 434  0 _updateNowButton.setEnabled((_is != null) && (_erris != null) && (!ended));
 435  0 _runAgainButton.setEnabled((_is == null) || (_erris == null) || (ended));
 436    }
 437   
 438    /** Creates the buttons for controlling the regions. Should be overridden. */
 439  0 protected JComponent[] makeButtons() {
 440  0 _updateNowButton = new JButton("Update");
 441  0 _updateNowButton.addActionListener(new ActionListener() {
 442  0 public void actionPerformed(ActionEvent e) {
 443  0 EventQueue.invokeLater(new Runnable() { public void run() { updateText(); } }); }
 444    });
 445  0 _runAgainButton = new JButton("Run Again");
 446  0 _runAgainButton.addActionListener(new ActionListener() {
 447  0 public void actionPerformed(ActionEvent e) {
 448  0 runAgainActionPerformed(e);
 449    }
 450    });
 451  0 return new JComponent[] { _updateNowButton, _runAgainButton };
 452    }
 453   
 454    /** Read new text from the stream.
 455    * @param finish whether to read the entire rest */
 456  0 protected void readText(final boolean finish) {
 457    // MainFrame.LOG.log("readText");
 458  0 if (((_is != null) || (_erris != null))) {
 459  0 _changeCount = 0;
 460    // MainFrame.LOG.log("\tgot text");
 461  0 try {
 462    // MainFrame.LOG.log("\treading...");
 463    // abort after reading 5 blocks (50 kB), read more later
 464    // don't block the event thread any longer
 465  0 while((_is != null) &&
 466    (_erris != null) &&
 467    (_changeCount <= BUFFER_READS_PER_TIMER) &&
 468    (_erris != null) &&
 469    ((_red = _is.read(_buf)) >= 0)) {
 470   
 471    // MainFrame.LOG.log("\tread " + _red + " bytes");
 472  0 _sb.append(new String(_buf, 0, _red));
 473  0 if (finish) { _changeCount = 1; } else { ++_changeCount; }
 474    }
 475  0 while((_changeCount <= BUFFER_READS_PER_TIMER) &&
 476    (_erris != null) &&
 477    ((_errred = _erris.read(_errbuf)) >= 0)) {
 478    // MainFrame.LOG.log("\tread " + _red + " bytes");
 479  0 _sb.append(new String(_errbuf, 0, _errred));
 480  0 if (finish) { _changeCount = 1; } else { ++_changeCount; }
 481    }
 482  0 if ((_red > 0) && (_changeCount < BUFFER_READS_PER_TIMER)) {
 483  0 _sb.append(new String(_buf, 0, _red));
 484  0 if (finish) { _changeCount = 1; } else { ++_changeCount; }
 485    }
 486  0 if ((_errred > 0) && (_changeCount<BUFFER_READS_PER_TIMER)) {
 487  0 _sb.append(new String(_errbuf, 0, _errred));
 488  0 if (finish) { _changeCount = 1; } else { ++_changeCount; }
 489    }
 490  0 if ((_p != null) && (_is == null)) {
 491  0 try {
 492    // try to get exitValue() to see if process has terminated; exit value is not otherwise important
 493  0 _p.exitValue();
 494    // if no exception is thrown, then the process has finished, and the stream may be null
 495    }
 496    catch(IllegalThreadStateException e) {
 497    // process has NOT finished yet, but the stream is null; this is a problem
 498  0 _sb.append("\nInput stream suddenly became null.");
 499    }
 500    }
 501  0 if ((_p != null) && (_erris == null)) {
 502  0 try {
 503    // try to get exitValue() to see if process has terminated; exit value is not otherwise important
 504  0 _p.exitValue();
 505    // if no exception is thrown, then the process has finished, and the stream may be null
 506    }
 507    catch(IllegalThreadStateException e) {
 508    // process has NOT finished yet, but the stream is null; this is a problem
 509  0 _sb.append("\nError input stream suddenly became null.");
 510    }
 511    }
 512    }
 513    catch(IOException ioe) {
 514    // MainFrame.LOG.log("\taborted");
 515    // stop polling
 516  0 if (_p != null) {
 517  0 try {
 518  0 _p.exitValue();
 519    // if we get here, process has finished, and we don't display the I/O exception
 520    }
 521    catch(IllegalThreadStateException e) {
 522    // process has NOT finished yet, display the I/O exception
 523  0 _sb.append("\n\nI/O Exception reading from process:\n" + ioe.toString());
 524  0 edu.rice.cs.util.GeneralProcessCreator.LOG.log("\n\nI/O Exception reading from process:");
 525  0 edu.rice.cs.util.GeneralProcessCreator.LOG.log(ioe.toString(),ioe);
 526    }
 527    }
 528  0 if (finish) { _changeCount = 1; } else { ++_changeCount; }
 529  0 abortActionPerformed(null);
 530    }
 531    }
 532    }
 533   
 534    /** Update the text area with the text that was read. */
 535  0 protected void updateText() {
 536    // MainFrame.LOG.log("updateText");
 537  0 if (_updateNowButton.isEnabled()) {
 538    // try {
 539    // if ((_is != null) && (_p != null) &&
 540    // (_is.ready()) &&
 541    // (_p.getInputStream().available() > 0)) { readText(false); }
 542    // }
 543    // catch(IOException ioe) {
 544    // try {
 545    // _p.exitValue();
 546    // // if we get here, process has finished, and we don't display the I/O exception
 547    // }
 548    // catch(IllegalThreadStateException e) {
 549    // // process has NOT finished yet, display the I/O exception
 550    // _sb.append("\n\nI/O Exception reading from process\n");
 551    // }
 552    // abortActionPerformed(null);
 553    // ++_changeCount;
 554    // }
 555  0 if (_changeCount > 0) {
 556  0 _changeCount = 0;
 557  0 EventQueue.invokeLater(new Runnable() {
 558  0 public void run() {
 559    // MainFrame.LOG.log("\tsetting text");
 560  0 _textArea.setText(_sb.toString());
 561  0 int maxLines = edu.rice.cs.drjava.DrJava.getConfig().
 562    getSetting(edu.rice.cs.drjava.config.OptionConstants.FOLLOW_FILE_LINES);
 563  0 if (maxLines > 0) { // if maxLines is 0, buffer is unlimited
 564  0 try {
 565  0 int start = 0;
 566  0 int len = _textArea.getText().length();
 567  0 int curLines = _textArea.getLineCount();
 568  0 if (curLines>maxLines) {
 569  0 start = _textArea.getLineStartOffset(curLines-maxLines);
 570  0 len -= start;
 571  0 _sb = new StringBuilder(_textArea.getText(start,len));
 572  0 _textArea.setText(_sb.toString());
 573    }
 574    }
 575    catch(javax.swing.text.BadLocationException e) { /* ignore, do not truncate */ }
 576    }
 577    // MainFrame.LOG.log("\ttext length = " + s.length());
 578    }
 579    });
 580    }
 581    // MainFrame.LOG.log("\tupdating buttons");
 582  0 updateButtons();
 583    }
 584    }
 585    }