/*
* 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;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import org.pentaho.reporting.engine.classic.core.util.PageFormatFactory;
import org.pentaho.reporting.libraries.serializer.SerializerHelper;
/**
* A page definition, that consists of one or many pages. The pages are allowed to overlapp or to leave areas of the
* page uncovered.
*
* @author Thomas Morgner
* @see PageDefinition
*/
public class CustomPageDefinition implements PageDefinition
{
/**
* The page bounds, the imageable area on the global virtual page.
*/
private transient ArrayList pageBoundsList;
/**
* The page format list.
*/
private transient ArrayList pageFormatList;
/**
* The total width of the page.
*/
private float width;
/**
* The total height of the page.
*/
private float height;
/**
* Creates a new (initialy empty and therefore invalid) page definition.
*/
public CustomPageDefinition()
{
pageBoundsList = new ArrayList();
pageFormatList = new ArrayList();
}
/**
* Adds a new page format to the page definition.
*
* @param format the page format
* @param x the x-position to where the imageable-x of the pageformat is mapped.
* @param y the y-position to where the imageable-y of the pageformat is mapped.
*/
public void addPageFormat(final PageFormat format, final float x, final float y)
{
if (format == null)
{
throw new NullPointerException("The given pageformat must not be null.");
}
width = Math.max(width, (float) (format.getImageableWidth() + x));
height = Math.max(height, (float) (format.getImageableHeight() + y));
final Rectangle2D bounds = new Rectangle2D.Double
(x, y, format.getImageableWidth(), format.getImageableHeight());
pageBoundsList.add(bounds);
pageFormatList.add(format.clone());
}
/**
* Returns the number of physical pages in the logical page definition.
*
* @return the number of physical pages.
*/
public int getPageCount()
{
return pageBoundsList.size();
}
/**
* Returns the page format for the given page number. The page format contains local coordinates - that means that the
* point (0,0) denotes the upper left corner of this returned page format and not global coordinates.
*
* @param pos the position of the pageformat within the page
* @return the given pageformat.
*/
public PageFormat getPageFormat(final int pos)
{
final PageFormat fmt = (PageFormat) pageFormatList.get(pos);
return (PageFormat) fmt.clone();
}
/**
* Describes the internal position of the given page within the logical page. The logical page does not include any
* page margins, the printable area for a page starts at (0,0).
*
* @param index the index of the page.
* @return the position of the page (within the global page).
*/
public Rectangle2D getPagePosition(final int index)
{
final Rectangle2D rec = (Rectangle2D) pageBoundsList.get(index);
return rec.getBounds2D();
}
/**
* Returns all page positions as array.
*
* @return the collected page positions
* @see PageDefinition#getPagePosition(int)
*/
public Rectangle2D[] getPagePositions()
{
final Rectangle2D[] rects = new Rectangle2D[pageBoundsList.size()];
for (int i = 0; i < pageBoundsList.size(); i++)
{
final Rectangle2D rec = (Rectangle2D) pageBoundsList.get(i);
rects[i] = rec.getBounds2D();
}
return rects;
}
/**
* Returns the total width of the page definition.
*
* @return the total width of the page definition.
*/
public float getWidth()
{
return width;
}
/**
* Returns the total height of the page definition.
*
* @return the total height of the page definition.
*/
public float getHeight()
{
return height;
}
/**
* Clones the given page definition object.
*
* @return a clone of this page definition.
* @throws CloneNotSupportedException if an error occured.
*/
public Object clone()
throws CloneNotSupportedException
{
final CustomPageDefinition def = (CustomPageDefinition) super.clone();
def.pageBoundsList = (ArrayList) pageBoundsList.clone();
def.pageFormatList = (ArrayList) pageFormatList.clone();
return def;
}
/**
* Deserizalize the report and restore the pageformat.
*
* @param out the objectoutput stream
* @throws java.io.IOException if errors occur
*/
private void writeObject(final ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
final SerializerHelper instance = SerializerHelper.getInstance();
final Iterator pageBoundsIterator = pageBoundsList.iterator();
while (pageBoundsIterator.hasNext())
{
instance.writeObject(pageBoundsIterator.next(), out);
}
instance.writeObject(null, out);
final Iterator pageFormatIterator = pageFormatList.iterator();
while (pageFormatIterator.hasNext())
{
instance.writeObject(pageFormatIterator.next(), out);
}
instance.writeObject(null, out);
}
/**
* Resolve the pageformat, as PageFormat is not serializable.
*
* @param in the input stream.
* @throws java.io.IOException if there is an IO problem.
* @throws ClassNotFoundException if there is a class problem.
*/
private void readObject(final ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
final SerializerHelper instance = SerializerHelper.getInstance();
pageBoundsList = new ArrayList();
pageFormatList = new ArrayList();
Object o = instance.readObject(in);
while (o != null)
{
final Rectangle2D rect = (Rectangle2D) o;
pageBoundsList.add(rect);
o = instance.readObject(in);
}
o = instance.readObject(in);
while (o != null)
{
final PageFormat format = (PageFormat) o;
pageFormatList.add(format);
o = instance.readObject(in);
}
}
/**
* Checks whether the given object is equal to this one.
*
* @param obj the other object.
* @return true, if the other object is equal, false otherwise.
*/
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof CustomPageDefinition))
{
return false;
}
final CustomPageDefinition customPageDefinition = (CustomPageDefinition) obj;
if (height != customPageDefinition.height)
{
return false;
}
if (width != customPageDefinition.width)
{
return false;
}
if (!pageBoundsList.equals(customPageDefinition.pageBoundsList))
{
return false;
}
if (pageFormatList.size() != customPageDefinition.pageFormatList.size())
{
return false;
}
for (int i = 0; i < pageFormatList.size(); i++)
{
final PageFormat pf = (PageFormat) pageFormatList.get(i);
final PageFormat cpf = (PageFormat) customPageDefinition.pageFormatList.get(i);
if (PageFormatFactory.isEqual(pf, cpf) == false)
{
return false;
}
}
return true;
}
/**
* Computes the hashcode of this page definition.
*
* @return the hashcode.
*/
public int hashCode()
{
int result = pageBoundsList.hashCode();
result = 29 * result + pageFormatList.hashCode();
result = 29 * result + width == 0.0f ? 0 : Float.floatToIntBits(width);
result = 29 * result + height == 0.0f ? 0 : Float.floatToIntBits(height);
return result;
}
}