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

Source Code of org.pentaho.reporting.engine.classic.core.Band

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

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.pentaho.reporting.engine.classic.core.filter.types.bands.BandType;
import org.pentaho.reporting.engine.classic.core.style.BandDefaultStyleSheet;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;

/**
* A report band is a collection of other elements and bands, similiar to an AWT-Container.
* <p/>
* This implementation is not synchronized, to take care that you externally synchronize it when using multiple threads
* to modify instances of this class.
* <p/>
* Trying to add a parent of an band as child to the band, will result in an exception.
*
* @author David Gilbert
* @author Thomas Morgner
*/
public class Band extends Section
{
  /**
   * An empty array to prevent object creation.
   */
  private static final Element[] EMPTY_ARRAY = new Element[0];

  /**
   * All the elements for this band.
   */
  private ArrayList<Element> allElements;

  /**
   * Cached elements.
   */
  private transient Element[] allElementsCached;

  /**
   * The prefix for anonymous bands, bands without an userdefined name.
   */
  public static final String ANONYMOUS_BAND_PREFIX = "anonymousBand@";

  /**
   * Constructs a new band (initially empty).
   */
  public Band()
  {
    setElementType(new BandType());
  }

  public Band(final InstanceID id)
  {
    super(id);
    setElementType(new BandType());
  }

  /**
   * Constructs a new band with the given pagebreak attributes. Pagebreak attributes have no effect on subbands.
   *
   * @param pagebreakAfter  defines, whether a pagebreak should be done after that band was printed.
   * @param pagebreakBefore defines, whether a pagebreak should be done before that band gets printed.
   */
  public Band(final boolean pagebreakBefore, final boolean pagebreakAfter)
  {
    this();
    if (pagebreakBefore)
    {
      setPagebreakBeforePrint(pagebreakBefore);
    }
    if (pagebreakAfter)
    {
      setPagebreakAfterPrint(pagebreakAfter);
    }
  }

  /**
   * Returns the global stylesheet for all bands. This stylesheet provides the predefined default values for some of the
   * stylekeys.
   *
   * @return the global default stylesheet.
   */
  public ElementStyleSheet getDefaultStyleSheet()
  {
    return BandDefaultStyleSheet.getBandDefaultStyle();
  }

  /**
   * Adds a report element to the band.
   *
   * @param element the element that should be added
   * @throws NullPointerException     if the given element is null
   * @throws IllegalArgumentException if the position is invalid, either negative or greater than the number of elements
   *                                  in this band or if the given element is a parent of this element.
   */
  public void addElement(final Element element)
  {
    addElement(getElementCount(), element);
  }

  /**
   * Adds a report element to the band. The element will be inserted at the specified position.
   *
   * @param position the position where to insert the element
   * @param element  the element that should be added
   * @throws NullPointerException     if the given element is null
   * @throws IllegalArgumentException if the position is invalid, either negative or greater than the number of elements
   *                                  in this band or if the given element is a parent of this element.
   */
  public void addElement(final int position, final Element element)
  {
    if (position < 0)
    {
      throw new IllegalArgumentException("Position < 0");
    }
    if (position > getElementCount())
    {
      throw new IllegalArgumentException("Position < 0");
    }
    if (element == null)
    {
      throw new NullPointerException("Band.addElement(...): element is null.");
    }

    validateLooping(element);
    if (unregisterParent(element))
    {
      return;
    }

    if (allElements == null)
    {
      allElements = new ArrayList<Element>();
    }
    // add the element, update the childs Parent and the childs stylesheet.
    allElements.add(position, element);
    allElementsCached = null;

    // then add the parents, or the band's parent will be unregistered ..
    registerAsChild(element);
    notifyNodeChildAdded(element);
  }

  /**
   * Adds a collection of elements to the band.
   *
   * @param elements the element collection.
   * @throws NullPointerException     if one of the given elements is null
   * @throws IllegalArgumentException if one of the given element is a parent of this element.
   */
  public void addElements(final Collection elements)
  {
    if (elements == null)
    {
      throw new NullPointerException("Band.addElements(...): collection is null.");
    }

    final Iterator iterator = elements.iterator();
    while (iterator.hasNext())
    {
      final Element element = (Element) iterator.next();
      addElement(element);
    }
  }

  /**
   * Returns the first element in the list that is known by the given name. Functions should use {@link
   * org.pentaho.reporting.engine.classic.core.function.FunctionUtilities#findAllElements(Band, String)} or {@link
   * org.pentaho.reporting.engine.classic.core.function.FunctionUtilities#findElement(Band, String)} instead.
   *
   * @param name the element name.
   * @return the first element with the specified name, or <code>null</code> if there is no such element.
   * @throws NullPointerException if the given name is null.
   */
  public Element getElement(final String name)
  {
    if (name == null)
    {
      throw new NullPointerException("Band.getElement(...): name is null.");
    }

    final Element[] elements = internalGetElementArray();
    final int elementsSize = elements.length;
    for (int i = 0; i < elementsSize; i++)
    {
      final Element e = elements[i];
      final String elementName = e.getName();
      if (elementName != null)
      {
        if (elementName.equals(name))
        {
          return e;
        }
      }
    }
    return null;
  }


  /**
   * Removes an element from the band.
   *
   * @param e the element to be removed.
   * @throws NullPointerException if the given element is null.
   */
  public void removeElement(final Element e)
  {
    if (e == null)
    {
      throw new NullPointerException();
    }
    if (e.getParentSection() != this)
    {
      // this is none of my childs, ignore the request ...
      return;
    }
    if (allElements == null)
    {
      return;
    }

    e.setParent(null);
    allElements.remove(e);
    allElementsCached = null;
    notifyNodeChildRemoved(e);
  }

  public void removeElement(int index)
  {
    removeElement(getElement(index));
  }

  public void setElementAt(final int position, final Element element)
  {
    if (position < 0)
    {
      throw new IllegalArgumentException("Position < 0");
    }
    if (position >= getElementCount())
    {
      throw new IllegalArgumentException("Position >= size");
    }
    if (element == null)
    {
      throw new NullPointerException("Band.addElement(...): element is null.");
    }

    validateLooping(element);
    if (unregisterParent(element))
    {
      return;
    }

    if (allElements == null)
    {
      throw new IllegalStateException("The throws above should have caught that state");
    }
    // add the element, update the childs Parent and the childs stylesheet.
    final Element o = allElements.set(position, element);
    o.setParent(null);
    allElementsCached = null;

    // then add the parents, or the band's parent will be unregistered ..
    registerAsChild(element);
    notifyNodeChildRemoved(o);
    notifyNodeChildAdded(element);


  }

  public void clear()
  {
    final Element[] elements = internalGetElementArray();
    for (int i = 0; i < elements.length; i++)
    {
      final Element element = elements[i];
      removeElement(element);
    }
  }

  /**
   * Returns the number of elements in this band.
   *
   * @return the number of elements of this band.
   */
  public int getElementCount()
  {
    if (allElements == null)
    {
      return 0;
    }
    return allElements.size();
  }

  /**
   * Returns an array of the elements in the band. If the band is empty, an empty array is returned.
   * <p/>
   * Implementation note: The array returned is a copy of the internal backend. Any modification of the array will no
   * longer result in modifications of the internal object state. To avoid unneccessary object creations, you can use
   * the {@link Band#unsafeGetElementArray()} method now.
   *
   * @return the elements.
   */
  public Element[] getElementArray()
  {
    return internalGetElementArray().clone();
  }

  /**
   * An internal method that allows other internal methods to work with the uncloned backend.
   *
   * @return the elements as array.
   */
  private Element[] internalGetElementArray()
  {
    if (allElementsCached == null)
    {
      if (allElements == null || allElements.isEmpty())
      {
        allElementsCached = Band.EMPTY_ARRAY;
      }
      else
      {
        Element[] elements = new Element[allElements.size()];
        elements = allElements.toArray(elements);
        allElementsCached = elements;
      }
    }
    return allElementsCached;
  }

  public final Element[] unsafeGetElementArray()
  {
    return internalGetElementArray();
  }

  /**
   * Returns the element stored add the given index.
   *
   * @param index the element position within this band
   * @return the element
   * @throws IndexOutOfBoundsException if the index is invalid.
   */
  public Element getElement(final int index)
  {
    if (allElements == null)
    {
      throw new IndexOutOfBoundsException("This index is invalid.");
    }
    return allElements.get(index);
  }

  /**
   * Returns a string representation of the band, useful mainly for debugging purposes.
   *
   * @return a string representation of this band.
   */
  public String toString()
  {
    final StringBuilder b = new StringBuilder(100);
    b.append(this.getClass().getName());
    b.append("={name=\"");
    b.append(getName());
    b.append("\", size=\"");
    b.append(getElementCount());
    b.append("\", layout=\"");
    b.append(getStyle().getStyleProperty(BandStyleKeys.LAYOUT));
    b.append("\"}");
    return b.toString();
  }

  /**
   * Clones this band and all elements contained in this band. After the cloning the band is no longer connected to a
   * report definition.
   *
   * @return the clone of this band.
   */
  public Band clone()
  {
    final Band b = (Band) super.clone();
    if (allElements != null)
    {
      final int elementSize = allElements.size();
      b.allElements = (ArrayList<Element>) allElements.clone();
      b.allElements.clear();
      b.allElementsCached = new Element[elementSize];

      if (allElementsCached != null)
      {
        for (int i = 0; i < elementSize; i++)
        {
          final Element eC = (Element) allElementsCached[i].clone();
          b.allElements.add(eC);
          b.allElementsCached[i] = eC;
          eC.setParent(b);
        }
      }
      else
      {
        for (int i = 0; i < elementSize; i++)
        {
          final Element e = allElements.get(i);
          final Element eC = (Element) e.clone();
          b.allElements.add(eC);
          b.allElementsCached[i] = eC;
          eC.setParent(b);
        }
      }
    }
    return b;
  }

  /**
   * Creates a deep copy of this element and regenerates all instance-ids.
   *
   * @return the copy of the element.
   */
  public Band derive(final boolean preserveElementInstanceIds)
  {
    final Band b = (Band) super.derive(preserveElementInstanceIds);
    if (allElements != null)
    {
      final int elementSize = allElements.size();
      b.allElements = (ArrayList<Element>) allElements.clone();
      b.allElements.clear();
      b.allElementsCached = new Element[elementSize];

      if (allElementsCached != null)
      {
        for (int i = 0; i < elementSize; i++)
        {
          final Element eC = allElementsCached[i].derive(preserveElementInstanceIds);
          b.allElements.add(eC);
          b.allElementsCached[i] = eC;
          eC.setParent(b);
        }
      }
      else
      {
        for (int i = 0; i < elementSize; i++)
        {
          final Element e = allElements.get(i);
          final Element eC = e.derive(preserveElementInstanceIds);
          b.allElements.add(eC);
          b.allElementsCached[i] = eC;
          eC.setParent(b);
        }
      }
    }
    return b;
  }

  /**
   * Returns, whether the page layout manager should perform a pagebreak before this page is printed. This will have no
   * effect on empty pages or if the band is no root-level band.
   *
   * @return true, if to force a pagebreak before this band is printed, false otherwise
   */
  public boolean isPagebreakBeforePrint()
  {
    return getStyle().getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_BEFORE);
  }

  /**
   * Defines, whether the page layout manager should perform a pagebreak before this page is printed. This will have no
   * effect on empty pages or if the band is no root-level band.
   *
   * @param pagebreakBeforePrint set to true, if to force a pagebreak before this band is printed, false otherwise
   */
  public void setPagebreakBeforePrint(final boolean pagebreakBeforePrint)
  {
    getStyle().setBooleanStyleProperty(BandStyleKeys.PAGEBREAK_BEFORE, pagebreakBeforePrint);
    notifyNodePropertiesChanged();
  }

  /**
   * Returns, whether the page layout manager should perform a pagebreak before this page is printed. This will have no
   * effect on empty pages or if the band is no root-level band.
   *
   * @return true, if to force a pagebreak before this band is printed, false otherwise
   */
  public boolean isPagebreakAfterPrint()
  {
    return getStyle().getBooleanStyleProperty(BandStyleKeys.PAGEBREAK_AFTER);
  }

  /**
   * Defines, whether the page layout manager should perform a pagebreak before this page is printed. This will have no
   * effect on empty pages or if the band is no root-level band.
   *
   * @param pagebreakAfterPrint set to true, if to force a pagebreak before this band is printed, false otherwise
   */
  public void setPagebreakAfterPrint(final boolean pagebreakAfterPrint)
  {
    getStyle().setBooleanStyleProperty(BandStyleKeys.PAGEBREAK_AFTER, pagebreakAfterPrint);
    notifyNodePropertiesChanged();
  }

  public void setLayout(final String layout)
  {
    getStyle().setStyleProperty(BandStyleKeys.LAYOUT, layout);
    notifyNodePropertiesChanged();
  }

  public String getLayout()
  {
    return (String) getStyle().getStyleProperty(BandStyleKeys.LAYOUT);
  }

}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.Band

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.