console output to stderr and stdout, and console buffer stays constant size (needs...
[jalview.git] / src / jalview / gui / Console.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.io.*;
22 import java.awt.*;
23 import java.awt.event.*;
24 import javax.swing.*;
25
26 import org.apache.log4j.SimpleLayout;
27
28 /**
29  * Simple Jalview Java Console. Version 1 - allows viewing of console output after desktop is created.
30  * Acquired with thanks from RJHM's site http://www.comweb.nl/java/Console/Console.html
31  *  A simple Java Console for your application (Swing version)
32  * Requires Java 1.1.5 or higher
33  * Disclaimer the use of this source is at your own risk. 
34  * Permision to use and distribute into your own applications
35  * RJHM van den Bergh , rvdb@comweb.nl
36  */
37
38 public class Console extends WindowAdapter implements WindowListener,
39         ActionListener, Runnable
40 {
41   private JFrame frame;
42
43   private JTextArea textArea;
44
45   private Thread reader;
46
47   private Thread reader2;
48
49   private boolean quit;
50   private final PrintStream stdout = System.out;
51   private final PrintStream stderr = System.err;
52   private final PipedInputStream pin = new PipedInputStream();
53
54   private final PipedInputStream pin2 = new PipedInputStream();
55
56
57   Thread errorThrower; // just for testing (Throws an Exception at this Console
58   // are we attached to some parent Desktop
59   Desktop parent = null;
60   public Console()
61   {
62     // create all components and add them
63     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
64     frame = initFrame("Java Console", screenSize.width / 2,
65             screenSize.height / 2, -1, -1);
66     initConsole(true);
67   }
68
69   private void initConsole(boolean visible)
70   {
71     // CutAndPasteTransfer cpt = new CutAndPasteTransfer();
72     //textArea = cpt.getTextArea();
73     textArea = new JTextArea();
74     textArea.setEditable(false);
75     JButton button = new JButton("clear");
76
77     // frame = cpt;
78     frame.getContentPane().setLayout(new BorderLayout());
79     frame.getContentPane().add(new JScrollPane(textArea),
80             BorderLayout.CENTER);
81     frame.getContentPane().add(button, BorderLayout.SOUTH);
82     frame.setVisible(visible);
83
84     frame.addWindowListener(this);
85     button.addActionListener(this);
86
87     try
88     {
89       PipedOutputStream pout = new PipedOutputStream(this.pin);
90       System.setOut(new PrintStream(pout, true));
91     } catch (java.io.IOException io)
92     {
93       textArea.append("Couldn't redirect STDOUT to this console\n"
94               + io.getMessage());
95     } catch (SecurityException se)
96     {
97       textArea.append("Couldn't redirect STDOUT to this console\n"
98               + se.getMessage());
99     }
100
101     try
102     {
103       PipedOutputStream pout2 = new PipedOutputStream(this.pin2);
104       System.setErr(new PrintStream(pout2, true));
105     } catch (java.io.IOException io)
106     {
107       textArea.append("Couldn't redirect STDERR to this console\n"
108               + io.getMessage());
109     } catch (SecurityException se)
110     {
111       textArea.append("Couldn't redirect STDERR to this console\n"
112               + se.getMessage());
113     }
114
115     quit = false; // signals the Threads that they should exit
116
117     // Starting two seperate threads to read from the PipedInputStreams
118     //
119     reader = new Thread(this);
120     reader.setDaemon(true);
121     reader.start();
122     //
123     reader2 = new Thread(this);
124     reader2.setDaemon(true);
125     reader2.start();
126   }
127   public void test() {
128     // testing part
129     // you may omit this part for your application
130     // 
131     
132     System.out.println("Hello World 2");
133     System.out.println("All fonts available to Graphic2D:\n");
134     GraphicsEnvironment ge = GraphicsEnvironment
135             .getLocalGraphicsEnvironment();
136     String[] fontNames = ge.getAvailableFontFamilyNames();
137     for (int n = 0; n < fontNames.length; n++)
138       System.out.println(fontNames[n]);
139     // Testing part: simple an error thrown anywhere in this JVM will be printed
140     // on the Console
141     // We do it with a seperate Thread becasue we don't wan't to break a Thread
142     // used by the Console.
143     System.out.println("\nLets throw an error on this console");
144     errorThrower = new Thread(this);
145     errorThrower.setDaemon(true);
146     errorThrower.start();
147   }
148
149   private JFrame initFrame(String string, int i, int j, int x, int y)
150   {
151     JFrame frame = new JFrame(string);
152     frame.setName(string);
153     if (x==-1)
154       x = (int) (i / 2);
155     if (y==-1)
156       y = (int) (j / 2);
157     frame.setBounds(x, y, i, j);
158     return frame;
159   }
160
161   /**
162    * attach a console to the desktop - the desktop will open it if requested.
163    * 
164    * @param desktop
165    */
166   public Console(Desktop desktop)
167   {
168     parent = desktop;
169     // window name - get x,y,width, height possibly scaled
170     Rectangle bounds = desktop.getLastKnownDimensions("JAVA_CONSOLE_");
171     if (bounds==null)
172     {
173     frame = initFrame("Jalview Java Console", desktop.getWidth() / 2,
174             desktop.getHeight() / 4,desktop.getX(),desktop.getY());
175     } else {
176       frame = initFrame("Jalview Java Console", bounds.width, bounds.height, bounds.x, bounds.y);
177     }
178     // desktop.add(frame);
179     initConsole(false);
180     JalviewAppender jappender = new JalviewAppender();
181     jappender.setLayout(new SimpleLayout());
182     JalviewAppender.setTextArea(textArea);
183     org.apache.log4j.Logger.getRootLogger().addAppender(jappender);
184   }
185
186   public synchronized void stopConsole()
187   {
188     quit = true;
189     this.notifyAll(); // stop all threads
190     try
191     {
192       reader.join(10);
193       pin.close();
194     } catch (Exception e)
195     {
196     }
197     try
198     {
199       reader2.join(10);
200       pin2.close();
201     } catch (Exception e)
202     {
203     }
204 //    System.exit(0);
205   }
206
207   public synchronized void windowClosed(WindowEvent evt)
208   {
209     frame.setVisible(false);
210     if (parent == null)
211     {
212
213       stopConsole();
214     } else {
215       parent.showConsole(false);
216     }
217   }
218
219   public synchronized void windowClosing(WindowEvent evt)
220   {
221     frame.setVisible(false); // default behaviour of JFrame
222 //    frame.dispose();
223   }
224
225   public synchronized void actionPerformed(ActionEvent evt)
226   {
227     textArea.setText("");
228   }
229   int lines=0,lim=1000;
230   public synchronized void run()
231   {
232     try
233     {
234       while (Thread.currentThread() == reader)
235       {
236         try
237         {
238           this.wait(100);
239         } catch (InterruptedException ie)
240         {
241         }
242         if (pin.available() != 0)
243         {
244           String input = this.readLine(pin);
245           stdout.print(input);
246           textArea.append(input);
247           lines++;
248         }
249         if (quit)
250           return;
251       }
252
253       while (Thread.currentThread() == reader2)
254       {
255         try
256         {
257           this.wait(100);
258         } catch (InterruptedException ie)
259         {
260         }
261         if (pin2.available() != 0)
262         {
263           String input = this.readLine(pin2);
264           stderr.print(input);
265           textArea.append(input);
266           lines++;
267         }
268         if (quit)
269           return;
270       }
271     } catch (Exception e)
272     {
273       textArea.append("\nConsole reports an Internal error.");
274       textArea.append("The error is: " + e);
275       lines+=2;
276     }
277
278     // just for testing (Throw a Nullpointer after 1 second)
279     if (Thread.currentThread() == errorThrower)
280     {
281       try
282       {
283         this.wait(1000);
284       } catch (InterruptedException ie)
285       {
286       }
287       throw new NullPointerException(
288               "Application test: throwing an NullPointerException It should arrive at the console");
289     }
290     // trim the buffer
291     if (lines>lim)
292     {
293       try {
294         String header = textArea.getText(0,textArea.getLineEndOffset(5))+"\n..Truncated..\n"; // keep first 5 lines for startup info
295         int truncate = textArea.getLineEndOffset(lim-7-lines);
296         textArea.setText(header+textArea.getText(truncate,textArea.getText().length()-truncate)); } catch (Exception e)
297         {
298           e.printStackTrace();
299         }
300         lines = textArea.getLineCount();
301     }
302
303   }
304
305   public synchronized String readLine(PipedInputStream in)
306           throws IOException
307   {
308     String input = "";
309     do
310     {
311       int available = in.available();
312       if (available == 0)
313         break;
314       byte b[] = new byte[available];
315       in.read(b);
316       input = input + new String(b, 0, b.length);
317     } while (!input.endsWith("\n") && !input.endsWith("\r\n") && !quit);
318     return input;
319   }
320
321   public static void main(String[] arg)
322   {
323     new Console().test(); // create console with not reference
324     
325   }
326
327   public void setVisible(boolean selected)
328   {
329     frame.setVisible(selected);
330     if (selected == true)
331     {
332       frame.toFront();
333     }    
334   }
335
336   public Rectangle getBounds()
337   {
338     if (frame!=null)
339     {
340       return frame.getBounds();
341     }
342     return null;
343   }
344 }