5a23048c7ee0dfb3094d0c628cca2970ba6d2cf9
[jalview.git] / src / jalview / gui / Console.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.GraphicsEnvironment;
27 import java.awt.GridBagConstraints;
28 import java.awt.GridBagLayout;
29 import java.awt.Rectangle;
30 import java.awt.Toolkit;
31 import java.awt.datatransfer.Clipboard;
32 import java.awt.datatransfer.StringSelection;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.MouseAdapter;
36 import java.awt.event.MouseEvent;
37 import java.awt.event.WindowAdapter;
38 import java.awt.event.WindowEvent;
39 import java.awt.event.WindowListener;
40 import java.io.IOException;
41 import java.io.PipedInputStream;
42 import java.io.PipedOutputStream;
43 import java.io.PrintStream;
44
45 import javax.swing.BorderFactory;
46 import javax.swing.JButton;
47 import javax.swing.JComboBox;
48 import javax.swing.JFrame;
49 import javax.swing.JLabel;
50 import javax.swing.JPanel;
51 import javax.swing.JScrollPane;
52 import javax.swing.JTextArea;
53 import javax.swing.border.Border;
54 import javax.swing.text.DefaultCaret;
55
56 import jalview.log.JLoggerI.LogLevel;
57 import jalview.log.JLoggerLog4j;
58 import jalview.log.JalviewAppender;
59 import jalview.util.ChannelProperties;
60 import jalview.util.MessageManager;
61 import jalview.util.Platform;
62
63 /**
64  * Simple Jalview Java Console. Version 1 - allows viewing of console output
65  * after desktop is created. Acquired with thanks from RJHM's site
66  * http://www.comweb.nl/java/Console/Console.html A simple Java Console for your
67  * application (Swing version) Requires Java 1.1.5 or higher Disclaimer the use
68  * of this source is at your own risk. Permision to use and distribute into your
69  * own applications RJHM van den Bergh , rvdb@comweb.nl
70  */
71
72 public class Console extends WindowAdapter
73         implements WindowListener, ActionListener, Runnable
74 {
75   private JFrame frame;
76
77   private JTextArea textArea;
78
79   /*
80    * unused - tally and limit for lines in console window int lines = 0;
81    * 
82    * int lim = 1000;
83    */
84   int byteslim = 102400, bytescut = 76800; // 100k and 75k cut point.
85
86   private Thread reader, reader2, textAppender;
87
88   private boolean quit;
89
90   private final PrintStream stdout = System.out, stderr = System.err;
91
92   private PipedInputStream pin = new PipedInputStream();
93
94   private PipedInputStream pin2 = new PipedInputStream();
95
96   private StringBuffer displayPipe = new StringBuffer();
97
98   Thread errorThrower; // just for testing (Throws an Exception at this Console
99
100   // are we attached to some parent Desktop
101   Desktop parent = null;
102
103   private int MIN_WIDTH = 300;
104
105   private int MIN_HEIGHT = 250;
106
107   private JComboBox<LogLevel> logLevelCombo = new JComboBox<LogLevel>();
108
109   protected LogLevel startingLogLevel = LogLevel.INFO;
110
111   public Console()
112   {
113     // create all components and add them
114     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
115     frame = initFrame("Java Console", screenSize.width / 2,
116             screenSize.height / 2, -1, -1);
117     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
118     initConsole(true);
119   }
120
121   private void initConsole(boolean visible)
122   {
123     initConsole(visible, true);
124   }
125
126   /**
127    * 
128    * @param visible
129    *          - open the window
130    * @param redirect
131    *          - redirect std*
132    */
133   private void initConsole(boolean visible, boolean redirect)
134   {
135     // CutAndPasteTransfer cpt = new CutAndPasteTransfer();
136     // textArea = cpt.getTextArea();
137     textArea = new JTextArea();
138     textArea.setEditable(false);
139     // autoscroll
140     DefaultCaret caret = (DefaultCaret) textArea.getCaret();
141     caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
142     // toggle autoscroll by clicking on the text area
143     Border pausedBorder = BorderFactory.createMatteBorder(2, 2, 2, 2,
144             textArea.getForeground());
145     Border noBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2);
146     JScrollPane scrollPane = new JScrollPane(textArea);
147     scrollPane.setBorder(noBorder);
148     textArea.addMouseListener(new MouseAdapter()
149     {
150       public void mouseClicked(MouseEvent e)
151       {
152         if (e.getButton() == MouseEvent.BUTTON1)
153         {
154           if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE)
155           {
156             caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
157             scrollPane.setBorder(pausedBorder);
158           }
159           else
160           {
161             caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
162             textArea.setCaretPosition(textArea.getDocument().getLength());
163             scrollPane.setBorder(noBorder);
164           }
165         }
166       }
167     });
168
169     JButton clearButton = new JButton(
170             MessageManager.getString("action.clear"));
171     JButton copyToClipboardButton = new JButton(
172             MessageManager.getString("label.copy_to_clipboard"));
173     copyToClipboardButton.addActionListener(new ActionListener()
174     {
175       public void actionPerformed(ActionEvent e)
176       {
177         copyConsoleTextToClipboard();
178       }
179     });
180     copyToClipboardButton.addMouseListener(new MouseAdapter()
181     {
182       private Color bg = textArea.getBackground();
183
184       private Color fg = textArea.getForeground();
185
186       public void mousePressed(MouseEvent e)
187       {
188         textArea.setBackground(textArea.getSelectionColor());
189         textArea.setForeground(textArea.getSelectedTextColor());
190       }
191
192       public void mouseReleased(MouseEvent e)
193       {
194         textArea.setBackground(bg);
195         textArea.setForeground(fg);
196       }
197
198     });
199     copyToClipboardButton.setToolTipText(
200             MessageManager.getString("label.copy_to_clipboard_tooltip"));
201
202     JLabel logLevelLabel = new JLabel(
203             MessageManager.getString("label.log_level") + ":");
204
205     // logLevelCombo.addItem(LogLevel.ALL);
206     logLevelCombo.addItem(LogLevel.TRACE);
207     logLevelCombo.addItem(LogLevel.DEBUG);
208     logLevelCombo.addItem(LogLevel.INFO);
209     logLevelCombo.addItem(LogLevel.WARN);
210     // logLevelCombo.addItem(LogLevel.ERROR);
211     // logLevelCombo.addItem(LogLevel.FATAL);
212     // logLevelCombo.addItem(LogLevel.ERROR);
213     // logLevelCombo.addItem(LogLevel.OFF);
214     // set startingLogLevel
215     startingLogLevel = jalview.bin.Console.log == null ? LogLevel.INFO
216             : jalview.bin.Console.log.getLevel();
217     setChosenLogLevelCombo();
218     logLevelCombo.addActionListener(new ActionListener()
219     {
220       public void actionPerformed(ActionEvent e)
221       {
222         if (jalview.bin.Console.log != null)
223         {
224           jalview.bin.Console.log
225                   .setLevel((LogLevel) logLevelCombo.getSelectedItem());
226         }
227       }
228
229     });
230
231     // frame = cpt;
232     frame.getContentPane().setLayout(new BorderLayout());
233     frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
234     JPanel southPanel = new JPanel();
235     southPanel.setLayout(new GridBagLayout());
236
237     JPanel logLevelPanel = new JPanel();
238     logLevelPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
239     logLevelPanel.add(logLevelLabel);
240     logLevelPanel.add(logLevelCombo);
241     String logLevelTooltip = MessageManager.formatMessage(
242             "label.log_level_tooltip", startingLogLevel.toString());
243     logLevelLabel.setToolTipText(logLevelTooltip);
244     logLevelCombo.setToolTipText(logLevelTooltip);
245
246     GridBagConstraints gbc = new GridBagConstraints();
247     gbc.gridx = 0;
248     gbc.gridy = 0;
249     gbc.gridwidth = 1;
250     gbc.gridheight = 1;
251     gbc.weightx = 0.1;
252     southPanel.add(logLevelPanel, gbc);
253
254     gbc.gridx++;
255     gbc.weightx = 0.8;
256     gbc.fill = GridBagConstraints.HORIZONTAL;
257     southPanel.add(clearButton, gbc);
258
259     gbc.gridx++;
260     gbc.weightx = 0.1;
261     gbc.fill = GridBagConstraints.NONE;
262     southPanel.add(copyToClipboardButton, gbc);
263
264     southPanel.setVisible(true);
265     frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
266     frame.setVisible(visible);
267     updateConsole = visible;
268     frame.addWindowListener(this);
269     clearButton.addActionListener(this);
270
271     if (redirect)
272     {
273       redirectStreams();
274     }
275     else
276     {
277       unredirectStreams();
278     }
279     quit = false; // signals the Threads that they should exit
280
281     // Starting two seperate threads to read from the PipedInputStreams
282     //
283     reader = new Thread(this);
284     reader.setDaemon(true);
285     reader.start();
286     //
287     reader2 = new Thread(this);
288     reader2.setDaemon(true);
289     reader2.start();
290     // and a thread to append text to the textarea
291     textAppender = new Thread(this);
292     textAppender.setDaemon(true);
293     textAppender.start();
294
295     // set icons
296     frame.setIconImages(ChannelProperties.getIconList());
297   }
298
299   private void setChosenLogLevelCombo()
300   {
301     setChosenLogLevelCombo(startingLogLevel);
302   }
303
304   private void setChosenLogLevelCombo(LogLevel setLogLevel)
305   {
306     logLevelCombo.setSelectedItem(setLogLevel);
307     if (!logLevelCombo.getSelectedItem().equals(setLogLevel))
308     {
309       // setLogLevel not (yet) in list
310       if (setLogLevel != null && setLogLevel instanceof LogLevel)
311       {
312         // add new item to list (might be set via .jalview_properties)
313         boolean added = false;
314         for (int i = 0; i < logLevelCombo.getItemCount(); i++)
315         {
316           LogLevel l = (LogLevel) logLevelCombo.getItemAt(i);
317           if (l.compareTo(setLogLevel) >= 0)
318           {
319             logLevelCombo.insertItemAt(setLogLevel, i);
320             added = true;
321             break;
322           }
323         }
324         if (!added) // lower priority than others or some confusion -- add to
325                     // end of list
326         {
327           logLevelCombo.addItem(setLogLevel);
328         }
329         logLevelCombo.setSelectedItem(setLogLevel);
330       }
331       else
332       {
333         logLevelCombo.setSelectedItem(LogLevel.INFO);
334       }
335     }
336   }
337
338   private void copyConsoleTextToClipboard()
339   {
340     String consoleText = textArea.getText();
341     StringSelection consoleTextSelection = new StringSelection(consoleText);
342     Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
343     cb.setContents(consoleTextSelection, null);
344   }
345
346   PipedOutputStream pout = null, perr = null;
347
348   public void redirectStreams()
349   {
350     if (pout == null)
351     {
352       try
353       {
354         pout = new PipedOutputStream(this.pin);
355         System.setOut(new PrintStream(pout, true));
356       } catch (java.io.IOException io)
357       {
358         textArea.append("Couldn't redirect STDOUT to this console\n"
359                 + io.getMessage());
360         io.printStackTrace(stderr);
361       } catch (SecurityException se)
362       {
363         textArea.append("Couldn't redirect STDOUT to this console\n"
364                 + se.getMessage());
365         se.printStackTrace(stderr);
366       }
367
368       try
369       {
370         perr = new PipedOutputStream(this.pin2);
371         System.setErr(new PrintStream(perr, true));
372       } catch (java.io.IOException io)
373       {
374         textArea.append("Couldn't redirect STDERR to this console\n"
375                 + io.getMessage());
376         io.printStackTrace(stderr);
377       } catch (SecurityException se)
378       {
379         textArea.append("Couldn't redirect STDERR to this console\n"
380                 + se.getMessage());
381         se.printStackTrace(stderr);
382       }
383     }
384   }
385
386   public void unredirectStreams()
387   {
388     if (pout != null)
389     {
390       try
391       {
392         System.setOut(stdout);
393         pout.flush();
394         pout.close();
395         pin = new PipedInputStream();
396         pout = null;
397       } catch (java.io.IOException io)
398       {
399         textArea.append("Couldn't unredirect STDOUT to this console\n"
400                 + io.getMessage());
401         io.printStackTrace(stderr);
402       } catch (SecurityException se)
403       {
404         textArea.append("Couldn't unredirect STDOUT to this console\n"
405                 + se.getMessage());
406         se.printStackTrace(stderr);
407       }
408
409       try
410       {
411         System.setErr(stderr);
412         perr.flush();
413         perr.close();
414         pin2 = new PipedInputStream();
415         perr = null;
416       } catch (java.io.IOException io)
417       {
418         textArea.append("Couldn't unredirect STDERR to this console\n"
419                 + io.getMessage());
420         io.printStackTrace(stderr);
421       } catch (SecurityException se)
422       {
423         textArea.append("Couldn't unredirect STDERR to this console\n"
424                 + se.getMessage());
425         se.printStackTrace(stderr);
426       }
427     }
428   }
429
430   public void test()
431   {
432     // testing part
433     // you may omit this part for your application
434     //
435
436     System.out.println("Hello World 2");
437     System.out.println("All fonts available to Graphic2D:\n");
438     GraphicsEnvironment ge = GraphicsEnvironment
439             .getLocalGraphicsEnvironment();
440     String[] fontNames = ge.getAvailableFontFamilyNames();
441     for (int n = 0; n < fontNames.length; n++)
442     {
443       System.out.println(fontNames[n]);
444     }
445     // Testing part: simple an error thrown anywhere in this JVM will be printed
446     // on the Console
447     // We do it with a seperate Thread becasue we don't wan't to break a Thread
448     // used by the Console.
449     System.out.println("\nLets throw an error on this console");
450     errorThrower = new Thread(this);
451     errorThrower.setDaemon(true);
452     errorThrower.start();
453   }
454
455   private JFrame initFrame(String string, int i, int j, int x, int y)
456   {
457     JFrame frame = new JFrame(string);
458     frame.setName(string);
459     if (x == -1)
460     {
461       x = i / 2;
462     }
463     if (y == -1)
464     {
465       y = j / 2;
466     }
467     frame.setBounds(x, y, i, j);
468     return frame;
469   }
470
471   /**
472    * attach a console to the desktop - the desktop will open it if requested.
473    * 
474    * @param desktop
475    */
476   public Console(Desktop desktop)
477   {
478     this(desktop, true);
479   }
480
481   /**
482    * attach a console to the desktop - the desktop will open it if requested.
483    * 
484    * @param desktop
485    * @param showjconsole
486    *          - if true, then redirect stdout immediately
487    */
488   public Console(Desktop desktop, boolean showjconsole)
489   {
490     parent = desktop;
491     // window name - get x,y,width, height possibly scaled
492     Rectangle bounds = desktop.getLastKnownDimensions("JAVA_CONSOLE_");
493     if (bounds == null)
494     {
495       frame = initFrame(
496               ChannelProperties.getProperty("app_name") + " Java Console",
497               desktop.getWidth() / 2, desktop.getHeight() / 4,
498               desktop.getX(), desktop.getY());
499     }
500     else
501     {
502       frame = initFrame(
503               ChannelProperties.getProperty("app_name") + " Java Console",
504               bounds.width, bounds.height, bounds.x, bounds.y);
505     }
506     frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
507     // desktop.add(frame);
508     initConsole(false);
509     LogLevel level = (LogLevel) logLevelCombo.getSelectedItem();
510     if (!Platform.isJS())
511     {
512       JalviewAppender jappender = new JalviewAppender(level);
513       JalviewAppender.setTextArea(textArea);
514       jappender.start();
515       if (jalview.bin.Console.log != null
516               && jalview.bin.Console.log instanceof JLoggerLog4j)
517       {
518         JLoggerLog4j.addAppender(jalview.bin.Console.log, jappender);
519       }
520     }
521   }
522
523   public synchronized void stopConsole()
524   {
525     quit = true;
526     this.notifyAll();
527     /*
528      * reader.notify(); reader2.notify(); if (errorThrower!=null)
529      * errorThrower.notify(); // stop all threads if (textAppender!=null)
530      * textAppender.notify();
531      */
532     if (pout != null)
533     {
534       try
535       {
536         reader.join(10);
537         pin.close();
538       } catch (Exception e)
539       {
540       }
541       try
542       {
543         reader2.join(10);
544         pin2.close();
545       } catch (Exception e)
546       {
547       }
548       try
549       {
550         textAppender.join(10);
551       } catch (Exception e)
552       {
553       }
554     }
555     /*
556     if (!frame.isVisible())
557     {
558       frame.dispose();
559     }
560     */
561     // System.exit(0);
562   }
563
564   @Override
565   public synchronized void windowClosed(WindowEvent evt)
566   {
567     frame.setVisible(false);
568     closeConsoleGui();
569   }
570
571   private void closeConsoleGui()
572   {
573     updateConsole = false;
574     if (parent == null)
575     {
576
577       stopConsole();
578     }
579     else
580     {
581       parent.showConsole(false);
582     }
583   }
584
585   @Override
586   public synchronized void windowClosing(WindowEvent evt)
587   {
588     frame.setVisible(false); // default behaviour of JFrame
589     closeConsoleGui();
590
591     // frame.dispose();
592   }
593
594   @Override
595   public synchronized void actionPerformed(ActionEvent evt)
596   {
597     trimBuffer(true);
598     // textArea.setText("");
599   }
600
601   @Override
602   public synchronized void run()
603   {
604     try
605     {
606       while (Thread.currentThread() == reader)
607       {
608         if (pin == null || pin.available() == 0)
609         {
610           try
611           {
612             this.wait(100);
613             if (pin.available() == 0)
614             {
615               trimBuffer(false);
616             }
617           } catch (InterruptedException ie)
618           {
619           }
620         }
621
622         while (pin.available() != 0)
623         {
624           String input = this.readLine(pin);
625           stdout.print(input);
626           long time = System.nanoTime();
627           appendToTextArea(input);
628           // stderr.println("Time taken to stdout append:\t"
629           // + (System.nanoTime() - time) + " ns");
630           // lines++;
631         }
632         if (quit)
633         {
634           return;
635         }
636       }
637
638       while (Thread.currentThread() == reader2)
639       {
640         if (pin2.available() == 0)
641         {
642           try
643           {
644             this.wait(100);
645             if (pin2.available() == 0)
646             {
647               trimBuffer(false);
648             }
649           } catch (InterruptedException ie)
650           {
651           }
652         }
653         while (pin2.available() != 0)
654         {
655           String input = this.readLine(pin2);
656           stderr.print(input);
657           long time = System.nanoTime();
658           appendToTextArea(input);
659           // stderr.println("Time taken to stderr append:\t"
660           // + (System.nanoTime() - time) + " ns");
661           // lines++;
662         }
663         if (quit)
664         {
665           return;
666         }
667       }
668       while (Thread.currentThread() == textAppender)
669       {
670         if (updateConsole)
671         {
672           // check string buffer - if greater than console, clear console and
673           // replace with last segment of content, otherwise, append all to
674           // content.
675           long count;
676           while (displayPipe.length() > 0)
677           {
678             count = 0;
679             StringBuffer tmp = new StringBuffer(), replace;
680             synchronized (displayPipe)
681             {
682               replace = displayPipe;
683               displayPipe = tmp;
684             }
685             // simply append whole buffer
686             textArea.append(replace.toString());
687             count += replace.length();
688             if (count > byteslim)
689             {
690               trimBuffer(false);
691             }
692           }
693           if (displayPipe.length() == 0)
694           {
695             try
696             {
697               this.wait(100);
698               if (displayPipe.length() == 0)
699               {
700                 trimBuffer(false);
701               }
702             } catch (InterruptedException e)
703             {
704             }
705           }
706         }
707         else
708         {
709           try
710           {
711             this.wait(100);
712           } catch (InterruptedException e)
713           {
714
715           }
716         }
717         if (quit)
718         {
719           return;
720         }
721
722       }
723     } catch (Exception e)
724     {
725       textArea.append("\nConsole reports an Internal error.");
726       textArea.append("The error is: " + e.getMessage());
727       // Need to uncomment this to ensure that line tally is synched.
728       // lines += 2;
729       stderr.println(
730               "Console reports an Internal error.\nThe error is: " + e);
731     }
732
733     // just for testing (Throw a Nullpointer after 1 second)
734     if (Thread.currentThread() == errorThrower)
735     {
736       try
737       {
738         this.wait(1000);
739       } catch (InterruptedException ie)
740       {
741       }
742       throw new NullPointerException(
743               MessageManager.getString("exception.application_test_npe"));
744     }
745   }
746
747   private void appendToTextArea(final String input)
748   {
749     if (updateConsole == false)
750     {
751       // do nothing;
752       return;
753     }
754     long time = System.nanoTime();
755     javax.swing.SwingUtilities.invokeLater(new Runnable()
756     {
757       @Override
758       public void run()
759       {
760         displayPipe.append(input); // change to stringBuffer
761         // displayPipe.flush();
762
763       }
764     });
765     // stderr.println("Time taken to Spawnappend:\t" + (System.nanoTime() -
766     // time)
767     // + " ns");
768   }
769
770   private String header = null;
771
772   private boolean updateConsole = false;
773
774   private synchronized void trimBuffer(boolean clear)
775   {
776     if (header == null && textArea.getLineCount() > 5)
777     {
778       try
779       {
780         header = textArea.getText(0, textArea.getLineStartOffset(5))
781                 + "\nTruncated...\n";
782       } catch (Exception e)
783       {
784         e.printStackTrace();
785       }
786     }
787     // trim the buffer
788     int tlength = textArea.getDocument().getLength();
789     if (header != null)
790     {
791       if (clear || (tlength > byteslim))
792       {
793         try
794         {
795           if (!clear)
796           {
797             long time = System.nanoTime();
798             textArea.replaceRange(header, 0, tlength - bytescut);
799             // stderr.println("Time taken to cut:\t"
800             // + (System.nanoTime() - time) + " ns");
801           }
802           else
803           {
804             textArea.setText(header);
805           }
806         } catch (Exception e)
807         {
808           e.printStackTrace();
809         }
810         // lines = textArea.getLineCount();
811       }
812     }
813
814   }
815
816   public synchronized String readLine(PipedInputStream in)
817           throws IOException
818   {
819     String input = "";
820     int lp = -1;
821     do
822     {
823       int available = in.available();
824       if (available == 0)
825       {
826         break;
827       }
828       byte b[] = new byte[available];
829       in.read(b);
830       input = input + new String(b, 0, b.length);
831       // counts lines - we don't do this for speed.
832       // while ((lp = input.indexOf("\n", lp + 1)) > -1)
833       // {
834       // lines++;
835       // }
836     } while (!input.endsWith("\n") && !input.endsWith("\r\n") && !quit);
837     return input;
838   }
839
840   /**
841    * @j2sIgnore
842    * @param arg
843    */
844   public static void main(String[] arg)
845   {
846     new Console().test(); // create console with not reference
847
848   }
849
850   public void setVisible(boolean selected)
851   {
852     frame.setVisible(selected);
853     if (selected == true)
854     {
855       setChosenLogLevelCombo();
856       redirectStreams();
857       updateConsole = true;
858       frame.toFront();
859     }
860     else
861     {
862       // reset log level to what it was before
863       if (jalview.bin.Console.log != null)
864       {
865         jalview.bin.Console.log.setLevel(startingLogLevel);
866       }
867
868       unredirectStreams();
869       updateConsole = false;
870     }
871   }
872
873   public Rectangle getBounds()
874   {
875     if (frame != null)
876     {
877       return frame.getBounds();
878     }
879     return null;
880   }
881
882   /**
883    * set the banner that appears at the top of the console output
884    * 
885    * @param string
886    */
887   public void setHeader(String string)
888   {
889     header = string;
890     if (header.charAt(header.length() - 1) != '\n')
891     {
892       header += "\n";
893     }
894     textArea.insert(header, 0);
895   }
896
897   /**
898    * get the banner
899    * 
900    * @return
901    */
902   public String getHeader()
903   {
904     return header;
905   }
906 }