Package org.pentaho.reporting.engine.classic.core.layout.build

Source Code of org.pentaho.reporting.engine.classic.core.layout.build.DefaultLayoutModelBuilder

/*!
* 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.awt.Shape;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.Group;
import org.pentaho.reporting.engine.classic.core.GroupBody;
import org.pentaho.reporting.engine.classic.core.ImageContainer;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.filter.types.bands.SubReportType;
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.ModelPrinter;
import org.pentaho.reporting.engine.classic.core.layout.TextProducer;
import org.pentaho.reporting.engine.classic.core.layout.model.BlockRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.ProgressMarkerRenderBox;
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.model.RenderableReplacedContentBox;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition;
import org.pentaho.reporting.engine.classic.core.layout.model.context.StaticBoxLayoutProperties;
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.layout.style.DynamicHeightWrapperStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.DynamicReplacedContentStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.NonDynamicHeightWrapperStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.NonDynamicReplacedContentStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.SimpleStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.SubReportStyleSheet;
import org.pentaho.reporting.engine.classic.core.states.ReportStateKey;
import org.pentaho.reporting.engine.classic.core.states.process.SubReportProcessType;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.BorderStyle;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleKey;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.engine.classic.core.util.ReportDrawable;
import org.pentaho.reporting.engine.classic.core.util.ShapeDrawable;
import org.pentaho.reporting.libraries.resourceloader.factory.drawable.DrawableWrapper;

public class DefaultLayoutModelBuilder implements LayoutModelBuilder, Cloneable
{
  private static final Log logger = LogFactory.getLog(DefaultLayoutModelBuilder.class);

  private OutputProcessorMetaData metaData;
  private ReportStateKey stateKey;
  private LayoutModelBuilderContext context;
  private RenderNodeFactory renderNodeFactory;
  private TextProducer textProducer;

  private boolean strictLegacyMode;
  private boolean limitedSubReports;
  private boolean collapseProgressMarker;
  private ProcessingContext processingContext;
  private String legacySectionName;
  private boolean designtime;

  public DefaultLayoutModelBuilder()
  {
    this("Section-0");
  }

  public DefaultLayoutModelBuilder(final String legacySectionName)
  {
    this.collapseProgressMarker = true;
    this.legacySectionName = legacySectionName;
  }

  protected boolean isAllowMergeSection()
  {
    return limitedSubReports == false;
  }

  public void initialize(final ProcessingContext processingContext,
                         final RenderBox parentBox,
                         final RenderNodeFactory renderNodeFactory)
  {
    if (parentBox == null)
    {
      throw new NullPointerException();
    }
    if (processingContext == null)
    {
      throw new NullPointerException();
    }

    if (this.processingContext != processingContext)
    {
      this.processingContext = processingContext;
      this.metaData = processingContext.getOutputProcessorMetaData();
      this.strictLegacyMode = metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY);
      this.designtime = metaData.isFeatureSupported(OutputProcessorFeature.DESIGNTIME);

      this.renderNodeFactory = renderNodeFactory;
      this.textProducer = createTextProducer();
    }

    this.context = new DefaultLayoutModelBuilderContext(null, parentBox);
  }

  protected TextProducer createTextProducer()
  {
    return new TextProducer(metaData);
  }

  protected ProcessingContext getProcessingContext()
  {
    return processingContext;
  }

  public OutputProcessorMetaData getMetaData()
  {
    return metaData;
  }

  public void updateState(final ReportStateKey stateKey)
  {
    this.stateKey = stateKey;
  }

  public InstanceID startBox(final ReportElement element)
  {
    final StyleSheet computedStyle = element.getComputedStyle();
    final String layout = (String) computedStyle.getStyleProperty(BandStyleKeys.LAYOUT, BandStyleKeys.LAYOUT_CANVAS);
    return startBox(element, computedStyle, layout, false);
  }

  private InstanceID startBox(final ReportElement element,
                        final StyleSheet styleSheet,
                        final String layout,
                        final boolean auto)
  {
    closeAutoGeneratedPostfixBoxes();

    if (BandStyleKeys.LAYOUT_AUTO.equals(layout))
    {
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
    }
    else if (BandStyleKeys.LAYOUT_INLINE.equals(layout))
    {
      if (this.context.getRenderBox().isAcceptInlineBoxes() == false)
      {
        // parent context is not a inline-inside context.
        // So we need to create a auto-paragraph wrapper to open a inline-context
        this.context = new DefaultLayoutModelBuilderContext
            (this.context, renderNodeFactory.createAutoParagraph(element, styleSheet, stateKey));

        // PRD-3750 - A empty inline-band that creates a auto-paragraph reserves space on the vertical axis.
        if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY) ||
            metaData.isFeatureSupported(OutputProcessorFeature.PRD_3750))
        {
          this.context.setAutoGeneratedWrapperBox(true);

          this.context = new DefaultLayoutModelBuilderContext(this.context,
              renderNodeFactory.produceRenderBox(element, styleSheet, DefaultRenderNodeFactory.LAYOUT_PARAGRAPH_LINEBOX, stateKey));
        }
      }
      else
      {
        this.context = new DefaultLayoutModelBuilderContext
            (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
      }
    }
    else if (this.context.getRenderBox().isAcceptInlineBoxes())
    {
      // inline elements only accept inline element childs
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, BandStyleKeys.LAYOUT_INLINE, stateKey));
    }
    else if (BandStyleKeys.LAYOUT_TABLE_CELL.equals(layout))
    {
      // a table body always needs a table parent ..
      if (LayoutNodeTypes.TYPE_BOX_TABLE_ROW != this.context.getRenderBox().getLayoutNodeType())
      {
        startBox(element, renderNodeFactory.createAutoGeneratedSectionStyleSheet(styleSheet),
            BandStyleKeys.LAYOUT_TABLE_ROW, true);
      }
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
    }
    else if (BandStyleKeys.LAYOUT_TABLE_ROW.equals(layout))
    {
      // a table body always needs a table parent ..
      if (LayoutNodeTypes.TYPE_BOX_TABLE_SECTION != this.context.getRenderBox().getLayoutNodeType())
      {
        startBox(element, renderNodeFactory.createAutoGeneratedSectionStyleSheet(styleSheet),
            BandStyleKeys.LAYOUT_TABLE_BODY, true);
      }
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
    }
    else if (BandStyleKeys.LAYOUT_TABLE_BODY.equals(layout) ||
        BandStyleKeys.LAYOUT_TABLE_FOOTER.equals(layout) ||
        BandStyleKeys.LAYOUT_TABLE_HEADER.equals(layout))
    {
      // a table body always needs a table parent ..
      if (LayoutNodeTypes.TYPE_BOX_TABLE != this.context.getRenderBox().getLayoutNodeType())
      {
        startBox(element, renderNodeFactory.createAutoGeneratedSectionStyleSheet(styleSheet),
            BandStyleKeys.LAYOUT_TABLE, true);
      }
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
    }
    else
    {
      // handle ordinary elements, block, canvas, row ..
      this.context = new DefaultLayoutModelBuilderContext
          (this.context, renderNodeFactory.produceRenderBox(element, styleSheet, layout, stateKey));
    }

    this.context.setAutoGeneratedWrapperBox(auto);
    this.context.setEmpty(isEmptyElement(element, styleSheet, metaData));
    if (!auto)
    {
      if (isControlBand(styleSheet))
      {
        this.context.getRenderBox().getStaticBoxLayoutProperties().setPlaceholderBox
            (StaticBoxLayoutProperties.PlaceholderType.SECTION);
      }
      else
      {
        this.context.getRenderBox().getStaticBoxLayoutProperties().setPlaceholderBox
            (StaticBoxLayoutProperties.PlaceholderType.NONE);
      }
    }
    this.textProducer.startText();
    return this.context.getRenderBox().getInstanceId();
  }


  private static boolean isEmptyElement(final ReportElement band,
                                        final StyleSheet style,
                                        final OutputProcessorMetaData metaData)
  {
    if (isControlBand(style))
    {
      return false;
    }

    if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY))
    {
      if (band instanceof Band)
      {
        final Band b = (Band) band;
        if (b.getElementCount() > 0)
        {
          return false;
        }
      }
    }

    if (BandStyleKeys.LAYOUT_AUTO.equals(style.getStyleProperty(BandStyleKeys.LAYOUT)))
    {
      // A auto-band is considered empty.
      return true;
    }

    // A band is not empty, if it has a defined minimum or preferred height
    if (isLengthDefined(ElementStyleKeys.HEIGHT, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.WIDTH, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.POS_Y, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.POS_X, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.MIN_HEIGHT, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.MIN_WIDTH, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.PADDING_TOP, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.PADDING_LEFT, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.PADDING_BOTTOM, style))
    {
      return false;
    }
    if (isLengthDefined(ElementStyleKeys.PADDING_RIGHT, style))
    {
      return false;
    }
    if (BorderStyle.NONE.equals
        (style.getStyleProperty(ElementStyleKeys.BORDER_BOTTOM_STYLE, BorderStyle.NONE)) == false)
    {
      return false;
    }
    if (BorderStyle.NONE.equals(style.getStyleProperty(ElementStyleKeys.BORDER_TOP_STYLE, BorderStyle.NONE)) == false)
    {
      return false;
    }
    if (BorderStyle.NONE.equals(style.getStyleProperty(ElementStyleKeys.BORDER_LEFT_STYLE, BorderStyle.NONE)) == false)
    {
      return false;
    }
    if (BorderStyle.NONE.equals
        (style.getStyleProperty(ElementStyleKeys.BORDER_RIGHT_STYLE, BorderStyle.NONE)) == false)
    {
      return false;
    }
    if (style.getStyleProperty(ElementStyleKeys.BACKGROUND_COLOR) != null)
    {
      return false;
    }

    if (metaData.isExtraContentElement(band.getStyle(), band.getAttributes()))
    {
      return false;
    }
    return true;
  }

  public static boolean isControlBand(final StyleSheet style)
  {
    if (style.getStyleProperty(BandStyleKeys.COMPUTED_SHEETNAME) != null)
    {
      return true;
    }
    if (style.getStyleProperty(BandStyleKeys.BOOKMARK) != null)
    {
      return true;
    }
    if (BandStyleKeys.LAYOUT_INLINE.equals(style.getStyleProperty(BandStyleKeys.LAYOUT)) == false)
    {
      if (Boolean.TRUE.equals(style.getStyleProperty(BandStyleKeys.PAGEBREAK_AFTER)))
      {
        return true;
      }
      if (Boolean.TRUE.equals(style.getStyleProperty(BandStyleKeys.PAGEBREAK_BEFORE)))
      {
        return true;
      }
    }
    return false;
  }

  private static boolean isLengthDefined(final StyleKey key, final StyleSheet styleSheet)
  {
    if (key.isInheritable())
    {
      if (styleSheet.isLocalKey(key) == false)
      {
        return false;
      }
    }

    final Object o = styleSheet.getStyleProperty(key, null);
    if (o == null)
    {
      return false;
    }
    if (o instanceof Number == false)
    {
      return false;
    }
    final Number n = (Number) o;
    return n.doubleValue() != 0;
  }

  public void startSection()
  {
    final String layoutMode;
    if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY))
    {
      layoutMode = BandStyleKeys.LAYOUT_BLOCK;
    }
    else
    {
      layoutMode = BandStyleKeys.LAYOUT_AUTO;
    }

    final RenderBox renderBox = renderNodeFactory.produceSectionBox(layoutMode, null);
    if (isAllowMergeSection())
    {
      this.context = new BandSectionLayoutModelBuilderContext(this.metaData, this.context, renderBox);
    }
    else
    {
      this.context = new DefaultLayoutModelBuilderContext(this.context, renderBox);
    }
    this.context.setEmpty(true);

    if (legacySectionName != null)
    {
      this.context.getRenderBox().setName(legacySectionName);
    }

    this.textProducer.startText();
  }

  public void startSection(final ReportElement element, final int sectionSize)
  {
    final StyleSheet resolverStyleSheet = element.getComputedStyle();
    final String layoutMode;
    final boolean legacyMode = metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY);
    if (legacyMode)
    {
      layoutMode = BandStyleKeys.LAYOUT_BLOCK;
    }
    else
    {
      String layout = (String) resolverStyleSheet.getStyleProperty(BandStyleKeys.LAYOUT, BandStyleKeys.LAYOUT_AUTO);
      if (BandStyleKeys.LAYOUT_INLINE.equals(layout) &&
          !this.context.getRenderBox().isAcceptInlineBoxes()) {
        layoutMode = BandStyleKeys.LAYOUT_BLOCK;
      }
      else {
        layoutMode = layout;
      }
    }


    final GroupSection groupSection = new GroupSection
        (renderNodeFactory.produceRenderBox(element, resolverStyleSheet, layoutMode, null),
            renderNodeFactory.createAutoGeneratedSectionStyleSheet(resolverStyleSheet), sectionSize, legacyMode);
    this.context = new SectionLayoutModelBuilderContext(this.context, groupSection, legacyMode);
    this.context.setEmpty(true);

    if (element instanceof GroupBody ||
        element instanceof Group)
    {
      // PRD-3154 - do we need to set placeholder to true?
      // todo: PRD-3154: This is black magic, placeholder box true is evil.
      // Need to evaluate side-effects of this beast. Is it safe for keep-together boxes?
      this.context.getRenderBox().getStaticBoxLayoutProperties().setPlaceholderBox
          (StaticBoxLayoutProperties.PlaceholderType.SECTION);
    }
    this.textProducer.startText();
  }

  private void closeAutoGeneratedPostfixBoxes()
  {
  }

  public boolean isEmptyElementsHaveSignificance()
  {
    if (designtime)
    {
      return true;
    }

    final RenderBox box = this.context.getRenderBox();
    return box.isEmptyNodesHaveSignificance();
  }

  public boolean isEmptyElementsHaveSignificanceInParent()
  {
    final LayoutModelBuilderContext parent = this.context.getParent();
    if (parent == null)
    {
      return false;
    }

    final RenderBox box = parent.getRenderBox();
    return box.isEmptyNodesHaveSignificance();
  }

  private void ensureEmptyChildIsAdded(final RenderBox parent, final ReportElement element)
  {
    final StyleSheet resolverStyleSheet = element.getComputedStyle();
    final RenderBox box;
    if (parent.isAcceptInlineBoxes())
    {
      box = renderNodeFactory.produceRenderBox(element, resolverStyleSheet, BandStyleKeys.LAYOUT_INLINE, getStateKey());
    }
    else
    {
      box = renderNodeFactory.produceRenderBox(element, resolverStyleSheet, BandStyleKeys.LAYOUT_BLOCK, getStateKey());
    }
    box.getStaticBoxLayoutProperties().setPlaceholderBox(StaticBoxLayoutProperties.PlaceholderType.SECTION);
    box.close();
    parent.addChild(box);
  }

  public void processContent(final ReportElement element,
                             final Object computedValue,
                             final Object rawValue)
  {
    if (computedValue == null)
    {
      final StyleSheet resolvedStyle = element.getComputedStyle();
      final RenderBox parentRenderBox = this.context.getRenderBox();
      if (parentRenderBox.isEmptyNodesHaveSignificance() ||
          metaData.isExtraContentElement(resolvedStyle, element.getAttributes()))
      {
        ensureEmptyChildIsAdded(parentRenderBox, element);
        this.context.setEmpty(false);
      }
      return;
    }

    if (String.class.equals(computedValue.getClass()))
    {
      processText(element, (String) computedValue, rawValue);
    }
    else if (computedValue instanceof Shape)
    {
      final StyleSheet resolvedStyle = element.getComputedStyle();
      final Shape shape = (Shape) computedValue;
      final ReportDrawable reportDrawable = new ShapeDrawable
          (shape, resolvedStyle.getBooleanStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO));
      processReportDrawable(element, reportDrawable, rawValue);
    }
    else if (computedValue instanceof ReportDrawable)
    {
      processReportDrawable(element, (ReportDrawable) computedValue, rawValue);
    }
    else if (computedValue instanceof ImageContainer ||
        computedValue instanceof DrawableWrapper)
    {
      processReplacedContent(element, computedValue, rawValue);
    }
    else if (DrawableWrapper.isDrawable(computedValue))
    {
      processReplacedContent(element, new DrawableWrapper(computedValue), rawValue);
    }
    else
    {
      processText(element, String.valueOf(computedValue), rawValue);
    }
  }

  private boolean isTableContext(RenderNode node)
  {
    while (node != null)
    {
      if ((node.getLayoutNodeType() & LayoutNodeTypes.MASK_BOX_TABLE) == LayoutNodeTypes.MASK_BOX_TABLE)
      {
        return true;
      }
      node = node.getParent();
    }
    return false;
  }

  protected void processText(final ReportElement element,
                             String computedValue,
                             final Object rawValue)
  {
    final SimpleStyleSheet resolverStyleSheet = element.getComputedStyle();
    if (computedValue != null &&
        resolverStyleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT))
    {
      computedValue = computedValue.trim();
    }

    if (this.context.getRenderBox().isAcceptInlineBoxes() == false)
    {
      final StyleSheet elementStyle;
      final int parentNodeType = this.context.getRenderBox().getLayoutNodeType();
      if (strictLegacyMode && (parentNodeType & LayoutNodeTypes.MASK_BOX_CANVAS) == LayoutNodeTypes.MASK_BOX_CANVAS)
      {
        // A table always claims all elements as dynamic. Use the max-height to limit the expansion of elements.
        if (isTableContext(this.context.getRenderBox()) == false &&
            resolverStyleSheet.getBooleanStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT) == false)
        {
          elementStyle = new NonDynamicHeightWrapperStyleSheet(resolverStyleSheet);
        }
        else
        {
          elementStyle = new DynamicHeightWrapperStyleSheet(resolverStyleSheet);
        }
      }
      else
      {
        elementStyle = resolverStyleSheet;
      }

      this.textProducer.startText();

      final RenderBox renderBox = renderNodeFactory.createAutoParagraph(element, elementStyle, stateKey);
      final RenderNode[] renderNodes = textProducer.getRenderNodes(element, elementStyle, computedValue);
      renderBox.addChilds(renderNodes);
      renderBox.setRawValue(rawValue);

      this.context = new DefaultLayoutModelBuilderContext(this.context, renderBox);
      this.context.setEmpty(renderNodes.length == 0 && isEmptyElement(element, resolverStyleSheet, metaData));
      this.context = this.context.close();
    }
    else
    {
      final StyleSheet safeElementStyle = renderNodeFactory.createStyle(resolverStyleSheet);
      final RenderBox renderBox = renderNodeFactory.produceRenderBox(element, resolverStyleSheet, BandStyleKeys.LAYOUT_INLINE, stateKey);
      final RenderNode[] renderNodes = textProducer.getRenderNodes(element, safeElementStyle, computedValue);
      renderBox.addChilds(renderNodes);
      renderBox.setRawValue(rawValue);

      this.context = new DefaultLayoutModelBuilderContext(this.context, renderBox);
      this.context.setEmpty(renderNodes.length == 0 && isEmptyElement(element, resolverStyleSheet, metaData));
      this.context = this.context.close();
    }
  }

  protected void processReportDrawable(final ReportElement element,
                                       final ReportDrawable reportDrawable,
                                       final Object rawValue)
  {

    final SimpleStyleSheet resolverStyleSheet = element.getComputedStyle();
    reportDrawable.setStyleSheet(resolverStyleSheet);
    reportDrawable.setConfiguration(processingContext.getConfiguration());
    reportDrawable.setResourceBundleFactory(processingContext.getResourceBundleFactory());

    if (reportDrawable instanceof DrawableWrapper)
    {
      processReplacedContent(element, reportDrawable, rawValue);
    }
    else
    {
      processReplacedContent(element, new DrawableWrapper(reportDrawable), rawValue);
    }
  }

  protected void processReplacedContent(final ReportElement element,
                                        final Object value,
                                        final Object rawValue)
  {
    final RenderBox box = this.context.getRenderBox();
    final SimpleStyleSheet resolverStyleSheet = element.getComputedStyle();

    final StyleSheet elementStyle;
    if (box.isAcceptInlineBoxes() == false)
    {
      if (isTableContext(box) == false &&
          resolverStyleSheet.getBooleanStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT) == false)
      {
        elementStyle = new NonDynamicReplacedContentStyleSheet(resolverStyleSheet);
      }
      else
      {
        elementStyle = new DynamicReplacedContentStyleSheet(resolverStyleSheet);
      }
    }
    else
    {
      elementStyle = resolverStyleSheet;
    }

    final RenderableReplacedContentBox child =
        renderNodeFactory.createReplacedContent(element, elementStyle, value, rawValue, stateKey);
    child.setName(element.getName());
    this.context.addChild(child);
    this.context.setEmpty(false);
  }


  public boolean finishBox()
  {
    boolean empty = this.context.isEmpty();
    if (empty)
    {
      if (isEmptyElementsHaveSignificanceInParent())
      {
        this.context.setEmpty(false);
        empty = false;
      }
    }

    this.context = this.context.close();
    while (this.context.isAutoGeneratedWrapperBox())
    {
      this.context = this.context.close();
    }
    return empty;
  }

  public void endSection()
  {
    this.context = this.context.close();
    while (this.context.isAutoGeneratedWrapperBox())
    {
      this.context = this.context.close();
    }
  }

  public InstanceID createSubflowPlaceholder(final ReportElement element)
  {
    final StyleSheet resolverStyleSheet = element.getComputedStyle();
    final RenderBox subReportBox = renderNodeFactory.produceSubReportPlaceholder(element, resolverStyleSheet, stateKey);
    this.context.addChild(subReportBox);
    this.context.setEmpty(false);
    return subReportBox.getInstanceId();
  }

  public InlineSubreportMarker processSubReport(final SubReport element)
  {
    if (isLimitedSubReports())
    {
      logger.debug("Not adding subreport: Subreports in header or footer area are not allowed.");
      return null;
    }

    final RenderBox parentBox = this.context.getRenderBox();
    if (parentBox.isAcceptInlineBoxes())
    {
      logger.warn("Not adding subreport: Subreports in inline-contexts are not supported.");
      return null;
    }

    final StyleSheet resolverStyleSheet = element.getComputedStyle();
    final RenderBox subReportBox = renderNodeFactory.produceSubReportPlaceholder(element, resolverStyleSheet, stateKey);
    this.context.addChild(subReportBox);
    this.context.setEmpty(false);
    final InstanceID subReportBoxId = subReportBox.getInstanceId();
    // the box will be closed
    return new InlineSubreportMarker(element, subReportBoxId, SubReportProcessType.INLINE);
  }

  public boolean isEmpty()
  {
    return context.isEmpty();
  }

  public void print()
  {
    ModelPrinter.INSTANCE.print(context.getRenderBox());
  }

  protected LayoutModelBuilderContext getContext()
  {
    return context;
  }

  protected void setContext(final LayoutModelBuilderContext context)
  {
    this.context = context;
  }

  protected TextProducer getTextProducer()
  {
    return textProducer;
  }

  protected RenderNodeFactory getRenderNodeFactory()
  {
    return renderNodeFactory;
  }

  protected ReportStateKey getStateKey()
  {
    return stateKey;
  }

  public void startSubFlow(final InstanceID insertationPoint)
  {
    final RenderBox box;
    if (insertationPoint == null)
    {
      throw new IllegalStateException();
    }

    final RenderBox rootBox = getLayoutRoot();
    box = (RenderBox) rootBox.findNodeById(insertationPoint);
    if (box == null)
    {
      dontPushBoxToContext();
    } else {
      pushBoxToContext(box, false);
    }
  }

  protected void pushBoxToContext(final RenderBox box, final boolean empty)
  {
    this.context = new DefaultLayoutModelBuilderContext(this.context, box);
    this.context.setEmpty(empty);
    this.textProducer.startText();
  }

  protected void dontPushBoxToContext() {
    this.context = new DummyLayoutModelBuilderContext(this.context);
    this.context.setEmpty(true);
  }

  public void startSubFlow(final ReportElement element)
  {
    final StyleSheet resolverStyleSheet = element.getComputedStyle();

    final RenderBox box;
    if (metaData.isFeatureSupported(OutputProcessorFeature.STRICT_COMPATIBILITY))
    {
      final StyleSheet styleSheet = new SubReportStyleSheet
          (resolverStyleSheet.getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_BEFORE),
              (resolverStyleSheet.getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_AFTER)));

      final SimpleStyleSheet reportStyle = new SimpleStyleSheet(styleSheet);
      final BoxDefinition boxDefinition = renderNodeFactory.getBoxDefinition(reportStyle);
      box = new BlockRenderBox
          (reportStyle, element.getObjectID(), boxDefinition, SubReportType.INSTANCE, element.getAttributes(), null);
    }
    else
    {
      box = renderNodeFactory.produceRenderBox(element, resolverStyleSheet, BandStyleKeys.LAYOUT_BLOCK, stateKey);
    }

    box.getStaticBoxLayoutProperties().setPlaceholderBox(StaticBoxLayoutProperties.PlaceholderType.SECTION);
    if (element.getName() != null)
    {
      box.setName("Banded-SubReport-Section" + ": name=" + element.getName());
    }
    else
    {
      box.setName("Banded-SubReport-Section");
    }

    pushBoxToContext(box, false);
  }

  private RenderBox getLayoutRoot()
  {
    LayoutModelBuilderContext context = this.context;
    while (context != null)
    {
      if (context.getParent() == null)
      {
        return context.getRenderBox();
      }
      context = context.getParent();
    }
    throw new IllegalStateException();
  }

  public void suspendSubFlow()
  {
    this.context = this.context.getParent();
  }

  public void endSubFlow()
  {
    endSection();
  }

  public void addProgressMarkerBox()
  {
    final RenderBox parent = this.context.getRenderBox();
    final RenderNode child = parent.getLastChild();
    if (isCollapseProgressMarker() &&
        child != null && child.getNodeType() == LayoutNodeTypes.TYPE_BOX_PROGRESS_MARKER)
    {
      final ProgressMarkerRenderBox markerRenderBox = (ProgressMarkerRenderBox) child;
      markerRenderBox.setStateKey(stateKey);
    }
    else
    {
      final ProgressMarkerRenderBox markerBox = new ProgressMarkerRenderBox();
      markerBox.setStateKey(stateKey);
      this.context.addChild(markerBox);
      markerBox.close();
    }
    this.context.setEmpty(false);
  }

  public void addManualPageBreakBox(final long range)
  {
    final RenderBox breakIndicatorBox = renderNodeFactory.createPageBreakIndicatorBox(stateKey, range);

    this.context.addChild(breakIndicatorBox);
    this.context.setEmpty(false);
  }

  public void setCollapseProgressMarker(final boolean collapseProgressMarker)
  {
    this.collapseProgressMarker = collapseProgressMarker;
  }

  public boolean isCollapseProgressMarker()
  {
    return collapseProgressMarker;
  }

  public void setLimitedSubReports(final boolean limitedSubReports)
  {
    this.limitedSubReports = limitedSubReports;
  }

  public boolean isLimitedSubReports()
  {
    return limitedSubReports;
  }

  public DefaultLayoutModelBuilder clone()
  {
    try
    {
      return (DefaultLayoutModelBuilder) super.clone();
    }
    catch (CloneNotSupportedException e)
    {
      throw new IllegalStateException(e);
    }
  }

  public LayoutModelBuilder deriveForPageBreak()
  {
    final DefaultLayoutModelBuilder clone = clone();
    clone.context = context.deriveForPagebreak();
    return clone;
  }

  public LayoutModelBuilder deriveForStorage(final RenderBox clonedContent)
  {
    final DefaultLayoutModelBuilder clone = clone();
    clone.context = context.deriveForStorage(clonedContent);
    return clone;
  }

  public void restoreStateAfterRollback()
  {
    LayoutModelBuilderContext c = context;
    while (c != null)
    {
      c.restoreStateAfterRollback();
      c = c.getParent();
    }
  }

  public void validateAfterCommit()
  {
    LayoutModelBuilderContext c = context;
    while (c != null)
    {
      c.validateAfterCommit();
      c = c.getParent();
    }
  }

  public void performParanoidModelCheck(final RenderBox logicalPageBox)
  {
    LayoutModelBuilderContext c = context;
    while (c != null)
    {
      c.performParanoidModelCheck();

      final RenderBox renderBox = c.getRenderBox();
      testIsLogicalPageParent(renderBox, logicalPageBox);

      c = c.getParent();
    }
  }

  private void testIsLogicalPageParent(RenderBox b, final RenderBox logicalPageBox)
  {
    while (b != null)
    {
      if (b == logicalPageBox)
      {
        return;
      }
      b = b.getParent();
    }
    throw new IllegalStateException();
  }

  public void legacyFlagNotEmpty()
  {
    context.setEmpty(false);
  }

  public void legacyAddPlaceholder(final ReportElement element)
  {
    final RenderBox parentRenderBox = this.context.getRenderBox();
    ensureEmptyChildIsAdded(parentRenderBox, element);
    this.context.setEmpty(false);
  }

  public RenderNode dangerousRawAccess()
  {
    return context.getRenderBox();
  }

  public void close()
  {
  }


}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.layout.build.DefaultLayoutModelBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.