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?
RtfTextrun textrun = container.getTextrun();
textrun.addParagraphBreak();
- textrun.popAttributes();
+ textrun.popBlockAttributes();
} catch (IOException ioe) {
log.error("startBlock:" + ioe.getMessage());
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());
RtfTextrun textrun = container.getTextrun();
textrun.addParagraphBreak();
- textrun.popAttributes();
+ textrun.popBlockAttributes();
} catch (IOException ioe) {
log.error("startBlock:" + ioe.getMessage());
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());
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());
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());
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
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;
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 {
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 {