import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.HashMap;
+import java.util.TreeMap;
import org.apache.fop.traits.WritingModeTraitsGetter;
out.writeFloat((float) viewArea.getWidth());
out.writeFloat((float) viewArea.getHeight());
out.writeBoolean(clip);
- out.writeObject(traits);
+ out.writeObject((TreeMap)traits);
out.writeObject(regionReference);
}
viewArea = new Rectangle2D.Float(in.readFloat(), in.readFloat(),
in.readFloat(), in.readFloat());
clip = in.readBoolean();
- traits = (HashMap)in.readObject();
+ traits = (TreeMap)in.readObject();
setRegionReference((RegionReference) in.readObject());
}
RegionViewport rv = new RegionViewport((Rectangle2D)viewArea.clone());
rv.regionReference = (RegionReference)regionReference.clone();
if (traits != null) {
- rv.traits = new HashMap(traits);
+ rv.traits = new TreeMap(traits);
}
if (foreignAttributes != null) {
rv.foreignAttributes = new HashMap(foreignAttributes);
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.TreeMap;
import org.apache.fop.area.Area;
import org.apache.fop.area.Viewport;
out.writeFloat((float) contentPosition.getHeight());
}
out.writeBoolean(clip);
- out.writeObject(traits);
+ out.writeObject((TreeMap)traits);
out.writeObject(content);
}
in.readFloat());
}
this.clip = in.readBoolean();
- this.traits = (HashMap) in.readObject();
+ this.traits = (TreeMap) in.readObject();
this.content = (Area) in.readObject();
}
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfParagraphBreak;
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;
true, this);
RtfTextrun textrun = container.getTextrun();
+ RtfParagraphBreak par = textrun.addParagraphBreak();
+
+ RtfTableCell cellParent = (RtfTableCell)textrun.getParentOfClass(RtfTableCell.class);
+ if (cellParent != null && par != null) {
+ int iDepth = cellParent.findChildren(textrun);
+ cellParent.setLastParagraph(par, iDepth);
+ }
- textrun.addParagraphBreak();
int breakValue = toRtfBreakValue(bl.getBreakAfter());
textrun.popBlockAttributes(breakValue);
if (bDefer) {
return;
}
+ try {
+ RtfTableCell cell = (RtfTableCell)builderContext.getContainer(RtfTableCell.class, false, this);
+ cell.finish();
+
+ } catch (Exception e) {
+ log.error("endCell: " + e.getMessage());
+ throw new RuntimeException(e.getMessage());
+ }
builderContext.popContainer();
builderContext.getTableContext().selectNextColumn();
return children.size();
}
+ private int findChildren(RtfElement aChild, int iStart) {
+ for (Iterator it = this.getChildren().iterator(); it.hasNext();) {
+ final RtfElement e = (RtfElement)it.next();
+ if (aChild == e) {
+ return iStart;
+ } else if (e instanceof RtfContainer) {
+ int iFound = ((RtfContainer)e).findChildren(aChild, (iStart + 1));
+ if (iFound != -1) {
+ return iFound;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find the passed child in the current container
+ * @param aChild the child element
+ * @return the depth (nested level) inside the current container
+ */
+ public int findChildren(RtfElement aChild) {
+ return findChildren(aChild, 0);
+ }
+
/**
* Add by Boris Poudérous on 07/22/2002
* Set the children list
/** find the first parent where c.isAssignableFrom(parent.getClass()) is true
* @return null if not found
*/
- RtfElement getParentOfClass(Class c) {
+ public RtfElement getParentOfClass(Class c) {
RtfElement result = null;
RtfElement current = this;
while (current.parent != null) {
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.rtf.rtflib.rtfdoc;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/** Class which represents a paragraph break.*/
+
+public class RtfParagraphBreak extends RtfElement {
+ private static final String DEFAULT_PARAGRAPH = "par";
+
+ private String controlWord = DEFAULT_PARAGRAPH;
+
+ RtfParagraphBreak(RtfContainer parent, Writer w)
+ throws IOException {
+ super(parent, w);
+ }
+
+ /**
+ * @return true if this element would generate no "useful" RTF content
+ */
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /**
+ * write RTF code of all our children
+ * @throws IOException for I/O problems
+ */
+ protected void writeRtfContent() throws IOException {
+ if (controlWord != null ) {
+ writeControlWord(controlWord);
+ }
+ }
+
+ /**
+ * Whether or not the break can be skipped.
+ * If the paragraph marks a table cell end it is not possible
+ * @return boolean
+ */
+ public boolean canHide() {
+ return this.controlWord.equals ( DEFAULT_PARAGRAPH );
+ }
+
+ /**
+ * Sets a different control word for this paragraph. If this method
+ * is used the paragraph will always be displayed (@see canHide))
+ * @param controlWord the new control word
+ */
+ public void switchControlWord(String controlWord) {
+ this.controlWord = controlWord;
+ }
+}
private boolean setCenter;
private boolean setRight;
private int id;
+ private RtfParagraphBreak lastBreak = null;
+ private int lastBreakDepth = Integer.MIN_VALUE;
+
+ private static final String TABLE_CELL_PARAGRAPH = "cell";
+ private static final String TABLE_CELL_NESTED_PARAGRAPH = "nestcell";
/** default cell width (in twips ??) */
public static final int DEFAULT_CELL_WIDTH = 2000;
if (getRow().getTable().isNestedTable()) {
//nested table
- writeControlWordNS("nestcell");
+ if (lastBreak == null) {
+ writeControlWordNS("nestcell");
+ }
writeGroupMark(true);
writeControlWord("nonesttables");
writeControlWord("par");
//writeControlWord("par");
}
- writeControlWord("cell");
+ if (lastBreak == null) {
+ writeControlWord("cell");
+ }
}
}
return null;
}
+
+ /**
+ * The table cell decides whether or not a newly added paragraph break
+ * will be used to write the cell-end control word.
+ * For nested tables it is not necessary.
+ *
+ * @param parBreak the paragraph break element
+ * @param breakDepth The depth is necessary for picking the correct break element.
+ * If it is deeper inside the whole cell it will be used, and if there is something on
+ * the same level (depth) it is also set because the method is called for all breaks
+ * in the correct order.
+ */
+ public void setLastParagraph(RtfParagraphBreak parBreak, int breakDepth) {
+ if (parBreak != null && breakDepth >= lastBreakDepth) {
+ lastBreak = parBreak;
+ lastBreakDepth = breakDepth;
+ }
+ }
+
+ /**
+ * The last paragraph break was just stored before,
+ * now the control word is really switched
+ */
+ public void finish() {
+ //If it is nested and contains another table do not set it
+ if (getRow().getTable().isNestedTable() && table != null) {
+ lastBreak = null;
+ } else if (lastBreak != null) {
+ lastBreak.switchControlWord(
+ getRow().getTable().isNestedTable()
+ ? TABLE_CELL_NESTED_PARAGRAPH
+ : TABLE_CELL_PARAGRAPH);
+ }
+ }
}
}
}
- /** Class which represents a paragraph break.*/
- private class RtfParagraphBreak extends RtfElement {
-
- RtfParagraphBreak(RtfContainer parent, Writer w)
- throws IOException {
- super(parent, w);
- }
-
- /**
- * @return true if this element would generate no "useful" RTF content
- */
- public boolean isEmpty() {
- return false;
- }
-
- /**
- * write RTF code of all our children
- * @throws IOException for I/O problems
- */
- protected void writeRtfContent() throws IOException {
- writeControlWord("par");
- }
- }
-
/** Create an RTF container as a child of given container */
RtfTextrun(RtfContainer parent, Writer w, RtfAttributes attrs) throws IOException {
super(parent, w, attrs);
* Inserts paragraph break before all close group marks.
*
* @throws IOException for I/O problems
+ * @return The paragraph break element
*/
- public void addParagraphBreak() throws IOException {
- // get copy of children list
- List children = getChildren();
- Stack tmp = new Stack();
-
- // delete all previous CloseGroupMark
- int deletedCloseGroupCount = 0;
-
- ListIterator lit = children.listIterator(children.size());
- while (lit.hasPrevious()
- && (lit.previous() instanceof RtfCloseGroupMark)) {
- tmp.push(Integer.valueOf(((RtfCloseGroupMark)lit.next()).getBreakType()));
- 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(((Integer)tmp.pop()).intValue());
- }
- }
- }
+ public RtfParagraphBreak addParagraphBreak() throws IOException {
+ // get copy of children list
+ List children = getChildren();
+ Stack tmp = new Stack();
+ RtfParagraphBreak par = null;
+
+ // delete all previous CloseGroupMark
+ int deletedCloseGroupCount = 0;
+
+ ListIterator lit = children.listIterator(children.size());
+ while (lit.hasPrevious()
+ && (lit.previous() instanceof RtfCloseGroupMark)) {
+ tmp.push(Integer.valueOf(((RtfCloseGroupMark)lit.next()).getBreakType()));
+ lit.remove();
+ deletedCloseGroupCount++;
+ }
+
+ if (children.size() != 0) {
+ // add paragraph break and restore all deleted close group marks
+ setChildren(children);
+ par = new RtfParagraphBreak(this, writer);
+ for (int i = 0; i < deletedCloseGroupCount; i++) {
+ addCloseGroupMark(((Integer)tmp.pop()).intValue());
+ }
+ }
+ return par;
+ }
/**
* Inserts a leader.
* child.
* -If the RtfTextrun is the last child of its parent, write a
* RtfParagraphBreak only, if it is not the last child.
+ * -If the RtfParagraphBreak can not be hidden (e.g. a table cell requires it)
+ * it is also written
*/
boolean bHide = false;
bHide = bRtfParagraphBreak;
|| bFirst
|| (bSuppressLastPar && bLast && lastParagraphBreak != null
&& e == lastParagraphBreak)
- || bBookmark);
+ || bBookmark)
+ && ((RtfParagraphBreak)e).canHide();
if (!bHide) {
newLine();
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Code" dev="GA" type="fix" fixes-bug="51009" due-to="Max Aster">
+ RTF generates unexpected lines for blocks in tables. Also fix three findbugs issues.
+ </action>
<action context="Code" dev="GA" type="fix" fixes-bug="51007" due-to="Max Aster">
RTF tables do not support percent column-widths.
</action>