Writing RTF files from Java Swing DefaultStyledDocuments
by Bill Stackhouse (
[email protected])
May be freely reposted in its entirety. All java source contained may be freely used or modified in any products without license.
Introduction
Writing RTF files from Swing requires knowledge of RTF, Swing styled documents, and Swing styles. This is an attempt to pull the necessary information into a single tutorial. There are minor bugs in Swing support for RTF that need to be corrected and an explanation of how to do that is provided. Sample classes are provided for inserting styled text into a Swing styled document. Finally, an example is included.
Alternatives
There are two open source products available to write RTF files - iText and SRW. Neither support integration with Swing styled documents, AWT fonts, or tagging RTF paragraphs with globally defined styles.
iText in the past supported writing both PDF and RTF files. As of version 5.0.0, all RTF support has been removed.
http://sourceforge.net/projects/itext/
SRW provides basic support for writing RTF files.
http://sourceforge.net/projects/srw/
RTF Styles in Microsoft Word
Microsoft Word supports styles defined globally for a document and specifically at the paragraph and character level. The use of globally defined styles allows consistent formatting throughout a document and simplifies changing formatting. These styles are defined and applied using the Format Style menu. They may be applied using the Formatting Toolbar as well. Style changes applied with Format Paragraph and Format Font are unique to the current selection and any text added at that location.
Resulting RTF files saved by Microsoft Word will define \stylesheet for all globally defined styles. Paragraphs tagged with these styles will have a \pard to associate the style with the paragraph.
Swing Styled Documents
Swing text classes such as JTextArea use DefaultStyledDocument to provide formatting of text using the Style class. Portions of text are associated with a style and the document may have multiple styles. There is structure, but no concept of a 'paragraph'.
Writing an RTF file does not require using JTextArea if the document is not displayed. Instead a DefaultStyledDocument can be created alone.
Later, classes will be presented for encapsulating the details of inserting styled text into a document.
Swing RTF Classes
Swing RTF is often considered 'unusable'. Three problems and limitations minimize the utility of the Swing RTF classes, though there are many features that should be added and bugs fixed. Looking at the Java bug database for RTF bugs, there are many reported.
1) alignment is always written as ALIGN_LEFT (\ql)
2) \pard is only written if the Style has a special attribute
3) no way to insert page breaks
Comparing javax.swing.text.rtf between Java 1.4, 1.5, and 1.6, only a few changes were made to RTFReader.java between 1.4 and 1.5. No changes other than copyright dates in comments were made between 1.5 and 1.6.
Fixes are made by copying the source files from the package javax.swing.text.rtf into a new package in outside of the JDK, either in a separate project or in the one using the corrected classes. Since little maintenance is made to these files, this should not cause future problems or incompatibilities. All source in these files refer only to public methods in classes in other packages. Files for javax.swing.text.rtf.charsets are necessary. The line numbers below refer to the files from Java 1.6.
On Mac OS the source is located in the JavaVM.framework/Home/src.jar. The charasets are in JavaVM.framework/Home/Classes/classes.jar.
Problem 1) Attributes with a constant value are not processed correctly (eg. Alignment=3). This affects both paragraph and tab alignment. JDK bug number 4735839 provide hints, though probably not sufficent. Make the following changes to fully solve the problem.
RTFGenerator.java line 231, replace method attrDiff with
In other references to attrDiff add a null parameter as follows (lines 462, 480, 716, 733, 743),
RTFGenerator.java line 473 replace checkControlWord with
Problem 2) Marking a paragraph with \pard occurs if the attribute {"style:type","paragraph"} is part of the style and the style is applied using setLogicalStyle. Standard support does not provide access to these keywords, nor is this documented. Add a new class RTFStyle in the package with the updated java files.
Problem 3) RTF uses the \page tag to force a hard page break. Add the following so that the hex character 0x0C in a document will write the \page tag and reading \page will insert 0x0C.
at RTFGenerator.java line 882 in writeCharacter add
at RTFReader.java after line 97 add
Styled Text Classes
Encapsulating the details of inserting styled text into a document will provide cleaner source. Two classes, Paragraph and Chunk are provided as examples. Paragraph will represent a single paragraph from the first character to the NEW LINE character. Chunk will represent a phrase in the paragraph with a single style. One or more chunks exist in a paragraph.
Putting it all together
The following provides a simple example of using these concepts.
1) define styles
Styles are associated with a StyleContext and should be divided between styles for a full paragraph (font, alignment, first line indent, etc.) and those for pieces of a paragraph (bold, italics, text color, etc.).
2) Create a document.
If the document is to be associated with a JTextPane, then use the following.
3) Add text to document.
The following will insert "The way to write RTF" with the first "T" in Helvetica-Bold and RTF in the paragraph font but italicized.
The following will add a page break before the paragraph.
or
4) Write document to file
5) Debugging
The contents of the RTF file and the document can be written to the console.