/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. 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 General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.print.layout;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.geom.Point2D;
import java.awt.image.ImageObserver;
import java.io.Serializable;
import java.util.Properties;
import java.util.logging.Level;
import org.compiere.model.MQuery;
import org.compiere.print.MPrintFormatItem;
import org.compiere.print.PrintData;
import org.compiere.util.CLogger;
/**
* Abstract base class for Print Element
*
* @author Jorg Janke
* @version $Id: PrintElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $
*/
public abstract class PrintElement implements ImageObserver, Serializable
{
/**
* generated serial id
*/
private static final long serialVersionUID = 5894090289966933777L;
/**
* Constructor
*/
protected PrintElement ()
{
} // PrintElement
/** Link Color */
public static final Color LINK_COLOR = Color.blue;
/** Calculated Size of Element */
protected float p_width = 0f;
protected float p_height = 0f;
protected boolean p_sizeCalculated = false;
/** Max Size of Element */
protected float p_maxWidth = 0f;
protected float p_maxHeight = 0f;
/** Field Align Type */
protected String p_FieldAlignmentType;
/** Location on Page */
protected Point2D.Double p_pageLocation = null;
/** Loading Flag */
private boolean m_imageNotLoaded = true;
/** Logger */
protected CLogger log = CLogger.getCLogger(getClass());
private Page m_currentPage;
private PrintData m_printData;
private int m_rowIndex = -1;
private String m_pageLogic;
/**
* Get Calculated Width
* @return Width
*/
public float getWidth()
{
if (!p_sizeCalculated)
p_sizeCalculated = calculateSize();
return p_width;
} // getWidth
/**
* Get Calculated Height
* @return Height
*/
public float getHeight()
{
if (!p_sizeCalculated)
p_sizeCalculated = calculateSize();
return p_height;
} // getHeight
/**
* Get Calculated Height on page
* @param pageNo page number
* @return Height
*/
public float getHeight (int pageNo)
{
return getHeight();
} // getHeight
/**
* Get number of pages
* @return page count (1)
*/
public int getPageCount()
{
return 1;
} // getPageCount
/**
* Layout and Calculate Size
* @return true if calculated
*/
protected abstract boolean calculateSize();
/**
* Layout Element
* @param maxWidth max width
* @param maxHeight max height
* @param isHeightOneLine just one line
* @param FieldAlignmentType alignment type (MPrintFormatItem.FIELD_ALIGN_*)
*/
public void layout (float maxWidth, float maxHeight, boolean isHeightOneLine,
String FieldAlignmentType)
{
if (isHeightOneLine)
p_maxHeight = -1f;
else if (maxHeight > 0f)
p_maxHeight = maxHeight;
p_maxWidth = maxWidth;
//
p_FieldAlignmentType = FieldAlignmentType;
if (p_FieldAlignmentType == null || p_FieldAlignmentType.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Default))
p_FieldAlignmentType = MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft;
//
p_sizeCalculated = calculateSize();
} // layout
/**
* Set Maximum Height
* @param maxHeight maximum height (0) is no limit
*/
public void setMaxHeight (float maxHeight)
{
p_maxHeight = maxHeight;
} // setMaxHeight
/**
* Set Maximum Width
* @param maxWidth maximum width (0) is no limit
*/
public void setMaxWidth (float maxWidth)
{
p_maxWidth = maxWidth;
} // setMaxWidth
/**
* Set Location within page.
* Called from LayoutEngine.layoutForm(), layout(), createStandardFooterHeader()
* @param pageLocation location within page
*/
public void setLocation (Point2D pageLocation)
{
p_pageLocation = new Point2D.Double(pageLocation.getX(), pageLocation.getY());
} // setLocation
/**
* Get Location within page
* @return location within page
*/
public Point2D getLocation()
{
return p_pageLocation;
} // getLocation
/**
* Return Absolute Position
* @param pageStart start of page
* @return absolute position
*/
protected Point2D.Double getAbsoluteLocation(Point2D pageStart)
{
Point2D.Double retValue = new Point2D.Double(
p_pageLocation.x + pageStart.getX(), p_pageLocation.y + pageStart.getY());
return retValue;
} // getAbsoluteLocation
/**
* Get relative Bounds of Element
* @return bounds
*/
public Rectangle getBounds()
{
if (p_pageLocation == null)
return new Rectangle (0,0, (int)p_width, (int)p_height);
return new Rectangle ((int)p_pageLocation.x, (int)p_pageLocation.y, (int)p_width, (int)p_height);
} // getBounds
/**
* Get Drill Down Query
* @param relativePoint point to find print element
* @param pageNo page number
* @return null (subclass to overwrite)
*/
public MQuery getDrillDown (Point relativePoint, int pageNo)
{
return null;
} // getDrillDown
/**
* Get Drill Across Query
* @param relativePoint point to find print element
* @param pageNo page number
* @return null (subclass to overwrite)
*/
public MQuery getDrillAcross (Point relativePoint, int pageNo)
{
return null;
} // getDrillAcross
/**
* Translate Content if required.
* If content is translated, the element needs to stay in the bounds
* of the originally calculated size and need to align the field.
* @param ctx context
*/
public void translate (Properties ctx)
{
// noop
} // translate
/**
* Content is translated
* @return false
*/
public boolean isTranslated()
{
return false;
} // translate
/**
* Paint/Print.
* @param g2D Graphics
* @param pageNo page number for multi page support (0 = header/footer)
* @param pageStart top left Location of page
* @param ctx context
* @param isView true if online view (IDs are links)
*/
public abstract void paint (Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView);
/**
* Image Observer
* @param img image
* @param infoflags Observer flags
* @param x x coordinate
* @param y y coordinate
* @param width image width
* @param height image height
* @return false if the infoflags indicate that the image is completely loaded; true otherwise
*/
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
// copied from java.awt.component
m_imageNotLoaded = (infoflags & (ALLBITS|ABORT)) == 0;
if (log.isLoggable(Level.FINEST)) log.finest("Flags=" + infoflags
+ ", x=" + x + ", y=" + y + ", width=" + width + ", height=" + height
+ " - NotLoaded=" + m_imageNotLoaded);
return m_imageNotLoaded;
} // imageUpdate
/**
* Wait until Image is loaded.
* @param image image
* @return true if loaded
*/
public boolean waitForLoad (Image image)
{
long start = System.currentTimeMillis();
Thread.yield();
int count = 0;
try
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
while (!toolkit.prepareImage(image, -1, -1, this)) // ImageObserver calls imageUpdate
{
// Timeout
if (count > 1000) // about 20+ sec overall
{
log.severe (this + " - Timeout - "
+ (System.currentTimeMillis()-start) + "ms - #" + count);
return false;
}
try
{
if (count < 10)
Thread.sleep(10);
else if (count < 100)
Thread.sleep(15);
else
Thread.sleep(20);
}
catch (InterruptedException ex)
{
log.log(Level.SEVERE, "", ex);
break;
}
count++;
}
}
catch (Exception e) // java.lang.SecurityException
{
log.log(Level.SEVERE, "", e);
return false;
}
if (count > 0)
if (log.isLoggable(Level.FINE)) log.fine((System.currentTimeMillis()-start) + "ms - #" + count);
return true;
} // waitForLoad
/**
* Get Detail Info
* @return detail info (empty string, subclass to overwrite)
*/
protected String getDetailInfo()
{
return "";
} // getDetailInfo
/**
* String Representation
* @return info
*/
@Override
public String toString()
{
String cn = getClass().getName();
StringBuilder sb = new StringBuilder();
sb.append(cn.substring(cn.lastIndexOf('.')+1)).append("[");
sb.append("Bounds=").append(getBounds())
.append(",Height=").append(p_height).append("(").append(p_maxHeight)
.append("),Width=").append(p_width).append("(").append(p_maxHeight)
.append("),PageLocation=").append(p_pageLocation);
sb.append("]");
return sb.toString();
} // toString
/**
* Set current page
* @param page
*/
public void setCurrentPage(Page page)
{
m_currentPage = page;
}
/**
* Get current page
* @return page
*/
protected Page getCurrentPage()
{
return m_currentPage;
}
/**
* Set print data
* @param printData
*/
public void setPrintData(PrintData printData)
{
m_printData = printData;
}
/**
* Get print data
* @return print data
*/
public PrintData getPrintData()
{
return m_printData;
}
/**
* Set row index
* @param row
*/
public void setRowIndex(int row)
{
m_rowIndex = row;
}
/**
* Get row index
* @return row index
*/
public int getRowIndex()
{
return m_rowIndex;
}
/**
* Set page logic expression
* @param displayLogic
*/
public void setPageLogic(String displayLogic)
{
m_pageLogic = displayLogic;
}
/**
* Get page logic expression
* @return page logic expression
*/
public String getPageLogic()
{
return m_pageLogic;
}
} // PrintElement