Methods Summary |
---|
java.lang.String | approximationForUnicode(char ch)
/* TODO: Find reasonable approximations for all Unicode characters
in all RTF code pages... heh, heh... */
return "?";
|
private static java.lang.Object | attrDiff(javax.swing.text.MutableAttributeSet oldAttrs, javax.swing.text.AttributeSet newAttrs, java.lang.Object key, java.lang.Object dfl)
Object oldValue, newValue;
oldValue = oldAttrs.getAttribute(key);
newValue = newAttrs.getAttribute(key);
if (newValue == oldValue)
return null;
if (newValue == null) {
oldAttrs.removeAttribute(key);
if (dfl != null && !dfl.equals(oldValue))
return dfl;
else
return null;
}
if (oldValue == null ||
!equalArraysOK(oldValue, newValue)) {
oldAttrs.addAttribute(key, newValue);
return newValue;
}
return null;
|
protected void | checkControlWord(javax.swing.text.MutableAttributeSet currentAttributes, javax.swing.text.AttributeSet newAttributes, javax.swing.text.rtf.RTFAttribute word)
Object parm;
if ((parm = attrDiff(currentAttributes, newAttributes,
word.swingName(), MagicToken)) != null) {
if (parm == MagicToken)
parm = null;
word.writeValue(parm, this, true);
}
|
protected void | checkControlWords(javax.swing.text.MutableAttributeSet currentAttributes, javax.swing.text.AttributeSet newAttributes, javax.swing.text.rtf.RTFAttribute[] words, int domain)
int wordIndex;
int wordCount = words.length;
for(wordIndex = 0; wordIndex < wordCount; wordIndex++) {
RTFAttribute attr = words[wordIndex];
if (attr.domain() == domain)
checkControlWord(currentAttributes, newAttributes, attr);
}
|
protected void | checkNumericControlWord(javax.swing.text.MutableAttributeSet currentAttributes, javax.swing.text.AttributeSet newAttributes, java.lang.Object attrName, java.lang.String controlWord, float dflt, float scale)
Object parm;
if ((parm = attrDiff(currentAttributes, newAttributes,
attrName, MagicToken)) != null) {
float targ;
if (parm == MagicToken)
targ = dflt;
else
targ = ((Number)parm).floatValue();
writeControlWord(controlWord, Math.round(targ * scale));
}
|
protected static int | convertCharacter(int[] conversion, char ch)Takes a char and a conversion table (an int[] in the current
implementation, but conversion tables should be treated as an opaque
type) and returns the
corresponding byte value (as an int, since bytes are signed).
int index;
for(index = 0; index < conversion.length; index += 2) {
if(conversion[index] == ch)
return conversion[index + 1];
}
return 0; /* 0 indicates an unrepresentable character */
|
private static boolean | equalArraysOK(java.lang.Object a, java.lang.Object b)
Object[] aa, bb;
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.equals(b))
return true;
if (!(a.getClass().isArray() && b.getClass().isArray()))
return false;
aa = (Object[])a;
bb = (Object[])b;
if (aa.length != bb.length)
return false;
int i;
int l = aa.length;
for(i = 0; i < l; i++) {
if (!equalArraysOK(aa[i], bb[i]))
return false;
}
return true;
|
public void | examineElement(javax.swing.text.Element el)
AttributeSet a = el.getAttributes();
String fontName;
Object foregroundColor, backgroundColor;
tallyStyles(a);
if (a != null) {
/* TODO: default color must be color 0! */
foregroundColor = StyleConstants.getForeground(a);
if (foregroundColor != null &&
colorTable.get(foregroundColor) == null) {
colorTable.put(foregroundColor, new Integer(colorCount));
colorCount ++;
}
backgroundColor = a.getAttribute(StyleConstants.Background);
if (backgroundColor != null &&
colorTable.get(backgroundColor) == null) {
colorTable.put(backgroundColor, new Integer(colorCount));
colorCount ++;
}
fontName = StyleConstants.getFontFamily(a);
if (fontName == null)
fontName = defaultFontFamily;
if (fontName != null &&
fontTable.get(fontName) == null) {
fontTable.put(fontName, new Integer(fontCount));
fontCount ++;
}
}
int el_count = el.getElementCount();
for(int el_idx = 0; el_idx < el_count; el_idx ++) {
examineElement(el.getElement(el_idx));
}
|
private javax.swing.text.Style | findStyle(javax.swing.text.AttributeSet a)
while(a != null) {
if (a instanceof Style) {
Object aNum = styleTable.get(a);
if (aNum != null)
return (Style)a;
}
a = a.getResolveParent();
}
return null;
|
private java.lang.Integer | findStyleNumber(javax.swing.text.AttributeSet a, java.lang.String domain)
while(a != null) {
if (a instanceof Style) {
Integer aNum = (Integer)styleTable.get(a);
if (aNum != null) {
if (domain == null ||
domain.equals(a.getAttribute(Constants.StyleType)))
return aNum;
}
}
a = a.getResolveParent();
}
return null;
|
static int[] | outputConversionForName(java.lang.String name)
char[] table = (char[])RTFReader.getCharacterSet(name);
return outputConversionFromTranslationTable(table);
|
static int[] | outputConversionFromTranslationTable(char[] table)Takes a translation table (a 256-element array of characters)
and creates an output conversion table for use by
convertCharacter().
int[] conversion = new int[2 * table.length];
int index;
for(index = 0; index < table.length; index ++) {
conversion[index * 2] = table[index];
conversion[(index * 2) + 1] = index;
}
return conversion;
|
protected void | resetCharacterAttributes(javax.swing.text.MutableAttributeSet currentAttributes)
writeControlWord("plain");
int wordIndex;
int wordCount = RTFAttributes.attributes.length;
for(wordIndex = 0; wordIndex < wordCount; wordIndex++) {
RTFAttribute attr = RTFAttributes.attributes[wordIndex];
if (attr.domain() == RTFAttribute.D_CHARACTER)
attr.setDefault(currentAttributes);
}
StyleConstants.setFontFamily(currentAttributes, defaultFontFamily);
currentAttributes.removeAttribute(StyleConstants.FontSize); /* =default */
currentAttributes.removeAttribute(StyleConstants.Background);
currentAttributes.removeAttribute(StyleConstants.Foreground);
currentAttributes.removeAttribute(StyleConstants.LineSpacing);
currentAttributes.removeAttribute("characterStyle");
|
protected void | resetParagraphAttributes(javax.swing.text.MutableAttributeSet currentAttributes)
writeControlWord("pard");
currentAttributes.addAttribute(StyleConstants.Alignment, Zero);
int wordIndex;
int wordCount = RTFAttributes.attributes.length;
for(wordIndex = 0; wordIndex < wordCount; wordIndex++) {
RTFAttribute attr = RTFAttributes.attributes[wordIndex];
if (attr.domain() == RTFAttribute.D_PARAGRAPH)
attr.setDefault(currentAttributes);
}
currentAttributes.removeAttribute("paragraphStyle");
currentAttributes.removeAttribute(Constants.Tabs);
|
protected void | resetSectionAttributes(javax.swing.text.MutableAttributeSet currentAttributes)
writeControlWord("sectd");
int wordIndex;
int wordCount = RTFAttributes.attributes.length;
for(wordIndex = 0; wordIndex < wordCount; wordIndex++) {
RTFAttribute attr = RTFAttributes.attributes[wordIndex];
if (attr.domain() == RTFAttribute.D_SECTION)
attr.setDefault(currentAttributes);
}
currentAttributes.removeAttribute("sectionStyle");
|
private void | tallyStyles(javax.swing.text.AttributeSet a)
while (a != null) {
if (a instanceof Style) {
Integer aNum = (Integer)styleTable.get(a);
if (aNum == null) {
styleCount = styleCount + 1;
aNum = new Integer(styleCount);
styleTable.put(a, aNum);
}
}
a = a.getResolveParent();
}
|
void | updateCharacterAttributes(javax.swing.text.MutableAttributeSet current, javax.swing.text.AttributeSet newAttributes, boolean updateStyleChanges)
Object parm;
if (updateStyleChanges) {
Object oldStyle = current.getAttribute("characterStyle");
Object newStyle = findStyleNumber(newAttributes,
Constants.STCharacter);
if (oldStyle != newStyle) {
if (oldStyle != null) {
resetCharacterAttributes(current);
}
if (newStyle != null) {
writeControlWord("cs", ((Integer)newStyle).intValue());
current.addAttribute("characterStyle", newStyle);
} else {
current.removeAttribute("characterStyle");
}
}
}
if ((parm = attrDiff(current, newAttributes,
StyleConstants.FontFamily, null)) != null) {
Number fontNum = (Number)fontTable.get(parm);
writeControlWord("f", fontNum.intValue());
}
checkNumericControlWord(current, newAttributes,
StyleConstants.FontSize, "fs",
defaultFontSize, 2f);
checkControlWords(current, newAttributes,
RTFAttributes.attributes, RTFAttribute.D_CHARACTER);
checkNumericControlWord(current, newAttributes,
StyleConstants.LineSpacing, "sl",
0, 20f); /* TODO: sl wackiness */
if ((parm = attrDiff(current, newAttributes,
StyleConstants.Background, MagicToken)) != null) {
int colorNum;
if (parm == MagicToken)
colorNum = 0;
else
colorNum = ((Number)colorTable.get(parm)).intValue();
writeControlWord("cb", colorNum);
}
if ((parm = attrDiff(current, newAttributes,
StyleConstants.Foreground, null)) != null) {
int colorNum;
if (parm == MagicToken)
colorNum = 0;
else
colorNum = ((Number)colorTable.get(parm)).intValue();
writeControlWord("cf", colorNum);
}
|
void | updateParagraphAttributes(javax.swing.text.MutableAttributeSet current, javax.swing.text.AttributeSet newAttributes, boolean emitStyleChanges)
Object parm;
Object oldStyle, newStyle;
/* The only way to get rid of tabs or styles is with the \pard keyword,
emitted by resetParagraphAttributes(). Ideally we should avoid
emitting \pard if the new paragraph's tabs are a superset of the old
paragraph's tabs. */
if (emitStyleChanges) {
oldStyle = current.getAttribute("paragraphStyle");
newStyle = findStyleNumber(newAttributes, Constants.STParagraph);
if (oldStyle != newStyle) {
if (oldStyle != null) {
resetParagraphAttributes(current);
oldStyle = null;
}
}
} else {
oldStyle = null;
newStyle = null;
}
Object oldTabs = current.getAttribute(Constants.Tabs);
Object newTabs = newAttributes.getAttribute(Constants.Tabs);
if (oldTabs != newTabs) {
if (oldTabs != null) {
resetParagraphAttributes(current);
oldTabs = null;
oldStyle = null;
}
}
if (oldStyle != newStyle && newStyle != null) {
writeControlWord("s", ((Integer)newStyle).intValue());
current.addAttribute("paragraphStyle", newStyle);
}
checkControlWords(current, newAttributes,
RTFAttributes.attributes, RTFAttribute.D_PARAGRAPH);
if (oldTabs != newTabs && newTabs != null) {
TabStop tabs[] = (TabStop[])newTabs;
int index;
for(index = 0; index < tabs.length; index ++) {
TabStop tab = tabs[index];
switch (tab.getAlignment()) {
case TabStop.ALIGN_LEFT:
case TabStop.ALIGN_BAR:
break;
case TabStop.ALIGN_RIGHT:
writeControlWord("tqr");
break;
case TabStop.ALIGN_CENTER:
writeControlWord("tqc");
break;
case TabStop.ALIGN_DECIMAL:
writeControlWord("tqdec");
break;
}
switch (tab.getLeader()) {
case TabStop.LEAD_NONE:
break;
case TabStop.LEAD_DOTS:
writeControlWord("tldot");
break;
case TabStop.LEAD_HYPHENS:
writeControlWord("tlhyph");
break;
case TabStop.LEAD_UNDERLINE:
writeControlWord("tlul");
break;
case TabStop.LEAD_THICKLINE:
writeControlWord("tlth");
break;
case TabStop.LEAD_EQUALS:
writeControlWord("tleq");
break;
}
int twips = Math.round(20f * tab.getPosition());
if (tab.getAlignment() == TabStop.ALIGN_BAR) {
writeControlWord("tb", twips);
} else {
writeControlWord("tx", twips);
}
}
current.addAttribute(Constants.Tabs, tabs);
}
|
void | updateSectionAttributes(javax.swing.text.MutableAttributeSet current, javax.swing.text.AttributeSet newAttributes, boolean emitStyleChanges)
if (emitStyleChanges) {
Object oldStyle = current.getAttribute("sectionStyle");
Object newStyle = findStyleNumber(newAttributes, Constants.STSection);
if (oldStyle != newStyle) {
if (oldStyle != null) {
resetSectionAttributes(current);
}
if (newStyle != null) {
writeControlWord("ds", ((Integer)newStyle).intValue());
current.addAttribute("sectionStyle", newStyle);
} else {
current.removeAttribute("sectionStyle");
}
}
}
checkControlWords(current, newAttributes,
RTFAttributes.attributes, RTFAttribute.D_SECTION);
|
public void | writeBegingroup()
outputStream.write('{");
afterKeyword = false;
|
public void | writeCharacter(char ch)
/* Nonbreaking space is in most RTF encodings, but the keyword is
preferable; same goes for tabs */
if (ch == 0xA0) { /* nonbreaking space */
outputStream.write(0x5C); /* backslash */
outputStream.write(0x7E); /* tilde */
afterKeyword = false; /* non-alpha keywords are self-terminating */
return;
}
if (ch == 0x09) { /* horizontal tab */
writeControlWord("tab");
return;
}
if (ch == 10 || ch == 13) { /* newline / paragraph */
/* ignore CRs, we'll write a paragraph element soon enough */
return;
}
int b = convertCharacter(outputConversion, ch);
if (b == 0) {
/* Unicode characters which have corresponding RTF keywords */
int i;
for(i = 0; i < textKeywords.length; i++) {
if (textKeywords[i].character == ch) {
writeControlWord(textKeywords[i].keyword);
return;
}
}
/* In some cases it would be reasonable to check to see if the
glyph being written out is in the Symbol encoding, and if so,
to switch to the Symbol font for this character. TODO. */
/* Currently all unrepresentable characters are written as
Unicode escapes. */
String approximation = approximationForUnicode(ch);
if (approximation.length() != unicodeCount) {
unicodeCount = approximation.length();
writeControlWord("uc", unicodeCount);
}
writeControlWord("u", (int)ch);
writeRawString(" ");
writeRawString(approximation);
afterKeyword = false;
return;
}
if (b > 127) {
int nybble;
outputStream.write('\\");
outputStream.write('\'");
nybble = ( b & 0xF0 ) >>> 4;
outputStream.write(hexdigits[nybble]);
nybble = ( b & 0x0F );
outputStream.write(hexdigits[nybble]);
afterKeyword = false;
return;
}
switch (b) {
case '}":
case '{":
case '\\":
outputStream.write(0x5C); /* backslash */
afterKeyword = false; /* in a keyword, actually ... */
/* fall through */
default:
if (afterKeyword) {
outputStream.write(0x20); /* space */
afterKeyword = false;
}
outputStream.write(b);
break;
}
|
public void | writeControlWord(java.lang.String keyword)
outputStream.write('\\");
writeRawString(keyword);
afterKeyword = true;
|
public void | writeControlWord(java.lang.String keyword, int arg)
outputStream.write('\\");
writeRawString(keyword);
writeRawString(String.valueOf(arg)); /* TODO: correct in all cases? */
afterKeyword = true;
|
public static void | writeDocument(javax.swing.text.Document d, java.io.OutputStream to)
RTFGenerator gen = new RTFGenerator(to);
Element root = d.getDefaultRootElement();
gen.examineElement(root);
gen.writeRTFHeader();
gen.writeDocumentProperties(d);
/* TODO this assumes a particular element structure; is there
a way to iterate more generically ? */
int max = root.getElementCount();
for(int idx = 0; idx < max; idx++)
gen.writeParagraphElement(root.getElement(idx));
gen.writeRTFTrailer();
|
void | writeDocumentProperties(javax.swing.text.Document doc)
/* Write the document properties */
int i;
boolean wroteSomething = false;
for(i = 0; i < RTFAttributes.attributes.length; i++) {
RTFAttribute attr = RTFAttributes.attributes[i];
if (attr.domain() != RTFAttribute.D_DOCUMENT)
continue;
Object prop = doc.getProperty(attr.swingName());
boolean ok = attr.writeValue(prop, this, false);
if (ok)
wroteSomething = true;
}
if (wroteSomething)
writeLineBreak();
|
public void | writeEndgroup()
outputStream.write('}");
afterKeyword = false;
|
public void | writeLineBreak()
writeRawString("\n");
afterKeyword = false;
|
public void | writeParagraphElement(javax.swing.text.Element el)
updateParagraphAttributes(outputAttributes, el.getAttributes(), true);
int sub_count = el.getElementCount();
for(int idx = 0; idx < sub_count; idx ++) {
writeTextElement(el.getElement(idx));
}
writeControlWord("par");
writeLineBreak(); /* makes the raw file more readable */
|
public void | writeRTFHeader()
int index;
/* TODO: Should the writer attempt to examine the text it's writing
and pick a character set which will most compactly represent the
document? (currently the writer always uses the ansi character
set, which is roughly ISO-8859 Latin-1, and uses Unicode escapes
for all other characters. However Unicode is a relatively
recent addition to RTF, and not all readers will understand it.) */
writeBegingroup();
writeControlWord("rtf", 1);
writeControlWord("ansi");
outputConversion = outputConversionForName("ansi");
writeLineBreak();
/* write font table */
String[] sortedFontTable = new String[fontCount];
Enumeration fonts = fontTable.keys();
String font;
while(fonts.hasMoreElements()) {
font = (String)fonts.nextElement();
Integer num = (Integer)(fontTable.get(font));
sortedFontTable[num.intValue()] = font;
}
writeBegingroup();
writeControlWord("fonttbl");
for(index = 0; index < fontCount; index ++) {
writeControlWord("f", index);
writeControlWord("fnil"); /* TODO: supply correct font style */
writeText(sortedFontTable[index]);
writeText(";");
}
writeEndgroup();
writeLineBreak();
/* write color table */
if (colorCount > 1) {
Color[] sortedColorTable = new Color[colorCount];
Enumeration colors = colorTable.keys();
Color color;
while(colors.hasMoreElements()) {
color = (Color)colors.nextElement();
Integer num = (Integer)(colorTable.get(color));
sortedColorTable[num.intValue()] = color;
}
writeBegingroup();
writeControlWord("colortbl");
for(index = 0; index < colorCount; index ++) {
color = sortedColorTable[index];
if (color != null) {
writeControlWord("red", color.getRed());
writeControlWord("green", color.getGreen());
writeControlWord("blue", color.getBlue());
}
writeRawString(";");
}
writeEndgroup();
writeLineBreak();
}
/* write the style sheet */
if (styleCount > 1) {
writeBegingroup();
writeControlWord("stylesheet");
Enumeration styles = styleTable.keys();
while(styles.hasMoreElements()) {
Style style = (Style)styles.nextElement();
int styleNumber = ((Integer)styleTable.get(style)).intValue();
writeBegingroup();
String styleType = (String)style.getAttribute(Constants.StyleType);
if (styleType == null)
styleType = Constants.STParagraph;
if (styleType.equals(Constants.STCharacter)) {
writeControlWord("*");
writeControlWord("cs", styleNumber);
} else if(styleType.equals(Constants.STSection)) {
writeControlWord("*");
writeControlWord("ds", styleNumber);
} else {
writeControlWord("s", styleNumber);
}
AttributeSet basis = style.getResolveParent();
MutableAttributeSet goat;
if (basis == null) {
goat = new SimpleAttributeSet();
} else {
goat = new SimpleAttributeSet(basis);
}
updateSectionAttributes(goat, style, false);
updateParagraphAttributes(goat, style, false);
updateCharacterAttributes(goat, style, false);
basis = style.getResolveParent();
if (basis != null && basis instanceof Style) {
Integer basedOn = (Integer)styleTable.get(basis);
if (basedOn != null) {
writeControlWord("sbasedon", basedOn.intValue());
}
}
Style nextStyle = (Style)style.getAttribute(Constants.StyleNext);
if (nextStyle != null) {
Integer nextNum = (Integer)styleTable.get(nextStyle);
if (nextNum != null) {
writeControlWord("snext", nextNum.intValue());
}
}
Boolean hidden = (Boolean)style.getAttribute(Constants.StyleHidden);
if (hidden != null && hidden.booleanValue())
writeControlWord("shidden");
Boolean additive = (Boolean)style.getAttribute(Constants.StyleAdditive);
if (additive != null && additive.booleanValue())
writeControlWord("additive");
writeText(style.getName());
writeText(";");
writeEndgroup();
}
writeEndgroup();
writeLineBreak();
}
outputAttributes = new SimpleAttributeSet();
|
public void | writeRTFTrailer()
writeEndgroup();
writeLineBreak();
|
public void | writeRawString(java.lang.String str)
int strlen = str.length();
for (int offset = 0; offset < strlen; offset ++)
outputStream.write((int)str.charAt(offset));
|
public void | writeText(javax.swing.text.Segment s)
int pos, end;
char[] array;
pos = s.offset;
end = pos + s.count;
array = s.array;
for( ; pos < end; pos ++)
writeCharacter(array[pos]);
|
public void | writeText(java.lang.String s)
int pos, end;
pos = 0;
end = s.length();
for( ; pos < end; pos ++)
writeCharacter(s.charAt(pos));
|
public void | writeTextElement(javax.swing.text.Element el)
updateCharacterAttributes(outputAttributes, el.getAttributes(), true);
if (el.isLeaf()) {
try {
el.getDocument().getText(el.getStartOffset(),
el.getEndOffset() - el.getStartOffset(),
this.workingSegment);
} catch (BadLocationException ble) {
/* TODO is this the correct error to raise? */
ble.printStackTrace();
throw new InternalError(ble.getMessage());
}
writeText(this.workingSegment);
} else {
int sub_count = el.getElementCount();
for(int idx = 0; idx < sub_count; idx ++)
writeTextElement(el.getElement(idx));
}
|