X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FConsole.java;h=b8aad2164586459ecff9de21ed670f3902bd0ffc;hb=014225ccc81b43fa06c1cba99b8934c71e65b8d9;hp=4fe45c8e60850a4ba27a1575c684dcceac081b59;hpb=2f4f1d8fb6878271b64f327bc58c895f458137af;p=jalview.git diff --git a/src/jalview/gui/Console.java b/src/jalview/gui/Console.java index 4fe45c8..b8aad21 100644 --- a/src/jalview/gui/Console.java +++ b/src/jalview/gui/Console.java @@ -1,31 +1,65 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GraphicsEnvironment; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.PrintStream; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.border.Border; +import javax.swing.text.DefaultCaret; + +import jalview.bin.Cache; +import jalview.log.JLoggerI.LogLevel; +import jalview.log.JLoggerLog4j; +import jalview.log.JalviewAppender; +import jalview.util.ChannelProperties; import jalview.util.MessageManager; - -import java.io.*; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; - -import org.apache.log4j.SimpleLayout; +import jalview.util.Platform; /** * Simple Jalview Java Console. Version 1 - allows viewing of console output @@ -36,8 +70,8 @@ import org.apache.log4j.SimpleLayout; * own applications RJHM van den Bergh , rvdb@comweb.nl */ -public class Console extends WindowAdapter implements WindowListener, - ActionListener, Runnable +public class Console extends WindowAdapter + implements WindowListener, ActionListener, Runnable { private JFrame frame; @@ -67,12 +101,21 @@ public class Console extends WindowAdapter implements WindowListener, // are we attached to some parent Desktop Desktop parent = null; + private int MIN_WIDTH = 300; + + private int MIN_HEIGHT = 250; + + private JComboBox logLevelCombo = new JComboBox(); + + protected LogLevel startingLogLevel = null; + public Console() { // create all components and add them Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); frame = initFrame("Java Console", screenSize.width / 2, screenSize.height / 2, -1, -1); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); initConsole(true); } @@ -94,17 +137,150 @@ public class Console extends WindowAdapter implements WindowListener, // textArea = cpt.getTextArea(); textArea = new JTextArea(); textArea.setEditable(false); - JButton button = new JButton(MessageManager.getString("action.clear")); + // autoscroll + DefaultCaret caret = (DefaultCaret) textArea.getCaret(); + caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); + // toggle autoscroll by clicking on the text area + Border pausedBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, + textArea.getForeground()); + Border noBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2); + JScrollPane scrollPane = new JScrollPane(textArea); + scrollPane.setBorder(noBorder); + textArea.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (e.getButton() == MouseEvent.BUTTON1) + { + if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE) + { + caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); + scrollPane.setBorder(pausedBorder); + } + else + { + caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); + textArea.setCaretPosition(textArea.getDocument().getLength()); + scrollPane.setBorder(noBorder); + } + } + } + }); + + JButton clearButton = new JButton( + MessageManager.getString("action.clear")); + JButton copyToClipboardButton = new JButton( + MessageManager.getString("label.copy_to_clipboard")); + copyToClipboardButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + copyConsoleTextToClipboard(); + } + }); + copyToClipboardButton.addMouseListener(new MouseAdapter() + { + private Color bg = textArea.getBackground(); + + private Color fg = textArea.getForeground(); + + @Override + public void mousePressed(MouseEvent e) + { + textArea.setBackground(textArea.getSelectionColor()); + textArea.setForeground(textArea.getSelectedTextColor()); + } + + @Override + public void mouseReleased(MouseEvent e) + { + textArea.setBackground(bg); + textArea.setForeground(fg); + } + + }); + copyToClipboardButton.setToolTipText( + MessageManager.getString("label.copy_to_clipboard_tooltip")); + + JLabel logLevelLabel = new JLabel( + MessageManager.getString("label.log_level") + ":"); + + // logLevelCombo.addItem(LogLevel.ALL); + logLevelCombo.addItem(LogLevel.TRACE); + logLevelCombo.addItem(LogLevel.DEBUG); + logLevelCombo.addItem(LogLevel.INFO); + logLevelCombo.addItem(LogLevel.WARN); + // logLevelCombo.addItem(LogLevel.ERROR); + // logLevelCombo.addItem(LogLevel.FATAL); + // logLevelCombo.addItem(LogLevel.ERROR); + // logLevelCombo.addItem(LogLevel.OFF); + // set startingLogLevel + + if (jalview.bin.Console.getLogger() == null) + { + startingLogLevel = jalview.bin.Console.getCachedLogLevel(); + } + else + { + startingLogLevel = jalview.bin.Console.getLogger().getLevel(); + } + setChosenLogLevelCombo(); + logLevelCombo.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (jalview.bin.Console.log != null) + { + jalview.bin.Console.log + .setLevel((LogLevel) logLevelCombo.getSelectedItem()); + } + } + + }); // frame = cpt; frame.getContentPane().setLayout(new BorderLayout()); - frame.getContentPane().add(new JScrollPane(textArea), - BorderLayout.CENTER); - frame.getContentPane().add(button, BorderLayout.SOUTH); + frame.getContentPane().add(scrollPane, BorderLayout.CENTER); + JPanel southPanel = new JPanel(); + southPanel.setLayout(new GridBagLayout()); + + JPanel logLevelPanel = new JPanel(); + logLevelPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT); + logLevelPanel.add(logLevelLabel); + logLevelPanel.add(logLevelCombo); + String logLevelTooltip = MessageManager.formatMessage( + "label.log_level_tooltip", startingLogLevel.toString()); + logLevelLabel.setToolTipText(logLevelTooltip); + logLevelCombo.setToolTipText(logLevelTooltip); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0.1; + southPanel.add(logLevelPanel, gbc); + + gbc.gridx++; + gbc.weightx = 0.8; + gbc.fill = GridBagConstraints.HORIZONTAL; + southPanel.add(clearButton, gbc); + + gbc.gridx++; + gbc.weightx = 0.1; + gbc.fill = GridBagConstraints.NONE; + southPanel.add(copyToClipboardButton, gbc); + + southPanel.setVisible(true); + frame.getContentPane().add(southPanel, BorderLayout.SOUTH); frame.setVisible(visible); updateConsole = visible; frame.addWindowListener(this); - button.addActionListener(this); + clearButton.addActionListener(this); + if (redirect) { redirectStreams(); @@ -128,6 +304,56 @@ public class Console extends WindowAdapter implements WindowListener, textAppender = new Thread(this); textAppender.setDaemon(true); textAppender.start(); + + // set icons + frame.setIconImages(ChannelProperties.getIconList()); + } + + private void setChosenLogLevelCombo() + { + setChosenLogLevelCombo(startingLogLevel); + } + + private void setChosenLogLevelCombo(LogLevel setLogLevel) + { + logLevelCombo.setSelectedItem(setLogLevel); + if (!logLevelCombo.getSelectedItem().equals(setLogLevel)) + { + // setLogLevel not (yet) in list + if (setLogLevel != null && setLogLevel instanceof LogLevel) + { + // add new item to list (might be set via .jalview_properties) + boolean added = false; + for (int i = 0; i < logLevelCombo.getItemCount(); i++) + { + LogLevel l = logLevelCombo.getItemAt(i); + if (l.compareTo(setLogLevel) >= 0) + { + logLevelCombo.insertItemAt(setLogLevel, i); + added = true; + break; + } + } + if (!added) // lower priority than others or some confusion -- add to + // end of list + { + logLevelCombo.addItem(setLogLevel); + } + logLevelCombo.setSelectedItem(setLogLevel); + } + else + { + logLevelCombo.setSelectedItem(LogLevel.INFO); + } + } + } + + private void copyConsoleTextToClipboard() + { + String consoleText = textArea.getText(); + StringSelection consoleTextSelection = new StringSelection(consoleText); + Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); + cb.setContents(consoleTextSelection, null); } PipedOutputStream pout = null, perr = null; @@ -220,18 +446,20 @@ public class Console extends WindowAdapter implements WindowListener, // you may omit this part for your application // - System.out.println("Hello World 2"); - System.out.println("All fonts available to Graphic2D:\n"); + jalview.bin.Console.outPrintln("Hello World 2"); + jalview.bin.Console.outPrintln("All fonts available to Graphic2D:\n"); GraphicsEnvironment ge = GraphicsEnvironment .getLocalGraphicsEnvironment(); String[] fontNames = ge.getAvailableFontFamilyNames(); for (int n = 0; n < fontNames.length; n++) - System.out.println(fontNames[n]); + { + jalview.bin.Console.outPrintln(fontNames[n]); + } // Testing part: simple an error thrown anywhere in this JVM will be printed // on the Console // We do it with a seperate Thread becasue we don't wan't to break a Thread // used by the Console. - System.out.println("\nLets throw an error on this console"); + jalview.bin.Console.outPrintln("\nLets throw an error on this console"); errorThrower = new Thread(this); errorThrower.setDaemon(true); errorThrower.start(); @@ -242,9 +470,13 @@ public class Console extends WindowAdapter implements WindowListener, JFrame frame = new JFrame(string); frame.setName(string); if (x == -1) - x = (int) (i / 2); + { + x = i / 2; + } if (y == -1) - y = (int) (j / 2); + { + y = j / 2; + } frame.setBounds(x, y, i, j); return frame; } @@ -256,37 +488,45 @@ 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_"); - if (bounds == null) + Rectangle bounds = parent == null ? null + : parent.getLastKnownDimensions("JAVA_CONSOLE_"); + if (bounds != null) { - frame = initFrame("Jalview Java Console", desktop.getWidth() / 2, - desktop.getHeight() / 4, desktop.getX(), desktop.getY()); + frame = initFrame( + ChannelProperties.getProperty("app_name") + " Java Console", + bounds.width, bounds.height, bounds.x, bounds.y); + } + else if (parent != null && parent.getWidth() > 0 + && parent.getHeight() > 0) + { + frame = initFrame( + ChannelProperties.getProperty("app_name") + " Java Console", + parent.getWidth() / 2, parent.getHeight() / 4, parent.getX(), + parent.getY()); } else { - frame = initFrame("Jalview Java Console", bounds.width, - bounds.height, bounds.x, bounds.y); + frame = initFrame( + ChannelProperties.getProperty("app_name") + " Java Console", + MIN_WIDTH, MIN_HEIGHT, 10, 10); } - // desktop.add(frame); + frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); + // parent.add(frame); initConsole(false); - JalviewAppender jappender = new JalviewAppender(); - jappender.setLayout(new SimpleLayout()); - JalviewAppender.setTextArea(textArea); - org.apache.log4j.Logger.getRootLogger().addAppender(jappender); + LogLevel level = (LogLevel) logLevelCombo.getSelectedItem(); + if (!Platform.isJS()) + { + JalviewAppender jappender = new JalviewAppender(level); + JalviewAppender.setTextArea(textArea); + jappender.start(); + if (jalview.bin.Console.log != null + && jalview.bin.Console.log instanceof JLoggerLog4j) + { + JLoggerLog4j.addAppender(jalview.bin.Console.log, jappender); + } + } } public synchronized void stopConsole() @@ -306,6 +546,7 @@ public class Console extends WindowAdapter implements WindowListener, pin.close(); } catch (Exception e) { + jalview.bin.Console.debug("pin.close() error", e); } try { @@ -313,21 +554,26 @@ public class Console extends WindowAdapter implements WindowListener, pin2.close(); } catch (Exception e) { + jalview.bin.Console.debug("pin2.close() error", e); } try { textAppender.join(10); } catch (Exception e) { + jalview.bin.Console.debug("textAppender.join(10) error", e); } } + /* if (!frame.isVisible()) { frame.dispose(); } + */ // System.exit(0); } + @Override public synchronized void windowClosed(WindowEvent evt) { frame.setVisible(false); @@ -348,6 +594,7 @@ public class Console extends WindowAdapter implements WindowListener, } } + @Override public synchronized void windowClosing(WindowEvent evt) { frame.setVisible(false); // default behaviour of JFrame @@ -356,12 +603,14 @@ public class Console extends WindowAdapter implements WindowListener, // frame.dispose(); } + @Override public synchronized void actionPerformed(ActionEvent evt) { trimBuffer(true); // textArea.setText(""); } + @Override public synchronized void run() { try @@ -372,13 +621,14 @@ public class Console extends WindowAdapter implements WindowListener, { try { - this.wait(100); + this.wait(100); // ##### implicated BLOCKED if (pin.available() == 0) { trimBuffer(false); } } catch (InterruptedException ie) { + jalview.bin.Console.debug("pin.available() error", ie); } } @@ -393,7 +643,9 @@ public class Console extends WindowAdapter implements WindowListener, // lines++; } if (quit) + { return; + } } while (Thread.currentThread() == reader2) @@ -402,13 +654,14 @@ public class Console extends WindowAdapter implements WindowListener, { try { - this.wait(100); + this.wait(100); // ##### implicated BLOCKED if (pin2.available() == 0) { trimBuffer(false); } } catch (InterruptedException ie) { + jalview.bin.Console.debug("pin.available() error", ie); } } while (pin2.available() != 0) @@ -422,7 +675,9 @@ public class Console extends WindowAdapter implements WindowListener, // lines++; } if (quit) + { return; + } } while (Thread.currentThread() == textAppender) { @@ -442,12 +697,16 @@ public class Console extends WindowAdapter implements WindowListener, displayPipe = tmp; } // simply append whole buffer - textArea.append(replace.toString()); - count += replace.length(); - if (count > byteslim) + synchronized (textArea.getDocument()) { - trimBuffer(false); + textArea.append(replace.toString()); // ##### implicated BLOCKED + count += replace.length(); + if (count > byteslim) + { + trimBuffer(false); + } } + } if (displayPipe.length() == 0) { @@ -460,8 +719,8 @@ public class Console extends WindowAdapter implements WindowListener, } } catch (InterruptedException e) { + jalview.bin.Console.debug("displayPipe.length() error", e); } - ; } } else @@ -471,7 +730,7 @@ public class Console extends WindowAdapter implements WindowListener, this.wait(100); } catch (InterruptedException e) { - + jalview.bin.Console.debug("this.wait(100) error", e); } } if (quit) @@ -486,8 +745,8 @@ public class Console extends WindowAdapter implements WindowListener, textArea.append("The error is: " + e.getMessage()); // Need to uncomment this to ensure that line tally is synched. // lines += 2; - stderr.println("Console reports an Internal error.\nThe error is: " - + e); + stderr.println( + "Console reports an Internal error.\nThe error is: " + e); } // just for testing (Throw a Nullpointer after 1 second) @@ -498,9 +757,10 @@ public class Console extends WindowAdapter implements WindowListener, this.wait(1000); } catch (InterruptedException ie) { + jalview.bin.Console.debug("this.wait(1000) error", ie); } throw new NullPointerException( - "Application test: throwing an NullPointerException It should arrive at the console"); + MessageManager.getString("exception.application_test_npe")); } } @@ -514,6 +774,7 @@ public class Console extends WindowAdapter implements WindowListener, long time = System.nanoTime(); javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { displayPipe.append(input); // change to stringBuffer @@ -540,7 +801,7 @@ public class Console extends WindowAdapter implements WindowListener, + "\nTruncated...\n"; } catch (Exception e) { - e.printStackTrace(); + jalview.bin.Console.warn("textArea Exception", e); } } // trim the buffer @@ -564,7 +825,7 @@ public class Console extends WindowAdapter implements WindowListener, } } catch (Exception e) { - e.printStackTrace(); + jalview.bin.Console.warn("textArea Exception", e); } // lines = textArea.getLineCount(); } @@ -581,7 +842,9 @@ public class Console extends WindowAdapter implements WindowListener, { int available = in.available(); if (available == 0) + { break; + } byte b[] = new byte[available]; in.read(b); input = input + new String(b, 0, b.length); @@ -594,6 +857,10 @@ public class Console extends WindowAdapter implements WindowListener, return input; } + /** + * @j2sIgnore + * @param arg + */ public static void main(String[] arg) { new Console().test(); // create console with not reference @@ -605,12 +872,19 @@ public class Console extends WindowAdapter implements WindowListener, frame.setVisible(selected); if (selected == true) { + setChosenLogLevelCombo(); redirectStreams(); updateConsole = true; frame.toFront(); } else { + // reset log level to what it was before + if (jalview.bin.Console.log != null) + { + jalview.bin.Console.log.setLevel(startingLogLevel); + } + unredirectStreams(); updateConsole = false; }