/******************************************************************************
* 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.Dimension;
import java.awt.Font;
import java.awt.Graphics;
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.print.PageFormat;
import java.awt.print.Pageable;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.attribute.DocAttributeSet;
import org.adempiere.base.Core;
import org.compiere.model.MQuery;
import org.compiere.model.MTable;
import org.compiere.model.PrintInfo;
import org.compiere.print.ArchiveEngine;
import org.compiere.print.CPaper;
import org.compiere.print.DataEngine;
import org.compiere.print.MPrintColor;
import org.compiere.print.MPrintFont;
import org.compiere.print.MPrintFormat;
import org.compiere.print.MPrintFormatItem;
import org.compiere.print.MPrintPaper;
import org.compiere.print.MPrintTableFormat;
import org.compiere.print.PrintData;
import org.compiere.print.PrintDataElement;
import org.compiere.print.util.SerializableMatrix;
import org.compiere.print.util.SerializableMatrixImpl;
import org.compiere.report.MReportLine;
import org.compiere.util.CLogger;
import org.compiere.util.CacheMgt;
import org.compiere.util.DB;
import org.compiere.util.DefaultEvaluatee;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Evaluator;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.NamePair;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.idempiere.print.IPrintHeaderFooter;
import org.idempiere.print.StandardHeaderFooter;
/**
* Print Engine.
* All coordinates are relative to the Page.
* The Language setting is maintained in the format.
*
* @author Jorg Janke
* @version $Id: LayoutEngine.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $
*
* @author Teo Sarca, SC ARHIPAC SERVICE SRL
*
BF [ 1673505 ] BarCode/Image problem when print format is not form
* BF [ 1673542 ] Can't add static image in report table cell
* BF [ 1673548 ] Image is not scaled in a report table cell
* BF [ 1807917 ] Layout positioning issue with m_maxHeightSinceNewLine
* BF [ 1825876 ] Layout boxes with auto width not working
* FR [ 1966406 ] Report Engine: AD_PInstance_Logs should be displayed
* BF [ 2487307 ] LayoutEngine: NPE when Barcode field is null
* BF [ 2828893 ] Problem with NextPage in Print Format
* https://sourceforge.net/p/adempiere/bugs/2001/
* @author victor.perez@e-evolution.com, e-Evolution
* BF [ 2011567 ] Implement Background Image for Document printed
* https://sourceforge.net/p/adempiere/feature-requests/477/
* @author Michael Judd (Akuna Ltd)
* BF [ 2695078 ] Country is not translated on invoice
*/
public class LayoutEngine implements Pageable, Printable, Doc
{
/**
* Constructor
* @param format
* @param data
* @param query
* @param info
*/
public LayoutEngine (MPrintFormat format, PrintData data, MQuery query, PrintInfo info)
{
this(format,data,query,info,0);
}
/**
* Detail Constructor
* @param format Print Format
* @param data Print Data
* @param query query for parameter info
* @param info
* @param windowNo
*/
public LayoutEngine (MPrintFormat format, PrintData data, MQuery query, PrintInfo info, int windowNo )
{
this(format, data, query, info , null, windowNo);
} // LayoutEngine
/**
* Detail Constructor
* @param format
* @param data
* @param query
* @param info
* @param trxName
*/
public LayoutEngine (MPrintFormat format, PrintData data, MQuery query, PrintInfo info , String trxName)
{
this(format,data,query,info,trxName,0);
}
/**
* Detail Constructor
* @param format Print Format
* @param data Print Data
* @param query query for parameter info
* @param info
* @param trxName
* @param windowNo
*/
public LayoutEngine (MPrintFormat format, PrintData data, MQuery query, PrintInfo info , String trxName, int windowNo)
{
m_windowNo = windowNo;
m_TrxName = trxName;
if (log.isLoggable(Level.INFO)) log.info(format + " - " + data + " - " + query);
//
setPrintFormat(format, false);
setPrintData(data, query, false);
setPrintInfo(info);
layout();
} // LayoutEngine
/** Logger */
private static CLogger log = CLogger.getCLogger (LayoutEngine.class);
/** Existing Layout */
private boolean m_hasLayout = false;
/** The Format */
private MPrintFormat m_format;
/** Print Context */
private Properties m_printCtx;
/** The Data */
private PrintData m_data;
/** The Query (parameter */
private MQuery m_query;
/** Default Color */
private MPrintColor m_printColor;
/** Default Font */
private MPrintFont m_printFont;
/** Printed Column Count */
private int m_columnCount = -1;
/** Transaction name */
private String m_TrxName = null;
/** PrintInfo **/
private PrintInfo m_PrintInfo = null;
/** Window No */
private int m_windowNo = 0;
/** Paper - default: standard portrait */
private CPaper m_paper;
/** Header Area Height (1/4") */
private int m_headerHeight = 18; // 1/4" => 72/4
/** Footer Area Height (1/4") */
private int m_footerHeight = 18;
/** Current Page Number */
private int m_pageNo = 0;
/** Current Page */
private Page m_currPage;
/** Pages */
private ArrayList m_pages = new ArrayList();
/** Header&Footer for all pages */
private HeaderFooter m_headerFooter;
/** Header Coordinates */
private Rectangle m_header = new Rectangle ();
/** Content Coordinates */
private Rectangle m_content = new Rectangle();
/** Footer Coordinates */
private Rectangle m_footer = new Rectangle();
/** Temporary NL Position */
private int m_tempNLPositon = 0;
/** Header Area */
public static final int AREA_HEADER = 0;
/** Content Area */
public static final int AREA_CONTENT = 1;
/** Footer Area */
public static final int AREA_FOOTER = 2;
/** Area Pointer */
private int m_area = AREA_CONTENT;
/** Current Position in 1/72 inch */
private Point2D.Double[] m_position = new Point2D.Double[]
{new Point2D.Double(0,0), new Point2D.Double(0,0), new Point2D.Double(0,0)};
/** Max Height Since New Line */
private float m_maxHeightSinceNewLine[] = new float[] {0f, 0f, 0f};
/** Primary Table Element for Page XY Info */
private TableElement m_tableElement = null;
/** Last Height by area */
private float m_lastHeight[] = new float[] {0f, 0f, 0f};
/** Last Width by area */
private float m_lastWidth[] = new float[] {0f, 0f, 0f};
/** Draw using attributed String vs. Text Layout where possible */
//hengsin: [ 1564523 ] Max width of print element not always respected
//tspc: [ 2084725 ] setting s_FASTDRAW to false is causing exported pdf to be generated as image
public static boolean s_FASTDRAW = true;
/** Print Copy (print interface) */
private boolean m_isCopy = false;
/** True Image */
public static Image IMAGE_TRUE = null;
/** False Image */
public static Image IMAGE_FALSE = null;
/** Image Size */
public static Dimension IMAGE_SIZE = new Dimension(10,10);
private Map childPrintFormatDetails = new HashMap();
/** suppress repeat columns */
public Boolean[] colSuppressRepeats;
static {
Toolkit tk = Toolkit.getDefaultToolkit();
URL url = LayoutEngine.class.getResource("true10.gif");
if (url != null)
IMAGE_TRUE = tk.getImage(url);
url = LayoutEngine.class.getResource("false10.gif");
/** @todo load images via medialoader */
if (url != null)
IMAGE_FALSE = tk.getImage(url);
} // static init
/**
* Set Print Format.
* Optionally re-calculate layout.
* @param format print Format
* @param doLayout if layout exists, redo it
*/
public void setPrintFormat (MPrintFormat format, boolean doLayout)
{
m_format = format;
this.colSuppressRepeats = null;
// Initial & Default Settings
m_printCtx = new Properties(format.getCtx());
// Set Paper
boolean tempHasLayout = m_hasLayout;
m_hasLayout = false; // do not start re-calculation
MPrintPaper mPaper = MPrintPaper.get(format.getAD_PrintPaper_ID());
if (m_format.isStandardHeaderFooter()) {
StandardHeaderFooter headerFooter = new StandardHeaderFooter();
setPaper(mPaper.getCPaper(),
headerFooter.getHeaderHeight(), headerFooter.getFooterHeight());
}
else if (m_format.getAD_PrintHeaderFooter_ID() > 0) {
IPrintHeaderFooter printHeaderFooter = Core.getPrintHeaderFooter(m_format.getAD_PrintHeaderFooter());
if (printHeaderFooter != null) {
setPaper(mPaper.getCPaper(),
printHeaderFooter.getHeaderHeight(), printHeaderFooter.getFooterHeight());
} else {
setPaper(mPaper.getCPaper(),
m_format.getHeaderMargin(), m_format.getFooterMargin());
}
} else {
setPaper(mPaper.getCPaper(),
m_format.getHeaderMargin(), m_format.getFooterMargin());
}
m_hasLayout = tempHasLayout;
//
m_printColor = MPrintColor.get(getCtx(), format.getAD_PrintColor_ID());
m_printFont = MPrintFont.get (format.getAD_PrintFont_ID());
// Print Context
Env.setContext(m_printCtx, Page.CONTEXT_REPORTNAME, m_format.get_Translation(MPrintFormat.COLUMNNAME_Name));
Env.setContext(m_printCtx, Page.CONTEXT_HEADER, Env.getHeader(m_printCtx, m_windowNo));
Env.setContext(m_printCtx, Env.LANGUAGE, m_format.getLanguage().getAD_Language());
if (m_hasLayout && doLayout)
layout(); // re-calculate
} // setPrintFormat
/**
* Set PrintData.
* Optionally re-calculate layout.
* @param data data
* @param query query for parameter
* @param doLayout if layout exists, redo it
*/
public void setPrintData (PrintData data, MQuery query, boolean doLayout)
{
m_data = data;
m_query = query;
if (m_hasLayout && doLayout)
layout(); // re-calculate
} // setPrintData
/**
* Set print data.
* Optionally re-calculate layout.
* @param data
* @param query
* @param doLayout if layout exists, redo it
* @param trxName
*/
public void setPrintData (PrintData data, MQuery query, boolean doLayout, String trxName)
{
m_data = data;
m_query = query;
m_TrxName = trxName;
if (m_hasLayout && doLayout)
layout(); // re-calculate
} // setPrintData
/**
* Set Paper
* @param paper Paper
*/
public void setPaper (CPaper paper)
{
setPaper(paper, m_headerHeight, m_footerHeight);
} // setPaper
/**
* Set Paper.
* If layout exists and page size has change, re-calculate layout.
* @param paper Paper
* @param headerHeight header height
* @param footerHeight footer height
*/
public void setPaper (CPaper paper, int headerHeight, int footerHeight)
{
if (paper == null)
return;
//
boolean paperChange = headerHeight != m_headerHeight || footerHeight != m_footerHeight;
if (!paperChange)
paperChange = !paper.equals(m_paper);
//
if (log.isLoggable(Level.FINE))
log.fine(paper + " - Header=" + headerHeight + ", Footer=" + footerHeight);
m_paper = paper;
m_headerHeight = headerHeight;
m_footerHeight = footerHeight;
calculatePageSize();
//
if (m_hasLayout && paperChange)
layout(); // re-calculate
} // setPaper
/**
* Show Dialog and Set Paper.
* Optionally re-calculate layout.
* @param job printer job
*/
public void pageSetupDialog (PrinterJob job)
{
if (m_paper.pageSetupDialog(job))
{
setPaper(m_paper);
layout();
}
} // pageSetupDialog
/**
* Set Paper from Page Format.
* PageFormat is derived from CPaper.
* @param pf Optional PageFormat. If null, use standard paper Portrait.
*/
protected void setPageFormat (PageFormat pf)
{
if (pf != null)
setPaper(new CPaper(pf));
else
setPaper(null);
} // setPageFormat
/**
* Get Page Format
* @return page format
*/
public PageFormat getPageFormat ()
{
return m_paper.getPageFormat();
} // getPageFormat
/**
* Calculate Page size based on Paper and header/footerHeight.
*
* Paper: 8.5x11.0" Portrait x=32.0,y=32.0 w=548.0,h=728.0
* +------------------------ Paper 612x792
* | non-imageable space 32x32
* | +--------------------- Header = printable area start
* | | headerHeight=32 => [x=32,y=32,width=548,height=32]
* | +--------------------- Content
* | | => [x=32,y=64,width=548,height=664]
* | |
* | |
* | |
* | +--------------------- Footer
* | | footerHeight=32 => [x=32,y=728,width=548,height=32]
* | +--------------------- Footer end = printable area end
* | non-imageable space
* +------------------------
*
*/
private void calculatePageSize()
{
int x = (int)m_paper.getImageableX (true);
int w = (int)m_paper.getImageableWidth (true);
//
int y = (int)m_paper.getImageableY (true);
int h = (int)m_paper.getImageableHeight (true);
int height = m_headerHeight;
m_header.setBounds (x, y, w, height);
//
y += height;
height = h-m_headerHeight-m_footerHeight;
m_content.setBounds (x, y, w, height);
//
y += height;
height = m_footerHeight;
m_footer.setBounds (x, y, w, height);
if (log.isLoggable(Level.FINE)) log.fine("Paper=" + m_paper + ",HeaderHeight=" + m_headerHeight + ",FooterHeight=" + m_footerHeight
+ " => Header=" + m_header + ",Contents=" + m_content + ",Footer=" + m_footer);
} // calculatePageSize
/**
* Set Paper
* @return Paper
*/
public CPaper getPaper()
{
return m_paper;
} // getPaper
/**
* Create Layout
*/
private void layout()
{
// Header/Footer
m_headerFooter = new HeaderFooter(m_printCtx);
if (!m_format.isForm()) {
if (m_format.isStandardHeaderFooter()) {
StandardHeaderFooter headerFooter = new StandardHeaderFooter();
headerFooter.createHeaderFooter(m_format, m_headerFooter, m_header, m_footer, m_query);
} else if (m_format.getAD_PrintHeaderFooter_ID() > 0) {
IPrintHeaderFooter printHeaderFooter = Core.getPrintHeaderFooter(m_format.getAD_PrintHeaderFooter());
if (printHeaderFooter != null) {
printHeaderFooter.createHeaderFooter(m_format, m_headerFooter, m_header, m_footer, m_query);
} else {
if (log.isLoggable(Level.WARNING))
log.warning("Print Header/Footer not found, AD_PrintHeaderFooter_ID="+m_format.getAD_PrintHeaderFooter_ID());
}
}
}
//
m_pageNo = 0;
m_pages.clear();
m_tableElement = null;
newPage(true, false); // initialize
//
if (m_format.isForm())
layoutForm();
else
{
// Parameter
PrintElement element = layoutParameter();
if (element != null)
{
m_currPage.addElement (element);
element.setLocation(m_position[AREA_CONTENT]);
m_position[AREA_CONTENT].y += element.getHeight() + 5; // GAP
}
// Process Instance Log (if any):
element = layoutPInstanceLogs();
if (element != null)
{
m_currPage.addElement (element);
element.setLocation(m_position[AREA_CONTENT]);
m_position[AREA_CONTENT].y += element.getHeight() + 5; // GAP
}
// Table
if (m_data != null)
{
element = layoutTable(m_format, m_data, 0);
element.setLocation(m_content.getLocation());
for (int p = 1; p <= element.getPageCount(); p++)
{
if (p != 1)
newPage(true, false);
m_currPage.addElement (element);
}
}
}
//
String pageInfo = String.valueOf(m_pages.size()) + getPageInfo(m_pages.size());
Env.setContext(m_printCtx, Page.CONTEXT_PAGECOUNT, pageInfo);
Timestamp now = new Timestamp(System.currentTimeMillis());
Env.setContext(m_printCtx, Page.CONTEXT_DATE,
DisplayType.getDateFormat(DisplayType.Date, m_format.getLanguage()).format(now));
Env.setContext(m_printCtx, Page.CONTEXT_TIME,
DisplayType.getDateFormat(DisplayType.DateTime, m_format.getLanguage()).format(now));
//
// Page Background Image
Image image = null;
MPrintTableFormat tf = m_format.getTableFormat();
MTable table = MTable.get(getCtx(), getPrintInfo().getAD_Table_ID());
if(table.getColumn("IsPrinted") != null && !table.isView())
{
String tableName = table.getTableName();
final String sql = "SELECT IsPrinted FROM "+tableName+" WHERE "+tableName+"_ID=?";
boolean isPrinted = "Y".equals(DB.getSQLValueStringEx(m_TrxName, sql, getPrintInfo().getRecord_ID()));
if(isPrinted)
{
image = tf.getImageWaterMark();
}
}
else
{
image = tf.getImage();
}
// Update Page Info
int pages = m_pages.size();
for (int i = 0; i < pages; i++)
{
Page page = m_pages.get(i);
int pageNo = page.getPageNo();
pageInfo = String.valueOf(pageNo) + getPageInfo(pageNo);
page.setPageInfo(pageInfo);
page.setPageCount(pages);
page.setBackgroundImage(image);
}
m_hasLayout = true;
} // layout
/**
* Get PrintLayout (Report) Context
* @return context
*/
public Properties getCtx()
{
return m_printCtx;
} // getCtx
/**
* Get the number of printed Columns
* @return no of printed columns
*/
public int getColumnCount()
{
return m_columnCount;
} // getColumnCount
/**
* Set the current Print Area
* @param area see HEADER_.. constants
*/
protected void setArea (int area)
{
if (m_area == area)
return;
if (area < 0 || area > 2)
throw new ArrayIndexOutOfBoundsException (area);
m_area = area;
} // setArea
/**
* Get the current Print Area
* @return area see HEADER_.. constants
*/
public int getArea ()
{
return m_area;
} // getArea
/**
* Get bounds of current Area
* @return rectangle with bounds
*/
public Rectangle getAreaBounds()
{
Rectangle part = m_content;
if (m_area == AREA_HEADER)
part = m_header;
else if (m_area == AREA_FOOTER)
part = m_footer;
//
return part;
} // getAreaBounds
/**
* Create New Page, set position to top content
* @param force if false will check if nothing printed so far
* @param preserveXPos preserve X Position of content area
* @return new page no
*/
protected int newPage (boolean force, boolean preserveXPos)
{
// We are on a new page
if (!force
&& m_position[AREA_CONTENT].getX() == m_content.x
&& m_position[AREA_CONTENT].getY() == m_content.y)
{
if (log.isLoggable(Level.FINE))
log.fine("skipped");
return m_pageNo;
}
m_pageNo++;
m_currPage = new Page (m_printCtx, m_pageNo);
m_pages.add(m_currPage);
//
m_position[AREA_HEADER].setLocation(m_header.x, m_header.y);
if (preserveXPos)
m_position[AREA_CONTENT].setLocation(m_position[AREA_CONTENT].x, m_content.y);
else
m_position[AREA_CONTENT].setLocation(m_content.x, m_content.y);
m_position[AREA_FOOTER].setLocation(m_footer.x, m_footer.y);
m_maxHeightSinceNewLine = new float[] {0f, 0f, 0f};
if (log.isLoggable(Level.FINER)) log.finer("Page=" + m_pageNo);
return m_pageNo;
} // newPage
/**
* Move to New Line (may cause new page)
*/
protected void newLine ()
{
Rectangle part = m_content;
if (m_area == AREA_HEADER)
part = m_header;
else if (m_area == AREA_FOOTER)
part = m_footer;
// Temporary NL Position
int xPos = part.x;
if (m_tempNLPositon != 0)
xPos = m_tempNLPositon;
if (isYspaceFor(m_maxHeightSinceNewLine[m_area]))
{
m_position[m_area].setLocation(xPos, m_position[m_area].y + m_maxHeightSinceNewLine[m_area]);
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
}
else if (m_area == AREA_CONTENT)
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough Y space "
+ m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area);
newPage(true, false);
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
}
else // footer/header
{
m_position[m_area].setLocation(part.x, m_position[m_area].y + m_maxHeightSinceNewLine[m_area]);
log.log(Level.SEVERE, "Outside of Area(" + m_area + "): " + m_position[m_area]);
}
m_maxHeightSinceNewLine[m_area] = 0f;
} // newLine
/**
* Get current Page Number (not zero based)
* @return Page No
*/
public int getPageNo()
{
return m_pageNo;
} // getPageNo
/**
* Get Page
* @param pageNo page number (NOT zero based)
* @return Page
*/
public Page getPage (int pageNo)
{
if (pageNo <= 0 || pageNo > m_pages.size())
{
log.log(Level.SEVERE, "No page #" + pageNo);
return null;
}
Page retValue = m_pages.get(pageNo-1);
return retValue;
} // getPage
/**
* Get Pages
* @return Pages in ArrayList
*/
public ArrayList getPages()
{
return m_pages;
} // getPages
/**
* Get Header and Footer info
* @return Header and Footer
*/
public HeaderFooter getHeaderFooter()
{
return m_headerFooter;
} // getPages
/**
* Set Current page to Page No
* @param pageNo page number (NOT zero based)
*/
protected void setPage (int pageNo)
{
if (pageNo <= 0 || pageNo > m_pages.size())
{
log.log(Level.SEVERE, "No page #" + pageNo);
return;
}
Page retValue = m_pages.get(pageNo-1);
m_currPage = retValue;
} // setPage
/**
* Get Page Info for Multi-Page tables
* @param pageNo page
* @return info e.g. (1,1)
*/
public String getPageInfo(int pageNo)
{
if (m_tableElement == null || m_tableElement.getPageXCount() == 1)
return "";
int pi = m_tableElement.getPageIndex(pageNo);
StringBuilder sb = new StringBuilder("(");
sb.append(m_tableElement.getPageYIndex(pi)+1).append(",")
.append(m_tableElement.getPageXIndex(pi)+1).append(")");
return sb.toString();
} // getPageInfo
/**
* Get Max Page Info for Multi-Page tables
* @return info e.g. (3,2)
*/
public String getPageInfoMax()
{
if (m_tableElement == null || m_tableElement.getPageXCount() == 1)
return "";
StringBuilder sb = new StringBuilder("(");
sb.append(m_tableElement.getPageYCount()).append(",")
.append(m_tableElement.getPageXCount()).append(")");
return sb.toString();
} // getPageInfoMax
/**
* Get Print Format Model
* @return model
*/
public MPrintFormat getFormat()
{
return m_format;
} // getFormat
/**
* Get Print Interface (Pageable, Printable, Doc)
* @param isCopy true if it is a document copy
* @return this or null if nothing to print
*/
public LayoutEngine getPageable (boolean isCopy)
{
setCopy(isCopy);
if (getNumberOfPages() == 0
|| !ArchiveEngine.isValid(this))
{
log.warning("Nothing to print - " + toString());
return null;
}
return this;
} // getPageable
/**
* Set Position on current page (no check)
* @param p point relative in area
*/
protected void setRelativePosition (Point2D p)
{
if (p == null)
return;
Rectangle part = m_content;
if (m_area == AREA_HEADER)
part = m_header;
else if (m_area == AREA_FOOTER)
part = m_footer;
m_position[m_area].setLocation(part.x + p.getX(), part.y + p.getY());
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
} // setPosition
/**
* Set Position on current page (no check)
* @param x x position in 1/72 inch
* @param y y position in 1/72 inch
*/
protected void setRelativePosition (float x, float y)
{
setRelativePosition(new Point2D.Float(x, y));
} // setPosition
/**
* Get current position on current page
* @return current position
*/
public Point2D getPosition ()
{
return m_position[m_area];
} // getPosition
/**
* Set X Position on current page
* @param x x position in 1/72 inch
*/
protected void setX (float x)
{
m_position[m_area].x = x;
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
} // setX
/**
* Add to X Position on current page
* @param xOffset add offset to x position in 1/72 inch
*/
protected void addX (float xOffset)
{
if (xOffset == 0f)
return;
m_position[m_area].x += xOffset;
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
} // addX
/**
* Get X Position on current page
* @return x position in 1/72 inch
*/
public float getX ()
{
return (float)m_position[m_area].x;
} // getX
/**
* Set Y Position on current page
* @param y y position in 1/72 inch
*/
protected void setY (int y)
{
m_position[m_area].y = y;
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
} // setY
/**
* Add to Y Position - may cause New Page
* @param yOffset add offset to y position in 1/72 inch
*/
protected void addY (int yOffset)
{
if (yOffset == 0f)
return;
if (isYspaceFor(yOffset))
{
m_position[m_area].y += yOffset;
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
}
else if (m_area == AREA_CONTENT)
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough Y space "
+ m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area);
newPage(true, true);
if (log.isLoggable(Level.FINEST)) log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y);
}
else
{
m_position[m_area].y += yOffset;
log.log(Level.SEVERE, "Outside of Area: " + m_position);
}
} // addY
/**
* Get Y Position on current page
* @return y position in 1/72 inch
*/
public float getY ()
{
return (float)m_position[m_area].y;
} // getY
/**
* Get remaining X dimension space on current page in current Area
* @return space in 1/72 inch remaining in line
*/
public float getXspace()
{
Rectangle part = m_content;
if (m_area == AREA_HEADER)
part = m_header;
else if (m_area == AREA_FOOTER)
part = m_footer;
//
return (float)(part.x + part.width - m_position[m_area].x);
} // getXspace
/**
* Is Remaining Space OK for Width in Area
* @param width width
* @return true if width fits in area
*/
public boolean isXspaceFor (float width)
{
return (getXspace()-width) >= 0f;
} // isXspaceFor
/**
* Get remaining Y dimension space on current page in Area
* @return space in 1/72 inch remaining on page
*/
public float getYspace()
{
Rectangle part = m_content;
if (m_area == AREA_HEADER)
part = m_header;
else if (m_area == AREA_FOOTER)
part = m_footer;
//
return (float)(part.y + part.height - m_position[m_area].y);
} // getYspace
/**
* Is Remaining Space OK for Height in Area
* @param height height
* @return true if height fits in area
*/
public boolean isYspaceFor (float height)
{
return (getYspace()-height) >= 0f;
} // isYspaceFor
/**
* Layout Form.
* For every Row, loop through the Format
* and calculate element size and position.
*/
private void layoutForm()
{
m_columnCount = 0;
if (m_data == null)
return;
// for every row
int rowCount = m_data.getRowCount();
for (int row = 0; row < rowCount; row++)
{
if (log.isLoggable(Level.INFO)) log.info("Row=" + row);
m_data.setRowIndex(row);
if (row > 0 && m_format.isBreakPagePerRecord())
newPage(true, false); // break page per record when the report is a form
boolean somethingPrinted = true; // prevent NL of nothing printed and suppress null
// for every item
for (int i = 0; i < m_format.getItemCount(); i++)
{
MPrintFormatItem item = m_format.getItem(i);
if (!item.isPrinted())
continue;
m_columnCount++;
// Read Header/Footer just once
if (row > 0 && (item.isHeader() || item.isFooter()))
continue;
// Position
if (item.isHeader()) // Area
setArea(AREA_HEADER);
else if (item.isFooter())
setArea(AREA_FOOTER);
else
setArea(AREA_CONTENT);
//
if (item.isSetNLPosition() && item.isRelativePosition())
m_tempNLPositon = 0;
// New Page/Line
if (item.isNextLine() && somethingPrinted) // new line
{
newLine ();
somethingPrinted = false;
}
else
{
addX(m_lastWidth[m_area]);
}
if (item.isNextPage()) // item.isPageBreak() // new page
{
newPage(false, false);
}
// Relative Position space
if (item.isRelativePosition())
{
addX(item.getXSpace());
addY(item.getYSpace());
}
else // Absolute relative position
setRelativePosition(item.getXPosition(), item.getYPosition());
// Temporary NL Position when absolute positioned
if (item.isSetNLPosition() && !item.isRelativePosition())
m_tempNLPositon = (int)getPosition().getX();
// line alignment
String alignment = item.getFieldAlignmentType();
int maxWidth = item.getMaxWidth();
boolean lineAligned = false;
if (item.isRelativePosition())
{
if (item.isLineAlignLeading())
{
alignment = MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft;
maxWidth = getAreaBounds().width;
lineAligned = true;
}
else if (item.isLineAlignCenter())
{
alignment = MPrintFormatItem.FIELDALIGNMENTTYPE_Center;
maxWidth = getAreaBounds().width;
lineAligned = true;
}
else if (item.isLineAlignTrailing())
{
alignment = MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight;
maxWidth = getAreaBounds().width;
lineAligned = true;
}
}
// Type
PrintElement element = null;
if ( !PrintDataEvaluatee.hasPageLogic(item.getDisplayLogic()) && !isDisplayed(m_data, item) )
{
;
}
else if (item.isTypePrintFormat()) //** included PrintFormat
{
element = includeFormat (item, m_data);
}
else if (item.isBarcode())
{
element = createBarcodeElement(item, m_data);
if (element != null)
{
element.layout(maxWidth, item.getMaxHeight(), false, alignment);
}
}
else if (item.isTypeImage()) //** Image
{
if (item.isImageField())
element = createImageElement (item, m_data);
else if (item.isImageIsAttached())
element = ImageElement.get (item.get_ID());
else
{
String url = item.getImageURL();
if (url.indexOf(Evaluator.VARIABLE_START_END_MARKER) >= 0)
{
PrintDataEvaluatee.PrintDataDataProvider dp = new PrintDataEvaluatee.PrintDataDataProvider(null, m_data);
DefaultEvaluatee evaluatee = new DefaultEvaluatee(dp);
url = Env.parseVariable(url, evaluatee, true, false);
}
element = ImageElement.get (url);
}
if (element != null)
element.layout(maxWidth, item.getMaxHeight(), false, alignment);
}
else if (item.isTypeField()) //** Field
{
if (maxWidth == 0 && item.isFieldAlignBlock())
maxWidth = getAreaBounds().width;
element = createFieldElement (item, maxWidth, alignment, m_format.isForm());
}
else if (item.isTypeBox()) //** Line/Box
{
if (m_format.isForm())
element = createBoxElement(item);
// Auto detect width - teo_sarca, BF [ 1825876 ]
if (element != null && maxWidth == 0) {
maxWidth = getAreaBounds().width;
element.setMaxWidth(maxWidth);
}
}
/** START DEVCOFFEE: Script print format type **/
else if (item.getPrintFormatType().equals(MPrintFormatItem.PRINTFORMATTYPE_Script))
{
element = createFieldElement (item, maxWidth, alignment, m_format.isForm());
}
else // (item.isTypeText()) //** Text
{
String printName = item.getPrintName (m_format.getLanguage ());
int summaryTagStart = printName == null ? -1 : printName.indexOf("");
int summaryTagEnd = summaryTagStart >= 0 ? printName.indexOf("", summaryTagStart) : -1;
if (summaryTagStart >= 0 && summaryTagEnd > summaryTagStart) {
if (m_data.isFunctionRow(row) && row+1 == rowCount) {
printName = printName.substring(summaryTagStart+3);
printName = printName.substring(0, printName.length()-4);
} else {
printName = printName.substring(0, summaryTagStart);
}
}
if (maxWidth == 0 && item.isFieldAlignBlock())
maxWidth = getAreaBounds().width;
element = createStringElement (printName,
item.getAD_PrintColor_ID (), item.getAD_PrintFont_ID (),
maxWidth, item.getMaxHeight (), item.isHeightOneLine (), alignment, true);
}
// Printed - set last width/height
if (element != null)
{
somethingPrinted = true;
if (!lineAligned)
m_lastWidth[m_area] = element.getWidth();
m_lastHeight[m_area] = element.getHeight();
}
else
{
somethingPrinted = false;
m_lastWidth[m_area] = 0f;
m_lastHeight[m_area] = 0f;
// Carlos Ruiz - globalqss - 20060826
// Fix problem when the element is not printed but X Space was previously added
if (item.isRelativePosition())
{
addX(-item.getXSpace());
addY(-item.getYSpace());
}
// end globalqss
}
// Does it fit?
if (item.isRelativePosition() && !lineAligned)
{
if (!isXspaceFor(m_lastWidth[m_area]))
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough X space for "
+ m_lastWidth[m_area] + " - remaining " + getXspace() + " - Area=" + m_area);
newLine ();
}
if (m_area == AREA_CONTENT && !isYspaceFor(m_lastHeight[m_area]))
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough Y space "
+ m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area);
newPage (true, true);
}
}
// We know Position and Size
if (element != null)
element.setLocation(m_position[m_area]);
// Add to Area
if (m_area == AREA_CONTENT)
m_currPage.addElement (element);
else
m_headerFooter.addElement (element);
if (PrintDataEvaluatee.hasPageLogic(item.getDisplayLogic()))
{
element.setPrintData(m_data);
element.setRowIndex(row);
element.setPageLogic(item.getDisplayLogic());
}
//
if (m_lastHeight[m_area] > m_maxHeightSinceNewLine[m_area])
m_maxHeightSinceNewLine[m_area] = m_lastHeight[m_area];
// Reset maxHeightSinceNewLine if we have an absolute position - teo_sarca BF [ 1807917 ]
if (!item.isRelativePosition())
m_maxHeightSinceNewLine[m_area] = m_lastHeight[m_area];
} // for every item
} // for every row
} // layoutForm
/**
* Include Table Format
* @param item print format item
* @param data print data
* @return Print Element
*/
private PrintElement includeFormat (MPrintFormatItem item, PrintData data)
{
newLine();
PrintElement element = null;
//
// COF #10540 - avoid error when generating PDF due to inconsistency in the configuration
if (item.getAD_PrintFormatChild_ID() <= 0)
{
log.log(Level.SEVERE, "Included format not configured. AD_PrintFormat_ID = " + item.getAD_PrintFormat_ID() + ", AD_PrintFormatItem_ID=" + item.getAD_PrintFormatItem_ID());
return element;
}
MPrintFormat format = MPrintFormat.get (getCtx(), item.getAD_PrintFormatChild_ID(), false);
format.setLanguage(m_format.getLanguage());
if (m_format.isTranslationView())
format.setTranslationLanguage(m_format.getLanguage());
int AD_Column_ID = item.getAD_Column_ID();
if (log.isLoggable(Level.INFO)) log.info(format + " - Item=" + item.getName() + " (" + AD_Column_ID + ")");
//
Object obj = data.getNodeByPrintFormatItemId(item.getAD_PrintFormatItem_ID());
if (obj == null)
{
data.dumpHeader();
data.dumpCurrentRow();
log.log(Level.SEVERE, "No Node - AD_Column_ID="
+ AD_Column_ID + " - " + item + " - " + data);
return null;
}
PrintDataElement dataElement = (PrintDataElement)obj;
String recordString = dataElement.getValueKey();
if (recordString == null || recordString.length() == 0)
{
data.dumpHeader();
data.dumpCurrentRow();
log.log(Level.SEVERE, "No Record Key - " + dataElement
+ " - AD_Column_ID=" + AD_Column_ID + " - " + item);
return null;
}
MQuery query = new MQuery (format.getAD_Table_ID());
if (Util.isUUID(recordString)) {
query.addRestriction(item.getColumnName(), MQuery.EQUAL, recordString);
} else {
int Record_ID = 0;
try
{
Record_ID = Integer.parseInt(recordString);
}
catch (Exception e)
{
data.dumpCurrentRow();
log.log(Level.SEVERE, "Invalid Record Key - " + recordString
+ " (" + e.getMessage()
+ ") - AD_Column_ID=" + AD_Column_ID + " - " + item);
return null;
}
query.addRestriction(item.getColumnName(), MQuery.EQUAL, Integer.valueOf(Record_ID));
}
format.setTranslationViewQuery(query);
if (log.isLoggable(Level.FINE))
log.fine(query.toString());
//
DataEngine de = new DataEngine(format.getLanguage(),m_TrxName, m_windowNo);
PrintData includedData = de.getPrintData(data.getCtx(), format, query);
if (includedData == null)
return null;
if (log.isLoggable(Level.FINE))
log.fine(includedData.toString());
setChildPrintFormatDetails(item, includedData); //map printdata and printformat item
//
element = layoutTable (format, includedData, item.getXSpace());
// handle multi page tables
if (element.getPageCount() > 1)
{
Point2D.Double loc = m_position[m_area];
element.setLocation(loc);
for (int p = 1; p < element.getPageCount(); p++) // don't add last one
{
m_currPage.addElement (element);
newPage(true, false);
}
m_position[m_area] = loc;
((TableElement)element).setHeightToLastPage();
}
m_lastWidth[m_area] = element.getWidth();
m_lastHeight[m_area] = element.getHeight();
if (!isXspaceFor(m_lastWidth[m_area]))
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough X space for "
+ m_lastWidth[m_area] + " - remaining " + getXspace() + " - Area=" + m_area);
newLine ();
}
if (m_area == AREA_CONTENT && !isYspaceFor(m_lastHeight[m_area]))
{
if (log.isLoggable(Level.FINEST)) log.finest("Not enough Y space "
+ m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area);
newPage (true, false);
}
//
return element;
} // includeFormat
/**
* Create String Element
*
* @param content string to be printed
* @param AD_PrintColor_ID color
* @param AD_PrintFont_ID font
* @param maxWidth max width
* @param maxHeight max height
* @param isHeightOneLine onle line only
* @param FieldAlignmentType alignment type (MPrintFormatItem.FIELD_ALIGN_*)
* @param isTranslated if true and content contaiins @variable@, it is dynamically translated during print
* @return Print Element
*/
private PrintElement createStringElement (String content, int AD_PrintColor_ID, int AD_PrintFont_ID,
int maxWidth, int maxHeight, boolean isHeightOneLine, String FieldAlignmentType, boolean isTranslated)
{
if (content == null || content.length() == 0)
return null;
// Color / Font
Color color = getColor(); // default
if (AD_PrintColor_ID != 0 && m_printColor.get_ID() != AD_PrintColor_ID)
{
MPrintColor c = MPrintColor.get (getCtx(), AD_PrintColor_ID);
if (c.getColor() != null)
color = c.getColor();
}
Font font = m_printFont.getFont(); // default
if (AD_PrintFont_ID != 0 && m_printFont.get_ID() != AD_PrintFont_ID)
{
MPrintFont f = MPrintFont.get (AD_PrintFont_ID);
if (f.getFont() != null)
font = f.getFont();
}
PrintElement e = new StringElement(content, font, color, null, isTranslated);
e.layout (maxWidth, maxHeight, isHeightOneLine, FieldAlignmentType);
return e;
} // createStringElement
/**
* Create Field Element
* @param item Format Item
* @param maxWidth max width
* @param FieldAlignmentType alignment type (MPrintFormatItem.FIELD_ALIGN_*)
* @param isForm true if document
* @return Print Element or null if nothing to print
*/
private PrintElement createFieldElement (MPrintFormatItem item, int maxWidth,
String FieldAlignmentType, boolean isForm)
{
// Get Data
Object obj = m_data.getNodeByPrintFormatItemId(item.getAD_PrintFormatItem_ID());
if (obj == null)
return null;
else if (obj instanceof PrintDataElement)
;
else
{
log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass());
return null;
}
// Convert DataElement to String
PrintDataElement data = (PrintDataElement)obj;
if (data.isNull() && item.isSuppressNull())
return null;
String stringContent = data.getValueDisplay (m_format.getLanguage());
if ((stringContent == null || stringContent.length() == 0) && item.isSuppressNull())
return null;
// non-string
Object content = stringContent;
if (data.getValue() instanceof Boolean)
content = data.getValue();
// Convert AmtInWords Content to alpha
if ("AmtInWords".equals(item.getColumnName()))
{
if (log.isLoggable(Level.FINE))
log.fine("AmtInWords: " + stringContent);
stringContent = Msg.getAmtInWords (m_format.getLanguage(), stringContent);
content = stringContent;
}
// Label
String label = item.getPrintName(m_format.getLanguage());
String labelSuffix = item.getPrintNameSuffix(m_format.getLanguage());
// ID Type
NamePair ID = null;
if (data.isID())
{ // Record_ID/ColumnName
Object value = data.getValue();
if (value instanceof KeyNamePair)
ID = new KeyNamePair(((KeyNamePair)value).getKey(), item.getColumnName());
else if (value instanceof ValueNamePair)
ID = new ValueNamePair(((ValueNamePair)value).getValue(), item.getColumnName());
}
else if (MPrintFormatItem.FIELDALIGNMENTTYPE_Default.equals(FieldAlignmentType))
{
if (data.isNumeric())
FieldAlignmentType = MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight;
else
FieldAlignmentType = MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft;
}
// Get Color/ Font
Color color = getColor(); // default
if (ID != null && !isForm)
; // link color/underline handled in PrintElement classes
else if (item.getAD_PrintColor_ID() != 0 && m_printColor.get_ID() != item.getAD_PrintColor_ID())
{
MPrintColor c = MPrintColor.get (getCtx(), item.getAD_PrintColor_ID());
if (c.getColor() != null)
color = c.getColor();
}
Font font = m_printFont.getFont(); // default
if (item.getAD_PrintFont_ID() != 0 && m_printFont.get_ID() != item.getAD_PrintFont_ID())
{
MPrintFont f = MPrintFont.get (item.getAD_PrintFont_ID());
if (f.getFont() != null)
font = f.getFont();
}
// Create String, HTML or Location
PrintElement e = null;
if (data.getDisplayType() == DisplayType.Location)
{
e = new LocationElement(m_printCtx, ((KeyNamePair)ID).getKey(), font, color,
item.isHeightOneLine(), label, labelSuffix, m_format.getLanguage().getAD_Language());
e.layout (maxWidth, item.getMaxHeight(), item.isHeightOneLine(), FieldAlignmentType);
}
else
{
if (HTMLElement.isHTML(stringContent))
e = new HTMLElement(stringContent);
else
e = new StringElement(content, font, color, isForm ? null : ID, label, labelSuffix);
e.layout (maxWidth, item.getMaxHeight(), item.isHeightOneLine(), FieldAlignmentType);
}
return e;
} // createFieldElement
/**
* Create Box/Line Element
* @param item item
* @return box element
*/
private PrintElement createBoxElement (MPrintFormatItem item)
{
Color color = getColor(); // default
if (item.getAD_PrintColor_ID() != 0
&& m_printColor.get_ID() != item.getAD_PrintColor_ID())
{
MPrintColor c = MPrintColor.get (getCtx(), item.getAD_PrintColor_ID());
if (c.getColor() != null)
color = c.getColor();
}
return new BoxElement(item, color);
} // createBoxElement
/**
* Create Image Element from item
* @param item print format item
* @param printData
* @return image element
*/
private PrintElement createImageElement (MPrintFormatItem item, PrintData printData)
{
Object obj = printData.getNodeByPrintFormatItem(item);
if (obj == null)
return null;
else if (obj instanceof PrintDataElement)
;
else
{
log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass());
return null;
}
PrintDataElement data = (PrintDataElement)obj;
if (data.isNull() && item.isSuppressNull())
return null;
String url = data.getValueDisplay (m_format.getLanguage());
if ((url == null || url.length() == 0))
{
if (item.isSuppressNull())
return null;
else // should create an empty area
return null;
}
ImageElement element = null;
if (data.getDisplayType() == DisplayType.Image) {
element = ImageElement.get (data, url);
} else {
element = ImageElement.get (url);
}
return element;
} // createImageElement
/**
* Create Barcode Element
* @param item item
* @param printData
* @return barcode element
*/
private PrintElement createBarcodeElement (MPrintFormatItem item, PrintData printData)
{
// Get Data
Object obj = printData.getNodeByPrintFormatItem(item);
if (obj == null)
return null;
else if (obj instanceof PrintDataElement)
;
else
{
log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass());
return null;
}
// Convert DataElement to String
PrintDataElement data = (PrintDataElement)obj;
if (data.isNull() && item.isSuppressNull())
return null;
String stringContent = data.getValueDisplay (m_format.getLanguage());
if ((stringContent == null || stringContent.length() == 0) && item.isSuppressNull())
return null;
BarcodeElement element = new BarcodeElement (stringContent, item);
if (element.isValid())
return element;
return null;
} // createBarcodeElement
/**
* Get default Color
* @return color
*/
public Color getColor()
{
if (m_printColor == null)
return Color.BLACK;
return m_printColor.getColor();
} // getColor
/**
* Layout Table.
* Convert PrintData into TableElement.
* @param format format to use
* @param printData data to use
* @param xOffset X Axis - offset (start of table) i.e. indentation
* @return TableElement
*/
private PrintElement layoutTable (MPrintFormat format, PrintData printData,
int xOffset)
{
if (log.isLoggable(Level.INFO)) log.info(format.getName() + " - " + printData.getName());
MPrintTableFormat tf = format.getTableFormat();
// Initial Values
HashMap rowColFont = new HashMap();
MPrintFont printFont = MPrintFont.get (format.getAD_PrintFont_ID());
rowColFont.put(new Point(TableElement.ALL,TableElement.ALL), printFont.getFont());
tf.setStandard_Font(printFont.getFont());
rowColFont.put(new Point(TableElement.HEADER_ROW,TableElement.ALL), tf.getHeader_Font());
//
HashMap rowColColor = new HashMap();
MPrintColor printColor = MPrintColor.get (getCtx(), format.getAD_PrintColor_ID());
rowColColor.put(new Point(TableElement.ALL,TableElement.ALL), printColor.getColor());
rowColColor.put(new Point(TableElement.HEADER_ROW,TableElement.ALL), tf.getHeaderFG_Color());
//
HashMap rowColBackground = new HashMap();
rowColBackground.put(new Point(TableElement.HEADER_ROW,TableElement.ALL), tf.getHeaderBG_Color());
//
HashMap rowColReportLine = new HashMap ();
//
HashMap colPositions = new HashMap ();
// Sizes
boolean multiLineHeader = tf.isMultiLineHeader();
int pageNoStart = m_pageNo;
int repeatedColumns = 1;
Rectangle firstPage = new Rectangle(m_content);
firstPage.x += xOffset;
firstPage.width -= xOffset;
int yOffset = (int)m_position[AREA_CONTENT].y - m_content.y;
firstPage.y += yOffset;
firstPage.height -= yOffset;
Rectangle nextPages = new Rectangle(m_content);
nextPages.x += xOffset;
nextPages.width -= xOffset;
// Column count
List instanceAttributeList = new ArrayList<>();
List instanceAttributeItems = new ArrayList<>();
int columnCount = 0;
for (int c = 0; c < format.getItemCount(); c++)
{
if (format.getItem(c).isPrinted())
{
if (format.getItem(c).isTypeField())
{
if(format.getItem(c).isPrintInstanceAttributes())
{
instanceAttributeList.add(columnCount);
instanceAttributeItems.add(format.getItem(c));
continue;
}
}
columnCount++;
}
}
// Header & Column Setup
ValueNamePair[] columnHeader = new ValueNamePair[columnCount];
int[] columnMaxWidth = new int[columnCount];
int[] columnMaxHeight = new int[columnCount];
boolean[] fixedWidth = new boolean [columnCount];
Boolean [] colSuppressRepeats = new Boolean[columnCount];
String[] columnJustification = new String[columnCount];
HashMap additionalLines = new HashMap();
ArrayList pageLogics = new ArrayList();
boolean hasPageLogic = false;
int col = 0;
for (int c = 0; c < format.getItemCount(); c++)
{
MPrintFormatItem item = format.getItem(c);
if (instanceAttributeItems.contains(item))
continue;
if (item.isPrinted())
{
if (item.isNextLine() && item.getBelowColumn() != 0)
{
additionalLines.put(Integer.valueOf(col), Integer.valueOf(item.getBelowColumn()-1));
if (!item.isSuppressNull())
{
if (item.is_Immutable())
item = new MPrintFormatItem(item);
item.setIsSuppressNull(true); // display size will be set to 0 in TableElement
//this can be tenant or system print format
item.saveCrossTenantSafeEx();
CacheMgt.get().reset(MPrintFormat.Table_Name, format.get_ID());
}
}
columnHeader[col] = new ValueNamePair(item.getColumnName(),
item.getPrintName(format.getLanguage()));
colPositions.put(item.getPrintName(), col);
columnMaxWidth[col] = item.getMaxWidth();
fixedWidth[col] = (columnMaxWidth[col] != 0 && item.isFixedWidth());
colSuppressRepeats[col] = item.isSuppressRepeats();
if (item.isSuppressNull())
{
if (columnMaxWidth[col] == 0)
columnMaxWidth[col] = -1; // indication suppress if Null
else
columnMaxWidth[col] *= -1;
}
columnMaxHeight[col] = item.getMaxHeight();
if (item.isHeightOneLine())
columnMaxHeight[col] = -1;
columnJustification[col] = item.getFieldAlignmentType();
if (columnJustification[col] == null || columnJustification[col].equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Default))
columnJustification[col] = MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft; // when generated sets correct alignment
// Column Fonts
if (item.getAD_PrintFont_ID() != 0 && item.getAD_PrintFont_ID() != format.getAD_PrintFont_ID())
{
MPrintFont font = MPrintFont.get(item.getAD_PrintFont_ID());
rowColFont.put(new Point(TableElement.ALL, col), font.getFont());
}
if (item.getAD_PrintColor_ID() != 0 && item.getAD_PrintColor_ID() != format.getAD_PrintColor_ID())
{
MPrintColor color = MPrintColor.get (getCtx(), item.getAD_PrintColor_ID());
rowColColor.put(new Point(TableElement.ALL, col), color.getColor());
}
//
if (PrintDataEvaluatee.hasPageLogic(item.getDisplayLogic()))
{
pageLogics.add(item.getDisplayLogic());
hasPageLogic = true;
}
else
{
pageLogics.add(null);
}
//
col++;
}
}
// The Data
int rows = printData.getRowCount();
SerializableMatrix elements = new SerializableMatrixImpl(m_PrintInfo.getName());
KeyNamePair[] pk = new KeyNamePair[rows];
String pkColumnName = null;
ArrayList functionRows = new ArrayList();
ArrayList pageBreak = new ArrayList();
ArrayList finReportSumRows = new ArrayList();
int lastLevelNo = 0;
// for all rows
for (int row = 0; row < rows; row++)
{
int levelNo = 0;
ArrayList columns = new ArrayList();
printData.setRowIndex(row);
if (printData.isFunctionRow())
{
functionRows.add(Integer.valueOf(row));
rowColFont.put(new Point(row, TableElement.ALL), tf.getFunct_Font());
rowColColor.put(new Point(row, TableElement.ALL), tf.getFunctFG_Color());
rowColBackground.put(new Point(row, TableElement.ALL), tf.getFunctBG_Color());
if (printData.isPageBreak())
{
pageBreak.add(Integer.valueOf(row));
if (log.isLoggable(Level.FINER))
log.finer("PageBreak row=" + row);
}
}
// Summary/Line Levels for Financial Reports
else
{
levelNo = printData.getLineLevelNo();
if (levelNo < 0)
levelNo = -levelNo;
if (levelNo < lastLevelNo)
finReportSumRows.add(row);
if (levelNo != 0)
{
Font base = printFont.getFont();
if (levelNo == 1)
rowColFont.put(new Point(row, TableElement.ALL),
new Font(base.getName(), Font.ITALIC, base.getSize() - levelNo));
else if (levelNo == 2)
rowColFont.put(new Point(row, TableElement.ALL),
new Font(base.getName(), Font.PLAIN, base.getSize() - levelNo));
}
lastLevelNo = levelNo;
}
MReportLine rLine = printData.getMReportLine();
// for all columns
for (int c = 0; c < format.getItemCount(); c++)
{
Serializable columnElement = null;
MPrintFormatItem item = format.getItem(c);
if (instanceAttributeItems.contains(item))
continue;
Serializable dataElement = null;
if (item.isPrinted()) // Text Columns
{
if (rLine != null && levelNo == 0 && item.getColumnName().startsWith("Col_"))
rowColReportLine.put(new Point(row, colPositions.get(item.getPrintName())), rLine);
if ( !PrintDataEvaluatee.hasPageLogic(item.getDisplayLogic()) && !isDisplayed(printData, item) )
{
;
}
else if (item.isTypeImage())
{
if (item.isImageField())
columnElement = createImageElement (item, printData);
else if (item.isImageIsAttached())
columnElement = ImageElement.get (item.get_ID());
else
{
String url = item.getImageURL();
if (url.indexOf(Evaluator.VARIABLE_START_END_MARKER) >= 0)
{
PrintDataEvaluatee.PrintDataDataProvider dp = new PrintDataEvaluatee.PrintDataDataProvider(null, printData);
DefaultEvaluatee evaluatee = new DefaultEvaluatee(dp);
url = Env.parseVariable(url, evaluatee, true, false);
}
columnElement = ImageElement.get (url);
}
if (columnElement != null)
((PrintElement)columnElement).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
}
else if (item.isBarcode())
{
columnElement = createBarcodeElement(item, printData);
if (columnElement != null)
((PrintElement)columnElement).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
}
else if (item.isTypeText() )
{
columnElement = item.getPrintName(format.getLanguage());
}
else if (item.isTypeField() || item.getPrintFormatType().equals(MPrintFormatItem.PRINTFORMATTYPE_Script))
{
Object obj = printData.getNodeByPrintFormatItem(item);
if (obj == null)
;
else if (obj instanceof PrintDataElement)
{
PrintDataElement pde = (PrintDataElement)obj;
if (pde.isID() || pde.isYesNo())
dataElement = (Serializable) pde.getValue();
else
dataElement = pde.getValueDisplay(format.getLanguage());
}
else
log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass());
columnElement = dataElement;
}
else // item.isTypeBox() or isTypePrintFormat()
{
log.warning("Unsupported: " + (item.isTypeBox() ? "Box" : "PrintFormat") + " in Table: " + item);
}
columns.add(columnElement);
} // printed
} // for all columns
elements.addRow(columns);
PrintDataElement pde = printData.getPKey();
if (pde != null) // for FunctionRows
{
pk[row] = (KeyNamePair)pde.getValue();
if (pkColumnName == null)
pkColumnName = pde.getColumnName();
}
} // for all rows
//add asi attributes columns
List asiElements = new ArrayList<>();
if (instanceAttributeList.size() > 0) {
for(int i = 0; i < instanceAttributeItems.size(); i ++) {
MPrintFormatItem item = instanceAttributeItems.get(i);
int columnIndex = instanceAttributeList.get(i);
InstanceAttributeData asiElement = new InstanceAttributeData(item, columnIndex);
asiElement.readAttributesData(printData);
asiElements.add(asiElement);
}
int columnOffset = 0;
for (InstanceAttributeData element : asiElements) {
TableProperties tableProperties = new TableProperties(columnHeader, columnMaxWidth, columnMaxHeight, fixedWidth, colSuppressRepeats,
columnJustification);
int currentCount = columnHeader.length;
element.updateTable(elements, tableProperties, columnOffset);
columnHeader = tableProperties.getColumnHeader();
columnMaxWidth = tableProperties.getColumnMaxWidth();
columnMaxHeight = tableProperties.getColumnMaxHeight();
fixedWidth = tableProperties.getFixedWidth();
colSuppressRepeats = tableProperties.getColSuppressRepeats();
columnJustification = tableProperties.getColumnJustification();
columnOffset += columnHeader.length - currentCount;
}
}
//
TableElement table = new TableElement(columnHeader,
columnMaxWidth, columnMaxHeight, columnJustification,
fixedWidth, functionRows, multiLineHeader,
elements, pk, pkColumnName,
pageNoStart, firstPage, nextPages, repeatedColumns, additionalLines,
rowColFont, rowColColor, rowColBackground,
tf, pageBreak, colSuppressRepeats, rowColReportLine, finReportSumRows);
table.layout(0,0,false, MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft);
if (m_tableElement == null)
m_tableElement = table;
if (format == m_format)
this.colSuppressRepeats = colSuppressRepeats;
if (hasPageLogic)
{
table.setPageLogics(pageLogics);
table.setTablePrintData(printData);
}
return table;
} // layoutTable
/**
* Layout Parameter based on MQuery
* @return PrintElement
*/
private PrintElement layoutParameter ()
{
if (m_query == null || !m_query.isActive() || (m_query.getReportProcessQuery() != null && !m_query.getReportProcessQuery().isActive()))
return null;
//
ParameterElement pe = new ParameterElement(m_query, m_printCtx, m_format.getTableFormat());
pe.layout(0, 0, false, null);
pe.fitToPage((int) getPaper().getImageableWidth(true));
return pe;
} // layoutParameter
/**
* Layout Process Instance Logs (if any)
* @return PrintElement
*/
private PrintElement layoutPInstanceLogs()
{
if (m_query == null || !m_query.isActive() || m_query.getAD_PInstance_ID() <= 0)
return null;
//
PInstanceLogElement e = new PInstanceLogElement(m_printCtx, m_query, m_format.getTableFormat());
if (e.getEffectiveRowCount() <= 0) {
return null;
}
e.layout(0, 0, false, null);
return e;
}
/**
* Get number of pages (Pageable Interface)
* @return number of pages
*/
@Override
public int getNumberOfPages()
{
return m_pages.size();
} // getNumberOfPages
/**
* Get Page Format (Pageable Interface)
* @param pageIndex page index
* @return Page Format
* @throws IndexOutOfBoundsException
*/
@Override
public PageFormat getPageFormat (int pageIndex) throws IndexOutOfBoundsException
{
if (!havePage(pageIndex))
throw new IndexOutOfBoundsException("No page index=" + pageIndex);
return getPageFormat();
} // getPageFormat
/**
* Get Printable (PageableInterface)
* @param pageIndex page index
* @return this
* @throws IndexOutOfBoundsException
*/
@Override
public Printable getPrintable (int pageIndex) throws IndexOutOfBoundsException
{
if (!havePage(pageIndex))
throw new IndexOutOfBoundsException("No page index=" + pageIndex);
return this;
} // getPrintable
/**
* Print Page (Printable Interface)
* @param graphics graphics
* @param pageFormat page format (ignored)
* @param pageIndex page index
* @return PageExists/NoSuchPage
* @throws PrinterException
*/
@Override
public int print (Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException
{
if (!havePage(pageIndex))
return Printable.NO_SUCH_PAGE;
//
Rectangle r = new Rectangle (0, 0, (int)getPaper().getWidth(true), (int)getPaper().getHeight(true));
Page page = getPage(pageIndex+1);
//
page.paint((Graphics2D)graphics, r, false, m_isCopy); // sets context
getHeaderFooter().setCurrentPage(page);
getHeaderFooter().paint((Graphics2D)graphics, r, false);
getHeaderFooter().setCurrentPage(null);
//
return Printable.PAGE_EXISTS;
} // print
/**
* Do we have the page
* @param pageIndex page index
* @return true if page exists
*/
private boolean havePage (int pageIndex)
{
if (pageIndex < 0 || pageIndex >= getNumberOfPages())
return false;
return true;
} // havePage
/**
* Print Copy
* @return true if copy
*/
public boolean isCopy()
{
return m_isCopy;
} // isCopy
/**
* Set Copy
* @param isCopy if true document is a copy
*/
public void setCopy (boolean isCopy)
{
m_isCopy = isCopy;
} // setCopy
/**
* Get the doc flavor (Doc Interface)
* @return SERVICE_FORMATTED.PAGEABLE
*/
@Override
public DocFlavor getDocFlavor()
{
return DocFlavor.SERVICE_FORMATTED.PAGEABLE;
} // getDocFlavor
/**
* Get Print Data (Doc Interface)
* @return this
* @throws IOException
*/
@Override
public Object getPrintData() throws IOException
{
return this;
} // getPrintData
/**
* Get Document Attributes (Doc Interface)
* @return null to obtain all attribute values from the
* job's attribute set.
*/
@Override
public DocAttributeSet getAttributes()
{
return null;
} // getAttributes
/**
* Obtains a reader for extracting character print data from this doc.
* (Doc Interface)
* @return null
* @exception IOException
*/
@Override
public Reader getReaderForText() throws IOException
{
return null;
} // getReaderForText
/**
* Obtains an input stream for extracting byte print data from this doc.
* (Doc Interface)
* @return null
* @exception IOException
*/
@Override
public InputStream getStreamForBytes() throws IOException
{
return null;
} // getStreamForBytes
/**
*
* @param info PrintInfo
*/
public void setPrintInfo(PrintInfo info)
{
m_PrintInfo = info;
}
/**
*
* @return PrintInfo
*/
public PrintInfo getPrintInfo()
{
return m_PrintInfo;
}
/**
* Set child print format details
* @param printFormatItem print format item that reference a child print format
* @param printData print data of child print format
*/
public void setChildPrintFormatDetails(MPrintFormatItem printFormatItem, PrintData printData)
{
childPrintFormatDetails.put(printFormatItem, printData);
}
/**
* Get child print format details
* @return Print Format Item:Print Data of Child Print Format.
*/
public Map getChildPrintFormatDetails()
{
return childPrintFormatDetails;
}
/**
* Is item printed
* @param data
* @param item
* @return true if printed
*/
private boolean isDisplayed(PrintData data, MPrintFormatItem item) {
if ( Util.isEmpty(item.getDisplayLogic() ))
return true;
boolean display = Evaluator.evaluateLogic(new PrintDataEvaluatee(getPage(getPageNo()), data), item.getDisplayLogic());
return display;
}
/**
* Get suppress repeat columns
* @param format
* @return columns (true - suppress repeat, false - not suppress repeat)
*/
public static Boolean [] getColSuppressRepeats (MPrintFormat format){
if (format.isForm())
return null;
List colSuppressRepeats = new ArrayList<>();
for (int c = 0; c < format.getItemCount(); c++)
{
MPrintFormatItem item = format.getItem(c);
if (item.isPrinted())
{
colSuppressRepeats.add(item.isSuppressRepeats());
}
}
return colSuppressRepeats.toArray(new Boolean[0]);
}
} // LayoutEngine