private PercentContext percentManager = new PercentContext();
+
/**
* Creates a new RTF structure handler.
* @param userAgent the FOUserAgent for this process
return;
} else {
- builderContext.popContainer();
+ builderContext.popContainer(RtfSection.class, this);
this.pagemaster = null;
}
}
//just do nothing
} else if (regionBefore != null
&& fl.getFlowName().equals(regionBefore.getRegionName())) {
- builderContext.popContainer();
+ builderContext.popContainer(RtfBefore.class, this);
} else if (regionAfter != null
&& fl.getFlowName().equals(regionAfter.getRegionName())) {
- builderContext.popContainer();
+ builderContext.popContainer(RtfAfter.class, this);
}
} catch (Exception e) {
log.error("endFlow: " + e.getMessage());
nestedTableDepth--;
builderContext.popTableContext();
- builderContext.popContainer();
+ builderContext.popContainer(RtfTable.class, this);
}
/** {@inheritDoc} */
/** {@inheritDoc} */
public void startHeader(TableHeader header) {
+ builderContext.pushPart(header);
startPart(header);
}
/** {@inheritDoc} */
public void endHeader(TableHeader header) {
+ builderContext.popPart(header.getClass(), this);
endPart(header);
}
/** {@inheritDoc} */
public void startFooter(TableFooter footer) {
+ builderContext.pushPart(footer);
startPart(footer);
}
/** {@inheritDoc} */
public void endFooter(TableFooter footer) {
+ builderContext.popPart(footer.getClass(), this);
endPart(footer);
}
* {@inheritDoc}
*/
public void startBody(TableBody body) {
+ builderContext.pushPart(body);
startPart(body);
}
/** {@inheritDoc} */
public void endBody(TableBody body) {
+ builderContext.popPart(TableBody.class, this);
endPart(body);
}
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfTableRow.class, this);
builderContext.getTableContext().decreaseRowSpannings();
}
throw new RuntimeException(e.getMessage());
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfTableCell.class, this);
builderContext.getTableContext().selectNextColumn();
}
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfList.class, this);
}
/** {@inheritDoc} */
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfListItem.class, this);
}
/** {@inheritDoc} */
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfListItemLabel.class, this);
}
/** {@inheritDoc} */
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfHyperLink.class, this);
}
/** {@inheritDoc} */
return;
}
- builderContext.popContainer();
+ builderContext.popContainer(RtfFootnote.class, this);
}
/** {@inheritDoc} */
}
}
+ /**
+ * Closes any mismatched tags that are detected in the RTF structure.
+ * @param containerClass The class representing the tag to close.
+ * @return Determines whether the tag mismatch has been handled.
+ */
+ public boolean endContainer(Class containerClass) {
+ if (containerClass == RtfTableRow.class) {
+ endRow(null);
+ return true;
+ }
+ return false;
+ }
+
/**
* Calls the event handlers for the passed FONode and all its elements.
*
--- /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;
+
+import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable;
+import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow;
+import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
+
+/**
+ * This class creates objects which are missing from the XSL:FO but are required
+ * by the RTF format.
+ */
+public class RTFPlaceHolderHelper {
+ /** The context object for building the RTF */
+ private BuilderContext builderContext;
+
+ /**
+ * Creates a new instance for the RTF place holder which attempts to resolve
+ * mismatches in structure between XSL:FO and RTF.
+ * @param builderContext The builder context
+ */
+ public RTFPlaceHolderHelper(BuilderContext builderContext) {
+ this.builderContext = builderContext;
+ }
+
+ /**
+ * A method to create an object which is missing and required from the
+ * RTF structure.
+ * @param containerClass The class which is missing
+ * @throws Exception
+ */
+ public void createRTFPlaceholder(Class containerClass) throws RtfException {
+ if (containerClass == RtfTableRow.class) {
+ createRtfTableRow();
+ }
+ }
+
+ private void createRtfTableRow() throws RtfException {
+ try {
+ RtfContainer element = builderContext.getContainer(RtfTable.class, true, null);
+ if (element != null && element instanceof RtfTable) {
+ RtfTable table = (RtfTable)element;
+ RtfAttributes attribs = new RtfAttributes();
+ RtfTableRow newRow = table.newTableRow(attribs);
+ builderContext.pushContainer(newRow);
+ builderContext.getTableContext().selectFirstColumn();
+ }
+ } catch (Exception ex) {
+ throw new RtfException(ex.getMessage());
+ }
+ }
+}
import java.util.Stack;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.render.rtf.RTFHandler;
+import org.apache.fop.render.rtf.RTFPlaceHolderHelper;
import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfOptions;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfContainer;
*/
public class BuilderContext {
+
+ /** Static logging instance */
+ protected static final Log LOG = LogFactory.getLog(BuilderContext.class.getName());
+
/** stack of RtfContainers */
private final Stack containers = new Stack();
* @throws RtfException if not caught
*/
public RtfContainer getContainer(Class containerClass, boolean required,
- Object /*IBuilder*/ forWhichBuilder) throws RtfException {
+ Object forWhichBuilder) throws RtfException {
// 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(containers,
+ RtfContainer result = (RtfContainer)getObjectFromStack(containers,
containerClass);
if (result == null && required) {
- throw new RtfException(
- "No RtfContainer of class '" + containerClass.getName()
- + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
- );
+ RTFPlaceHolderHelper placeHolderHelper = new RTFPlaceHolderHelper(this);
+ placeHolderHelper.createRTFPlaceholder(containerClass);
+ result = getContainer(containerClass, required, forWhichBuilder);
+ if (result == null) {
+ throw new RtfException(
+ "No RtfContainer of class '" + containerClass.getName()
+ + "' available for '" + forWhichBuilder.getClass().getName() + "' builder"
+ );
+ }
}
return result;
containers.push(c);
}
+ /**
+ * Push a Class representing a non-writeable section of the FO tree
+ * @param part the part
+ */
+ public void pushPart(FObj part) {
+ containers.push(part);
+ }
+
/**
* In some cases an RtfContainer must be replaced by another one on the
* stack. This happens when handling nested fo:blocks for example: after
}
/** pop the topmost RtfContainer from our stack */
- public void popContainer() {
- containers.pop();
+ public void popContainer(Class containerClass, RTFHandler handler) {
+ handlePop(containerClass, handler);
+ }
+
+ /** pop the topmost part class from our stack */
+ public void popPart(Class part, RTFHandler handler) {
+ handlePop(part, handler);
+ }
+
+ /**
+ * This method checks for any tag mismatches between what is being closed
+ * and what exists on the stack. If a mismatch is found, then it will push
+ * the object back onto the stack and attempt to close the given section
+ * before retrying with the current pop task.
+ * @param aClass The class to be popped from the stack
+ * @param handler The RTF handler class to fix any mismatches
+ */
+ private void handlePop(Class aClass, RTFHandler handler) {
+ Object object = containers.pop();
+ if (object.getClass() != aClass) {
+ pushAndClose(aClass, object, handler);
+ }
+ }
+
+ private void pushAndClose(Class aClass, Object object, RTFHandler handler) {
+ containers.push(object);
+ if (handler.endContainer(object.getClass())) {
+ popContainer(aClass, handler);
+ } else {
+ /* This should never happen unless a placeholder is not catered for
+ * in the RTFHandler.endContainer method. */
+ LOG.warn("Unhandled RTF structure tag mismatch detected between " +
+ aClass.getSimpleName() + " and "+object.getClass().getSimpleName());
+ }
}
/* push an IBuilder to our stack /