Package org.pentaho.reporting.engine.classic.core.layout.process.text

Source Code of org.pentaho.reporting.engine.classic.core.layout.process.text.SimpleTextMinorAxisLayoutStep

/*
* 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) 2006 - 2013 Pentaho Corporation..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.layout.process.text;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.ElementAlignment;
import org.pentaho.reporting.engine.classic.core.InvalidReportStateException;
import org.pentaho.reporting.engine.classic.core.layout.model.FinishedRenderNode;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.PageGrid;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphPoolBox;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphRenderBox;
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.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.process.AbstractMinorAxisLayoutStep;
import org.pentaho.reporting.engine.classic.core.layout.process.IterateSimpleStructureProcessStep;
import org.pentaho.reporting.engine.classic.core.layout.process.alignment.CenterAlignmentProcessor;
import org.pentaho.reporting.engine.classic.core.layout.process.alignment.JustifyAlignmentProcessor;
import org.pentaho.reporting.engine.classic.core.layout.process.alignment.LeftAlignmentProcessor;
import org.pentaho.reporting.engine.classic.core.layout.process.alignment.RightAlignmentProcessor;
import org.pentaho.reporting.engine.classic.core.layout.process.alignment.TextAlignmentProcessor;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.EndSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.InlineNodeSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.ReplacedContentSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.SequenceList;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.SpacerSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.StartSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.TextSequenceElement;
import org.pentaho.reporting.engine.classic.core.layout.process.util.MinorAxisNodeContext;
import org.pentaho.reporting.engine.classic.core.layout.process.util.MinorAxisParagraphBreakState;
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.style.WhitespaceCollapse;
import org.pentaho.reporting.libraries.base.util.ArgumentNullException;

public class SimpleTextMinorAxisLayoutStep extends IterateSimpleStructureProcessStep implements TextMinorAxisLayoutStep
{
  private static final Log logger = LogFactory.getLog(SimpleTextMinorAxisLayoutStep.class);

  private MinorAxisParagraphBreakState lineBreakState;
  private MinorAxisNodeContext nodeContext;
  private PageGrid pageGrid;
  private OutputProcessorMetaData metaData;
  private TextAlignmentProcessor centerProcessor;
  private TextAlignmentProcessor rightProcessor;
  private TextAlignmentProcessor leftProcessor;
  private TextAlignmentProcessor justifyProcessor;

  public SimpleTextMinorAxisLayoutStep(final OutputProcessorMetaData metaData)
  {
    ArgumentNullException.validate("metaData", metaData);

    this.metaData = metaData;
    this.lineBreakState = new MinorAxisParagraphBreakState();
  }

  public MinorAxisNodeContext getNodeContext()
  {
    return nodeContext;
  }

  public void process(final ParagraphRenderBox box,
                      final MinorAxisNodeContext nodeContext,
                      final PageGrid pageGrid)
  {
    this.nodeContext = nodeContext;
    this.pageGrid = pageGrid;
    try
    {
      lineBreakState.init(box);

      processParagraphChildsNormal(box);

      lineBreakState.deinit();

    }
    finally
    {
      this.pageGrid = null;
    }
  }

  private void processParagraphChildsNormal(final ParagraphRenderBox box)
  {
    final MinorAxisParagraphBreakState breakState = getLineBreakState();

    if (box.isComplexParagraph())
    {
      final RenderBox lineboxContainer = box.getLineboxContainer();
      RenderNode node = lineboxContainer.getFirstChild();
      while (node != null)
      {
        // all childs of the linebox container must be inline boxes. They
        // represent the lines in the paragraph. Any other element here is
        // a error that must be reported
        if (node.getNodeType() != LayoutNodeTypes.TYPE_BOX_LINEBOX)
        {
          throw new IllegalStateException("Expected ParagraphPoolBox elements.");
        }

        final ParagraphPoolBox inlineRenderBox = (ParagraphPoolBox) node;
        if (startLine(inlineRenderBox))
        {
          processBoxChilds(inlineRenderBox);
          finishLine(inlineRenderBox, breakState);
        }

        node = node.getNext();
      }
    }
    else
    {
      final ParagraphPoolBox node = box.getPool();

      if (node.getFirstChild() == null)
      {
        return;
      }

      // all childs of the linebox container must be inline boxes. They
      // represent the lines in the paragraph. Any other element here is
      // a error that must be reported
      if (startLine(node))
      {
        processBoxChilds(node);
        finishLine(node, breakState);
      }
    }
  }

  private boolean startLine(final RenderBox inlineRenderBox)
  {
    final MinorAxisParagraphBreakState breakState = getLineBreakState();
    if (breakState.isInsideParagraph() == false)
    {
      return false;
    }

    if (breakState.isSuspended())
    {
      return false;
    }

    breakState.clear();
    breakState.add(StartSequenceElement.INSTANCE, inlineRenderBox);
    return true;
  }

  private void finishLine(final RenderBox inlineRenderBox,
                          final MinorAxisParagraphBreakState breakState)
  {
    if (breakState.isInsideParagraph() == false || breakState.isSuspended())
    {
      throw new IllegalStateException("No active breakstate, finish-line cannot continue.");
    }

    final MinorAxisNodeContext nodeContext = getNodeContext();
    final PageGrid pageGrid = getPageGrid();
    final OutputProcessorMetaData metaData = getMetaData();
    breakState.add(EndSequenceElement.INSTANCE, inlineRenderBox);

    final ParagraphRenderBox paragraph = breakState.getParagraph();

    final ElementAlignment textAlignment = paragraph.getTextAlignment();
    final long textIndent = paragraph.getTextIndent();
    final long firstLineIndent = paragraph.getFirstLineIndent();
    // This aligns all direct childs. Once that is finished, we have to
    // check, whether possibly existing inner-paragraphs are still valid
    // or whether moving them violated any of the inner-pagebreak constraints.
    final TextAlignmentProcessor processor = create(textAlignment);

    final SequenceList sequence = breakState.getSequence();

    final long lineEnd;
    final boolean overflowX = paragraph.getStaticBoxLayoutProperties().isOverflowX();
    if (overflowX)
    {
      lineEnd = nodeContext.getX1() + AbstractMinorAxisLayoutStep.OVERFLOW_DUMMY_WIDTH;
    }
    else
    {
      lineEnd = nodeContext.getX2();
    }

    long lineStart = Math.min(lineEnd, nodeContext.getX1() + firstLineIndent);
    if (lineEnd - lineStart <= 0)
    {
      final long minimumChunkWidth = paragraph.getPool().getMinimumChunkWidth();
      processor.initialize(metaData, sequence, lineStart, lineStart + minimumChunkWidth, pageGrid, overflowX);
      nodeContext.updateX2(lineStart + minimumChunkWidth);
      logger.warn("Auto-Corrected zero-width first-line on paragraph - " + paragraph.getName());
    }
    else
    {
      processor.initialize(metaData, sequence, lineStart, lineEnd, pageGrid, overflowX);
      if (overflowX == false)
      {
        nodeContext.updateX2(lineEnd);
      }
    }

    while (processor.hasNext())
    {
      final RenderNode linebox = processor.next();
      if (linebox.getLayoutNodeType() != LayoutNodeTypes.TYPE_BOX_LINEBOX)
      {
        throw new IllegalStateException("Line must not be null");
      }

      paragraph.addGeneratedChild(linebox);

      if (processor.hasNext())
      {
        lineStart = Math.min(lineEnd, nodeContext.getX1() + textIndent);

        if (lineEnd - lineStart <= 0)
        {
          final long minimumChunkWidth = paragraph.getPool().getMinimumChunkWidth();
          processor.updateLineSize(lineStart, lineStart + minimumChunkWidth);
          nodeContext.updateX2(lineStart + minimumChunkWidth);
          logger.warn("Auto-Corrected zero-width text-line on paragraph continuation - " + paragraph.getName());
        }
        else
        {
          processor.updateLineSize(lineStart, lineEnd);
          if (overflowX == false)
          {
            nodeContext.updateX2(lineEnd);
          }
        }

      }
    }

    processor.deinitialize();
  }

  protected boolean startBox(final RenderBox box)
  {
    if (lineBreakState.isInsideParagraph() == false)
    {
      throw new InvalidReportStateException("A inline-level box outside of a paragraph box is not allowed.");
    }

    final int nodeType = box.getLayoutNodeType();
    if (nodeType == LayoutNodeTypes.TYPE_BOX_CONTENT)
    {
      lineBreakState.add(ReplacedContentSequenceElement.INSTANCE, box);
      return false;
    }

    lineBreakState.add(StartSequenceElement.INSTANCE, box);
    return true;
  }

  protected void processOtherNode(final RenderNode node)
  {
    if (lineBreakState.isInsideParagraph() == false)
    {
      throw new InvalidReportStateException("A inline-level box outside of a paragraph box is not allowed.");
    }

    final int nodeType = node.getNodeType();
    if (nodeType == LayoutNodeTypes.TYPE_NODE_FINISHEDNODE)
    {
      final FinishedRenderNode finNode = (FinishedRenderNode) node;
      node.setCachedWidth(finNode.getLayoutedWidth());
      return;
    }

    if (nodeType == LayoutNodeTypes.TYPE_NODE_TEXT)
    {
      lineBreakState.add(TextSequenceElement.INSTANCE, node);
    }
    else if (nodeType == LayoutNodeTypes.TYPE_NODE_SPACER)
    {
      final StyleSheet styleSheet = node.getStyleSheet();
      if (WhitespaceCollapse.PRESERVE.equals(styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE)) &&
          styleSheet.getBooleanStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT) == false)
      {
        // bug-alert: This condition could indicate a workaround for a logic-flaw in the text-processor
        lineBreakState.add(SpacerSequenceElement.INSTANCE, node);
      }
      else if (lineBreakState.isContainsContent())
      {
        lineBreakState.add(SpacerSequenceElement.INSTANCE, node);
      }
    }
    else
    {
      lineBreakState.add(InlineNodeSequenceElement.INSTANCE, node);
    }
  }

  protected void finishBox(final RenderBox box)
  {
    if (lineBreakState.isInsideParagraph() == false)
    {
      throw new InvalidReportStateException("A inline-level box outside of a paragraph box is not allowed.");
    }

    final int nodeType = box.getLayoutNodeType();
    if (nodeType == LayoutNodeTypes.TYPE_BOX_CONTENT)
    {
      return;
    }

    lineBreakState.add(EndSequenceElement.INSTANCE, box);
  }

  /**
   * Reuse the processors ..
   *
   * @param alignment
   * @return
   */
  protected TextAlignmentProcessor create(final ElementAlignment alignment)
  {
    if (ElementAlignment.CENTER.equals(alignment))
    {
      if (centerProcessor == null)
      {
        centerProcessor = new CenterAlignmentProcessor();
      }
      return centerProcessor;
    }
    else if (ElementAlignment.RIGHT.equals(alignment))
    {
      if (rightProcessor == null)
      {
        rightProcessor = new RightAlignmentProcessor();
      }
      return rightProcessor;
    }
    else if (ElementAlignment.JUSTIFY.equals(alignment))
    {
      if (justifyProcessor == null)
      {
        justifyProcessor = new JustifyAlignmentProcessor();
      }
      return justifyProcessor;
    }

    if (leftProcessor == null)
    {
      leftProcessor = new LeftAlignmentProcessor();
    }
    return leftProcessor;
  }

  public PageGrid getPageGrid()
  {
    return pageGrid;
  }

  public OutputProcessorMetaData getMetaData()
  {
    return metaData;
  }

  protected MinorAxisParagraphBreakState getLineBreakState()
  {
    return lineBreakState;
  }


}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.layout.process.text.SimpleTextMinorAxisLayoutStep

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.