| /* |
| * 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; |
| |
| // Java |
| import java.awt.Dimension; |
| import java.awt.Rectangle; |
| import java.awt.geom.Point2D; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.w3c.dom.Document; |
| |
| import org.xml.sax.SAXException; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.xmlgraphics.image.loader.Image; |
| import org.apache.xmlgraphics.image.loader.ImageException; |
| import org.apache.xmlgraphics.image.loader.ImageFlavor; |
| import org.apache.xmlgraphics.image.loader.ImageInfo; |
| import org.apache.xmlgraphics.image.loader.ImageManager; |
| import org.apache.xmlgraphics.image.loader.ImageSessionContext; |
| import org.apache.xmlgraphics.image.loader.ImageSize; |
| import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; |
| import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; |
| import org.apache.xmlgraphics.image.loader.util.ImageUtil; |
| |
| import org.apache.fop.ResourceEventProducer; |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.datatypes.LengthBase; |
| import org.apache.fop.datatypes.PercentBaseContext; |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.FOEventHandler; |
| import org.apache.fop.fo.FONode; |
| import org.apache.fop.fo.FOText; |
| import org.apache.fop.fo.FObj; |
| import org.apache.fop.fo.XMLObj; |
| import org.apache.fop.fo.flow.AbstractGraphics; |
| import org.apache.fop.fo.flow.BasicLink; |
| import org.apache.fop.fo.flow.Block; |
| import org.apache.fop.fo.flow.BlockContainer; |
| import org.apache.fop.fo.flow.Character; |
| import org.apache.fop.fo.flow.ExternalGraphic; |
| import org.apache.fop.fo.flow.Footnote; |
| import org.apache.fop.fo.flow.FootnoteBody; |
| import org.apache.fop.fo.flow.Inline; |
| import org.apache.fop.fo.flow.InstreamForeignObject; |
| import org.apache.fop.fo.flow.Leader; |
| import org.apache.fop.fo.flow.ListBlock; |
| import org.apache.fop.fo.flow.ListItem; |
| import org.apache.fop.fo.flow.ListItemBody; |
| import org.apache.fop.fo.flow.ListItemLabel; |
| import org.apache.fop.fo.flow.PageNumber; |
| import org.apache.fop.fo.flow.PageNumberCitation; |
| import org.apache.fop.fo.flow.PageNumberCitationLast; |
| import org.apache.fop.fo.flow.table.Table; |
| import org.apache.fop.fo.flow.table.TableBody; |
| import org.apache.fop.fo.flow.table.TableCell; |
| import org.apache.fop.fo.flow.table.TableColumn; |
| import org.apache.fop.fo.flow.table.TableFooter; |
| import org.apache.fop.fo.flow.table.TableHeader; |
| import org.apache.fop.fo.flow.table.TablePart; |
| import org.apache.fop.fo.flow.table.TableRow; |
| import org.apache.fop.fo.pagination.Flow; |
| import org.apache.fop.fo.pagination.PageSequence; |
| import org.apache.fop.fo.pagination.PageSequenceMaster; |
| import org.apache.fop.fo.pagination.Region; |
| import org.apache.fop.fo.pagination.SimplePageMaster; |
| import org.apache.fop.fo.pagination.StaticContent; |
| import org.apache.fop.fo.properties.CommonBorderPaddingBackground; |
| import org.apache.fop.fo.properties.EnumLength; |
| import org.apache.fop.fonts.FontSetup; |
| import org.apache.fop.layoutmgr.inline.ImageLayout; |
| import org.apache.fop.layoutmgr.table.ColumnSetup; |
| import org.apache.fop.render.DefaultFontResolver; |
| import org.apache.fop.render.RendererEventProducer; |
| import org.apache.fop.render.rtf.rtflib.exceptions.RtfException; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfBeforeContainer; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfListContainer; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTableContainer; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTextrunContainer; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAfter; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfBefore; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfDocumentArea; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfElement; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFile; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFootnote; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfHyperLink; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfSection; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableCell; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun; |
| import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel; |
| import org.apache.fop.render.rtf.rtflib.tools.BuilderContext; |
| import org.apache.fop.render.rtf.rtflib.tools.PercentContext; |
| import org.apache.fop.render.rtf.rtflib.tools.TableContext; |
| |
| /** |
| * RTF Handler: generates RTF output using the structure events from |
| * the FO Tree sent to this structure handler. |
| */ |
| public class RTFHandler extends FOEventHandler { |
| |
| private RtfFile rtfFile; |
| private final OutputStream os; |
| private static Log log = LogFactory.getLog(RTFHandler.class); |
| private RtfSection sect; |
| private RtfDocumentArea docArea; |
| private boolean bDefer; //true, if each called handler shall be |
| //processed at later time. |
| private boolean bPrevHeaderSpecified = false; //true, if there has been a |
| //header in any page-sequence |
| private boolean bPrevFooterSpecified = false; //true, if there has been a |
| //footer in any page-sequence |
| private boolean bHeaderSpecified = false; //true, if there is a header |
| //in current page-sequence |
| private boolean bFooterSpecified = false; //true, if there is a footer |
| //in current page-sequence |
| private BuilderContext builderContext = new BuilderContext(null); |
| |
| private SimplePageMaster pagemaster; |
| |
| private int nestedTableDepth = 1; |
| |
| private PercentContext percentManager = new PercentContext(); |
| |
| /** |
| * Creates a new RTF structure handler. |
| * @param userAgent the FOUserAgent for this process |
| * @param os OutputStream to write to |
| */ |
| public RTFHandler(FOUserAgent userAgent, OutputStream os) { |
| super(userAgent); |
| this.os = os; |
| bDefer = true; |
| |
| boolean base14Kerning = false; |
| FontSetup.setup(fontInfo, null, new DefaultFontResolver(userAgent), base14Kerning); |
| } |
| |
| /** |
| * Central exception handler for I/O exceptions. |
| * @param ioe IOException to handle |
| */ |
| protected void handleIOTrouble(IOException ioe) { |
| RendererEventProducer eventProducer = RendererEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.ioError(this, ioe); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startDocument() throws SAXException { |
| // TODO sections should be created |
| try { |
| rtfFile = new RtfFile(new OutputStreamWriter(os)); |
| docArea = rtfFile.startDocumentArea(); |
| } catch (IOException ioe) { |
| // TODO could we throw Exception in all FOEventHandler events? |
| throw new SAXException(ioe); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endDocument() throws SAXException { |
| try { |
| rtfFile.flush(); |
| } catch (IOException ioe) { |
| // TODO could we throw Exception in all FOEventHandler events? |
| throw new SAXException(ioe); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startPageSequence(PageSequence pageSeq) { |
| try { |
| //This is needed for region handling |
| if (this.pagemaster == null) { |
| String reference = pageSeq.getMasterReference(); |
| this.pagemaster |
| = pageSeq.getRoot().getLayoutMasterSet().getSimplePageMaster(reference); |
| if (this.pagemaster == null) { |
| RTFEventProducer eventProducer = RTFEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.onlySPMSupported(this, reference, pageSeq.getLocator()); |
| PageSequenceMaster master |
| = pageSeq.getRoot().getLayoutMasterSet().getPageSequenceMaster(reference); |
| this.pagemaster = master.getNextSimplePageMaster( |
| false, false, false, false); |
| } |
| } |
| |
| if (bDefer) { |
| return; |
| } |
| |
| sect = docArea.newSection(); |
| |
| //read page size and margins, if specified |
| //only simple-page-master supported, so pagemaster may be null |
| if (pagemaster != null) { |
| sect.getRtfAttributes().set( |
| PageAttributesConverter.convertPageAttributes( |
| pagemaster)); |
| } else { |
| RTFEventProducer eventProducer = RTFEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.noSPMFound(this, pageSeq.getLocator()); |
| } |
| |
| builderContext.pushContainer(sect); |
| |
| //Calculate usable page width for this flow |
| int useAblePageWidth = pagemaster.getPageWidth().getValue() |
| - pagemaster.getCommonMarginBlock().marginLeft.getValue() |
| - pagemaster.getCommonMarginBlock().marginRight.getValue() |
| - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_LEFT).intValue() |
| - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_RIGHT).intValue(); |
| percentManager.setDimension(pageSeq, useAblePageWidth); |
| |
| bHeaderSpecified = false; |
| bFooterSpecified = false; |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endPageSequence(PageSequence pageSeq) { |
| if (bDefer) { |
| //If endBlock was called while SAX parsing, and the passed FO is Block |
| //nested within another Block, stop deferring. |
| //Now process all deferred FOs. |
| bDefer = false; |
| recurseFONode(pageSeq); |
| this.pagemaster = null; |
| bDefer = true; |
| |
| return; |
| } else { |
| builderContext.popContainer(); |
| this.pagemaster = null; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startFlow(Flow fl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| log.debug("starting flow: " + fl.getFlowName()); |
| boolean handled = false; |
| Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY); |
| Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE); |
| Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER); |
| if (fl.getFlowName().equals(regionBody.getRegionName())) { |
| // if there is no header in current page-sequence but there has been |
| // a header in a previous page-sequence, insert an empty header. |
| if (bPrevHeaderSpecified && !bHeaderSpecified) { |
| RtfAttributes attr = new RtfAttributes(); |
| attr.set(RtfBefore.HEADER); |
| |
| final IRtfBeforeContainer contBefore |
| = (IRtfBeforeContainer)builderContext.getContainer |
| (IRtfBeforeContainer.class, true, this); |
| contBefore.newBefore(attr); |
| } |
| |
| // if there is no footer in current page-sequence but there has been |
| // a footer in a previous page-sequence, insert an empty footer. |
| if (bPrevFooterSpecified && !bFooterSpecified) { |
| RtfAttributes attr = new RtfAttributes(); |
| attr.set(RtfAfter.FOOTER); |
| |
| final IRtfAfterContainer contAfter |
| = (IRtfAfterContainer)builderContext.getContainer |
| (IRtfAfterContainer.class, true, this); |
| contAfter.newAfter(attr); |
| } |
| handled = true; |
| } else if (regionBefore != null |
| && fl.getFlowName().equals(regionBefore.getRegionName())) { |
| bHeaderSpecified = true; |
| bPrevHeaderSpecified = true; |
| |
| final IRtfBeforeContainer c |
| = (IRtfBeforeContainer)builderContext.getContainer( |
| IRtfBeforeContainer.class, |
| true, this); |
| |
| RtfAttributes beforeAttributes = ((RtfElement)c).getRtfAttributes(); |
| if (beforeAttributes == null) { |
| beforeAttributes = new RtfAttributes(); |
| } |
| beforeAttributes.set(RtfBefore.HEADER); |
| |
| RtfBefore before = c.newBefore(beforeAttributes); |
| builderContext.pushContainer(before); |
| handled = true; |
| } else if (regionAfter != null |
| && fl.getFlowName().equals(regionAfter.getRegionName())) { |
| bFooterSpecified = true; |
| bPrevFooterSpecified = true; |
| |
| final IRtfAfterContainer c |
| = (IRtfAfterContainer)builderContext.getContainer( |
| IRtfAfterContainer.class, |
| true, this); |
| |
| RtfAttributes afterAttributes = ((RtfElement)c).getRtfAttributes(); |
| if (afterAttributes == null) { |
| afterAttributes = new RtfAttributes(); |
| } |
| |
| afterAttributes.set(RtfAfter.FOOTER); |
| |
| RtfAfter after = c.newAfter(afterAttributes); |
| builderContext.pushContainer(after); |
| handled = true; |
| } |
| if (!handled) { |
| log.warn("A " + fl.getLocalName() + " has been skipped: " + fl.getFlowName()); |
| } |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startFlow: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endFlow(Flow fl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY); |
| Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE); |
| Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER); |
| if (fl.getFlowName().equals(regionBody.getRegionName())) { |
| //just do nothing |
| } else if (regionBefore != null |
| && fl.getFlowName().equals(regionBefore.getRegionName())) { |
| builderContext.popContainer(); |
| } else if (regionAfter != null |
| && fl.getFlowName().equals(regionAfter.getRegionName())) { |
| builderContext.popContainer(); |
| } |
| } catch (Exception e) { |
| log.error("endFlow: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startBlock(Block bl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfAttributes rtfAttr |
| = TextAttributesConverter.convertAttributes(bl); |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, |
| true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addParagraphBreak(); |
| textrun.pushBlockAttributes(rtfAttr); |
| textrun.addBookmark(bl.getId()); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startBlock: " + e.getMessage()); |
| throw new RuntimeException("Exception: " + e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endBlock(Block bl) { |
| |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, |
| true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addParagraphBreak(); |
| int breakValue = toRtfBreakValue(bl.getBreakAfter()); |
| textrun.popBlockAttributes(breakValue); |
| |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startBlock:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startBlockContainer(BlockContainer blc) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfAttributes rtfAttr |
| = TextAttributesConverter.convertBlockContainerAttributes(blc); |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, |
| true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addParagraphBreak(); |
| textrun.pushBlockAttributes(rtfAttr); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startBlock: " + e.getMessage()); |
| throw new RuntimeException("Exception: " + e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endBlockContainer(BlockContainer bl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, |
| true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addParagraphBreak(); |
| int breakValue = toRtfBreakValue(bl.getBreakAfter()); |
| textrun.popBlockAttributes(breakValue); |
| |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startBlock:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| private int toRtfBreakValue(int foBreakValue) { |
| switch (foBreakValue) { |
| case Constants.EN_PAGE: |
| return RtfTextrun.BREAK_PAGE; |
| case Constants.EN_EVEN_PAGE: |
| return RtfTextrun.BREAK_EVEN_PAGE; |
| case Constants.EN_ODD_PAGE: |
| return RtfTextrun.BREAK_ODD_PAGE; |
| case Constants.EN_COLUMN: |
| return RtfTextrun.BREAK_COLUMN; |
| default: |
| return RtfTextrun.BREAK_NONE; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startTable(Table tbl) { |
| if (bDefer) { |
| return; |
| } |
| |
| // create an RtfTable in the current table container |
| TableContext tableContext = new TableContext(builderContext); |
| |
| try { |
| final IRtfTableContainer tc |
| = (IRtfTableContainer)builderContext.getContainer( |
| IRtfTableContainer.class, true, null); |
| |
| RtfAttributes atts |
| = TableAttributesConverter.convertTableAttributes(tbl); |
| |
| RtfTable table = tc.newTable(atts, tableContext); |
| table.setNestedTableDepth(nestedTableDepth); |
| nestedTableDepth++; |
| |
| CommonBorderPaddingBackground border = tbl.getCommonBorderPaddingBackground(); |
| RtfAttributes borderAttributes = new RtfAttributes(); |
| |
| BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.BEFORE, |
| borderAttributes, ITableAttributes.CELL_BORDER_TOP); |
| BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.AFTER, |
| borderAttributes, ITableAttributes.CELL_BORDER_BOTTOM); |
| BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.START, |
| borderAttributes, ITableAttributes.CELL_BORDER_LEFT); |
| BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.END, |
| borderAttributes, ITableAttributes.CELL_BORDER_RIGHT); |
| |
| table.setBorderAttributes(borderAttributes); |
| |
| builderContext.pushContainer(table); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startTable:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| |
| builderContext.pushTableContext(tableContext); |
| } |
| |
| /** {@inheritDoc} */ |
| public void endTable(Table tbl) { |
| if (bDefer) { |
| return; |
| } |
| |
| nestedTableDepth--; |
| builderContext.popTableContext(); |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startColumn(TableColumn tc) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| int iWidth = tc.getColumnWidth().getValue(percentManager); |
| percentManager.setDimension(tc, iWidth); |
| |
| //convert to twips |
| Float width = new Float(FoUnitsConverter.getInstance().convertMptToTwips(iWidth)); |
| builderContext.getTableContext().setNextColumnWidth(width); |
| builderContext.getTableContext().setNextColumnRowSpanning( |
| new Integer(0), null); |
| builderContext.getTableContext().setNextFirstSpanningCol(false); |
| } catch (Exception e) { |
| log.error("startColumn: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endColumn(TableColumn tc) { |
| if (bDefer) { |
| return; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startHeader(TableHeader header) { |
| startPart(header); |
| } |
| |
| /** {@inheritDoc} */ |
| public void endHeader(TableHeader header) { |
| endPart(header); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startFooter(TableFooter footer) { |
| startPart(footer); |
| } |
| |
| /** {@inheritDoc} */ |
| public void endFooter(TableFooter footer) { |
| endPart(footer); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startInline(Inline inl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfAttributes rtfAttr |
| = TextAttributesConverter.convertCharacterAttributes(inl); |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| textrun.pushInlineAttributes(rtfAttr); |
| textrun.addBookmark(inl.getId()); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (FOPException fe) { |
| log.error("startInline:" + fe.getMessage()); |
| throw new RuntimeException(fe.getMessage()); |
| } catch (Exception e) { |
| log.error("startInline:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endInline(Inline inl) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| textrun.popInlineAttributes(); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startInline:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| private void startPart(TablePart part) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfAttributes atts = TableAttributesConverter.convertTablePartAttributes(part); |
| |
| RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this); |
| tbl.setHeaderAttribs(atts); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startPart: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| private void endPart(TablePart tb) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this); |
| tbl.setHeaderAttribs(null); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("endPart: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void startBody(TableBody body) { |
| startPart(body); |
| } |
| |
| /** {@inheritDoc} */ |
| public void endBody(TableBody body) { |
| endPart(body); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void startRow(TableRow tr) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| // create an RtfTableRow in the current RtfTable |
| final RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, |
| true, null); |
| |
| RtfAttributes atts = TableAttributesConverter.convertRowAttributes(tr, |
| tbl.getHeaderAttribs()); |
| |
| if (tr.getParent() instanceof TableHeader) { |
| atts.set(ITableAttributes.ATTR_HEADER); |
| } |
| |
| builderContext.pushContainer(tbl.newTableRow(atts)); |
| |
| // reset column iteration index to correctly access column widths |
| builderContext.getTableContext().selectFirstColumn(); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startRow: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endRow(TableRow tr) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| TableContext tctx = builderContext.getTableContext(); |
| final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class, |
| true, null); |
| |
| //while the current column is in row-spanning, act as if |
| //a vertical merged cell would have been specified. |
| while (tctx.getNumberOfColumns() > tctx.getColumnIndex() |
| && tctx.getColumnRowSpanningNumber().intValue() > 0) { |
| RtfTableCell vCell = row.newTableCellMergedVertically( |
| (int)tctx.getColumnWidth(), |
| tctx.getColumnRowSpanningAttrs()); |
| |
| if (!tctx.getFirstSpanningCol()) { |
| vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS); |
| } |
| |
| tctx.selectNextColumn(); |
| } |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("endRow: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| |
| |
| builderContext.popContainer(); |
| builderContext.getTableContext().decreaseRowSpannings(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startCell(TableCell tc) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| TableContext tctx = builderContext.getTableContext(); |
| final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class, |
| true, null); |
| |
| int numberRowsSpanned = tc.getNumberRowsSpanned(); |
| int numberColumnsSpanned = tc.getNumberColumnsSpanned(); |
| |
| //while the current column is in row-spanning, act as if |
| //a vertical merged cell would have been specified. |
| while (tctx.getNumberOfColumns() > tctx.getColumnIndex() |
| && tctx.getColumnRowSpanningNumber().intValue() > 0) { |
| RtfTableCell vCell = row.newTableCellMergedVertically( |
| (int)tctx.getColumnWidth(), |
| tctx.getColumnRowSpanningAttrs()); |
| |
| if (!tctx.getFirstSpanningCol()) { |
| vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS); |
| } |
| |
| tctx.selectNextColumn(); |
| } |
| |
| //get the width of the currently started cell |
| float width = tctx.getColumnWidth(); |
| |
| // create an RtfTableCell in the current RtfTableRow |
| RtfAttributes atts = TableAttributesConverter.convertCellAttributes(tc); |
| RtfTableCell cell = row.newTableCell((int)width, atts); |
| |
| //process number-rows-spanned attribute |
| if (numberRowsSpanned > 1) { |
| // Start vertical merge |
| cell.setVMerge(RtfTableCell.MERGE_START); |
| |
| // set the number of rows spanned |
| tctx.setCurrentColumnRowSpanning(new Integer(numberRowsSpanned), |
| cell.getRtfAttributes()); |
| } else { |
| tctx.setCurrentColumnRowSpanning( |
| new Integer(numberRowsSpanned), null); |
| } |
| |
| //process number-columns-spanned attribute |
| if (numberColumnsSpanned > 0) { |
| // Get the number of columns spanned |
| tctx.setCurrentFirstSpanningCol(true); |
| |
| // We widthdraw one cell because the first cell is already created |
| // (it's the current cell) ! |
| for (int i = 0; i < numberColumnsSpanned - 1; ++i) { |
| tctx.selectNextColumn(); |
| |
| //aggregate width for further elements |
| width += tctx.getColumnWidth(); |
| tctx.setCurrentFirstSpanningCol(false); |
| RtfTableCell hCell = row.newTableCellMergedHorizontally( |
| 0, null); |
| |
| if (numberRowsSpanned > 1) { |
| // Start vertical merge |
| hCell.setVMerge(RtfTableCell.MERGE_START); |
| |
| // set the number of rows spanned |
| tctx.setCurrentColumnRowSpanning( |
| new Integer(numberRowsSpanned), |
| cell.getRtfAttributes()); |
| } else { |
| tctx.setCurrentColumnRowSpanning( |
| new Integer(numberRowsSpanned), cell.getRtfAttributes()); |
| } |
| } |
| } |
| //save width of the cell, convert from twips to mpt |
| percentManager.setDimension(tc, (int)width * 50); |
| |
| builderContext.pushContainer(cell); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startCell: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endCell(TableCell tc) { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| builderContext.getTableContext().selectNextColumn(); |
| } |
| |
| // Lists |
| /** {@inheritDoc} */ |
| public void startList(ListBlock lb) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| // create an RtfList in the current list container |
| final IRtfListContainer c |
| = (IRtfListContainer)builderContext.getContainer( |
| IRtfListContainer.class, true, this); |
| final RtfList newList = c.newList( |
| ListAttributesConverter.convertAttributes(lb)); |
| builderContext.pushContainer(newList); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (FOPException fe) { |
| log.error("startList: " + fe.getMessage()); |
| throw new RuntimeException(fe.getMessage()); |
| } catch (Exception e) { |
| log.error("startList: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endList(ListBlock lb) { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startListItem(ListItem li) { |
| if (bDefer) { |
| return; |
| } |
| |
| // create an RtfListItem in the current RtfList |
| try { |
| RtfList list = (RtfList)builderContext.getContainer( |
| RtfList.class, true, this); |
| |
| /** |
| * If the current list already contains a list item, then close the |
| * list and open a new one, so every single list item gets its own |
| * list. This allows every item to have a different list label. |
| * If all the items would be in the same list, they had all the |
| * same label. |
| */ |
| //TODO: do this only, if the labels content <> previous labels content |
| if (list.getChildCount() > 0) { |
| this.endListBody(); |
| this.endList((ListBlock) li.getParent()); |
| this.startList((ListBlock) li.getParent()); |
| this.startListBody(); |
| |
| list = (RtfList)builderContext.getContainer( |
| RtfList.class, true, this); |
| } |
| |
| builderContext.pushContainer(list.newListItem()); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startList: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endListItem(ListItem li) { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startListLabel() { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfListItem item |
| = (RtfListItem)builderContext.getContainer(RtfListItem.class, true, this); |
| |
| RtfListItemLabel label = item.new RtfListItemLabel(item); |
| builderContext.pushContainer(label); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startPageNumber: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endListLabel() { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startListBody() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void endListBody() { |
| } |
| |
| // Static Regions |
| /** {@inheritDoc} */ |
| public void startStatic() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void endStatic() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void startMarkup() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void endMarkup() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void startLink(BasicLink basicLink) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| |
| RtfHyperLink link = textrun.addHyperlink(new RtfAttributes()); |
| |
| if (basicLink.hasExternalDestination()) { |
| link.setExternalURL(basicLink.getExternalDestination()); |
| } else { |
| link.setInternalURL(basicLink.getInternalDestination()); |
| } |
| |
| builderContext.pushContainer(link); |
| |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startLink: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endLink() { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void image(ExternalGraphic eg) { |
| if (bDefer) { |
| return; |
| } |
| |
| String uri = eg.getURL(); |
| ImageInfo info = null; |
| try { |
| |
| //set image data |
| FOUserAgent userAgent = eg.getUserAgent(); |
| ImageManager manager = userAgent.getFactory().getImageManager(); |
| info = manager.getImageInfo(uri, userAgent.getImageSessionContext()); |
| |
| putGraphic(eg, info); |
| } catch (ImageException ie) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); |
| } catch (FileNotFoundException fe) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); |
| } catch (IOException ioe) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void foreignObject(InstreamForeignObject ifo) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| XMLObj child = ifo.getChildXMLObj(); |
| Document doc = child.getDOMDocument(); |
| String ns = child.getNamespaceURI(); |
| |
| ImageInfo info = new ImageInfo(null, null); |
| // Set the resolution to that of the FOUserAgent |
| FOUserAgent ua = ifo.getUserAgent(); |
| ImageSize size = new ImageSize(); |
| size.setResolution(ua.getSourceResolution()); |
| |
| // Set the image size to the size of the svg. |
| Point2D csize = new Point2D.Float(-1, -1); |
| Point2D intrinsicDimensions = child.getDimension(csize); |
| if (intrinsicDimensions == null) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.ifoNoIntrinsicSize(this, child.getLocator()); |
| return; |
| } |
| size.setSizeInMillipoints( |
| (int)Math.round(intrinsicDimensions.getX() * 1000), |
| (int)Math.round(intrinsicDimensions.getY() * 1000)); |
| size.calcPixelsFromSize(); |
| info.setSize(size); |
| |
| ImageXMLDOM image = new ImageXMLDOM(info, doc, ns); |
| |
| FOUserAgent userAgent = ifo.getUserAgent(); |
| ImageManager manager = userAgent.getFactory().getImageManager(); |
| Map hints = ImageUtil.getDefaultHints(ua.getImageSessionContext()); |
| Image converted = manager.convertImage(image, FLAVORS, hints); |
| putGraphic(ifo, converted); |
| |
| } catch (ImageException ie) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageError(this, null, ie, null); |
| } catch (IOException ioe) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageIOError(this, null, ioe, null); |
| } |
| } |
| |
| private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { |
| ImageFlavor.RAW_EMF, ImageFlavor.RAW_PNG, ImageFlavor.RAW_JPEG |
| }; |
| |
| /** |
| * Puts a graphic/image into the generated RTF file. |
| * @param abstractGraphic the graphic (external-graphic or instream-foreign-object) |
| * @param info the image info object |
| * @throws IOException In case of an I/O error |
| */ |
| private void putGraphic(AbstractGraphics abstractGraphic, ImageInfo info) |
| throws IOException { |
| try { |
| FOUserAgent userAgent = abstractGraphic.getUserAgent(); |
| ImageManager manager = userAgent.getFactory().getImageManager(); |
| ImageSessionContext sessionContext = userAgent.getImageSessionContext(); |
| Map hints = ImageUtil.getDefaultHints(sessionContext); |
| Image image = manager.getImage(info, FLAVORS, hints, sessionContext); |
| |
| putGraphic(abstractGraphic, image); |
| } catch (ImageException ie) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageError(this, null, ie, null); |
| } |
| } |
| |
| /** |
| * Puts a graphic/image into the generated RTF file. |
| * @param abstractGraphic the graphic (external-graphic or instream-foreign-object) |
| * @param image the image |
| * @throws IOException In case of an I/O error |
| */ |
| private void putGraphic(AbstractGraphics abstractGraphic, Image image) |
| throws IOException { |
| byte[] rawData = null; |
| |
| final ImageInfo info = image.getInfo(); |
| |
| if (image instanceof ImageRawStream) { |
| ImageRawStream rawImage = (ImageRawStream)image; |
| InputStream in = rawImage.createInputStream(); |
| try { |
| rawData = IOUtils.toByteArray(in); |
| } finally { |
| IOUtils.closeQuietly(in); |
| } |
| } |
| |
| if (rawData == null) { |
| ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.imageWritingError(this, null); |
| return; |
| } |
| |
| //Set up percentage calculations |
| this.percentManager.setDimension(abstractGraphic); |
| PercentBaseContext pContext = new PercentBaseContext() { |
| |
| public int getBaseLength(int lengthBase, FObj fobj) { |
| switch (lengthBase) { |
| case LengthBase.IMAGE_INTRINSIC_WIDTH: |
| return info.getSize().getWidthMpt(); |
| case LengthBase.IMAGE_INTRINSIC_HEIGHT: |
| return info.getSize().getHeightMpt(); |
| default: |
| return percentManager.getBaseLength(lengthBase, fobj); |
| } |
| } |
| |
| }; |
| ImageLayout layout = new ImageLayout(abstractGraphic, pContext, |
| image.getInfo().getSize().getDimensionMpt()); |
| |
| final IRtfTextrunContainer c |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| final RtfExternalGraphic rtfGraphic = c.getTextrun().newImage(); |
| |
| //set URL |
| if (info.getOriginalURI() != null) { |
| rtfGraphic.setURL(info.getOriginalURI()); |
| } |
| rtfGraphic.setImageData(rawData); |
| |
| FoUnitsConverter converter = FoUnitsConverter.getInstance(); |
| Dimension viewport = layout.getViewportSize(); |
| Rectangle placement = layout.getPlacement(); |
| int cropLeft = Math.round(converter.convertMptToTwips(-placement.x)); |
| int cropTop = Math.round(converter.convertMptToTwips(-placement.y)); |
| int cropRight = Math.round(converter.convertMptToTwips( |
| -1 * (viewport.width - placement.x - placement.width))); |
| int cropBottom = Math.round(converter.convertMptToTwips( |
| -1 * (viewport.height - placement.y - placement.height))); |
| rtfGraphic.setCropping(cropLeft, cropTop, cropRight, cropBottom); |
| |
| int width = Math.round(converter.convertMptToTwips(viewport.width)); |
| int height = Math.round(converter.convertMptToTwips(viewport.height)); |
| width += cropLeft + cropRight; |
| height += cropTop + cropBottom; |
| rtfGraphic.setWidthTwips(width); |
| rtfGraphic.setHeightTwips(height); |
| |
| //TODO: make this configurable: |
| // int compression = m_context.m_options.getRtfExternalGraphicCompressionRate (); |
| int compression = 0; |
| if (compression != 0) { |
| if (!rtfGraphic.setCompressionRate(compression)) { |
| log.warn("The compression rate " + compression |
| + " is invalid. The value has to be between 1 and 100 %."); |
| } |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void pageRef() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void startFootnote(Footnote footnote) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, |
| true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| RtfFootnote rtfFootnote = textrun.addFootnote(); |
| |
| builderContext.pushContainer(rtfFootnote); |
| |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startFootnote: " + e.getMessage()); |
| throw new RuntimeException("Exception: " + e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endFootnote(Footnote footnote) { |
| if (bDefer) { |
| return; |
| } |
| |
| builderContext.popContainer(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startFootnoteBody(FootnoteBody body) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfFootnote rtfFootnote |
| = (RtfFootnote)builderContext.getContainer( |
| RtfFootnote.class, |
| true, this); |
| |
| rtfFootnote.startBody(); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startFootnoteBody: " + e.getMessage()); |
| throw new RuntimeException("Exception: " + e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endFootnoteBody(FootnoteBody body) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfFootnote rtfFootnote |
| = (RtfFootnote)builderContext.getContainer( |
| RtfFootnote.class, |
| true, this); |
| |
| rtfFootnote.endBody(); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("endFootnoteBody: " + e.getMessage()); |
| throw new RuntimeException("Exception: " + e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void leader(Leader l) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| percentManager.setDimension(l); |
| RtfAttributes rtfAttr = TextAttributesConverter.convertLeaderAttributes( |
| l, percentManager); |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addLeader(rtfAttr); |
| |
| } catch (Exception e) { |
| log.error("startLeader: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** |
| * @param text FOText object |
| * @param data Array of characters to process. |
| * @param start Offset for characters to process. |
| * @param length Portion of array to process. |
| */ |
| public void text(FOText text, char[] data, int start, int length) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| RtfAttributes rtfAttr |
| = TextAttributesConverter.convertCharacterAttributes(text); |
| |
| textrun.pushInlineAttributes(rtfAttr); |
| textrun.addString(new String(data, start, length - start)); |
| textrun.popInlineAttributes(); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("characters:" + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startPageNumber(PageNumber pagenum) { |
| if (bDefer) { |
| return; |
| } |
| |
| try { |
| RtfAttributes rtfAttr |
| = TextAttributesConverter.convertCharacterAttributes( |
| pagenum); |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| |
| RtfTextrun textrun = container.getTextrun(); |
| textrun.addPageNumber(rtfAttr); |
| } catch (IOException ioe) { |
| handleIOTrouble(ioe); |
| } catch (Exception e) { |
| log.error("startPageNumber: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void endPageNumber(PageNumber pagenum) { |
| if (bDefer) { |
| return; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startPageNumberCitation(PageNumberCitation l) { |
| if (bDefer) { |
| return; |
| } |
| try { |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addPageNumberCitation(l.getRefId()); |
| |
| } catch (Exception e) { |
| log.error("startPageNumberCitation: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void startPageNumberCitationLast(PageNumberCitationLast l) { |
| if (bDefer) { |
| return; |
| } |
| try { |
| |
| IRtfTextrunContainer container |
| = (IRtfTextrunContainer)builderContext.getContainer( |
| IRtfTextrunContainer.class, true, this); |
| RtfTextrun textrun = container.getTextrun(); |
| |
| textrun.addPageNumberCitation(l.getRefId()); |
| |
| } catch (RtfException e) { |
| log.error("startPageNumberCitationLast: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } catch (IOException e) { |
| log.error("startPageNumberCitationLast: " + e.getMessage()); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| private void prepareTable(Table tab) { |
| // Allows to receive the available width of the table |
| percentManager.setDimension(tab); |
| |
| // Table gets expanded by half of the border on each side inside Word |
| // When using wide borders the table gets cut off |
| int tabDiff = tab.getCommonBorderPaddingBackground().getBorderStartWidth(false) / 2 |
| + tab.getCommonBorderPaddingBackground().getBorderEndWidth(false); |
| |
| // check for "auto" value |
| if (!(tab.getInlineProgressionDimension().getMaximum(null).getLength() |
| instanceof EnumLength)) { |
| // value specified |
| percentManager.setDimension(tab, |
| tab.getInlineProgressionDimension().getMaximum(null) |
| .getLength().getValue(percentManager) |
| - tabDiff); |
| } else { |
| // set table width again without border width |
| percentManager.setDimension(tab, percentManager.getBaseLength( |
| LengthBase.CONTAINING_BLOCK_WIDTH, tab) - tabDiff); |
| } |
| |
| ColumnSetup columnSetup = new ColumnSetup(tab); |
| //int sumOfColumns = columnSetup.getSumOfColumnWidths(percentManager); |
| float tableWidth = percentManager.getBaseLength(LengthBase.CONTAINING_BLOCK_WIDTH, tab); |
| float tableUnit = columnSetup.computeTableUnit(percentManager, Math.round(tableWidth)); |
| percentManager.setTableUnit(tab, Math.round(tableUnit)); |
| |
| } |
| |
| /** |
| * Calls the appropriate event handler for the passed FObj. |
| * |
| * @param foNode FO node whose event is to be called |
| * @param bStart TRUE calls the start handler, FALSE the end handler |
| */ |
| private void invokeDeferredEvent(FONode foNode, boolean bStart) { // CSOK: MethodLength |
| if (foNode instanceof PageSequence) { |
| if (bStart) { |
| startPageSequence( (PageSequence) foNode); |
| } else { |
| endPageSequence( (PageSequence) foNode); |
| } |
| } else if (foNode instanceof Flow) { |
| if (bStart) { |
| startFlow( (Flow) foNode); |
| } else { |
| endFlow( (Flow) foNode); |
| } |
| } else if (foNode instanceof StaticContent) { |
| if (bStart) { |
| startStatic(); |
| } else { |
| endStatic(); |
| } |
| } else if (foNode instanceof ExternalGraphic) { |
| if (bStart) { |
| image( (ExternalGraphic) foNode ); |
| } |
| } else if (foNode instanceof InstreamForeignObject) { |
| if (bStart) { |
| foreignObject( (InstreamForeignObject) foNode ); |
| } |
| } else if (foNode instanceof Block) { |
| if (bStart) { |
| startBlock( (Block) foNode); |
| } else { |
| endBlock( (Block) foNode); |
| } |
| } else if (foNode instanceof BlockContainer) { |
| if (bStart) { |
| startBlockContainer( (BlockContainer) foNode); |
| } else { |
| endBlockContainer( (BlockContainer) foNode); |
| } |
| } else if (foNode instanceof BasicLink) { |
| //BasicLink must be placed before Inline |
| if (bStart) { |
| startLink( (BasicLink) foNode); |
| } else { |
| endLink(); |
| } |
| } else if (foNode instanceof Inline) { |
| if (bStart) { |
| startInline( (Inline) foNode); |
| } else { |
| endInline( (Inline) foNode); |
| } |
| } else if (foNode instanceof FOText) { |
| if (bStart) { |
| FOText text = (FOText) foNode; |
| text(text, text.getCharArray(), 0, text.length()); |
| } |
| } else if (foNode instanceof Character) { |
| if (bStart) { |
| Character c = (Character) foNode; |
| character(c); |
| } |
| } else if (foNode instanceof PageNumber) { |
| if (bStart) { |
| startPageNumber( (PageNumber) foNode); |
| } else { |
| endPageNumber( (PageNumber) foNode); |
| } |
| } else if (foNode instanceof Footnote) { |
| if (bStart) { |
| startFootnote( (Footnote) foNode); |
| } else { |
| endFootnote( (Footnote) foNode); |
| } |
| } else if (foNode instanceof FootnoteBody) { |
| if (bStart) { |
| startFootnoteBody( (FootnoteBody) foNode); |
| } else { |
| endFootnoteBody( (FootnoteBody) foNode); |
| } |
| } else if (foNode instanceof ListBlock) { |
| if (bStart) { |
| startList( (ListBlock) foNode); |
| } else { |
| endList( (ListBlock) foNode); |
| } |
| } else if (foNode instanceof ListItemBody) { |
| if (bStart) { |
| startListBody(); |
| } else { |
| endListBody(); |
| } |
| } else if (foNode instanceof ListItem) { |
| if (bStart) { |
| startListItem( (ListItem) foNode); |
| } else { |
| endListItem( (ListItem) foNode); |
| } |
| } else if (foNode instanceof ListItemLabel) { |
| if (bStart) { |
| startListLabel(); |
| } else { |
| endListLabel(); |
| } |
| } else if (foNode instanceof Table) { |
| if (bStart) { |
| startTable( (Table) foNode); |
| } else { |
| endTable( (Table) foNode); |
| } |
| } else if (foNode instanceof TableHeader) { |
| if (bStart) { |
| startHeader( (TableHeader) foNode); |
| } else { |
| endHeader( (TableHeader) foNode); |
| } |
| } else if (foNode instanceof TableFooter) { |
| if (bStart) { |
| startFooter( (TableFooter) foNode); |
| } else { |
| endFooter( (TableFooter) foNode); |
| } |
| } else if (foNode instanceof TableBody) { |
| if (bStart) { |
| startBody( (TableBody) foNode); |
| } else { |
| endBody( (TableBody) foNode); |
| } |
| } else if (foNode instanceof TableColumn) { |
| if (bStart) { |
| startColumn( (TableColumn) foNode); |
| } else { |
| endColumn( (TableColumn) foNode); |
| } |
| } else if (foNode instanceof TableRow) { |
| if (bStart) { |
| startRow( (TableRow) foNode); |
| } else { |
| endRow( (TableRow) foNode); |
| } |
| } else if (foNode instanceof TableCell) { |
| if (bStart) { |
| startCell( (TableCell) foNode); |
| } else { |
| endCell( (TableCell) foNode); |
| } |
| } else if (foNode instanceof Leader) { |
| if (bStart) { |
| leader((Leader) foNode); |
| } |
| } else if (foNode instanceof PageNumberCitation) { |
| if (bStart) { |
| startPageNumberCitation((PageNumberCitation) foNode); |
| } else { |
| endPageNumberCitation((PageNumberCitation) foNode); |
| } |
| } else if (foNode instanceof PageNumberCitationLast) { |
| if (bStart) { |
| startPageNumberCitationLast((PageNumberCitationLast) foNode); |
| } else { |
| endPageNumberCitationLast((PageNumberCitationLast) foNode); |
| } |
| } else { |
| RTFEventProducer eventProducer = RTFEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.ignoredDeferredEvent(this, foNode, bStart, foNode.getLocator()); |
| } |
| } |
| |
| /** |
| * Calls the event handlers for the passed FONode and all its elements. |
| * |
| * @param foNode FONode object which shall be recursed |
| */ |
| private void recurseFONode(FONode foNode) { |
| invokeDeferredEvent(foNode, true); |
| |
| if (foNode instanceof PageSequence) { |
| PageSequence pageSequence = (PageSequence) foNode; |
| |
| Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE); |
| if (regionBefore != null) { |
| FONode staticBefore = (FONode) pageSequence.getFlowMap().get( |
| regionBefore.getRegionName()); |
| if (staticBefore != null) { |
| recurseFONode(staticBefore); |
| } |
| } |
| Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER); |
| if (regionAfter != null) { |
| FONode staticAfter = (FONode) pageSequence.getFlowMap().get( |
| regionAfter.getRegionName()); |
| if (staticAfter != null) { |
| recurseFONode(staticAfter); |
| } |
| } |
| |
| |
| recurseFONode( pageSequence.getMainFlow() ); |
| } else if (foNode instanceof Table) { |
| Table table = (Table) foNode; |
| |
| //recurse all table-columns |
| if (table.getColumns() != null) { |
| //Calculation for column-widths which are not set |
| prepareTable(table); |
| |
| for (Iterator it = table.getColumns().iterator(); it.hasNext();) { |
| recurseFONode( (FONode) it.next() ); |
| } |
| } else { |
| //TODO Implement implicit column setup handling! |
| RTFEventProducer eventProducer = RTFEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.explicitTableColumnsRequired(this, table.getLocator()); |
| } |
| |
| //recurse table-header |
| if (table.getTableHeader() != null) { |
| recurseFONode( table.getTableHeader() ); |
| } |
| |
| //recurse table-footer |
| if (table.getTableFooter() != null) { |
| recurseFONode( table.getTableFooter() ); |
| } |
| |
| if (foNode.getChildNodes() != null) { |
| for (Iterator it = foNode.getChildNodes(); it.hasNext();) { |
| recurseFONode( (FONode) it.next() ); |
| } |
| } |
| } else if (foNode instanceof ListItem) { |
| ListItem item = (ListItem) foNode; |
| |
| recurseFONode(item.getLabel()); |
| recurseFONode(item.getBody()); |
| } else if (foNode instanceof Footnote) { |
| Footnote fn = (Footnote)foNode; |
| |
| recurseFONode(fn.getFootnoteCitation()); |
| recurseFONode(fn.getFootnoteBody()); |
| } else { |
| //Any other FO-Object: Simply recurse through all childNodes. |
| if (foNode.getChildNodes() != null) { |
| for (Iterator it = foNode.getChildNodes(); it.hasNext();) { |
| FONode fn = (FONode)it.next(); |
| if (log.isTraceEnabled()) { |
| log.trace(" ChildNode for " + fn + " (" + fn.getName() + ")"); |
| } |
| recurseFONode(fn); |
| } |
| } |
| } |
| |
| invokeDeferredEvent(foNode, false); |
| } |
| } |