]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Bugzilla #36480:
authorJeremias Maerki <jeremias@apache.org>
Mon, 14 Nov 2005 18:02:14 +0000 (18:02 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 14 Nov 2005 18:02:14 +0000 (18:02 +0000)
Improved space-before/space-after support for RTF output. Fixes problems with space support in the existing code.
Submitted by: Sergey Simonchik <Sergey.Simonchik.at.borland.com>

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@344172 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/render/rtf/RTFHandler.java
src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceManager.java [new file with mode: 0644]
src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceSplitter.java [new file with mode: 0644]
src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java

index 3f85094e5daf3f6429220741d0dacba3dcb0842c..601a248647e9c326195959c211d3720b9f5ef3b8 100644 (file)
@@ -336,7 +336,7 @@ public class RTFHandler extends FOEventHandler {
             RtfTextrun textrun = container.getTextrun();
 
             textrun.addParagraphBreak();
-            textrun.pushAttributes(rtfAttr);
+            textrun.pushBlockAttributes(rtfAttr);
             textrun.addBookmark(bl.getId());
         } catch (IOException ioe) {
             // TODO could we throw Exception in all FOEventHandler events?
@@ -367,7 +367,7 @@ public class RTFHandler extends FOEventHandler {
             RtfTextrun textrun = container.getTextrun();
 
             textrun.addParagraphBreak();
-            textrun.popAttributes();
+            textrun.popBlockAttributes();
 
         } catch (IOException ioe) {
             log.error("startBlock:" + ioe.getMessage());
@@ -398,7 +398,7 @@ public class RTFHandler extends FOEventHandler {
             RtfTextrun textrun = container.getTextrun();
 
             textrun.addParagraphBreak();
-            textrun.pushAttributes(rtfAttr);
+            textrun.pushBlockAttributes(rtfAttr);
         } catch (IOException ioe) {
             // TODO could we throw Exception in all FOEventHandler events?
             log.error("startBlock: " + ioe.getMessage());
@@ -426,7 +426,7 @@ public class RTFHandler extends FOEventHandler {
             RtfTextrun textrun = container.getTextrun();
 
             textrun.addParagraphBreak();
-            textrun.popAttributes();
+            textrun.popBlockAttributes();
 
         } catch (IOException ioe) {
             log.error("startBlock:" + ioe.getMessage());
@@ -552,7 +552,7 @@ public class RTFHandler extends FOEventHandler {
                     IRtfTextrunContainer.class, true, this);
 
             RtfTextrun textrun = container.getTextrun();
-            textrun.pushAttributes(rtfAttr);
+            textrun.pushInlineAttributes(rtfAttr);
             textrun.addBookmark(inl.getId());
         } catch (IOException ioe) {
             log.error("startInline:" + ioe.getMessage());
@@ -581,7 +581,7 @@ public class RTFHandler extends FOEventHandler {
                     IRtfTextrunContainer.class, true, this);
 
             RtfTextrun textrun = container.getTextrun();
-            textrun.popAttributes();
+            textrun.popInlineAttributes();
         } catch (IOException ioe) {
             log.error("startInline:" + ioe.getMessage());
             throw new RuntimeException(ioe.getMessage());
@@ -1146,9 +1146,9 @@ public class RTFHandler extends FOEventHandler {
             RtfAttributes rtfAttr
                 = TextAttributesConverter.convertCharacterAttributes(text);
 
-            textrun.pushAttributes(rtfAttr);
+            textrun.pushInlineAttributes(rtfAttr);
             textrun.addString(new String(data, start, length - start));
-            textrun.popAttributes();
+            textrun.popInlineAttributes();
          } catch (IOException ioe) {
             // FIXME could we throw Exception in all FOEventHandler events?
             log.error("characters: " + ioe.getMessage());
diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceManager.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceManager.java
new file mode 100644 (file)
index 0000000..f734084
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.rtf.rtflib.rtfdoc;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * This class is responsible for saving space-before/space-after attributes 
+ * history and adding spacing to established candidates (i.e. attributes) or 
+ * accumulation spacing in case of candidate absence.
+ */
+public class RtfSpaceManager {
+    /** Stack for saving rtf block-level attributes. */
+    private LinkedList blockAttributes = new LinkedList();
+
+    /** Stack for saving rtf inline-level attributes. */
+    private LinkedList inlineAttributes = new LinkedList();
+
+    /**
+     * Keeps value of accumulated space in twips. For example if block has
+     * nonzero space-before or space-after properties and has no plain text
+     * inside, then the next block should has increased value of space-before
+     * property.
+     */
+    private int accumulatedSpace = 0;
+    
+    /**
+     * Construct a newly allocated <code>RtfSpaceManager</code> object.
+     */
+    public RtfSpaceManager() {
+    }
+
+    /**
+     * Iterates block-level stack (i.e. all open blocks) and stops updating 
+     * candidate for adding space-before/space-after attribute in case of 
+     * candidate presence.
+     */
+    public void stopUpdatingSpaceBefore() {
+        for (Iterator it = blockAttributes.iterator(); it.hasNext();) {
+            RtfSpaceSplitter splitter = (RtfSpaceSplitter) it.next();
+            if (splitter.isBeforeCadidateSet()) {
+                splitter.stopUpdatingSpaceBefore();
+            }
+        }
+    }
+    
+    /**
+     * Set attributes as candidate for space attributes inheritance.
+     * 
+     * @param attrs  attributes to set
+     */
+    public void setCandidate(RtfAttributes attrs) {
+        for (Iterator it = blockAttributes.iterator(); it.hasNext();) {
+            RtfSpaceSplitter splitter = (RtfSpaceSplitter) it.next();
+            splitter.setSpaceBeforeCandidate(attrs);
+            splitter.setSpaceAfterCandidate(attrs);
+        }
+    }
+    
+    /**
+     * Builds RtfSpaceSplitter on <code>attrs</code> and adds it to the 
+     * block-level stack.
+     * 
+     * @param attrs  RtfAttribute to add
+     * @return instance of RtfSpaceSplitter
+     */
+    public RtfSpaceSplitter pushRtfSpaceSplitter(RtfAttributes attrs) {
+        RtfSpaceSplitter splitter;
+        splitter = new RtfSpaceSplitter(attrs, accumulatedSpace);
+        // set accumulatedSpace to 0, because now accumulatedSpace used 
+        // in splitter
+        accumulatedSpace = 0;
+        blockAttributes.addLast(splitter);
+        return splitter;
+    }
+    
+    /**
+     * Removes RtfSpaceSplitter from top of block-level stack.
+     */
+    public void popRtfSpaceSplitter() {
+        if (!blockAttributes.isEmpty()) {
+            RtfSpaceSplitter splitter;
+            splitter = (RtfSpaceSplitter) blockAttributes.removeLast();
+            accumulatedSpace += splitter.flush();
+        }
+    }
+
+    /**
+     * Pushes inline attributes to inline-level stack.
+     * 
+     * @param attrs attributes to add
+     */
+    public void pushInlineAttributes(RtfAttributes attrs) {
+        inlineAttributes.addLast(attrs);
+    }
+
+    /**
+     * Pops inline attributes from inline-level stack.
+     */
+    public void popInlineAttributes() {
+        if (!inlineAttributes.isEmpty()) {
+            inlineAttributes.removeLast();
+        }
+    }
+
+    /**
+     * Peeks at inline-level attribute stack.
+     * 
+     * @return RtfAttributes from top of inline-level stack
+     */
+    public RtfAttributes getLastInlineAttribute() {
+        return (RtfAttributes) inlineAttributes.getLast();
+    }
+}
diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceSplitter.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSpaceSplitter.java
new file mode 100644 (file)
index 0000000..d42d4a5
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.rtf.rtflib.rtfdoc;
+
+/**
+ * This class splits block attributes into space-before attribute, space-after
+ * attribute and common attributes.
+ */
+public class RtfSpaceSplitter {
+
+    /** Common attributes for all text. */
+    private RtfAttributes commonAttributes;
+
+    /** Space-before attributes of a block. */
+    private int spaceBefore;
+
+    /** Space-after attributes of a block. */
+    private int spaceAfter;
+
+    /** Indicate that we can update candidate for space-before. */
+    private boolean updatingSpaceBefore;
+
+    /** Candidate for adding space-before. */
+    private RtfAttributes spaceBeforeCandidate;
+
+    /** Candidate for adding space-before. */
+    private RtfAttributes spaceAfterCandidate;
+
+    /**
+     * Create RtfSpaceSplitter with given RtfAttributes.
+     * 
+     * @param attrs  RtfAttributes for splitting
+     * @param previousSpace  integer, representing accumulated spacing
+     */
+    public RtfSpaceSplitter(RtfAttributes attrs, int previousSpace) {
+        commonAttributes = attrs;
+        updatingSpaceBefore = true;
+        spaceBeforeCandidate = null;
+        spaceAfterCandidate = null;
+
+        spaceBefore = split(RtfText.SPACE_BEFORE) + previousSpace;
+        spaceAfter = split(RtfText.SPACE_AFTER);
+    }
+
+    /**
+     * Remove attributes with name <code>key</code> from
+     * <code>commonAttributes</code> and return it as int.
+     * 
+     * @param key  attributes name to extract
+     * @return integer, representing value of extracted attributes
+     */
+    public int split(String key) {
+        Integer i = (Integer) commonAttributes.getValue(key);
+        if (i == null) {
+            i = new Integer(0);
+        }
+
+        commonAttributes.unset(key);
+        return i.intValue();
+    }
+
+    /** @return attributes, applicable to whole block. */
+    public RtfAttributes getCommonAttributes() {
+        return commonAttributes;
+    }
+
+    /** @return space-before value. */
+    public int getSpaceBefore() {
+        return spaceBefore;
+    }
+
+    /** 
+     * Sets a candidate for space-before property.
+     * 
+     * @param candidate  instance of <code>RtfAttributes</code>, considered as 
+     *        a candidate for space-before adding
+     */
+    public void setSpaceBeforeCandidate(RtfAttributes candidate) {
+        if (updatingSpaceBefore) {
+            this.spaceBeforeCandidate = candidate;
+        }
+    }
+
+    /** 
+     * Sets a candidate for space-after property.
+     * 
+     * @param candidate  instance of <code>RtfAttributes</code>, considered as 
+     *        a candidate for space-after adding
+     */
+    public void setSpaceAfterCandidate(RtfAttributes candidate) {
+        this.spaceAfterCandidate = candidate;
+    }
+
+    /** @return true, if candidate for space-before is set. */
+    public boolean isBeforeCadidateSet() {
+        return spaceBeforeCandidate != null;
+    }
+
+    /** @return true, if candidate for space-after is set. */
+    public boolean isAfterCadidateSet() {
+        return spaceAfterCandidate != null;
+    }
+    
+    /**
+     * Stops updating candidates for space-before attribute.
+     */
+    public void stopUpdatingSpaceBefore() {
+        updatingSpaceBefore = false;
+    } 
+
+    /**
+     * Adds corresponding attributes to their candidates.
+     * 
+     * @return integer, representing value of space-before/space-after 
+     *   attributes, that can't be added anywhere (i.e. these attributes 
+     *   hasn't their candidates)
+     */
+    public int flush() {
+        int accumulatingSpace = 0;
+        if (!isBeforeCadidateSet()) {
+            accumulatingSpace += spaceBefore;
+        } else {
+            spaceBeforeCandidate.addIntegerValue(spaceBefore,
+                    RtfText.SPACE_BEFORE);
+        }
+
+        if (!isAfterCadidateSet()) {
+            accumulatingSpace += spaceAfter;
+        } else {
+            spaceAfterCandidate.addIntegerValue(spaceAfter, 
+                            RtfText.SPACE_AFTER);
+        }
+
+        return accumulatingSpace;
+    }
+}
index 56316bbc8a0d6d87aec0d21be1eec9cb2d6fc5c1..a919c555e19b6d6abd8d1a8878047e4527d3cc5b 100644 (file)
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.io.Writer;
 import java.util.List;
 import java.util.Iterator;
+import java.util.ListIterator;
 
 // FOP
 import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
@@ -43,6 +44,9 @@ public class RtfTextrun extends RtfContainer {
     private boolean bSuppressLastPar = false;
     private RtfListItem rtfListItem;
     
+    /** Manager for handling space-* property. */
+    private RtfSpaceManager rtfSpaceManager = new RtfSpaceManager();
+    
     /**  Class which represents the opening of a RTF group mark.*/
     private class RtfOpenGroupMark extends RtfElement {
                 
@@ -121,24 +125,121 @@ public class RtfTextrun extends RtfContainer {
         super(parent, w, attrs);
     }
     
-    public void pushAttributes(RtfAttributes attrs) throws IOException {
+    
+    /**
+     * Adds instance of <code>OpenGroupMark</code> as a child with attributes.
+     * 
+     * @param attrs  attributes to add
+     * @throws IOException for I/O problems
+     */
+    public void addOpenGroupMark(RtfAttributes attrs) throws IOException {
         RtfOpenGroupMark r = new RtfOpenGroupMark(this, writer, attrs);
     }
-    
-    public void popAttributes() throws IOException {
+
+    /**
+     * Adds instance of <code>CloseGroupMark</code> as a child.
+     * 
+     * @throws IOException for I/O problems
+     */
+    public void addCloseGroupMark() throws IOException {
         RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer);
     }
     
+    /**
+     * Pushes block attributes, notifies all opened blocks about pushing block 
+     * attributes, adds <code>OpenGroupMark</code> as a child.
+     * 
+     * @param attrs  the block attributes to push
+     * @throws IOException for I/O problems
+     */
+    public void pushBlockAttributes(RtfAttributes attrs) throws IOException {
+        rtfSpaceManager.stopUpdatingSpaceBefore();
+        RtfSpaceSplitter splitter = rtfSpaceManager.pushRtfSpaceSplitter(attrs);
+        addOpenGroupMark(splitter.getCommonAttributes());
+    }
+    
+    /**
+     * Pops block attributes, notifies all opened blocks about pushing block 
+     * attributes, adds <code>CloseGroupMark</code> as a child.
+     * 
+     * @throws IOException for I/O problems
+     */
+    public void popBlockAttributes() throws IOException {
+        rtfSpaceManager.popRtfSpaceSplitter();
+        rtfSpaceManager.stopUpdatingSpaceBefore();
+        addCloseGroupMark();
+    }
+
+    /**
+     * Pushes inline attributes.
+     * 
+     * @param attrs  the inline attributes to push
+     * @throws IOException for I/O problems
+     */
+    public void pushInlineAttributes(RtfAttributes attrs) throws IOException {
+        rtfSpaceManager.pushInlineAttributes(attrs);
+        addOpenGroupMark(attrs);
+    }
+
+    /**
+     * Pop inline attributes.
+     * 
+     * @throws IOException for I/O problems
+     */
+    public void popInlineAttributes() throws IOException {
+        rtfSpaceManager.popInlineAttributes();
+        addCloseGroupMark();
+    }
+    
+    /**
+     * Add string to children list.
+     * 
+     * @param s  string to add
+     * @throws IOException for I/O problems
+     */
     public void addString(String s) throws IOException {
+        if (s.equals("")) {
+            return;
+        }
+        RtfAttributes attrs = rtfSpaceManager.getLastInlineAttribute();
+        //add RtfSpaceSplitter to inherit accumulated space
+        rtfSpaceManager.pushRtfSpaceSplitter(attrs);
+        rtfSpaceManager.setCandidate(attrs);
         RtfString r = new RtfString(this, writer, s);
+        rtfSpaceManager.popRtfSpaceSplitter();
     }
     
     public RtfFootnote addFootnote() throws IOException {
         return new RtfFootnote(this, writer);
     }
     
+    /**
+     * Inserts paragraph break before all close group marks.
+     * 
+     * @throws IOException  for I/O problems
+     */
     public void addParagraphBreak() throws IOException {
-        RtfParagraphBreak r = new RtfParagraphBreak(this, writer);
+        // get copy of children list
+        List children = getChildren();
+
+        // delete all previous CloseGroupMark
+        int deletedCloseGroupCount = 0;
+
+        ListIterator lit = children.listIterator(children.size());
+        while (lit.hasPrevious()
+                && (lit.previous() instanceof RtfCloseGroupMark)) {
+            lit.remove();
+            deletedCloseGroupCount++;
+        }
+
+        if (children.size() != 0) {
+            // add paragraph break and restore all deleted close group marks
+            setChildren(children);
+            new RtfParagraphBreak(this, writer);
+            for (int i = 0; i < deletedCloseGroupCount; i++) {
+                addCloseGroupMark();
+            }
+        }
     }
     
     public void addPageNumber(RtfAttributes attr) throws IOException {