]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
changes for RTF tables, submitted by Peter Herweg, see http://nagoya.apache.org/bugzi...
authorWilliam Victor Mote <vmote@apache.org>
Thu, 18 Sep 2003 15:57:25 +0000 (15:57 +0000)
committerWilliam Victor Mote <vmote@apache.org>
Thu, 18 Sep 2003 15:57:25 +0000 (15:57 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196921 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/fo/flow/TableBody.java
src/java/org/apache/fop/rtf/renderer/BuilderContext.java [new file with mode: 0644]
src/java/org/apache/fop/rtf/renderer/FoUnitsConverter.java [new file with mode: 0644]
src/java/org/apache/fop/rtf/renderer/RTFHandler.java
src/java/org/apache/fop/rtf/renderer/TableAttributesConverter.java [new file with mode: 0644]
src/java/org/apache/fop/rtf/renderer/TableContext.java [new file with mode: 0644]
src/java/org/apache/fop/rtf/rtflib/rtfdoc/ITableAttributes.java
src/java/org/apache/fop/rtf/rtflib/rtfdoc/RtfTable.java

index 71cd68b85488fbacaf777447ae3a8a0f0c961106..474acc814189b613943a5e106e60e8ded5f361d4 100644 (file)
@@ -50,6 +50,9 @@
  */
 package org.apache.fop.fo.flow;
 
+// XML
+import org.xml.sax.Attributes;
+
 // FOP
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.datatypes.ColorType;
@@ -123,5 +126,20 @@ public class TableBody extends FObj {
         fotv.serveTableBody(this);
     }
 
+    /**
+     * @see org.apache.fop.fo.FObj#handleAttrs
+     */
+    public void handleAttrs(Attributes attlist) throws FOPException {
+        super.handleAttrs(attlist);
+
+        setupID();
+
+        getFOTreeControl().getFOInputHandler().startBody(this);
+    }
+
+    protected void end() {
+        getFOTreeControl().getFOInputHandler().endBody(this);
+    }
+
 }
 
diff --git a/src/java/org/apache/fop/rtf/renderer/BuilderContext.java b/src/java/org/apache/fop/rtf/renderer/BuilderContext.java
new file mode 100644 (file)
index 0000000..00e41c5
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * ============================================================================
+ *                    The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include the following acknowledgment: "This product includes software
+ *    developed by the Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself, if
+ *    and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ *    endorse or promote products derived from this software without prior
+ *    written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ *    "Apache" appear in their name, without prior written permission of the
+ *    Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.rtf.renderer;
+
+import java.util.Stack;
+import org.apache.fop.rtf.rtflib.rtfdoc.*;
+
+
+/**  A BuilderContext holds context information when building an RTF document
+ *
+ *  @author Bertrand Delacretaz <bdelacretaz@codeconsult.ch>
+ *  @author putzi
+ *  @author Peter Herweg <pherweg@web.de>
+ *
+ *  This class was originally developed by Bertrand Delacretaz bdelacretaz@codeconsult.ch
+ *  for the JFOR project and is now integrated into FOP.
+ */
+
+
+class BuilderContext
+{
+       /** stack of RtfContainers */
+       private final Stack m_containers = new Stack();
+
+       /** stack of TableContexts */
+       private final Stack m_tableContexts = new Stack();
+
+       /** stack of IBuilders */
+       private final Stack m_builders = new Stack();
+
+       /** Rtf options */
+       IRtfOptions m_options;
+
+       BuilderContext(IRtfOptions rtfOptions)
+       {
+               m_options = rtfOptions;
+       }
+
+       /** find first object of given class from top of stack s
+        *  @return null if not found
+        */
+       private Object getObjectFromStack(Stack s,Class desiredClass)
+       {
+               Object result = null;
+               final Stack copy = (Stack)s.clone();
+               while(!copy.isEmpty()) {
+                       final Object o = copy.pop();
+                       if(desiredClass.isAssignableFrom(o.getClass())) {
+                               result = o;
+                               break;
+                       }
+               }
+               return result;
+       }
+
+       /* find the "nearest" IBuilder of given class /
+       Object getBuilder(Class builderClass,boolean required)
+       throws Exception
+       {
+               final IBuilder result = (IBuilder)getObjectFromStack(m_builders,builderClass);
+               if(result == null && required) {
+                       throw new Exception(
+                               "IBuilder of class '" + builderClass.getName() + "' not found on builders stack"
+                          );
+               }
+               return result;
+       }*/
+
+       /** find the "nearest" container that implements the given interface on our stack
+        *  @param required if true, ConverterException is thrown if no container found
+        *  @param forWhichBuilder used in error message if container not found
+        */
+       RtfContainer getContainer(Class containerClass,boolean required,Object /*IBuilder*/ forWhichBuilder) throws Exception
+       {
+               // TODO what to do if the desired container is not at the top of the stack?
+               // close top-of-stack container?
+               final RtfContainer result = (RtfContainer)getObjectFromStack(m_containers,containerClass);
+
+               if(result == null && required) {
+                       throw new Exception(
+                               "No RtfContainer of class '" + containerClass.getName()
+                               + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
+                          );
+               }
+
+               return result;
+       }
+
+       /** push an RtfContainer on our stack */
+       void pushContainer(RtfContainer c)
+       {
+               m_containers.push(c);
+       }
+
+       /** in some cases an RtfContainer must be replaced by another one on the stack.
+        *  this happens when handling nested fo:blocks for example: after handling a nested block
+        *  the enclosing block must switch to a new paragraph container to handle what follows the nested block.
+        *  TODO: what happens to elements that are "more on top" than oldC on the stack? shouldn't they be closed
+        *  or something?
+        */
+       void replaceContainer(RtfContainer oldC,RtfContainer newC)
+       throws Exception
+       {
+               // treating the Stack as a Vector allows such manipulations (yes, I hear you screaming ;-)
+               final int index = m_containers.indexOf(oldC);
+               if(index < 0) throw new Exception("container to replace not found:" + oldC);
+               m_containers.setElementAt(newC,index);
+       }
+
+       /** pop the topmost RtfContainer from our stack */
+       void popContainer()
+       {
+               m_containers.pop();
+       }
+
+       /* push an IBuilder to our stack /
+       void pushBuilder(IBuilder b)
+       {
+               m_builders.push(b);
+       }*/
+
+       /** pop the topmost IBuilder from our stack and return previous builder on stack
+        *  @return null if builders stack is empty
+
+       IBuilder popBuilderAndGetPreviousOne()
+       {
+               IBuilder result = null;
+               m_builders.pop();
+               if(!m_builders.isEmpty()) {
+                       result = (IBuilder)m_builders.peek();
+               }
+               return result;
+       }
+    */
+       /** return the current TableContext */
+       TableContext getTableContext()
+       {
+               return (TableContext)m_tableContexts.peek();
+       }
+
+       /** push a TableContext to our stack */
+       void pushTableContext(TableContext tc)
+       {
+               m_tableContexts.push(tc);
+       }
+
+       /** pop a TableContext from our stack */
+       void popTableContext()
+       {
+               m_tableContexts.pop();
+       }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/rtf/renderer/FoUnitsConverter.java b/src/java/org/apache/fop/rtf/renderer/FoUnitsConverter.java
new file mode 100644 (file)
index 0000000..99bec8f
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * ============================================================================
+ *                    The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include the following acknowledgment: "This product includes software
+ *    developed by the Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself, if
+ *    and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ *    endorse or promote products derived from this software without prior
+ *    written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ *    "Apache" appear in their name, without prior written permission of the
+ *    Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.rtf.renderer;
+
+import java.util.*;
+
+//FOP
+import org.apache.fop.apps.FOPException;
+
+
+/**  Converts XSL-FO units to RTF units
+ *
+ *  @author Bertrand Delacretaz <bdelacretaz@codeconsult.ch>
+ *  @author putzi
+ *  @author Peter Herweg <pherweg@web.de>
+ *
+ *  This class was originally developed by Bertrand Delacretaz bdelacretaz@codeconsult.ch
+ *  for the JFOR project and is now integrated into FOP.
+ */
+
+class FoUnitsConverter
+{
+    private static final FoUnitsConverter m_instance = new FoUnitsConverter();
+
+    /** points to twips: 1 twip is 1/20 of a point */
+    public static final float POINT_TO_TWIPS = 20f;
+
+    /** millimeters and centimeters to twips: , one point is 1/72 of an inch, one inch is 25.4 mm */
+    public static final float IN_TO_TWIPS = 72f * POINT_TO_TWIPS;
+    public static final float MM_TO_TWIPS = IN_TO_TWIPS / 25.4f;
+    public static final float CM_TO_TWIPS = 10 * MM_TO_TWIPS;
+
+
+    /** conversion factors keyed by xsl:fo units names */
+    private static final Map m_twipFactors = new HashMap();
+    static {
+        m_twipFactors.put("mm",new Float(MM_TO_TWIPS));
+        m_twipFactors.put("cm",new Float(CM_TO_TWIPS));
+        m_twipFactors.put("pt",new Float(POINT_TO_TWIPS));
+        m_twipFactors.put("in",new Float(IN_TO_TWIPS));
+    }
+
+    /** singleton pattern */
+    private FoUnitsConverter()
+    {
+    }
+
+    /** singleton pattern */
+    static FoUnitsConverter getInstance()
+    {
+        return m_instance;
+    }
+
+    /** convert given value to RTF units
+     *  @param foValue a value like "12mm"
+     *  TODO: tested with "mm" units only, needs work to comply with FO spec
+     * Why does it search for period instead of simply breaking last two
+     *  Characters into another units string? - Chris
+     */
+    float convertToTwips(String foValue)
+    throws FOPException
+    {
+        foValue = foValue.trim();
+
+        // break value into number and units
+        final StringBuffer number = new StringBuffer();
+        final StringBuffer units = new StringBuffer();
+
+        for(int i=0; i < foValue.length(); i++) {
+            final char c = foValue.charAt(i);
+            if(Character.isDigit(c) || c == '.') {
+                number.append(c);
+            } else {
+                // found the end of the digits
+                units.append(foValue.substring(i).trim());
+                break;
+            }
+        }
+
+        return numberToTwips(number.toString(),units.toString());
+    }
+
+
+    /** convert given value to twips according to given units */
+    private float numberToTwips(String number,String units)
+    throws FOPException
+    {
+        float result = 0;
+
+        // convert number to integer
+        try {
+            if(number != null && number.trim().length() > 0) {
+                result = Float.valueOf(number).floatValue();
+            }
+        } catch(Exception e) {
+            throw new FOPException("number format error: cannot convert '" + number + "' to float value");
+        }
+
+        // find conversion factor
+        if(units != null && units.trim().length() > 0) {
+            final Float factor = (Float)m_twipFactors.get(units.toLowerCase());
+            if(factor == null) throw new FOPException("conversion factor not found for '" + units + "' units");
+            result *= factor.floatValue();
+        }
+
+        return result;
+    }
+
+    /** convert a font size given in points like "12pt" */
+    int convertFontSize(String size)
+    throws FOPException
+    {
+        size = size.trim();
+        final String FONT_SUFFIX = "pt";
+        if(!size.endsWith(FONT_SUFFIX)) {
+            throw new FOPException("Invalid font size '" + size + "', must end with '" + FONT_SUFFIX + "'");
+        }
+
+        float result = 0;
+        size = size.substring(0,size.length() - FONT_SUFFIX.length());
+        try {
+            result = (Float.valueOf(size).floatValue());
+        } catch(Exception e) {
+            throw new FOPException("Invalid font size value '" + size + "'");
+        }
+
+        // RTF font size units are in half-points
+        return (int)(result * 2.0);
+    }
+}
index 2de35ed5865dd307f4bea938ac49ac12c13efc8b..cb38defabe782d7d60acea7e885050a465dfff47 100644 (file)
@@ -55,7 +55,8 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 
-import org.apache.fop.apps.Driver;
+import org.apache.avalon.framework.logger.ConsoleLogger;
+import org.apache.avalon.framework.logger.Logger;
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.datatypes.ColorType;
 import org.apache.fop.fo.FOInputHandler;
@@ -73,7 +74,9 @@ import org.apache.fop.fo.flow.TableRow;
 import org.apache.fop.fo.pagination.Flow;
 import org.apache.fop.fo.pagination.PageSequence;
 import org.apache.fop.fo.properties.Constants;
+import org.apache.fop.fo.Property;
 import org.apache.fop.apps.Document;
+import org.apache.fop.rtf.rtflib.rtfdoc.IRtfParagraphContainer;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfAttributes;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfColorTable;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfDocumentArea;
@@ -81,22 +84,31 @@ import org.apache.fop.rtf.rtflib.rtfdoc.RtfFile;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfParagraph;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfSection;
 import org.apache.fop.rtf.rtflib.rtfdoc.RtfText;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfTable;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfTableRow;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfTableCell;
+import org.apache.fop.rtf.rtflib.rtfdoc.IRtfTableContainer;
 import org.xml.sax.SAXException;
 
 /**
  * RTF Handler: generates RTF output using the structure events from
  * the FO Tree sent to this structure handler.
  *
- * @author bdelacretaz@apache.org
+ * @author Bertrand Delacretaz <bdelacretaz@codeconsult.ch>
+ * @author Trembicki-Guy, Ed <GuyE@DNB.com>
+ * @author Boris Poudérous <boris.pouderous@eads-telecom.com>
+ * @author Peter Herweg <pherweg@web.de>
  */
 public class RTFHandler extends FOInputHandler {
 
     private RtfFile rtfFile;
     private final OutputStream os;
+    private final Logger log=new ConsoleLogger();
     private RtfSection sect;
     private RtfDocumentArea docArea;
     private RtfParagraph para;
     private boolean warned = false;
+    private BuilderContext m_context=new BuilderContext(null);
 
     private static final String ALPHA_WARNING = "WARNING: RTF renderer is "
         + "veryveryalpha at this time, see class org.apache.fop.rtf.renderer.RTFHandler";
@@ -116,7 +128,7 @@ public class RTFHandler extends FOInputHandler {
         this.os = os;
         // use pdf fonts for now, this is only for resolving names
         org.apache.fop.render.pdf.FontSetup.setup(doc, null);
-        System.err.println(ALPHA_WARNING);
+        log.warn(ALPHA_WARNING);
     }
 
     /**
@@ -151,12 +163,14 @@ public class RTFHandler extends FOInputHandler {
     public void startPageSequence(PageSequence pageSeq)  {
         try {
             sect = docArea.newSection();
+            m_context.pushContainer(sect);
             if (!warned) {
                 sect.newParagraph().newText(ALPHA_WARNING);
                 warned = true;
             }
         } catch (IOException ioe) {
             // FIXME could we throw Exception in all FOInputHandler events?
+            log.error("startPageSequence: " + ioe.getMessage());
             throw new Error("IOException: " + ioe);
         }
     }
@@ -165,6 +179,7 @@ public class RTFHandler extends FOInputHandler {
      * @see org.apache.fop.fo.FOInputHandler#endPageSequence(PageSequence)
      */
     public void endPageSequence(PageSequence pageSeq) throws FOPException {
+        m_context.popContainer();
     }
 
     /**
@@ -190,11 +205,20 @@ public class RTFHandler extends FOInputHandler {
             attrBlockFontSize(bl, rtfAttr);
             attrBlockFontWeight(bl, rtfAttr);
 
-            para = sect.newParagraph(rtfAttr);
+            IRtfParagraphContainer pc=(IRtfParagraphContainer)m_context.getContainer(IRtfParagraphContainer.class,true,null);
+            para = pc.newParagraph(rtfAttr);
+
+            m_context.pushContainer(para);
         } catch (IOException ioe) {
             // FIXME could we throw Exception in all FOInputHandler events?
+            log.error("startBlock: " + ioe.getMessage());
             throw new Error("IOException: " + ioe);
         }
+        catch(Exception e)
+        {
+            log.error("startBlock: " + e.getMessage());
+            throw new Error("Exception: " + e);
+        }
     }
 
 
@@ -202,18 +226,65 @@ public class RTFHandler extends FOInputHandler {
      * @see org.apache.fop.fo.FOInputHandler#endBlock(Block)
      */
     public void endBlock(Block bl) {
+        m_context.popContainer();
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#startTable(Table)
      */
     public void startTable(Table tbl) {
+        // create an RtfTable in the current table container
+        TableContext tableContext = new TableContext(m_context);
+        RtfAttributes atts=new RtfAttributes();
+
+        try
+        {
+            final IRtfTableContainer tc = (IRtfTableContainer)m_context.getContainer(IRtfTableContainer.class,true,null);
+            m_context.pushContainer(tc.newTable(atts, tableContext));
+        }
+        catch(Exception e)
+        {
+            log.error("startTable:" + e.getMessage());
+            throw new Error(e.getMessage());
+        }
+
+        m_context.pushTableContext(tableContext);
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#endTable(Table)
      */
     public void endTable(Table tbl) {
+        m_context.popTableContext();
+        m_context.popContainer();
+    }
+
+    /**
+    *
+    * @param th TableColumn that is starting;
+    */
+
+    public void startColumn(TableColumn tc) {
+        try
+        {
+            Integer iWidth=new Integer(tc.getColumnWidth()/1000);
+            m_context.getTableContext().setNextColumnWidth(iWidth.toString()+"pt");
+            m_context.getTableContext().setNextColumnRowSpanning(new Integer(0),null);
+        }
+        catch(Exception e)
+        {
+            log.error("startColumn: " + e.getMessage());
+            throw new Error(e.getMessage());
+        }
+
+    }
+
+     /**
+     *
+     * @param th TableColumn that is ending;
+     */
+
+    public void endColumn(TableColumn tc){
     }
 
     /**
@@ -244,50 +315,124 @@ public class RTFHandler extends FOInputHandler {
      * @see org.apache.fop.fo.FOInputHandler#startBody(TableBody)
      */
     public void startBody(TableBody tb) {
+        try
+        {
+            RtfAttributes atts=TableAttributesConverter.convertRowAttributes (tb.properties, null, null);
+
+            RtfTable tbl = (RtfTable)m_context.getContainer(RtfTable.class,true,this);
+            tbl.setHeaderAttribs(atts);
+        }
+        catch(Exception e)
+        {
+            log.error("startBody: " + e.getMessage());
+            throw new Error(e.getMessage());
+        }
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#endBody(TableBody)
      */
     public void endBody(TableBody tb) {
-    }
-
-    /**
-     *
-     * @param tc TableColumn that is starting;
-     */
-    public void startColumn(TableColumn tc) {
-    }
-
-    /**
-     *
-     * @param tc TableColumn that is ending;
-     */
-    public void endColumn(TableColumn tc) {
+        try
+        {
+            RtfTable tbl = (RtfTable)m_context.getContainer(RtfTable.class,true,this);
+            tbl.setHeaderAttribs( null );
+        }
+        catch(Exception e)
+        {
+            log.error("endBody: " + e.getMessage());
+            throw new Error(e.getMessage());
+        }
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#startRow(TableRow)
      */
     public void startRow(TableRow tr) {
+        try
+        {
+            // create an RtfTableRow in the current RtfTable
+            final RtfTable tbl = (RtfTable)m_context.getContainer(RtfTable.class,true,null);
+
+            RtfAttributes tblAttribs = tbl.getRtfAttributes();
+            RtfAttributes tblRowAttribs = new RtfAttributes();
+            RtfAttributes atts=TableAttributesConverter.convertRowAttributes(tr.properties,null,tbl.getHeaderAttribs());
+
+            m_context.pushContainer(tbl.newTableRow( atts ));
+
+            // reset column iteration index to correctly access column widths
+            m_context.getTableContext().selectFirstColumn();
+        }
+        catch(Exception e)
+        {
+            log.error("startRow: " + e.getMessage());
+            throw new Error(e.getMessage());
+        }
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#endRow(TableRow)
      */
     public void endRow(TableRow tr) {
+        m_context.popContainer();
+        m_context.getTableContext().decreaseRowSpannings();
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#startCell(TableCell)
      */
     public void startCell(TableCell tc) {
+        try
+        {
+            TableContext tctx=m_context.getTableContext();
+            final RtfTableRow row = (RtfTableRow)m_context.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)
+            {
+                row.newTableCellMergedVertically((int)tctx.getColumnWidth(),tctx.getColumnRowSpanningAttrs());
+                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.properties,null);
+            RtfTableCell cell=row.newTableCell((int)width, atts);
+
+            //process number-rows-spanned attribute
+            Property p=null;
+            if ((p=tc.properties.get("number-rows-spanned")) != null && false)
+            {
+                // Start vertical merge
+                cell.setVMerge(RtfTableCell.MERGE_START);
+
+                // set the number of rows spanned
+                tctx.setCurrentColumnRowSpanning(new Integer(p.getNumber().intValue()), cell.getRtfAttributes());
+            }
+            else
+            {
+                tctx.setCurrentColumnRowSpanning(new Integer(1),null);
+            }
+
+            m_context.pushContainer(cell);
+        }
+        catch(Exception e)
+        {
+            log.error("startCell: " + e.getMessage());
+            throw new Error(e.getMessage());
+        }
     }
 
     /**
      * @see org.apache.fop.fo.FOInputHandler#endCell(TableCell)
      */
     public void endCell(TableCell tc) {
+        m_context.popContainer();
+        m_context.getTableContext().selectNextColumn();
     }
 
     // Lists
@@ -414,6 +559,7 @@ public class RTFHandler extends FOInputHandler {
             para.newText(new String(data, start, length));
          } catch (IOException ioe) {
             // FIXME could we throw Exception in all FOInputHandler events?
+            log.error("characters: " + ioe.getMessage());
             throw new Error("IOException: " + ioe);
         }
     }
@@ -468,6 +614,8 @@ public class RTFHandler extends FOInputHandler {
         if ((fopValue.getRed() == 0) && (fopValue.getGreen() == 0)
                 && (fopValue.getBlue() == 0) && (fopValue.getAlpha() == 0)) {
             rtfColor = RtfColorTable.getInstance().getColorNumber("white").intValue();
+            currentRTFBackgroundColor = -1;
+            return;
         } else {
             rtfColor = convertFOPColorToRTF(fopValue);
         }
diff --git a/src/java/org/apache/fop/rtf/renderer/TableAttributesConverter.java b/src/java/org/apache/fop/rtf/renderer/TableAttributesConverter.java
new file mode 100644 (file)
index 0000000..49f7bb6
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * ============================================================================
+ *                    The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include the following acknowledgment: "This product includes software
+ *    developed by the Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself, if
+ *    and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ *    endorse or promote products derived from this software without prior
+ *    written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ *    "Apache" appear in their name, without prior written permission of the
+ *    Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.rtf.renderer;
+
+//RTF
+import org.apache.fop.rtf.rtflib.rtfdoc.BorderAttributesConverter;
+
+//FOP
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.logger.ConsoleLogger;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.EnumProperty;
+import org.apache.fop.fo.expr.NCnameProperty;
+import org.apache.fop.fo.properties.Constants;
+import org.apache.fop.fo.LengthProperty;
+import org.apache.fop.fo.ListProperty;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.Property;
+import org.apache.fop.fo.ColorTypeProperty;
+import org.apache.fop.fo.NumberProperty;
+import org.apache.fop.datatypes.ColorType;
+
+import org.xml.sax.Attributes;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfAttributes;
+import org.apache.fop.rtf.rtflib.rtfdoc.ITableAttributes;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfColorTable;
+
+/**
+ * Contributor(s):
+ *  @author Roberto Marra <roberto@link-u.com>
+ *  @author Boris Poudérous <boris.pouderous@eads-telecom.com>
+ *  @author Normand Massé
+ *  @author Peter Herweg <pherweg@web.de>
+ *
+ * This class was originally developed for the JFOR project and
+ * is now integrated into FOP.
+-----------------------------------------------------------------------------*/
+
+/**
+ * Provides methods to convert the attributes to RtfAttributes.
+ */
+
+public class TableAttributesConverter {
+
+    static Logger log=new ConsoleLogger();
+
+    //////////////////////////////////////////////////
+    // @@ Construction
+    //////////////////////////////////////////////////
+
+    /**
+     * Constructor.
+     */
+    private TableAttributesConverter() {
+    }
+
+    //////////////////////////////////////////////////
+    // @@ Static converter methods
+    //////////////////////////////////////////////////
+
+
+    /**
+     * Converts cell attributes to rtf attributes.
+     * @param attrs Given attributes
+     * @param defaultAttributes Default rtf attributes
+     *
+     * @return All valid rtf attributes together
+     *
+     * @throws ConverterException On convertion error
+     */
+    static RtfAttributes convertCellAttributes(PropertyList props, PropertyList defProps)
+    throws FOPException {
+
+        Property p;
+        EnumProperty ep;
+        RtfColorTable colorTable=RtfColorTable.getInstance();
+
+        RtfAttributes attrib=null;
+
+        if(defProps!=null)
+        {
+            attrib=convertCellAttributes(defProps,null);
+        }
+        else
+        {
+            attrib=new RtfAttributes();
+        }
+
+        boolean isBorderPresent=false;
+
+        // Cell background color
+        if ((p=props.getNearestSpecified("background-color"))!=null)
+        {
+            ColorType color=p.getColorType();
+            if(color!=null)
+            {
+                if(color.getAlpha()!=0
+                || color.getRed()!=0
+                || color.getGreen()!=0
+                || color.getBlue()!=0)
+                {
+                    attrib.set(
+                        ITableAttributes.CELL_COLOR_BACKGROUND,
+                        RTFHandler.convertFOPColorToRTF(color));
+                }
+            }
+            else
+            {
+                log.warn("Named color '" + p.toString() + "' not found. ");
+            }
+
+        }
+
+        // Cell borders :
+        if ((p=props.getExplicit("border-color"))!=null){
+            ListProperty listprop=(ListProperty)p;
+            ColorType color=null;
+            if(listprop.getList().get(0) instanceof NCnameProperty){
+                color=new ColorType(((NCnameProperty)listprop.getList().get(0)).getNCname());
+            }
+            else if(listprop.getList().get(0) instanceof ColorTypeProperty){
+                color=((ColorTypeProperty)listprop.getList().get(0)).getColorType();
+            }
+
+            attrib.set(
+                BorderAttributesConverter.BORDER_COLOR,
+                colorTable.getColorNumber((int)color.getRed(),(int)color.getGreen(),(int)color.getBlue()).intValue());
+        }
+        if ((p=props.getExplicit("border-top-color"))!=null){
+            ColorType color=p.getColorType();
+            attrib.set(
+                BorderAttributesConverter.BORDER_COLOR,
+                colorTable.getColorNumber((int)color.getRed(),(int)color.getGreen(),(int)color.getBlue()).intValue());
+        }
+        if((p=props.getExplicit("border-bottom-color"))!=null){
+            ColorType color=p.getColorType();
+            attrib.set(
+                BorderAttributesConverter.BORDER_COLOR,
+                colorTable.getColorNumber((int)color.getRed(),(int)color.getGreen(),(int)color.getBlue()).intValue());
+        }
+        if((p=props.getExplicit("border-left-color"))!=null){
+            ColorType color=p.getColorType();
+            attrib.set(
+                BorderAttributesConverter.BORDER_COLOR,
+                colorTable.getColorNumber((int)color.getRed(),(int)color.getGreen(),(int)color.getBlue()).intValue());
+        }
+        if((p=props.getExplicit("border-right-color"))!=null){
+            ColorType color=p.getColorType();
+            attrib.set(
+                BorderAttributesConverter.BORDER_COLOR,
+                colorTable.getColorNumber((int)color.getRed(),(int)color.getGreen(),(int)color.getBlue()).intValue());
+        }
+
+        // Border styles do not inherit from parent
+        if((p=props.get("border-style"))!=null){
+            log.warn("border-style not implemented. Please use border-style-left, ...-right, ...-top or ...-bottom");
+            /*
+            attrib.set(ITableAttributes.CELL_BORDER_LEFT,  "\\"+convertAttributetoRtf(e.getEnum()));
+            attrib.set(ITableAttributes.CELL_BORDER_RIGHT, "\\"+convertAttributetoRtf(e.getEnum()));
+            attrib.set(ITableAttributes.CELL_BORDER_BOTTOM,"\\"+convertAttributetoRtf(e.getEnum()));
+            attrib.set(ITableAttributes.CELL_BORDER_TOP,   "\\"+convertAttributetoRtf(e.getEnum()));
+            isBorderPresent=true;
+            */
+        }
+        ep=(EnumProperty)props.get("border-top-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.CELL_BORDER_TOP,   "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-bottom-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.CELL_BORDER_BOTTOM,"\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-left-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.CELL_BORDER_LEFT,  "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-right-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.CELL_BORDER_RIGHT, "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+
+        if((p=props.get("border-width"))!=null) {
+            ListProperty listprop=(ListProperty)p;
+            LengthProperty lengthprop=(LengthProperty)listprop.getList().get(0);
+
+            Float f=new Float(lengthprop.getLength().getValue()/1000f);
+            String sValue = f.toString() + "pt";
+
+            attrib.set(BorderAttributesConverter.BORDER_WIDTH, (int)FoUnitsConverter.getInstance().convertToTwips(sValue));
+        }
+        else if(isBorderPresent){
+            //if not defined, set default border width
+            //note 20 twips = 1 point
+            attrib.set(BorderAttributesConverter.BORDER_WIDTH, (int)FoUnitsConverter.getInstance().convertToTwips("1pt"));
+        }
+
+
+        // Column spanning :
+        NumberProperty n=(NumberProperty)props.get("number-columns-spanned");
+        if(n!=null && n.getNumber().intValue()>1) {
+            attrib.set(ITableAttributes.COLUMN_SPAN, n.getNumber().intValue());
+        }
+
+        return attrib;
+    }
+
+
+    /**
+     * Converts table and row attributes to rtf attributes.
+     *
+     * @param attrs Given attributes
+     * @param defaultAttributes Default rtf attributes
+     *
+     * @return All valid rtf attributes together
+     *
+     * @throws ConverterException On convertion error
+     */
+    static RtfAttributes convertRowAttributes(PropertyList props, PropertyList defProps, RtfAttributes rtfatts)
+    throws FOPException {
+
+        Property p;
+        EnumProperty ep;
+        RtfColorTable colorTable=RtfColorTable.getInstance();
+
+        RtfAttributes attrib=null;
+
+        if(defProps!=null)
+        {
+            attrib=convertRowAttributes(defProps,null,rtfatts);
+        }
+        else
+        {
+            if(rtfatts==null)
+                attrib=new RtfAttributes();
+            else
+                attrib=rtfatts;
+        }
+
+        String attrValue;
+        boolean isBorderPresent=false;
+        //need to set a default width
+
+        //check for keep-together row attribute
+        if ((p=props.get("keep-together.within-page"))!=null){
+            attrib.set(ITableAttributes.ROW_KEEP_TOGETHER);
+        }
+
+        if ((p=props.get("keep-together"))!=null){
+            attrib.set(ITableAttributes.ROW_KEEP_TOGETHER);
+        }
+
+        //Check for keep-with-next row attribute.
+        if ((p=props.get("keep-together"))!=null){
+            attrib.set(ITableAttributes.ROW_KEEP_WITH_NEXT);
+        }
+
+        //Check for keep-with-previous row attribute.
+        if ((p=props.get("keep-with-previous"))!=null){
+            attrib.set(ITableAttributes.ROW_KEEP_WITH_PREVIOUS);
+        }
+
+        //Check for height row attribute.
+        if ((p=props.get("height"))!=null){
+            Float f=new Float(p.getLength().getValue()/1000);
+            attrValue = f.toString() + "pt";
+            attrib.set(ITableAttributes.ROW_HEIGHT, (int)FoUnitsConverter.getInstance().convertToTwips(attrValue));
+        }
+
+        /* to write a border to a side of a cell one must write the directional side (ie. left, right) and the inside value
+         * if one needs to be taken out ie if the cell lies on the edge of a table or not, the offending value will be taken out
+         * by RtfTableRow.  This is because you can't say BORDER_TOP and BORDER_HORIZONTAL if the cell lies at the
+         * top of the table.  Similarly using BORDER_BOTTOM and BORDER_HORIZONTAL will not work if the cell lies at th
+         * bottom of the table.  The same rules apply for left right and vertical.
+
+         * Also, the border type must be written after every control word.  Thus it is implemented that the border type is the value
+         * of the border place.
+         */
+        if((p=props.get("border-style"))!=null){
+            log.warn("border-style not implemented. Please use border-style-left, ...-right, ...-top or ...-bottom");
+
+//            attrValue = new String(AbstractBuilder.getValue( attrs, "border-style", defAttrs ));
+//            attrib.set(ITableAttributes.ROW_BORDER_LEFT,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            attrib.set(ITableAttributes.ROW_BORDER_RIGHT,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            attrib.set(ITableAttributes.ROW_BORDER_BOTTOM,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            attrib.set(ITableAttributes.ROW_BORDER_TOP,"\\"+BorderAttributesConverter.convertAttributetoRtf(attrValue));
+//            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-top-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_TOP,       "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL,"\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-bottom-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_BOTTOM,    "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL,"\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-left-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_LEFT,     "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL, "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-right-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_RIGHT,    "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL, "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-horizontal-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL, "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_TOP,        "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_BOTTOM,     "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+        ep=(EnumProperty)props.get("border-vertical-style");
+        if(ep!=null && ep.getEnum()!=Constants.NONE){
+            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL,  "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_LEFT,      "\\"+convertAttributetoRtf(ep.getEnum()));
+            attrib.set(ITableAttributes.ROW_BORDER_RIGHT,     "\\"+convertAttributetoRtf(ep.getEnum()));
+            isBorderPresent=true;
+        }
+
+        if((p=props.get("border-width"))!=null){
+            ListProperty listprop=(ListProperty)p;
+            LengthProperty lengthprop=(LengthProperty)listprop.getList().get(0);
+
+            Float f=new Float(lengthprop.getLength().getValue()/1000f);
+            String sValue = f.toString() + "pt";
+
+            attrib.set(BorderAttributesConverter.BORDER_WIDTH, (int)FoUnitsConverter.getInstance().convertToTwips(sValue));
+        }
+        else if(isBorderPresent){
+            //if not defined, set default border width
+            //note 20 twips = 1 point
+            attrib.set(BorderAttributesConverter.BORDER_WIDTH, (int)FoUnitsConverter.getInstance().convertToTwips("1pt"));
+        }
+
+        return attrib;
+    }
+
+
+
+    public static String convertAttributetoRtf(int iBorderStyle) {
+        // Added by Normand Masse
+        // "solid" is interpreted like "thin"
+        if (iBorderStyle==Constants.SOLID) {
+            return BorderAttributesConverter.BORDER_SINGLE_THICKNESS;
+/*        } else if (iBorderStyle==Constants.THIN) {
+                        return BorderAttributesConverter.BORDER_SINGLE_THICKNESS;
+        } else if (iBorderStyle==Constants.THICK) {
+            return BorderAttributesConverter.BORDER_DOUBLE_THICKNESS;
+        } else if (iBorderStyle==Constants. value.equals("shadowed")) {
+            return BorderAttributesConverter.BORDER_SHADOWED;*/
+        } else if (iBorderStyle==Constants.DOUBLE) {
+            return BorderAttributesConverter.BORDER_DOUBLE;
+        } else if (iBorderStyle==Constants.DOTTED) {
+            return BorderAttributesConverter.BORDER_DOTTED;
+        } else if (iBorderStyle==Constants.DASHED) {
+            return BorderAttributesConverter.BORDER_DASH;
+/*        } else if (iBorderStyle==Constants value.equals("hairline")) {
+            return BorderAttributesConverter.BORDER_HAIRLINE;*/
+/*        } else if (iBorderStyle==Constant value.equals("dot-dash")) {
+            return BorderAttributesConverter.BORDER_DOT_DASH;
+        } else if (iBorderStyle==Constant value.equals("dot-dot-dash")) {
+            return BorderAttributesConverter.BORDER_DOT_DOT_DASH;
+        } else if (iBorderStyle==Constant value.equals("triple")) {
+            return BorderAttributesConverter.BORDER_TRIPLE;
+        } else if (iBorderStyle==Constant value.equals("wavy")) {
+            return BorderAttributesConverter.BORDER_WAVY;
+        } else if (iBorderStyle==Constant value.equals("wavy-double")) {
+            return BorderAttributesConverter.BORDER_WAVY_DOUBLE;
+        } else if (iBorderStyle==Constant value.equals("striped")) {
+            return BorderAttributesConverter.BORDER_STRIPED;
+        } else if (iBorderStyle==Constant value.equals("emboss")) {
+            return BorderAttributesConverter.BORDER_EMBOSS;
+        } else if (iBorderStyle==Constant value.equals("engrave")) {
+            return BorderAttributesConverter.BORDER_ENGRAVE;*/
+        } else {
+            return null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/rtf/renderer/TableContext.java b/src/java/org/apache/fop/rtf/renderer/TableContext.java
new file mode 100644 (file)
index 0000000..088da98
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * ============================================================================
+ *                    The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include the following acknowledgment: "This product includes software
+ *    developed by the Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself, if
+ *    and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ *    endorse or promote products derived from this software without prior
+ *    written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ *    "Apache" appear in their name, without prior written permission of the
+ *    Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.rtf.renderer;
+
+import java.util.*;
+
+import org.apache.avalon.framework.logger.ConsoleLogger;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.fop.rtf.rtflib.rtfdoc.RtfAttributes;
+import org.apache.fop.rtf.rtflib.interfaces.ITableColumnsInfo;
+
+
+/** Used when handling fo:table to hold information to build the table.
+ *
+ *  Contributor(s):
+ *  @author Bertrand Delacretaz <bdelacretaz@codeconsult.ch>
+ *  @author Trembicki-Guy, Ed <GuyE@DNB.com>
+ *  @author Boris Poudérous <boris.pouderous@eads-telecom.com>
+ *  @author Peter Herweg <pherweg@web.de>
+ *
+ *  This class was originally developed for the JFOR project and
+ *  is now integrated into FOP.
+ */
+
+class TableContext implements ITableColumnsInfo
+{
+    private final Logger log=new ConsoleLogger();
+    private final BuilderContext m_context;
+    private final ArrayList m_colWidths = new ArrayList();
+    private int m_colIndex;
+
+    /**
+     * Added by Peter Herweg on 2002-06-29
+     * This ArrayList contains one element for each column in the table.
+     * value == 0 means there is no row-spanning
+     * value >  0 means there is row-spanning
+     * Each value in the list is decreased by 1 after each finished table-row
+     */
+    private final ArrayList m_colRowSpanningNumber = new ArrayList();
+
+    /**
+     * Added by Peter Herweg on 2002-06-29
+     * If there has a vertical merged cell to be created, its attributes are
+     * inherited from the corresponding MERGE_START-cell.
+     * For this purpose the attributes of a cell are stored in this array, as soon
+     * as a number-rows-spanned attribute has been found.
+     */
+    private final ArrayList m_colRowSpanningAttrs = new ArrayList();  //Added by Peter Herweg on 2002-06-29
+
+    private boolean m_bNextRowBelongsToHeader=false;
+
+    public void setNextRowBelongsToHeader(boolean bNextRowBelongsToHeader)
+    {
+       m_bNextRowBelongsToHeader=bNextRowBelongsToHeader;
+    }
+
+       public boolean getNextRowBelongsToHeader()
+       {
+               return m_bNextRowBelongsToHeader;
+       }
+
+    TableContext(BuilderContext ctx)
+    {
+        m_context = ctx;
+    }
+
+    void setNextColumnWidth(String strWidth)
+    throws Exception
+    {
+
+        m_colWidths.add( new Float(FoUnitsConverter.getInstance().convertToTwips(strWidth)));
+    }
+
+    //Added by Peter Herweg on 2002-06-29
+    RtfAttributes getColumnRowSpanningAttrs()
+    {
+        return (RtfAttributes)m_colRowSpanningAttrs.get(m_colIndex);
+    }
+
+    //Added by Peter Herweg on 2002-06-29
+    Integer getColumnRowSpanningNumber()
+    {
+        return (Integer)m_colRowSpanningNumber.get(m_colIndex);
+    }
+
+    //Added by Peter Herweg on 2002-06-29
+    void setCurrentColumnRowSpanning(Integer iRowSpanning,  RtfAttributes attrs)
+    throws Exception
+    {
+
+        if(m_colIndex<m_colRowSpanningNumber.size())
+        {
+            m_colRowSpanningNumber.set(m_colIndex, iRowSpanning);
+            m_colRowSpanningAttrs.set(m_colIndex, attrs);
+        }
+        else
+        {
+            m_colRowSpanningNumber.add(iRowSpanning);
+            m_colRowSpanningAttrs.add(m_colIndex, attrs);
+        }
+    }
+
+    //Added by Peter Herweg on 2002-06-29
+    public void setNextColumnRowSpanning(Integer iRowSpanning,  RtfAttributes attrs)
+    {
+        m_colRowSpanningNumber.add(iRowSpanning);
+        m_colRowSpanningAttrs.add(m_colIndex, attrs);
+    }
+
+    /**
+     * Added by Peter Herweg on 2002-06-29
+     * This function is called after each finished table-row.
+     * It decreases all values in m_colRowSpanningNumber by 1. If a value
+     * reaches 0 row-spanning is finished, and the value won't be decreased anymore.
+     */
+    public void decreaseRowSpannings()
+    {
+        for(int z=0;z<m_colRowSpanningNumber.size();++z)
+        {
+            Integer i=(Integer)m_colRowSpanningNumber.get(z);
+
+            if(i.intValue()>0)
+                i=new Integer(i.intValue()-1);
+
+            m_colRowSpanningNumber.set(z,i);
+
+            if(i.intValue()==0)
+                m_colRowSpanningAttrs.set(z,null);
+        }
+    }
+
+    /** reset the column iteration index, meant to be called when creating a new row
+     * The 'public' modifier has been added by Boris Poudérous for 'number-columns-spanned' processing
+     */
+    public void selectFirstColumn()
+    {
+        m_colIndex = 0;
+    }
+
+    /** increment the column iteration index
+     * The 'public' modifier has been added by Boris Poudérous for 'number-columns-spanned' processing
+     */
+    public void selectNextColumn()
+    {
+        m_colIndex++;
+    }
+
+    /** get current column width according to column iteration index
+     *  @return INVALID_COLUMN_WIDTH if we cannot find the value
+     *  The 'public' modifier has been added by Boris Poudérous for 'number-columns-spanned' processing
+     */
+    public float getColumnWidth()
+    {
+        try {
+            return ((Float)m_colWidths.get(m_colIndex)).floatValue();
+       } catch (IndexOutOfBoundsException ex) {
+            // this code contributed by Trembicki-Guy, Ed <GuyE@DNB.com>
+            log.warn("fo:table-column width not defined, using " + INVALID_COLUM_WIDTH);
+            return INVALID_COLUM_WIDTH;
+        }
+    }
+
+     /** Added by Boris Poudérous on 07/22/2002 */
+     public int getColumnIndex()
+     {
+       return m_colIndex;
+     }
+     /** - end - */
+
+     /** Added by Boris Poudérous on 07/22/2002 */
+     public int getNumberOfColumns()
+     {
+       return m_colWidths.size();
+     }
+     /** - end - */
+}
+
index c3d1a2d5f96a6dd13a83a69157f0c094a2bc05a9..6314e303a54005ae7488086fdd25cee9e4117685 100644 (file)
@@ -152,6 +152,7 @@ public interface ITableAttributes {
 //Table row attributes
     /** row attribute, keep-together */
     public static final String ROW_KEEP_TOGETHER = "trkeep";
+    public static final String ROW_HEIGHT = "trrh";
 
     /**
      * This control word is nonexistent in RTF, used to simulate the
index be05e4c776459d8fb929b551122a7f712230e055..a874dc21a30dc6ffb1440179f21f4a67401e6d1a 100755 (executable)
@@ -176,6 +176,10 @@ public class RtfTable extends RtfContainer {
         headerAttribs = attrs;
     }
 
+    public RtfAttributes getHeaderAttribs() {
+        return headerAttribs;
+    }
+
     /**
      * Added by Normand Masse
      * @return the table-header attributes if they are present, otherwise the