/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.render.rtf.rtflib.rtfdoc; /* * This file is part of the RTF library of the FOP project, which was originally * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to * the FOP project. */ import java.io.IOException; import java.io.Writer; import java.util.List; import org.apache.fop.apps.FOPException; /** * <p>Model of an RTF paragraph, which can contain RTF text elements.</p> * * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch), * Andreas Putz (a.putz@skynamics.com), and * Boris Poudérous (boris.pouderous@free.fr).</p> */ public class RtfParagraph extends RtfBookmarkContainerImpl implements IRtfTextContainer, IRtfPageBreakContainer, IRtfHyperLinkContainer, IRtfExternalGraphicContainer, IRtfPageNumberContainer, IRtfPageNumberCitationContainer { private RtfText text; private RtfHyperLink hyperlink; private RtfExternalGraphic externalGraphic; private RtfPageNumber pageNumber; private RtfPageNumberCitation pageNumberCitation; // Above line added by Boris POUDEROUS on 2002/07/09 private boolean keepn; private boolean resetProperties; /* needed for importing Rtf into FrameMaker FrameMaker is not as forgiving as word in rtf thus /pard/par must be written in a page break directly after a table. /pard is probably needed in other places also, this is just a hack to make FrameMaker import Jfor rtf correctly */ private boolean writeForBreak; /** Set of attributes that must be copied at the start of a paragraph */ private static final String[] PARA_ATTRIBUTES = {"intbl"}; /** Create an RTF paragraph as a child of given container with default attributes */ RtfParagraph(IRtfParagraphContainer parent, Writer w) throws IOException { super((RtfContainer)parent, w); } /** Create an RTF paragraph as a child of given container with given attributes */ RtfParagraph(IRtfParagraphContainer parent, Writer w, RtfAttributes attr) throws IOException { super((RtfContainer)parent, w, attr); } /** * Accessor for the paragraph text * @return the paragraph text */ public String getText() { return (text.getText()); } /** Set the keepn attribute for this paragraph */ public void setKeepn() { this.keepn = true; } /** Force reset properties */ public void setResetProperties() { this.resetProperties = true; } /** * IRtfTextContainer requirement: return a copy of our attributes * @return a copy of this paragraphs attributes * @throws FOPException if attributes cannot be cloned */ public RtfAttributes getTextContainerAttributes() throws FOPException { if (attrib == null) { return null; } try { return (RtfAttributes)this.attrib.clone(); } catch (CloneNotSupportedException e) { throw new FOPException(e); } } /** * Overridden to write our attributes before our content * @throws IOException for I/O problems */ protected void writeRtfPrefix() throws IOException { //Reset paragraph properties if needed if (resetProperties) { writeControlWord("pard"); } /* * Original comment said "do not write text attributes here, they are * handled by RtfText." However, the text attributes appear to be * relevant to paragraphs as well. */ writeAttributes(attrib, RtfText.ATTR_NAMES); writeAttributes(attrib, PARA_ATTRIBUTES); // Added by Normand Masse // Write alignment attributes after \intbl for cells if (attrib.isSet("intbl") && mustWriteAttributes()) { writeAttributes(attrib, RtfText.ALIGNMENT); } //Set keepn if needed (Keep paragraph with the next paragraph) if (keepn) { writeControlWord("keepn"); } // start a group for this paragraph and write our own attributes if needed if (mustWriteGroupMark()) { writeGroupMark(true); } if (mustWriteAttributes()) { // writeAttributes(m_attrib, new String [] {"cs"}); // Added by Normand Masse // If \intbl then attributes have already been written (see higher in method) if (!attrib.isSet("intbl")) { writeAttributes(attrib, RtfText.ALIGNMENT); } //this line added by Chris Scott, Westinghouse writeAttributes(attrib, RtfText.BORDER); writeAttributes(attrib, RtfText.INDENT); writeAttributes(attrib, RtfText.TABS); if (writeForBreak) { writeControlWord("pard\\par"); } } } /** * Overridden to close paragraph * @throws IOException for I/O problems */ protected void writeRtfSuffix() throws IOException { // sometimes the end of paragraph mark must be suppressed in table cells boolean writeMark = true; if (parent instanceof RtfTableCell) { writeMark = ((RtfTableCell)parent).paragraphNeedsPar(this); } if (writeMark) { writeControlWord("par"); } if (mustWriteGroupMark()) { writeGroupMark(false); } } /** * Close current text run if any and start a new one with default attributes * @param str if not null, added to the RtfText created * @return the new RtfText object * @throws IOException for I/O problems */ public RtfText newText(String str) throws IOException { return newText(str, null); } /** * Close current text run if any and start a new one * @param str if not null, added to the RtfText created * @param attr attributes of the text * @return the new RtfText object * @throws IOException for I/O problems */ public RtfText newText(String str, RtfAttributes attr) throws IOException { closeAll(); text = new RtfText(this, writer, str, attr); return text; } /** * add a page break * @throws IOException for I/O problems */ public void newPageBreak() throws IOException { writeForBreak = true; new RtfPageBreak(this, writer); } /** * add a line break * @throws IOException for I/O problems */ public void newLineBreak() throws IOException { new RtfLineBreak(this, writer); } /** * Add a page number * @return new RtfPageNumber object * @throws IOException for I/O problems */ public RtfPageNumber newPageNumber()throws IOException { pageNumber = new RtfPageNumber(this, writer); return pageNumber; } /** * Added by Boris POUDEROUS on 2002/07/09 * @param id string containing the citation text * @return the new RtfPageNumberCitation object * @throws IOException for I/O problems */ public RtfPageNumberCitation newPageNumberCitation(String id) throws IOException { pageNumberCitation = new RtfPageNumberCitation(this, writer, id); return pageNumberCitation; } /** * Creates a new hyperlink. * @param str string containing the hyperlink text * @param attr attributes of new hyperlink * @return the new RtfHyperLink object * @throws IOException for I/O problems */ public RtfHyperLink newHyperLink(String str, RtfAttributes attr) throws IOException { hyperlink = new RtfHyperLink(this, writer, str, attr); return hyperlink; } /** * Start a new external graphic after closing all other elements * @return the new RtfExternalGraphic * @throws IOException for I/O problems */ public RtfExternalGraphic newImage() throws IOException { closeAll(); externalGraphic = new RtfExternalGraphic(this, writer); return externalGraphic; } private void closeCurrentText() throws IOException { if (text != null) { text.close(); } } private void closeCurrentHyperLink() throws IOException { if (hyperlink != null) { hyperlink.close(); } } private void closeAll() throws IOException { closeCurrentText(); closeCurrentHyperLink(); } /** * Depending on RtfOptions, do not emit any RTF for empty paragraphs * @return true if RTF should be written */ protected boolean okToWriteRtf() { boolean result = super.okToWriteRtf(); if (parent.getOptions().ignoreEmptyParagraphs() && getChildCount() == 0) { // TODO should test that this is the last RtfParagraph in the cell instead // of simply testing for last child?? result = false; } return result; } /** true if we must write our own (non-text) attributes in the RTF */ private boolean mustWriteAttributes() { boolean writeAttributes = false; final int children = getChildCount(); if (children > 0) { final List childList = getChildren(); for (int i = 0; i < children; i++) { final RtfElement el = (RtfElement) childList.get(i); if (!el.isEmpty()) { if (el.getClass() == RtfText.class) { boolean tmp = ((RtfText) el).isNbsp(); if (!tmp) { writeAttributes = true; break; } } else { writeAttributes = true; break; } } } } return writeAttributes; } /** true if we must write a group mark around this paragraph * TODO is this correct, study interaction with mustWriteAttributes() * <-- On implementation i have noticed if the groupmark set, the * format attributes are only for this content, i think this * implementation is ok */ private boolean mustWriteGroupMark() { return getChildCount() > 0; } /** * accessor for text attributes * @return attributes of the text */ public RtfAttributes getTextAttributes() { if (text == null) { return null; } return text.getTextAttributes(); } }