?? rtfgenerator.java
字號:
/* * @(#)RTFGenerator.java 1.13 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package javax.swing.text.rtf;import java.lang.*;import java.util.*;import java.awt.Color;import java.awt.Font;import java.io.OutputStream;import java.io.IOException;import javax.swing.text.*;/** * Generates an RTF output stream (java.io.OutputStream) from rich text * (handed off through a series of LTTextAcceptor calls). Can be used to * generate RTF from any object which knows how to write to a text acceptor * (e.g., LTAttributedText and LTRTFFilter). * * <p>Note that this is a lossy conversion since RTF's model of * text does not exactly correspond with LightText's. * * @see LTAttributedText * @see LTRTFFilter * @see LTTextAcceptor * @see java.io.OutputStream */class RTFGenerator extends Object{ /* These dictionaries map Colors, font names, or Style objects to Integers */ Dictionary colorTable; int colorCount; Dictionary fontTable; int fontCount; Dictionary styleTable; int styleCount; /* where all the text is going */ OutputStream outputStream; boolean afterKeyword; MutableAttributeSet outputAttributes; /* the value of the last \\ucN keyword emitted */ int unicodeCount; /* for efficiency's sake (ha) */ private Segment workingSegment; int[] outputConversion; /** The default color, used for text without an explicit color * attribute. */ static public final Color defaultRTFColor = Color.black; static public final float defaultFontSize = 12f; static public final String defaultFontFamily = "Helvetica"; /* constants so we can avoid allocating objects in inner loops */ /* these should all be final, but javac seems to be a bit buggy */ static protected Integer One, Zero; static protected Boolean False; static protected Float ZeroPointZero; static private Object MagicToken; /* An array of character-keyword pairs. This could be done as a dictionary (and lookup would be quicker), but that would require allocating an object for every character written (slow!). */ static class CharacterKeywordPair { public char character; public String keyword; }; static protected CharacterKeywordPair[] textKeywords; static { One = new Integer(1); Zero = new Integer(0); False = Boolean.valueOf(false); MagicToken = new Object(); ZeroPointZero = new Float(0); Dictionary textKeywordDictionary = RTFReader.textKeywords; Enumeration keys = textKeywordDictionary.keys(); Vector tempPairs = new Vector(); while(keys.hasMoreElements()) { CharacterKeywordPair pair = new CharacterKeywordPair(); pair.keyword = (String)keys.nextElement(); pair.character = ((String)textKeywordDictionary.get(pair.keyword)).charAt(0); tempPairs.addElement(pair); } textKeywords = new CharacterKeywordPair[tempPairs.size()]; tempPairs.copyInto(textKeywords); } static final char[] hexdigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };static public void writeDocument(Document d, OutputStream to) throws IOException{ 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();}public RTFGenerator(OutputStream to){ colorTable = new Hashtable(); colorTable.put(defaultRTFColor, new Integer(0)); colorCount = 1; fontTable = new Hashtable(); fontCount = 0; styleTable = new Hashtable(); /* TODO: put default style in style table */ styleCount = 0; workingSegment = new Segment(); outputStream = to; unicodeCount = 1;}public void examineElement(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 void tallyStyles(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(); }}private Style findStyle(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 Integer findStyleNumber(AttributeSet a, 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 private Object attrDiff(MutableAttributeSet oldAttrs, AttributeSet newAttrs, Object key, 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;}static private boolean equalArraysOK(Object a, 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;} /* Writes a line break to the output file, for ease in debugging */public void writeLineBreak() throws IOException{ writeRawString("\n"); afterKeyword = false;}public void writeRTFHeader() throws IOException{ 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();}void writeDocumentProperties(Document doc) throws IOException{ /* 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 writeRTFTrailer() throws IOException{ writeEndgroup(); writeLineBreak();}protected void checkNumericControlWord(MutableAttributeSet currentAttributes, AttributeSet newAttributes, Object attrName, String controlWord, float dflt, float scale) throws IOException{ 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 void checkControlWord(MutableAttributeSet currentAttributes, AttributeSet newAttributes, RTFAttribute word) throws IOException{ Object parm; if ((parm = attrDiff(currentAttributes, newAttributes, word.swingName(), MagicToken)) != null) { if (parm == MagicToken) parm = null; word.writeValue(parm, this, true); }}protected void checkControlWords(MutableAttributeSet currentAttributes, AttributeSet newAttributes, RTFAttribute words[], int domain) throws IOException{ int wordIndex; int wordCount = words.length; for(wordIndex = 0; wordIndex < wordCount; wordIndex++) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -