Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/eireneh/swing/DocumentWriter.java


1   
2   package com.eireneh.swing;
3   
4   import java.io.*;
5   import java.lang.reflect.InvocationTargetException;
6   
7   import javax.swing.*;
8   import javax.swing.text.*;
9   import javax.swing.event.*;
10  
11  import com.eireneh.util.LogicError;
12  
13  /**
14  * A DocumentWriter is-a Writer that uses a Document so all text printed
15  * to the Writer ends up in the JTextArea.
16  * A Document is a Container for text that supports editing and provides
17  * notification of changes (serves as the model in an MVC relationship).
18  * 
19  * <table border='1' cellPadding='3' cellSpacing='0' width="100%">
20  * <tr><td bgColor='white'class='TableRowColor'><font size='-7'>
21  * Distribution Licence:<br />
22  * Project B is free software; you can redistribute it
23  * and/or modify it under the terms of the GNU General Public License,
24  * version 2 as published by the Free Software Foundation.<br />
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * General Public License for more details.<br />
29  * The License is available on the internet
30  * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, by writing to
31  * <i>Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32  * MA 02111-1307, USA</i>, Or locally at the Licence link below.<br />
33  * The copyright to this program is held by it's authors.
34  * </font></td></tr></table>
35  * @see <a href='http://www.eireneh.com/servlets/Web'>Project B Home</a>
36  * @see docs.Licence
37  * @author Joe Walker
38  */
39  public class DocumentWriter extends Writer
40  {
41      /**
42      * Create the DocumentWriter with no Document, that just
43      * dumps the text it get into the bin
44      */
45      public DocumentWriter()
46      {
47      }
48  
49      /**
50      * Create the DocumentWriter with a Document to write to
51      * @param doc The destination Document
52      */
53      public DocumentWriter(Document doc)
54      {
55          this.doc = doc;
56      }
57  
58      /**
59      * Accessor for the Document that we are updating
60      * @param doc The current document
61      */
62      public Document getDocument()
63      {
64          return doc;
65      }
66  
67      /**
68      * Accessor for the Document that we are updating
69      * @return The new document
70      */
71      public void setDocument(Document doc)
72      {
73          try
74          {
75              flush();
76          }
77          catch (IOException ex)
78          {
79              // we just wanted to make sure that updates to the old
80              // Document didn't go to the new one, so dumping the
81              // exception whilst not ideal seems like the best option.
82          }
83  
84          synchronized (lock)
85          {
86              this.doc = doc;
87          }
88      }
89  
90      /**
91      * Write a portion of an array of characters.
92      * @param cbuf Array of characters
93      * @param off Offset from which to start writing characters
94      * @param len Number of characters to write
95      * @exception IOException If an I/O error occurs
96      */
97      public void write(char[] cbuf, int off, int len) throws IOException
98      {
99          synchronized (lock)
100         {
101             queue = queue + new String(cbuf, off, len);
102             update();
103         }
104     }
105 
106     /**
107     * Write a single character.  The character to be written is contained in
108     * the 16 low-order bits of the given integer value; the 16 high-order bits
109     * are ignored.
110     * <p> Subclasses that intend to support efficient single-character output
111     * should override this method.
112     * @exception  IOException  If an I/O error occurs
113     */
114     public void write(int c) throws IOException
115     {
116         synchronized (lock)
117         {
118             queue = queue + (char) c;
119             update();
120         }
121     }
122 
123     /**
124     * Write an array of characters.
125     * @param cbuf Array of characters to be written
126     * @exception IOException If an I/O error occurs
127     */
128     public void write(char cbuf[]) throws IOException
129     {
130         synchronized (lock)
131         {
132             queue = queue + cbuf;
133             update();
134         }
135     }
136 
137     /**
138     * Write a string.
139     * @param str String to be written
140     * @exception IOException If an I/O error occurs
141     */
142     public void write(String str) throws IOException
143     {
144         synchronized (lock)
145         {
146             queue = queue + str;
147             update();
148         }
149     }
150 
151     /**
152     * Write a portion of a string.
153     * @param str A String
154     * @param off Offset from which to start writing characters
155     * @param len Number of characters to write
156     * @exception IOException If an I/O error occurs
157     */
158     public void write(String str, int off, int len) throws IOException
159     {
160         synchronized (lock)
161         {
162             queue = queue + str.substring(off, off+len);
163             update();
164         }
165     }
166 
167     /**
168     * Set up the gui to read an update. Note this must only be called
169     * from within a synchronized (lock) section of code
170     */
171     private void update()
172     {
173         if (updater == null)
174         {
175             updater = new Updater();
176             SwingUtilities.invokeLater(updater);
177         }
178     }
179 
180     /**
181     * Flush the stream.  If the stream has saved any characters from the
182     * various write() methods in a buffer, write them immediately to their
183     * intended destination.  Then, if that destination is another character or
184     * byte stream, flush it.  Thus one flush() invocation will flush all the
185     * buffers in a chain of Writers and OutputStreams.
186     * @exception  IOException  If an I/O error occurs
187     */
188     public void flush() throws IOException
189     {
190         if (updater != null)
191         {
192             // Changes are outstanding. It is OK to force an update using
193             // this method because the scheduled update will kick in
194             // later, find that the queue is empty, and do nothing. No
195             // problem. It would be good to cancel an update but I dont
196             // know of a way to do that.
197             try
198             {
199                 SwingUtilities.invokeAndWait(updater);
200             }
201             catch (InterruptedException ex)
202             {
203                 throw new IOException(""+ex);
204             }
205             catch (InvocationTargetException ex)
206             {
207                 throw new IOException(""+ex);
208             }
209         }
210     }
211 
212     /**
213     * Close the stream, flushing it first.  Once a stream has been closed,
214     * further write() or flush() invocations will cause an IOException to be
215     * thrown.  Closing a previously-closed stream, however, has no effect.
216     * @exception IOException If an I/O error occurs
217     */
218     public void close() throws IOException
219     {
220         closed = true;
221     }
222 
223     /** The object to lock on to read or write the queue or the updater */
224     protected Object lock = new Object();
225 
226     /** The queue of strings to be added to the GUI */
227     protected String queue = "";
228 
229     /** The destination Document */
230     protected Document doc = null;
231 
232     /** The destination Document */
233     protected boolean closed = false;
234 
235     /** The updater waiting to be run */
236     protected Updater updater = null;
237 
238     /**
239     * For Thread/Swing correctness we should only update in the GUI thread
240     */
241     class Updater implements Runnable
242     {
243         public void run()
244         {
245             synchronized (lock)
246             {
247                 try
248                 {
249                     doc.insertString(doc.getLength(), queue, null);
250                 }
251                 catch (BadLocationException ex)
252                 {
253                     throw new LogicError();
254                 }
255 
256                 queue = "";
257 
258                 // This simply releases the pointer that our parent had
259                 // to us, it does not affect how this thread is being
260                 // executed. The practical effect is that any further
261                 // writes know to create a new updater
262                 updater = null;
263             }
264         }
265     }
266 }