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

Source Code of org.pentaho.reporting.engine.classic.core.layout.model.RenderNode

/*
* 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) 2001 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.layout.model;

import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.ReportAttributeMap;
import org.pentaho.reporting.engine.classic.core.layout.model.context.NodeLayoutProperties;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.states.ReportStateKey;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.VerticalTextAlign;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictBounds;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.base.util.DebugLog;

/**
* Creation-Date: 03.04.2007, 13:16:06
*
* @author Thomas Morgner
*/
public abstract class RenderNode implements Cloneable
{
  private static Boolean paranoidModelChecks;

  protected static boolean isParanoidChecks()
  {
    if (paranoidModelChecks == null)
    {
      final Configuration configuration = ClassicEngineBoot.getInstance().getGlobalConfig();
      if ("true".equals(configuration.getConfigProperty
          ("org.pentaho.reporting.engine.classic.core.layout.ParanoidChecks")))
      {
        paranoidModelChecks = Boolean.TRUE;
      }
      else
      {
        paranoidModelChecks = Boolean.FALSE;
      }
    }
    return paranoidModelChecks.booleanValue();   
  }

  public static final int HORIZONTAL_AXIS = 0;
  public static final int VERTICAL_AXIS = 1;

  public static final int CACHE_CLEAN = 0;
  public static final int CACHE_DIRTY = 1;
  public static final int CACHE_DEEP_DIRTY = 2;

  private long changeTracker;

  private RenderBox parentNode;
  private RenderNode nextNode;
  private RenderNode prevNode;

  private boolean frozen;
  private boolean hibernated;

  private long minimumChunkWidth;
  private long maximumBoxWidth;
  private NodeLayoutProperties nodeLayoutProperties;

  private long cachedAge;
  private long cachedParentWidth;

  private long cachedX;
  private long cachedY;
  private long cachedWidth;
  private long cachedHeight;

  private long x;
  private long y;
  private long width;
  private long height;

  private int cacheState;
  private boolean finished;
  private boolean virtualNode;
  private ReportAttributeMap attributes;
  private ElementType elementType;

  protected RenderNode(final int majorAxis,
                       final int minorAxis,
                       final StyleSheet styleSheet,
                       final InstanceID instanceID,
                       final ElementType elementType,
                       final ReportAttributeMap attributes)
  {
    this(elementType, attributes, new NodeLayoutProperties(majorAxis, minorAxis, styleSheet, instanceID));
  }

  protected RenderNode(final ElementType elementType,
                       final ReportAttributeMap attributes,
                       final NodeLayoutProperties nodeLayoutProperties)
  {
    if (attributes == null)
    {
      throw new NullPointerException();
    }
    if (nodeLayoutProperties == null)
    {
      throw new NullPointerException();
    }
    if (elementType == null)
    {
      throw new NullPointerException();
    }

    this.elementType = elementType;
    this.attributes = attributes;
    this.nodeLayoutProperties = nodeLayoutProperties;
    this.cacheState = RenderNode.CACHE_DEEP_DIRTY;
  }

  public ElementType getElementType()
  {
    return elementType;
  }

  public ReportAttributeMap getAttributes()
  {
    return attributes;
  }

  /**
   * The content-ref-count counts inline-subreports.
   */
  public int getContentRefCount()
  {
    return 0;
  }

  public boolean isSizeSpecifiesBorderBox()
  {
    return true;
  }

  public abstract int getNodeType();

  public int getMinorAxis()
  {
    return this.nodeLayoutProperties.getMinorAxis();
  }

  public int getMajorAxis()
  {
    return this.nodeLayoutProperties.getMajorAxis();
  }

  public final NodeLayoutProperties getNodeLayoutProperties()
  {
    return nodeLayoutProperties;
  }

  public long getComputedWidth()
  {
     return 0;
  }

  public final long getX()
  {
    return x;
  }

  public final void setX(final long x)
  {
    this.x = x;
    //this.updateChangeTracker();
  }

  public final long getY()
  {
    return y;
  }

  public final void shift(final long amount)
  {
    this.y += amount;
    this.updateCacheState(RenderNode.CACHE_DEEP_DIRTY);
  }

  public final void setY(final long y)
  {
    this.y = y;
    this.updateCacheState(RenderNode.CACHE_DEEP_DIRTY);
  }

  protected final void updateCacheState(final int state)
  {
    switch (state)
    {
//      case CACHE_CLEAN:
//        this.cacheState = CACHE_CLEAN;
//        break;
      case RenderNode.CACHE_DIRTY:
        if (cacheState == RenderNode.CACHE_CLEAN)
        {
          this.cacheState = RenderNode.CACHE_DIRTY;
          final RenderBox parent = getParent();
          if (parent != null)
          {
            parent.updateCacheState(RenderNode.CACHE_DIRTY);
          }
        }
        // if cache-state either dirty or deep-dirty, no need to update.
        break;
      case RenderNode.CACHE_DEEP_DIRTY:
        if (cacheState == RenderNode.CACHE_CLEAN)
        {
          this.cacheState = RenderNode.CACHE_DEEP_DIRTY;
          final RenderBox parent = getParent();
          if (parent != null)
          {
            parent.updateCacheState(RenderNode.CACHE_DIRTY);
          }
        }
        break;
      default:
        throw new IllegalArgumentException();
    }
  }

  public final long getWidth()
  {
    return width;
  }

  public final void setWidth(final long width)
  {
    if (width < 0)
    {
      throw new IndexOutOfBoundsException("Width cannot be negative");
    }

    if (width == 0 && height == 96067)
    {
      throw new NullPointerException();
    }
    this.width = width;
    this.updateCacheState(RenderNode.CACHE_DIRTY);
    //this.updateChangeTracker();
  }

  public final long getHeight()
  {
    return height;
  }

  public final void setHeight(final long height)
  {
    if (height < 0)
    {
      throw new IndexOutOfBoundsException("Height cannot be negative");
    }
    if (width == 0 && height == 96067)
    {
      throw new NullPointerException();
    }
    this.height = height;
    this.updateCacheState(RenderNode.CACHE_DIRTY);
    //this.updateChangeTracker();
  }

  public final StyleSheet getStyleSheet()
  {
    return nodeLayoutProperties.getStyleSheet();
  }

  public InstanceID getInstanceId()
  {
    return nodeLayoutProperties.getInstanceId();
  }

  protected void updateChangeTracker()
  {
    changeTracker += 1;
    if (cacheState == RenderNode.CACHE_CLEAN)
    {
      cacheState = RenderNode.CACHE_DIRTY;
    }
    final RenderBox parent = getParent();
    if (parent != null)
    {
      parent.updateChangeTracker();
    }
  }

  public final long getChangeTracker()
  {
    return changeTracker;
  }

  public final RenderBox getParent()
  {
    return parentNode;
  }

  protected final void setParent(final RenderBox parent)
  {
    if (isParanoidChecks())
    {
      final RenderNode prev = getPrev();
      if (parent != null && prev == parent)
      {
        throw new IllegalStateException("Assertation failed: Cannot have a parent that is the same as a silbling.");
      }
      if (parent == null)
      {
        final RenderNode next = getNext();
        if (next != null)
        {
          throw new NullPointerException();
        }
        if (prev != null)
        {
          throw new NullPointerException();
        }
      }
    }
    // Object oldParent = this.parent;
    this.parentNode = parent;
  }

  public final RenderNode getPrev()
  {
    return prevNode;
  }

  protected final void setPrevUnchecked(final RenderNode prev)
  {
    this.prevNode = prev;
  }

  protected final void setPrev(final RenderNode prev)
  {
    this.prevNode = prev;
    if (isParanoidChecks() && prev != null)
    {
      final RenderBox parent = getParent();
      if (prev == parent)
      {
        throw new IllegalStateException();
      }

      if (parent != null)
      {
        if (parent.getFirstChild() == this)
        {
          throw new NullPointerException("Cannot have a prev node if the parent has me as first child.");
        }
      }
    }
  }

  public final RenderNode getNext()
  {
    return nextNode;
  }

  protected final void setNextUnchecked(final RenderNode next)
  {
    this.nextNode = next;
  }
 
  protected final void setNext(final RenderNode next)
  {
    this.nextNode = next;
    if (isParanoidChecks() && next != null)
    {
      final RenderBox parent = getParent();
      if (next == parent)
      {
        throw new IllegalStateException();
      }

      if (parent != null)
      {
        if (parent.getLastChild() == this)
        {
          throw new NullPointerException("Cannot have a next-node, if the parent has me as last child.");
        }
      }
    }
  }

  public LogicalPageBox getLogicalPage()
  {
    RenderNode parent = this;
    while (parent != null)
    {
      if ((parent.getNodeType() & LayoutNodeTypes.TYPE_BOX_LOGICALPAGE) == LayoutNodeTypes.TYPE_BOX_LOGICALPAGE)
      {
        return (LogicalPageBox) parent;
      }

      parent = parent.getParent();
    }
    return null;
  }

  /**
   * Clones this node. Be aware that cloning can get you into deep trouble, as the relations this node has may no longer
   * be valid.
   *
   * @return
   * @noinspection CloneDoesntDeclareCloneNotSupportedException
   */
  public Object clone()
  {
    try
    {
      return super.clone();
    }
    catch (final CloneNotSupportedException e)
    {
      // ignored ..
      throw new IllegalStateException("Clone failed for some reason.");
    }
  }

  /**
   * Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
   * longer have any parent, silbling, child or any other relationships with other nodes.
   *
   * @param deep
   * @return
   */
  public RenderNode derive(final boolean deep)
  {
    final RenderNode node = (RenderNode) clone();
    node.parentNode = null;
    node.nextNode = null;
    node.prevNode = null;
    node.hibernated = false;
    if (deep)
    {
      node.cachedAge = -1;
      node.cacheState = CACHE_DEEP_DIRTY;
    }
    return node;
  }

  /**
   * Derives an hibernation copy. The resulting object should get stripped of all unnecessary caching information and
   * all objects, which will be regenerated when the layouting restarts. Size does matter here.
   *
   * @return
   */
  public RenderNode hibernate()
  {
    final RenderNode node = (RenderNode) clone();
    node.parentNode = null;
    node.nextNode = null;
    node.prevNode = null;
    node.hibernated = true;
    return node;
  }

  public RenderNode deriveFrozen(final boolean deep)
  {
    final RenderNode node = (RenderNode) clone();
    node.parentNode = null;
    node.nextNode = null;
    node.prevNode = null;
    node.frozen = true;
    node.hibernated = false;
    return node;
  }

  public boolean isFrozen()
  {
    return frozen;
  }

  public boolean isHibernated()
  {
    return hibernated;
  }

  protected void setHibernated(final boolean hibernated)
  {
    this.hibernated = hibernated;
  }

  public RenderNode findNodeById(final Object instanceId)
  {
    if (instanceId == getInstanceId())
    {
      return this;
    }
    return null;
  }

  public boolean isOpen()
  {
    return false;
  }

  public boolean isEmpty()
  {
    return false;
  }

  public boolean isDiscardable()
  {
    return false;
  }

  /**
   * If that method returns true, the element will not be used for rendering. For the purpose of computing sizes or
   * performing the layouting (in the validate() step), this element will treated as if it is not there.
   * <p/>
   * If the element reports itself as non-empty, however, it will affect the margin computation.
   *
   * @return
   */
  public boolean isIgnorableForRendering()
  {
    return isEmpty();
  }

  public void freeze()
  {
    frozen = true;
  }

  public long getMaximumBoxWidth()
  {
    return maximumBoxWidth;
  }

  public void setMaximumBoxWidth(final long maximumBoxWidth)
  {
    this.maximumBoxWidth = maximumBoxWidth;
  }

  public long getMinimumChunkWidth()
  {
    return minimumChunkWidth;
  }

  protected void setMinimumChunkWidth(final long minimumChunkWidth)
  {
    if (minimumChunkWidth < 0)
    {
      throw new IllegalArgumentException();
    }
    this.minimumChunkWidth = minimumChunkWidth;
  }

  public long getEffectiveMarginTop()
  {
    return 0;
  }

  public long getEffectiveMarginBottom()
  {
    return 0;
  }

  public VerticalTextAlign getVerticalTextAlignment()
  {
    return nodeLayoutProperties.getVerticalTextAlign();
  }
//
//  /**
//   * The sticky-Marker contains the original Y of this node.
//   * @return
//   */
//  public long getStickyMarker()
//  {
//    return stickyMarker;
//  }
//
//  public void setStickyMarker(final long stickyMarker)
//  {
//    this.stickyMarker = stickyMarker;
//  }

  public String getName()
  {
    return null;
  }

  public boolean isBreakAfter()
  {
    return false;
  }

  public final long getCachedAge()
  {
    return cachedAge;
  }

  public final void setCachedAge(final long cachedAge)
  {
    this.cachedAge = cachedAge;
  }

  public final long getCachedParentWidth()
  {
    return cachedParentWidth;
  }

  public final void setCachedParentWidth(final long cachedParentWidth)
  {
    this.cachedParentWidth = cachedParentWidth;
  }


  /**
   * Returns the cached y position. This position is known after all layouting steps have been finished. In most cases
   * the layouter tries to reuse the cached values instead of recomputing everything from scratch on each iteration.
   * <p/>
   * The cached positions always specify the border-box. If the user specified sizes as content-box sizes, the layouter
   * converts them into border-box sizes before filling the cache.
   *
   * @return the cached x position
   */
  public final long getCachedX()
  {
    return cachedX;
  }

  /**
   * Defines the cached x position. This position is known after all layouting steps have been finished. In most cases
   * the layouter tries to reuse the cached values instead of recomputing everything from scratch on each iteration.
   * <p/>
   * The cached positions always specify the border-box. If the user specified sizes as content-box sizes, the layouter
   * converts them into border-box sizes before filling the cache.
   *
   * @param cachedX the cached x position
   */
  public final void setCachedX(final long cachedX)
  {
    this.cachedX = cachedX;
  }

  /**
   * Returns the cached y position. This position is known after all layouting steps have been finished. In most cases
   * the layouter tries to reuse the cached values instead of recomputing everything from scratch on each iteration.
   * <p/>
   * The cached positions always specify the border-box. If the user specified sizes as content-box sizes, the layouter
   * converts them into border-box sizes before filling the cache.
   *
   * @return the cached y position
   */
  public final long getCachedY()
  {
    return cachedY;
  }

  /**
   * Defines the cached y position. This position is known after all layouting steps have been finished. In most cases
   * the layouter tries to reuse the cached values instead of recomputing everything from scratch on each iteration.
   * <p/>
   * The cached positions always specify the border-box. If the user specified sizes as content-box sizes, the layouter
   * converts them into border-box sizes before filling the cache.
   *
   * @param cachedY the cached y position
   */
  public final void setCachedY(final long cachedY)
  {
    this.cachedY = cachedY;
  }

  public final void shiftCached(final long amount)
  {
    this.cachedY += amount;
  }

  public final long getCachedWidth()
  {
    return cachedWidth;
  }

  public final void setCachedWidth(final long cachedWidth)
  {
    if (cachedWidth < 0)
    {
      throw new IndexOutOfBoundsException("'cached width' cannot be negative.");
    }
    this.cachedWidth = cachedWidth;
  }

  public final long getCachedHeight()
  {
    return cachedHeight;
  }

  public final void setCachedHeight(final long cachedHeight)
  {
    if (cachedHeight < 0)
    {
      throw new IndexOutOfBoundsException("'cached height' cannot be negative.");
    }
    if (cacheState == CACHE_CLEAN && this.cachedHeight > 0 && cachedHeight == 0)
    {
      throw new IndexOutOfBoundsException("'cached height' cannot be set to null.");
    }
    this.cachedHeight = cachedHeight;
  }

  public void apply()
  {
    this.x = this.cachedX;
    this.y = this.cachedY;
    this.width = this.cachedWidth;
    this.height = this.cachedHeight;
    this.cachedAge = this.changeTracker;
    this.cacheState = RenderNode.CACHE_CLEAN;
    final RenderBox parent = getParent();
    if (parent == null)
    {
      this.cachedParentWidth = 0;
    }
    else
    {
      this.cachedParentWidth = parent.getWidth();
    }
    if (width == 0 && height == 96067)
    {
      throw new NullPointerException();
    }
  }

  public final boolean isCacheValid()
  {
    if (cachedAge != changeTracker)
    {
      return false;
    }

    final RenderBox parent = getParent();
    if (parent == null)
    {
      if (this.cachedParentWidth != 0)
      {
        return false;
      }
    }
    else
    {
      if (this.cachedParentWidth != parent.getWidth())
      {
        return false;
      }
    }
    return true;
  }

  /**
   * Checks whether this node can be removed. This flag is used by iterative streaming output targets to mark nodes that
   * have been fully processed.
   *
   * @return
   */
  public boolean isFinished()
  {
    return finished;
  }

  public void setFinished(final boolean finished)
  {
    if (this.finished == true && finished == false)
    {
      throw new IllegalStateException("Cannot undo a finished-marker");
    }
    this.finished = finished;
  }

  public int getCacheState()
  {
    return cacheState;
  }

  public void markCacheClean()
  {
    if (cachedY != y)
    {
      throw new IllegalStateException();
    }
    cacheState = RenderNode.CACHE_CLEAN;
  }

  public ReportStateKey getStateKey()
  {
    return null;
  }

  public boolean isBoxOverflowX()
  {
    return false;
  }

  public boolean isBoxOverflowY()
  {
    return false;
  }
  public final boolean isNodeVisible(final StrictBounds drawArea, final boolean overflowX, final boolean overflowY)
  {
    final long drawAreaX0 = drawArea.getX();
    final long drawAreaY0 = drawArea.getY();
    return isNodeVisible(drawAreaX0, drawAreaY0, drawArea.getWidth(), drawArea.getHeight(), overflowX, overflowY);
  }

  public final boolean isNodeVisible(final StrictBounds drawArea)
  {
    final long drawAreaX0 = drawArea.getX();
    final long drawAreaY0 = drawArea.getY();
    return isNodeVisible(drawAreaX0, drawAreaY0, drawArea.getWidth(), drawArea.getHeight());
  }

  public final boolean isNodeVisible(final long drawAreaX0, final long drawAreaY0,
                                     final long drawAreaWidth, final long drawAreaHeight)
  {
    return isNodeVisible(drawAreaX0, drawAreaY0, drawAreaWidth, drawAreaHeight, isBoxOverflowX(), isBoxOverflowY());
  }

  public final boolean isNodeVisible(final long drawAreaX0, final long drawAreaY0,
                                     final long drawAreaWidth, final long drawAreaHeight,
                                     final boolean overflowX, final boolean overflowY)
  {
    if (getStyleSheet().getBooleanStyleProperty(ElementStyleKeys.VISIBLE) == false)
    {
      return false;
    }

    final long drawAreaX1 = drawAreaX0 + drawAreaWidth;
    final long drawAreaY1 = drawAreaY0 + drawAreaHeight;

    final long x2 = x + width;
    final long y2 = y + height;

    if (width == 0)
    {
      if (x2 < drawAreaX0)
      {
        return false;
      }
      if (x > drawAreaX1)
      {
        return false;
      }
    }
    else if (overflowX == false)
    {
      if (x2 <= drawAreaX0)
      {
        return false;
      }
      if (x >= drawAreaX1)
      {
        return false;
      }
    }
    if (height == 0)
    {
      if (y2 < drawAreaY0)
      {
        return false;
      }
      if (y > drawAreaY1)
      {
        return false;
      }
    }
    else if (overflowY == false)
    {
      if (y2 <= drawAreaY0)
      {
        return false;
      }
      if (y >= drawAreaY1)
      {
        return false;
      }
    }
    return true;
  }

  public boolean isVirtualNode()
  {
    return virtualNode;
  }

  public void setVirtualNode(final boolean virtualNode)
  {
    this.virtualNode = virtualNode;
  }


  public final boolean isBoxVisible(final StrictBounds drawArea)
  {
    return isBoxVisible(drawArea.getX(), drawArea.getY(), drawArea.getWidth(), drawArea.getHeight());
  }

  public final boolean isBoxVisible(final long x, final long y, final long width, final long height)
  {
    if (isNodeVisible(x, y, width, height) == false)
    {
      return false;
    }

    final RenderBox parent = getParent();
    if (parent == null)
    {
      return true;
    }

    final StyleSheet styleSheet = getStyleSheet();
    if (styleSheet.getStyleProperty(ElementStyleKeys.ANCHOR_NAME) != null)
    {
      return true;
    }


    if (parent.getStaticBoxLayoutProperties().isOverflowX() == false)
    {
      final long parentX1 = parent.getX();
      final long parentX2 = parentX1 + parent.getWidth();

      if (getWidth() == 0)
      {
        // could be a line ..
        return true;
      }

      final long boxX1 = getX();
      final long boxX2 = boxX1 + getWidth();

      if (boxX2 <= parentX1)
      {
        return false;
      }
      if (boxX1 >= parentX2)
      {
        return false;
      }
    }

    if (parent.getStaticBoxLayoutProperties().isOverflowY() == false)
    {
      // Compute whether the box is at least partially contained in the parent's bounding box.
      final long parentY1 = parent.getY();
      final long parentY2 = parentY1 + parent.getHeight();

      if (getHeight() == 0)
      {
        // could be a line ..
        return true;
      }

      final long boxY1 = getY();
      final long boxY2 = boxY1 + getHeight();

      if (boxY2 <= parentY1)
      {
        return false;
      }
      if (boxY1 >= parentY2)
      {
        return false;
      }
    }
    return true;
  }
}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.layout.model.RenderNode

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.