JAL-1953 2.11.2 with Archeopteryx!
[jalview.git] / src / jalview / gui / Console.java
index f4fe876..140f6cc 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * 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.
  * 
  */
 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.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
@@ -38,8 +69,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;
 
@@ -69,6 +100,14 @@ 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<LogLevel> logLevelCombo = new JComboBox<LogLevel>();
+
+  protected LogLevel startingLogLevel = LogLevel.INFO;
+
   public Console()
   {
     // create all components and add them
@@ -96,17 +135,138 @@ 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()
+    {
+      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()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        copyConsoleTextToClipboard();
+      }
+    });
+    copyToClipboardButton.addMouseListener(new MouseAdapter()
+    {
+      private Color bg = textArea.getBackground();
+
+      private Color fg = textArea.getForeground();
+
+      public void mousePressed(MouseEvent e)
+      {
+        textArea.setBackground(textArea.getSelectionColor());
+        textArea.setForeground(textArea.getSelectedTextColor());
+      }
+
+      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
+    startingLogLevel = jalview.bin.Console.log == null ? LogLevel.INFO
+            : jalview.bin.Console.log.getLevel();
+    setChosenLogLevelCombo();
+    logLevelCombo.addActionListener(new ActionListener()
+    {
+      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();
@@ -119,17 +279,67 @@ public class Console extends WindowAdapter implements WindowListener,
 
     // Starting two seperate threads to read from the PipedInputStreams
     //
-    reader = new Thread(this);
+    reader = new Thread(this, "ConsoleReader1");
     reader.setDaemon(true);
     reader.start();
     //
-    reader2 = new Thread(this);
+    reader2 = new Thread(this, "ConsoleReader2");
     reader2.setDaemon(true);
     reader2.start();
     // and a thread to append text to the textarea
-    textAppender = new Thread(this);
+    textAppender = new Thread(this, "ConsoleTextAppend");
     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 = (LogLevel) 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;
@@ -228,13 +438,15 @@ public class Console extends WindowAdapter implements WindowListener,
             .getLocalGraphicsEnvironment();
     String[] fontNames = ge.getAvailableFontFamilyNames();
     for (int n = 0; n < fontNames.length; n++)
+    {
       System.out.println(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");
-    errorThrower = new Thread(this);
+    errorThrower = new Thread(this, "ConsoleErrorLog");
     errorThrower.setDaemon(true);
     errorThrower.start();
   }
@@ -244,9 +456,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;
   }
@@ -275,20 +491,32 @@ public class Console extends WindowAdapter implements WindowListener,
     Rectangle bounds = desktop.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",
+              desktop.getWidth() / 2, desktop.getHeight() / 4,
+              desktop.getX(), desktop.getY());
     }
     else
     {
-      frame = initFrame("Jalview Java Console", bounds.width,
-              bounds.height, bounds.x, bounds.y);
+      frame = initFrame(
+              ChannelProperties.getProperty("app_name") + " Java Console",
+              bounds.width, bounds.height, bounds.x, bounds.y);
     }
+    frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
     // desktop.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()
@@ -330,6 +558,7 @@ public class Console extends WindowAdapter implements WindowListener,
     // System.exit(0);
   }
 
+  @Override
   public synchronized void windowClosed(WindowEvent evt)
   {
     frame.setVisible(false);
@@ -350,6 +579,7 @@ public class Console extends WindowAdapter implements WindowListener,
     }
   }
 
+  @Override
   public synchronized void windowClosing(WindowEvent evt)
   {
     frame.setVisible(false); // default behaviour of JFrame
@@ -358,12 +588,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
@@ -395,7 +627,9 @@ public class Console extends WindowAdapter implements WindowListener,
           // lines++;
         }
         if (quit)
+        {
           return;
+        }
       }
 
       while (Thread.currentThread() == reader2)
@@ -424,7 +658,9 @@ public class Console extends WindowAdapter implements WindowListener,
           // lines++;
         }
         if (quit)
+        {
           return;
+        }
       }
       while (Thread.currentThread() == textAppender)
       {
@@ -463,7 +699,6 @@ public class Console extends WindowAdapter implements WindowListener,
             } catch (InterruptedException e)
             {
             }
-            ;
           }
         }
         else
@@ -488,8 +723,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)
@@ -501,7 +736,8 @@ public class Console extends WindowAdapter implements WindowListener,
       } catch (InterruptedException ie)
       {
       }
-      throw new NullPointerException(MessageManager.getString("exception.application_test_npe"));
+      throw new NullPointerException(
+              MessageManager.getString("exception.application_test_npe"));
     }
   }
 
@@ -515,6 +751,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
@@ -582,7 +819,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);
@@ -595,6 +834,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
@@ -606,12 +849,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;
     }