From 8ab4d7fd34f0d91ed71f5cd5a9016aa8adcdc2a7 Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 21 May 2010 09:43:24 +0000 Subject: [PATCH] quick workaround for JAL-537. --- src/jalview/gui/Console.java | 364 +++++++++++++++++++++++++++++++++++------- src/jalview/gui/Desktop.java | 6 +- 2 files changed, 307 insertions(+), 63 deletions(-) diff --git a/src/jalview/gui/Console.java b/src/jalview/gui/Console.java index 3be4c8b..fd40320 100644 --- a/src/jalview/gui/Console.java +++ b/src/jalview/gui/Console.java @@ -39,24 +39,24 @@ public class Console extends WindowAdapter implements WindowListener, private JFrame frame; private JTextArea textArea; - +/* unused - tally and limit for lines in console window int lines = 0; int lim = 1000; +*/ + int byteslim = 102400, bytescut = 76800; // 100k and 75k cut point. - private Thread reader; - - private Thread reader2; + private Thread reader, reader2, textAppender; private boolean quit; - private final PrintStream stdout = System.out; + private final PrintStream stdout = System.out, stderr = System.err; - private final PrintStream stderr = System.err; + private PipedInputStream pin = new PipedInputStream(); - private final PipedInputStream pin = new PipedInputStream(); + private PipedInputStream pin2 = new PipedInputStream(); - private final PipedInputStream pin2 = new PipedInputStream(); + private StringBuffer displayPipe = new StringBuffer(); Thread errorThrower; // just for testing (Throws an Exception at this Console @@ -74,6 +74,16 @@ public class Console extends WindowAdapter implements WindowListener, private void initConsole(boolean visible) { + initConsole(visible, true); + } + + /** + * + * @param visible - open the window + * @param redirect - redirect std* + */ + private void initConsole(boolean visible, boolean redirect) + { // CutAndPasteTransfer cpt = new CutAndPasteTransfer(); // textArea = cpt.getTextArea(); textArea = new JTextArea(); @@ -86,49 +96,109 @@ public class Console extends WindowAdapter implements WindowListener, BorderLayout.CENTER); frame.getContentPane().add(button, BorderLayout.SOUTH); frame.setVisible(visible); - + updateConsole = visible; frame.addWindowListener(this); button.addActionListener(this); + if (redirect) + { + redirectStreams(); + } else { + unredirectStreams(); + } + quit = false; // signals the Threads that they should exit - try + // Starting two seperate threads to read from the PipedInputStreams + // + reader = new Thread(this); + reader.setDaemon(true); + reader.start(); + // + reader2 = new Thread(this); + reader2.setDaemon(true); + reader2.start(); + // and a thread to append text to the textarea + textAppender = new Thread(this); + textAppender.setDaemon(true); + textAppender.start(); + } + PipedOutputStream pout=null,perr=null; + public void redirectStreams() { + if (pout==null) { - PipedOutputStream pout = new PipedOutputStream(this.pin); - System.setOut(new PrintStream(pout, true)); + try + { + pout = new PipedOutputStream(this.pin); + System.setOut(new PrintStream(pout, true)); } catch (java.io.IOException io) { textArea.append("Couldn't redirect STDOUT to this console\n" + io.getMessage()); + io.printStackTrace(stderr); } catch (SecurityException se) { textArea.append("Couldn't redirect STDOUT to this console\n" + se.getMessage()); + se.printStackTrace(stderr); } try { - PipedOutputStream pout2 = new PipedOutputStream(this.pin2); - System.setErr(new PrintStream(pout2, true)); + perr = new PipedOutputStream(this.pin2); + System.setErr(new PrintStream(perr, true)); } catch (java.io.IOException io) { textArea.append("Couldn't redirect STDERR to this console\n" + io.getMessage()); + io.printStackTrace(stderr); } catch (SecurityException se) { textArea.append("Couldn't redirect STDERR to this console\n" + se.getMessage()); + se.printStackTrace(stderr); + } + } + } + public void unredirectStreams() { + if (pout!=null) + { + try + { + System.setOut(stdout); + pout.flush(); + pout.close(); + pin = new PipedInputStream(); + pout=null; + } catch (java.io.IOException io) + { + textArea.append("Couldn't unredirect STDOUT to this console\n" + + io.getMessage()); + io.printStackTrace(stderr); + } catch (SecurityException se) + { + textArea.append("Couldn't unredirect STDOUT to this console\n" + + se.getMessage()); + se.printStackTrace(stderr); } - quit = false; // signals the Threads that they should exit - - // Starting two seperate threads to read from the PipedInputStreams - // - reader = new Thread(this); - reader.setDaemon(true); - reader.start(); - // - reader2 = new Thread(this); - reader2.setDaemon(true); - reader2.start(); + try + { + System.setErr(stderr); + perr.flush(); + perr.close(); + pin2 = new PipedInputStream(); + perr = null; + } catch (java.io.IOException io) + { + textArea.append("Couldn't unredirect STDERR to this console\n" + + io.getMessage()); + io.printStackTrace(stderr); + } catch (SecurityException se) + { + textArea.append("Couldn't unredirect STDERR to this console\n" + + se.getMessage()); + se.printStackTrace(stderr); + } + } } public void test() @@ -173,6 +243,16 @@ public class Console extends WindowAdapter implements WindowListener, */ public Console(Desktop desktop) { + this(desktop, true); + } + /** + * attach a console to the desktop - the desktop will open it if requested. + * + * @param desktop + * @param showjconsole - if true, then redirect stdout immediately + */ + public Console(Desktop desktop, boolean showjconsole) + { parent = desktop; // window name - get x,y,width, height possibly scaled Rectangle bounds = desktop.getLastKnownDimensions("JAVA_CONSOLE_"); @@ -194,10 +274,20 @@ public class Console extends WindowAdapter implements WindowListener, org.apache.log4j.Logger.getRootLogger().addAppender(jappender); } + public synchronized void stopConsole() { quit = true; - this.notifyAll(); // stop all threads + this.notifyAll(); + /*reader.notify(); + reader2.notify(); + if (errorThrower!=null) + errorThrower.notify(); // stop all threads + if (textAppender!=null) + textAppender.notify(); + */ + if (pout!=null) + { try { reader.join(10); @@ -212,12 +302,27 @@ public class Console extends WindowAdapter implements WindowListener, } catch (Exception e) { } + try + { + textAppender.join(10); + } catch (Exception e) + { + } + } + if (!frame.isVisible()) + { + frame.dispose(); + } // System.exit(0); } public synchronized void windowClosed(WindowEvent evt) { frame.setVisible(false); + closeConsoleGui(); + } + private void closeConsoleGui() { + updateConsole = false; if (parent == null) { @@ -232,6 +337,8 @@ public class Console extends WindowAdapter implements WindowListener, public synchronized void windowClosing(WindowEvent evt) { frame.setVisible(false); // default behaviour of JFrame + closeConsoleGui(); + // frame.dispose(); } @@ -247,48 +354,124 @@ public class Console extends WindowAdapter implements WindowListener, { while (Thread.currentThread() == reader) { - try - { - this.wait(100); - } catch (InterruptedException ie) + if (pin==null || pin.available() == 0) { + try + { + this.wait(100); + if (pin.available() == 0) + { + trimBuffer(false); + } + } catch (InterruptedException ie) + { + } } + while (pin.available() != 0) { String input = this.readLine(pin); stdout.print(input); - textArea.append(input); + long time = System.nanoTime(); + appendToTextArea(input); + //stderr.println("Time taken to stdout append:\t" + // + (System.nanoTime() - time) + " ns"); // lines++; } if (quit) return; - trimBuffer(false); } while (Thread.currentThread() == reader2) { - try - { - this.wait(100); - } catch (InterruptedException ie) + if (pin2.available() == 0) { + try + { + this.wait(100); + if (pin2.available() == 0) + { + trimBuffer(false); + } + } catch (InterruptedException ie) + { + } } while (pin2.available() != 0) { String input = this.readLine(pin2); stderr.print(input); - textArea.append(input); + long time = System.nanoTime(); + appendToTextArea(input); + //stderr.println("Time taken to stderr append:\t" + // + (System.nanoTime() - time) + " ns"); // lines++; } if (quit) return; - trimBuffer(false); + } + while (Thread.currentThread() == textAppender) + { + if (updateConsole) + { + // check string buffer - if greater than console, clear console and + // replace with last segment of content, otherwise, append all to + // content. + long count; + while (displayPipe.length() > 0) + { + count = 0; + StringBuffer tmp = new StringBuffer(), replace; + synchronized (displayPipe) + { + replace = displayPipe; + displayPipe = tmp; + } + // simply append whole buffer + textArea.append(replace.toString()); + count += replace.length(); + if (count > byteslim) + { + trimBuffer(false); + } + } + if (displayPipe.length() == 0) + { + try + { + this.wait(100); + if (displayPipe.length() == 0) + { + trimBuffer(false); + } + } catch (InterruptedException e) + { + } + ; + } + } + else + { + try + { + this.wait(100); + } catch (InterruptedException e) + { + + } + } + if (quit) + { + return; + } + } } catch (Exception e) { textArea.append("\nConsole reports an Internal error."); textArea.append("The error is: " + e.getMessage()); - lines += 2; + // Need to uncomment this to ensure that line tally is synched. + // lines += 2; stderr.println("Console reports an Internal error.\nThe error is: " + e); } @@ -307,38 +490,70 @@ public class Console extends WindowAdapter implements WindowListener, } } + private void appendToTextArea(final String input) + { + if (updateConsole == false) + { + // do nothing; + return; + } + long time = System.nanoTime(); + javax.swing.SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + displayPipe.append(input); // change to stringBuffer + // displayPipe.flush(); + + } + }); + // stderr.println("Time taken to Spawnappend:\t" + (System.nanoTime() - + // time) + // + " ns"); + } + + private String header = null; + + private boolean updateConsole = false; + private synchronized void trimBuffer(boolean clear) { - // trim the buffer - if (clear || lines > lim) + if (header == null && textArea.getLineCount() > 5) { try { - if (lines > 5) + header = textArea.getText(0, textArea.getLineStartOffset(5)) + + "\nTruncated...\n"; + } catch (Exception e) + { + e.printStackTrace(); + } + } + // trim the buffer + int tlength = textArea.getDocument().getLength(); + if (header != null) + { + if (clear || (tlength > byteslim)) + { + try { - // minimum length for truncation/clearing - String header = textArea.getText(0, textArea.getLineEndOffset(5)) - + "\n..Truncated..\n"; // keep first 5 lines for startup info - int truncate; if (!clear) { - truncate = textArea.getLineEndOffset(lines - lim - 7); - textArea.setText(header - + textArea.getText(truncate, textArea.getText() - .length() - - truncate)); + long time = System.nanoTime(); + textArea.replaceRange(header, 0, tlength - bytescut); + //stderr.println("Time taken to cut:\t" + // + (System.nanoTime() - time) + " ns"); } else { textArea.setText(header); } + } catch (Exception e) + { + e.printStackTrace(); } - - } catch (Exception e) - { - e.printStackTrace(); + // lines = textArea.getLineCount(); } - lines = textArea.getLineCount(); } } @@ -356,10 +571,11 @@ public class Console extends WindowAdapter implements WindowListener, byte b[] = new byte[available]; in.read(b); input = input + new String(b, 0, b.length); - while ((lp = input.indexOf("\n", lp + 1)) > -1) - { - lines++; - } + // counts lines - we don't do this for speed. + // while ((lp = input.indexOf("\n", lp + 1)) > -1) + // { + // lines++; + // } } while (!input.endsWith("\n") && !input.endsWith("\r\n") && !quit); return input; } @@ -375,8 +591,15 @@ public class Console extends WindowAdapter implements WindowListener, frame.setVisible(selected); if (selected == true) { + redirectStreams(); + updateConsole = true; frame.toFront(); } + else + { + unredirectStreams(); + updateConsole = false; + } } public Rectangle getBounds() @@ -387,4 +610,25 @@ public class Console extends WindowAdapter implements WindowListener, } return null; } + + /** + * set the banner that appears at the top of the console output + * @param string + */ + public void setHeader(String string) + { + header = string; + if (header.charAt(header.length()-1)!='\n') { + header+="\n"; + } + textArea.insert(header, 0); + } + /** + * get the banner + * @return + */ + public String getHeader() + { + return header; + } } diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 3ea93ce..7a972a1 100755 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -113,9 +113,9 @@ public class Desktop extends jalview.jbgui.GDesktop implements setBounds((int) (screenSize.width - 900) / 2, (int) (screenSize.height - 650) / 2, 900, 650); } - jconsole = new Console(this); - // immediately output essential build information - System.out.println("Jalview Desktop " + jconsole = new Console(this, showjconsole); + // add essential build information + jconsole.setHeader("Jalview Desktop " + jalview.bin.Cache.getProperty("VERSION") + "\n" + "Build Date: " + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n" -- 1.7.10.2