17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text.rtf;
26
27 import java.lang.*;
28 import java.util.*;
29 import java.io.*;
30 import java.awt.Color;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import javax.swing.text.*;
34
35 /**
36 * Takes a sequence of RTF tokens and text and appends the text
37 * described by the RTF to a <code>StyledDocument</code> (the <em>target</em>).
38 * The RTF is lexed
39 * from the character stream by the <code>RTFParser</code> which is this class's
40 * superclass.
41 *
42 * This class is an indirect subclass of OutputStream. It must be closed
43 * in order to guarantee that all of the text has been sent to
44 * the text acceptor.
45 *
46 * @see RTFParser
47 * @see java.io.OutputStream
48 */
49 class RTFReader extends RTFParser
50 {
51 /** The object to which the parsed text is sent. */
52 StyledDocument target;
53
54 /** Miscellaneous information about the parser's state. This
55 * dictionary is saved and restored when an RTF group begins
56 * or ends. */
57 Dictionary<Object, Object> parserState; /* Current parser state */
58 /** This is the "dst" item from parserState. rtfDestination
59 * is the current rtf destination. It is cached in an instance
60 * variable for speed. */
61 Destination rtfDestination;
62 /** This holds the current document attributes. */
63 MutableAttributeSet documentAttributes;
64
65 /** This Dictionary maps Integer font numbers to String font names. */
66 Dictionary<Integer, String> fontTable;
67 /** This array maps color indices to Color objects. */
68 Color[] colorTable;
69 /** This array maps character style numbers to Style objects. */
70 Style[] characterStyles;
71 /** This array maps paragraph style numbers to Style objects. */
72 Style[] paragraphStyles;
73 /** This array maps section style numbers to Style objects. */
74 Style[] sectionStyles;
75
76 /** This is the RTF version number, extracted from the \rtf keyword.
77 * The version information is currently not used. */
78 int rtfversion;
79
80 /** <code>true</code> to indicate that if the next keyword is unknown,
81 * the containing group should be ignored. */
82 boolean ignoreGroupIfUnknownKeyword;
83
84 /** The parameter of the most recently parsed \\ucN keyword,
85 * used for skipping alternative representations after a
86 * Unicode character. */
87 int skippingCharacters;
88
89 private static Dictionary<String, RTFAttribute> straightforwardAttributes;
90 static {
91 straightforwardAttributes = RTFAttributes.attributesByKeyword();
92 }
93
94 private MockAttributeSet mockery;
95
96 /* this should be final, but there's a bug in javac... */
97 /** textKeywords maps RTF keywords to single-character strings,
98 * for those keywords which simply insert some text. */
99 static Dictionary<String, String> textKeywords = null;
100 static {
187 text = text.substring(skippingCharacters);
188 skippingCharacters = 0;
189 }
190 }
191
192 if (rtfDestination != null) {
193 rtfDestination.handleText(text);
194 return;
195 }
196
197 warning("Text with no destination. oops.");
198 }
199
200 /** The default color for text which has no specified color. */
201 Color defaultColor()
202 {
203 return Color.black;
204 }
205
206 /** Called by the superclass when a new RTF group is begun.
207 * This implementation saves the current <code>parserState</code>, and gives
208 * the current destination a chance to save its own state.
209 * @see RTFParser#begingroup
210 */
211 public void begingroup()
212 {
213 if (skippingCharacters > 0) {
214 /* TODO this indicates an error in the RTF. Log it? */
215 skippingCharacters = 0;
216 }
217
218 /* we do this little dance to avoid cloning the entire state stack and
219 immediately throwing it away. */
220 Object oldSaveState = parserState.get("_savedState");
221 if (oldSaveState != null)
222 parserState.remove("_savedState");
223 @SuppressWarnings("unchecked")
224 Dictionary<String, Object> saveState = (Dictionary<String, Object>)((Hashtable)parserState).clone();
225 if (oldSaveState != null)
226 saveState.put("_savedState", oldSaveState);
227 parserState.put("_savedState", saveState);
228
229 if (rtfDestination != null)
230 rtfDestination.begingroup();
231 }
232
233 /** Called by the superclass when the current RTF group is closed.
234 * This restores the parserState saved by <code>begingroup()</code>
235 * as well as invoking the endgroup method of the current
236 * destination.
237 * @see RTFParser#endgroup
238 */
239 public void endgroup()
240 {
241 if (skippingCharacters > 0) {
242 /* NB this indicates an error in the RTF. Log it? */
243 skippingCharacters = 0;
244 }
245
246 @SuppressWarnings("unchecked")
247 Dictionary<Object, Object> restoredState = (Dictionary<Object, Object>)parserState.get("_savedState");
248 Destination restoredDestination = (Destination)restoredState.get("dst");
249 if (restoredDestination != rtfDestination) {
250 rtfDestination.close(); /* allow the destination to clean up */
251 rtfDestination = restoredDestination;
252 }
253 Dictionary<Object, Object> oldParserState = parserState;
254 parserState = restoredState;
1516 attr.setDefault(characterAttributes);
1517 }
1518
1519 parserState.remove("sectionStyle");
1520 }
1521 }
1522
1523 /** RTFReader.TextHandlingDestination provides basic text handling
1524 * functionality. Subclasses must implement: <dl>
1525 * <dt>deliverText()<dd>to handle a run of text with the same
1526 * attributes
1527 * <dt>finishParagraph()<dd>to end the current paragraph and
1528 * set the paragraph's attributes
1529 * <dt>endSection()<dd>to end the current section
1530 * </dl>
1531 */
1532 abstract class TextHandlingDestination
1533 extends AttributeTrackingDestination
1534 implements Destination
1535 {
1536 /** <code>true</code> if the reader has not just finished
1537 * a paragraph; false upon startup */
1538 boolean inParagraph;
1539
1540 public TextHandlingDestination()
1541 {
1542 super();
1543 inParagraph = false;
1544 }
1545
1546 public void handleText(String text)
1547 {
1548 if (! inParagraph)
1549 beginParagraph();
1550
1551 deliverText(text, currentTextAttributes());
1552 }
1553
1554 abstract void deliverText(String text, AttributeSet characterAttributes);
1555
1556 public void close()
1585 protected void beginParagraph()
1586 {
1587 inParagraph = true;
1588 }
1589
1590 protected void endParagraph()
1591 {
1592 AttributeSet pgfAttributes = currentParagraphAttributes();
1593 AttributeSet chrAttributes = currentTextAttributes();
1594 finishParagraph(pgfAttributes, chrAttributes);
1595 inParagraph = false;
1596 }
1597
1598 abstract void finishParagraph(AttributeSet pgfA, AttributeSet chrA);
1599
1600 abstract void endSection();
1601 }
1602
1603 /** RTFReader.DocumentDestination is a concrete subclass of
1604 * TextHandlingDestination which appends the text to the
1605 * StyledDocument given by the <code>target</code> ivar of the
1606 * containing RTFReader.
1607 */
1608 class DocumentDestination
1609 extends TextHandlingDestination
1610 implements Destination
1611 {
1612 public void deliverText(String text, AttributeSet characterAttributes)
1613 {
1614 try {
1615 target.insertString(target.getLength(),
1616 text,
1617 currentTextAttributes());
1618 } catch (BadLocationException ble) {
1619 /* This shouldn't be able to happen, of course */
1620 /* TODO is InternalError the correct error to throw? */
1621 throw new InternalError(ble.getMessage(), ble);
1622 }
1623 }
1624
1625 public void finishParagraph(AttributeSet pgfAttributes,
|
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text.rtf;
26
27 import java.lang.*;
28 import java.util.*;
29 import java.io.*;
30 import java.awt.Color;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import javax.swing.text.*;
34
35 /**
36 * Takes a sequence of RTF tokens and text and appends the text
37 * described by the RTF to a {@code StyledDocument} (the <em>target</em>).
38 * The RTF is lexed
39 * from the character stream by the {@code RTFParser} which is this class's
40 * superclass.
41 *
42 * This class is an indirect subclass of OutputStream. It must be closed
43 * in order to guarantee that all of the text has been sent to
44 * the text acceptor.
45 *
46 * @see RTFParser
47 * @see java.io.OutputStream
48 */
49 class RTFReader extends RTFParser
50 {
51 /** The object to which the parsed text is sent. */
52 StyledDocument target;
53
54 /** Miscellaneous information about the parser's state. This
55 * dictionary is saved and restored when an RTF group begins
56 * or ends. */
57 Dictionary<Object, Object> parserState; /* Current parser state */
58 /** This is the "dst" item from parserState. rtfDestination
59 * is the current rtf destination. It is cached in an instance
60 * variable for speed. */
61 Destination rtfDestination;
62 /** This holds the current document attributes. */
63 MutableAttributeSet documentAttributes;
64
65 /** This Dictionary maps Integer font numbers to String font names. */
66 Dictionary<Integer, String> fontTable;
67 /** This array maps color indices to Color objects. */
68 Color[] colorTable;
69 /** This array maps character style numbers to Style objects. */
70 Style[] characterStyles;
71 /** This array maps paragraph style numbers to Style objects. */
72 Style[] paragraphStyles;
73 /** This array maps section style numbers to Style objects. */
74 Style[] sectionStyles;
75
76 /** This is the RTF version number, extracted from the \rtf keyword.
77 * The version information is currently not used. */
78 int rtfversion;
79
80 /** {@code true} to indicate that if the next keyword is unknown,
81 * the containing group should be ignored. */
82 boolean ignoreGroupIfUnknownKeyword;
83
84 /** The parameter of the most recently parsed \\ucN keyword,
85 * used for skipping alternative representations after a
86 * Unicode character. */
87 int skippingCharacters;
88
89 private static Dictionary<String, RTFAttribute> straightforwardAttributes;
90 static {
91 straightforwardAttributes = RTFAttributes.attributesByKeyword();
92 }
93
94 private MockAttributeSet mockery;
95
96 /* this should be final, but there's a bug in javac... */
97 /** textKeywords maps RTF keywords to single-character strings,
98 * for those keywords which simply insert some text. */
99 static Dictionary<String, String> textKeywords = null;
100 static {
187 text = text.substring(skippingCharacters);
188 skippingCharacters = 0;
189 }
190 }
191
192 if (rtfDestination != null) {
193 rtfDestination.handleText(text);
194 return;
195 }
196
197 warning("Text with no destination. oops.");
198 }
199
200 /** The default color for text which has no specified color. */
201 Color defaultColor()
202 {
203 return Color.black;
204 }
205
206 /** Called by the superclass when a new RTF group is begun.
207 * This implementation saves the current {@code parserState}, and gives
208 * the current destination a chance to save its own state.
209 * @see RTFParser#begingroup
210 */
211 public void begingroup()
212 {
213 if (skippingCharacters > 0) {
214 /* TODO this indicates an error in the RTF. Log it? */
215 skippingCharacters = 0;
216 }
217
218 /* we do this little dance to avoid cloning the entire state stack and
219 immediately throwing it away. */
220 Object oldSaveState = parserState.get("_savedState");
221 if (oldSaveState != null)
222 parserState.remove("_savedState");
223 @SuppressWarnings("unchecked")
224 Dictionary<String, Object> saveState = (Dictionary<String, Object>)((Hashtable)parserState).clone();
225 if (oldSaveState != null)
226 saveState.put("_savedState", oldSaveState);
227 parserState.put("_savedState", saveState);
228
229 if (rtfDestination != null)
230 rtfDestination.begingroup();
231 }
232
233 /** Called by the superclass when the current RTF group is closed.
234 * This restores the parserState saved by {@code begingroup()}
235 * as well as invoking the endgroup method of the current
236 * destination.
237 * @see RTFParser#endgroup
238 */
239 public void endgroup()
240 {
241 if (skippingCharacters > 0) {
242 /* NB this indicates an error in the RTF. Log it? */
243 skippingCharacters = 0;
244 }
245
246 @SuppressWarnings("unchecked")
247 Dictionary<Object, Object> restoredState = (Dictionary<Object, Object>)parserState.get("_savedState");
248 Destination restoredDestination = (Destination)restoredState.get("dst");
249 if (restoredDestination != rtfDestination) {
250 rtfDestination.close(); /* allow the destination to clean up */
251 rtfDestination = restoredDestination;
252 }
253 Dictionary<Object, Object> oldParserState = parserState;
254 parserState = restoredState;
1516 attr.setDefault(characterAttributes);
1517 }
1518
1519 parserState.remove("sectionStyle");
1520 }
1521 }
1522
1523 /** RTFReader.TextHandlingDestination provides basic text handling
1524 * functionality. Subclasses must implement: <dl>
1525 * <dt>deliverText()<dd>to handle a run of text with the same
1526 * attributes
1527 * <dt>finishParagraph()<dd>to end the current paragraph and
1528 * set the paragraph's attributes
1529 * <dt>endSection()<dd>to end the current section
1530 * </dl>
1531 */
1532 abstract class TextHandlingDestination
1533 extends AttributeTrackingDestination
1534 implements Destination
1535 {
1536 /** {@code true} if the reader has not just finished
1537 * a paragraph; false upon startup */
1538 boolean inParagraph;
1539
1540 public TextHandlingDestination()
1541 {
1542 super();
1543 inParagraph = false;
1544 }
1545
1546 public void handleText(String text)
1547 {
1548 if (! inParagraph)
1549 beginParagraph();
1550
1551 deliverText(text, currentTextAttributes());
1552 }
1553
1554 abstract void deliverText(String text, AttributeSet characterAttributes);
1555
1556 public void close()
1585 protected void beginParagraph()
1586 {
1587 inParagraph = true;
1588 }
1589
1590 protected void endParagraph()
1591 {
1592 AttributeSet pgfAttributes = currentParagraphAttributes();
1593 AttributeSet chrAttributes = currentTextAttributes();
1594 finishParagraph(pgfAttributes, chrAttributes);
1595 inParagraph = false;
1596 }
1597
1598 abstract void finishParagraph(AttributeSet pgfA, AttributeSet chrA);
1599
1600 abstract void endSection();
1601 }
1602
1603 /** RTFReader.DocumentDestination is a concrete subclass of
1604 * TextHandlingDestination which appends the text to the
1605 * StyledDocument given by the {@code target} ivar of the
1606 * containing RTFReader.
1607 */
1608 class DocumentDestination
1609 extends TextHandlingDestination
1610 implements Destination
1611 {
1612 public void deliverText(String text, AttributeSet characterAttributes)
1613 {
1614 try {
1615 target.insertString(target.getLength(),
1616 text,
1617 currentTextAttributes());
1618 } catch (BadLocationException ble) {
1619 /* This shouldn't be able to happen, of course */
1620 /* TODO is InternalError the correct error to throw? */
1621 throw new InternalError(ble.getMessage(), ble);
1622 }
1623 }
1624
1625 public void finishParagraph(AttributeSet pgfAttributes,
|