001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: RtfElement.java 426576 2006-07-28 15:44:37Z jeremias $ */
019:
020: package org.apache.fop.render.rtf.rtflib.rtfdoc;
021:
022: /*
023: * This file is part of the RTF library of the FOP project, which was originally
024: * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other
025: * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
026: * the FOP project.
027: */
028:
029: import java.io.Writer;
030: import java.io.IOException;
031: import java.util.Iterator;
032:
033: //import org.apache.fop.render.rtf.rtflib.jfor.main.JForVersionInfo;
034:
035: /** Base class for all elements of an RTF file.
036: * @author Bertrand Delacretaz bdelacretaz@codeconsult.ch
037: * @author Andreas Putz a.putz@skynamics.com
038: */
039: public abstract class RtfElement {
040: /** Writer to be used */
041: protected final Writer writer;
042: /** parent element */
043: protected final RtfContainer parent;
044: /** attributes of the element */
045: protected final RtfAttributes attrib;
046: private boolean written;
047: private boolean closed;
048: private final int id;
049: private static int idCounter;
050:
051: /** Create an RTF element as a child of given container */
052: RtfElement(RtfContainer parent, Writer w) throws IOException {
053: this (parent, w, null);
054: }
055:
056: /** Create an RTF element as a child of given container with given attributes */
057: RtfElement(RtfContainer parent, Writer w, RtfAttributes attr)
058: throws IOException {
059:
060: id = idCounter++;
061: this .parent = parent;
062: attrib = (attr != null ? attr : new RtfAttributes());
063: if (this .parent != null) {
064: this .parent.addChild(this );
065: }
066: writer = w;
067: written = false;
068: }
069:
070: /**
071: * Does nothing, meant to allow elements to write themselves without waiting
072: * for write(), but not implemented yet
073: * @throws IOException for I/O problems
074: */
075: public final void close() throws IOException {
076: closed = true;
077: }
078:
079: /**
080: * Write the RTF code of this element to our Writer
081: * @throws IOException for I/O problems
082: */
083: public final void writeRtf() throws IOException {
084: if (!written) {
085: written = true;
086: if (okToWriteRtf()) {
087: writeRtfPrefix();
088: writeRtfContent();
089: writeRtfSuffix();
090: }
091: }
092: }
093:
094: /**
095: * Starts a new line in the RTF file being written. This is only to format
096: * the RTF file itself (for easier debugging), not its content.
097: * @throws IOException in case of an I/O problem
098: */
099: public void newLine() throws IOException {
100: writer.write("\n");
101: }
102:
103: /**
104: * Write an RTF control word to our Writer
105: * @param word RTF control word to write
106: * @throws IOException for I/O problems
107: */
108: protected final void writeControlWord(String word)
109: throws IOException {
110: writer.write('\\');
111: writer.write(word);
112: writer.write(' ');
113: }
114:
115: /**
116: * Write an RTF control word to our Writer, preceeded by a star '*'
117: * meaning "ignore this if you don't know what it means"
118: * @param word RTF control word to write
119: * @throws IOException for I/O problems
120: */
121: protected final void writeStarControlWord(String word)
122: throws IOException {
123: writer.write("\\*\\");
124: writer.write(word);
125: writer.write(' ');
126: }
127:
128: /**
129: * Same as writeStarControlWord(String word), except with no space behind it
130: * @param word RTF control word to write
131: * @throws IOException for I/O problems
132: */
133: protected final void writeStarControlWordNS(String word)
134: throws IOException {
135: writer.write("\\*\\");
136: writer.write(word);
137: }
138:
139: /**
140: * Write rtf control word without the space behind it
141: * @param word RTF control word to write
142: * @throws IOException for I/O problems
143: */
144: protected final void writeControlWordNS(String word)
145: throws IOException {
146: writer.write('\\');
147: writer.write(word);
148: }
149:
150: /**
151: * Called before writeRtfContent()
152: * @throws IOException for I/O problems
153: */
154: protected void writeRtfPrefix() throws IOException {
155: }
156:
157: /**
158: * Must be implemented to write RTF content to m_writer
159: * @throws IOException for I/O problems
160: */
161: protected abstract void writeRtfContent() throws IOException;
162:
163: /**
164: * Called after writeRtfContent()
165: * @throws IOException for I/O problems
166: */
167: protected void writeRtfSuffix() throws IOException {
168: }
169:
170: /**
171: * Write a start or end group mark
172: * @param isStart set to true if this is a start mark
173: * @throws IOException for I/O problems
174: */
175: protected final void writeGroupMark(boolean isStart)
176: throws IOException {
177: writer.write(isStart ? "{" : "}");
178: }
179:
180: /**
181: * Write given attribute values to our Writer
182: * @param attr RtfAttributes to be written
183: * @param nameList if given, only attribute names from this list are considered
184: * @throws IOException for I/O problems
185: */
186: protected void writeAttributes(RtfAttributes attr, String[] nameList)
187: throws IOException {
188: if (attr == null) {
189: return;
190: }
191:
192: if (nameList != null) {
193: // process only given attribute names
194: for (int i = 0; i < nameList.length; i++) {
195: final String name = nameList[i];
196: if (attr.isSet(name)) {
197: writeOneAttribute(name, attr.getValue(name));
198: }
199: }
200: } else {
201: // process all defined attributes
202: for (Iterator it = attr.nameIterator(); it.hasNext();) {
203: final String name = (String) it.next();
204: if (attr.isSet(name)) {
205: writeOneAttribute(name, attr.getValue(name));
206: }
207: }
208: }
209: }
210:
211: /**
212: * Write one attribute to our Writer
213: * @param name name of attribute to write
214: * @param value value of attribute to be written
215: * @throws IOException for I/O problems
216: */
217: protected void writeOneAttribute(String name, Object value)
218: throws IOException {
219: String cw = name;
220: if (value instanceof Integer) {
221: // attribute has integer value, must write control word + value
222: cw += value;
223: } else if (value instanceof String) {
224: cw += value;
225: } else if (value instanceof RtfAttributes) {
226: writeControlWord(cw);
227: writeAttributes((RtfAttributes) value, null);
228: return;
229: }
230: writeControlWord(cw);
231: }
232:
233: /**
234: * Write one attribute to our Writer without a space
235: * @param name name of attribute to write
236: * @param value value of attribute to be written
237: * @throws IOException for I/O problems
238: */
239: protected void writeOneAttributeNS(String name, Object value)
240: throws IOException {
241: String cw = name;
242: if (value instanceof Integer) {
243: // attribute has integer value, must write control word + value
244: cw += value;
245: } else if (value instanceof String) {
246: cw += value;
247: } else if (value instanceof RtfAttributes) {
248: writeControlWord(cw);
249: writeAttributes((RtfAttributes) value, null);
250: return;
251: }
252: writeControlWordNS(cw);
253: }
254:
255: /**
256: * can be overridden to suppress all RTF output
257: * @return true if this object can be written into the RTF
258: */
259: protected boolean okToWriteRtf() {
260: return true;
261: }
262:
263: /** debugging to given PrintWriter */
264: void dump(Writer w, int indent) throws IOException {
265: for (int i = 0; i < indent; i++) {
266: w.write(' ');
267: }
268: w.write(this .toString());
269: w.write('\n');
270: w.flush();
271: }
272:
273: /**
274: * minimal debugging display
275: * @return String representation of object
276: */
277: public String toString() {
278: return (this == null) ? "null" : (this .getClass().getName()
279: + " #" + id);
280: }
281:
282: /** true if close() has been called */
283: boolean isClosed() {
284: return closed;
285: }
286:
287: /** access our RtfFile, which is always the topmost parent */
288: RtfFile getRtfFile() {
289: // go up the chain of parents until we find the topmost one
290: RtfElement result = this ;
291: while (result.parent != null) {
292: result = result.parent;
293: }
294:
295: // topmost parent must be an RtfFile
296: // a ClassCastException here would mean that the parent-child structure is not as expected
297: return (RtfFile) result;
298: }
299:
300: /** find the first parent where c.isAssignableFrom(parent.getClass()) is true
301: * @return null if not found
302: */
303: RtfElement getParentOfClass(Class c) {
304: RtfElement result = null;
305: RtfElement current = this ;
306: while (current.parent != null) {
307: current = current.parent;
308: if (c.isAssignableFrom(current.getClass())) {
309: result = current;
310: break;
311: }
312: }
313: return result;
314: }
315:
316: /**
317: * @return true if this element would generate no "useful" RTF content
318: */
319: public abstract boolean isEmpty();
320:
321: /**
322: * Make a visible entry in the RTF for an exception
323: * @param ie Exception to flag
324: * @throws IOException for I/O problems
325: */
326: protected void writeExceptionInRtf(Exception ie) throws IOException {
327: writeGroupMark(true);
328: writeControlWord("par");
329:
330: // make the exception message stand out so that the problem is visible
331: writeControlWord("fs48");
332: // RtfStringConverter.getInstance().writeRtfString(m_writer,
333: // JForVersionInfo.getShortVersionInfo() + ": ");
334: RtfStringConverter.getInstance().writeRtfString(writer,
335: ie.getClass().getName());
336:
337: writeControlWord("fs20");
338: RtfStringConverter.getInstance().writeRtfString(writer,
339: " " + ie.toString());
340:
341: writeControlWord("par");
342: writeGroupMark(false);
343: }
344:
345: /**
346: * Added by Normand Masse
347: * Used for attribute inheritance
348: * @return RtfAttributes
349: */
350: public RtfAttributes getRtfAttributes() {
351: return attrib;
352: }
353: }
|