/* * 07/28/2008 * RtfGenerator.java - Generates RTF via a simple Java API. * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.rsyntaxtextarea; import java.awt.Color; import java.awt.Font; import java.awt.Toolkit; import java.util.ArrayList; import java.util.List; import org.fife.ui.rtextarea.RTextArea; /** * Generates RTF text via a simple Java API. *
* * The following RTF features are supported: *
null, the
* default font is used.
* @param fg
* The foreground of the text. If this is null,
* the default foreground color is used.
* @param bg
* The background color of the text. If this is
* null, the default background color is used.
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg) {
appendToDoc(text, f, fg, bg, false);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text
* The text to append.
* @param f
* The font of the text. If this is null, the
* default font is used.
* @param bg
* The background color of the text. If this is
* null, the default background color is used.
* @param underline
* Whether the text should be underlined.
* @see #appendNewline()
*/
public void appendToDocNoFG(String text, Font f, Color bg, boolean underline) {
appendToDoc(text, f, null, bg, underline, false);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text
* The text to append.
* @param f
* The font of the text. If this is null, the
* default font is used.
* @param fg
* The foreground of the text. If this is null,
* the default foreground color is used.
* @param bg
* The background color of the text. If this is
* null, the default background color is used.
* @param underline
* Whether the text should be underlined.
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg, boolean underline) {
appendToDoc(text, f, fg, bg, underline, true);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text
* The text to append.
* @param f
* The font of the text. If this is null, the
* default font is used.
* @param fg
* The foreground of the text. If this is null,
* the default foreground color is used.
* @param bg
* The background color of the text. If this is
* null, the default background color is used.
* @param underline
* Whether the text should be underlined.
* @param setFG
* Whether the foreground specified by fg should
* be honored (if it is non-null).
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg, boolean underline, boolean setFG) {
if (text != null) {
// Set font to use, if different from last addition.
int fontIndex = f == null ? 0 : (getFontIndex(fontList, f) + 1);
if (fontIndex != lastFontIndex) {
document.append("\\f").append(fontIndex);
lastFontIndex = fontIndex;
lastWasControlWord = true;
}
// Set styles to use.
if (f != null) {
int fontSize = fixFontSize(f.getSize2D() * 2); // Half points!
if (fontSize != lastFontSize) {
document.append("\\fs").append(fontSize);
lastFontSize = fontSize;
lastWasControlWord = true;
}
if (f.isBold() != lastBold) {
document.append(lastBold ? "\\b0" : "\\b");
lastBold = !lastBold;
lastWasControlWord = true;
}
if (f.isItalic() != lastItalic) {
document.append(lastItalic ? "\\i0" : "\\i");
lastItalic = !lastItalic;
lastWasControlWord = true;
}
} else { // No font specified - assume neither bold nor italic.
if (lastFontSize != DEFAULT_FONT_SIZE) {
document.append("\\fs").append(DEFAULT_FONT_SIZE);
lastFontSize = DEFAULT_FONT_SIZE;
lastWasControlWord = true;
}
if (lastBold) {
document.append("\\b0");
lastBold = false;
lastWasControlWord = true;
}
if (lastItalic) {
document.append("\\i0");
lastItalic = false;
lastWasControlWord = true;
}
}
if (underline) {
document.append("\\ul");
lastWasControlWord = true;
}
// Set the foreground color.
if (setFG) {
int fgIndex = 0;
if (fg != null) { // null => fg color index 0
fgIndex = getColorIndex(colorList, fg) + 1;
}
if (fgIndex != lastFGIndex) {
document.append("\\cf").append(fgIndex);
lastFGIndex = fgIndex;
lastWasControlWord = true;
}
}
// Set the background color.
if (bg != null) {
int pos = getColorIndex(colorList, bg);
document.append("\\highlight").append(pos + 1);
lastWasControlWord = true;
}
if (lastWasControlWord) {
document.append(' '); // Delimiter
lastWasControlWord = false;
}
escapeAndAdd(document, text);
// Reset everything that was set for this text fragment.
if (bg != null) {
document.append("\\highlight0");
lastWasControlWord = true;
}
if (underline) {
document.append("\\ul0");
lastWasControlWord = true;
}
}
}
/**
* Appends some text to a buffer, with special care taken for special
* characters as defined by the RTF spec.
*
* \tab"
*
*
* Java2D assumes 72 dpi. On systems with larger dpi (Windows, GTK, etc.),
* font rendering will appear too small if we simply return a Java "Font"
* object's getSize() value. We need to adjust it for the screen
* resolution.
*
* @param pointSize
* A Java Font's point size, as returned from
*
*
* If the font is not in the list, it is added, and its new index is
* returned.
*
* @param list
* The list (possibly) containing the font.
* @param font
* The font to get the index of.
* @return The index of the font.
*/
private static int getFontIndex(List list, Font font) {
String fontName = font.getFamily();
for (int i = 0; i < list.size(); i++) {
Font font2 = list.get(i);
if (font2.getFamily().equals(fontName)) {
return i;
}
}
list.add(font);
return list.size() - 1;
}
private String getFontTableRtf() {
// Example:
// "{\\fonttbl{\\f0\\fmodern\\fcharset0 Courier;}}"
StringBuilder sb = new StringBuilder();
// Workaround for text areas using the Java logical font "Monospaced"
// by default. There's no way to know what it's mapped to, so we
// just search for a monospaced font on the system.
String monoFamilyName = getMonospacedFontFamily();
sb.append("{\\fonttbl{\\f0\\fnil\\fcharset0 " + monoFamilyName + ";}");
for (int i = 0; i < fontList.size(); i++) {
Font f = fontList.get(i);
String familyName = f.getFamily();
if (familyName.equals("Monospaced")) {
familyName = monoFamilyName;
}
sb.append("{\\f").append(i + 1).append("\\fnil\\fcharset0 ");
sb.append(familyName).append(";}");
}
sb.append('}');
return sb.toString();
}
/**
* Returns a good "default" monospaced font to use when Java's logical
* font "Monospaced" is found.
*
* @return The monospaced font family to use.
*/
private static String getMonospacedFontFamily() {
String family = RTextArea.getDefaultFont().getFamily();
if ("Monospaced".equals(family)) {
family = "Courier";
}
return family;
}
/**
* Returns the RTF document created by this generator.
*
* @return The RTF document, as a getSize2D().
* @return The font point size, adjusted for the current screen resolution.
* This will allow other applications to render fonts the same
* size as they appear in the Java application.
*/
private int fixFontSize(float pointSize) {
if (screenRes != 72) { // Java2D assumes 72 dpi
pointSize = Math.round(pointSize * 72f / screenRes);
}
return (int) pointSize;
}
/**
* Returns the index of the specified item in a list. If the item
* is not in the list, it is added, and its new index is returned.
*
* @param list
* The list (possibly) containing the item.
* @param item
* The item to get the index of.
* @return The index of the item.
*/
private static int getColorIndex(ListString.
*/
public String getRtf() {
StringBuilder sb = new StringBuilder();
sb.append("{");
// Header
sb.append("\\rtf1\\ansi\\ansicpg1252");
sb.append("\\deff0"); // First font in font table is the default
sb.append("\\deflang1033");
sb.append("\\viewkind4"); // "Normal" view
sb.append("\\uc\\pard\\f0");
sb.append("\\fs20"); // Font size in half-points (default 24)
sb.append(getFontTableRtf()).append('\n');
sb.append(getColorTableRtf()).append('\n');
// Content
sb.append(document);
sb.append("}");
// System.err.println("*** " + sb.length());
return sb.toString();
}
/**
* Resets this generator. All document information and content is
* cleared.
*/
public void reset() {
fontList.clear();
colorList.clear();
document.setLength(0);
lastWasControlWord = false;
lastFontIndex = 0;
lastFGIndex = 0;
lastBold = false;
lastItalic = false;
lastFontSize = DEFAULT_FONT_SIZE;
screenRes = Toolkit.getDefaultToolkit().getScreenResolution();
}
}