/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.build;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.function.ProcessingContext;
import org.pentaho.reporting.engine.classic.core.layout.InlineSubreportMarker;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.states.ReportStateKey;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
public class FooterLayoutModelBuilder extends LayoutModelBuilderWrapper
{
private static final Log logger = LogFactory.getLog(FooterLayoutModelBuilder.class);
private ArrayList<RenderNode> slots;
private int slotCounter;
private RenderBox parentBox;
private int inBoxDepth;
private ReportStateKey stateKey;
private boolean empty;
private OutputProcessorMetaData metaData;
public FooterLayoutModelBuilder(final LayoutModelBuilder backend)
{
super(backend);
backend.setLimitedSubReports(true);
backend.setCollapseProgressMarker(false);
this.slots = new ArrayList<RenderNode>();
}
public void initialize(final ProcessingContext metaData,
final RenderBox parentBox,
final RenderNodeFactory renderNodeFactory)
{
this.parentBox = parentBox;
getParent().initialize(metaData, parentBox, renderNodeFactory);
this.metaData = metaData.getOutputProcessorMetaData();
}
public void setLimitedSubReports(final boolean limitedSubReports)
{
}
public void updateState(final ReportStateKey stateKey)
{
this.stateKey = stateKey;
getParent().updateState(stateKey);
}
public InstanceID startBox(final ReportElement element)
{
InstanceID instanceID = getParent().startBox(element);
if (inBoxDepth == 0)
{
if (logger.isDebugEnabled())
{
logger.debug("Started a Box: " + slotCounter + " " + element);
}
}
inBoxDepth += 1;
return instanceID;
}
public void startSection(final ReportElement element, final int sectionSize)
{
throw new UnsupportedOperationException("Global sections cannot be started for page headers");
}
public InlineSubreportMarker processSubReport(final SubReport element)
{
throw new UnsupportedOperationException("SubReports cannot be started for page headers");
}
public boolean finishBox()
{
if (inBoxDepth == 1)
{
empty &= super.isEmpty();
}
super.finishBox();
inBoxDepth -= 1;
if (inBoxDepth == 0)
{
slotCounter += 1;
if (logger.isDebugEnabled())
{
logger.debug("Finshed a Box: " + slotCounter + " - empty: " + super.isEmpty());
}
return super.isEmpty();
}
return empty;
}
public boolean isEmpty()
{
if (inBoxDepth == 0)
{
return empty;
}
return super.isEmpty();
}
public void endSubFlow()
{
throw new UnsupportedOperationException("SubReport sections cannot be started for page headers");
}
public void addProgressMarkerBox()
{
super.addProgressMarkerBox();
slotCounter += 1;
}
public void addManualPageBreakBox(final long range)
{
throw new UnsupportedOperationException("PageBreak sections cannot be started for page headers");
}
public LayoutModelBuilder deriveForStorage(final RenderBox clonedContent)
{
final FooterLayoutModelBuilder clone = (FooterLayoutModelBuilder) super.deriveForStorage(clonedContent);
clone.slots = (ArrayList<RenderNode>) slots.clone();
clone.slots.clear();
clone.parentBox = clonedContent;
return clone;
}
public LayoutModelBuilder deriveForPageBreak()
{
final FooterLayoutModelBuilder clone = (FooterLayoutModelBuilder) super.deriveForPageBreak();
clone.slots = (ArrayList<RenderNode>) slots.clone();
clone.slots.clear();
return clone;
}
public void startSection()
{
empty = true;
slots.clear();
slotCounter = 0;
// check what slots are filled and update the list
final RenderNode firstChild = parentBox.getFirstChild();
if (firstChild instanceof RenderBox)
{
final RenderBox slottedContent = (RenderBox) firstChild;
RenderNode box = slottedContent.getFirstChild();
if (logger.isDebugEnabled())
{
logger.debug("Start Section: " + parentBox);
logger.debug(" Section: " + slottedContent);
logger.debug(" Section: " + box);
logger.debug(" Key : " + stateKey);
}
boolean sticky = false;
while (box != null)
{
if (box.getStyleSheet().getBooleanStyleProperty(BandStyleKeys.STICKY))
{
sticky = true;
}
if (sticky)
{
if (logger.isDebugEnabled())
{
logger.debug("Added Slot[]: " + box);
logger.debug(" Slot[]: " + box.getElementType());
logger.debug(" Slot[]: " + box.getStateKey());
}
slots.add(box);
}
box = box.getNext();
}
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("Added Reverse Section: " + slotCounter + " " + slots.size() + " " + firstChild);
}
}
if (logger.isDebugEnabled())
{
logger.debug("Clear Footer for new print.");
}
parentBox.clear();
super.startSection();
}
public void endSection()
{
if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY))
{
super.legacyFlagNotEmpty();
}
super.endSection();
/**
* DOCMARK: This is a incomplete fix for PRD-3620 - this fix needs some work as the layouter code has
* changed significantly since PRD-3.9 and currently does not behave exactly like the old version.
*
* To make sticky page-footers behave correctly, we need to ensure that progress-marker are not merged
* and that empty bands produce exactly one progress marker.
*/
if (logger.isDebugEnabled())
{
logger.debug("Slot counter: " + slotCounter + " " + slots.size());
for (int i = 0; i < slots.size(); i++)
{
final RenderNode renderNode = slots.get(i);
logger.debug("Slots[" + i + "]: " + renderNode);
logger.debug(" [" + i + "]: " + renderNode.getStateKey());
}
}
// this is not correct ... we should insert the new band before the old one ..
final RenderNode firstChild = parentBox.getFirstChild();
if (slotCounter < slots.size() &&
(firstChild.getLayoutNodeType() & LayoutNodeTypes.MASK_BOX) == LayoutNodeTypes.MASK_BOX)
{
final ArrayList<RenderNode> childsAdded = new ArrayList<RenderNode>();
// Store the added children until we need them ..
final RenderBox sectionBox = (RenderBox) firstChild;
RenderNode child = sectionBox.getFirstChild();
while (child != null)
{
final RenderNode next = child.getNext();
sectionBox.remove(child);
childsAdded.add(child);
if (logger.isDebugEnabled())
{
logger.debug("New[" + "]: " + child);
}
child = next;
}
sectionBox.clear();
// first insert the saved ones ...
for (int i = slots.size() - slotCounter - 1; i >= 0; i--)
{
final RenderNode node = slots.get(i);
final RenderNode derived = node.derive(true);
if (logger.isDebugEnabled())
{
logger.debug("Rescued[" + i + "]: " + slots.get(i));
}
sectionBox.addGeneratedChild(derived);
}
for (int i = 0; i < childsAdded.size(); i++)
{
final RenderNode node = childsAdded.get(i);
if (logger.isDebugEnabled())
{
logger.debug("New[" + "]: " + node);
}
sectionBox.addGeneratedChild(node);
}
}
}
public InstanceID createSubflowPlaceholder(final ReportElement element)
{
throw new UnsupportedOperationException("SubReport sections cannot be started for page headers");
}
public void startSubFlow(final InstanceID insertationPoint)
{
throw new UnsupportedOperationException("SubReport sections cannot be started for page headers");
}
public void startSubFlow(final ReportElement element)
{
throw new UnsupportedOperationException("SubReport sections cannot be started for page headers");
}
public void suspendSubFlow()
{
throw new UnsupportedOperationException("SubReport sections cannot be started for page headers");
}
}