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