1 package org.opentrafficsim.remotecontrol;
2
3 import java.io.OutputStream;
4 import java.lang.reflect.InvocationTargetException;
5
6 import javax.swing.JTextArea;
7 import javax.swing.SwingUtilities;
8
9 /**
10 * Output stream that writes to a Swing component. Derived from
11 * https://www.codejava.net/java-se/swing/redirect-standard-output-streams-to-jtextarea
12 * <p>
13 * Copyright (c) 2020-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14 * BSD-style license. See <a href="https://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
15 * </p>
16 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
17 * @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
18 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
19 */
20 public class TextAreaOutputStream extends OutputStream
21 {
22 /** Swing output object to append all output to. */
23 private final JTextArea textArea;
24
25 /**
26 * Construct a new TextAreaOutputStream object.
27 * @param textArea JTextArea; the text area to append the output onto
28 */
29 TextAreaOutputStream(final JTextArea textArea)
30 {
31 this.textArea = textArea;
32 }
33
34 /**
35 * Write to the textArea. May only be called from within the AWT thread!
36 * @param bytes byte[]; bytes to write
37 * @param offset int; offset within bytes of the first byte to write
38 * @param length int; number of bytes to write
39 */
40 public void awtWrite(final byte[] bytes, final int offset, final int length)
41 {
42 synchronized (this.textArea)
43 {
44 for (int index = offset; index < offset + length; index++)
45 {
46 // redirects data to the text area
47 this.textArea.append(String.valueOf((char) (bytes[index])));
48 }
49 // scrolls the text area to the end of data
50 this.textArea.setCaretPosition(this.textArea.getDocument().getLength());
51 }
52 }
53
54 /**
55 * Write to the textArea. May only be called from within the AWT thread!
56 * @param b int; byte to write
57 */
58 public void awtWrite(final int b)
59 {
60 synchronized (this.textArea)
61 {
62 // redirects data to the text area
63 this.textArea.append(String.valueOf((char) b));
64 // scrolls the text area to the end of data
65 this.textArea.setCaretPosition(this.textArea.getDocument().getLength());
66 }
67 }
68
69 /** {@inheritDoc} */
70 @Override
71 public void write(final byte[] bytes, final int offset, final int length)
72 {
73 if (SwingUtilities.isEventDispatchThread())
74 {
75 awtWrite(bytes, offset, length);
76 }
77 else
78 {
79 try
80 {
81 SwingUtilities.invokeAndWait(new Runnable()
82 {
83 /** {@inheritDoc} */
84 @Override
85 public void run()
86 {
87 awtWrite(bytes, offset, length);
88 }
89 });
90 }
91 catch (InvocationTargetException | InterruptedException e)
92 {
93 e.printStackTrace();
94 }
95 }
96 }
97
98 /** {@inheritDoc} */
99 @Override
100 public void write(final byte[] bytes)
101 {
102 write(bytes, 0, bytes.length);
103 }
104
105 /** {@inheritDoc} */
106 @Override
107 public void write(final int b)
108 {
109 try
110 {
111 SwingUtilities.invokeAndWait(new Runnable()
112 {
113 /** {@inheritDoc} */
114 @Override
115 public void run()
116 {
117 awtWrite(b);
118 }
119 });
120 }
121 catch (InvocationTargetException | InterruptedException e)
122 {
123 e.printStackTrace();
124 }
125 }
126
127 }