From c62705c72f7b6165a4a3439c6125f84855d8be3f Mon Sep 17 00:00:00 2001 From: vpj-cd Date: Fri, 17 Nov 2006 03:12:59 +0000 Subject: [PATCH] move branch adempire311 to trunk --- print/.classpath | 12 + print/.project | 25 + print/.xdoclet | 2 + print/RUN_build.bat | 21 + print/RUN_build.sh | 18 + print/build.xml | 84 + print/documentation.bat | 5 + print/packages.txt | 2 + print/print.html | 33 + print/printData.dtd | 10 + .../src/org/compiere/print/ArchiveEngine.java | 142 ++ print/src/org/compiere/print/CPaper.java | 426 ++++ print/src/org/compiere/print/CPrinter.java | 158 ++ print/src/org/compiere/print/DataEngine.java | 1043 ++++++++++ print/src/org/compiere/print/MPrintColor.java | 245 +++ print/src/org/compiere/print/MPrintFont.java | 245 +++ .../src/org/compiere/print/MPrintFormat.java | 863 ++++++++ .../org/compiere/print/MPrintFormatItem.java | 596 ++++++ .../compiere/print/MPrintFormatProcess.java | 87 + print/src/org/compiere/print/MPrintGraph.java | 54 + print/src/org/compiere/print/MPrintPaper.java | 252 +++ .../org/compiere/print/MPrintTableFormat.java | 597 ++++++ print/src/org/compiere/print/PrintData.java | 776 ++++++++ .../org/compiere/print/PrintDataColumn.java | 137 ++ .../org/compiere/print/PrintDataElement.java | 383 ++++ .../org/compiere/print/PrintDataFunction.java | 228 +++ .../org/compiere/print/PrintDataGroup.java | 311 +++ .../org/compiere/print/PrintDataHandler.java | 165 ++ .../org/compiere/print/PrintFormatUtil.java | 167 ++ print/src/org/compiere/print/PrintUtil.java | 519 +++++ .../src/org/compiere/print/ReportEngine.java | 1331 +++++++++++++ print/src/org/compiere/print/View.java | 278 +++ .../compiere/print/layout/BarcodeElement.java | 216 ++ .../org/compiere/print/layout/BoxElement.java | 122 ++ .../print/layout/Dimension2DImpl.java | 171 ++ .../compiere/print/layout/GraphElement.java | 64 + .../compiere/print/layout/GridElement.java | 209 ++ .../compiere/print/layout/HTMLElement.java | 146 ++ .../compiere/print/layout/HTMLRenderer.java | 387 ++++ .../compiere/print/layout/HeaderFooter.java | 104 + .../compiere/print/layout/ImageElement.java | 289 +++ .../compiere/print/layout/LayoutEngine.java | 1765 +++++++++++++++++ .../print/layout/LocationElement.java | 83 + print/src/org/compiere/print/layout/Page.java | 218 ++ .../print/layout/ParameterElement.java | 54 + .../compiere/print/layout/PrintElement.java | 348 ++++ .../compiere/print/layout/StringElement.java | 606 ++++++ .../compiere/print/layout/TableElement.java | 1550 +++++++++++++++ .../src/org/compiere/print/layout/false10.gif | Bin 0 -> 471 bytes .../src/org/compiere/print/layout/true10.gif | Bin 0 -> 400 bytes print/src/org/compiere/print/package.html | 34 + 51 files changed, 15581 insertions(+) create mode 100644 print/.classpath create mode 100644 print/.project create mode 100644 print/.xdoclet create mode 100644 print/RUN_build.bat create mode 100644 print/RUN_build.sh create mode 100644 print/build.xml create mode 100644 print/documentation.bat create mode 100644 print/packages.txt create mode 100644 print/print.html create mode 100644 print/printData.dtd create mode 100644 print/src/org/compiere/print/ArchiveEngine.java create mode 100644 print/src/org/compiere/print/CPaper.java create mode 100644 print/src/org/compiere/print/CPrinter.java create mode 100644 print/src/org/compiere/print/DataEngine.java create mode 100644 print/src/org/compiere/print/MPrintColor.java create mode 100644 print/src/org/compiere/print/MPrintFont.java create mode 100644 print/src/org/compiere/print/MPrintFormat.java create mode 100644 print/src/org/compiere/print/MPrintFormatItem.java create mode 100644 print/src/org/compiere/print/MPrintFormatProcess.java create mode 100644 print/src/org/compiere/print/MPrintGraph.java create mode 100644 print/src/org/compiere/print/MPrintPaper.java create mode 100644 print/src/org/compiere/print/MPrintTableFormat.java create mode 100644 print/src/org/compiere/print/PrintData.java create mode 100644 print/src/org/compiere/print/PrintDataColumn.java create mode 100644 print/src/org/compiere/print/PrintDataElement.java create mode 100644 print/src/org/compiere/print/PrintDataFunction.java create mode 100644 print/src/org/compiere/print/PrintDataGroup.java create mode 100644 print/src/org/compiere/print/PrintDataHandler.java create mode 100644 print/src/org/compiere/print/PrintFormatUtil.java create mode 100644 print/src/org/compiere/print/PrintUtil.java create mode 100644 print/src/org/compiere/print/ReportEngine.java create mode 100644 print/src/org/compiere/print/View.java create mode 100644 print/src/org/compiere/print/layout/BarcodeElement.java create mode 100644 print/src/org/compiere/print/layout/BoxElement.java create mode 100644 print/src/org/compiere/print/layout/Dimension2DImpl.java create mode 100644 print/src/org/compiere/print/layout/GraphElement.java create mode 100644 print/src/org/compiere/print/layout/GridElement.java create mode 100644 print/src/org/compiere/print/layout/HTMLElement.java create mode 100644 print/src/org/compiere/print/layout/HTMLRenderer.java create mode 100644 print/src/org/compiere/print/layout/HeaderFooter.java create mode 100644 print/src/org/compiere/print/layout/ImageElement.java create mode 100644 print/src/org/compiere/print/layout/LayoutEngine.java create mode 100644 print/src/org/compiere/print/layout/LocationElement.java create mode 100644 print/src/org/compiere/print/layout/Page.java create mode 100644 print/src/org/compiere/print/layout/ParameterElement.java create mode 100644 print/src/org/compiere/print/layout/PrintElement.java create mode 100644 print/src/org/compiere/print/layout/StringElement.java create mode 100644 print/src/org/compiere/print/layout/TableElement.java create mode 100644 print/src/org/compiere/print/layout/false10.gif create mode 100644 print/src/org/compiere/print/layout/true10.gif create mode 100644 print/src/org/compiere/print/package.html diff --git a/print/.classpath b/print/.classpath new file mode 100644 index 0000000000..6f092c0ec6 --- /dev/null +++ b/print/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/print/.project b/print/.project new file mode 100644 index 0000000000..ae97735fee --- /dev/null +++ b/print/.project @@ -0,0 +1,25 @@ + + + print + + + dbPort + looks + tools + + + + org.eclipse.jdt.core.javabuilder + + + + + com.ibm.etools.validation.validationbuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/print/.xdoclet b/print/.xdoclet new file mode 100644 index 0000000000..a336b0bb42 --- /dev/null +++ b/print/.xdoclet @@ -0,0 +1,2 @@ + + diff --git a/print/RUN_build.bat b/print/RUN_build.bat new file mode 100644 index 0000000000..55ef1c2654 --- /dev/null +++ b/print/RUN_build.bat @@ -0,0 +1,21 @@ +@Title Build Print +@Rem $Header: /cvsroot/adempiere/print/RUN_build.bat,v 1.9 2005/09/16 00:50:35 jjanke Exp $ + +@CALL ..\utils_dev\myDevEnv.bat + +@IF %ADEMPIERE_ENV%==N GOTO NOBUILD +@IF NOT %ADEMPIERE_ENV%==Y GOTO NOBUILD + +@echo Cleanup ... +@"%JAVA_HOME%\bin\java" -Dant.home="." %ANT_PROPERTIES% org.apache.tools.ant.Main clean + +@echo Building ... +@"%JAVA_HOME%\bin\java" -Dant.home="." %ANT_PROPERTIES% org.apache.tools.ant.Main printDistribute + +@Echo Done ... +@sleep 60 +@exit + +:NOBUILD +@Echo Check myDevEnv.bat (copy from myDevEnvTemplate.bat) +@Pause \ No newline at end of file diff --git a/print/RUN_build.sh b/print/RUN_build.sh new file mode 100644 index 0000000000..5f80633c60 --- /dev/null +++ b/print/RUN_build.sh @@ -0,0 +1,18 @@ +# Module compiling script +# Ported from Windows script Marek Mosiewicz + + +SAVED_DIR=`pwd` #save current dir +cd `dirname $0`/../utils_dev #change dir to place where script resides - doesn not work with sym links +UTILS_DEV=`pwd` #this is adempiere source +cd $SAVED_DIR #back to the saved directory + +. $UTILS_DEV/myDevEnv.sh #call environment +echo done +if [ ! $ADEMPIERE_ENV==Y ] ; then + echo "Can't set developemeent environemnt - check myDevEnv.sh" + exit 1 +fi + +echo running Ant +$JAVA_HOME/bin/java -Dant.home="." $ANT_PROPERTIES org.apache.tools.ant.Main diff --git a/print/build.xml b/print/build.xml new file mode 100644 index 0000000000..053e9a4752 --- /dev/null +++ b/print/build.xml @@ -0,0 +1,84 @@ + + + + + + + + + This buildfile is used to build the print subproject within + the Adempiere project. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/print/documentation.bat b/print/documentation.bat new file mode 100644 index 0000000000..659c934f80 --- /dev/null +++ b/print/documentation.bat @@ -0,0 +1,5 @@ +@Rem API Documentation for Base + +call ..\doc\documentation.bat src doc -private + +@pause \ No newline at end of file diff --git a/print/packages.txt b/print/packages.txt new file mode 100644 index 0000000000..919144c67b --- /dev/null +++ b/print/packages.txt @@ -0,0 +1,2 @@ +org.compiere.print +org.compiere.print.layout diff --git a/print/print.html b/print/print.html new file mode 100644 index 0000000000..300d037d5a --- /dev/null +++ b/print/print.html @@ -0,0 +1,33 @@ + + + +JBuilder Project print.jpx + + +

Project print Notes

+
+ + + + +
Title: + + +
Author: + + +
Company: + + +
Description: + + +

+

Things to do...

+
    + +
  1. First +
  2. Second +
+ + diff --git a/print/printData.dtd b/print/printData.dtd new file mode 100644 index 0000000000..85a90eb421 --- /dev/null +++ b/print/printData.dtd @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/print/src/org/compiere/print/ArchiveEngine.java b/print/src/org/compiere/print/ArchiveEngine.java new file mode 100644 index 0000000000..b608a188b1 --- /dev/null +++ b/print/src/org/compiere/print/ArchiveEngine.java @@ -0,0 +1,142 @@ +/****************************************************************************** + * 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; + +import java.awt.print.*; +import org.compiere.model.*; +import org.compiere.print.layout.*; +import org.compiere.util.*; +import com.qoppa.pdf.*; +import com.qoppa.pdfProcess.*; + + +/** + * Archive Engine. + * Based on Settings on Client Level + * Keys set for + * - Menu Reports - AD_Report_ID + * - Win Report - AD_Table_ID + * - Documents - AD_Table_ID & Record_ID & C_Customer_ID + * + * @author Jorg Janke + * @version $Id: ArchiveEngine.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class ArchiveEngine +{ + /** + * Get/Create Archive. + * @param layout layout + * @param info print info + * @return existing document or newly created if Client enabled archiving. + * Will return NULL if archiving not enabled + */ + public PDFDocument archive (LayoutEngine layout, PrintInfo info) + { + // Do we need to Archive ? + MClient client = MClient.get(layout.getCtx()); + String aaClient = client.getAutoArchive(); + String aaRole = null; // role.getAutoArchive(); // TODO + String aa = aaClient; + if (aa == null) + aa = MClient.AUTOARCHIVE_None; + if (aaRole != null) + { + if (aaRole.equals(MClient.AUTOARCHIVE_AllReportsDocuments)) + aa = aaRole; + else if (aaRole.equals(MClient.AUTOARCHIVE_Documents) && !aaClient.equals(MClient.AUTOARCHIVE_AllReportsDocuments)) + aa = aaRole; + } + // Mothing to Archive + if (aa.equals(MClient.AUTOARCHIVE_None)) + return null; + // Archive External only + if (aa.equals(MClient.AUTOARCHIVE_ExternalDocuments)) + { + if (info.isReport()) + return null; + } + // Archive Documents only + if (aa.equals(MClient.AUTOARCHIVE_Documents)) + { + if (info.isReport()) + return null; + } + + // Create Printable + byte[] data = Document.getPDFAsArray(layout.getPageable(false)); // No Copy + if (data == null) + return null; + + // TODO to be done async + MArchive archive = new MArchive (layout.getCtx(),info, null); + archive.setBinaryData(data); + archive.save(); + + return null; + } // archive + + /** + * Can we archive the document? + * @param layout layout + * @return true if can be archived + */ + public static boolean isValid (LayoutEngine layout) + { + return (layout != null + && Document.isValid((Pageable)layout) + && layout.getNumberOfPages() > 0); + } // isValid + + + /** + * Get Archive Engine + * @return engine + */ + public static ArchiveEngine get() + { + if (s_engine == null) + s_engine = new ArchiveEngine(); + return s_engine; + } // get + + // Create Archiver + static { + s_engine = new ArchiveEngine(); + } + + /** Logger */ + private static CLogger log = CLogger.getCLogger(ArchiveEngine.class); + /** Singleton */ + private static ArchiveEngine s_engine = null; + + + /************************************************************************** + * ArchiveEngine + */ + private ArchiveEngine () + { + super (); + if (s_engine == null) + s_engine = this; + } // ArchiveEngine + + /** The base document */ +// private PDFDocument m_document = Document.createBlank(); + + + +} // ArchiveEngine diff --git a/print/src/org/compiere/print/CPaper.java b/print/src/org/compiere/print/CPaper.java new file mode 100644 index 0000000000..09cfebe03b --- /dev/null +++ b/print/src/org/compiere/print/CPaper.java @@ -0,0 +1,426 @@ +/****************************************************************************** + * 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; + +import java.awt.*; +import java.awt.print.*; +import java.util.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; +import org.compiere.util.*; + +/** + * Adempiere Paper + * + * @author Jorg Janke + * @version $Id: CPaper.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class CPaper extends Paper +{ + /** + * Constructor. + * Derive Paper from PageForamt + * @param pf PageFormat + */ + public CPaper (PageFormat pf) + { + super(); + m_landscape = pf.getOrientation() != PageFormat.PORTRAIT; + // try to find MediaSize + float x = (float)pf.getWidth(); + float y = (float)pf.getHeight(); + MediaSizeName msn = MediaSize.findMedia (x/72, y/72, MediaSize.INCH); + MediaSize ms = null; + if (msn == null) + msn = MediaSize.findMedia (y/72, x/72, MediaSize.INCH); // flip it + if (msn != null) + ms = MediaSize.getMediaSizeForName(msn); + setMediaSize(ms, m_landscape); + // set size directly + setSize(pf.getWidth(), pf.getHeight()); + setImageableArea(pf.getImageableX(), pf.getImageableY(), + pf.getImageableWidth(), pf.getImageableHeight()); + } // CPaper + + /** + * Constructor. + * Get Media Size from Default Language + * @param landscape true if landscape, false if portrait + */ + public CPaper (boolean landscape) + { + this (Language.getLoginLanguage(), landscape); + } // CPaper + + /** + * Constructor. + * Get Media Size from Language, + * @param language language to derive media size + * @param landscape true if landscape, false if portrait + */ + private CPaper (Language language, boolean landscape) + { + this (language.getMediaSize(), landscape); + } // CPaper + + /** + * Detail Constructor 1/2 inch on all sides + * @param mediaSize media size + * @param landscape true if landscape, false if portrait + */ + private CPaper (MediaSize mediaSize, boolean landscape) + { + this (mediaSize, landscape, 36, 36, 36, 36); + } // CPaper + + /** + * Detail Constructor + * @param mediaSize media size + * @param left x in 1/72 inch + * @param top y in 1/72 inch + * @param right right x in 1/72 + * @param bottom bottom y in 1/72 + * @param landscape true if landscape, false if portrait + */ + public CPaper (MediaSize mediaSize, boolean landscape, + double left, double top, double right, double bottom) + { + super(); + setMediaSize (mediaSize, landscape); + setImageableArea(left, top, getWidth()-left-right, getHeight()-top-bottom); + } // CPaper + + /** Media size */ + private MediaSize m_mediaSize; + /** Landscape flag */ + private boolean m_landscape = false; + /** Logger */ + private static CLogger log = CLogger.getCLogger(CPaper.class); + + /** + * Set Media Size + * @param mediaSize media size + * @param landscape true if landscape, false if portrait + */ + public void setMediaSize (MediaSize mediaSize, boolean landscape) + { + if (mediaSize == null) + throw new IllegalArgumentException("MediaSize is null"); + m_mediaSize = mediaSize; + m_landscape = landscape; + + // Get Sise in Inch * 72 + double width = m_mediaSize.getX (MediaSize.INCH) * 72; + double height = m_mediaSize.getY (MediaSize.INCH) * 72; + // Set Size + setSize (width, height); + log.fine(mediaSize.getMediaSizeName() + ": " + m_mediaSize + " - Landscape=" + m_landscape); + } // setMediaSize + + /** + * Get Media Size + * @return media size + */ + public MediaSizeName getMediaSizeName() + { + return m_mediaSize.getMediaSizeName(); + } // getMediaSizeName + + /** + * Get Media Size + * @return media size + */ + public MediaSize getMediaSize() + { + return m_mediaSize; + } // getMediaSize + + /** + * Get Printable Media Area + * @return Printable Area + */ + public MediaPrintableArea getMediaPrintableArea() + { + MediaPrintableArea area = new MediaPrintableArea ((float)getImageableX()/72, (float)getImageableY()/72, + (float)getImageableWidth()/72, (float)getImageableHeight()/72, MediaPrintableArea.INCH); + // log.fine( "CPaper.getMediaPrintableArea", area.toString(MediaPrintableArea.INCH, "\"")); + return area; + } // getMediaPrintableArea + + /** + * Get Printable Media Area + * @param area Printable Area + */ + public void setMediaPrintableArea (MediaPrintableArea area) + { + int inch = MediaPrintableArea.INCH; + log.fine(area.toString(inch, "\"")); + setImageableArea(area.getX(inch)*72, area.getY(inch)*72, + area.getWidth(inch)*72, area.getHeight(inch)*72); + } // setMediaPrintableArea + + /** + * Is Landscape + * @return true if landscape + */ + public boolean isLandscape() + { + return m_landscape; + } // isLandscape + + /*************************************************************************/ + + /** + * Show Dialog and Set Paper + * @param job printer job + * @return true if changed. + */ + public boolean pageSetupDialog(PrinterJob job) + { + PrintRequestAttributeSet prats = getPrintRequestAttributeSet(); + // Page Dialog + PageFormat pf = job.pageDialog(prats); + setPrintRequestAttributeSet(prats); + return true; + } // pageSetupDialog + + /** + * Return Print Request Attributes + * @return PrintRequestAttributeSet + */ + public PrintRequestAttributeSet getPrintRequestAttributeSet() + { + PrintRequestAttributeSet pratts = new HashPrintRequestAttributeSet(); + // media-printable-area = (25.4,25.4)->(165.1,228.6)mm - class javax.print.attribute.standard.MediaPrintableArea + pratts.add(getMediaPrintableArea()); + // orientation-requested = landscape - class javax.print.attribute.standard.OrientationRequested + if (isLandscape()) + pratts.add(OrientationRequested.LANDSCAPE); + else + pratts.add(OrientationRequested.PORTRAIT); + // media = na-legal + pratts.add(getMediaSizeName()); + + return pratts; + } // getPrintRequestAttributes + + /** + * Set Print Request Attributes + * @param prats PrintRequestAttributeSet + */ + public void setPrintRequestAttributeSet (PrintRequestAttributeSet prats) + { + boolean landscape = m_landscape; + MediaSize ms = m_mediaSize; + MediaPrintableArea area = getMediaPrintableArea(); + + Attribute[] atts = prats.toArray(); + for (int i = 0; i < atts.length; i++) + { + if (atts[i] instanceof OrientationRequested) + { + OrientationRequested or = (OrientationRequested)atts[i]; + if (or.equals(OrientationRequested.PORTRAIT)) + landscape = false; + else + landscape = true; + } + else if (atts[i] instanceof MediaSizeName) + { + MediaSizeName msn = (MediaSizeName)atts[i]; + ms = MediaSize.getMediaSizeForName(msn); + } + else if (atts[i] instanceof MediaPrintableArea) + { + area = (MediaPrintableArea)atts[i]; + } + else // unhandeled + System.out.println(atts[i].getName() + " = " + atts[i] + " - " + atts[i].getCategory()); + } + // + setMediaSize(ms, landscape); + setMediaPrintableArea(area); + } // getPrintRequestAttributes + + + /*************************************************************************/ + + /** + * Get the Page Format for the Papaer + * @return Page Format + */ + public PageFormat getPageFormat() + { + PageFormat pf = new PageFormat(); + pf.setPaper(this); + int orient = PageFormat.PORTRAIT; + if (m_landscape) + orient = PageFormat.LANDSCAPE; + pf.setOrientation(orient); + return pf; + } // getPageFormat + + /*************************************************************************/ + + /** + * Get String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("CPaper["); + sb.append(getWidth()/72).append("x").append(getHeight()/72).append('"') + .append(m_landscape ? " Landscape " : " Portrait ") + .append("x=").append(getImageableX()) + .append(",y=").append(getImageableY()) + .append(" w=").append(getImageableWidth()) + .append(",h=").append(getImageableHeight()) + .append("]"); + return sb.toString(); + } // toString + + /** + * Get "nice" String Representation + * @param ctx context + * @return info + */ + public String toString (Properties ctx) + { + StringBuffer sb = new StringBuffer(); + // Print Media size + sb.append(m_mediaSize.getMediaSizeName()); + // Print dimension + String name = m_mediaSize.getMediaSizeName().toString(); + if (!name.startsWith("iso")) + sb.append(" - ").append(m_mediaSize.toString(MediaSize.INCH,"\"")) + .append(" (").append(getMediaPrintableArea().toString(MediaPrintableArea.INCH,"\"")); + if (!name.startsWith("na")) + sb.append(" - ").append(m_mediaSize.toString(MediaSize.MM,"mm")) + .append(" (").append(getMediaPrintableArea().toString(MediaPrintableArea.MM,"mm")); + // Print Orientation + sb.append(") - ") + .append(Msg.getMsg(ctx, m_landscape ? "Landscape" : "Portrait")); + return sb.toString(); + } // toString + + /** + * Equals + * @param obj compare + * @return true if equal + */ + public boolean equals (Object obj) + { + if (obj instanceof CPaper) + { + CPaper cp = (CPaper)obj; + if (cp.isLandscape() != m_landscape) + return false; + // media size is more descriptive + if (getImageableX() == cp.getImageableX() && getImageableY() == cp.getImageableY() + && getImageableWidth() == cp.getImageableWidth() && getImageableHeight() == cp.getImageableHeight()) + return true; + } + return false; + } // equals + + /*************************************************************************/ + + /** + * Get Width in 1/72 inch + * @param orientationCorrected correct for orientation + * @return width + */ + public double getWidth (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getHeight(); + return super.getWidth(); + } + + /** + * Get Height in 1/72 inch + * @param orientationCorrected correct for orientation + * @return height + */ + public double getHeight (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getWidth(); + return super.getHeight(); + } + + /** + * Get Image Y in 1/72 inch + * @param orientationCorrected correct for orientation + * @return imagable Y + */ + public double getImageableY (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getImageableX(); + return super.getImageableY(); + } + + /** + * Get Image X in 1/72 inch + * @param orientationCorrected correct for orientation + * @return imagable X + */ + public double getImageableX (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getImageableY(); + return super.getImageableX(); + } + + /** + * Get Image Height in 1/72 inch + * @param orientationCorrected correct for orientation + * @return imagable height + */ + public double getImageableHeight (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getImageableWidth(); + return super.getImageableHeight(); + } + /** + * Get Image Width in 1/72 inch + * @param orientationCorrected correct for orientation + * @return imagable width + */ + public double getImageableWidth (boolean orientationCorrected) + { + if (orientationCorrected && m_landscape) + return super.getImageableHeight(); + return super.getImageableWidth(); + } + + /** + * Get Margin + * @param orientationCorrected correct for orientation + * @return margin + */ + public Insets getMargin (boolean orientationCorrected) + { + return new Insets ((int)getImageableY(orientationCorrected), // top + (int)getImageableX(orientationCorrected), // left + (int)(getHeight(orientationCorrected)-getImageableY(orientationCorrected)-getImageableHeight(orientationCorrected)), // bottom + (int)(getWidth(orientationCorrected)-getImageableX(orientationCorrected)-getImageableWidth(orientationCorrected))); // right + } // getMargin + +} // CPapaer diff --git a/print/src/org/compiere/print/CPrinter.java b/print/src/org/compiere/print/CPrinter.java new file mode 100644 index 0000000000..af674fc535 --- /dev/null +++ b/print/src/org/compiere/print/CPrinter.java @@ -0,0 +1,158 @@ +/****************************************************************************** + * 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; + +import java.awt.event.*; +import java.awt.print.*; +import javax.print.*; +import org.compiere.swing.*; +import org.compiere.util.*; + +/** + * Adempiere Printer Selection + * + * @author Jorg Janke + * @version $Id: CPrinter.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class CPrinter extends CComboBox implements ActionListener +{ + /** + * Get Print (Services) Names + * @return Printer Name array + */ + public static String[] getPrinterNames() + { + String[] retValue = new String[s_services.length]; + for (int i = 0; i < s_services.length; i++) + retValue[i] = s_services[i].getName(); + return retValue; + } // getPrintServiceNames + + + /** + * Return default PrinterJob + * @return PrinterJob + */ + public static PrinterJob getPrinterJob() + { + return getPrinterJob(Ini.getProperty(Ini.P_PRINTER)); + } // getPrinterJob + + /** + * Return PrinterJob with selected printer name. + * @param printerName if null, get default printer (Ini) + * @return PrinterJob + */ + public static PrinterJob getPrinterJob (String printerName) + { + PrinterJob pj = null; + PrintService ps = null; + try + { + pj = PrinterJob.getPrinterJob(); + + // find printer service + if (printerName == null || printerName.length() == 0) + printerName = Ini.getProperty(Ini.P_PRINTER); + if (printerName != null && printerName.length() != 0) + { + // System.out.println("CPrinter.getPrinterJob - searching " + printerName); + for (int i = 0; i < s_services.length; i++) + { + String serviceName = s_services[i].getName(); + if (printerName.equals(serviceName)) + { + ps = s_services[i]; + // System.out.println("CPrinter.getPrinterJob - found " + printerName); + break; + } + // System.out.println("CPrinter.getPrinterJob - not: " + serviceName); + } + } // find printer service + + try + { + if (ps != null) + pj.setPrintService(ps); + } + catch (Exception e) + { + log.warning("Could not set Print Service: " + e.toString()); + } + // + PrintService psUsed = pj.getPrintService(); + if (psUsed == null) + log.warning("Print Service not Found"); + else + { + String serviceName = psUsed.getName(); + if (printerName != null && !printerName.equals(serviceName)) + log.warning("Not found: " + printerName + " - Used: " + serviceName); + } + } + catch (Exception e) + { + log.warning("Could not create for " + printerName + ": " + e.toString()); + } + return pj; + } // getPrinterJob + + + /** Available Printer Services */ +// private static PrintService[] s_services = PrinterJob.lookupPrintServices(); + private static PrintService[] s_services = PrintServiceLookup.lookupPrintServices(null,null); + + /** Logger */ + private static CLogger log = CLogger.getCLogger (CPrinter.class); + + + /************************************************************************** + * Create PrinterJob + */ + public CPrinter() + { + super(getPrinterNames()); + // Set Default + setValue(Ini.getProperty(Ini.P_PRINTER)); + this.addActionListener(this); + } // CPrinter + + /** + * Action Listener + * @param e event + */ + public void actionPerformed (ActionEvent e) + { + + } // actionPerformed + + /** + * Get PrintService + * @return print service + */ + public PrintService getPrintService() + { + String currentService = (String)getSelectedItem(); + for (int i = 0; i < s_services.length; i++) + { + if (s_services[i].getName().equals(currentService)) + return s_services[i]; + } + return PrintServiceLookup.lookupDefaultPrintService(); + } // getPrintService + +} // CPrinter diff --git a/print/src/org/compiere/print/DataEngine.java b/print/src/org/compiere/print/DataEngine.java new file mode 100644 index 0000000000..82f1a7d138 --- /dev/null +++ b/print/src/org/compiere/print/DataEngine.java @@ -0,0 +1,1043 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Data Engine. + * Creates SQL and laods data into PrintData (including totals/etc.) + * + * @author Jorg Janke + * @version $Id: DataEngine.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class DataEngine +{ + /** + * Constructor + * @param language Language of the data (for translation) + */ + public DataEngine (Language language) + { + if (language != null) + m_language = language; + } // DataEngine + + /** Logger */ + private static CLogger log = CLogger.getCLogger (DataEngine.class); + + /** Synonym */ + private String m_synonym = "A"; + + /** Default Language */ + private Language m_language = Language.getLoginLanguage(); + /** Break & Column Funcations */ + private PrintDataGroup m_group = new PrintDataGroup(); + /** Start Time */ + private long m_startTime = System.currentTimeMillis(); + /** Running Total after .. lines */ + private int m_runningTotalLines = -1; + /** Print String */ + private String m_runningTotalString = null; + + /** Key Indicator in Report */ + public static final String KEY = "*"; + + + /************************************************************************** + * Load Data + * + * @param format print format + * @param query query + * @param ctx context + * @return PrintData or null + */ + public PrintData getPrintData (Properties ctx, MPrintFormat format, MQuery query) + { + if (format == null) + throw new IllegalStateException ("No print format"); + String tableName = null; + String reportName = format.getName(); + // + if (format.getAD_ReportView_ID() != 0) + { + String sql = "SELECT t.AD_Table_ID, t.TableName, rv.Name " + + "FROM AD_Table t" + + " INNER JOIN AD_ReportView rv ON (t.AD_Table_ID=rv.AD_Table_ID) " + + "WHERE rv.AD_ReportView_ID=?"; // 1 + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, format.getAD_ReportView_ID()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + tableName = rs.getString(2); // TableName + reportName = rs.getString(3); + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + return null; + } + } + else + { + String sql = "SELECT TableName FROM AD_Table WHERE AD_Table_ID=?"; // #1 + try + { + PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null); + pstmt.setInt(1, format.getAD_Table_ID()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + tableName = rs.getString(1); // TableName + rs.close(); + pstmt.close(); + } + catch (SQLException e1) + { + log.log(Level.SEVERE, sql, e1); + return null; + } + } + if (tableName == null) + { + log.log(Level.SEVERE, "Not found Format=" + format); + return null; + } + if (format.isTranslationView() && tableName.toLowerCase().endsWith("_v")) // _vt not just _v + tableName += "t"; + format.setTranslationViewQuery (query); + // + PrintData pd = getPrintDataInfo (ctx, format, query, reportName, tableName); + if (pd == null) + return null; + loadPrintData(pd, format); + return pd; + } // getPrintData + + + /************************************************************************** + * Create Load SQL and update PrintData Info + * + * @param ctx context + * @param format print format + * @param query query + * @param reportName report name + * @param tableName table name + * @return PrintData or null + */ + private PrintData getPrintDataInfo (Properties ctx, MPrintFormat format, MQuery query, + String reportName, String tableName) + { + m_startTime = System.currentTimeMillis(); + log.info(reportName + " - " + m_language.getAD_Language()); + log.fine("TableName=" + tableName + ", Query=" + query); + log.fine("Format=" + format); + ArrayList columns = new ArrayList(); + m_group = new PrintDataGroup(); + + // Order Columns (identifed by non zero/null SortNo) + int[] orderAD_Column_IDs = format.getOrderAD_Column_IDs(); + ArrayList orderColumns = new ArrayList(orderAD_Column_IDs.length); + for (int i = 0; i < orderAD_Column_IDs.length; i++) + { + log.finest("Order AD_Column_ID=" + orderAD_Column_IDs[i]); + orderColumns.add(""); // initial value overwritten with fully qualified name + } + + // Direct SQL w/o Reference Info + StringBuffer sqlSELECT = new StringBuffer("SELECT "); + StringBuffer sqlFROM = new StringBuffer(" FROM "); + sqlFROM.append(tableName); + StringBuffer sqlGROUP = new StringBuffer(" GROUP BY "); + // + boolean IsGroupedBy = false; + // + String sql = "SELECT c.AD_Column_ID,c.ColumnName," // 1..2 + + "c.AD_Reference_ID,c.AD_Reference_Value_ID," // 3..4 + + "c.FieldLength,c.IsMandatory,c.IsKey,c.IsParent," // 5..8 + + "COALESCE(rvc.IsGroupFunction,'N'),rvc.FunctionColumn," // 9..10 + + "pfi.IsGroupBy,pfi.IsSummarized,pfi.IsAveraged,pfi.IsCounted, " // 11..14 + + "pfi.IsPrinted,pfi.SortNo,pfi.IsPageBreak, " // 15..17 + + "pfi.IsMinCalc,pfi.IsMaxCalc, " // 18..19 + + "pfi.isRunningTotal,pfi.RunningTotalLines, " // 20..21 + + "pfi.IsVarianceCalc, pfi.IsDeviationCalc, " // 22..23 + + "c.ColumnSQL " // 24 + + "FROM AD_PrintFormat pf" + + " INNER JOIN AD_PrintFormatItem pfi ON (pf.AD_PrintFormat_ID=pfi.AD_PrintFormat_ID)" + + " INNER JOIN AD_Column c ON (pfi.AD_Column_ID=c.AD_Column_ID)" + + " LEFT OUTER JOIN AD_ReportView_Col rvc ON (pf.AD_ReportView_ID=rvc.AD_ReportView_ID AND c.AD_Column_ID=rvc.AD_Column_ID) " + + "WHERE pf.AD_PrintFormat_ID=?" // #1 + + " AND pfi.IsActive='Y' AND (pfi.IsPrinted='Y' OR c.IsKey='Y' OR pfi.SortNo > 0) " + + "ORDER BY pfi.IsPrinted DESC, pfi.SeqNo"; // Functions are put in first column + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, format.get_ID()); + ResultSet rs = pstmt.executeQuery(); + + m_synonym = "A"; // synonym + while (rs.next()) + { + // get Values from record + int AD_Column_ID = rs.getInt(1); + String ColumnName = rs.getString(2); + String ColumnSQL = rs.getString(24); + if (ColumnSQL == null) + ColumnSQL = ""; + int AD_Reference_ID = rs.getInt(3); + int AD_Reference_Value_ID = rs.getInt(4); + // ColumnInfo + int FieldLength = rs.getInt(5); + boolean IsMandatory = "Y".equals(rs.getString(6)); + boolean IsKey = "Y".equals(rs.getString(7)); + boolean IsParent = "Y".equals(rs.getString(8)); + // SQL GroupBy + boolean IsGroupFunction = "Y".equals(rs.getString(9)); + if (IsGroupFunction) + IsGroupedBy = true; + String FunctionColumn = rs.getString(10); + if (FunctionColumn == null) + FunctionColumn = ""; + // Breaks/Column Functions + if ("Y".equals(rs.getString(11))) + m_group.addGroupColumn(ColumnName); + if ("Y".equals(rs.getString(12))) + m_group.addFunction(ColumnName, PrintDataFunction.F_SUM); + if ("Y".equals(rs.getString(13))) + m_group.addFunction(ColumnName, PrintDataFunction.F_MEAN); + if ("Y".equals(rs.getString(14))) + m_group.addFunction(ColumnName, PrintDataFunction.F_COUNT); + if ("Y".equals(rs.getString(18))) // IsMinCalc + m_group.addFunction(ColumnName, PrintDataFunction.F_MIN); + if ("Y".equals(rs.getString(19))) // IsMaxCalc + m_group.addFunction(ColumnName, PrintDataFunction.F_MAX); + if ("Y".equals(rs.getString(22))) // IsVarianceCalc + m_group.addFunction(ColumnName, PrintDataFunction.F_VARIANCE); + if ("Y".equals(rs.getString(23))) // IsDeviationCalc + m_group.addFunction(ColumnName, PrintDataFunction.F_DEVIATION); + if ("Y".equals(rs.getString(20))) // isRunningTotal + // RunningTotalLines only once - use max + m_runningTotalLines = Math.max(m_runningTotalLines, rs.getInt(21)); + + // General Info + boolean IsPrinted = "Y".equals(rs.getString(15)); + int SortNo = rs.getInt(16); + boolean isPageBreak = "Y".equals(rs.getString(17)); + + // Fully qualified Table.Column for ordering + String orderName = tableName + "." + ColumnName; + PrintDataColumn pdc = null; + + // -- Key -- + if (IsKey) + { + // => Table.Column, + sqlSELECT.append(tableName).append(".").append(ColumnName).append(","); + sqlGROUP.append(tableName).append(".").append(ColumnName).append(","); + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, AD_Reference_ID, FieldLength, KEY, isPageBreak); // KeyColumn + } + else if (!IsPrinted) // not printed Sort Columns + ; + // -- Parent, TableDir (and unqualified Search) -- + else if (IsParent + || AD_Reference_ID == DisplayType.TableDir + || (AD_Reference_ID == DisplayType.Search && AD_Reference_Value_ID == 0) + ) + { + if (ColumnSQL.length() > 0) + { + log.warning(ColumnName + " - virtual column not allowed with this Display type"); + continue; + } + // Creates Embedded SQL in the form + // SELECT ColumnTable.Name FROM ColumnTable WHERE TableName.ColumnName=ColumnTable.ColumnName + String eSql = MLookupFactory.getLookup_TableDirEmbed(m_language, ColumnName, tableName); + + // TableName + String table = ColumnName; + if (table.endsWith("_ID")) + table = table.substring(0, table.length()-3); + // DisplayColumn + String display = ColumnName; + // => (..) AS AName, Table.ID, + sqlSELECT.append("(").append(eSql).append(") AS ").append(m_synonym).append(display).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + sqlGROUP.append(m_synonym).append(display).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + orderName = m_synonym + display; + // + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, AD_Reference_ID, FieldLength, orderName, isPageBreak); + synonymNext(); + } + + // -- Table -- + else if (AD_Reference_ID == DisplayType.Table + || (AD_Reference_ID == DisplayType.Search && AD_Reference_Value_ID != 0) + ) + { + if (ColumnSQL.length() > 0) + { + log.warning(ColumnName + " - virtual column not allowed with this Display type"); + continue; + } + TableReference tr = getTableReference(AD_Reference_Value_ID); + String display = tr.DisplayColumn; + // => A.Name AS AName, Table.ID, + if (tr.IsValueDisplayed) + sqlSELECT.append(m_synonym).append(".Value||'-'||"); + sqlSELECT.append(m_synonym).append(".").append(display); + sqlSELECT.append(" AS ").append(m_synonym).append(display).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + sqlGROUP.append(m_synonym).append(".").append(display).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + orderName = m_synonym + display; + + // => x JOIN table A ON (x.KeyColumn=A.Key) + if (IsMandatory) + sqlFROM.append(" INNER JOIN "); + else + sqlFROM.append(" LEFT OUTER JOIN "); + sqlFROM.append(tr.TableName).append(" ").append(m_synonym).append(" ON (") + .append(tableName).append(".").append(ColumnName).append("=") + .append(m_synonym).append(".").append(tr.KeyColumn).append(")"); + // + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, AD_Reference_ID, FieldLength, orderName, isPageBreak); + synonymNext(); + } + + // -- List or Button with ReferenceValue -- + else if (AD_Reference_ID == DisplayType.List + || (AD_Reference_ID == DisplayType.Button && AD_Reference_Value_ID != 0)) + { + if (ColumnSQL.length() > 0) + { + log.warning(ColumnName + " - virtual column not allowed with this Display type"); + continue; + } + if (Env.isBaseLanguage(m_language, "AD_Ref_List")) + { + // => A.Name AS AName, + sqlSELECT.append(m_synonym).append(".Name AS ").append(m_synonym).append("Name,"); + sqlGROUP.append(m_synonym).append(".Name,"); + orderName = m_synonym + "Name"; + // => x JOIN AD_Ref_List A ON (x.KeyColumn=A.Value AND A.AD_Reference_ID=123) + if (IsMandatory) + sqlFROM.append(" INNER JOIN "); + else + sqlFROM.append(" LEFT OUTER JOIN "); + sqlFROM.append("AD_Ref_List ").append(m_synonym).append(" ON (") + .append(tableName).append(".").append(ColumnName).append("=").append(m_synonym).append(".Value") + .append(" AND ").append(m_synonym).append(".AD_Reference_ID=").append(AD_Reference_Value_ID).append(")"); + } + else + { + // => A.Name AS AName, + sqlSELECT.append(m_synonym).append(".Name AS ").append(m_synonym).append("Name,"); + sqlGROUP.append(m_synonym).append(".Name,"); + orderName = m_synonym + "Name"; + + // LEFT OUTER JOIN AD_Ref_List XA ON (AD_Table.EntityType=XA.Value AND XA.AD_Reference_ID=245) + // LEFT OUTER JOIN AD_Ref_List_Trl A ON (XA.AD_Ref_List_ID=A.AD_Ref_List_ID AND A.AD_Language='de_DE') + if (IsMandatory) + sqlFROM.append(" INNER JOIN "); + else + sqlFROM.append(" LEFT OUTER JOIN "); + sqlFROM.append(" AD_Ref_List X").append(m_synonym).append(" ON (") + .append(tableName).append(".").append(ColumnName).append("=X") + .append(m_synonym).append(".Value AND X").append(m_synonym).append(".AD_Reference_ID=").append(AD_Reference_Value_ID) + .append(")"); + if (IsMandatory) + sqlFROM.append(" INNER JOIN "); + else + sqlFROM.append(" LEFT OUTER JOIN "); + sqlFROM.append(" AD_Ref_List_Trl ").append(m_synonym).append(" ON (X") + .append(m_synonym).append(".AD_Ref_List_ID=").append(m_synonym).append(".AD_Ref_List_ID") + .append(" AND ").append(m_synonym).append(".AD_Language='").append(m_language.getAD_Language()).append("')"); + } + // TableName.ColumnName, + sqlSELECT.append(tableName).append(".").append(ColumnName).append(","); + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, AD_Reference_ID, FieldLength, orderName, isPageBreak); + synonymNext(); + } + + // -- Special Lookups -- + else if (AD_Reference_ID == DisplayType.Location + || AD_Reference_ID == DisplayType.Account + || AD_Reference_ID == DisplayType.Locator + || AD_Reference_ID == DisplayType.PAttribute + ) + { + if (ColumnSQL.length() > 0) + { + log.warning(ColumnName + " - virtual column not allowed with this Display type"); + continue; + } + // TableName, DisplayColumn + String table = ""; + String key = ""; + String display = ""; + String synonym = null; + // + if (AD_Reference_ID == DisplayType.Location) + { + table = "C_Location"; + key = "C_Location_ID"; + display = "City||'.'"; // in case City is empty + synonym = "Address"; + } + else if (AD_Reference_ID == DisplayType.Account) + { + table = "C_ValidCombination"; + key = "C_ValidCombination_ID"; + display = "Combination"; + } + else if (AD_Reference_ID == DisplayType.Locator) + { + table = "M_Locator"; + key = "M_Locator_ID"; + display = "Value"; + } + else if (AD_Reference_ID == DisplayType.PAttribute) + { + table = "M_AttributeSetInstance"; + key = "M_AttributeSetInstance_ID"; + display = "Description"; + if (CLogMgt.isLevelFine()) + display += "||'{'||" + m_synonym + ".M_AttributeSetInstance_ID||'}'"; + synonym = "Description"; + } + if (synonym == null) + synonym = display; + + // => A.Name AS AName, table.ID, + sqlSELECT.append(m_synonym).append(".").append(display).append(" AS ") + .append(m_synonym).append(synonym).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + sqlGROUP.append(m_synonym).append(".").append(synonym).append(",") + .append(tableName).append(".").append(ColumnName).append(","); + orderName = m_synonym + synonym; + // => x JOIN table A ON (table.ID=A.Key) + if (IsMandatory) + sqlFROM.append(" INNER JOIN "); + else + sqlFROM.append(" LEFT OUTER JOIN "); + sqlFROM.append(table).append(" ").append(m_synonym).append(" ON (") + .append(tableName).append(".").append(ColumnName).append("=") + .append(m_synonym).append(".").append(key).append(")"); + // + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, AD_Reference_ID, FieldLength, orderName, isPageBreak); + synonymNext(); + } + + // -- Standard Column -- + else + { + int index = FunctionColumn.indexOf("@"); + StringBuffer sb = new StringBuffer(); + if (ColumnSQL != null && ColumnSQL.length() > 0) + { + // => ColumnSQL AS ColumnName + sb.append(ColumnSQL); + sqlSELECT.append(sb).append(" AS ").append(ColumnName).append(","); + if (!IsGroupFunction) + sqlGROUP.append(sb).append(","); + orderName = ColumnName; // no prefix for synonym + } + else if (index == -1) + { + // => Table.Column, + sb.append(tableName).append(".").append(ColumnName).append(","); + sqlSELECT.append(sb); + if (!IsGroupFunction) + sqlGROUP.append(sb).append(","); + } + else + { + // => Function(Table.Column) AS Column -- function has @ where column name goes + sb.append(FunctionColumn.substring(0, index)) + // If I eg entered sum(amount) as function column in the report view the query would look like: + // Tablename.amountsum(amount), after removing the line below I get the wanted result. The original query column (tablename.column) is replaced by the function column entered in the report view window. + // .append(tableName).append(".").append(ColumnName) // xxxxxx + .append(FunctionColumn.substring(index+1)); + sqlSELECT.append(sb).append(" AS ").append(ColumnName).append(","); + if (!IsGroupFunction) + sqlGROUP.append(sb).append(","); + orderName = ColumnName; // no prefix for synonym + } + pdc = new PrintDataColumn(AD_Column_ID, ColumnName, + AD_Reference_ID, FieldLength, ColumnName, isPageBreak); + } + + // Order Sequence - Overwrite order column name + for (int i = 0; i < orderAD_Column_IDs.length; i++) + { + if (AD_Column_ID == orderAD_Column_IDs[i]) + { + orderColumns.set(i, orderName); + break; + } + } + + // + if (pdc == null || (!IsPrinted && !IsKey)) + continue; + + columns.add(pdc); + } // for all Fields in Tab + rs.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, "SQL=" + sql + " - ID=" + format.get_ID(), e); + } + + if (columns.size() == 0) + { + log.log(Level.SEVERE, "No Colums - Delete Report Format " + reportName + " and start again"); + log.finest("No Colums - SQL=" + sql + " - ID=" + format.get_ID()); + return null; + } + + boolean hasLevelNo = false; + if (tableName.startsWith("T_Report")) + { + hasLevelNo = true; + if (sqlSELECT.indexOf("LevelNo") == -1) + sqlSELECT.append("LevelNo,"); + } + + /** + * Assemble final SQL - delete last SELECT ',' + */ + StringBuffer finalSQL = new StringBuffer(); + finalSQL.append(sqlSELECT.substring(0, sqlSELECT.length()-1)) + .append(sqlFROM); + + // WHERE clause + if (tableName.startsWith("T_Report")) + { + finalSQL.append(" WHERE "); + for (int i = 0; i < query.getRestrictionCount(); i++) + { + String q = query.getWhereClause (i); + if (q.indexOf("AD_PInstance_ID") != -1) // ignore all other Parameters + finalSQL.append (q); + } // for all restrictions + } + else + { + // User supplied Where Clause + if (query != null && query.isActive ()) + { + finalSQL.append (" WHERE "); + if (!query.getTableName ().equals (tableName)) + query.setTableName (tableName); + finalSQL.append (query.getWhereClause (true)); + } + // Access Restriction + MRole role = MRole.getDefault(ctx, false); + if (role.getAD_Role_ID() == 0 && !Ini.isClient()) + ; // System Access + else + finalSQL = new StringBuffer (role.addAccessSQL (finalSQL.toString (), + tableName, MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO)); + } + + // Group By + if (IsGroupedBy) + finalSQL.append(sqlGROUP.substring(0, sqlGROUP.length()-1)); // last , + + // Add ORDER BY clause + if (orderColumns != null) + { + for (int i = 0; i < orderColumns.size(); i++) + { + if (i == 0) + finalSQL.append(" ORDER BY "); + else + finalSQL.append(","); + String by = (String)orderColumns.get(i); + if (by == null || by.length() == 0) + by = String.valueOf(i+1); + finalSQL.append(by); + } + } // order by + + + // Print Data + PrintData pd = new PrintData (ctx, reportName); + PrintDataColumn[] info = new PrintDataColumn [columns.size()]; + columns.toArray(info); // column order is is m_synonymc with SELECT column position + pd.setColumnInfo(info); + pd.setTableName(tableName); + pd.setSQL(finalSQL.toString()); + pd.setHasLevelNo(hasLevelNo); + + log.finest (finalSQL.toString ()); + log.finest ("Group=" + m_group); + return pd; + } // getPrintDataInfo + + /** + * Next Synonym. + * Creates next synonym A..Z AA..ZZ AAA..ZZZ + */ + private void synonymNext() + { + int length = m_synonym.length(); + char cc = m_synonym.charAt(0); + if (cc == 'Z') + { + cc = 'A'; + length++; + } + else + cc++; + // + m_synonym = String.valueOf(cc); + if (length == 1) + return; + m_synonym += String.valueOf(cc); + if (length == 2) + return; + m_synonym += String.valueOf(cc); + } // synonymNext + + /** + * Get TableName and ColumnName for Reference Tables. + * @param AD_Reference_Value_ID reference value + * @return 0=TableName, 1=KeyColumn, 2=DisplayColumn + */ + public static TableReference getTableReference (int AD_Reference_Value_ID) + { + TableReference tr = new TableReference(); + // + String SQL = "SELECT t.TableName, ck.ColumnName AS KeyColumn," // 1..2 + + " cd.ColumnName AS DisplayColumn, rt.IsValueDisplayed, cd.IsTranslated " + + "FROM AD_Ref_Table rt" + + " INNER JOIN AD_Table t ON (rt.AD_Table_ID = t.AD_Table_ID)" + + " INNER JOIN AD_Column ck ON (rt.AD_Key = ck.AD_Column_ID)" + + " INNER JOIN AD_Column cd ON (rt.AD_Display = cd.AD_Column_ID) " + + "WHERE rt.AD_Reference_ID=?" // 1 + + " AND rt.IsActive = 'Y' AND t.IsActive = 'Y'"; + try + { + PreparedStatement pstmt = DB.prepareStatement(SQL, null); + pstmt.setInt (1, AD_Reference_Value_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + tr.TableName = rs.getString(1); + tr.KeyColumn = rs.getString(2); + tr.DisplayColumn = rs.getString(3); + tr.IsValueDisplayed = "Y".equals(rs.getString(4)); + tr.IsTranslated = "Y".equals(rs.getString(5)); + } + rs.close(); + pstmt.close(); + } + catch (SQLException ex) + { + log.log(Level.SEVERE, SQL, ex); + } + return tr; + } // getTableReference + + + /************************************************************************** + * Load Data into PrintData + * @param pd print data with SQL and ColumnInfo set + * @param format print format + */ + private void loadPrintData (PrintData pd, MPrintFormat format) + { + // Translate Spool Output + boolean translateSpool = pd.getTableName().equals("T_Spool"); + m_runningTotalString = Msg.getMsg(format.getLanguage(), "RunningTotal"); + int rowNo = 0; + PrintDataColumn pdc = null; + boolean hasLevelNo = pd.hasLevelNo(); + int levelNo = 0; + // + try + { + PreparedStatement pstmt = DB.prepareStatement(pd.getSQL(), null); + ResultSet rs = pstmt.executeQuery(); + // Row Loop + while (rs.next()) + { + if (hasLevelNo) + levelNo = rs.getInt("LevelNo"); + else + levelNo = 0; + // Check Group Change ---------------------------------------- + if (m_group.getGroupColumnCount() > 1) // one is GRANDTOTAL_ + { + // Check Columns for Function Columns + for (int i = pd.getColumnInfo().length-1; i >= 0; i--) // backwards (leaset group first) + { + PrintDataColumn group_pdc = pd.getColumnInfo()[i]; + if (!m_group.isGroupColumn(group_pdc.getColumnName())) + continue; + + // Group change + Object value = m_group.groupChange(group_pdc.getColumnName(), rs.getObject(group_pdc.getAlias())); + if (value != null) // Group change + { + char[] functions = m_group.getFunctions(group_pdc.getColumnName()); + for (int f = 0; f < functions.length; f++) + { + printRunningTotal(pd, levelNo, rowNo++); + pd.addRow(true, levelNo); + // get columns + for (int c = 0; c < pd.getColumnInfo().length; c++) + { + pdc = pd.getColumnInfo()[c]; + // log.fine("loadPrintData - PageBreak = " + pdc.isPageBreak()); + + if (group_pdc.getColumnName().equals(pdc.getColumnName())) + { + String valueString = value.toString(); + if (value instanceof Timestamp) + valueString = DisplayType.getDateFormat(pdc.getDisplayType(), m_language).format(value); + valueString += PrintDataFunction.getFunctionSymbol(functions[f]); + pd.addNode(new PrintDataElement(pdc.getColumnName(), + valueString, DisplayType.String, false, pdc.isPageBreak())); + } + else if (m_group.isFunctionColumn(pdc.getColumnName(), functions[f])) + { + pd.addNode(new PrintDataElement(pdc.getColumnName(), + m_group.getValue(group_pdc.getColumnName(), + pdc.getColumnName(), functions[f]), + PrintDataFunction.getFunctionDisplayType(functions[f]), + false, pdc.isPageBreak())); + } + } // for all columns + } // for all functions + // Reset Group Values + for (int c = 0; c < pd.getColumnInfo().length; c++) + { + pdc = pd.getColumnInfo()[c]; + m_group.reset(group_pdc.getColumnName(), pdc.getColumnName()); + } + } // Group change + } // for all columns + } // group change + + // new row --------------------------------------------------- + printRunningTotal(pd, levelNo, rowNo++); + pd.addRow(false, levelNo); + int counter = 1; + // get columns + for (int i = 0; i < pd.getColumnInfo().length; i++) + { + pdc = pd.getColumnInfo()[i]; + PrintDataElement pde = null; + + // Key Column - No DisplayColumn + if (pdc.getAlias().equals(KEY)) + { + if (pdc.getColumnName().endsWith("_ID")) + { + // int id = rs.getInt(pdc.getColumnIDName()); + int id = rs.getInt(counter++); + if (!rs.wasNull()) + { + KeyNamePair pp = new KeyNamePair(id, KEY); // Key + pde = new PrintDataElement(pdc.getColumnName(), pp, pdc.getDisplayType(), true, pdc.isPageBreak()); + } + } + else + { + // String id = rs.getString(pdc.getColumnIDName()); + String id = rs.getString(counter++); + if (!rs.wasNull()) + { + ValueNamePair pp = new ValueNamePair(id, KEY); // Key + pde = new PrintDataElement(pdc.getColumnName(), pp, pdc.getDisplayType(), true, pdc.isPageBreak()); + } + } + } + // Non-Key Column + else + { + // Display and Value Column + if (pdc.hasAlias()) + { + // DisplayColumn first + String display = rs.getString(counter++); + if (pdc.getColumnName().endsWith("_ID")) + { + int id = rs.getInt(counter++); + if (display != null && !rs.wasNull()) + { + KeyNamePair pp = new KeyNamePair(id, display); + pde = new PrintDataElement(pdc.getColumnName(), pp, pdc.getDisplayType()); + } + } + else + { + String id = rs.getString(counter++); + if (display != null && !rs.wasNull()) + { + ValueNamePair pp = new ValueNamePair(id, display); + pde = new PrintDataElement(pdc.getColumnName(), pp, pdc.getDisplayType()); + } + } + } + // Display Value only + else + { + // Transformation for Booleans + if (pdc.getDisplayType() == DisplayType.YesNo) + { + String s = rs.getString(counter++); + if (!rs.wasNull()) + { + boolean b = s.equals("Y"); + pde = new PrintDataElement(pdc.getColumnName(), new Boolean(b), pdc.getDisplayType()); + } + } + else if (pdc.getDisplayType() == DisplayType.TextLong) + { + Clob clob = rs.getClob(counter++); + String value = ""; + if (clob != null) + { + long length = clob.length(); + value = clob.getSubString(1, (int)length); + } + pde = new PrintDataElement(pdc.getColumnName(), value, pdc.getDisplayType()); + } + else + // The general case + { + Object obj = rs.getObject(counter++); + if (obj != null && obj instanceof String) + { + obj = ((String)obj).trim(); + if (((String)obj).length() == 0) + obj = null; + } + if (obj != null) + { + // Translate Spool Output + if (translateSpool && obj instanceof String) + { + String s = (String)obj; + s = Msg.parseTranslation(pd.getCtx(), s); + pde = new PrintDataElement(pdc.getColumnName(), s, pdc.getDisplayType()); + } + else + pde = new PrintDataElement(pdc.getColumnName(), obj, pdc.getDisplayType()); + } + } + } // Value only + } // Non-Key Column + if (pde != null) + { + pd.addNode(pde); + m_group.addValue(pde.getColumnName(), pde.getFunctionValue()); + } + } // for all columns + + } // for all rows + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, pdc + " - " + e.getMessage() + "\nSQL=" + pd.getSQL()); + } + + // -- we have all rows - finish + // Check last Group Change + if (m_group.getGroupColumnCount() > 1) // one is TOTAL + { + for (int i = pd.getColumnInfo().length-1; i >= 0; i--) // backwards (leaset group first) + { + PrintDataColumn group_pdc = pd.getColumnInfo()[i]; + if (!m_group.isGroupColumn(group_pdc.getColumnName())) + continue; + Object value = m_group.groupChange(group_pdc.getColumnName(), new Object()); + if (value != null) // Group change + { + char[] functions = m_group.getFunctions(group_pdc.getColumnName()); + for (int f = 0; f < functions.length; f++) + { + printRunningTotal(pd, levelNo, rowNo++); + pd.addRow(true, levelNo); + // get columns + for (int c = 0; c < pd.getColumnInfo().length; c++) + { + pdc = pd.getColumnInfo()[c]; + if (group_pdc.getColumnName().equals(pdc.getColumnName())) + { + String valueString = value.toString(); + if (value instanceof Timestamp) + valueString = DisplayType.getDateFormat(pdc.getDisplayType(), m_language).format(value); + valueString += PrintDataFunction.getFunctionSymbol(functions[f]); + pd.addNode(new PrintDataElement(pdc.getColumnName(), + valueString, DisplayType.String)); + } + else if (m_group.isFunctionColumn(pdc.getColumnName(), functions[f])) + { + pd.addNode(new PrintDataElement(pdc.getColumnName(), + m_group.getValue(group_pdc.getColumnName(), + pdc.getColumnName(), functions[f]), + PrintDataFunction.getFunctionDisplayType(functions[f]))); + } + } + } // for all functions + // No Need to Reset + } // Group change + } + } // last group change + + // Add Total Lines + if (m_group.isGroupColumn(PrintDataGroup.TOTAL)) + { + char[] functions = m_group.getFunctions(PrintDataGroup.TOTAL); + for (int f = 0; f < functions.length; f++) + { + printRunningTotal(pd, levelNo, rowNo++); + pd.addRow(true, levelNo); + // get columns + for (int c = 0; c < pd.getColumnInfo().length; c++) + { + pdc = pd.getColumnInfo()[c]; + if (c == 0) // put Function in first Column + { + String name = ""; + if (!format.getTableFormat().isPrintFunctionSymbols()) // Translate Sum, etc. + name = Msg.getMsg(format.getLanguage(), PrintDataFunction.getFunctionName(functions[f])); + name += PrintDataFunction.getFunctionSymbol(functions[f]); // Symbol + pd.addNode(new PrintDataElement(pdc.getColumnName(), name.trim(), DisplayType.String)); + } + else if (m_group.isFunctionColumn(pdc.getColumnName(), functions[f])) + { + pd.addNode(new PrintDataElement(pdc.getColumnName(), + m_group.getValue(PrintDataGroup.TOTAL, + pdc.getColumnName(), functions[f]), + PrintDataFunction.getFunctionDisplayType(functions[f]))); + } + } // for all columns + } // for all functions + // No Need to Reset + } // TotalLine + + if (pd.getRowCount() == 0) + { + if (CLogMgt.isLevelFiner()) + log.warning("NO Rows - ms=" + (System.currentTimeMillis()-m_startTime) + + " - " + pd.getSQL()); + else + log.warning("NO Rows - ms=" + (System.currentTimeMillis()-m_startTime)); + } + else + log.info("Rows=" + pd.getRowCount() + + " - ms=" + (System.currentTimeMillis()-m_startTime)); + } // loadPrintData + + /** + * Print Running Total + * @param pd Print Data to add lines to + * @param levelNo level no + * @param rowNo row no + */ + private void printRunningTotal (PrintData pd, int levelNo, int rowNo) + { + if (m_runningTotalLines < 1) // -1 = none + return; + log.fine("(" + m_runningTotalLines + ") - Row=" + rowNo + + ", mod=" + rowNo % m_runningTotalLines); + if (rowNo % m_runningTotalLines != 0) + return; + + log.fine("Row=" + rowNo); + PrintDataColumn pdc = null; + int start = 0; + if (rowNo == 0) // no page break on page 1 + start = 1; + for (int rt = start; rt < 2; rt++) + { + pd.addRow (true, levelNo); + // get sum columns + for (int c = 0; c < pd.getColumnInfo().length; c++) + { + pdc = pd.getColumnInfo()[c]; + if (c == 0) + { + String title = "RunningTotal"; + pd.addNode(new PrintDataElement(pdc.getColumnName(), + title, DisplayType.String, false, rt==0)); // page break + } + else if (m_group.isFunctionColumn(pdc.getColumnName(), PrintDataFunction.F_SUM)) + { + pd.addNode(new PrintDataElement(pdc.getColumnName(), + m_group.getValue(PrintDataGroup.TOTAL, pdc.getColumnName(), PrintDataFunction.F_SUM), + PrintDataFunction.getFunctionDisplayType(PrintDataFunction.F_SUM), false, false)); + } + } // for all sum columns + } // two lines + } // printRunningTotal + + + /************************************************************************* + * Test + * @param args args + */ + public static void main(String[] args) + { + org.compiere.Adempiere.startup(true); + + // DataEngine de = new DataEngine(null); + DataEngine de = new DataEngine(Language.getLanguage("de_DE")); + MQuery query = new MQuery(); + query.addRestriction("AD_Table_ID", MQuery.LESS, 105); + // PrintData pd = de.load_fromTable(100, query, null, null, false); + // pd.dump(); + // pd.createXML(new javax.xml.transform.stream.StreamResult(System.out)); + } + +} // DataEngine + +/** + * Table Reference Info + */ +class TableReference +{ + /** Table Name */ + public String TableName; + /** Key Column */ + public String KeyColumn; + /** Display Column */ + public String DisplayColumn; + /** Displayed */ + public boolean IsValueDisplayed = false; + /** Translated */ + public boolean IsTranslated = false; +} // TableReference diff --git a/print/src/org/compiere/print/MPrintColor.java b/print/src/org/compiere/print/MPrintColor.java new file mode 100644 index 0000000000..91736ab7bb --- /dev/null +++ b/print/src/org/compiere/print/MPrintColor.java @@ -0,0 +1,245 @@ +/****************************************************************************** + * 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; + +import java.awt.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * AD_PrintColor Print Color Model + * + * @author Jorg Janke + * @version $Id: MPrintColor.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintColor extends X_AD_PrintColor +{ + + /************************************************************************** + * Create Color in Database and save + * @param color color + * @param name name + * @return MPrintColor + */ + static MPrintColor create (Color color, String name) + { + MPrintColor pc = new MPrintColor (Env.getCtx(), 0, null); + pc.setName(name); + pc.setColor(color); + pc.save(); + return pc; + } // create + + /*************************************************************************/ + + /** Dark Green */ + public static final Color darkGreen = new Color (0, 128, 0); + /** Black Green */ + public static final Color blackGreen = new Color (0, 64, 0); + /** Dark Blue */ + public static final Color darkBlue = new Color (0, 0, 128); + /** Black Blue */ + public static final Color blackBlue = new Color (0, 0, 64); + /** White Gray */ + public static final Color whiteGray = new Color (224, 224, 224); + /** Brown */ + public static final Color brown = new Color (153, 102, 51); + /** Dark Brown */ + public static final Color darkBrown = new Color (102, 51, 0); + + /*************************************************************************/ + + /** Cached Colors */ + static private CCache s_colors = new CCache("AD_PrintColor", 20); + /** Static Logger */ + private static CLogger s_log = CLogger.getCLogger (MPrintColor.class); + + /** + * Get Color. + * if id = 0, it returns a new color (black) - but do not modify/save as cached + * @param ctx context + * @param AD_PrintColor_ID id + * @return Color + */ + static public MPrintColor get (Properties ctx, int AD_PrintColor_ID) + { + // if (AD_PrintColor_ID == 0) + // return new MPrintColor (ctx, 0); + Integer key = new Integer(AD_PrintColor_ID); + MPrintColor pc = (MPrintColor)s_colors.get(key); + if (pc == null) + { + pc = new MPrintColor (ctx, AD_PrintColor_ID, null); + s_colors.put(key, pc); + } + return pc; + } // get + + /** + * Get Color + * @param ctx context + * @param AD_PrintColor_ID id + * @return Color or null + */ + static public MPrintColor get (Properties ctx, String AD_PrintColor_ID) + { + if (AD_PrintColor_ID == null || AD_PrintColor_ID.length() == 0) + return null; + try + { + int id = Integer.parseInt(AD_PrintColor_ID); + return get(ctx, id); + } + catch (Exception e) + { + s_log.log(Level.SEVERE, "AD_PrintColor_ID=" + AD_PrintColor_ID + + " - " + e.toString()); + } + return null; + } // get + + + /************************************************************************** + * Constructor + * @param ctx context + * @param AD_PrintColor_ID ID + * @param trxName transaction + */ + public MPrintColor(Properties ctx, int AD_PrintColor_ID, String trxName) + { + super (ctx, AD_PrintColor_ID, trxName); + if (AD_PrintColor_ID == 0) + setIsDefault(false); + } // MPrintColor + + /** Color cached */ + private Color m_cacheColor = null; + + /** + * Get Color + * @return Color + */ + public Color getColor() + { + if (m_cacheColor != null) + return m_cacheColor; + String code = getCode(); + if (code == null || code.equals(".")) + m_cacheColor = Color.black; + try + { + if (code != null && !code.equals(".")) + { + int rgba = Integer.parseInt(code); + m_cacheColor = new Color(rgba, false); + } + } + catch (Exception e) + { + log.log(Level.SEVERE, "MPrintColor.getColor", e); + } + if (code == null) + m_cacheColor = Color.black; + // log.fine( "MPrintColor.getColor " + code, m_cacheColor); + return m_cacheColor; + } // getColor + + /** + * Set Color + * @param color Color + */ + public void setColor (Color color) + { + int rgba = color.getRGB(); + super.setCode(String.valueOf(rgba)); + } // setColor + + /** + * Get Color as RRGGBB hex string for HTML font tag + * @return rgb hex value + */ + public String getRRGGBB() + { + Color color = getColor(); + StringBuffer sb = new StringBuffer(); + sb.append(Util.toHex((byte)color.getRed())) + .append(Util.toHex((byte)color.getGreen())) + .append(Util.toHex((byte)color.getBlue())); + return sb.toString(); + } // getRRGGBB + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("MPrintColor["); + sb.append("ID=").append(get_ID()) + .append(",Name=").append(getName()) + .append(",RGB=").append(getCode()) + .append(",").append(getColor()) + .append("]"); + return sb.toString(); + } // toString + + + /************************************************************************** + * Create Standard Colors + * @param args args + */ + public static void main(String[] args) + { + org.compiere.Adempiere.startupEnvironment(true); + Color[] colors = new Color[] + {Color.black, Color.red, Color.green, Color.blue, + Color.darkGray, Color.gray, Color.lightGray, Color.white, + Color.cyan, Color.magenta, Color.orange, Color.pink, Color.yellow, + SystemColor.textHighlight}; + String[] names = new String[] + {"Black", "Red", "Green", "Blue", + "Gray dark", "Gray", "Gray light", "White", + "Cyan", "Magenta", "Orange", "Pink", "Yellow", + "Blue dark"}; + for (int i = 0; i < colors.length; i++) + System.out.println(names[i] + " = " + colors[i] + " RGB=" + colors[i].getRGB() + + " -> " + new Color(colors[i].getRGB(), false) + + " -> " + new Color(colors[i].getRGB(), true)); +/** + // Create Colors + for (int i = 0; i < colors.length; i++) + create(colors[i], names[i]); + create(whiteGray, "Gray white"); + create(darkGreen, "Green dark"); + create(blackGreen, "Green black"); + create(blackBlue, "Blue black"); + create(brown, "Brown"); + create(darkBrown, "Brown dark"); +**/ + + // Read All Colors + int[] IDs = PO.getAllIDs ("AD_PrintColor", null, null); + for (int i = 0; i < IDs.length; i++) + { + MPrintColor pc = new MPrintColor(Env.getCtx(), IDs[i], null); + System.out.println(IDs[i] + ": " + pc + " = " + pc.getColor() + ", RGB=" + pc.getColor().getRGB()); + } + } // main + +} // MPrintColor diff --git a/print/src/org/compiere/print/MPrintFont.java b/print/src/org/compiere/print/MPrintFont.java new file mode 100644 index 0000000000..da7d557017 --- /dev/null +++ b/print/src/org/compiere/print/MPrintFont.java @@ -0,0 +1,245 @@ +/****************************************************************************** + * 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; + +import java.awt.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * AD_PrintFont Print Font Model + * + * @author Jorg Janke + * @version $Id: MPrintFont.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintFont extends X_AD_PrintFont +{ + /** + * Constructor + * @param ctx context + * @param AD_PrintFont_ID ID + * @param trxName transaction + */ + private MPrintFont(Properties ctx, int AD_PrintFont_ID, String trxName) + { + super (ctx, AD_PrintFont_ID, trxName); + if (AD_PrintFont_ID == 0) + setIsDefault(false); + } // MPrintFont + + /** Font cached */ + private Font m_cacheFont = null; + + /*************************************************************************/ + + /** + * Get Font + * @return Font + */ + public Font getFont() + { + if (m_cacheFont != null) + return m_cacheFont; + String code = (String)get_Value("Code"); + if (code == null || code.equals(".")) + m_cacheFont = new Font (null); + try + { + if (code != null && !code.equals(".")) + // fontfamilyname-style-pointsize + m_cacheFont = Font.decode(code); + } + catch (Exception e) + { + log.log(Level.SEVERE, "MPrintFont.getFont", e); + } + if (code == null) + m_cacheFont = new Font (null); // family=dialog,name=Dialog,style=plain,size=12 + // log.fine( "MPrintFont.getFont " + code, m_cacheFont); + return m_cacheFont; + } // getFont + + /** + * Set Font + * @param font Font + */ + public void setFont (Font font) + { + // fontfamilyname-style-pointsize + StringBuffer sb = new StringBuffer(); + sb.append(font.getFamily()).append("-"); + int style = font.getStyle(); + if (style == Font.PLAIN) + sb.append("PLAIN"); + else if (style == Font.BOLD) + sb.append("BOLD"); + else if (style == Font.ITALIC) + sb.append("ITALIC"); + else if (style == (Font.BOLD + Font.ITALIC)) + sb.append("BOLDITALIC"); + sb.append("-").append(font.getSize()); + setCode(sb.toString()); + } // setFont + + /*************************************************************************/ + + /** + * Create Font in Database and save + * @param font font + * @return PrintFont + */ + static MPrintFont create (Font font) + { + MPrintFont pf = new MPrintFont(Env.getCtx(), 0, null); + StringBuffer name = new StringBuffer (font.getName()); + if (font.isBold()) + name.append(" bold"); + if (font.isItalic()) + name.append(" italic"); + name.append(" ").append(font.getSize()); + pf.setName(name.toString()); + pf.setFont(font); + pf.save(); + return pf; + } // create + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("MPrintFont["); + sb.append("ID=").append(get_ID()) + .append(",Name=").append(getName()) + .append("PSName=").append(getFont().getPSName()) + .append(getFont()) + .append("]"); + return sb.toString(); + } // toString + + /** + * Get PostScript Level 2 definition. + * e.g. /dialog 12 selectfont + * @return PostScript command + */ + public String toPS() + { + StringBuffer sb = new StringBuffer("/"); + sb.append(getFont().getPSName()); + if (getFont().isBold()) + sb.append(" Bold"); + if (getFont().isItalic()) + sb.append(" Italic"); + sb.append(" ").append(getFont().getSize()) + .append(" selectfont"); + return sb.toString(); + } // toPS + + /** + * Dump Font + * @param font font + */ + static void dump (Font font) + { + System.out.println("Family=" + font.getFamily()); + System.out.println("FontName=" + font.getFontName()); + System.out.println("Name=" + font.getName()); + System.out.println("PSName=" + font.getPSName()); + System.out.println("Style=" + font.getStyle()); + System.out.println("Size=" + font.getSize()); + System.out.println("Attributes:"); + Map map = font.getAttributes(); + Iterator keys = map.keySet().iterator(); + while (keys.hasNext()) + { + Object key = keys.next(); + Object value = map.get(key); + System.out.println(" - " + key + "=" + value); + } + System.out.println(font); + } // dump + + /*************************************************************************/ + + /** Cached Fonts */ + static private CCache s_fonts = new CCache("AD_PrintFont", 20); + + /** + * Get Font + * @param AD_PrintFont_ID id + * @return Font + */ + static public MPrintFont get (int AD_PrintFont_ID) + { + Integer key = new Integer(AD_PrintFont_ID); + MPrintFont pf = (MPrintFont)s_fonts.get(key); + if (pf == null) + { + pf = new MPrintFont (Env.getCtx(), AD_PrintFont_ID, null); + s_fonts.put(key, pf); + } + return pf; + } // get + + /*************************************************************************/ + + /** + * Seed Fonts + * @param args args + */ + public static void main(String[] args) + { + System.out.println("Available Fonts:"); + String[] family = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + for (int i = 0; i < family.length; i++) + System.out.println(" - " + family[i]); + + org.compiere.Adempiere.startup(true); + MPrintFont pf = new MPrintFont(Env.getCtx(), 100, null); + dump( pf.getFont() ); + + String[] systemLocical = new String[] {"Dialog", "DialogInput", "Monospaced", "Serif", "SansSerif"}; + for (int i = 0; i < systemLocical.length; i++) + { + // create(new Font(systemLocical[i], Font.BOLD, 13)); + // create(new Font(systemLocical[i], Font.PLAIN, 11)); + // create(new Font(systemLocical[i], Font.BOLD, 11)); + // create(new Font(systemLocical[i], Font.ITALIC, 11)); + // create(new Font(systemLocical[i], Font.PLAIN, 10)); + // create(new Font(systemLocical[i], Font.BOLD, 10)); + // create(new Font(systemLocical[i], Font.ITALIC, 10)); + // create(new Font(systemLocical[i], Font.PLAIN, 9)); + // create(new Font(systemLocical[i], Font.BOLD, 9)); + // create(new Font(systemLocical[i], Font.ITALIC, 9)); + // create(new Font(systemLocical[i], Font.PLAIN, 8)); + // create(new Font(systemLocical[i], Font.BOLD, 8)); + // create(new Font(systemLocical[i], Font.ITALIC, 8)); + } + + // Read All Fonts + int[] IDs = PO.getAllIDs ("AD_PrintFont", null, null); + for (int i = 0; i < IDs.length; i++) + { + pf = new MPrintFont(Env.getCtx(), IDs[i], null); + System.out.println(IDs[i] + " = " + pf.getFont()); + } + + } // main +} // MPrintFont diff --git a/print/src/org/compiere/print/MPrintFormat.java b/print/src/org/compiere/print/MPrintFormat.java new file mode 100644 index 0000000000..02af8a8c0c --- /dev/null +++ b/print/src/org/compiere/print/MPrintFormat.java @@ -0,0 +1,863 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * AD_PrintFormat - Print Format Model. + * (Add missing Items with PrintFormatUtil) + * + * @author Jorg Janke + * @version $Id: MPrintFormat.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintFormat extends X_AD_PrintFormat +{ + /** + * Public Constructor. + * Use static get methods + * @param ctx context + * @param AD_PrintFormat_ID AD_PrintFormat_ID + * @param trxName transaction + */ + public MPrintFormat (Properties ctx, int AD_PrintFormat_ID, String trxName) + { + super (ctx, AD_PrintFormat_ID, trxName); + // Language=[Deutsch,Locale=de_DE,AD_Language=en_US,DatePattern=DD.MM.YYYY,DecimalPoint=false] + m_language = Language.getLoginLanguage(); + if (AD_PrintFormat_ID == 0) + { + setStandardHeaderFooter(true); + setIsTableBased(true); + setIsForm(false); + setIsDefault(false); + } + m_items = getItems(); + } // MPrintFormat + + /** + * Load Constructor + * @param ctx context + * @param rs result set + * @param trxName transaction + */ + public MPrintFormat (Properties ctx, ResultSet rs, String trxName) + { + super(ctx, rs, trxName); + m_language = Language.getLoginLanguage(); + m_items = getItems(); + } // MPrintFormat + + /** Items */ + private MPrintFormatItem[] m_items = null; + /** Translation View Language */ + private String m_translationViewLanguage = null; + /** Language of Report */ + private Language m_language; + /** Table Format */ + private MPrintTableFormat m_tFormat; + + private static CLogger s_log = CLogger.getCLogger (MPrintFormat.class); + + /** + * Get Language + * @return language + */ + public Language getLanguage() + { + return m_language; + } // getLanguage + + /** + * Set Language + * @param language language + */ + public void setLanguage(Language language) + { + if (language != null) + { + m_language = language; + // log.fine("setLanguage - " + language); + } + m_translationViewLanguage = null; + } // getLanguage + + /** + * Get AD_Column_ID of Order Columns + * @return Array of AD_Column_IDs in Sort Order + */ + public int[] getOrderAD_Column_IDs() + { + HashMap map = new HashMap(); // SortNo - AD_Column_ID + for (int i = 0; i < m_items.length; i++) + { + // Sort Order and Column must be > 0 + if (m_items[i].getSortNo() != 0 && m_items[i].getAD_Column_ID() != 0) + map.put(new Integer(m_items[i].getSortNo()), new Integer(m_items[i].getAD_Column_ID())); + } + // Get SortNo and Sort them + Integer[] keys = new Integer[map.keySet().size()]; + map.keySet().toArray(keys); + Arrays.sort(keys); + + // Create AD_Column_ID array + int[] retValue = new int[keys.length]; + for (int i = 0; i < keys.length; i++) + { + Integer value = (Integer)map.get(keys[i]); + retValue[i] = value.intValue(); + } + return retValue; + } // getOrderAD_Column_IDs + + /** + * Get AD_Column_IDs of columns in Report + * @return Array of AD_Column_ID + */ + public int[] getAD_Column_IDs() + { + ArrayList list = new ArrayList(); + for (int i = 0; i < m_items.length; i++) + { + if (m_items[i].getAD_Column_ID() != 0 && m_items[i].isPrinted()) + list.add(new Integer(m_items[i].getAD_Column_ID())); + } + // Convert + int[] retValue = new int[list.size()]; + for (int i = 0; i < list.size(); i++) + retValue[i] = ((Integer)list.get(i)).intValue(); + return retValue; + } // getAD_Column_IDs + + /** + * Set Items + * @param items items + */ + private void setItems (MPrintFormatItem[] items) + { + if (items != null) + m_items = items; + } // setItems + + /** + * Get active Items + * @return items + */ + private MPrintFormatItem[] getItems() + { + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM AD_PrintFormatItem pfi " + + "WHERE pfi.AD_PrintFormat_ID=? AND pfi.IsActive='Y'" + // Display restrictions - Passwords, etc. + + " AND NOT EXISTS (SELECT * FROM AD_Field f " + + "WHERE pfi.AD_Column_ID=f.AD_Column_ID" + + " AND (f.IsEncrypted='Y' OR f.ObscureType IS NOT NULL))" + + "ORDER BY SeqNo"; + MRole role = MRole.getDefault(getCtx(), false); + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, get_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + MPrintFormatItem pfi = new MPrintFormatItem(p_ctx, rs, get_TrxName()); + if (role.isColumnAccess(getAD_Table_ID(), pfi.getAD_Column_ID(), true)) + list.add (pfi); + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + // + MPrintFormatItem[] retValue = new MPrintFormatItem[list.size()]; + list.toArray(retValue); + return retValue; + } // getItems + + /** + * Get Item Count + * @return number of items or -1 if items not defined + */ + public int getItemCount() + { + if (m_items == null) + return -1; + return m_items.length; + } // getItemCount + + /** + * Get Print Format Item + * @param index index + * @return Print Format Item + */ + public MPrintFormatItem getItem (int index) + { + if (index < 0 || index >= m_items.length) + throw new ArrayIndexOutOfBoundsException("Index=" + index + " - Length=" + m_items.length); + return m_items[index]; + } // getItem + + /** + * Set the translation of the Format Items to the original + */ + public void setTranslation() + { + StringBuffer sb = new StringBuffer ("UPDATE AD_PrintFormatItem_Trl t" + + " SET (PrintName, PrintNameSuffix)=" + + " (SELECT PrintName, PrintNameSuffix FROM AD_PrintFormatItem i WHERE i.AD_PrintFormatItem_ID=t.AD_PrintFormatItem_ID) " + + "WHERE AD_PrintFormatItem_ID IN" + + " (SELECT AD_PrintFormatItem_ID FROM AD_PrintFormatItem WHERE AD_PrintFormat_ID=").append(get_ID()).append(")"); + int no = DB.executeUpdate(sb.toString(), get_TrxName()); + log.fine("setTranslation #" + no); + } // setTranslation + + + /************************************************************************** + * Set Standard Header + * @param standardHeaderFooter true if std header + */ + public void setStandardHeaderFooter (boolean standardHeaderFooter) + { + super.setIsStandardHeaderFooter(standardHeaderFooter); + if (standardHeaderFooter) + { + setFooterMargin(0); + setHeaderMargin(0); + } + } // setSatndardHeaderFooter + + /** + * Set Table based. + * Reset Form + * @param tableBased true if table based + */ + public void setIsTableBased (boolean tableBased) + { + super.setIsTableBased (tableBased); + if (tableBased) + super.setIsForm(false); + } // setIsTableBased + + + /************************************************************************** + * Set Translation View Language. + * @param language language (checked for base language) + */ + public void setTranslationLanguage (Language language) + { + if (language == null || language.isBaseLanguage()) + { + log.info("Ignored - " + language); + m_translationViewLanguage = null; + } + else + { + log.info("Language=" + language.getAD_Language()); + m_translationViewLanguage = language.getAD_Language(); + m_language = language; + } + } // setTranslationLanguage + + /** + * Get Translation View use + * @return true if a translation view is used + */ + public boolean isTranslationView() + { + return m_translationViewLanguage != null; + } // isTranslationView + + /** + * Update the Query to access the Translation View. + * Can be called multiple times, adds only if not set already + * @param query query to be updated + */ + public void setTranslationViewQuery (MQuery query) + { + // Set Table Name and add add restriction, if a view and language set + if (m_translationViewLanguage != null && query != null && query.getTableName().toUpperCase().endsWith("_V")) + { + query.setTableName(query.getTableName() + "t"); + query.addRestriction("AD_Language", MQuery.EQUAL, m_translationViewLanguage); + } + } // setTranslationViewQuery + + + /************************************************************************** + * Get Optional TableFormat + * @param AD_PrintTableFormat_ID table format + */ + public void setAD_PrintTableFormat_ID (int AD_PrintTableFormat_ID) + { + super.setAD_PrintTableFormat_ID(AD_PrintTableFormat_ID); + m_tFormat = MPrintTableFormat.get (getCtx(), AD_PrintTableFormat_ID, getAD_PrintFont_ID()); + } // getAD_PrintTableFormat_ID + + /** + * Get Table Format + * @return Table Format + */ + public MPrintTableFormat getTableFormat() + { + if (m_tFormat == null) + m_tFormat = MPrintTableFormat.get(getCtx(), getAD_PrintTableFormat_ID(), getAD_PrintFont_ID()); + return m_tFormat; + } // getTableFormat + + /** + * Sting Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer ("MPrintFormat[ID=").append(get_ID()) + .append(",Name=").append(getName()) + .append(",Language=").append(getLanguage()) + .append(",Items=").append(getItemCount()) + .append("]"); + return sb.toString(); + } // toString + + + /************************************************************************** + * Load Special data (images, ..). + * To be extended by sub-classes + * @param rs result set + * @param index zero based index + * @return value value + * @throws SQLException + */ + protected Object loadSpecial (ResultSet rs, int index) throws SQLException + { + // CreateCopy + // log.config(p_info.getColumnName(index)); + return null; + } // loadSpecial + + /** + * Save Special Data. + * To be extended by sub-classes + * @param value value + * @param index index + * @return SQL code for INSERT VALUES clause + */ + protected String saveNewSpecial (Object value, int index) + { + // CreateCopy + // String colName = p_info.getColumnName(index); + // String colClass = p_info.getColumnClass(index).toString(); + // String colValue = value == null ? "null" : value.getClass().toString(); + // log.log(Level.SEVERE, "Unknown class for column " + colName + " (" + colClass + ") - Value=" + colValue); + if (value == null) + return "NULL"; + return value.toString(); + } // saveNewSpecial + + + /************************************************************************** + * Create MPrintFormat for Table + * @param ctx context + * @param AD_Table_ID table + * @return print format + */ + static public MPrintFormat createFromTable (Properties ctx, int AD_Table_ID) + { + return createFromTable(ctx, AD_Table_ID, 0); + } // createFromTable + + /** + * Create MPrintFormat for Table + * @param ctx context + * @param AD_Table_ID table + * @param AD_PrintFormat_ID 0 or existing PrintFormat + * @return print format + */ + static public MPrintFormat createFromTable (Properties ctx, + int AD_Table_ID, int AD_PrintFormat_ID) + { + int AD_Client_ID = Env.getAD_Client_ID(ctx); + s_log.info ("AD_Table_ID=" + AD_Table_ID + " - AD_Client_ID=" + AD_Client_ID); + + MPrintFormat pf = new MPrintFormat(ctx, AD_PrintFormat_ID, null); + pf.setAD_Table_ID (AD_Table_ID); + + // Get Info + String sql = "SELECT TableName," // 1 + + " (SELECT COUNT(*) FROM AD_PrintFormat x WHERE x.AD_Table_ID=t.AD_Table_ID AND x.AD_Client_ID=c.AD_Client_ID) AS Count," + + " COALESCE (cpc.AD_PrintColor_ID, pc.AD_PrintColor_ID) AS AD_PrintColor_ID," // 3 + + " COALESCE (cpf.AD_PrintFont_ID, pf.AD_PrintFont_ID) AS AD_PrintFont_ID," + + " COALESCE (cpp.AD_PrintPaper_ID, pp.AD_PrintPaper_ID) AS AD_PrintPaper_ID " + + "FROM AD_Table t, AD_Client c" + + " LEFT OUTER JOIN AD_PrintColor cpc ON (cpc.AD_Client_ID=c.AD_Client_ID AND cpc.IsDefault='Y')" + + " LEFT OUTER JOIN AD_PrintFont cpf ON (cpf.AD_Client_ID=c.AD_Client_ID AND cpf.IsDefault='Y')" + + " LEFT OUTER JOIN AD_PrintPaper cpp ON (cpp.AD_Client_ID=c.AD_Client_ID AND cpp.IsDefault='Y')," + + " AD_PrintColor pc, AD_PrintFont pf, AD_PrintPaper pp " + + "WHERE t.AD_Table_ID=? AND c.AD_Client_ID=?" // #1/2 + + " AND pc.IsDefault='Y' AND pf.IsDefault='Y' AND pp.IsDefault='Y'"; + boolean error = true; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_Table_ID); + pstmt.setInt(2, AD_Client_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + // Name + String TableName = rs.getString(1); + String ColumnName = TableName + "_ID"; + String s = ColumnName; + if (!ColumnName.equals("T_Report_ID")) + { + s = Msg.translate (ctx, ColumnName); + if (ColumnName.equals (s)) // not found + s = Msg.translate (ctx, TableName); + } + int count = rs.getInt(2); + if (count > 0) + s += "_" + (count+1); + pf.setName(s); + // + pf.setAD_PrintColor_ID(rs.getInt(3)); + pf.setAD_PrintFont_ID(rs.getInt(4)); + pf.setAD_PrintPaper_ID(rs.getInt(5)); + // + error = false; + } + else + s_log.log(Level.SEVERE, "No info found " + AD_Table_ID); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, sql, e); + } + if (error) + return null; + + // Save & complete + if (!pf.save()) + return null; + // pf.dump(); + pf.setItems (createItems(ctx, pf)); + // + return pf; + } // createFromTable + + /** + * Create MPrintFormat for ReportView + * @param ctx context + * @param AD_ReportView_ID ReportView + * @param ReportName - optional Report Name + * @return print format + */ + static public MPrintFormat createFromReportView (Properties ctx, int AD_ReportView_ID, String ReportName) + { + int AD_Client_ID = Env.getAD_Client_ID(ctx); + s_log.info ("AD_ReportView_ID=" + AD_ReportView_ID + " - AD_Client_ID=" + AD_Client_ID + " - " + ReportName); + + MPrintFormat pf = new MPrintFormat(ctx, 0, null); + pf.setAD_ReportView_ID (AD_ReportView_ID); + + // Get Info + String sql = "SELECT t.TableName," + + " (SELECT COUNT(*) FROM AD_PrintFormat x WHERE x.AD_ReportView_ID=rv.AD_ReportView_ID AND x.AD_Client_ID=c.AD_Client_ID) AS Count," + + " COALESCE (cpc.AD_PrintColor_ID, pc.AD_PrintColor_ID) AS AD_PrintColor_ID," + + " COALESCE (cpf.AD_PrintFont_ID, pf.AD_PrintFont_ID) AS AD_PrintFont_ID," + + " COALESCE (cpp.AD_PrintPaper_ID, pp.AD_PrintPaper_ID) AS AD_PrintPaper_ID," + + " t.AD_Table_ID " + + "FROM AD_ReportView rv" + + " INNER JOIN AD_Table t ON (rv.AD_Table_ID=t.AD_Table_ID)," + + " AD_Client c" + + " LEFT OUTER JOIN AD_PrintColor cpc ON (cpc.AD_Client_ID=c.AD_Client_ID AND cpc.IsDefault='Y')" + + " LEFT OUTER JOIN AD_PrintFont cpf ON (cpf.AD_Client_ID=c.AD_Client_ID AND cpf.IsDefault='Y')" + + " LEFT OUTER JOIN AD_PrintPaper cpp ON (cpp.AD_Client_ID=c.AD_Client_ID AND cpp.IsDefault='Y')," + + " AD_PrintColor pc, AD_PrintFont pf, AD_PrintPaper pp " + + "WHERE rv.AD_ReportView_ID=? AND c.AD_Client_ID=?" + + " AND pc.IsDefault='Y' AND pf.IsDefault='Y' AND pp.IsDefault='Y'"; + boolean error = true; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_ReportView_ID); + pstmt.setInt(2, AD_Client_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + // Name + String name = ReportName; + if (name == null || name.length() == 0) + name = rs.getString(1); // TableName + int count = rs.getInt(2); + if (count > 0) + name += "_" + count; + pf.setName(name); + // + pf.setAD_PrintColor_ID(rs.getInt(3)); + pf.setAD_PrintFont_ID(rs.getInt(4)); + pf.setAD_PrintPaper_ID(rs.getInt(5)); + // + pf.setAD_Table_ID (rs.getInt(6)); + error = false; + } + else + s_log.log(Level.SEVERE, "Not found: AD_ReportView_ID=" + AD_ReportView_ID); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, sql, e); + } + if (error) + return null; + + // Save & complete + if (!pf.save()) + return null; + // pf.dump(); + pf.setItems (createItems(ctx, pf)); + // + return pf; + } // createFromReportView + + + /** + * Create Items. + * Using the display order of Fields in some Tab + * @param ctx context + * @param format print format + * @return items + */ + static private MPrintFormatItem[] createItems (Properties ctx, MPrintFormat format) + { + s_log.fine ("From window Tab ..."); + ArrayList list = new ArrayList(); + // Get Column List from Tab + String sql = "SELECT AD_Column_ID " //, Name, IsDisplayed, SeqNo + + "FROM AD_Field " + + "WHERE AD_Tab_ID=(SELECT AD_Tab_ID FROM AD_Tab WHERE AD_Table_ID=? AND ROWNUM=1)" + + " AND IsEncrypted='N' AND ObscureType IS NULL " + + "ORDER BY COALESCE(IsDisplayed,'N') DESC, SortNo, SeqNo, Name"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, format.get_TrxName()); + pstmt.setInt(1, format.getAD_Table_ID()); + ResultSet rs = pstmt.executeQuery(); + int seqNo = 1; + while (rs.next()) + { + MPrintFormatItem pfi = MPrintFormatItem.createFromColumn (format, rs.getInt(1), seqNo++); + if (pfi != null) + { + list.add (pfi); + s_log.finest("Tab: " + pfi); + } + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, "(tab) - " + sql, e); + } + // No Tab found for Table + if (list.size() == 0) + { + s_log.fine("From Table ..."); + sql = "SELECT AD_Column_ID " + + "FROM AD_Column " + + "WHERE AD_Table_ID=? " + + "ORDER BY IsIdentifier DESC, SeqNo, Name"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, format.get_TrxName()); + pstmt.setInt(1, format.getAD_Table_ID()); + ResultSet rs = pstmt.executeQuery(); + int seqNo = 1; + while (rs.next()) + { + MPrintFormatItem pfi = MPrintFormatItem.createFromColumn (format, rs.getInt(1), seqNo++); + if (pfi != null) + { + list.add (pfi); + s_log.finest("Table: " + pfi); + } + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, "(table) - " + sql, e); + } + } + + // + MPrintFormatItem[] retValue = new MPrintFormatItem[list.size()]; + list.toArray(retValue); + s_log.info(format + " - #" + retValue.length); + return retValue; + } // createItems + + /** + * Copy Items + * @param fromFormat from print format + * @param toFormat to print format (client, id) + * @return items + */ + static private MPrintFormatItem[] copyItems (MPrintFormat fromFormat, MPrintFormat toFormat) + { + s_log.info("From=" + fromFormat); + ArrayList list = new ArrayList(); + + MPrintFormatItem[] items = fromFormat.getItems(); + for (int i = 0; i < items.length; i++) + { + MPrintFormatItem pfi = items[i].copyToClient (toFormat.getAD_Client_ID(), toFormat.get_ID()); + if (pfi != null) + list.add (pfi); + } + // + MPrintFormatItem[] retValue = new MPrintFormatItem[list.size()]; + list.toArray(retValue); + copyTranslationItems (items, retValue); // JTP fix + return retValue; + } // copyItems + + /** + * Copy translation records (from - to) + * @param fromItems from items + * @param toItems to items + */ + static private void copyTranslationItems (MPrintFormatItem[] fromItems, + MPrintFormatItem[] toItems) + { + if (fromItems == null || toItems == null) + return; // should not happen + + int counter = 0; + for (int i = 0; i < fromItems.length; i++) + { + int fromID = fromItems[i].getAD_PrintFormatItem_ID(); + int toID = toItems[i].getAD_PrintFormatItem_ID(); + + StringBuffer sql = new StringBuffer("UPDATE AD_PrintFormatItem_Trl new ") + // Set + .append("SET (PrintName, PrintNameSuffix, IsTranslated) = ") + .append("(") + .append("SELECT PrintName, PrintNameSuffix, IsTranslated ") + .append("FROM AD_PrintFormatItem_Trl old ") + .append("WHERE old.AD_Language=new.AD_Language") + .append(" AND AD_PrintFormatItem_ID =").append(fromID) + .append(") ") + // WHERE + .append("WHERE AD_PrintFormatItem_ID=").append(toID) + .append(" AND EXISTS (SELECT AD_PrintFormatItem_ID ") + .append(" FROM AD_PrintFormatItem_trl old") + .append(" WHERE old.AD_Language=new.AD_Language") + .append(" AND AD_PrintFormatItem_ID =").append(fromID) + .append(")"); + int no = DB.executeUpdate(sql.toString(), null); + if (no == 0) // if first has no translation, the rest does neither + break; + counter += no; + } // for + s_log.finest("#" + counter); + } // copyTranslationItems + + + /************************************************************************** + * Copy existing Definition To Client + * @param ctx context + * @param from_AD_PrintFormat_ID format + * @param to_AD_PrintFormat_ID format + * @return print format + */ + public static MPrintFormat copy (Properties ctx, + int from_AD_PrintFormat_ID, int to_AD_PrintFormat_ID) + { + return copy (ctx, from_AD_PrintFormat_ID, to_AD_PrintFormat_ID, -1); + } // copy + + /** + * Copy existing Definition To Client + * @param ctx context + * @param AD_PrintFormat_ID format + * @param to_Client_ID to client + * @return print format + */ + public static MPrintFormat copyToClient (Properties ctx, + int AD_PrintFormat_ID, int to_Client_ID) + { + return copy (ctx, AD_PrintFormat_ID, 0, to_Client_ID); + } // copy + + /** + * Copy existing Definition To Client + * @param ctx context + * @param from_AD_PrintFormat_ID format + * @param to_AD_PrintFormat_ID to format or 0 for new + * @param to_Client_ID to client (ignored, if to_AD_PrintFormat_ID <> 0) + * @return print format + */ + private static MPrintFormat copy (Properties ctx, int from_AD_PrintFormat_ID, + int to_AD_PrintFormat_ID, int to_Client_ID) + { + s_log.info ("From AD_PrintFormat_ID=" + from_AD_PrintFormat_ID + + ", To AD_PrintFormat_ID=" + to_AD_PrintFormat_ID + + ", To Client_ID=" + to_Client_ID); + if (from_AD_PrintFormat_ID == 0) + throw new IllegalArgumentException ("From_AD_PrintFormat_ID is 0"); + // + MPrintFormat from = new MPrintFormat(ctx, from_AD_PrintFormat_ID, null); + MPrintFormat to = new MPrintFormat (ctx, to_AD_PrintFormat_ID, null); // could be 0 + MPrintFormat.copyValues (from, to); + // New + if (to_AD_PrintFormat_ID == 0) + { + if (to_Client_ID < 0) + to_Client_ID = Env.getAD_Client_ID(ctx); + to.setClientOrg (to_Client_ID, 0); + } + // Set Name - Remove TEMPLATE - add copy + to.setName(Util.replace(to.getName(), "TEMPLATE", String.valueOf(to_Client_ID))); + to.setName(to.getName() + + " " + Msg.getMsg(ctx, "Copy") + + " " + to.hashCode()); // unique name + // + to.save(); + + // Copy Items + to.setItems(copyItems(from,to)); + return to; + } // copyToClient + + /*************************************************************************/ + + /** Cached Formats */ + static private CCache s_formats = new CCache("AD_PrintFormat", 30); + + /** + * Get Format + * @param ctx context + * @param AD_PrintFormat_ID id + * @param readFromDisk refresh from disk + * @return Format + */ + static public MPrintFormat get (Properties ctx, int AD_PrintFormat_ID, boolean readFromDisk) + { + Integer key = new Integer(AD_PrintFormat_ID); + MPrintFormat pf = null; + if (!readFromDisk) + pf = (MPrintFormat)s_formats.get(key); + if (pf == null) + { + pf = new MPrintFormat (ctx, AD_PrintFormat_ID, null); + s_formats.put(key, pf); + } + return pf; + } // get + + /** + * Get (default) Printformat for Report View or Table + * @param ctx context + * @param AD_ReportView_ID id or 0 + * @param AD_Table_ID id or 0 + * @return first print format found or null + */ + static public MPrintFormat get (Properties ctx, int AD_ReportView_ID, int AD_Table_ID) + { + MPrintFormat retValue = null; + PreparedStatement pstmt = null; + String sql = "SELECT * FROM AD_PrintFormat WHERE "; + if (AD_ReportView_ID > 0) + sql += "AD_ReportView_ID=?"; + else + sql += "AD_Table_ID=?"; + sql += " ORDER BY IsDefault DESC"; + try + { + pstmt = DB.prepareStatement (sql, null); + pstmt.setInt (1, AD_ReportView_ID > 0 ? AD_ReportView_ID : AD_Table_ID); + ResultSet rs = pstmt.executeQuery (); + if (rs.next ()) + retValue = new MPrintFormat (ctx, rs, null); + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + s_log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + return retValue; + } // get + + /** + * Delete Format from Cache + * @param AD_PrintFormat_ID id + */ + static public void deleteFromCache (int AD_PrintFormat_ID) + { + Integer key = new Integer(AD_PrintFormat_ID); + s_formats.put(key, null); + } // deleteFromCache + + + /************************************************************************** + * Test + * @param args arga + */ + static public void main (String[] args) + { + org.compiere.Adempiere.startup(true); + /** + MPrintFormat.createFromTable(Env.getCtx(), 496); // Order + MPrintFormat.createFromTable(Env.getCtx(), 497); + MPrintFormat.createFromTable(Env.getCtx(), 516); // Invoice + MPrintFormat.createFromTable(Env.getCtx(), 495); + MPrintFormat.createFromTable(Env.getCtx(), 500); // Shipment + MPrintFormat.createFromTable(Env.getCtx(), 501); + + MPrintFormat.createFromTable(Env.getCtx(), 498); // Check + MPrintFormat.createFromTable(Env.getCtx(), 499); + MPrintFormat.createFromTable(Env.getCtx(), 498); // Remittance + **/ + } // main + + +} // MPrintFormat diff --git a/print/src/org/compiere/print/MPrintFormatItem.java b/print/src/org/compiere/print/MPrintFormatItem.java new file mode 100644 index 0000000000..5b3f47cddc --- /dev/null +++ b/print/src/org/compiere/print/MPrintFormatItem.java @@ -0,0 +1,596 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Print Format Item Model. + * Caches Column Name + * (Add missing Items with PrintFormatUtil) + * + * @author Jorg Janke + * @version $Id: MPrintFormatItem.java,v 1.3 2006/08/03 22:17:17 jjanke Exp $ + */ +public class MPrintFormatItem extends X_AD_PrintFormatItem +{ + /** + * Constructor + * @param ctx context + * @param AD_PrintFormatItem_ID AD_PrintFormatItem_ID + * @param trxName transaction + */ + public MPrintFormatItem (Properties ctx, int AD_PrintFormatItem_ID, String trxName) + { + super (ctx, AD_PrintFormatItem_ID, trxName); + // Default Setting + if (AD_PrintFormatItem_ID == 0) + { + setFieldAlignmentType(FIELDALIGNMENTTYPE_Default); + setLineAlignmentType(LINEALIGNMENTTYPE_None); + setPrintFormatType(PRINTFORMATTYPE_Text); + setPrintAreaType(PRINTAREATYPE_Content); + setShapeType(SHAPETYPE_NormalRectangle); + // + setIsCentrallyMaintained(true); + setIsRelativePosition(true); + setIsNextLine(false); + setIsNextPage(false); + setIsSetNLPosition(false); + setIsFilledRectangle(false); + setIsImageField(false); + setXSpace(0); + setYSpace(0); + setXPosition(0); + setYPosition(0); + setMaxWidth(0); + setIsFixedWidth(false); + setIsHeightOneLine(false); + setMaxHeight(0); + setLineWidth(1); + setArcDiameter(0); + // + setIsOrderBy(false); + setSortNo(0); + setIsGroupBy(false); + setIsPageBreak(false); + setIsSummarized(false); + setIsAveraged(false); + setIsCounted(false); + setIsMinCalc(false); + setIsMaxCalc(false); + setIsVarianceCalc(false); + setIsDeviationCalc(false); + setIsRunningTotal(false); + setImageIsAttached(false); + setIsSuppressNull(false); + } + } // MPrintFormatItem + + /** + * Constructor + * @param ctx context + * @param rs ResultSet + * @param trxName transaction + */ + public MPrintFormatItem (Properties ctx, ResultSet rs, String trxName) + { + super(ctx, rs, trxName); + } // MPrintFormatItem + + /** Locally cached column name */ + private String m_columnName = null; + /** Locally cached label translations */ + private HashMap m_translationLabel; + /** Locally cached suffix translations */ + private HashMap m_translationSuffix; + + private static CLogger s_log = CLogger.getCLogger (MPrintFormatItem.class); + + + /************************************************************************** + * Get print name with language + * @param language language - ignored if IsMultiLingualDocument not 'Y' + * @return print name + */ + public String getPrintName (Language language) + { + if (language == null || Env.isBaseLanguage(language, "AD_PrintFormatItem")) + return getPrintName(); + loadTranslations(); + String retValue = (String)m_translationLabel.get(language.getAD_Language()); + if (retValue == null || retValue.length() == 0) + return getPrintName(); + return retValue; + } // getPrintName + + /** + * Get print name suffix with language + * @param language language - ignored if IsMultiLingualDocument not 'Y' + * @return print name suffix + */ + public String getPrintNameSuffix (Language language) + { + if (language == null || Env.isBaseLanguage(language, "AD_PrintFormatItem")) + return getPrintNameSuffix(); + loadTranslations(); + String retValue = (String)m_translationSuffix.get(language.getAD_Language()); + if (retValue == null || retValue.length() == 0) + return getPrintNameSuffix(); + return retValue; + } // getPrintNameSuffix + + /** + * Load Translations + */ + private void loadTranslations() + { + if (m_translationLabel == null) + { + m_translationLabel = new HashMap(); + m_translationSuffix = new HashMap(); + String sql = "SELECT AD_Language, PrintName, PrintNameSuffix FROM AD_PrintFormatItem_Trl WHERE AD_PrintFormatItem_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, get_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + m_translationLabel.put (rs.getString (1), rs.getString (2)); + m_translationSuffix.put (rs.getString (1), rs.getString (3)); + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, "loadTrl", e); + } + } + } // loadTranslations + + + /** + * Type Field + * @return true if field + */ + public boolean isTypeField() + { + return getPrintFormatType().equals(PRINTFORMATTYPE_Field); + } + /** + * Type Text + * @return true if text + */ + public boolean isTypeText() + { + return getPrintFormatType().equals(PRINTFORMATTYPE_Text); + } + /** + * Type Print Format + * @return true if print format + */ + public boolean isTypePrintFormat() + { + return getPrintFormatType().equals(PRINTFORMATTYPE_PrintFormat); + } + /** + * Type Image + * @return true if image + */ + public boolean isTypeImage() + { + return getPrintFormatType().equals(PRINTFORMATTYPE_Image); + } + /** + * Type Box + * @return true if box + */ + public boolean isTypeBox() + { + return getPrintFormatType().equals(PRINTFORMATTYPE_Line) + || getPrintFormatType().equals(PRINTFORMATTYPE_Rectangle); + } + + /** + * Field Center + * @return true if center + */ + public boolean isFieldCenter() + { + return getFieldAlignmentType().equals(FIELDALIGNMENTTYPE_Center); + } + /** + * Field Align Leading + * @return true if leading + */ + public boolean isFieldAlignLeading() + { + return getFieldAlignmentType().equals(FIELDALIGNMENTTYPE_LeadingLeft); + } + /** + * Field Align Trailing + * @return true if trailing + */ + public boolean isFieldAlignTrailing() + { + return getFieldAlignmentType().equals(FIELDALIGNMENTTYPE_TrailingRight); + } + /** + * Field Align Block + * @return true if block + */ + public boolean isFieldAlignBlock() + { + return getFieldAlignmentType().equals(FIELDALIGNMENTTYPE_Block); + } + /** + * Field Align Default + * @return true if default alignment + */ + public boolean isFieldAlignDefault() + { + return getFieldAlignmentType().equals(FIELDALIGNMENTTYPE_Default); + } + /** + * Line Align Center + * @return true if center + */ + public boolean isLineAlignCenter() + { + return getLineAlignmentType().equals(LINEALIGNMENTTYPE_Center); + } + /** + * Line Align Leading + * @return true if leading + */ + public boolean isLineAlignLeading() + { + return getLineAlignmentType().equals(LINEALIGNMENTTYPE_LeadingLeft); + } + /** + * Line Align Trailing + * @return true if trailing + */ + public boolean isLineAlignTrailing() + { + return getLineAlignmentType().equals(LINEALIGNMENTTYPE_TrailingRight); + } + + /** + * Header + * @return true if area is header + */ + public boolean isHeader() + { + return getPrintAreaType().equals(PRINTAREATYPE_Header); + } + /** + * Content + * @return true if area is centent + */ + public boolean isContent() + { + return getPrintAreaType().equals(PRINTAREATYPE_Content); + } + /** + * Footer + * @return true if area is footer + */ + public boolean isFooter() + { + return getPrintAreaType().equals(PRINTAREATYPE_Footer); + } + + /** + * Barcode + * @return true if barcode selected + */ + public boolean isBarcode() + { + String s = getBarcodeType(); + return s != null && s.length() > 0; + } + + + /************************************************************************** + * String representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("MPrintFormatItem["); + sb.append("ID=").append(get_ID()) + .append(",Name=").append(getName()) + .append(",Print=").append(getPrintName()) + .append(", Seq=").append(getSeqNo()) + .append(",Sort=").append(getSortNo()) + .append(", Area=").append(getPrintAreaType()) + .append(", MaxWidth=").append(getMaxWidth()) + .append(",MaxHeight=").append(getMaxHeight()) + .append(",OneLine=").append(isHeightOneLine()) + .append(", Relative=").append(isRelativePosition()); + if (isRelativePosition()) + sb.append(",X=").append(getXSpace()).append(",Y=").append(getYSpace()) + .append(",LineAlign=").append(getLineAlignmentType()) + .append(",NewLine=").append(isNextLine()) + .append(",NewPage=").append(isPageBreak()); + else + sb.append(",X=").append(getXPosition()).append(",Y=").append(getYPosition()); + sb.append(",FieldAlign=").append(getFieldAlignmentType()); + // + sb.append(", Type=").append(getPrintFormatType()); + if (isTypeText()) + ; + else if (isTypeField()) + sb.append(",AD_Column_ID=").append(getAD_Column_ID()); + else if (isTypePrintFormat()) + sb.append(",AD_PrintFormatChild_ID=").append(getAD_PrintFormatChild_ID()) + .append(",AD_Column_ID=").append(getAD_Column_ID()); + else if (isTypeImage()) + sb.append(",ImageIsAttached=").append(isImageIsAttached()).append(",ImageURL=").append(getImageURL()); + // + sb.append(", Printed=").append(isPrinted()) + .append(",SeqNo=").append(getSeqNo()) + .append(",OrderBy=").append(isOrderBy()) + .append(",SortNo=").append(getSortNo()) + .append(",Summarized=").append(isSummarized()); + sb.append("]"); + return sb.toString(); + } // toString + + + /*************************************************************************/ + + + /** Lookup Map of AD_Column_ID for ColumnName */ + private static CCache s_columns = new CCache("AD_PrintFormatItem", 200); + + /** + * Get ColumnName from AD_Column_ID + * @return ColumnName + */ + public String getColumnName() + { + if (m_columnName == null) // Get Column Name from AD_Column not index + m_columnName = getColumnName (new Integer(getAD_Column_ID())); + return m_columnName; + } // getColumnName + + /** + * Get Column Name from AD_Column_ID. + * Be careful not to confuse it with PO method getAD_Column_ID (index) + * @param AD_Column_ID column + * @return Column Name + */ + private static String getColumnName (Integer AD_Column_ID) + { + if (AD_Column_ID == null || AD_Column_ID.intValue() == 0) + return null; + // + String retValue = (String)s_columns.get(AD_Column_ID); + if (retValue == null) + { + String sql = "SELECT ColumnName FROM AD_Column WHERE AD_Column_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_Column_ID.intValue()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + retValue = rs.getString(1); + s_columns.put(AD_Column_ID, retValue); + } + else + s_log.log(Level.SEVERE, "Not found AD_Column_ID=" + AD_Column_ID); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, "AD_Column_ID=" + AD_Column_ID, e); + } + } + return retValue; + } // getColumnName + + + /************************************************************************** + * Create Print Format Item from Column + * @param format parent + * @param AD_Column_ID column + * @param seqNo sequence of display if 0 it is not printed + * @return Print Format Item + */ + public static MPrintFormatItem createFromColumn (MPrintFormat format, int AD_Column_ID, int seqNo) + { + MPrintFormatItem pfi = new MPrintFormatItem (format.getCtx(), 0, null); + pfi.setAD_PrintFormat_ID (format.getAD_PrintFormat_ID()); + pfi.setClientOrg(format); + pfi.setAD_Column_ID(AD_Column_ID); + pfi.setPrintFormatType(PRINTFORMATTYPE_Field); + + // translation is dome by trigger + String sql = "SELECT c.ColumnName,e.Name,e.PrintName, " // 1..3 + + "c.AD_Reference_ID,c.IsKey,c.SeqNo " // 4..6 + + "FROM AD_Column c, AD_Element e " + + "WHERE c.AD_Column_ID=?" + + " AND c.AD_Element_ID=e.AD_Element_ID"; + // translate base entry if single language - trigger copies to trl tables + Language language = format.getLanguage(); + boolean trl = !Env.isMultiLingualDocument(format.getCtx()) && !language.isBaseLanguage(); + if (trl) + sql = "SELECT c.ColumnName,e.Name,e.PrintName, " // 1..3 + + "c.AD_Reference_ID,c.IsKey,c.SeqNo " // 4..6 + + "FROM AD_Column c, AD_Element_Trl e " + + "WHERE c.AD_Column_ID=?" + + " AND c.AD_Element_ID=e.AD_Element_ID" + + " AND e.AD_Language=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_Column_ID); + if (trl) + pstmt.setString(2, language.getAD_Language()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + String ColumnName = rs.getString(1); + pfi.setName(rs.getString(2)); + pfi.setPrintName(rs.getString(3)); + int displayType = rs.getInt(4); + if (DisplayType.isNumeric(displayType)) + pfi.setFieldAlignmentType(FIELDALIGNMENTTYPE_TrailingRight); + else if (displayType == DisplayType.Text || displayType == DisplayType.Memo ) + pfi.setFieldAlignmentType(FIELDALIGNMENTTYPE_Block); + else + pfi.setFieldAlignmentType(FIELDALIGNMENTTYPE_LeadingLeft); + boolean isKey = "Y".equals(rs.getString(5)); + // + if (isKey + || ColumnName.startsWith("Created") || ColumnName.startsWith("Updated") + || ColumnName.equals("AD_Client_ID") || ColumnName.equals("AD_Org_ID") + || ColumnName.equals("IsActive") + || displayType == DisplayType.Button || displayType == DisplayType.Binary + || displayType == DisplayType.ID || displayType == DisplayType.Image + || displayType == DisplayType.RowID + || seqNo == 0 ) + { + pfi.setIsPrinted(false); + pfi.setSeqNo(0); + } + else + { + pfi.setIsPrinted(true); + pfi.setSeqNo(seqNo); + } + int idSeqNo = rs.getInt(6); // IsIdentifier SortNo + if (idSeqNo > 0) + { + pfi.setIsOrderBy(true); + pfi.setSortNo(idSeqNo); + } + } + else + s_log.log(Level.SEVERE, "Not Found AD_Column_ID=" + AD_Column_ID + + " Trl=" + trl + " " + language.getAD_Language()); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + s_log.log(Level.SEVERE, sql, e); + } + if (!pfi.save()) + return null; + // pfi.dump(); + return pfi; + } // createFromColumn + + /** + * Copy existing Definition To Client + * @param To_Client_ID to client + * @param AD_PrintFormat_ID parent print format + * @return print format item + */ + public MPrintFormatItem copyToClient (int To_Client_ID, int AD_PrintFormat_ID) + { + MPrintFormatItem to = new MPrintFormatItem (p_ctx, 0, null); + MPrintFormatItem.copyValues(this, to); + to.setClientOrg(To_Client_ID, 0); + to.setAD_PrintFormat_ID(AD_PrintFormat_ID); + to.save(); + return to; + } // copyToClient + + + /** + * Before Save + * @param newRecord + * @return true if ok + */ + protected boolean beforeSave (boolean newRecord) + { + // Order + if (!isOrderBy()) + { + setSortNo(0); + setIsGroupBy(false); + setIsPageBreak(false); + } + // Rel Position + if (isRelativePosition()) + { + setXPosition(0); + setYPosition(0); + } + else + { + setXSpace(0); + setYSpace(0); + } + // Image + if (isImageField()) + { + setImageIsAttached(false); + setImageURL(null); + } + return true; + } // beforeSave + + /** + * After Save + * @param newRecord new + * @param success success + * @return success + */ + protected boolean afterSave (boolean newRecord, boolean success) + { + // Set Translation from Element + if (newRecord + // && MClient.get(getCtx()).isMultiLingualDocument() + && getPrintName() != null && getPrintName().length() > 0) + { + String sql = "UPDATE AD_PrintFormatItem_Trl trl " + + "SET PrintName = (SELECT e.PrintName " + + "FROM AD_Element_Trl e, AD_Column c " + + "WHERE e.AD_Language=trl.AD_Language" + + " AND e.AD_Element_ID=c.AD_Element_ID" + + " AND c.AD_Column_ID=" + getAD_Column_ID() + ") " + + "WHERE AD_PrintFormatItem_ID = " + get_ID() + + " AND EXISTS (SELECT * " + + "FROM AD_Element_Trl e, AD_Column c " + + "WHERE e.AD_Language=trl.AD_Language" + + " AND e.AD_Element_ID=c.AD_Element_ID" + + " AND c.AD_Column_ID=" + getAD_Column_ID() + + " AND trl.AD_PrintFormatItem_ID = " + get_ID() + ")" + + " AND EXISTS (SELECT * FROM AD_Client " + + "WHERE AD_Client_ID=trl.AD_Client_ID AND IsMultiLingualDocument='Y')"; + int no = DB.executeUpdate(sql, get_TrxName()); + log.fine("translations updated #" + no); + } + + return success; + } // afterSave + +} // MPrintFormatItem diff --git a/print/src/org/compiere/print/MPrintFormatProcess.java b/print/src/org/compiere/print/MPrintFormatProcess.java new file mode 100644 index 0000000000..08c1dfaec9 --- /dev/null +++ b/print/src/org/compiere/print/MPrintFormatProcess.java @@ -0,0 +1,87 @@ +/****************************************************************************** + * 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; + +import java.math.*; + +import org.compiere.process.*; + +/** + * MPrintFormat Process. + * Performs Copy existing or Create from Table + * Called when pressing the Copy/Create button in Window Print Format + * + * @author Jorg Janke + * @version $Id: MPrintFormatProcess.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintFormatProcess extends SvrProcess +{ + /** PrintFormat */ + private BigDecimal m_AD_PrintFormat_ID; + /** Table */ + private BigDecimal m_AD_Table_ID; + + /** + * Prepare - get Parameters. + */ + protected void prepare() + { + ProcessInfoParameter[] para = getParameter(); + for (int i = 0; i < para.length; i++) + { + String name = para[i].getParameterName(); + if (para[i].getParameter() == null) + ; + else if (name.equals("AD_PrintFormat_ID")) + m_AD_PrintFormat_ID = ((BigDecimal)para[i].getParameter()); + else if (name.equals("AD_Table_ID")) + m_AD_Table_ID = ((BigDecimal)para[i].getParameter()); + else + log.equals("prepare - Unknown Parameter=" + para[i].getParameterName()); + } + } // prepare + + /** + * Perrform process. + *
+	 *  If AD_Table_ID is not null, create from table,
+	 *  otherwise copy from AD_PrintFormat_ID
+	 *  
+ * @return Message + * @throws Exception + */ + protected String doIt() throws Exception + { + if (m_AD_Table_ID != null && m_AD_Table_ID.intValue() > 0) + { + log.info("Create from AD_Table_ID=" + m_AD_Table_ID); + MPrintFormat pf = MPrintFormat.createFromTable(getCtx(), m_AD_Table_ID.intValue(), getRecord_ID()); + addLog(m_AD_Table_ID.intValue(), null, new BigDecimal(pf.getItemCount()), pf.getName()); + return pf.getName() + " #" + pf.getItemCount(); + } + else if (m_AD_PrintFormat_ID != null && m_AD_PrintFormat_ID.intValue() > 0) + { + log.info("Copy from AD_PrintFormat_ID=" + m_AD_PrintFormat_ID); + MPrintFormat pf = MPrintFormat.copy (getCtx(), m_AD_PrintFormat_ID.intValue(), getRecord_ID()); + addLog(m_AD_PrintFormat_ID.intValue(), null, new BigDecimal(pf.getItemCount()), pf.getName()); + return pf.getName() + " #" + pf.getItemCount(); + } + else + throw new Exception (MSG_InvalidArguments); + } // doIt + +} // MPrintFormatProcess diff --git a/print/src/org/compiere/print/MPrintGraph.java b/print/src/org/compiere/print/MPrintGraph.java new file mode 100644 index 0000000000..6ad4e7389e --- /dev/null +++ b/print/src/org/compiere/print/MPrintGraph.java @@ -0,0 +1,54 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; + +import org.compiere.model.*; + +/** + * Graph Model + * + * @author Jorg Janke + * @version $Id: MPrintGraph.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintGraph extends X_AD_PrintGraph +{ + /** + * Standard Constructor + * @param ctx context + * @param AD_PrintGraph_ID graph id + * @param trxName trx + */ + public MPrintGraph (Properties ctx, int AD_PrintGraph_ID, String trxName) + { + super (ctx, AD_PrintGraph_ID, trxName); + } // MPrintGraph + + /** + * Load Constructor + * @param ctx context + * @param rs result set + * @param trxName trx + */ + public MPrintGraph (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MPrintGraph + +} // MPrintGraph diff --git a/print/src/org/compiere/print/MPrintPaper.java b/print/src/org/compiere/print/MPrintPaper.java new file mode 100644 index 0000000000..a2cf05fb98 --- /dev/null +++ b/print/src/org/compiere/print/MPrintPaper.java @@ -0,0 +1,252 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * AD_PrintPaper Print Paper Model + * + * @author Jorg Janke + * @version $Id: MPrintPaper.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintPaper extends X_AD_PrintPaper +{ + /** + * Get Paper + * @param AD_PrintPaper_ID id + * @return Paper + */ + static public MPrintPaper get (int AD_PrintPaper_ID) + { + Integer key = new Integer(AD_PrintPaper_ID); + MPrintPaper pp = (MPrintPaper)s_papers.get(key); + if (pp == null) + { + pp = new MPrintPaper (Env.getCtx(), AD_PrintPaper_ID, null); + s_papers.put(key, pp); + } + else + s_log.config("AD_PrintPaper_ID=" + AD_PrintPaper_ID); + return pp; + } // get + + /** + * Create Paper and save + * @param name name + * @param landscape landscape + * @return Paper + */ + static MPrintPaper create (String name, boolean landscape) + { + MPrintPaper pp = new MPrintPaper (Env.getCtx(), 0, null); + pp.setName(name); + pp.setIsLandscape(landscape); + pp.save(); + return pp; + } // create + + /** Logger */ + private static CLogger s_log = CLogger.getCLogger(MPrintPaper.class); + /** Cached Fonts */ + static private CCache s_papers + = new CCache("AD_PrintPaper", 5); + + + /************************************************************************** + * Constructor + * @param ctx context + * @param AD_PrintPaper_ID ID if 0 A4 + * @param trxName transaction + */ + public MPrintPaper(Properties ctx, int AD_PrintPaper_ID, String trxName) + { + super(ctx, AD_PrintPaper_ID, trxName); + if (AD_PrintPaper_ID == 0) + { + setIsDefault (false); + setIsLandscape (true); + setCode ("iso-a4"); + setMarginTop (36); + setMarginBottom (36); + setMarginLeft (36); + setMarginRight (36); + } + } // MPrintPaper + + /** + * Load Constructor + * @param ctx context + * @param rs result set + * @param trxName trx + */ + public MPrintPaper (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MPrintPaper + + + /** Media Size */ + private MediaSize m_mediaSize = null; + + /************************************************************************** + * Get Media Size. + * The search is hard coded as the javax.print.MediaSize* info is private + * @return MediaSize from Code + */ + public MediaSize getMediaSize() + { + if (m_mediaSize != null) + return m_mediaSize; + // + String nameCode = getCode(); + if (nameCode != null) + { + // Get Name + MediaSizeName nameMedia = null; + CMediaSizeName msn = new CMediaSizeName(4); + String[] names = msn.getStringTable(); + for (int i = 0; i < names.length; i++) + { + String name = names[i]; + if (name.equalsIgnoreCase(nameCode)) + { + nameMedia = (MediaSizeName)msn.getEnumValueTable()[i]; + log.finer("Name=" + nameMedia); + break; + } + } + if (nameMedia != null) + { + m_mediaSize = MediaSize.getMediaSizeForName(nameMedia); + log.fine("Name->Size=" + m_mediaSize); + } + } + // Create New Media Size + if (m_mediaSize == null) + { + float x = getSizeX().floatValue(); + float y = getSizeY().floatValue(); + if (x > 0 && y > 0) + { + m_mediaSize = new MediaSize(x, y, getUnitsInt(), MediaSizeName.A); + log.fine("Size=" + m_mediaSize); + } + } + // Fallback + if (m_mediaSize == null) + m_mediaSize = getMediaSizeDefault(); + return m_mediaSize; + } // getMediaSize + + /** + * Get Media Size + * @return Default Media Size based on Language + */ + public MediaSize getMediaSizeDefault() + { + m_mediaSize = Language.getLoginLanguage().getMediaSize(); + if (m_mediaSize == null) + m_mediaSize = MediaSize.ISO.A4; + log.fine("Size=" + m_mediaSize); + return m_mediaSize; + } // getMediaSizeDefault + + /** + * Get Units Int + * @return units + */ + public int getUnitsInt() + { + String du = getDimensionUnits(); + if (du == null || DIMENSIONUNITS_MM.equals(du)) + return Size2DSyntax.MM; + else + return Size2DSyntax.INCH; + } // getUnits + + /** + * Get CPaper + * @return CPaper + */ + public CPaper getCPaper() + { + CPaper retValue = new CPaper (getMediaSize(), isLandscape(), + getMarginLeft(), getMarginTop(), getMarginRight(), getMarginBottom()); + return retValue; + } // getCPaper + + /** + * Media Size Name + */ + class CMediaSizeName extends MediaSizeName + { + /** + * CMediaSizeName + * @param code + */ + public CMediaSizeName(int code) + { + super (code); + } // CMediaSizeName + + /** + * Get String Table + * @return string + */ + public String[] getStringTable () + { + return super.getStringTable (); + } + + /** + * Get Enum Value Table + * @return Media Sizes + */ + public EnumSyntax[] getEnumValueTable () + { + return super.getEnumValueTable (); + } + } // CMediaSizeName + + /************************************************************************** + * Test + * @param args args + */ + public static void main(String[] args) + { + org.compiere.Adempiere.startupEnvironment(true); + + // create ("Standard Landscape", true); + // create ("Standard Portrait", false); + + // Read All Papers + int[] IDs = PO.getAllIDs ("AD_PrintPaper", null, null); + for (int i = 0; i < IDs.length; i++) + { + System.out.println("--"); + MPrintPaper pp = new MPrintPaper(Env.getCtx(), IDs[i], null); + pp.dump(); + } + + } +} // MPrintPaper diff --git a/print/src/org/compiere/print/MPrintTableFormat.java b/print/src/org/compiere/print/MPrintTableFormat.java new file mode 100644 index 0000000000..54333dcbd9 --- /dev/null +++ b/print/src/org/compiere/print/MPrintTableFormat.java @@ -0,0 +1,597 @@ +/****************************************************************************** + * 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; + +import java.awt.*; +import java.math.*; +import java.sql.*; +import java.util.*; + +import org.compiere.model.*; +import java.util.logging.*; +import org.compiere.util.*; + +/** + * Table Print Format + * + * @author Jorg Janke + * @version $Id: MPrintTableFormat.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class MPrintTableFormat extends X_AD_PrintTableFormat +{ + /** + * Standard Constructor + * @param ctx context + * @param AD_PrintTableFormat_ID table format + * @param trxName transaction + */ + public MPrintTableFormat (Properties ctx, int AD_PrintTableFormat_ID, String trxName) + { + super (ctx, AD_PrintTableFormat_ID, trxName); + if (AD_PrintTableFormat_ID == 0) + { + // setName (null); + setIsDefault (false); + setIsPaintHeaderLines (true); // Y + setIsPaintBoundaryLines (false); + setIsPaintHLines (false); + setIsPaintVLines (false); + setIsPrintFunctionSymbols (true); + } + } // MPrintTableFormat + + /** + * Load Constructor + * @param ctx context + * @param rs result set + * @param trxName transaction + */ + public MPrintTableFormat (Properties ctx, ResultSet rs, String trxName) + { + super(ctx, rs, trxName); + } // MPrintTableFormat + + /*************************************************************************/ + + private Font standard_Font = new Font(null); + + private Font pageHeader_Font; + private Font pageFooter_Font; + private Color pageHeaderFG_Color; + private Color pageHeaderBG_Color; + private Color pageFooterFG_Color; + private Color pageFooterBG_Color; + + private Font parameter_Font; + private Color parameter_Color; + + private Font header_Font; + private Color headerFG_Color; + private Color headerBG_Color; + private Color hdrLine_Color; + private Stroke header_Stroke; // - + + private Font funct_Font; + private Color functFG_Color; + private Color functBG_Color; + + private Color lineH_Color; + private Color lineV_Color; + private Stroke lineH_Stroke; // - + private Stroke lineV_Stroke; // | + // + + /************************************************************************** + * Set Standard Font to derive other fonts if not defined + * @param standardFont standard font + */ + public void setStandard_Font(Font standardFont) + { + if (standardFont != null) + standard_Font = standardFont; + } // setStandard_Font + + /** + * Get Stndard Font + * @return stndard font + */ + public Font getStandard_Font() + { + return standard_Font; + } // getStandard_Font + + + /************************************************************************** + * Get Table Header Font + * @return table header font or Bold standard font + */ + public Font getHeader_Font() + { + if (header_Font != null) + return header_Font; + int i = getHdr_PrintFont_ID(); + if (i != 0) + header_Font = MPrintFont.get(i).getFont(); + if (header_Font == null) + header_Font = new Font (standard_Font.getName(), Font.BOLD, standard_Font.getSize()); + return header_Font; + } // getHeader_Font + + /** + * Get Header Foreground + * @return color or blue black + */ + public Color getHeaderFG_Color() + { + if (headerFG_Color != null) + return headerFG_Color; + int i = getHdrTextFG_PrintColor_ID(); + if (i != 0) + headerFG_Color = MPrintColor.get(getCtx(), i).getColor(); + if (headerFG_Color == null) + headerFG_Color = MPrintColor.blackBlue; + return headerFG_Color; + } // getHeaderFG_Color + + /** + * Get Header BG Color + * @return color or cyan + */ + public Color getHeaderBG_Color() + { + if (headerBG_Color != null) + return headerBG_Color; + int i = getHdrTextBG_PrintColor_ID(); + if (i != 0) + headerBG_Color = MPrintColor.get(getCtx(), i).getColor(); + if (headerBG_Color == null) + headerBG_Color = Color.cyan; + return headerBG_Color; + } // getHeaderBG_Color + + /** + * Get Header Line Color + * @return color or blue black + */ + public Color getHeaderLine_Color() + { + if (hdrLine_Color != null) + return hdrLine_Color; + int i = getHdrLine_PrintColor_ID(); + if (i != 0) + hdrLine_Color = MPrintColor.get(getCtx(), i).getColor(); + if (hdrLine_Color == null) + hdrLine_Color = MPrintColor.blackBlue; + return hdrLine_Color; + } // getHeaderLine_Color + + /** + * Get Header Stroke + * @return Header Stroke (default solid 2pt) + */ + public Stroke getHeader_Stroke() + { + if (header_Stroke == null) + { + float width = getHdrStroke().floatValue(); + if (getHdrStrokeType() == null || HDRSTROKETYPE_SolidLine.equals(getHdrStrokeType())) + header_Stroke = new BasicStroke(width); // - + // + else if (HDRSTROKETYPE_DashedLine.equals(getHdrStrokeType())) + header_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDashed(width), 0.0f); // - - + else if (HDRSTROKETYPE_DottedLine.equals(getHdrStrokeType())) + header_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDotted(width), 0.0f); // . . . + else if (HDRSTROKETYPE_Dash_DottedLine.equals(getHdrStrokeType())) + header_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDash_Dotted(width), 0.0f); // - . - + // default / fallback + if (header_Stroke == null) + header_Stroke = new BasicStroke(width); // - + } + return header_Stroke; + } // getHeader_Stroke + + /** + * Get Header Stroke for horizontal Lines + * @return stroke in pt (default 2) + */ + public BigDecimal getHdrStroke() + { + BigDecimal retValue = super.getHdrStroke(); + if (retValue == null || Env.ZERO.compareTo(retValue) <= 0) + retValue = new BigDecimal (2.0); + return retValue; + } // getHdrStroke + + + + /************************************************************************** + * Get Function Font + * @return function font or BoldItalic standard font + */ + public Font getFunct_Font() + { + if (funct_Font != null) + return funct_Font; + int i = getFunct_PrintFont_ID(); + if (i != 0) + funct_Font = MPrintFont.get(i).getFont(); + if (funct_Font == null) + funct_Font = new Font (standard_Font.getName(), Font.BOLD|Font.ITALIC, standard_Font.getSize()); + return funct_Font; + } // getFunct_Font + + /** + * Get Function BG Color + * @return color or white + */ + public Color getFunctBG_Color() + { + if (functBG_Color != null) + return functBG_Color; + int i = getFunctBG_PrintColor_ID(); + if (i != 0) + functBG_Color = MPrintColor.get(getCtx(), i).getColor(); + if (functBG_Color == null) + functBG_Color = Color.white; + return functBG_Color; + } // getFunctBG_Color + + /** + * Get Function FG Color + * @return color or green dark + */ + public Color getFunctFG_Color() + { + if (functFG_Color != null) + return functFG_Color; + int i = getFunctFG_PrintColor_ID(); + if (i != 0) + functFG_Color = MPrintColor.get(getCtx(), i).getColor(); + if (functFG_Color == null) + functFG_Color = MPrintColor.darkGreen; + return functFG_Color; + } // getFunctFG_Color + + + /************************************************************************** + * Get Parameter Font + * @return Italic standard font + */ + public Font getParameter_Font() + { + if (parameter_Font == null) + parameter_Font = new Font (standard_Font.getName(), Font.ITALIC, standard_Font.getSize()); + return parameter_Font; + } // getParameter_Font + + /** + * Get Parameter Color + * @return dark gray + */ + public Color getParameter_Color() + { + if (parameter_Color == null) + parameter_Color = Color.darkGray; + return parameter_Color; + } // getParameter_Color + + + /************************************************************************** + * Get Top Page Header Font + * @return Bold standard font + */ + public Font getPageHeader_Font() + { + if (pageHeader_Font == null) + pageHeader_Font = new Font (standard_Font.getName(), Font.BOLD, standard_Font.getSize()); + return pageHeader_Font; + } // getPageHeader_Font + + /** + * Get Page Header FG_Color + * @return color or blue black + */ + public Color getPageHeaderFG_Color() + { + if (pageHeaderFG_Color == null) + pageHeaderFG_Color = MPrintColor.blackBlue; + return pageHeaderFG_Color; + } // getPageHeaderFG_Color + + /** + * Get Page Header BG_Color + * @return color or white + */ + public Color getPageHeaderBG_Color() + { + if (pageHeaderBG_Color == null) + pageHeaderBG_Color = Color.white; + return pageHeaderBG_Color; + } // getPageHeaderBG_Color + + /** + * Get Page Footer Font + * @return 2pt smaller standard font + */ + public Font getPageFooter_Font() + { + if (pageFooter_Font == null) + pageFooter_Font = new Font (standard_Font.getName(), Font.PLAIN, standard_Font.getSize()-2); + return pageFooter_Font; + } // getPageFooter_Font + + /** + * Get PageFooter FG_Color + * @return blue black + */ + public Color getPageFooterFG_Color() + { + if (pageFooterFG_Color == null) + pageFooterFG_Color = MPrintColor.blackBlue; + return pageFooterFG_Color; + } // getPageFooterFG_Color + + /** + * Get Page Footer BG_Color + * @return white + */ + public Color getPageFooterBG_Color() + { + if (pageFooterBG_Color == null) + pageFooterBG_Color = Color.white; + return pageFooterBG_Color; + } // getPageFooterBG_Color + + + /************************************************************************** + * Get Horizontal Line Color. + * (one db attribute for line color) + * @return color or gray light + */ + public Color getHLine_Color() + { + if (lineH_Color != null) + return lineH_Color; + int i = getLine_PrintColor_ID(); + if (i != 0) + lineH_Color = MPrintColor.get(getCtx(), i).getColor(); + if (lineH_Color == null) + lineH_Color = Color.lightGray; + return lineH_Color; + } // getHLine_Color + + /** + * Get Verical Line Color. + * (one db attribute for line color) + * @return color or gray light + */ + public Color getVLine_Color() + { + if (lineV_Color != null) + return lineV_Color; + int i = getLine_PrintColor_ID(); + if (i != 0) + lineV_Color = MPrintColor.get(getCtx(), i).getColor(); + if (lineV_Color == null) + lineV_Color = Color.lightGray; + return lineV_Color; + } // getVLine_Color + + + /** + * Get Horizontal Line Stroke - + * (same DB line column) + * @return solid line baded on line width (default solid 1p) + */ + public Stroke getHLine_Stroke() + { + if (lineH_Stroke == null) + { + float width = getLineStroke().floatValue() / 2; + if (getHdrStrokeType() == null || LINESTROKETYPE_DottedLine.equals(getLineStrokeType())) + lineH_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDotted(width), 0.0f); // . . . + // + else if (LINESTROKETYPE_SolidLine.equals(getLineStrokeType())) + lineH_Stroke = new BasicStroke(width); // - + else if (LINESTROKETYPE_DashedLine.equals(getLineStrokeType())) + lineH_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDashed(width), 0.0f); // - - + else if (LINESTROKETYPE_Dash_DottedLine.equals(getLineStrokeType())) + lineH_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDash_Dotted(width), 0.0f); // - . - + // default / fallback + if (lineH_Stroke == null) + lineH_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDotted(width), 0.0f); // . . . + } + return lineH_Stroke; + } // getHLine_Stroke + + /** + * Get Vertical Line Stroke | + * (same DB line column) + * @return line based on line (1/2 of) width and stroke (default dotted 1/2p + */ + public Stroke getVLine_Stroke() + { + if (lineV_Stroke == null) + { + float width = getLineStroke().floatValue() / 2; + if (getHdrStrokeType() == null || LINESTROKETYPE_DottedLine.equals(getLineStrokeType())) + lineV_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDotted(width), 0.0f); // . . . + // + else if (LINESTROKETYPE_SolidLine.equals(getLineStrokeType())) + lineV_Stroke = new BasicStroke(width); // - + else if (LINESTROKETYPE_DashedLine.equals(getLineStrokeType())) + lineV_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDashed(width), 0.0f); // - - + else if (LINESTROKETYPE_Dash_DottedLine.equals(getLineStrokeType())) + lineV_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDash_Dotted(width), 0.0f); // - . - + // default / fallback + if (lineV_Stroke == null) + lineV_Stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, + 1.0f, getPatternDotted(width), 0.0f); // . . . + } + return lineV_Stroke; + } // getVLine_Stroke + + /** + * Get Horizontal Stroke for Lines - + * @return stroke in pt (default 1) + */ + public BigDecimal getLineStroke() + { + BigDecimal retValue = super.getLineStroke(); + if (retValue == null || Env.ZERO.compareTo(retValue) <= 0) + retValue = new BigDecimal (1.0); + return retValue; + } // getLineStroke + + /** + * Get Vertical Stroke for Lines | + * @return stroke in pt (default 1) + */ + public BigDecimal getVLineStroke() + { + BigDecimal retValue = super.getLineStroke(); + if (retValue == null || Env.ZERO.compareTo(retValue) <= 0) + retValue = new BigDecimal (1.0); + return retValue; + } // getVLineStroke + + /** + * Get Pattern Dotted . . . . + * @param width width of line + * @return pattern + */ + private float[] getPatternDotted (float width) + { + return new float[] {2*width, 2*width}; + } // getPatternDotted + + /** + * Get Pattern Dashed - - - - + * @param width width of line + * @return pattern + */ + private float[] getPatternDashed (float width) + { + return new float[] {10*width, 4*width}; + } // getPatternDashed + + /** + * Get Pattern Dash Dotted - . - . + * @param width width of line + * @return pattern + */ + private float[] getPatternDash_Dotted (float width) + { + return new float[] {10*width, 2*width, 2*width, 2*width}; + } // getPatternDash_Dotted + + + /*************************************************************************/ + + private static CCache s_cache + = new CCache("AD_PrintTableFormat", 3); + /** Static Logger */ + private static CLogger s_log = CLogger.getCLogger(MPrintTableFormat.class); + + /** + * Get Table Format. + * @param ctx context + * @param AD_PrintTableFormat_ID table format + * @param standard_font standard font + * @return Table Format + */ + static public MPrintTableFormat get (Properties ctx, int AD_PrintTableFormat_ID, Font standard_font) + { + Integer ii = new Integer (AD_PrintTableFormat_ID); + MPrintTableFormat tf = (MPrintTableFormat)s_cache.get(ii); + if (tf == null) + { + if (AD_PrintTableFormat_ID == 0) + tf = getDefault (ctx); + else + tf = new MPrintTableFormat (ctx, AD_PrintTableFormat_ID, null); + s_cache.put(ii, tf); + } + tf.setStandard_Font(standard_font); + return tf; + } // get + + /** + * Get Table Format + * @param ctx context + * @param AD_PrintTableFormat_ID table format + * @param AD_PrintFont_ID standard font + * @return Table Format + */ + static public MPrintTableFormat get (Properties ctx, int AD_PrintTableFormat_ID, int AD_PrintFont_ID) + { + return get (ctx, AD_PrintTableFormat_ID, MPrintFont.get (AD_PrintFont_ID).getFont()); + } // get + + /** + * Get Default Table Format. + * @param ctx context + * @return Default Table Format (need to set standard font) + */ + static public MPrintTableFormat getDefault (Properties ctx) + { + MPrintTableFormat tf = null; + String sql = "SELECT * FROM AD_PrintTableFormat " + + "WHERE AD_Client_ID IN (0,?) AND IsActive='Y' " + + "ORDER BY IsDefault DESC, AD_Client_ID DESC"; + int AD_Client_ID = Env.getAD_Client_ID(ctx); + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_Client_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + tf = new MPrintTableFormat (ctx, rs, null); + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + s_log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + return tf; + } // get + + +} // MPrintTableFormat diff --git a/print/src/org/compiere/print/PrintData.java b/print/src/org/compiere/print/PrintData.java new file mode 100644 index 0000000000..9e7ab5dc4a --- /dev/null +++ b/print/src/org/compiere/print/PrintData.java @@ -0,0 +1,776 @@ +/****************************************************************************** + * 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; + +import java.io.*; +import java.util.*; +import java.util.logging.*; +import javax.xml.parsers.*; +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; +import org.compiere.*; +import org.compiere.util.*; +import org.w3c.dom.*; + +/** + * Print Data Structure. + * Created by DataEngine + * A Structure has rows, wich contain elements. + * Elements can be end nodes (PrintDataElements) or data structures (PrintData). + * The row data is sparse - i.e. null if not existing. + * A Structure has optional meta info about content (PrintDataColumn). + * + * @author Jorg Janke + * @version $Id: PrintData.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintData implements Serializable +{ + /** + * Data Parent Constructor + * @param ctx context + * @param name data element name + */ + public PrintData (Properties ctx, String name) + { + if (name == null) + throw new IllegalArgumentException("Name cannot be null"); + m_ctx = ctx; + m_name = name; + } // PrintData + + /** + * Data Parent Constructor + * @param ctx context + * @param name data element name + * @param nodes ArrayList with nodes (content not checked) + */ + public PrintData (Properties ctx, String name, ArrayList nodes) + { + if (name == null) + throw new IllegalArgumentException("Name cannot be null"); + m_ctx = ctx; + m_name = name; + if (nodes != null) + m_nodes = nodes; + } // PrintData + + /** Context */ + private Properties m_ctx; + /** Data Structure Name */ + private String m_name; + /** Data Structure rows */ + private ArrayList> m_rows = new ArrayList>(); + /** Current Row Data Structure elements */ + private ArrayList m_nodes = null; + /** Current Row */ + private int m_row = -1; + /** List of Function Rows */ + private ArrayList m_functionRows = new ArrayList(); + + /** Table has LevelNo */ + private boolean m_hasLevelNo = false; + /** Level Number Indicator */ + private static final String LEVEL_NO = "LEVELNO"; + + /** Optional Column Meta Data */ + private PrintDataColumn[] m_columnInfo = null; + /** Optional sql */ + private String m_sql = null; + /** Optional TableName */ + private String m_TableName = null; + + /** XML Element Name */ + public static final String XML_TAG = "adempiereData"; + /** XML Row Name */ + public static final String XML_ROW_TAG = "row"; + /** XML Attribute Name */ + public static final String XML_ATTRIBUTE_NAME = "name"; + /** XML Attribute Count */ + public static final String XML_ATTRIBUTE_COUNT = "count"; + /** XML Attribute Number */ + public static final String XML_ATTRIBUTE_NO = "no"; + /** XML Attribute Function Row */ + public static final String XML_ATTRIBUTE_FUNCTION_ROW = "function_row"; + + /** Logger */ + private static CLogger log = CLogger.getCLogger(PrintData.class); + + /** + * Get Context + * @return context + */ + public Properties getCtx() + { + return m_ctx; + } // getName + + /** + * Get Name + * @return name + */ + public String getName() + { + return m_name; + } // getName + + /*************************************************************************/ + + /** + * Set optional Column Info + * @param newInfo Column Info + */ + public void setColumnInfo (PrintDataColumn[] newInfo) + { + m_columnInfo = newInfo; + } // setColumnInfo + + /** + * Get optional Column Info + * @return Column Info + */ + public PrintDataColumn[] getColumnInfo() + { + return m_columnInfo; + } // getColumnInfo + + /** + * Set SQL (optional) + * @param sql SQL + */ + public void setSQL (String sql) + { + m_sql = sql; + } // setSQL + + /** + * Get optional SQL + * @return SQL + */ + public String getSQL() + { + return m_sql; + } // getSQL + + /** + * Set TableName (optional) + * @param TableName TableName + */ + public void setTableName (String TableName) + { + m_TableName = TableName; + } // setTableName + + /** + * Get optional TableName + * @return TableName + */ + public String getTableName() + { + return m_TableName; + } // getTableName + + /** + * String representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("PrintData["); + sb.append(m_name).append(",Rows=").append(m_rows.size()); + if (m_TableName != null) + sb.append(",TableName=").append(m_TableName); + sb.append("]"); + return sb.toString(); + } // toString + + + + /************************************************************************** + * Returns true if no Nodes in row + * @return true if no Nodes in row + */ + public boolean isEmpty() + { + if (m_nodes == null) + return true; + return m_nodes.size() == 0; + } // isEmpty + + /** + * Return Number of nodes in row + * @return number of nodes in row + */ + public int getNodeCount() + { + if (m_nodes == null) + return 0; + return m_nodes.size(); + } // getNodeCount + + + /************************************************************************** + * Add Row + * @param functionRow true if function row + * @param levelNo Line detail Level Number 0=Normal + */ + public void addRow (boolean functionRow, int levelNo) + { + m_nodes = new ArrayList(); + m_row = m_rows.size(); + m_rows.add (m_nodes); + if (functionRow) + m_functionRows.add(new Integer(m_row)); + if (m_hasLevelNo && levelNo != 0) + addNode(new PrintDataElement(LEVEL_NO, new Integer(levelNo), DisplayType.Integer)); + } // addRow + + /** + * Set Row Index + * @param row row index + * @return true if success + */ + public boolean setRowIndex (int row) + { + if (row < 0 || row >= m_rows.size()) + return false; + m_row = row; + m_nodes = (ArrayList)m_rows.get(m_row); + return true; + } + + /** + * Set Row Index to next + * @return true if success + */ + public boolean setRowNext() + { + return setRowIndex(m_row+1); + } // setRowNext + + /** + * Get Row Count + * @return row count + */ + public int getRowCount() + { + return m_rows.size(); + } // getRowCount + + /** + * Get Current Row Index + * @return row index + */ + public int getRowIndex() + { + return m_row; + } // getRowIndex + + /** + * Is the Row a Function Row + * @param row row no + * @return true if function row + */ + public boolean isFunctionRow (int row) + { + return m_functionRows.contains(new Integer(row)); + } // isFunctionRow + + /** + * Is the current Row a Function Row + * @return true if function row + */ + public boolean isFunctionRow () + { + return m_functionRows.contains(new Integer(m_row)); + } // isFunctionRow + + /** + * Is the current Row a Function Row + * @return true if function row + */ + public boolean isPageBreak () + { + // page break requires function and meta data + if (isFunctionRow() && m_nodes != null) + { + for (int i = 0; i < m_nodes.size(); i++) + { + Object o = m_nodes.get(i); + if (o instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)o; + if (pde.isPageBreak()) + return true; + } + } + } + return false; + } // isPageBreak + + /** + * PrintData has Level No + * @param hasLevelNo true if sql contains LevelNo + */ + public void setHasLevelNo (boolean hasLevelNo) + { + m_hasLevelNo = hasLevelNo; + } // hasLevelNo + + /** + * PrintData has Level No + * @return true if sql contains LevelNo + */ + public boolean hasLevelNo() + { + return m_hasLevelNo; + } // hasLevelNo + + /** + * Get Line Level Number for current row + * @return line level no 0 = default + */ + public int getLineLevelNo () + { + if (m_nodes == null || !m_hasLevelNo) + return 0; + + for (int i = 0; i < m_nodes.size(); i++) + { + Object o = m_nodes.get (i); + if (o instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)o; + if (LEVEL_NO.equals (pde.getColumnName())) + { + Integer ii = (Integer)pde.getValue(); + return ii.intValue(); + } + } + } + return 0; + } // getLineLevel + + /*************************************************************************/ + + /** + * Add Parent node to Data Structure row + * @param parent parent + */ + public void addNode (PrintData parent) + { + if (parent == null) + throw new IllegalArgumentException("Parent cannot be null"); + if (m_nodes == null) + addRow(false, 0); + m_nodes.add (parent); + } // addNode + + /** + * Add node to Data Structure row + * @param node node + */ + public void addNode (PrintDataElement node) + { + if (node == null) + throw new IllegalArgumentException("Node cannot be null"); + if (m_nodes == null) + addRow(false, 0); + m_nodes.add (node); + } // addNode + + /** + * Get Node with index in row + * @param index index + * @return PrintData(Element) of index or null + */ + public Object getNode (int index) + { + if (m_nodes == null || index < 0 || index >= m_nodes.size()) + return null; + return m_nodes.get(index); + } // getNode + + /** + * Get Node with Name in row + * @param name name + * @return PrintData(Element) with Name or null + */ + public Object getNode (String name) + { + int index = getIndex (name); + if (index < 0) + return null; + return m_nodes.get(index); + } // getNode + + /** + * Get Node with AD_Column_ID in row + * @param AD_Column_ID AD_Column_ID + * @return PrintData(Element) with AD_Column_ID or null + */ + public Object getNode (Integer AD_Column_ID) + { + int index = getIndex (AD_Column_ID.intValue()); + if (index < 0) + return null; + return m_nodes.get(index); + } // getNode + + /** + * Get Primary Key in row + * @return PK or null + */ + public PrintDataElement getPKey() + { + if (m_nodes == null) + return null; + for (int i = 0; i < m_nodes.size(); i++) + { + Object o = m_nodes.get(i); + if (o instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)o; + if (pde.isPKey()) + return pde; + } + } + return null; + } // getPKey + + /** + * Get Index of Node in Structure (not recursing) row + * @param columnName name + * @return index or -1 + */ + public int getIndex (String columnName) + { + if (m_nodes == null) + return -1; + for (int i = 0; i < m_nodes.size(); i++) + { + Object o = m_nodes.get(i); + if (o instanceof PrintDataElement) + { + if (columnName.equals(((PrintDataElement)o).getColumnName())) + return i; + } + else if (o instanceof PrintData) + { + if (columnName.equals(((PrintData)o).getName())) + return i; + } + else + log.log(Level.SEVERE, "Element not PrintData(Element) " + o.getClass().getName()); + } + // As Data is stored sparse, there might be lots of NULL values + // log.log(Level.SEVERE, "PrintData.getIndex - Element not found - " + name); + return -1; + } // getIndex + + /** + * Get Index of Node in Structure (not recursing) row + * @param AD_Column_ID AD_Column_ID + * @return index or -1 + */ + public int getIndex (int AD_Column_ID) + { + if (m_columnInfo == null) + return -1; + for (int i = 0; i < m_columnInfo.length; i++) + { + if (m_columnInfo[i].getAD_Column_ID() == AD_Column_ID) + return getIndex(m_columnInfo[i].getColumnName()); + } + log.log(Level.SEVERE, "Column not found - AD_Column_ID=" + AD_Column_ID); + if (AD_Column_ID == 0) + Trace.printStack(); + return -1; + } // getIndex + + + /************************************************************************** + * Dump All Data - header and rows + */ + public void dump() + { + dump(this); + } // dump + + /** + * Dump All Data + */ + public void dumpHeader() + { + dumpHeader(this); + } // dumpHeader + + /** + * Dump All Data + */ + public void dumpCurrentRow() + { + dumpRow(this, m_row); + } // dump + + /** + * Dump all PrintData - header and rows + * @param pd print data + */ + private static void dump (PrintData pd) + { + dumpHeader(pd); + for (int i = 0; i < pd.getRowCount(); i++) + dumpRow(pd, i); + } // dump + + /** + * Dump PrintData Header + * @param pd print data + */ + private static void dumpHeader (PrintData pd) + { + log.info(pd.toString()); + if (pd.getColumnInfo() != null) + { + for (int i = 0; i < pd.getColumnInfo().length; i++) + log.config(i + ": " + pd.getColumnInfo()[i]); + } + } // dump + + /** + * Dump Row + * @param pd print data + * @param row row + */ + private static void dumpRow (PrintData pd, int row) + { + log.info("Row #" + row); + if (row < 0 || row >= pd.getRowCount()) + { + log.warning("- invalid -"); + return; + } + pd.setRowIndex(row); + if (pd.getNodeCount() == 0) + { + log.config("- n/a -"); + return; + } + for (int i = 0; i < pd.getNodeCount(); i++) + { + Object obj = pd.getNode(i); + if (obj == null) + log.config("- NULL -"); + else if (obj instanceof PrintData) + { + log.config("- included -"); + dump((PrintData)obj); + } + else if (obj instanceof PrintDataElement) + { + log.config(((PrintDataElement)obj).toStringX()); + } + else + log.config("- INVALID: " + obj); + } + } // dumpRow + + + /************************************************************************** + * Get XML Document representation + * @return XML document + */ + public Document getDocument() + { + Document document = null; + try + { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + // System.out.println(factory.getClass().getName()); + DocumentBuilder builder = factory.newDocumentBuilder(); + document = builder.newDocument(); + document.appendChild(document.createComment(Adempiere.getSummaryAscii())); + } + catch (Exception e) + { + System.err.println(e); + e.printStackTrace(); + } + // Root + Element root = document.createElement(PrintData.XML_TAG); + root.setAttribute(XML_ATTRIBUTE_NAME, getName()); + root.setAttribute(XML_ATTRIBUTE_COUNT, String.valueOf(getRowCount())); + document.appendChild(root); + processXML (this, document, root); + return document; + } // getDocument + + /** + * Process PrintData Tree + * @param pd Print Data + * @param document document + * @param root element to add to + */ + private static void processXML (PrintData pd, Document document, Element root) + { + for (int r = 0; r < pd.getRowCount(); r++) + { + pd.setRowIndex(r); + Element row = document.createElement(PrintData.XML_ROW_TAG); + row.setAttribute(XML_ATTRIBUTE_NO, String.valueOf(r)); + if (pd.isFunctionRow()) + row.setAttribute(XML_ATTRIBUTE_FUNCTION_ROW, "yes"); + root.appendChild(row); + // + for (int i = 0; i < pd.getNodeCount(); i++) + { + Object o = pd.getNode(i); + if (o instanceof PrintData) + { + PrintData pd_x = (PrintData)o; + Element element = document.createElement(PrintData.XML_TAG); + element.setAttribute(XML_ATTRIBUTE_NAME, pd_x.getName()); + element.setAttribute(XML_ATTRIBUTE_COUNT, String.valueOf(pd_x.getRowCount())); + row.appendChild(element); + processXML (pd_x, document, element); // recursive call + } + else if (o instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)o; + if (!pde.isNull()) + { + Element element = document.createElement(PrintDataElement.XML_TAG); + element.setAttribute(PrintDataElement.XML_ATTRIBUTE_NAME, pde.getColumnName()); + if (pde.hasKey()) + element.setAttribute(PrintDataElement.XML_ATTRIBUTE_KEY, pde.getValueKey()); + element.appendChild(document.createTextNode(pde.getValueDisplay(null))); // not formatted + row.appendChild(element); + } + } + else + log.log(Level.SEVERE, "Element not PrintData(Element) " + o.getClass().getName()); + } // columns + } // rows + } // processTree + + + /** + * Create XML representation to StreamResult + * @param result StreamResult + * @return true if success + */ + public boolean createXML (StreamResult result) + { + try + { + DOMSource source = new DOMSource(getDocument()); + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer transformer = tFactory.newTransformer(); + transformer.transform (source, result); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(StreamResult)", e); + return false; + } + return true; + } // createXML + + /** + * Create XML representation to File + * @param fileName file name + * @return true if success + */ + public boolean createXML (String fileName) + { + try + { + File file = new File(fileName); + file.createNewFile(); + StreamResult result = new StreamResult(file); + createXML (result); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(file)", e); + return false; + } + return true; + } // createXMLFile + + + /************************************************************************** + * Create PrintData from XML + * @param ctx context + * @param input InputSource + * @return PrintData + */ + public static PrintData parseXML (Properties ctx, File input) + { + log.config(input.toString()); + PrintData pd = null; + try + { + PrintDataHandler handler = new PrintDataHandler(ctx); + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser parser = factory.newSAXParser(); + parser.parse(input, handler); + pd = handler.getPrintData(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "", e); + } + return pd; + } // parseXML + + + /************************************************************************** + * Test + * @param args test + */ + public static void main(String[] args) + { + PrintData pd = new PrintData(new Properties(), "test1"); + pd.addNode(new PrintDataElement("test1element1","testvalue<1>",0)); + pd.addNode(new PrintDataElement("test1element2","testvalue&2&",0)); + + PrintData pdx = new PrintData(new Properties(), "test2"); + pdx.addNode(new PrintDataElement("test2element1-1","testvalue11",0)); + pdx.addNode(new PrintDataElement("test2element1-2","testvalue12",0)); + pdx.addRow(false, 0); + pdx.addNode(new PrintDataElement("test2element2-1","testvalue21",0)); + pdx.addNode(new PrintDataElement("test2element2-2","testvalue22",0)); + + pd.addNode(pdx); + pd.addNode(new PrintDataElement("test1element3","testvalue/3/",0)); + + pd.createXML("C:\\Temp\\printData.xml"); + pd.createXML(new StreamResult(System.out)); + System.out.println(""); + pd.dump(); + + // parse + System.out.println(""); + PrintData pd1 = parseXML (new Properties(), new File("C:\\Temp\\printData.xml")); + pd1.createXML(new StreamResult(System.out)); + System.out.println(""); + pd1.dump(); + } // main + +} // PrintData diff --git a/print/src/org/compiere/print/PrintDataColumn.java b/print/src/org/compiere/print/PrintDataColumn.java new file mode 100644 index 0000000000..40d38735dd --- /dev/null +++ b/print/src/org/compiere/print/PrintDataColumn.java @@ -0,0 +1,137 @@ +/****************************************************************************** + * 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; + +//import java.util.logging.*; + +/** + * Print Data Column. + * Optional Meta Data of Columns + * + * @author Jorg Janke + * @version $Id: PrintDataColumn.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintDataColumn +{ + /** + * Print Data Column + * + * @param AD_Column_ID Column + * @param columnName Column Name + * @param displayType Display Type + * @param columnSize Column Size + * @param alias Alias in query or the same as column name or null + * @param isPageBreak if true force page break after function + */ + public PrintDataColumn (int AD_Column_ID, String columnName, + int displayType, int columnSize, + String alias, boolean isPageBreak) + { + m_AD_Column_ID = AD_Column_ID; + m_columnName = columnName; + // + m_displayType = displayType; + m_columnSize = columnSize; + // + m_alias = alias; + if (m_alias == null) + m_alias = columnName; + m_pageBreak = isPageBreak; + } // PrintDataColumn + + private int m_AD_Column_ID; + private String m_columnName; + private int m_displayType; + private int m_columnSize; + private String m_alias; + private boolean m_pageBreak; + + /*************************************************************************/ + + /** + * Get AD_Column_ID + * @return AD_Column_ID + */ + public int getAD_Column_ID() + { + return m_AD_Column_ID; + } // getAD_Column_ID + + /** + * Get Column Name + * @return column name + */ + public String getColumnName() + { + return m_columnName; + } // getColumnName + + /** + * Get Display Type + * @return display type + */ + public int getDisplayType() + { + return m_displayType; + } // getDisplayType + + /** + * Get Alias Name + * @return alias column name + */ + public String getAlias() + { + return m_alias; + } // getAlias + + /** + * Column has Alias. + * (i.e. has a key) + * @return true if Alias + */ + public boolean hasAlias() + { + return !m_columnName.equals(m_alias); + } // hasAlias + + /** + * Column value forces page break + * @return true if page break + */ + public boolean isPageBreak() + { + return m_pageBreak; + } // isPageBreak + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("PrintDataColumn["); + sb.append("ID=").append(m_AD_Column_ID) + .append("-").append(m_columnName); + if (hasAlias()) + sb.append("(").append(m_alias).append(")"); + sb.append(",DisplayType=").append(m_displayType) + .append(",Size=").append(m_columnSize) + .append("]"); + return sb.toString(); + } // toString + +} // PrintDataColumn diff --git a/print/src/org/compiere/print/PrintDataElement.java b/print/src/org/compiere/print/PrintDataElement.java new file mode 100644 index 0000000000..40dbc2a4ab --- /dev/null +++ b/print/src/org/compiere/print/PrintDataElement.java @@ -0,0 +1,383 @@ +/****************************************************************************** + * 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; + +import java.math.*; +import java.sql.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Print Data Element + * + * @author Jorg Janke + * @version $Id: PrintDataElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintDataElement +{ + /** + * Print Data Element Constructor + * @param columnName name + * @param value display value + * @param displayType optional displayType + * @param isPKey is primary key + * @param isPageBreak if true force page break + */ + public PrintDataElement (String columnName, Object value, int displayType, boolean isPKey, boolean isPageBreak) + { + if (columnName == null) + throw new IllegalArgumentException("PrintDataElement - Name cannot be null"); + m_columnName = columnName; + m_value = value; + m_displayType = displayType; + m_isPKey = isPKey; + m_isPageBreak = isPageBreak; + } // PrintDataElement + + /** + * Print Data Element Constructor + * @param columnName name + * @param value display value + * @param displayType optional displayType + */ + public PrintDataElement(String columnName, Object value, int displayType) + { + this (columnName, value, displayType, false, false); + } // PrintDataElement + + /** Data Name */ + private String m_columnName; + /** Data Value */ + private Object m_value; + /** Display Type */ + private int m_displayType; + /** Is Primary Key */ + private boolean m_isPKey; + /** Is Page Break */ + private boolean m_isPageBreak; + + + /** XML Element Name */ + public static final String XML_TAG = "element"; + /** XML Attribute Name */ + public static final String XML_ATTRIBUTE_NAME = "name"; + /** XML Attribute Key */ + public static final String XML_ATTRIBUTE_KEY = "key"; + + + /** + * Get Name + * @return name + */ + public String getColumnName() + { + return m_columnName; + } // getName + + /** + * Get Node Value + * @return value + */ + public Object getValue() + { + return m_value; + } // getValue + + /** + * Get Function Value + * @return length or numeric value + */ + public BigDecimal getFunctionValue() + { + if (m_value == null) + return Env.ZERO; + + // Numbers - return number value + if (m_value instanceof BigDecimal) + return (BigDecimal)m_value; + if (m_value instanceof Number) + return new BigDecimal(((Number)m_value).doubleValue()); + + // Boolean - return 1 for true 0 for false + if (m_value instanceof Boolean) + { + if (((Boolean)m_value).booleanValue()) + return Env.ONE; + else + return Env.ZERO; + } + + // Return Length + String s = m_value.toString(); + return new BigDecimal(s.length()); + } // getFunctionValue + + /** + * Get Node Value Display + * @param language optional language - if null nubers/dates are not formatted + * @return display value optionally formatted + */ + public String getValueDisplay (Language language) + { + if (m_value == null) + return ""; + String retValue = m_value.toString(); + if (m_displayType == DisplayType.Location) + return getValueDisplay_Location(); + else if (m_columnName.equals("C_BPartner_Location_ID") || m_columnName.equals("Bill_Location_ID")) + return getValueDisplay_BPLocation(); + else if (m_displayType == 0 || m_value instanceof String || m_value instanceof NamePair) + ; + else if (language != null) // Optional formatting of Numbers and Dates + { + if (DisplayType.isNumeric(m_displayType)) + retValue = DisplayType.getNumberFormat(m_displayType, language).format(m_value); + else if (DisplayType.isDate(m_displayType)) + retValue = DisplayType.getDateFormat(m_displayType, language).format(m_value); + } + return retValue; + } // getValueDisplay + + /** + * Get Node Data Value as String + * @return data value + */ + public String getValueAsString() + { + if (m_value == null) + return ""; + String retValue = m_value.toString(); + if (m_value instanceof NamePair) + retValue = ((NamePair)m_value).getID(); + return retValue; + } // getValueDisplay + + /** + * Return Address String not just name + * @return Address String + */ + private String getValueDisplay_BPLocation () + { + try + { + int C_BPartner_Location_ID = Integer.parseInt (getValueKey ()); + if (C_BPartner_Location_ID != 0) + { + MLocation loc = MLocation.getBPLocation(Env.getCtx(), C_BPartner_Location_ID, null); + if (loc != null) + return loc.toStringCR(); + } + } + catch (Exception ex) + { + } + return m_value.toString(); + } // getValueDisplay_BPLocation + + + /** + * Return Address String not just City + * @return Address String + */ + private String getValueDisplay_Location () + { + try + { + int C_Location_ID = Integer.parseInt (getValueKey ()); + if (C_Location_ID != 0) + { + MLocation loc = new MLocation (Env.getCtx(), C_Location_ID, null); + if (loc != null) + return loc.toStringCR(); + } + } + catch (Exception ex) + { + } + return m_value.toString(); + } // getValueDisplay_Location + + + /** + * Get Node Value Key + * @return key + */ + public String getValueKey() + { + if (m_value == null) + return ""; + if (m_value instanceof NamePair) + return ((NamePair)m_value).getID(); + return ""; + } // getValueKey + + /** + * Is Value Null + * @return true if value is null + */ + public boolean isNull() + { + return m_value == null; + } // isNull + + /*************************************************************************/ + + /** + * Get Display Type + * @return Display Type + */ + public int getDisplayType() + { + return m_displayType; + } // getDisplayType + + /** + * Is Value numeric + * @return true if value is a numeric + */ + public boolean isNumeric() + { + if (m_displayType == 0) + return m_value instanceof BigDecimal; + return DisplayType.isNumeric(m_displayType); + } // isNumeric + + /** + * Is Value a date + * @return true if value is a date + */ + public boolean isDate() + { + if (m_displayType == 0) + return m_value instanceof Timestamp; + return DisplayType.isDate(m_displayType); + } // isDate + + /** + * Is Value an ID + * @return true if value is an ID + */ + public boolean isID() + { + return DisplayType.isID(m_displayType); + } // isID + + /** + * Is Value boolean + * @return true if value is a boolean + */ + public boolean isYesNo() + { + if (m_displayType == 0) + return m_value instanceof Boolean; + return DisplayType.YesNo == m_displayType; + } // isYesNo + + /** + * Is Value the primary key of row + * @return true if value is the PK + */ + public boolean isPKey() + { + return m_isPKey; + } // isPKey + + /** + * Column value forces page break + * @return true if page break + */ + public boolean isPageBreak() + { + return m_isPageBreak; + } // isPageBreak + + /*************************************************************************/ + + /** + * HashCode + * @return hash code + */ + public int hashCode() + { + if (m_value == null) + return m_columnName.hashCode(); + return m_columnName.hashCode() + m_value.hashCode(); + } // hashCode + + /** + * Equals + * @param compare compare object + * @return true if equals + */ + public boolean equals (Object compare) + { + if (compare instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)compare; + if (pde.getColumnName().equals(m_columnName)) + { + if (pde.getValue() != null && pde.getValue().equals(m_value)) + return true; + if (pde.getValue() == null && m_value == null) + return true; + } + } + return false; + } // equals + + /** + * String representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer(m_columnName).append("=").append(m_value); + if (m_isPKey) + sb.append("(PK)"); + return sb.toString(); + } // toString + + /** + * Value Has Key + * @return true if value has a key + */ + public boolean hasKey() + { + return m_value instanceof NamePair; + } // hasKey + + /** + * String representation with key info + * @return info + */ + public String toStringX() + { + if (m_value instanceof NamePair) + { + NamePair pp = (NamePair)m_value; + StringBuffer sb = new StringBuffer(m_columnName); + sb.append("(").append(pp.getID()).append(")") + .append("=").append(pp.getName()); + if (m_isPKey) + sb.append("(PK)"); + return sb.toString(); + } + else + return toString(); + } // toStringX + +} // PrintDataElement diff --git a/print/src/org/compiere/print/PrintDataFunction.java b/print/src/org/compiere/print/PrintDataFunction.java new file mode 100644 index 0000000000..2130d0713c --- /dev/null +++ b/print/src/org/compiere/print/PrintDataFunction.java @@ -0,0 +1,228 @@ +/****************************************************************************** + * 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; + +import java.math.*; +import org.compiere.util.*; + +/** + * Print Data Function + * + * @author Jorg Janke + * @version $Id: PrintDataFunction.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintDataFunction +{ + /** + * Constructor + */ + public PrintDataFunction () + { + } // PrintDataFunction + + + /** The Sum */ + private BigDecimal m_sum = Env.ZERO; + /** The Count */ + private int m_count = 0; + /** Total Count */ + private int m_totalCount = 0; + /** Minimum */ + private BigDecimal m_min = null; + /** Maximum */ + private BigDecimal m_max = null; + /** Sum of Squares */ + private BigDecimal m_sumSquare = Env.ZERO; + + /** Sum */ + static public final char F_SUM = 'S'; + /** Mean */ + static public final char F_MEAN = 'A'; // Average mu + /** Count */ + static public final char F_COUNT = 'C'; + /** Min */ + static public final char F_MIN = 'm'; + /** Max */ + static public final char F_MAX = 'M'; + /** Variance */ + static public final char F_VARIANCE = 'V'; // sigma square + /** Deviation */ + static public final char F_DEVIATION = 'D'; // sigma + + + /** Function Keys */ + static private final char[] FUNCTIONS = new char[] + {F_SUM, F_MEAN, F_COUNT, F_MIN, F_MAX, F_VARIANCE, F_DEVIATION}; + /** Symbols */ + static private final String[] FUNCTION_SYMBOLS = new String[] + {" \u03A3", " \u03BC", " \u2116", " \u2193", " \u2191", " \u03C3\u00B2", " \u03C3"}; + /** AD_Message Names of Functions */ + static private final String[] FUNCTION_NAMES = new String[] + {"Sum", "Mean", "Count", "Min", "Max", "Variance", "Deviation"}; + + /** + * Add Value to Counter + * @param bd data + */ + public void addValue (BigDecimal bd) + { + if (bd != null) + { + // Sum + m_sum = m_sum.add(bd); + // Count + m_count++; + // Min + if (m_min == null) + m_min = bd; + m_min = m_min.min(bd); + // Max + if (m_max == null) + m_max = bd; + m_max = m_max.max(bd); + // Sum of Squares + m_sumSquare = m_sumSquare.add (bd.multiply(bd)); + } + m_totalCount++; + } // addValue + + /** + * Get Function Value + * @param function function + * @return function value + */ + public BigDecimal getValue(char function) + { + // Sum + if (function == F_SUM) + return m_sum; + // Min/Max + if (function == F_MIN) + return m_min; + if (function == F_MAX) + return m_max; + // Count + BigDecimal count = new BigDecimal(m_count); + if (function == F_COUNT) + return count; + + // All other functions require count > 0 + if (m_count == 0) + return Env.ZERO; + + // Mean = sum/count - round to 4 digits + if (function == F_MEAN) + { + BigDecimal mean = m_sum.divide(count, 4, BigDecimal.ROUND_HALF_UP); + if (mean.scale() > 4) + mean = mean.setScale(4, BigDecimal.ROUND_HALF_UP); + return mean; + } + // Variance = sum of squares - (square of sum / count) + BigDecimal ss = m_sum.multiply(m_sum); + ss = ss.divide(count, 4, BigDecimal.ROUND_HALF_UP); + BigDecimal variance = m_sumSquare.subtract(ss); + if (function == F_VARIANCE) + { + if (variance.scale() > 4) + variance = variance.setScale(4, BigDecimal.ROUND_HALF_UP); + return variance; + } + // Standard Deviation + BigDecimal deviation = new BigDecimal(Math.sqrt(variance.doubleValue())); + if (deviation.scale() > 4) + deviation = deviation.setScale(4, BigDecimal.ROUND_HALF_UP); + return deviation; + } // getValue + + /** + * Reset Value + */ + public void reset() + { + m_count = 0; + m_totalCount = 0; + m_sum = Env.ZERO; + m_sumSquare = Env.ZERO; + m_min = null; + m_max = null; + } // reset + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("[") + .append("Count=").append(m_count).append(",").append(m_totalCount) + .append(",Sum=").append(m_sum) + .append(",SumSquare=").append(m_sumSquare) + .append(",Min=").append(m_min) + .append(",Max=").append(m_max); + sb.append("]"); + return sb.toString(); + } // toString + + /*************************************************************************/ + + /** + * Get Function Symbol of function + * @param function function + * @return function symbol + */ + static public String getFunctionSymbol (char function) + { + for (int i = 0; i < FUNCTIONS.length; i++) + { + if (FUNCTIONS[i] == function) + return FUNCTION_SYMBOLS[i]; + } + return "UnknownFunction=" + function; + } // getFunctionSymbol + + /** + * Get Function Name of function + * @param function function + * @return function name + */ + static public String getFunctionName (char function) + { + for (int i = 0; i < FUNCTIONS.length; i++) + { + if (FUNCTIONS[i] == function) + return FUNCTION_NAMES[i]; + } + return "UnknownFunction=" + function; + } // getFunctionName + + /** + * Get Funcuion Name of function + * @param function function + * @return function name + */ + static public int getFunctionDisplayType (char function) + { + if (function == F_SUM || function == F_MIN || function == F_MAX) + return DisplayType.Amount; + if (function == F_COUNT) + return DisplayType.Integer; + // Mean, Variance, Std. Deviation + return DisplayType.Number; + } // getFunctionName + +} // PrintDataFunction diff --git a/print/src/org/compiere/print/PrintDataGroup.java b/print/src/org/compiere/print/PrintDataGroup.java new file mode 100644 index 0000000000..6ccc04487f --- /dev/null +++ b/print/src/org/compiere/print/PrintDataGroup.java @@ -0,0 +1,311 @@ +/****************************************************************************** + * 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; + +import java.util.*; +import java.math.*; + +/** + * Group By Management + * + * @author Jorg Janke + * @version $Id: PrintDataGroup.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintDataGroup +{ + /** + * Constructor + */ + public PrintDataGroup () + { + } // PrintDataGroup + + /** Column-Function Delimiter */ + static public final String DELIMITER = "~"; + /** Grand Total Indicator */ + static public final String TOTAL = "=TOTAL="; + /** NULL substitute value */ + static private final Object NULL = new String(); + + /** List of group columns */ + private ArrayList m_groups = new ArrayList(); + /** Map of group column & value */ + private HashMap m_groupMap = new HashMap(); + /** List of column_function */ + private ArrayList m_functions = new ArrayList(); + /** Map of group_function column & function */ + private HashMap m_groupFunction = new HashMap(); + + + /************************************************************************** + * Add Group Column + * @param groupColumnName group column + */ + public void addGroupColumn (String groupColumnName) + { + m_groups.add(groupColumnName); + } // addGroup + + /** + * Get Grouyp Column Count. + * TOTAL is included as a column + * @return number of groups + */ + public int getGroupColumnCount() + { + return m_groups.size(); + } // getGroupColumnCount + + /** + * Column has a function + * @param columnName column name or TOTAL + * @return true if column has function + */ + public boolean isGroupColumn (String columnName) + { + if (columnName == null || m_groups.size() == 0) + return false; + for (int i = 0; i < m_groups.size(); i++) + { + if (columnName.equals(m_groups.get(i))) + return true; + } + return false; + } // isGroupColumn + + /** + * Check for Group Change + * @param groupColumnName column name + * @param value column value + * @return null if no group change otherwise old value + */ + public Object groupChange (String groupColumnName, Object value) + { + if (!isGroupColumn(groupColumnName)) + return null; + Object newValue = value; + if (newValue == null) + newValue = NULL; + // + if (m_groupMap.containsKey(groupColumnName)) + { + Object oldValue = m_groupMap.get(groupColumnName); + if (newValue.equals(oldValue)) + return null; + m_groupMap.put(groupColumnName, newValue); + return oldValue; + } + m_groupMap.put(groupColumnName, newValue); + return null; + } // groupChange + + + /************************************************************************** + * Add Function Column + * @param functionColumnName column name + * @param function function + */ + public void addFunction (String functionColumnName, char function) + { + m_functions.add(functionColumnName + DELIMITER + function); + if (!m_groups.contains(TOTAL)) + m_groups.add(TOTAL); + } // addFunction + + /** + * Column has a function + * @param columnName column name + * @return true if column has function + */ + public boolean isFunctionColumn (String columnName) + { + if (columnName == null || m_functions.size() == 0) + return false; + for (int i = 0; i < m_functions.size(); i++) + { + String f = (String)m_functions.get(i); + if (f.startsWith(columnName)) + return true; + } + return false; + } // isFunctionColumn + + /** + * Get calculated functions of column + * @param columnName column name or TOTAL + * @return array of functions + */ + public char[] getFunctions(String columnName) + { + ArrayList list = new ArrayList(); // the final function List + Iterator it = m_groupFunction.keySet().iterator(); + while(it.hasNext()) + { + String group_function = (String)it.next(); // =TOTAL=~LoadSeq + if (group_function.startsWith(columnName)) + { + group_function = group_function.substring(group_function.lastIndexOf(DELIMITER)+1); // LoadSeq + for (int i = 0; i < m_functions.size(); i++) + { + String col_function = ((String)m_functions.get(i)); // LoadSeq~A + if (col_function.startsWith(group_function)) + { + String function = col_function.substring(col_function.lastIndexOf(DELIMITER)+1); + if (!list.contains(function)) + list.add(function); + } + } + } + } + // Return Value + char[] retValue = new char[list.size()]; + for (int i = 0; i < retValue.length; i++) + retValue[i] = ((String)list.get(i)).charAt(0); + // log.finest( "PrintDataGroup.getFunctions for " + columnName + "/" + retValue.length, new String(retValue)); + return retValue; + } // getFunctions + + /** + * Column has a function + * @param columnName column name + * @param function function + * @return true if column has function + */ + public boolean isFunctionColumn (String columnName, char function) + { + if (columnName == null || m_functions.size() == 0) + return false; + String key = columnName + DELIMITER + function; + for (int i = 0; i < m_functions.size(); i++) + { + String f = (String)m_functions.get(i); + if (f.equals(key)) + return true; + } + return false; + } // isFunctionColumn + + + /************************************************************************** + * Add Value to groups + * @param functionColumnName column name + * @param functionValue value + */ + public void addValue (String functionColumnName, BigDecimal functionValue) + { + if (!isFunctionColumn(functionColumnName)) + return; + // Group Breaks + for (int i = 0; i < m_groups.size(); i++) + { + String groupColumnName = (String)m_groups.get(i); + String key = groupColumnName + DELIMITER + functionColumnName; + PrintDataFunction pdf = (PrintDataFunction)m_groupFunction.get(key); + if (pdf == null) + pdf = new PrintDataFunction(); + pdf.addValue(functionValue); + m_groupFunction.put(key, pdf); + } + } // addValue + + /** + * Get Value + * @param groupColumnName group column name (or TOTAL) + * @param functionColumnName function column name + * @param function function + * @return value + */ + public BigDecimal getValue (String groupColumnName, String functionColumnName, + char function) + { + String key = groupColumnName + DELIMITER + functionColumnName; + PrintDataFunction pdf = (PrintDataFunction)m_groupFunction.get(key); + if (pdf == null) + return null; + return pdf.getValue(function); + } // getValue + + /** + * Reset Function values + * @param groupColumnName group column name (or TOTAL) + * @param functionColumnName function column name + */ + public void reset (String groupColumnName, String functionColumnName) + { + String key = groupColumnName + DELIMITER + functionColumnName; + PrintDataFunction pdf = (PrintDataFunction)m_groupFunction.get(key); + if (pdf != null) + pdf.reset(); + } // reset + + /************************************************************************** + * String Representation + * @return info + */ + public String toString () + { + return toString(false); + } // toString + + /** + * String Representation + * @param withData with data + * @return info + */ + public String toString (boolean withData) + { + StringBuffer sb = new StringBuffer("PrintDataGroup["); + sb.append("Groups="); + for (int i = 0; i < m_groups.size(); i++) + { + if (i != 0) + sb.append(","); + sb.append(m_groups.get(i)); + } + if (withData) + { + Iterator it = m_groupMap.keySet().iterator(); + while(it.hasNext()) + { + Object key = it.next(); + Object value = m_groupMap.get(key); + sb.append(":").append(key).append("=").append(value); + } + } + sb.append(";Functions="); + for (int i = 0; i < m_functions.size(); i++) + { + if (i != 0) + sb.append(","); + sb.append(m_functions.get(i)); + } + if (withData) + { + Iterator it = m_groupFunction.keySet().iterator(); + while(it.hasNext()) + { + Object key = it.next(); + Object value = m_groupFunction.get(key); + sb.append(":").append(key).append("=").append(value); + } + } + sb.append("]"); + return sb.toString(); + } // toString + +} // PrintDataGroup + diff --git a/print/src/org/compiere/print/PrintDataHandler.java b/print/src/org/compiere/print/PrintDataHandler.java new file mode 100644 index 0000000000..9f8a8b3a10 --- /dev/null +++ b/print/src/org/compiere/print/PrintDataHandler.java @@ -0,0 +1,165 @@ +/****************************************************************************** + * 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; + +import java.util.*; + +import org.xml.sax.helpers.*; +import org.xml.sax.*; + +/** + * SAX Handler for parsing PrintData + * + * @author Jorg Janke + * @version $Id: PrintDataHandler.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintDataHandler extends DefaultHandler +{ + /** + * Constructor + * @param ctx context + */ + public PrintDataHandler(Properties ctx) + { + m_ctx = ctx; + } // PrintDataHandler + + /** Context */ + private Properties m_ctx = null; + /** Final Structure */ + private PrintData m_pd = null; + + /** Current Active Element Name */ + private String m_curPDEname = null; + /** Current Active Element Value */ + private StringBuffer m_curPDEvalue = null; + /** Current Active Print Data */ + private PrintData m_curPD = null; + + /** + * Get PrintData + * @return PrintData + */ + public PrintData getPrintData() + { + return m_pd; + } // getPrintData + + /*************************************************************************/ + + /** + * Receive notification of the start of an element. + * + * @param uri namespace + * @param localName simple name + * @param qName qualified name + * @param attributes attributes + * @throws org.xml.sax.SAXException + */ + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws org.xml.sax.SAXException + { + if (qName.equals(PrintData.XML_TAG)) + { + String name = attributes.getValue(PrintData.XML_ATTRIBUTE_NAME); + if (m_pd == null) + { + m_pd = new PrintData(m_ctx, name); + push(m_pd); + } + else + { + PrintData temp = new PrintData(m_ctx, name); + m_curPD.addNode(temp); + push(temp); + } + } + else if (qName.equals(PrintData.XML_ROW_TAG)) + { + m_curPD.addRow(false, 0); + } + else if (qName.equals(PrintDataElement.XML_TAG)) + { + m_curPDEname = attributes.getValue(PrintDataElement.XML_ATTRIBUTE_NAME); + m_curPDEvalue = new StringBuffer(); + } + } // startElement + + /** + * Receive notification of character data inside an element. + * + * @param ch buffer + * @param start start + * @param length length + * @throws SAXException + */ + public void characters (char ch[], int start, int length) + throws SAXException + { + m_curPDEvalue.append(ch, start, length); + } // characters + + /** + * Receive notification of the end of an element. + * @param uri namespace + * @param localName simple name + * @param qName qualified name + * @throws SAXException + */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (qName.equals(PrintData.XML_TAG)) + { + pop(); + } + else if (qName.equals(PrintDataElement.XML_TAG)) + { + m_curPD.addNode(new PrintDataElement(m_curPDEname, m_curPDEvalue.toString(),0)); + } + } // endElement + + /*************************************************************************/ + + /** Stack */ + private ArrayList m_stack = new ArrayList(); + + /** + * Push new PD on Stack and set m_cutPD + * @param newPD new PD + */ + private void push (PrintData newPD) + { + // add + m_stack.add(newPD); + m_curPD = newPD; + } // push + + /** + * Pop last PD from Stack and set m_cutPD + */ + private void pop () + { + // remove last + if (m_stack.size() > 0) + m_stack.remove(m_stack.size()-1); + // get previous + if (m_stack.size() > 0) + m_curPD = (PrintData)m_stack.get(m_stack.size()-1); + } // pop + +} // PrintDataHandler diff --git a/print/src/org/compiere/print/PrintFormatUtil.java b/print/src/org/compiere/print/PrintFormatUtil.java new file mode 100644 index 0000000000..65d4a6bf92 --- /dev/null +++ b/print/src/org/compiere/print/PrintFormatUtil.java @@ -0,0 +1,167 @@ +/****************************************************************************** + * 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; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.util.*; + +/** + * Print Format Utilities. + * - Add Missing Columns for all Print Format + * + * @author Jorg Janke + * @version $Id: PrintFormatUtil.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintFormatUtil +{ + /** + * Print Format Utility + * @param ctx context + */ + public PrintFormatUtil(Properties ctx) + { + super(); + m_ctx = ctx; + } // PrintFormatUtil + + /** Logger */ + private CLogger log = CLogger.getCLogger (getClass()); + /** Context */ + private Properties m_ctx; + + + /** + * Add Missing Columns for all Print Format + */ + public void addMissingColumns () + { + int total = 0; + String sql = "SELECT * FROM AD_PrintFormat pf " + + "ORDER BY Name"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, null); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + total += addMissingColumns(new MPrintFormat (m_ctx, rs, null)); + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + log.info ("Total = " + total); + } // addMissingColumns + + + /** + * Add Missing Columns for Print Format + * @param pf print format + * @return no of columns created + */ + public int addMissingColumns (MPrintFormat pf) + { + log.config(pf.toString()); + String sql = "SELECT c.AD_Column_ID, c.ColumnName " + + "FROM AD_Column c " + + "WHERE NOT EXISTS " + + "(SELECT * " + + "FROM AD_PrintFormatItem pfi" + + " INNER JOIN AD_PrintFormat pf ON (pfi.AD_PrintFormat_ID=pf.AD_PrintFormat_ID) " + + "WHERE pf.AD_Table_ID=c.AD_Table_ID" + + " AND pfi.AD_Column_ID=c.AD_Column_ID" + + " AND pfi.AD_PrintFormat_ID=?)" // 1 + + " AND c.AD_Table_ID=? " // 2 + + "ORDER BY 1"; + PreparedStatement pstmt = null; + int counter = 0; + try + { + pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, pf.getAD_PrintFormat_ID()); + pstmt.setInt(2, pf.getAD_Table_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + int AD_Column_ID = rs.getInt(1); + String ColumnName = rs.getString(2); + MPrintFormatItem pfi = MPrintFormatItem.createFromColumn (pf, AD_Column_ID, 0); + if (pfi.get_ID() != 0) + log.fine("#" + ++counter + " - added " + ColumnName); + else + log.warning("Not added: " + ColumnName); + } + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + if (counter == 0) + log.fine("None" + /** + + " - " + sql + + " - AD_PrintFormat_ID=" + pf.getAD_PrintFormat_ID() + + " - AD_Table_ID=" + pf.getAD_Table_ID() + */ + ); + else + log.fine("Added=" + counter); + return counter; + } // addMissingColumns + + + /************************************************************************** + * Main + * @param args arguments + */ + public static void main(String[] args) + { + org.compiere.Adempiere.startupEnvironment(true); + // + PrintFormatUtil pfu = new PrintFormatUtil (Env.getCtx()); + pfu.addMissingColumns(); + } // main + +} // PrintFormatUtils diff --git a/print/src/org/compiere/print/PrintUtil.java b/print/src/org/compiere/print/PrintUtil.java new file mode 100644 index 0000000000..936b1c24f3 --- /dev/null +++ b/print/src/org/compiere/print/PrintUtil.java @@ -0,0 +1,519 @@ +/****************************************************************************** + * 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; + +import java.awt.print.*; +import java.util.*; +import java.util.logging.*; +import javax.print.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; +import javax.swing.*; +import org.compiere.util.*; + +/** + * Print Utilities + * + * @author Jorg Janke + * @version $Id: PrintUtil.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class PrintUtil +{ + /** Logger */ + private static CLogger log = CLogger.getCLogger(PrintUtil.class); + /** Default Print Request Attribute Set */ + private static PrintRequestAttributeSet s_prats = new HashPrintRequestAttributeSet(); + + /** + * Return Default Print Request Attributes + * @return PrintRequestAttributeSet + */ + public static PrintRequestAttributeSet getDefaultPrintRequestAttributes() + { + return s_prats; + } // getDefaultPrintRequestAttributes + + /** + * Get Default Application Flavor + * @return Pageable + */ + public static DocFlavor getDefaultFlavor() + { + return DocFlavor.SERVICE_FORMATTED.PAGEABLE; + } // getDefaultFlavor + + /** + * Get Print Services for standard flavor and pratt + * @return print services + */ + public static PrintService[] getPrintServices () + { + return PrintServiceLookup.lookupPrintServices (getDefaultFlavor(), getDefaultPrintRequestAttributes()); + } // getPrintServices + + /** + * Get Default Print Service + * @return PrintService + */ + public static PrintService getDefaultPrintService() + { + return PrintServiceLookup.lookupDefaultPrintService(); + } // getPrintServices + + + /*************************************************************************/ + + /** + * Print (async) + * @param printerName optional printer name + * @param jobName optional printer job name + * @param pageable pageable + * @param copies number of copies + * @param withDialog if true, shows printer dialog + */ + static public void print (Pageable pageable, String printerName, String jobName, + int copies, boolean withDialog) + { + if (pageable == null) + return; + String name = "Adempiere_"; + if (jobName != null) + name += jobName; + // + PrinterJob job = CPrinter.getPrinterJob(printerName); + job.setJobName (name); + job.setPageable (pageable); + // Attributes + HashPrintRequestAttributeSet prats = new HashPrintRequestAttributeSet(); + prats.add(new Copies(copies)); + // Set Orientation + if (pageable.getPageFormat(0).getOrientation() == PageFormat.PORTRAIT) + prats.add(OrientationRequested.PORTRAIT); + else + prats.add(OrientationRequested.LANDSCAPE); + prats.add(new JobName(name, Language.getLoginLanguage().getLocale())); + prats.add(getJobPriority(pageable.getNumberOfPages(), copies, withDialog)); + // + print (job, prats, withDialog, false); + } // print + + /** + * Print Async + * @param pageable pageable + * @param prats print attribure set + */ + static public void print (Pageable pageable, PrintRequestAttributeSet prats) + { + PrinterJob job = CPrinter.getPrinterJob(); + job.setPageable(pageable); + print (job, prats, true, false); + } // print + + /** + * Print + * @param job printer job + * @param prats print attribure set + * @param withDialog if true shows Dialog + * @param waitForIt if false print async + */ + static public void print (final PrinterJob job, + final PrintRequestAttributeSet prats, + boolean withDialog, boolean waitForIt) + { + if (job == null) + return; + boolean printed = true; + + if (withDialog) + printed = job.printDialog(prats); + + if (printed) + { + if (withDialog) + { + Attribute[] atts = prats.toArray(); + for (int i = 0; i < atts.length; i++) + log.fine(atts[i].getName() + "=" + atts[i]); + } + // + if (waitForIt) + { + log.fine("(wait) " + job.getPrintService()); + try + { + job.print(prats); + } + catch (Exception ex) + { + log.log(Level.SEVERE, "(wait)", ex); + } + } + else // Async + { + // Create Thread + Thread printThread = new Thread() + { + public void run() + { + log.fine("print: " + job.getPrintService()); + try + { + job.print(prats); + } + catch (Exception ex) + { + log.log(Level.SEVERE, "print", ex); + } + } + }; + printThread.start(); + } // Async + } // printed + } // printAsync + + /** + * Get Job Priority based on pages printed. + * The more pages, the lower the priority + * @param pages number of pages + * @param copies number of copies + * @param withDialog dialog gets lower priority than direct print + * @return Job Priority + */ + static public JobPriority getJobPriority (int pages, int copies, boolean withDialog) + { + // Set priority (the more pages, the lower the priority) + int priority = copies * pages; + if (withDialog) // prefer direct print + priority *= 2; + priority = 100 - priority; // convert to 1-100 supported range + if (priority < 10) + priority = 10; + else if (priority > 100) + priority = 100; + return new JobPriority(priority); + } // getJobPriority + + /*************************************************************************/ + + /** + * Dump Printer Job info + * @param job printer job + */ + public static void dump (PrinterJob job) + { + StringBuffer sb = new StringBuffer(job.getJobName()); + sb.append("/").append(job.getUserName()) + .append(" Service=").append(job.getPrintService().getName()) + .append(" Copies=").append(job.getCopies()); + PageFormat pf = job.defaultPage(); + sb.append(" DefaultPage ") + .append("x=").append(pf.getImageableX()) + .append(",y=").append(pf.getImageableY()) + .append(" w=").append(pf.getImageableWidth()) + .append(",h=").append(pf.getImageableHeight()); + System.out.println(sb.toString()); + } // dump + + /** + * Dump Print Service Attribute Set to System.out + * @param psas PS Attribute Set + */ + public static void dump (PrintServiceAttributeSet psas) + { + System.out.println("PrintServiceAttributeSet - length=" + psas.size()); + Attribute[] ats = psas.toArray(); + for (int i = 0; i < ats.length; i++) + System.out.println(ats[i].getName() + " = " + ats[i] + " (" + ats[i].getCategory() + ")"); + } // dump + + /** + * Dump Print Request Service Attribute Set to System.out + * @param prats Print Request Attribute Set + */ + public static void dump (PrintRequestAttributeSet prats) + { + System.out.println("PrintRequestAttributeSet - length=" + prats.size()); + Attribute[] ats = prats.toArray(); + for (int i = 0; i < ats.length; i++) + System.out.println(ats[i].getName() + " = " + ats[i] + " (" + ats[i].getCategory() + ")"); + } // dump + + /** + * Dump Stream Print Services + * @param docFlavor flavor + * @param outputMimeType mime + */ + public static void dump (DocFlavor docFlavor, String outputMimeType) + { + System.out.println(); + System.out.println("DocFlavor=" + docFlavor + ", Output=" + outputMimeType); + StreamPrintServiceFactory[] spsfactories = + StreamPrintServiceFactory.lookupStreamPrintServiceFactories(docFlavor, outputMimeType); + for (int i = 0; i < spsfactories.length; i++) + { + System.out.println("- " + spsfactories[i]); + DocFlavor dfs[] = spsfactories[i].getSupportedDocFlavors(); + for (int j = 0; j < dfs.length; j++) + { + System.out.println(" -> " + dfs[j]); + } + } + } // dump + + /** + * Dump Stream Print Services + * @param docFlavor flavor + */ + public static void dump (DocFlavor docFlavor) + { + System.out.println(); + System.out.println("DocFlavor=" + docFlavor); + PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); + PrintService[] pss = + PrintServiceLookup.lookupPrintServices(docFlavor, pras); + for (int i = 0; i < pss.length; i++) + { + PrintService ps = pss[i]; + System.out.println("- " + ps); + System.out.println(" Factory=" + ps.getServiceUIFactory()); + ServiceUIFactory uiF = pss[i].getServiceUIFactory(); + if (uiF != null) + { + System.out.println("about"); + JDialog about = (JDialog) uiF.getUI (ServiceUIFactory.ABOUT_UIROLE, ServiceUIFactory.JDIALOG_UI); + about.setVisible(true); + System.out.println("admin"); + JDialog admin = (JDialog) uiF.getUI (ServiceUIFactory.ADMIN_UIROLE, ServiceUIFactory.JDIALOG_UI); + admin.setVisible(true); + System.out.println("main"); + JDialog main = (JDialog) uiF.getUI (ServiceUIFactory.MAIN_UIROLE, ServiceUIFactory.JDIALOG_UI); + main.setVisible(true); + System.out.println("reserved"); + JDialog res = (JDialog) uiF.getUI (ServiceUIFactory.RESERVED_UIROLE, ServiceUIFactory.JDIALOG_UI); + res.setVisible(true); + } + // + DocFlavor dfs[] = pss[i].getSupportedDocFlavors(); + System.out.println(" - Supported Doc Flavors"); + for (int j = 0; j < dfs.length; j++) + System.out.println(" -> " + dfs[j]); + // Attribute + Class[] attCat = pss[i].getSupportedAttributeCategories(); + System.out.println(" - Supported Attribute Categories"); + for (int j = 0; j < attCat.length; j++) + System.out.println(" -> " + attCat[j].getName() + + " = " + pss[i].getDefaultAttributeValue((Class)attCat[j])); + // + } + } // dump + + /*************************************************************************/ + + /** + * Test Print Services + */ + private static void testPS() + { + PrintService ps = getDefaultPrintService(); + ServiceUIFactory factory = ps.getServiceUIFactory(); + System.out.println(factory); + if (factory != null) + { + System.out.println("Factory"); + JPanel p0 = (JPanel) factory.getUI(ServiceUIFactory.ABOUT_UIROLE, ServiceUIFactory.JDIALOG_UI); + p0.setVisible(true); + JPanel p1 = (JPanel) factory.getUI(ServiceUIFactory.ADMIN_UIROLE, ServiceUIFactory.JDIALOG_UI); + p1.setVisible(true); + JPanel p2 = (JPanel) factory.getUI(ServiceUIFactory.MAIN_UIROLE, ServiceUIFactory.JDIALOG_UI); + p2.setVisible(true); + + } + System.out.println("1----------"); + PrinterJob pj = PrinterJob.getPrinterJob(); + PrintRequestAttributeSet pratts = getDefaultPrintRequestAttributes(); + // Page Dialog + PageFormat pf = pj.pageDialog(pratts); + System.out.println("Pratts Size = " + pratts.size()); + Attribute[] atts = pratts.toArray(); + for (int i = 0; i < atts.length; i++) + System.out.println(atts[i].getName() + " = " + atts[i] + " - " + atts[i].getCategory()); + System.out.println("PageFormat h=" + pf.getHeight() + ",w=" + pf.getWidth() + " - x=" + pf.getImageableX() + ",y=" + pf.getImageableY() + " - ih=" + pf.getImageableHeight() + ",iw=" + pf.getImageableWidth() + + " - Orient=" + pf.getOrientation()); + ps = pj.getPrintService(); + System.out.println("PrintService = " + ps.getName()); + + // Print Dialog + System.out.println("2----------"); + pj.printDialog(pratts); + System.out.println("Pratts Size = " + pratts.size()); + atts = pratts.toArray(); + for (int i = 0; i < atts.length; i++) + System.out.println(atts[i].getName() + " = " + atts[i] + " - " + atts[i].getCategory()); + pf = pj.defaultPage(); + System.out.println("PageFormat h=" + pf.getHeight() + ",w=" + pf.getWidth() + " - x=" + pf.getImageableX() + ",y=" + pf.getImageableY() + " - ih=" + pf.getImageableHeight() + ",iw=" + pf.getImageableWidth() + + " - Orient=" + pf.getOrientation()); + ps = pj.getPrintService(); + System.out.println("PrintService= " + ps.getName()); + + System.out.println("3----------"); + try + { + pj.setPrintService(ps); + } + catch (PrinterException pe) + { + System.out.println(pe); + } + pf = pj.validatePage(pf); + System.out.println("PageFormat h=" + pf.getHeight() + ",w=" + pf.getWidth() + " - x=" + pf.getImageableX() + ",y=" + pf.getImageableY() + " - ih=" + pf.getImageableHeight() + ",iw=" + pf.getImageableWidth() + + " - Orient=" + pf.getOrientation()); + ps = pj.getPrintService(); + System.out.println("PrintService= " + ps.getName()); + + + System.out.println("4----------"); + pj.printDialog(); + } // testPS + + /** + * Test Stream Print Services + */ + private static void testSPS() + { + // dump (DocFlavor.INPUT_STREAM.GIF, DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType()); + // dump (DocFlavor.SERVICE_FORMATTED.PAGEABLE, DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType()); + // dump (DocFlavor.INPUT_STREAM.GIF, DocFlavor.BYTE_ARRAY.PDF.getMimeType()); + // dump (DocFlavor.SERVICE_FORMATTED.PAGEABLE, DocFlavor.BYTE_ARRAY.GIF.getMediaSubtype()); + // dump (DocFlavor.SERVICE_FORMATTED.PAGEABLE, DocFlavor.BYTE_ARRAY.JPEG.getMediaSubtype()); + + // dump (DocFlavor.SERVICE_FORMATTED.PAGEABLE); // lists devices able to output pageable + // dump (DocFlavor.SERVICE_FORMATTED.PRINTABLE); + // dump (DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST); + // dump (DocFlavor.INPUT_STREAM.POSTSCRIPT); + + + PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); + PrintService[] pss = + PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, pras); + for (int i = 0; i < pss.length; i++) + { + PrintService ps = pss[i]; + String name = ps.getName(); + if (name.indexOf("PDF") != -1 || name.indexOf("Acrobat") != -1) + { + System.out.println("----"); + System.out.println(ps); + Class[] cat = ps.getSupportedAttributeCategories(); + for (int j = 0; j < cat.length; j++) + { + System.out.println("- " + cat[j]); + } + } + } + + // dump (null, DocFlavor.BYTE_ARRAY.PDF.getMimeType()); // lists PDF output + // dump (null, DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMediaType()); // lists PS output + + // dump(null, null); + } // testSPS + + + /************************************************************************** + * Create Print Form & Print Formats for a new Client. + * - Order, Invoice, etc. + * Called from VSetup + * @param AD_Client_ID new Client + */ + public static void setupPrintForm (int AD_Client_ID) + { + log.config("AD_Client_ID=" + AD_Client_ID); + Properties ctx = Env.getCtx(); + CLogMgt.enable(false); + // + // Order Template + int Order_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 100, AD_Client_ID).get_ID(); + int OrderLine_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 101, AD_Client_ID).get_ID(); + updatePrintFormatHeader(Order_PrintFormat_ID, OrderLine_PrintFormat_ID); + // Invoice + int Invoice_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 102, AD_Client_ID).get_ID(); + int InvoiceLine_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 103, AD_Client_ID).get_ID(); + updatePrintFormatHeader(Invoice_PrintFormat_ID, InvoiceLine_PrintFormat_ID); + // Shipment + int Shipment_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 104, AD_Client_ID).get_ID(); + int ShipmentLine_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 105, AD_Client_ID).get_ID(); + updatePrintFormatHeader(Shipment_PrintFormat_ID, ShipmentLine_PrintFormat_ID); + // Check + int Check_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 106, AD_Client_ID).get_ID(); + int RemittanceLine_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 107, AD_Client_ID).get_ID(); + updatePrintFormatHeader(Check_PrintFormat_ID, RemittanceLine_PrintFormat_ID); + // Remittance + int Remittance_PrintFormat_ID = MPrintFormat.copyToClient(ctx, 108, AD_Client_ID).get_ID(); + updatePrintFormatHeader(Remittance_PrintFormat_ID, RemittanceLine_PrintFormat_ID); + + // TODO: MPrintForm + // MPrintForm form = new MPrintForm(); + int AD_PrintForm_ID = DB.getNextID (AD_Client_ID, "AD_PrintForm", null); + String sql = "INSERT INTO AD_PrintForm(AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_PrintForm_ID," + + "Name,Order_PrintFormat_ID,Invoice_PrintFormat_ID,Remittance_PrintFormat_ID,Shipment_PrintFormat_ID)" + // + + " VALUES (" + AD_Client_ID + ",0,'Y',SysDate,0,SysDate,0," + AD_PrintForm_ID + "," + + "'" + Msg.translate(ctx, "Standard") + "'," + + Order_PrintFormat_ID + "," + Invoice_PrintFormat_ID + "," + + Remittance_PrintFormat_ID + "," + Shipment_PrintFormat_ID + ")"; + int no = DB.executeUpdate(sql, null); + if (no != 1) + log.log(Level.SEVERE, "PrintForm NOT inserted"); + // + CLogMgt.enable(true); + } // createDocuments + + /** + * Update the PrintFormat Header lines with Reference to Child Print Format. + * @param Header_ID AD_PrintFormat_ID for Header + * @param Line_ID AD_PrintFormat_ID for Line + */ + static private void updatePrintFormatHeader (int Header_ID, int Line_ID) + { + StringBuffer sb = new StringBuffer(); + sb.append("UPDATE AD_PrintFormatItem SET AD_PrintFormatChild_ID=") + .append(Line_ID) + .append(" WHERE AD_PrintFormatChild_ID IS NOT NULL AND AD_PrintFormat_ID=") + .append(Header_ID); + int no = DB.executeUpdate(sb.toString(), null); + } // updatePrintFormatHeader + + /*************************************************************************/ + + /** + * Test + * @param args arg + */ + public static void main(String[] args) + { + // org.compiere.Adempiere.startupClient(); + // setupPrintForm (11); + // setupPrintForm (1000000); + + + + testPS(); // Print Services + // testSPS(); // Stream Print Services + + // dumpSPS(null, null); + } // main + +} // PrintUtil diff --git a/print/src/org/compiere/print/ReportEngine.java b/print/src/org/compiere/print/ReportEngine.java new file mode 100644 index 0000000000..3b0ad7d224 --- /dev/null +++ b/print/src/org/compiere/print/ReportEngine.java @@ -0,0 +1,1331 @@ +/****************************************************************************** + * 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; + +import java.awt.print.*; +import java.io.*; +import java.net.*; +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import javax.print.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; +import javax.print.event.*; +import javax.xml.transform.stream.*; +import org.apache.ecs.*; +import org.apache.ecs.xhtml.*; +import org.compiere.model.*; +import org.compiere.print.layout.*; +import org.compiere.process.*; +import org.compiere.util.*; +import com.qoppa.pdf.*; + +/** + * Report Engine. + * For a given PrintFormat, + * create a Report + * + * @author Jorg Janke + * @version $Id: ReportEngine.java,v 1.4 2006/10/08 06:52:51 comdivision Exp $ + */ +public class ReportEngine implements PrintServiceAttributeListener +{ + /** + * Constructor + * @param ctx context + * @param pf Print Format + * @param query Optional Query + * @param info print info + */ + public ReportEngine (Properties ctx, MPrintFormat pf, MQuery query, PrintInfo info) + { + if (pf == null) + throw new IllegalArgumentException("ReportEngine - no PrintFormat"); + log.info(pf + " -- " + query); + m_ctx = ctx; + // + m_printFormat = pf; + m_info = info; + setQuery(query); // loads Data + } // ReportEngine + + /** Static Logger */ + private static CLogger log = CLogger.getCLogger (ReportEngine.class); + + /** Context */ + private Properties m_ctx; + + /** Print Format */ + private MPrintFormat m_printFormat; + /** Print Info */ + private PrintInfo m_info; + /** Query */ + private MQuery m_query; + /** Query Data */ + private PrintData m_printData; + /** Layout */ + private LayoutEngine m_layout = null; + /** Printer */ + private String m_printerName = Ini.getProperty(Ini.P_PRINTER); + /** View */ + private View m_view = null; + + /** + * Set PrintFormat. + * If Layout was created, re-create layout + * @param pf print format + */ + protected void setPrintFormat (MPrintFormat pf) + { + m_printFormat = pf; + if (m_layout != null) + { + setPrintData(); + m_layout.setPrintFormat(pf, false); + m_layout.setPrintData(m_printData, m_query, true); // format changes data + } + if (m_view != null) + m_view.revalidate(); + } // setPrintFormat + + /** + * Set Query and generate PrintData. + * If Layout was created, re-create layout + * @param query query + */ + protected void setQuery (MQuery query) + { + m_query = query; + if (query == null) + return; + // + setPrintData(); + if (m_layout != null) + m_layout.setPrintData(m_printData, m_query, true); + if (m_view != null) + m_view.revalidate(); + } // setQuery + + /** + * Get Query + * @return query + */ + public MQuery getQuery() + { + return m_query; + } // getQuery + + /** + * Set PrintData for Format restricted by Query. + * Nothing set if there is no query + * Sets m_printData + */ + private void setPrintData() + { + if (m_query == null) + return; + DataEngine de = new DataEngine(m_printFormat.getLanguage()); + setPrintData(de.getPrintData (m_ctx, m_printFormat, m_query)); + // m_printData.dump(); + } // setPrintData + + /** + * Get PrintData + * @return print data + */ + public PrintData getPrintData() + { + return m_printData; + } // getPrintData + + /** + * Set PrintData + * @param printData printData + */ + public void setPrintData (PrintData printData) + { + if (printData == null) + return; + m_printData = printData; + } // setPrintData + + + /************************************************************************** + * Layout + */ + private void layout() + { + if (m_printFormat == null) + throw new IllegalStateException ("No print format"); + if (m_printData == null) + throw new IllegalStateException ("No print data (Delete Print Format and restart)"); + m_layout = new LayoutEngine (m_printFormat, m_printData, m_query); + } // layout + + /** + * Get Layout + * @return Layout + */ + protected LayoutEngine getLayout() + { + if (m_layout == null) + layout(); + return m_layout; + } // getLayout + + /** + * Get PrintFormat (Report) Name + * @return name + */ + public String getName() + { + return m_printFormat.getName(); + } // getName + + /** + * Get PrintFormat + * @return print format + */ + public MPrintFormat getPrintFormat() + { + return m_printFormat; + } // getPrintFormat + + /** + * Get Print Info + * @return info + */ + public PrintInfo getPrintInfo() + { + return m_info; + } // getPrintInfo + + /** + * Get PrintLayout (Report) Context + * @return context + */ + public Properties getCtx() + { + return m_layout.getCtx(); + } // getCtx + + /** + * Get Row Count + * @return row count + */ + public int getRowCount() + { + return m_printData.getRowCount(); + } // getRowCount + + /** + * Get Column Count + * @return column count + */ + public int getColumnCount() + { + if (m_layout != null) + return m_layout.getColumnCount(); + return 0; + } // getColumnCount + + + /************************************************************************** + * Get View Panel + * @return view panel + */ + public View getView() + { + if (m_layout == null) + layout(); + if (m_view == null) + m_view = new View (m_layout); + return m_view; + } // getView + + + /************************************************************************** + * Print Report + */ + public void print () + { + log.info(m_info.toString()); + if (m_layout == null) + layout(); + + // Paper Attributes: media-printable-area, orientation-requested, media + PrintRequestAttributeSet prats = m_layout.getPaper().getPrintRequestAttributeSet(); + // add: copies, job-name, priority + if (m_info.isDocumentCopy() || m_info.getCopies() < 1) + prats.add (new Copies(1)); + else + prats.add (new Copies(m_info.getCopies())); + Locale locale = Language.getLoginLanguage().getLocale(); + prats.add(new JobName(m_printFormat.getName(), locale)); + prats.add(PrintUtil.getJobPriority(m_layout.getNumberOfPages(), m_info.getCopies(), true)); + + try + { + // PrinterJob + PrinterJob job = getPrinterJob(m_info.getPrinterName()); + // job.getPrintService().addPrintServiceAttributeListener(this); + job.setPageable(m_layout.getPageable(false)); // no copy + // Dialog + try + { + if (m_info.isWithDialog() && !job.printDialog(prats)) + return; + } + catch (Exception e) + { + log.log(Level.WARNING, "Operating System Print Issue, check & try again", e); + return; + } + + // submit + boolean printCopy = m_info.isDocumentCopy() && m_info.getCopies() > 1; + ArchiveEngine.get().archive(m_layout, m_info); + PrintUtil.print(job, prats, false, printCopy); + + // Document: Print Copies + if (printCopy) + { + log.info("Copy " + (m_info.getCopies()-1)); + prats.add(new Copies(m_info.getCopies()-1)); + job = getPrinterJob(m_info.getPrinterName()); + // job.getPrintService().addPrintServiceAttributeListener(this); + job.setPageable (m_layout.getPageable(true)); // Copy + PrintUtil.print(job, prats, false, false); + } + } + catch (Exception e) + { + log.log(Level.SEVERE, "", e); + } + } // print + + /** + * Print Service Attribute Listener. + * @param psae event + */ + public void attributeUpdate(PrintServiceAttributeEvent psae) + { + /** +PrintEvent on Win32 Printer : \\MAIN\HP LaserJet 5L +PrintServiceAttributeSet - length=2 +queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) +printer-is-accepting-jobs = accepting-jobs (class javax.print.attribute.standard.PrinterIsAcceptingJobs) +PrintEvent on Win32 Printer : \\MAIN\HP LaserJet 5L +PrintServiceAttributeSet - length=1 +queued-job-count = 1 (class javax.print.attribute.standard.QueuedJobCount) +PrintEvent on Win32 Printer : \\MAIN\HP LaserJet 5L +PrintServiceAttributeSet - length=1 +queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) + **/ + log.fine("attributeUpdate - " + psae); + // PrintUtil.dump (psae.getAttributes()); + } // attributeUpdate + + + /** + * Get PrinterJob based on PrinterName + * @param printerName optional Printer Name + * @return PrinterJob + */ + private PrinterJob getPrinterJob (String printerName) + { + if (printerName != null && printerName.length() > 0) + return CPrinter.getPrinterJob(printerName); + return CPrinter.getPrinterJob(m_printerName); + } // getPrinterJob + + /** + * Show Dialog and Set Paper + * Optionally re-calculate layout + */ + public void pageSetupDialog () + { + if (m_layout == null) + layout(); + m_layout.pageSetupDialog(getPrinterJob(m_printerName)); + if (m_view != null) + m_view.revalidate(); + } // pageSetupDialog + + /** + * Set Printer (name) + * @param printerName valid printer name + */ + public void setPrinterName(String printerName) + { + if (printerName == null) + m_printerName = Ini.getProperty(Ini.P_PRINTER); + else + m_printerName = printerName; + } // setPrinterName + + /** + * Get Printer (name) + * @return printer name + */ + public String getPrinterName() + { + return m_printerName; + } // getPrinterName + + + /************************************************************************** + * Create HTML File + * @param file file + * @param onlyTable if false create complete HTML document + * @param language optional language - if null the default language is used to format nubers/dates + * @return true if success + */ + public boolean createHTML (File file, boolean onlyTable, Language language) + { + try + { + Language lang = language; + if (lang == null) + lang = Language.getLoginLanguage(); + FileWriter fw = new FileWriter (file, false); + return createHTML (new BufferedWriter(fw), onlyTable, lang); + } + catch (FileNotFoundException fnfe) + { + log.log(Level.SEVERE, "(f) - " + fnfe.toString()); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(f)", e); + } + return false; + } // createHTML + + /** + * Write HTML to writer + * @param writer writer + * @param onlyTable if false create complete HTML document + * @param language optional language - if null nubers/dates are not formatted + * @return true if success + */ + public boolean createHTML (Writer writer, boolean onlyTable, Language language) + { + try + { + table table = new table(); + // + // for all rows (-1 = header row) + for (int row = -1; row < m_printData.getRowCount(); row++) + { + tr tr = new tr(); + table.addElement(tr); + if (row != -1) + m_printData.setRowIndex(row); + // for all columns + for (int col = 0; col < m_printFormat.getItemCount(); col++) + { + MPrintFormatItem item = m_printFormat.getItem(col); + if (item.isPrinted()) + { + // header row + if (row == -1) + { + th th = new th(); + tr.addElement(th); + th.addElement(Util.maskHTML(item.getPrintName(language))); + } + else + { + td td = new td(); + tr.addElement(td); + Object obj = m_printData.getNode(new Integer(item.getAD_Column_ID())); + if (obj == null) + td.addElement(" "); + else if (obj instanceof PrintDataElement) + { + String value = ((PrintDataElement)obj).getValueDisplay(language); // formatted + td.addElement(Util.maskHTML(value)); + } + else if (obj instanceof PrintData) + { + // ignore contained Data + } + else + log.log(Level.SEVERE, "Element not PrintData(Element) " + obj.getClass()); + } + } // printed + } // for all columns + } // for all rows + + // + PrintWriter w = new PrintWriter(writer); + if (onlyTable) + table.output(w); + else + { + XhtmlDocument doc = new XhtmlDocument(); + doc.appendBody(table); + doc.output(w); + } + w.flush(); + w.close(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(w)", e); + } + return false; + } // createHTML + + + /************************************************************************** + * Create CSV File + * @param file file + * @param delimiter delimiter, e.g. comma, tab + * @param language translation language + * @return true if success + */ + public boolean createCSV (File file, char delimiter, Language language) + { + try + { + FileWriter fw = new FileWriter (file, false); + return createCSV (new BufferedWriter(fw), delimiter, language); + } + catch (FileNotFoundException fnfe) + { + log.log(Level.SEVERE, "(f) - " + fnfe.toString()); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(f)", e); + } + return false; + } // createCSV + + /** + * Write CSV to writer + * @param writer writer + * @param delimiter delimiter, e.g. comma, tab + * @param language translation language + * @return true if success + */ + public boolean createCSV (Writer writer, char delimiter, Language language) + { + if (delimiter == 0) + delimiter = '\t'; + try + { + // for all rows (-1 = header row) + for (int row = -1; row < m_printData.getRowCount(); row++) + { + StringBuffer sb = new StringBuffer(); + if (row != -1) + m_printData.setRowIndex(row); + + // for all columns + boolean first = true; // first column to print + for (int col = 0; col < m_printFormat.getItemCount(); col++) + { + MPrintFormatItem item = m_printFormat.getItem(col); + if (item.isPrinted()) + { + // column delimiter (comma or tab) + if (first) + first = false; + else + sb.append(delimiter); + // header row + if (row == -1) + createCSVvalue (sb, delimiter, + m_printFormat.getItem(col).getPrintName(language)); + else + { + Object obj = m_printData.getNode(new Integer(item.getAD_Column_ID())); + String data = ""; + if (obj == null) + ; + else if (obj instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)obj; + if (pde.isPKey()) + data = pde.getValueAsString(); + else + data = pde.getValueDisplay(language); // formatted + } + else if (obj instanceof PrintData) + { + } + else + log.log(Level.SEVERE, "Element not PrintData(Element) " + obj.getClass()); + createCSVvalue (sb, delimiter, data); + } + } // printed + } // for all columns + writer.write(sb.toString()); + writer.write(Env.NL); + } // for all rows + // + writer.flush(); + writer.close(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(w)", e); + } + return false; + } // createCSV + + /** + * Add Content to CSV string. + * Encapsulate/mask content in " if required + * @param sb StringBuffer to add to + * @param delimiter delimiter + * @param content column value + */ + private void createCSVvalue (StringBuffer sb, char delimiter, String content) + { + // nothing to add + if (content == null || content.length() == 0) + return; + // + boolean needMask = false; + StringBuffer buff = new StringBuffer(); + char chars[] = content.toCharArray(); + for (int i = 0; i < chars.length; i++) + { + char c = chars[i]; + if (c == '"') + { + needMask = true; + buff.append(c); // repeat twice + } // mask if any control character + else if (!needMask && (c == delimiter || !Character.isLetterOrDigit(c))) + needMask = true; + buff.append(c); + } + + // Optionally mask value + if (needMask) + sb.append('"').append(buff).append('"'); + else + sb.append(buff); + } // addCSVColumnValue + + + /************************************************************************** + * Create XML File + * @param file file + * @return true if success + */ + public boolean createXML (File file) + { + try + { + FileWriter fw = new FileWriter (file, false); + return createXML (new BufferedWriter(fw)); + } + catch (FileNotFoundException fnfe) + { + log.log(Level.SEVERE, "(f) - " + fnfe.toString()); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(f)", e); + } + return false; + } // createXML + + /** + * Write XML to writer + * @param writer writer + * @return true if success + */ + public boolean createXML (Writer writer) + { + try + { + m_printData.createXML(new StreamResult(writer)); + writer.flush(); + writer.close(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(w)", e); + } + return false; + } // createXML + + + /************************************************************************** + * Create PDF file. + * (created in temporary storage) + * @return PDF file + */ + public File getPDF() + { + return getPDF (null); + } // getPDF + + /** + * Create PDF file. + * @param file file + * @return PDF file + */ + public File getPDF (File file) + { + try + { + if (file == null) + file = File.createTempFile ("ReportEngine", ".pdf"); + } + catch (IOException e) + { + log.log(Level.SEVERE, "", e); + } + if (createPDF (file)) + return file; + return null; + } // getPDF + + /** + * Create PDF File + * @param file file + * @return true if success + */ + public boolean createPDF (File file) + { + String fileName = null; + URI uri = null; + + try + { + if (file == null) + file = File.createTempFile ("ReportEngine", ".pdf"); + fileName = file.getAbsolutePath(); + uri = file.toURI(); + if (file.exists()) + file.delete(); + + } + catch (Exception e) + { + log.log(Level.SEVERE, "file", e); + return false; + } + + log.fine(uri.toString()); + + try + { + if (m_layout == null) + layout (); + ArchiveEngine.get().archive(m_layout, m_info); + Document.getPDFAsFile(fileName, m_layout.getPageable(false)); + } + catch (Exception e) + { + log.log(Level.SEVERE, "PDF", e); + return false; + } + + File file2 = new File(fileName); + log.info(file2.getAbsolutePath() + " - " + file2.length()); + return file2.exists(); + } // createPDF + + /** + * Create PDF as Data array + * @return pdf data + */ + public byte[] createPDFData () + { + try + { + if (m_layout == null) + layout (); + return Document.getPDFAsArray(m_layout.getPageable(false)); + } + catch (Exception e) + { + log.log(Level.SEVERE, "PDF", e); + } + return null; + } // createPDFData + + /************************************************************************** + * Create PostScript File + * @param file file + * @return true if success + */ + public boolean createPS (File file) + { + try + { + return createPS (new FileOutputStream(file)); + } + catch (FileNotFoundException fnfe) + { + log.log(Level.SEVERE, "(f) - " + fnfe.toString()); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(f)", e); + } + return false; + } // createPS + + /** + * Write PostScript to writer + * @param fos file output stream + * @return true if success + */ + public boolean createPS (FileOutputStream fos) + { + try + { + String outputMimeType = DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType(); + DocFlavor docFlavor = DocFlavor.SERVICE_FORMATTED.PAGEABLE; + StreamPrintServiceFactory[] spsfactories = + StreamPrintServiceFactory.lookupStreamPrintServiceFactories(docFlavor, outputMimeType); + if (spsfactories.length == 0) + { + log.log(Level.SEVERE, "(fos) - No StreamPrintService"); + return false; + } + // just use first one - sun.print.PSStreamPrinterFactory + // System.out.println("- " + spsfactories[0]); + StreamPrintService sps = spsfactories[0].getPrintService(fos); + // get format + if (m_layout == null) + layout(); + // print it + sps.createPrintJob().print(m_layout.getPageable(false), + new HashPrintRequestAttributeSet()); + // + fos.flush(); + fos.close(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "(fos)", e); + } + return false; + } // createPS + + + /************************************************************************** + * Get Report Engine for process info + * @param ctx context + * @param pi process info with AD_PInstance_ID + * @return report engine or null + */ + static public ReportEngine get (Properties ctx, ProcessInfo pi) + { + int AD_Client_ID = pi.getAD_Client_ID(); + // + int AD_Table_ID = 0; + int AD_ReportView_ID = 0; + String TableName = null; + String whereClause = ""; + int AD_PrintFormat_ID = 0; + boolean IsForm = false; + int Client_ID = -1; + + // Get AD_Table_ID and TableName + String sql = "SELECT rv.AD_ReportView_ID,rv.WhereClause," + + " t.AD_Table_ID,t.TableName, pf.AD_PrintFormat_ID, pf.IsForm, pf.AD_Client_ID " + + "FROM AD_PInstance pi" + + " INNER JOIN AD_Process p ON (pi.AD_Process_ID=p.AD_Process_ID)" + + " INNER JOIN AD_ReportView rv ON (p.AD_ReportView_ID=rv.AD_ReportView_ID)" + + " INNER JOIN AD_Table t ON (rv.AD_Table_ID=t.AD_Table_ID)" + + " LEFT OUTER JOIN AD_PrintFormat pf ON (p.AD_ReportView_ID=pf.AD_ReportView_ID AND pf.AD_Client_ID IN (0,?)) " + + "WHERE pi.AD_PInstance_ID=? " // #2 + + "ORDER BY pf.AD_Client_ID DESC, pf.IsDefault DESC"; // own first + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, AD_Client_ID); + pstmt.setInt(2, pi.getAD_PInstance_ID()); + ResultSet rs = pstmt.executeQuery(); + // Just get first + if (rs.next()) + { + AD_ReportView_ID = rs.getInt(1); // required + whereClause = rs.getString(2); + if (rs.wasNull()) + whereClause = ""; + // + AD_Table_ID = rs.getInt(3); + TableName = rs.getString(4); // required for query + AD_PrintFormat_ID = rs.getInt(5); // required + IsForm = "Y".equals(rs.getString(6)); // required + Client_ID = rs.getInt(7); + } + rs.close(); + pstmt.close(); + } + catch (SQLException e1) + { + log.log(Level.SEVERE, "(1) - " + sql, e1); + } + // Nothing found + if (AD_ReportView_ID == 0) + { + // Check Print format in Report Directly + sql = "SELECT t.AD_Table_ID,t.TableName, pf.AD_PrintFormat_ID, pf.IsForm " + + "FROM AD_PInstance pi" + + " INNER JOIN AD_Process p ON (pi.AD_Process_ID=p.AD_Process_ID)" + + " INNER JOIN AD_PrintFormat pf ON (p.AD_PrintFormat_ID=pf.AD_PrintFormat_ID)" + + " INNER JOIN AD_Table t ON (pf.AD_Table_ID=t.AD_Table_ID) " + + "WHERE pi.AD_PInstance_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, pi.getAD_PInstance_ID()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + whereClause = ""; + AD_Table_ID = rs.getInt(1); + TableName = rs.getString(2); // required for query + AD_PrintFormat_ID = rs.getInt(3); // required + IsForm = "Y".equals(rs.getString(4)); // required + Client_ID = AD_Client_ID; + } + rs.close(); + pstmt.close(); + } + catch (SQLException e1) + { + log.log(Level.SEVERE, "(2) - " + sql, e1); + } + if (AD_PrintFormat_ID == 0) + { + log.log(Level.SEVERE, "Report Info NOT found AD_PInstance_ID=" + pi.getAD_PInstance_ID() + + ",AD_Client_ID=" + AD_Client_ID); + return null; + } + } + + // Create Query from Parameters + MQuery query = null; + if (IsForm && pi.getRecord_ID() != 0) // Form = one record + query = MQuery.getEqualQuery(TableName + "_ID", pi.getRecord_ID()); + else + query = MQuery.get (ctx, pi.getAD_PInstance_ID(), TableName); + + // Add to static where clause from ReportView + if (whereClause.length() != 0) + query.addRestriction(whereClause); + + // Get Print Format + MPrintFormat format = null; + Object so = pi.getSerializableObject(); + if (so instanceof MPrintFormat) + format = (MPrintFormat)so; + if (format == null && AD_PrintFormat_ID != 0) + { + // We have a PrintFormat with the correct Client + if (Client_ID == AD_Client_ID) + format = MPrintFormat.get (ctx, AD_PrintFormat_ID, false); + else + format = MPrintFormat.copyToClient (ctx, AD_PrintFormat_ID, AD_Client_ID); + } + if (format != null && format.getItemCount() == 0) + { + log.info("No Items - recreating: " + format); + format.delete(true); + format = null; + } + // Create Format + if (format == null && AD_ReportView_ID != 0) + format = MPrintFormat.createFromReportView(ctx, AD_ReportView_ID, pi.getTitle()); + if (format == null) + return null; + // + PrintInfo info = new PrintInfo (pi); + info.setAD_Table_ID(AD_Table_ID); + + return new ReportEngine(ctx, format, query, info); + } // get + + /*************************************************************************/ + + /** Order = 0 */ + public static final int ORDER = 0; + /** Shipment = 1 */ + public static final int SHIPMENT = 1; + /** Invoice = 2 */ + public static final int INVOICE = 2; + /** Project = 3 */ + public static final int PROJECT = 3; + /** RfQ = 4 */ + public static final int RFQ = 4; + /** Remittance = 5 */ + public static final int REMITTANCE = 5; + /** Check = 6 */ + public static final int CHECK = 6; + /** Dunning = 7 */ + public static final int DUNNING = 7; + /** Movement = 8 */ + public static final int MOVEMENT = 8; + + private static final String[] DOC_TABLES = new String[] { + "C_Order_Header_v", "M_InOut_Header_v", "C_Invoice_Header_v", "C_Project_Header_v", + "C_RfQResponse_v", + "C_PaySelection_Check_v", "C_PaySelection_Check_v", + "C_DunningRunEntry_v", "M_Movement_Header_V" }; + private static final String[] DOC_BASETABLES = new String[] { + "C_Order", "M_InOut", "C_Invoice", "C_Project", + "C_RfQResponse", + "C_PaySelectionCheck", "C_PaySelectionCheck", + "C_DunningRunEntry", "M_Movement" }; + private static final String[] DOC_IDS = new String[] { + "C_Order_ID", "M_InOut_ID", "C_Invoice_ID", "C_Project_ID", + "C_RfQResponse_ID", + "C_PaySelectionCheck_ID", "C_PaySelectionCheck_ID", + "C_DunningRunEntry_ID", "M_Movement_ID" }; + private static final int[] DOC_TABLE_ID = new int[] { + X_C_Order.Table_ID, X_M_InOut.Table_ID, X_C_Invoice.Table_ID, X_C_Project.Table_ID, + X_C_RfQResponse.Table_ID, + X_C_PaySelectionCheck.Table_ID, X_C_PaySelectionCheck.Table_ID, + X_C_DunningRunEntry.Table_ID, X_M_Movement.Table_ID }; + + + /************************************************************************** + * Get Document Print Engine for Document Type. + * @param ctx context + * @param type document type + * @param Record_ID id + * @return Report Engine or null + */ + public static ReportEngine get (Properties ctx, int type, int Record_ID) + { + // Order - Print Shipment or Invoice + if (type == ORDER) + { + int[] what = getDocumentWhat (Record_ID); + if (what != null) + { + type = what[0]; + Record_ID = what[1]; + } + } // Order + // + String JobName = DOC_BASETABLES[type] + "_Print"; + int AD_PrintFormat_ID = 0; + int C_BPartner_ID = 0; + String DocumentNo = null; + int copies = 1; + + // Language + MClient client = MClient.get(ctx); + Language language = client.getLanguage(); + // Get Document Info + String sql = null; + if (type == CHECK) + sql = "SELECT bad.Check_PrintFormat_ID," // 1 + + " c.IsMultiLingualDocument,bp.AD_Language,bp.C_BPartner_ID,d.DocumentNo " // 2..5 + + "FROM C_PaySelectionCheck d" + + " INNER JOIN C_PaySelection ps ON (d.C_PaySelection_ID=ps.C_PaySelection_ID)" + + " INNER JOIN C_BankAccountDoc bad ON (ps.C_BankAccount_ID=bad.C_BankAccount_ID AND d.PaymentRule=bad.PaymentRule)" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN C_BPartner bp ON (d.C_BPartner_ID=bp.C_BPartner_ID) " + + "WHERE d.C_PaySelectionCheck_ID=?"; // info from BankAccount + else if (type == DUNNING) + sql = "SELECT dl.Dunning_PrintFormat_ID," + + " c.IsMultiLingualDocument,bp.AD_Language,bp.C_BPartner_ID,dr.DunningDate " + + "FROM C_DunningRunEntry d" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN C_BPartner bp ON (d.C_BPartner_ID=bp.C_BPartner_ID)" + + " INNER JOIN C_DunningRun dr ON (d.C_DunningRun_ID=dr.C_DunningRun_ID)" + + " INNER JOIN C_DunningLevel dl ON (dl.C_DunningLevel_ID=dr.C_DunningLevel_ID) " + + "WHERE d.C_DunningRunEntry_ID=?"; // info from Dunning + else if (type == REMITTANCE) + sql = "SELECT pf.Remittance_PrintFormat_ID," + + " c.IsMultiLingualDocument,bp.AD_Language,bp.C_BPartner_ID,d.DocumentNo " + + "FROM C_PaySelectionCheck d" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN AD_PrintForm pf ON (c.AD_Client_ID=pf.AD_Client_ID)" + + " INNER JOIN C_BPartner bp ON (d.C_BPartner_ID=bp.C_BPartner_ID) " + + "WHERE d.C_PaySelectionCheck_ID=?" // info from PrintForm + + " AND pf.AD_Org_ID IN (0,d.AD_Org_ID) ORDER BY pf.AD_Org_ID DESC"; + else if (type == PROJECT) + sql = "SELECT pf.Project_PrintFormat_ID," + + " c.IsMultiLingualDocument,bp.AD_Language,bp.C_BPartner_ID,d.Value " + + "FROM C_Project d" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN AD_PrintForm pf ON (c.AD_Client_ID=pf.AD_Client_ID)" + + " LEFT OUTER JOIN C_BPartner bp ON (d.C_BPartner_ID=bp.C_BPartner_ID) " + + "WHERE d.C_Project_ID=?" // info from PrintForm + + " AND pf.AD_Org_ID IN (0,d.AD_Org_ID) ORDER BY pf.AD_Org_ID DESC"; + else if (type == RFQ) + sql = "SELECT COALESCE(t.AD_PrintFormat_ID, pf.AD_PrintFormat_ID)," + + " c.IsMultiLingualDocument,bp.AD_Language,bp.C_BPartner_ID,rr.Name " + + "FROM C_RfQResponse rr" + + " INNER JOIN C_RfQ r ON (rr.C_RfQ_ID=r.C_RfQ_ID)" + + " INNER JOIN C_RfQ_Topic t ON (r.C_RfQ_Topic_ID=t.C_RfQ_Topic_ID)" + + " INNER JOIN AD_Client c ON (rr.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN C_BPartner bp ON (rr.C_BPartner_ID=bp.C_BPartner_ID)," + + " AD_PrintFormat pf " + + "WHERE pf.AD_Client_ID IN (0,rr.AD_Client_ID)" + + " AND pf.AD_Table_ID=725 AND pf.IsTableBased='N'" // from RfQ PrintFormat + + " AND rr.C_RfQResponse_ID=? " // Info from RfQTopic + + "ORDER BY t.AD_PrintFormat_ID, pf.AD_Client_ID DESC, pf.AD_Org_ID DESC"; + else if (type == MOVEMENT) + sql = "SELECT pf.Movement_PrintFormat_ID," + + " c.IsMultiLingualDocument, COALESCE(dt.DocumentCopies,0) " + + "FROM M_Movement d" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN AD_PrintForm pf ON (c.AD_Client_ID=pf.AD_Client_ID)" + + " LEFT OUTER JOIN C_DocType dt ON (d.C_DocType_ID=dt.C_DocType_ID) " + + "WHERE d.M_Movement_ID=?" // info from PrintForm + + " AND pf.AD_Org_ID IN (0,d.AD_Org_ID) ORDER BY pf.AD_Org_ID DESC"; + else // Get PrintFormat from Org or 0 of document client + sql = "SELECT pf.Order_PrintFormat_ID,pf.Shipment_PrintFormat_ID," // 1..2 + // Prio: 1. BPartner 2. DocType, 3. PrintFormat (Org) // see InvoicePrint + + " COALESCE (bp.Invoice_PrintFormat_ID,dt.AD_PrintFormat_ID,pf.Invoice_PrintFormat_ID)," // 3 + + " pf.Project_PrintFormat_ID, pf.Remittance_PrintFormat_ID," // 4..5 + + " c.IsMultiLingualDocument, bp.AD_Language," // 6..7 + + " COALESCE(dt.DocumentCopies,0)+COALESCE(bp.DocumentCopies,1), " // 8 + + " dt.AD_PrintFormat_ID,bp.C_BPartner_ID,d.DocumentNo " // 9..11 + + "FROM " + DOC_BASETABLES[type] + " d" + + " INNER JOIN AD_Client c ON (d.AD_Client_ID=c.AD_Client_ID)" + + " INNER JOIN AD_PrintForm pf ON (c.AD_Client_ID=pf.AD_Client_ID)" + + " INNER JOIN C_BPartner bp ON (d.C_BPartner_ID=bp.C_BPartner_ID)" + + " LEFT OUTER JOIN C_DocType dt ON (d.C_DocType_ID=dt.C_DocType_ID) " + + "WHERE d." + DOC_IDS[type] + "=?" // info from PrintForm + + " AND pf.AD_Org_ID IN (0,d.AD_Org_ID) " + + "ORDER BY pf.AD_Org_ID DESC"; + // + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, Record_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) // first record only + { + if (type == CHECK || type == DUNNING || type == REMITTANCE + || type == PROJECT || type == RFQ) + { + AD_PrintFormat_ID = rs.getInt(1); + copies = 1; + // Set Language when enabled + String AD_Language = rs.getString(3); + if (AD_Language != null)// && "Y".equals(rs.getString(2))) // IsMultiLingualDocument + language = Language.getLanguage(AD_Language); + C_BPartner_ID = rs.getInt(4); + if (type == DUNNING) + { + Timestamp ts = rs.getTimestamp(5); + DocumentNo = ts.toString(); + } + else + DocumentNo = rs.getString(5); + } + else if (type == MOVEMENT) { + AD_PrintFormat_ID = rs.getInt(1); + log.fine("PF 2 ="+AD_PrintFormat_ID); + //TODO VHARCQ SQL needs change for copies VHARCQ= rs.getInt(8); + } + else + { + // Set PrintFormat + AD_PrintFormat_ID = rs.getInt(type+1); + if (rs.getInt(9) != 0) // C_DocType.AD_PrintFormat_ID + AD_PrintFormat_ID = rs.getInt(9); + copies = rs.getInt(8); + // Set Language when enabled + String AD_Language = rs.getString(7); + if (AD_Language != null) // && "Y".equals(rs.getString(6))) // IsMultiLingualDocument + language = Language.getLanguage(AD_Language); + C_BPartner_ID = rs.getInt(10); + DocumentNo = rs.getString(11); + } + } + rs.close(); + pstmt.close(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "Record_ID=" + Record_ID + ", SQL=" + sql, e); + } + if (AD_PrintFormat_ID == 0) + { + log.log(Level.SEVERE, "No PrintFormat found for Type=" + type + ", Record_ID=" + Record_ID); + return null; + } + + // Get Format & Data + MPrintFormat format = MPrintFormat.get (ctx, AD_PrintFormat_ID, false); + format.setLanguage(language); // BP Language if Multi-Lingual + // if (!Env.isBaseLanguage(language, DOC_TABLES[type])) + format.setTranslationLanguage(language); + // query + MQuery query = new MQuery(DOC_TABLES[type]); + query.addRestriction(DOC_IDS[type], MQuery.EQUAL, new Integer(Record_ID)); + // log.config( "ReportCtrl.startDocumentPrint - " + format, query + " - " + language.getAD_Language()); + // + if (DocumentNo == null || DocumentNo.length() == 0) + DocumentNo = "DocPrint"; + PrintInfo info = new PrintInfo( + DocumentNo, + DOC_TABLE_ID[type], + Record_ID, + C_BPartner_ID); + info.setCopies(copies); + info.setDocumentCopy(false); // true prints "Copy" on second + info.setPrinterName(format.getPrinterName()); + + // Engine + ReportEngine re = new ReportEngine(ctx, format, query, info); + return re; + } // get + + /** + * Determine what Order document to print. + * @param C_Order_ID id + * @return int Array with [printWhat, ID] + */ + private static int[] getDocumentWhat (int C_Order_ID) + { + int[] what = new int[2]; + what[0] = ORDER; + what[1] = C_Order_ID; + // + String sql = "SELECT dt.DocSubTypeSO " + + "FROM C_DocType dt, C_Order o " + + "WHERE o.C_DocType_ID=dt.C_DocType_ID" + + " AND o.C_Order_ID=?"; + String DocSubTypeSO = null; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, C_Order_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + DocSubTypeSO = rs.getString(1); + rs.close(); + pstmt.close(); + } + catch (SQLException e1) + { + log.log(Level.SEVERE, "(1) - " + sql, e1); + return null; // error + } + if (DocSubTypeSO == null) + DocSubTypeSO = ""; + // WalkIn Receipt, WalkIn Invoice, + if (DocSubTypeSO.equals("WR") || DocSubTypeSO.equals("WI")) + what[0] = INVOICE; + // WalkIn Pickup, + else if (DocSubTypeSO.equals("WP")) + what[0] = SHIPMENT; + // Offer Binding, Offer Nonbinding, Standard Order + else + return what; + + // Get Record_ID of Invoice/Receipt + if (what[0] == INVOICE) + sql = "SELECT C_Invoice_ID REC FROM C_Invoice WHERE C_Order_ID=?" // 1 + + " ORDER BY C_Invoice_ID DESC"; + else + sql = "SELECT M_InOut_ID REC FROM M_InOut WHERE C_Order_ID=?" // 1 + + " ORDER BY M_InOut_ID DESC"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, C_Order_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + // if (i == 1 && ADialog.ask(0, null, what[0] == INVOICE ? "PrintOnlyRecentInvoice?" : "PrintOnlyRecentShipment?")) break; + what[1] = rs.getInt(1); + } + else // No Document Found + what[0] = ORDER; + + rs.close(); + pstmt.close(); + } + catch (SQLException e2) + { + log.log(Level.SEVERE, "(2) - " + sql, e2); + return null; + } + log.fine("Order => " + what[0] + " ID=" + what[1]); + return what; + } // getDocumentWhat + + /** + * Print Confirm. + * Update Date Printed + * @param type document type + * @param Record_ID record id + */ + public static void printConfirm (int type, int Record_ID) + { + StringBuffer sql = new StringBuffer(); + if (type == ORDER || type == SHIPMENT || type == INVOICE) + sql.append("UPDATE ").append(DOC_BASETABLES[type]) + .append(" SET DatePrinted=SysDate, IsPrinted='Y' WHERE ") + .append(DOC_IDS[type]).append("=").append(Record_ID); + // + if (sql.length() > 0) + { + int no = DB.executeUpdate(sql.toString(), null); + if (no != 1) + log.log(Level.SEVERE, "Updated records=" + no + " - should be just one"); + } + } // printConfirm + + + /************************************************************************* + * Test + * @param args args + */ + public static void main(String[] args) + { + org.compiere.Adempiere.startupEnvironment(true); + // + int AD_Table_ID = 100; + MQuery q = new MQuery("AD_Table"); + q.addRestriction("AD_Table_ID", "<", 108); + // + MPrintFormat f = MPrintFormat.createFromTable(Env.getCtx(), AD_Table_ID); + PrintInfo i = new PrintInfo("test", AD_Table_ID, 108, 0); + i.setAD_Table_ID(AD_Table_ID); + ReportEngine re = new ReportEngine(Env.getCtx(), f, q, i); + re.layout(); + /** + re.createCSV(new File("C:\\Temp\\test.csv"), ',', Language.getLanguage()); + re.createHTML(new File("C:\\Temp\\test.html"), false, Language.getLanguage()); + re.createXML(new File("C:\\Temp\\test.xml")); + re.createPS(new File ("C:\\Temp\\test.ps")); + re.createPDF(new File("C:\\Temp\\test.pdf")); + /****/ + re.print(); + // re.print(true, 1, false, "Epson Stylus COLOR 900 ESC/P 2"); // Dialog + // re.print(true, 1, false, "HP LaserJet 3300 Series PCL 6"); // Dialog + // re.print(false, 1, false, "Epson Stylus COLOR 900 ESC/P 2"); // Dialog + System.exit(0); + } // main + +} // ReportEngine diff --git a/print/src/org/compiere/print/View.java b/print/src/org/compiere/print/View.java new file mode 100644 index 0000000000..af2747e0b9 --- /dev/null +++ b/print/src/org/compiere/print/View.java @@ -0,0 +1,278 @@ +/****************************************************************************** + * 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; + +import java.awt.*; +import org.compiere.model.*; +import org.compiere.print.layout.*; +import org.compiere.swing.*; +import org.compiere.util.*; + +/** + * View Panel + * + * @author Jorg Janke + * @version $Id: View.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class View extends CPanel +{ + /** + * Print Preview + * @param layout Layout + */ + public View (LayoutEngine layout) + { + m_layout = layout; + } // View + + /** Layout to be Printed */ + private LayoutEngine m_layout; + + + /** Zoom Level */ + private int m_zoomLevel = 0; + /** Zoom Options */ + public static final String[] ZOOM_OPTIONS = new String[] + {"100%", "75%", "50%"}; + /** Margin around paper */ + public static int MARGIN = 5; + /** Margin Background Color */ + private static Color COLOR_BACKGROUND = Color.lightGray; + + /** Logger */ + private static CLogger log = CLogger.getCLogger(View.class); + + /*************************************************************************/ + + /** + * Minimum Size + * @return Max Page Size + */ + public Dimension getMinimumSize() + { + return getMaximumSize(); + } // getMinimumSize + + /** + * Minimum Size + * @return Max Page Size + */ + public Dimension getMaximumSize() + { + return new Dimension (getPaperWidth()+(2*MARGIN), + (getPaperHeight()+MARGIN)*getPageCount()+MARGIN); + } // getMaximumSize + + /** + * Preferred Size + * @return Max Page Size + */ + public Dimension getPreferredSize() + { + return getMaximumSize(); + } // getPreferredSize + + /** + * Is Archivable + * @return true if archivable + */ + public boolean isArchivable() + { + return ArchiveEngine.isValid(m_layout); + } // IsArchivable + + /** + * Paint Component + * @param g Graphics + */ + public void paintComponent (Graphics g) + { + // log.fine( "View.paintComponent", g.getClip()); + Graphics2D g2D = (Graphics2D)g; + Rectangle bounds = g2D.getClipBounds(); + // + g2D.setColor(COLOR_BACKGROUND); + g2D.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + + // for all pages + for (int page = 0; page < m_layout.getPages().size(); page++) + { + Rectangle pageRectangle = getRectangleOfPage(page+1); + if (bounds.intersects(pageRectangle)) + { + Page p = (Page)m_layout.getPages().get(page); + p.paint (g2D, pageRectangle, true, false); // sets context + m_layout.getHeaderFooter().paint(g2D, pageRectangle, true); + } // paint page + } // for all pages + } // paintComponent + + + /************************************************************************** + * Set Zoom Level + * @param level zoom level + */ + public void setZoomLevel(int level) + { + m_zoomLevel = level; + } // setZoomLevel + + /** + * Set Zoom Level + * @param levelString zoom level string + */ + public void setZoomLevel(String levelString) + { + for (int i = 0; i < ZOOM_OPTIONS.length; i++) + { + if (ZOOM_OPTIONS[i].equals(levelString)) + { + m_zoomLevel = i; + break; + } + } + } // setZoomLevel + + /** + * Get Zoom Level + * @return zoom level + */ + public int getZoomLevel() + { + return m_zoomLevel; + } // getZoomLevel + + /** + * Get Rectange of Page + * @param pageNo page no + * @return rectangle + */ + public Rectangle getRectangleOfPage(int pageNo) + { + int y = MARGIN + ((pageNo-1) * (getPaperHeight() + MARGIN)); + return new Rectangle (MARGIN, y, getPaperWidth(), getPaperHeight()); + } // getRectangleOfPage + + + /** + * Get Page at Point + * @param p Point + * @return page as float to determine also position on page + */ + public float getPageNoAt (Point p) + { + float y = p.y; + float pageHeight = getPaperHeight() + MARGIN; + return 1f + (y/pageHeight); + } // getPageAt + + /** + * Get Page Count + * @return page count + */ + public int getPageCount() + { + return m_layout.getPages().size(); + } // getPageCount + + /** + * Get Page Info for Multi-Page tables + * @param pageNo page + * @return info e.g. (1,1) + */ + public String getPageInfo(int pageNo) + { + return m_layout.getPageInfo(pageNo); + } // getPageInfo + + /** + * Get Max Page Info for Multi-Page tables + * @return info e.g. (3,2) + */ + public String getPageInfoMax() + { + return m_layout.getPageInfoMax(); + } // getPageInfo + + /** + * Get Paper + * @return paper + */ + public CPaper getPaper() + { + return m_layout.getPaper(); + } // getPaper + + /** + * Get Paper Height + * @return paper height + */ + public int getPaperHeight() + { + return (int)m_layout.getPaper().getHeight(true); + } // getPaperHeight + + /** + * Get Paper Height + * @return paper height + */ + public int getPaperWidth() + { + return (int)m_layout.getPaper().getWidth(true); + } // getPaperHeight + + /** + * Get Drill Down + * @param absolutePoint point + * @return Drill Down + */ + public MQuery getDrillDown (Point absolutePoint) + { + int pageNo = (int)getPageNoAt(absolutePoint); + Rectangle pageRectangle = getRectangleOfPage(pageNo); + Point relativePoint = new Point (absolutePoint.x-pageRectangle.x, + absolutePoint.y-pageRectangle.y); + Page page = (Page)m_layout.getPages().get(pageNo-1); + // + log.config("Relative=" + relativePoint + ", " + page); + // log.config("AbsolutePoint=" + absolutePoint + ", PageNo=" + pageNo + ", pageRectangle=" + pageRectangle); + MQuery retValue = page.getDrillDown (relativePoint); + if (retValue == null) + retValue = m_layout.getHeaderFooter().getDrillDown (relativePoint); + return retValue; + } // getDrillDown + + /** + * Get Drill Across + * @param absolutePoint point + * @return Drill Across + */ + public MQuery getDrillAcross (Point absolutePoint) + { + int pageNo = (int)getPageNoAt(absolutePoint); + Rectangle pageRectangle = getRectangleOfPage(pageNo); + Point relativePoint = new Point (absolutePoint.x-pageRectangle.x, + absolutePoint.y-pageRectangle.y); + Page page = (Page)m_layout.getPages().get(pageNo-1); + // + log.config("Relative=" + relativePoint + ", " + page); + // log.config("AbsolutePoint=" + absolutePoint + ", PageNo=" + pageNo + ", pageRectangle=" + pageRectangle); + return page.getDrillAcross (relativePoint); + } // getDrillAcross + + +} // View diff --git a/print/src/org/compiere/print/layout/BarcodeElement.java b/print/src/org/compiere/print/layout/BarcodeElement.java new file mode 100644 index 0000000000..05ca3dd9bb --- /dev/null +++ b/print/src/org/compiere/print/layout/BarcodeElement.java @@ -0,0 +1,216 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.util.*; +import org.compiere.print.*; + +import net.sourceforge.barbecue.*; +import net.sourceforge.barbecue.linear.code128.*; + +/** + * Barcode Print Element + * + * @author Jorg Janke + * @version $Id: BarcodeElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class BarcodeElement extends PrintElement +{ + /** + * Barcode Element Constructor + * @param code barcode data string + * @param item format item + */ + public BarcodeElement (String code, MPrintFormatItem item) + { + super (); + if (code == null || code.length() == 0 + || item == null + || item.getBarcodeType() == null || item.getBarcodeType().length() == 0) + m_valid = false; + + createBarcode(code, item); + if (m_barcode == null) + m_valid = false; + } // BarcodeElement + + /** Valid */ + private boolean m_valid = true; + /** Barcode */ + private Barcode m_barcode = null; + + /** + * Create Barcode + * @param code barcode data string + * @param item printformat item + */ + private void createBarcode(String code, MPrintFormatItem item) + { + String type = item.getBarcodeType(); + try + { + if (type.equals(MPrintFormatItem.BARCODETYPE_Codabar2Of7Linear)) + m_barcode = BarcodeFactory.create2of7(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_CodabarMonarchLinear)) + m_barcode = BarcodeFactory.createMonarch(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_CodabarNW_7Linear)) + m_barcode = BarcodeFactory.createNW7(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_CodabarUSD_4Linear)) + m_barcode = BarcodeFactory.createUSD4(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code128ACharacterSet)) + m_barcode = BarcodeFactory.createCode128A(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code128BCharacterSet)) + m_barcode = BarcodeFactory.createCode128B(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code128CCharacterSet)) + m_barcode = BarcodeFactory.createCode128C(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code128DynamicallySwitching)) + m_barcode = BarcodeFactory.createCode128(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code393Of9LinearWithChecksum)) + m_barcode = BarcodeFactory.create3of9(code, true); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code393Of9LinearWOChecksum)) + m_barcode = BarcodeFactory.create3of9(code, false); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code39LinearWithChecksum)) + m_barcode = BarcodeFactory.createCode39(code, true); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code39LinearWOChecksum)) + m_barcode = BarcodeFactory.createCode39(code, false); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code39USD3WithChecksum)) + m_barcode = BarcodeFactory.createUSD3(code, true); + else if (type.equals(MPrintFormatItem.BARCODETYPE_Code39USD3WOChecksum)) + m_barcode = BarcodeFactory.createUSD3(code, false); + else if (type.equals(MPrintFormatItem.BARCODETYPE_CodeabarLinear)) + m_barcode = BarcodeFactory.createCodabar(code); + + // http://www.idautomation.com/code128faq.html + else if (type.equals(MPrintFormatItem.BARCODETYPE_EAN128)) + m_barcode = BarcodeFactory.createEAN128(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_GlobalTradeItemNoGTINUCCEAN128)) + m_barcode = BarcodeFactory.createGlobalTradeItemNumber(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_PDF417TwoDimensional)) + m_barcode = BarcodeFactory.createPDF417(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_SCC_14ShippingCodeUCCEAN128)) + m_barcode = BarcodeFactory.createSCC14ShippingCode(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_ShipmentIDNumberUCCEAN128)) + m_barcode = BarcodeFactory.createShipmentIdentificationNumber(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_SSCC_18NumberUCCEAN128)) + m_barcode = BarcodeFactory.createSSCC18(code); + else if (type.equals(MPrintFormatItem.BARCODETYPE_UCC128)) + m_barcode = BarcodeFactory.createUCC128(UCCEAN128Barcode.EAN128_AI, code); + + // http://www.usps.com/cpim/ftp/pubs/pub97/97apxs_006.html#_Toc481397331 + else if (type.equals(MPrintFormatItem.BARCODETYPE_USPostalServiceUCCEAN128)) + { + m_barcode = BarcodeFactory.createUSPS(code); + m_barcode.setDrawingText(false); + } + else + log.warning("Invalid Type" + type); + } + catch (Exception e) + { + log.warning(code + " - " + e.toString()); + m_valid = false; + } + + if (m_valid && m_barcode != null) + { + if (item.getAD_PrintFont_ID() != 0) + { + MPrintFont mFont = MPrintFont.get(item.getAD_PrintFont_ID()); + if (mFont != null) + m_barcode.setFont(mFont.getFont()); + } + if (item.getMaxWidth() > 0) + m_barcode.setBarWidth(item.getMaxWidth()); + if (item.getMaxHeight() > 0) + m_barcode.setBarHeight(item.getMaxHeight()); + // m_barcode.setResolution(72); + // + p_width = m_barcode.getWidth(); + p_height = m_barcode.getHeight(); + log.fine(type + " height=" + p_height + ", width=" + p_width); + } + } // createBarcode + + /** + * Get Barcode + * @return Barcode + */ + public Barcode getBarcode() + { + return m_barcode; + } // getBarcode + + /** + * Is Barcode Valid + * @return true if valid + */ + public boolean isValid() + { + return m_valid; + } // isValid + + /** + * Layout and Calculate Size + * Set p_width & p_height + * @return true if calculated + */ + protected boolean calculateSize () + { + return true; + } // calculateSize + + + /** + * Paint Element + * @param g2D graphics + * @param pageNo page no + * @param pageStart page start + * @param ctx context + * @param isView view + */ + public void paint (Graphics2D g2D, int pageNo, Point2D pageStart, + Properties ctx, boolean isView) + { + if (!m_valid || m_barcode == null) + return; + + // Position + Point2D.Double location = getAbsoluteLocation(pageStart); + int x = (int)location.x; + if (MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight.equals(p_FieldAlignmentType)) + x += p_maxWidth - p_width; + else if (MPrintFormatItem.FIELDALIGNMENTTYPE_Center.equals(p_FieldAlignmentType)) + x += (p_maxWidth - p_width) / 2; + int y = (int)location.y; + + m_barcode.draw(g2D, x, y); + } // paint + + /** + * String Representation + * @return info + */ + public String toString () + { + if (m_barcode == null) + return super.toString(); + return super.toString() + " " + m_barcode.getData(); + } // toString + +} // BarcodeElement diff --git a/print/src/org/compiere/print/layout/BoxElement.java b/print/src/org/compiere/print/layout/BoxElement.java new file mode 100644 index 0000000000..356149c937 --- /dev/null +++ b/print/src/org/compiere/print/layout/BoxElement.java @@ -0,0 +1,122 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.util.*; +import org.compiere.print.*; + + +/** + * Line / Box Element + * + * @author Jorg Janke + * @version $Id: BoxElement.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class BoxElement extends PrintElement +{ + /** + * BoxElement + * @param item item + * @param color color + */ + public BoxElement (MPrintFormatItem item, Color color) + { + super (); + if (item != null && item.isTypeBox()) + { + m_item = item; + m_color = color; + } + } // BoxElement + + /** The Item */ + private MPrintFormatItem m_item = null; + private Color m_color = Color.BLACK; + + /** + * Calculate Size + * @return true if calculated + */ + protected boolean calculateSize () + { + p_width = 0; + p_height = 0; + if (m_item == null) + return true; + return true; + } // calculateSize + + /** + * Paint + * @param g2D graphics + * @param pageNo page + * @param pageStart page start + * @param ctx context + * @param isView true if Java + */ + public void paint (Graphics2D g2D, int pageNo, Point2D pageStart, + Properties ctx, boolean isView) + { + if (m_item == null) + return; + // + g2D.setColor(m_color); + BasicStroke s = new BasicStroke(m_item.getLineWidth()); + g2D.setStroke(s); + // + Point2D.Double location = getAbsoluteLocation(pageStart); + int x = (int)location.x; + int y = (int)location.y; + + int width = m_item.getMaxWidth(); + int height = m_item.getMaxHeight(); + + if (m_item.getPrintFormatType().equals(MPrintFormatItem.PRINTFORMATTYPE_Line)) + g2D.drawLine(x, y, x+width, y+height); + else + { + String type = m_item.getShapeType(); + if (type == null) + type = ""; + if (m_item.isFilledRectangle()) + { + if (type.equals(MPrintFormatItem.SHAPETYPE_3DRectangle)) + g2D.fill3DRect(x, y, width, height, true); + else if (type.equals(MPrintFormatItem.SHAPETYPE_Oval)) + g2D.fillOval(x, y, width, height); + else if (type.equals(MPrintFormatItem.SHAPETYPE_RoundRectangle)) + g2D.fillRoundRect(x, y, width, height, m_item.getArcDiameter(), m_item.getArcDiameter()); + else + g2D.fillRect(x, y, width, height); + } + else + { + if (type.equals(MPrintFormatItem.SHAPETYPE_3DRectangle)) + g2D.draw3DRect(x, y, width, height, true); + else if (type.equals(MPrintFormatItem.SHAPETYPE_Oval)) + g2D.drawOval(x, y, width, height); + else if (type.equals(MPrintFormatItem.SHAPETYPE_RoundRectangle)) + g2D.drawRoundRect(x, y, width, height, m_item.getArcDiameter(), m_item.getArcDiameter()); + else + g2D.drawRect(x, y, width, height); + } + } + } // paint + +} // BoxElement diff --git a/print/src/org/compiere/print/layout/Dimension2DImpl.java b/print/src/org/compiere/print/layout/Dimension2DImpl.java new file mode 100644 index 0000000000..86109b611d --- /dev/null +++ b/print/src/org/compiere/print/layout/Dimension2DImpl.java @@ -0,0 +1,171 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; + +/** + * 2D Dimesnion Implementation + * + * @author Jorg Janke + * @version $Id: Dimension2DImpl.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class Dimension2DImpl extends Dimension2D +{ + /** + * Constructor 0/0 + */ + public Dimension2DImpl() + { + } // Dimension2DImpl + + /** + * Constructor 0/0 + * @param dim dimension + */ + public Dimension2DImpl(Dimension dim) + { + setSize (dim); + } // Dimension2DImpl + + /** + * Constructor 0/0 + * @param Width width + * @param Height height + */ + public Dimension2DImpl(double Width, double Height) + { + setSize (Width, Height); + } // Dimension2DImpl + + /** Width */ + public double width = 0; + /** Height */ + public double height = 0; + + /** + * Set Size + * @param Width width + * @param Height height + */ + public void setSize (double Width, double Height) + { + this.width = Width; + this.height = Height; + } // setSize + + /** + * Set Size + * @param dim dimension + */ + public void setSize (Dimension dim) + { + this.width = dim.getWidth(); + this.height = dim.getHeight(); + } // setSize + + /** + * Add Size below existing + * @param dWidth width to increase if below + * @param dHeight height to add + */ + public void addBelow (double dWidth, double dHeight) + { + if (this.width < dWidth) + this.width = dWidth; + this.height += dHeight; + } // addBelow + + /** + * Add Size below existing + * @param dim add dimension + */ + public void addBelow (Dimension dim) + { + addBelow (dim.width, dim.height); + } // addBelow + + /** + * Round to next Int value + */ + public void roundUp() + { + width = Math.ceil(width); + height = Math.ceil(height); + } // roundUp + + + /** + * Get Width + * @return width + */ + public double getWidth() + { + return width; + } // getWidth + + /** + * Get Height + * @return height + */ + public double getHeight() + { + return height; + } // getHeight + + /*************************************************************************/ + + /** + * Hash Code + * @return hash code + */ + public int hashCode() + { + long bits = Double.doubleToLongBits(width); + bits ^= Double.doubleToLongBits(height) * 31; + return (((int) bits) ^ ((int) (bits >> 32))); + } // hashCode + + /** + * Equals + * @param obj object + * @return true if w/h is same + */ + public boolean equals (Object obj) + { + if (obj != null && obj instanceof Dimension2D) + { + Dimension2D d = (Dimension2D)obj; + if (d.getWidth() == width && d.getHeight() == height) + return true; + } + return false; + } // equals + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("Dimension2D[w=").append(width).append(",h=").append(height).append("]"); + return sb.toString(); + } // toString + +} // Dimension2DImpl diff --git a/print/src/org/compiere/print/layout/GraphElement.java b/print/src/org/compiere/print/layout/GraphElement.java new file mode 100644 index 0000000000..83796d1dd0 --- /dev/null +++ b/print/src/org/compiere/print/layout/GraphElement.java @@ -0,0 +1,64 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.util.*; +import org.compiere.print.*; + +/** + * Graphic Element + * + * @author Jorg Janke + * @version $Id: GraphElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class GraphElement extends PrintElement +{ + /** + * Constructor + * @param pg graph model + */ + public GraphElement(MPrintGraph pg) + { + } // GraphElement + + /** + * Layout and Calculate Size + * Set p_width & p_height + * @return true if calculated + */ + protected boolean calculateSize() + { + return false; + } // calcluateSize + + /** + * 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 void paint (Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + + } // paint + +} // GraphElement + diff --git a/print/src/org/compiere/print/layout/GridElement.java b/print/src/org/compiere/print/layout/GridElement.java new file mode 100644 index 0000000000..acb7a7bcec --- /dev/null +++ b/print/src/org/compiere/print/layout/GridElement.java @@ -0,0 +1,209 @@ +/****************************************************************************** + * 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.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.*; + +/** + * Grid Element. + * Simple Table with Rows/Columns, but no Headers + * + * @author Jorg Janke + * @version $Id: GridElement.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class GridElement extends PrintElement +{ + /** + * Grid Element Constructor + * Call setData to initialize content + * @param rows max rows + * @param cols max cols + */ + public GridElement(int rows, int cols) + { + m_rows = rows; + m_cols = cols; + m_textLayout = new TextLayout[rows][cols]; + m_iterator = new AttributedCharacterIterator[rows][cols]; + m_rowHeight = new int[rows]; + m_colWidth = new int[cols]; + // explicit init + for (int r = 0; r < m_rows; r++) + { + m_rowHeight[r] = 0; + for (int c = 0; c < m_cols; c++) + { + m_textLayout[r][c] = null; + m_iterator[r][c] = null; + } + } + for (int c = 0; c < m_cols; c++) + m_colWidth[c] = 0; + } // GridElement + + /** Gap between Rows */ + private int m_rowGap = 3; + /** Gap between Columns */ + private int m_colGap = 5; + + /** Rows */ + private int m_rows; + /** Columns */ + private int m_cols; + /** The Layout Data */ + private TextLayout[][] m_textLayout = null; + /** Character Iterator */ + private AttributedCharacterIterator[][] m_iterator = null; + + /** Row Height */ + private int[] m_rowHeight = null; + /** Column Width */ + private int[] m_colWidth = null; + /** Context */ + private FontRenderContext m_frc = new FontRenderContext(null, true, true); + + /** + * Create TextLayout from Data and calculate size. + * Called from ParameterElement and Location + * @param row row + * @param col column + * @param stringData info element + * @param font font + * @param foreground color for foreground + */ + public void setData (int row, int col, String stringData, Font font, Paint foreground) + { + if (stringData == null || stringData.length() == 0) + return; + // + // log.fine("setData - " + row + "/" + col + " - " + stringData); + AttributedString aString = new AttributedString(stringData); + aString.addAttribute(TextAttribute.FONT, font); + aString.addAttribute(TextAttribute.FOREGROUND, foreground); + AttributedCharacterIterator iter = aString.getIterator(); + TextLayout layout = new TextLayout(iter, m_frc); + setData (row, col, layout, iter); + } // setData + + /** + * Create TextLayout from Data and calculate size + * @param row row + * @param col column + * @param layout single line layout + * @param iter character iterator + */ + private void setData (int row, int col, TextLayout layout, AttributedCharacterIterator iter) + { + if (layout == null) + return; + if (p_sizeCalculated) + throw new IllegalStateException("Size already calculated"); + if (row < 0 || row >= m_rows) + throw new ArrayIndexOutOfBoundsException("Row Index=" + row + " Rows=" + m_rows); + if (col < 0 || col >= m_cols) + throw new ArrayIndexOutOfBoundsException("Column Index=" + col + " Cols=" + m_cols); + // + m_textLayout[row][col] = layout; + m_iterator[row][col] = iter; + // Set Size + int height = (int)(layout.getAscent() + layout.getDescent() + layout.getLeading())+1; + int width = (int)layout.getAdvance()+1; + if (m_rowHeight[row] < height) + m_rowHeight[row] = height; + if (m_colWidth[col] < width) + m_colWidth[col] = width; + } // setData + + /** + * Set Rpw/Column gap + * @param rowGap row gap + * @param colGap column gap + */ + public void setGap (int rowGap, int colGap) + { + m_rowGap = rowGap; + m_colGap = colGap; + } // setGap + + + /************************************************************************** + * Layout & Calculate Image Size. + * Set p_width & p_height + * @return true if calculated + */ + protected boolean calculateSize() + { + p_height = 0; + for (int r = 0; r < m_rows; r++) + { + p_height += m_rowHeight[r]; + if (m_rowHeight[r] > 0) + p_height += m_rowGap; + } + p_height -= m_rowGap; // remove last + p_width = 0; + for (int c = 0; c < m_cols; c++) + { + p_width += m_colWidth[c]; + if (m_colWidth[c] > 0) + p_width += m_colGap; + } + p_width -= m_colGap; // remove last + return true; + } // calculateSize + + /** + * Paint it + * @param g2D Graphics + * @param pageStart top left Location of page + * @param pageNo page number for multi page support (0 = header/footer) - ignored + * @param ctx print context + * @param isView true if online view (IDs are links) + */ + public void paint(Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + Point2D.Double location = getAbsoluteLocation(pageStart); + float y = (float)location.y; + // + for (int row = 0; row < m_rows; row++) + { + float x = (float)location.x; + for (int col = 0; col < m_cols; col++) + { + if (m_textLayout[row][col] != null) + { + float yy = y + m_textLayout[row][col].getAscent(); + // if (m_iterator[row][col] != null) + // g2D.drawString(m_iterator[row][col], x, yy); + // else + m_textLayout[row][col].draw(g2D, x, yy); + } + x += m_colWidth[col]; + if (m_colWidth[col] > 0) + x += m_colGap; + } + y += m_rowHeight[row]; + if (m_rowHeight[row] > 0) + y += m_rowGap; + } + } // paint + +} // GridElement diff --git a/print/src/org/compiere/print/layout/HTMLElement.java b/print/src/org/compiere/print/layout/HTMLElement.java new file mode 100644 index 0000000000..685721d0ff --- /dev/null +++ b/print/src/org/compiere/print/layout/HTMLElement.java @@ -0,0 +1,146 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.util.*; +//import org.compiere.model.*; + +/** + * HTML Form Print ELement. + * Restrictions: + * - Label is not printed + * - Alighnment is ignored + * + * @author Jorg Janke + * @version $Id: HTMLElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class HTMLElement extends PrintElement +{ + /** + * HTML String Constructor + * @param html html code + */ + public HTMLElement (String html) + { + if (html == null || html.equals("")) + throw new IllegalArgumentException("HTMLElement is null"); + log.fine("Length=" + html.length()); + // Create View + m_renderer = HTMLRenderer.get(html); + } // HTMLElement + + /** View for Printing */ + private HTMLRenderer m_renderer; + + + /************************************************************************** + * Layout and Calculate Size. + * Set p_width & p_height + * @return Size + */ + protected boolean calculateSize() + { + if (p_sizeCalculated) + return true; + // + p_height = m_renderer.getHeight(); + p_width = m_renderer.getWidth(); + + // Limits + if (p_maxWidth != 0f) + p_width = p_maxWidth; + if (p_maxHeight != 0f) + { + if (p_maxHeight == -1f) // one line only + p_height = m_renderer.getHeightOneLine(); + else + p_height = p_maxHeight; + } + // System.out.println("HTMLElement.calculate size - Width=" + // + p_width + "(" + p_maxWidth + ") - Height=" + p_height + "(" + p_maxHeight + ")"); + // + m_renderer.setAllocation((int)p_width, (int)p_height); + return true; + } // calculateSize + + /************************************************************************* + + /** + * Paint/Print. + * Calculate actual Size. + * The text is printed in the topmost left position - i.e. the leading is below the line + * @param g2D Graphics + * @param pageStart top left Location of page + * @param pageNo page number for multi page support (0 = header/footer) - ignored + * @param ctx print context + * @param isView true if online view (IDs are links) + */ + public void paint (Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + // 36.0/137.015625, Clip=java.awt.Rectangle[x=0,y=0,width=639,height=804], Translate=1.0/56.0, Scale=1.0/1.0, Shear=0.0/0.0 + // log.finest( "HTMLElement.paint", p_pageLocation.x + "/" + p_pageLocation.y + // + ", Clip=" + g2D.getClip() + // + ", Translate=" + g2D.getTransform().getTranslateX() + "/" + g2D.getTransform().getTranslateY() + // + ", Scale=" + g2D.getTransform().getScaleX() + "/" + g2D.getTransform().getScaleY() + // + ", Shear=" + g2D.getTransform().getShearX() + "/" + g2D.getTransform().getShearY()); + // + Point2D.Double location = getAbsoluteLocation(pageStart); + // log.finest( "HTMLElement.paint - PageStart=" + pageStart + ", Location=" + location); + // + Rectangle allocation = m_renderer.getAllocation(); + g2D.translate(location.x, location.y); + m_renderer.paint(g2D, allocation); + g2D.translate(-location.x, -location.y); + } // paint + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("HTMLElement["); + 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).append(" - "); + sb.append("]"); + return sb.toString(); + } // toString + + + /************************************************************************** + * Is content HTML + * @param content content + * @return true if HTML + */ + public static boolean isHTML (Object content) + { + if (content == null) + return false; + String s = content.toString(); + if (s.length() < 20) // assumption + return false; + s = s.trim().toUpperCase(); + if (s.startsWith("")) + return true; + return false; + } // isHTML + +} // HTMLElement diff --git a/print/src/org/compiere/print/layout/HTMLRenderer.java b/print/src/org/compiere/print/layout/HTMLRenderer.java new file mode 100644 index 0000000000..f449dffb75 --- /dev/null +++ b/print/src/org/compiere/print/layout/HTMLRenderer.java @@ -0,0 +1,387 @@ +/****************************************************************************** + * 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.*; +import java.io.*; +import javax.swing.text.*; +import javax.swing.text.html.*; +import java.util.logging.*; +import org.compiere.util.*; + +/** + * HTML Renderer View + * + * @author Jorg Janke + * @version $Id: HTMLRenderer.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class HTMLRenderer extends View +{ + /** + * Get View from HTML String + * @param html html string + * @return renderer view + */ + public static HTMLRenderer get (String html) + { + HTMLEditorKit kit = new HTMLEditorKit(); + HTMLDocument doc = (HTMLDocument)kit.createDefaultDocument(); + try + { + doc.remove(0, doc.getLength()); + Reader r = new StringReader(html); + kit.read(r, doc, 0); + } + catch (Exception e) + { + log.log(Level.SEVERE, "", e); + } + // Create Renderer + Element element = doc.getDefaultRootElement(); + ViewFactory factory = kit.getViewFactory(); + View view = factory.create(element); // Y_AXIS is main + HTMLRenderer renderer = new HTMLRenderer (factory, view); + renderer.preferenceChanged (null, true, true); + return renderer; + } // get + + /** Logger */ + private static CLogger log = CLogger.getCLogger(HTMLRenderer.class); + + /************************************************************************** + * Constructor + * @param f factory + * @param v root view + */ + public HTMLRenderer (ViewFactory f, View v) + { + super(null); + m_factory = f; + m_view = v; + m_view.setParent(this); + // initially layout to the preferred size + setSize(m_view.getPreferredSpan(X_AXIS), m_view.getPreferredSpan(Y_AXIS)); + } // HTMLRenderer + + private int m_width; + private View m_view; + private ViewFactory m_factory; + private Rectangle m_allocation; + + + /** + * Get Width + * @return width + */ + public float getWidth() + { + return getPreferredSpan(javax.swing.text.View.X_AXIS); + } // getWidth + + /** + * Get Height + * @return height + */ + public float getHeight() + { + return getPreferredSpan(javax.swing.text.View.Y_AXIS); + } // getHeight + + /** + * Get Height for one line + * @return height + */ + public float getHeightOneLine() + { + return 30f; // HARDCODED + } // getHeightOneLine + + /** + * Set Allocation (actual print size) + * @param width actual print width + * @param height actual print height + */ + public void setAllocation (int width, int height) + { + setAllocation (new Rectangle(width, height)); + } // setAllocation + + /** + * Set Allocation (actual size) + * @param allocation actual print size + */ + public void setAllocation(Rectangle allocation) + { + m_allocation = allocation; + } // setAllocation + + /** + * Get Allocation + * @return actual print size or if not defined the renderer size + */ + public Rectangle getAllocation() + { + if (m_allocation == null) + return new Rectangle((int)getWidth(), (int)getHeight()); + return m_allocation; + } // getAllocation + + + /** + * Fetches the attributes to use when rendering. At the root + * level there are no attributes. If an attribute is resolved + * up the view hierarchy this is the end of the line. + * @return attribute set + */ + public AttributeSet getAttributes() + { + return null; + } + + /** + * Determines the preferred span for this view along an axis. + * @param axis may be either X_AXIS or Y_AXIS + * @return the span the view would like to be rendered into. + * Typically the view is told to render into the span + * that is returned, although there is no guarantee. + * The parent may choose to resize or break the view. + */ + public float getPreferredSpan(int axis) + { + if (axis == X_AXIS) + { + // width currently laid out to + return m_width; + } + return m_view.getPreferredSpan(axis); + } + + /** + * Determines the minimum span for this view along an axis. + * + * @param axis may be either X_AXIS or Y_AXIS + * @return the span the view would like to be rendered into. + * Typically the view is told to render into the span + * that is returned, although there is no guarantee. + * The parent may choose to resize or break the view. + */ + public float getMinimumSpan(int axis) + { + return m_view.getMinimumSpan(axis); + } + + /** + * Determines the maximum span for this view along an axis. + * + * @param axis may be either X_AXIS or Y_AXIS + * @return the span the view would like to be rendered into. + * Typically the view is told to render into the span + * that is returned, although there is no guarantee. + * The parent may choose to resize or break the view. + */ + public float getMaximumSpan(int axis) + { + return Integer.MAX_VALUE; + } + + + /** + * Determines the desired alignment for this view along an axis. + * + * @param axis may be either X_AXIS or Y_AXIS + * @return the desired alignment, where 0.0 indicates the origin + * and 1.0 the full span away from the origin + */ + public float getAlignment(int axis) + { + return m_view.getAlignment(axis); + } + + /** + * Renders the view. + * + * @param g the graphics context + * @param allocation the region to render into + */ + public void paint(Graphics g, Shape allocation) + { + Rectangle alloc = allocation.getBounds(); + m_view.setSize(alloc.width, alloc.height); // layout + Shape oldClip = g.getClip(); + g.setClip(alloc); // limit print + m_view.paint(g, allocation); + g.setClip(oldClip); + } // paint + + /** + * Sets the view parent. + * + * @param parent the parent view + */ + public void setParent(View parent) + { + throw new Error("Can't set parent on root view"); + } + + /** + * Returns the number of views in this view. Since + * this view simply wraps the root of the view hierarchy + * it has exactly one child. + * + * @return the number of views + * @see #getView + */ + public int getViewCount() + { + return 1; + } + + /** + * Gets the n-th view in this container. + * + * @param n the number of the view to get + * @return the view + */ + public View getView(int n) + { + return m_view; + } + + /** + * Provides a mapping from the document model coordinate space + * to the coordinate space of the view mapped to it. + * + * @param pos the position to convert + * @param a the allocated region to render into + * @param b position + * @return the bounding box of the given position + * @throws BadLocationException + */ + public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException + { + return m_view.modelToView(pos, a, b); + } + + /** + * Provides a mapping from the document model coordinate space + * to the coordinate space of the view mapped to it. + * + * @param p0 the position to convert >= 0 + * @param b0 the bias toward the previous character or the + * next character represented by p0, in case the + * position is a boundary of two views. + * @param p1 the position to convert >= 0 + * @param b1 the bias toward the previous character or the + * next character represented by p1, in case the + * position is a boundary of two views. + * @param a the allocated region to render into + * @return the bounding box of the given position is returned + * @exception BadLocationException if the given position does + * not represent a valid location in the associated document + * @exception IllegalArgumentException for an invalid bias argument + * @see javax.swing.text.View#viewToModel(float, float, java.awt.Shape, javax.swing.text.Position.Bias[]) + */ + public Shape modelToView(int p0, Position.Bias b0, int p1, + Position.Bias b1, Shape a) throws BadLocationException + { + return m_view.modelToView(p0, b0, p1, b1, a); + } + + /** + * Provides a mapping from the view coordinate space to the logical + * coordinate space of the model. + * + * @param x x coordinate of the view location to convert + * @param y y coordinate of the view location to convert + * @param a the allocated region to render into + * @param bias bias + * @return the location within the model that best represents the + * given point in the view + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) + { + return m_view.viewToModel(x, y, a, bias); + } + + /** + * Returns the document model underlying the view. + * + * @return the model + */ + public Document getDocument() + { + return m_view.getDocument(); + } + + /** + * Returns the starting offset into the model for this view. + * + * @return the starting offset + */ + public int getStartOffset() + { + return m_view.getStartOffset(); + } + + /** + * Returns the ending offset into the model for this view. + * + * @return the ending offset + */ + public int getEndOffset() + { + return m_view.getEndOffset(); + } + + /** + * Gets the element that this view is mapped to. + * + * @return the view + */ + public Element getElement() + { + return m_view.getElement(); + } + + /** + * Sets the view size. + * + * @param width the width + * @param height the height + */ + public void setSize(float width, float height) + { + this.m_width = (int) width; + m_view.setSize(width, height); + } + + /** + * Fetches the factory to be used for building the + * various view fragments that make up the view that + * represents the model. This is what determines + * how the model will be represented. This is implemented + * to fetch the factory provided by the associated + * EditorKit. + * + * @return the factory + */ + public ViewFactory getViewFactory() + { + return m_factory; + } + +} // HTMLRenderer diff --git a/print/src/org/compiere/print/layout/HeaderFooter.java b/print/src/org/compiere/print/layout/HeaderFooter.java new file mode 100644 index 0000000000..075730fdf1 --- /dev/null +++ b/print/src/org/compiere/print/layout/HeaderFooter.java @@ -0,0 +1,104 @@ +/****************************************************************************** + * 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.*; +import java.util.*; +import org.compiere.model.*; + +/** + * Header Footer + * + * @author Jorg Janke + * @version $Id: HeaderFooter.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class HeaderFooter +{ + /** + * Standard Constructor + * @param ctx context + */ + public HeaderFooter (Properties ctx) + { + m_ctx = ctx; + } // HeaderFooter + + /** Context */ + private Properties m_ctx; + + /** Header/Footer content */ + private ArrayList m_elements = new ArrayList(); + /** Header/Footer content as Array */ + private PrintElement[] m_pe = null; + + /** + * Add Print Element to Page + * @param element print element + */ + public void addElement (PrintElement element) + { + if (element != null) + m_elements.add(element); + m_pe = null; + } // addElement + + /** + * Get Elements + * @return array of elements + */ + public PrintElement[] getElements() + { + if (m_pe == null) + { + m_pe = new PrintElement[m_elements.size()]; + m_elements.toArray(m_pe); + } + return m_pe; + } // getElements + + /** + * Paint Page Header/Footer on Graphics in Bounds + * + * @param g2D graphics + * @param bounds page bounds + * @param isView true if online view (IDs are links) + */ + public void paint (Graphics2D g2D, Rectangle bounds, boolean isView) + { + Point pageStart = new Point(bounds.getLocation()); + getElements(); + for (int i = 0; i < m_pe.length; i++) + m_pe[i].paint(g2D, 0, pageStart, m_ctx, isView); + } // paint + + /** + * Get DrillDown value + * @param relativePoint relative Point + * @return if found NamePait or null + */ + public MQuery getDrillDown (Point relativePoint) + { + MQuery retValue = null; + for (int i = 0; i < m_elements.size() && retValue == null; i++) + { + PrintElement element = (PrintElement)m_elements.get(i); + retValue = element.getDrillDown (relativePoint, 1); + } + return retValue; + } // getDrillDown + +} // HeaderFooter diff --git a/print/src/org/compiere/print/layout/ImageElement.java b/print/src/org/compiere/print/layout/ImageElement.java new file mode 100644 index 0000000000..f86ec2b436 --- /dev/null +++ b/print/src/org/compiere/print/layout/ImageElement.java @@ -0,0 +1,289 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * Image Element + * + * @author Jorg Janke + * @version $Id: ImageElement.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $ + */ +public class ImageElement extends PrintElement +{ + /** + * Create Image from URL + * @param imageURLString image url + * @return image element + */ + public static ImageElement get (String imageURLString) + { + Object key = imageURLString; + ImageElement image = (ImageElement)s_cache.get(key); + if (image == null) + { + image = new ImageElement(imageURLString); + s_cache.put(key, image); + } + return new ImageElement(image.getImage()); + } // get + + /** + * Create Image from URL + * @param imageURL image url + * @return image element + */ + public static ImageElement get (URL imageURL) + { + Object key = imageURL; + ImageElement image = (ImageElement)s_cache.get(key); + if (image == null) + { + image = new ImageElement(imageURL); + s_cache.put(key, image); + } + return new ImageElement(image.getImage()); + } // get + + /** + * Create Image from Attachment + * @param AD_PrintFormatItem_ID record id + * @return image element + */ + public static ImageElement get (int AD_PrintFormatItem_ID) + { + Object key = new Integer(AD_PrintFormatItem_ID); + ImageElement image = (ImageElement)s_cache.get(key); + if (image == null) + { + image = new ImageElement(AD_PrintFormatItem_ID); + s_cache.put(key, image); + } + return new ImageElement(image.getImage()); + } // get + + /** 60 minute Cache */ + private static CCache s_cache + = new CCache("ImageElement", 10, 60); + + /************************************************************************** + * Create from existing Image + * @param image image + */ + public ImageElement(Image image) + { + m_image = image; + if (m_image != null) + log.fine("Image=" + image); + else + log.log(Level.WARNING, "Image is NULL"); + } // ImageElement + + /** + * Create Image from URL + * @param imageURLstring image url + */ + private ImageElement(String imageURLstring) + { + URL imageURL = getURL(imageURLstring); + if (imageURL != null) + { + m_image = Toolkit.getDefaultToolkit().getImage(imageURL); + if (m_image != null) + log.fine("URL=" + imageURL); + else + log.log(Level.WARNING, "Not loaded - URL=" + imageURL); + } + else + log.log(Level.WARNING, "Invalid URL=" + imageURLstring); + } // ImageElement + + /** + * Create Image from URL + * @param imageURL image url + */ + private ImageElement(URL imageURL) + { + if (imageURL != null) + { + m_image = Toolkit.getDefaultToolkit().getImage(imageURL); + if (m_image != null) + log.fine("URL=" + imageURL); + else + log.log(Level.WARNING, "Not loaded - URL=" + imageURL); + } + else + log.severe ("ImageURL is NULL"); + } // ImageElement + + /** + * Create Image from Attachment + * @param AD_PrintFormatItem_ID record id + */ + private ImageElement(int AD_PrintFormatItem_ID) + { + loadAttachment(AD_PrintFormatItem_ID); + } // ImageElement + + /** The Image */ + private Image m_image = null; + /** Scale */ + private double m_scaleFactor = 1; + + /************************************************************************** + * Get URL from String + * @param urlString url or resource + * @return URL or null + */ + private URL getURL (String urlString) + { + URL url = null; + // not a URL - may be a resource + if (urlString.indexOf("://") == -1) + { + ClassLoader cl = getClass().getClassLoader(); + url = cl.getResource(urlString); + if (url != null) + return url; + log.log(Level.WARNING, "Not found - " + urlString); + return null; + } + // load URL + try + { + url = new URL (urlString); + } + catch (MalformedURLException ex) + { + log.log(Level.WARNING, urlString, ex); + } + return url; + } // getURL; + + /** + * Load Attachment + * @param AD_PrintFormatItem_ID record id + */ + private void loadAttachment(int AD_PrintFormatItem_ID) + { + MAttachment attachment = MAttachment.get(Env.getCtx(), + MPrintFormatItem.Table_ID, AD_PrintFormatItem_ID); + if (attachment == null) + { + log.log(Level.WARNING, "No Attachment - AD_PrintFormatItem_ID=" + AD_PrintFormatItem_ID); + return; + } + if (attachment.getEntryCount() != 1) + { + log.log(Level.WARNING, "Need just 1 Attachment Entry = " + attachment.getEntryCount()); + return; + } + byte[] imageData = attachment.getEntryData(0); + if (imageData != null) + m_image = Toolkit.getDefaultToolkit().createImage(imageData); + if (m_image != null) + log.fine(attachment.getEntryName(0) + + " - Size=" + imageData.length); + else + log.log(Level.WARNING, attachment.getEntryName(0) + + " - not loaded (must be gif or jpg) - AD_PrintFormatItem_ID=" + AD_PrintFormatItem_ID); + } // loadAttachment + + + /************************************************************************** + * Calculate Image Size. + * Set p_width & p_height + * @return true if calculated + */ + protected boolean calculateSize() + { + p_width = 0; + p_height = 0; + if (m_image == null) + return true; + // we have an image + waitForLoad(m_image); + if (m_image != null) + { + p_width = m_image.getWidth(this); + p_height = m_image.getHeight(this); + + if (p_width * p_height == 0) + return true; // don't bother scaling and prevent div by 0 + + // 0 = unlimited so scale to fit restricted dimension + if (p_maxWidth * p_maxHeight != 0) // scale to maintain aspect ratio + { + if (p_width/p_height > p_maxWidth/p_maxHeight) + // image "fatter" than available area + m_scaleFactor = p_maxWidth/p_width; + else + m_scaleFactor = p_maxHeight/p_height; + } + p_width = (float) m_scaleFactor * p_width; + p_height = (float) m_scaleFactor * p_height; + } + return true; + } // calculateSize + + /** + * Get the Image + * @return image + */ + public Image getImage() + { + return m_image; + } // getImage + + /** + * Paint Image + * @param g2D Graphics + * @param pageStart top left Location of page + * @param pageNo page number for multi page support (0 = header/footer) - ignored + * @param ctx print context + * @param isView true if online view (IDs are links) + */ + public void paint(Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + if (m_image == null) + return; + + // Position + Point2D.Double location = getAbsoluteLocation(pageStart); + int x = (int)location.x; + if (MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight.equals(p_FieldAlignmentType)) + x += p_maxWidth - p_width; + else if (MPrintFormatItem.FIELDALIGNMENTTYPE_Center.equals(p_FieldAlignmentType)) + x += (p_maxWidth - p_width) / 2; + int y = (int)location.y; + + // map a scaled and shifted version of the image to device space + AffineTransform transform = new AffineTransform(); + transform.translate(x,y); + transform.scale(m_scaleFactor, m_scaleFactor); + g2D.drawImage(m_image, transform, this); + } // paint + +} // ImageElement diff --git a/print/src/org/compiere/print/layout/LayoutEngine.java b/print/src/org/compiere/print/layout/LayoutEngine.java new file mode 100644 index 0000000000..cfc984d977 --- /dev/null +++ b/print/src/org/compiere/print/layout/LayoutEngine.java @@ -0,0 +1,1765 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.awt.print.*; +import java.io.*; +import java.net.*; +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import javax.print.*; +import javax.print.attribute.*; +import org.compiere.*; +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * Adempiere 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 $ + */ +public class LayoutEngine implements Pageable, Printable, Doc +{ + /** + * Detail Constructor + * @param format Print Format + * @param data Print Data + * @param query query for parameter info + */ + public LayoutEngine (MPrintFormat format, PrintData data, MQuery query) + { + log.info(format + " - " + data + " - " + query); + // s_FASTDRAW = MClient.get(format.getCtx()).isUseBetaFunctions(); + // + setPrintFormat(format, false); + setPrintData(data, query, false); + 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; + + + /** 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 */ + 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); + + 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 doLayout if layout exists, redo it + * @param format print Format + */ + public void setPrintFormat (MPrintFormat format, boolean doLayout) + { + m_format = format; + // 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()) + setPaper(mPaper.getCPaper()); + 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.getName()); + Env.setContext(m_printCtx, Page.CONTEXT_HEADER, Env.getHeader(m_printCtx, 0)); + 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 doLayout if layout exists, redo it + * @param query query for parameter + */ + public void setPrintData (PrintData data, MQuery query, boolean doLayout) + { + m_data = data; + m_query = query; + 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 + * Optionally 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); + // + 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) + { + log.info(""); + 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 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); + + 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() && m_format.isStandardHeaderFooter()) + createStandardHeaderFooter(); + // + 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 + } + // 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)); + // Update Page Info + int pages = m_pages.size(); + for (int i = 0; i < pages; i++) + { + Page page = (Page)m_pages.get(i); + int pageNo = page.getPageNo(); + pageInfo = String.valueOf(pageNo) + getPageInfo(pageNo); + page.setPageInfo(pageInfo); + page.setPageCount(pages); + } + + 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 + + /** + * Return 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) + { + 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}; + 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]); + log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y); + } + else if (m_area == AREA_CONTENT) + { + log.finest("Not enough Y space " + + m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area); + newPage(true, false); + 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 No + * @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 = (Page)m_pages.get(pageNo-1); + return retValue; + } // getPage + + /** + * Get Pages + * @return Pages in ArrayList + */ + public ArrayList getPages() + { + return m_pages; + } // getPages + + /** + * Get Header & Footer info + * @return Header&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 = (Page)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); + StringBuffer sb = new StringBuffer("("); + 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 ""; + StringBuffer sb = new StringBuffer("("); + sb.append(m_tableElement.getPageYCount()).append(",") + .append(m_tableElement.getPageXCount()).append(")"); + return sb.toString(); + } // getPageInfoMax + + /** + * Get 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 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()); + 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 the 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; + 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; + 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; + 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; + log.finest("Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y); + } + else if (m_area == AREA_CONTENT) + { + log.finest("Not enough Y space " + + m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area); + newPage(true, true); + 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 + + + /************************************************************************** + * Return remaining X dimension space _ on current page in 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 + + /** + * Remaining Space is 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 + + /** + * Return 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 + + /** + * Remaining Space is 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 + + /************************************************************************** + * Create Standard Header/Footer + *
+	 *  title           C        Page x of x
+	 *  Copyright      who         date&time
+	 *  
+ */ + private void createStandardHeaderFooter() + { + /** Removing/modifying the Adempiere logo/trademark/copyright is a violation of the license */ + PrintElement element = new ImageElement(org.compiere.Adempiere.getImageLogoSmall(true)); // 48x15 + // element = new ImageElement(org.compiere.Adempiere.getImageLogo()); // 100x30 + element.layout(48, 15, false, MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft); + element.setLocation(m_header.getLocation()); + m_headerFooter.addElement(element); + // + MPrintTableFormat tf = m_format.getTableFormat(); + Font font = tf.getPageHeader_Font(); + Color color = tf.getPageHeaderFG_Color(); + // + element = new StringElement("@*ReportName@", font, color, null, true); + element.layout (m_header.width, 0, true, MPrintFormatItem.FIELDALIGNMENTTYPE_Center); + element.setLocation(m_header.getLocation()); + m_headerFooter.addElement(element); + // + // + element = new StringElement("@Page@ @*Page@ @of@ @*PageCount@", font, color, null, true); + element.layout (m_header.width, 0, true, MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight); + element.setLocation(m_header.getLocation()); + m_headerFooter.addElement(element); + + // Footer + font = tf.getPageFooter_Font(); + color = tf.getPageFooterFG_Color(); + // + /** Removing/modifying the Adempiere logo/trademark/copyright is a violation of the license */ + element = new StringElement(Adempiere.ADEMPIERE_R, font, color, null, true); + /** If you have a valid Adempiere support contract, you can use the following */ + // element = new StringElement(Adempiere.NAME, font, color, null, true); + element.layout (m_footer.width, 0, true, MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft); + Point ft = m_footer.getLocation(); + ft.y += m_footer.height - element.getHeight() - 2; // 2pt above min + element.setLocation(ft); + m_headerFooter.addElement(element); + // + element = new StringElement("@*Header@", font, color, null, true); + element.layout (m_footer.width, 0, true, MPrintFormatItem.FIELDALIGNMENTTYPE_Center); + element.setLocation(ft); + m_headerFooter.addElement(element); + // + element = new StringElement("@*CurrentDateTime@", font, color, null, true); + element.layout (m_footer.width, 0, true, MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight); + element.setLocation(ft); + m_headerFooter.addElement(element); + } // createStandardHeaderFooter + + + + /************************************************************************** + * Layout Form. + * For every Row, loop through the Format + * and calculate element size and position. + */ + private void layoutForm() + { + // log.info("layoutForm"); + m_columnCount = 0; + if (m_data == null) + return; + // for every row + for (int row = 0; row < m_data.getRowCount(); row++) + { + log.info("Row=" + row); + m_data.setRowIndex(row); + boolean somethingPrinted = true; // prevent NL of nothing printed and supress null + // for every item + for (int i = 0; i < m_format.getItemCount(); i++) + { + MPrintFormatItem item = m_format.getItem(i); + // log.fine("layoutForm - Row=" + row + " - #" + i + " - " + item); + if (!item.isPrinted()) + continue; + // log.fine("layoutForm - Row=" + row + " - #" + i + " - " + item); + 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.isNextPage()) // item.isPageBreak() // new page + newPage(false, false); + else if (item.isNextLine() && somethingPrinted) // new line + { + newLine (); + somethingPrinted = false; + } + else + addX(m_lastWidth[m_area]); + // 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 (item.isTypePrintFormat()) //** included PrintFormat + { + element = includeFormat (item, m_data); + } + else if (item.isBarcode()) + { + element = createBarcodeElement(item); + element.layout(maxWidth, item.getMaxHeight(), false, alignment); + } + else if (item.isTypeImage()) //** Image + { + if (item.isImageField()) + element = createImageElement (item); + else if (item.isImageIsAttached()) + element = ImageElement.get (item.get_ID()); + else + element = ImageElement.get (item.getImageURL()); + 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); + } + else // (item.isTypeText()) //** Text + { + if (maxWidth == 0 && item.isFieldAlignBlock()) + maxWidth = getAreaBounds().width; + element = createStringElement (item.getPrintName (m_format.getLanguage ()), + 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; + } + + // Does it fit? + if (item.isRelativePosition() && !lineAligned) + { + if (!isXspaceFor(m_lastWidth[m_area])) + { + 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])) + { + log.finest("Not enough Y space " + + m_lastHeight[m_area] + " - remaining " + getYspace() + " - Area=" + m_area); + newPage (true, true); + } + } + // We know Position and Size + // log.fine( "LayoutEngine.layoutForm", + // "Page=" + m_pageNo + " [" + m_area + "] " + m_position[m_area].x + "/" + m_position[m_area].y + // + " w=" + lastWidth[m_area] + ",h=" + lastHeight[m_area] + " " + item); + 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 (m_lastHeight[m_area] > m_maxHeightSinceNewLine[m_area]) + 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; + // + 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(); + log.info(format + " - Item=" + item.getName() + " (" + AD_Column_ID + ")"); + // + Object obj = data.getNode(new Integer(AD_Column_ID)); + // Object obj = data.getNode(item.getColumnName()); // slower + 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; + } + 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; + } + MQuery query = new MQuery (format.getAD_Table_ID()); + query.addRestriction(item.getColumnName(), MQuery.EQUAL, new Integer(Record_ID)); + format.setTranslationViewQuery(query); + log.fine(query.toString()); + // + DataEngine de = new DataEngine(format.getLanguage()); + PrintData includedData = de.getPrintData(data.getCtx(), format, query); + log.fine(includedData.toString()); + if (includedData == null) + return null; + // + 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])) + { + 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])) + { + 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.getNode(new Integer(item.getAD_Column_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 (item.getColumnName().equals("AmtInWords")) + { + 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 handeled 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); + 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 item + * @return image element + */ + private PrintElement createImageElement (MPrintFormatItem item) + { + Object obj = m_data.getNode(new Integer(item.getAD_Column_ID())); + 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 = ImageElement.get (url); + return element; + } // createImageElement + + /** + * Create Barcode Element + * @param item item + * @return barcode element + */ + private PrintElement createBarcodeElement (MPrintFormatItem item) + { + // Get Data + Object obj = m_data.getNode(new Integer(item.getAD_Column_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; + + 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) + { + 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()); + // Sizes + boolean multiLineHeader = false; + 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 + int columnCount = 0; + for (int c = 0; c < format.getItemCount(); c++) + { + if (format.getItem(c).isPrinted()) + columnCount++; + } + // System.out.println("Cols=" + cols); + + // Header & Column Setup + ValueNamePair[] columnHeader = new ValueNamePair[columnCount]; + int[] columnMaxWidth = new int[columnCount]; + int[] columnMaxHeight = new int[columnCount]; + boolean[] fixedWidth = new boolean [columnCount]; + String[] columnJustification = new String[columnCount]; + HashMap additionalLines = new HashMap(); + + int col = 0; + for (int c = 0; c < format.getItemCount(); c++) + { + MPrintFormatItem item = format.getItem(c); + if (item.isPrinted()) + { + if (item.isNextLine() && item.getBelowColumn() != 0) + { + additionalLines.put(new Integer(col), new Integer(item.getBelowColumn()-1)); + if (!item.isSuppressNull()) + { + item.setIsSuppressNull(true); // display size will be set to 0 in TableElement + item.save(); + } + } + columnHeader[col] = new ValueNamePair(item.getColumnName(), + item.getPrintName(format.getLanguage())); + columnMaxWidth[col] = item.getMaxWidth(); + fixedWidth[col] = (columnMaxWidth[col] != 0 && item.isFixedWidth()); + 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()); + } + // + col++; + } + } + + // The Data + int rows = printData.getRowCount(); + // System.out.println("Rows=" + rows); + Object[][] data = new Object [rows][columnCount]; + KeyNamePair[] pk = new KeyNamePair[rows]; + String pkColumnName = null; + ArrayList functionRows = new ArrayList(); + ArrayList pageBreak = new ArrayList(); + + // for all rows + for (int row = 0; row < rows; row++) + { + // System.out.println("row=" + row); + printData.setRowIndex(row); + if (printData.isFunctionRow()) + { + functionRows.add(new Integer(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(new Integer(row)); + log.finer("PageBreak row=" + row); + } + } + // Summary/Line Levels for Finanial Reports + else + { + int levelNo = printData.getLineLevelNo(); + if (levelNo != 0) + { + if (levelNo < 0) + levelNo = -levelNo; + 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)); + } + } + // for all columns + col = 0; + for (int c = 0; c < format.getItemCount(); c++) + { + MPrintFormatItem item = format.getItem(c); + Object dataElement = null; + if (item.isPrinted() && item.getAD_Column_ID() > 0) // Text Columns + { + if (item.isTypePrintFormat()) + { + log.warning("Unsupported: PrintFormat in Table: " + item); + } + else if (item.isTypeImage()) + { + if (item.isImageField()) + { + Object obj = printData.getNode(new Integer(item.getAD_Column_ID())); + if (obj == null) + ; + else if (obj instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)obj; + data[row][col] = ImageElement.get ((String)pde.getValue()); + } + } + else if (item.isImageIsAttached()) + data[row][col] = ImageElement.get (item.get_ID()); + else + data[row][col] = ImageElement.get (item.getImageURL()); + } + else if (item.isBarcode()) + { + Object obj = printData.getNode(new Integer(item.getAD_Column_ID())); + if (obj == null) + ; + else if (obj instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)obj; + BarcodeElement element = new BarcodeElement ((String)pde.getValue(), item); + if (element.isValid()) + data[row][col] = element; + } + } + else + { + Object obj = printData.getNode(new Integer(item.getAD_Column_ID())); + if (obj == null) + ; + else if (obj instanceof PrintDataElement) + { + PrintDataElement pde = (PrintDataElement)obj; + if (pde.isID() || pde.isYesNo()) + dataElement = pde.getValue(); + else + dataElement = pde.getValueDisplay(format.getLanguage()); + } + else + log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass()); + // System.out.println(" row=" + row + ",col=" + col + " - " + item.getAD_Column_ID() + " => " + dataElement); + data[row][col] = dataElement; + } + col++; + } // printed + } // for all columns + + PrintDataElement pde = printData.getPKey(); + if (pde != null) // for FunctionRows + { + pk[row] = (KeyNamePair)pde.getValue(); + if (pkColumnName == null) + pkColumnName = pde.getColumnName(); + } + // else + // System.out.println("No PK " + printData); + } // for all rows + + // + TableElement table = new TableElement(columnHeader, + columnMaxWidth, columnMaxHeight, columnJustification, + fixedWidth, functionRows, multiLineHeader, + data, pk, pkColumnName, + pageNoStart, firstPage, nextPages, repeatedColumns, additionalLines, + rowColFont, rowColColor, rowColBackground, + tf, pageBreak); + table.layout(0,0,false, MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft); + if (m_tableElement == null) + m_tableElement = table; + return table; + } // layoutTable + + /** + * Layout Parameter based on MQuery + * @return PrintElement + */ + private PrintElement layoutParameter () + { + if (m_query == null || !m_query.isActive()) + return null; + // + ParameterElement pe = new ParameterElement(m_query, m_printCtx, m_format.getTableFormat()); + pe.layout(0, 0, false, null); + return pe; + } // layoutParameter + + + /************************************************************************** + * Get number of pages (Pageable Interface) + * @return number of pages + */ + public int getNumberOfPages() + { + return m_pages.size(); + } // getNumberOfPages + + /** + * Get Page Format (Pageable Interface) + * @param pageIndex page index + * @return Page Format + * @throws IndexOutOfBoundsException + */ + 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 + */ + 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 + */ + 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); + // + // log.fine("#" + m_id, "PageIndex=" + pageIndex + ", Copy=" + m_isCopy); + page.paint((Graphics2D)graphics, r, false, m_isCopy); // sets context + getHeaderFooter().paint((Graphics2D)graphics, r, false); + // + 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 + */ + public DocFlavor getDocFlavor() + { + return DocFlavor.SERVICE_FORMATTED.PAGEABLE; + } // getDocFlavor + + /** + * Get Print Data (Doc Interface) + * @return this + * @throws IOException + */ + 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. + */ + public DocAttributeSet getAttributes() + { + return null; + } // getAttributes + + /** + * Obtains a reader for extracting character print data from this doc. + * (Doc Interface) + * @return null + * @exception IOException + */ + 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 + */ + public InputStream getStreamForBytes() throws IOException + { + return null; + } // getStreamForBytes + +} // LayoutEngine diff --git a/print/src/org/compiere/print/layout/LocationElement.java b/print/src/org/compiere/print/layout/LocationElement.java new file mode 100644 index 0000000000..3e549103b6 --- /dev/null +++ b/print/src/org/compiere/print/layout/LocationElement.java @@ -0,0 +1,83 @@ +/****************************************************************************** + * 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.*; +import java.util.*; +import java.util.regex.*; + +import org.compiere.model.*; + +/** + * Location/Address Element. + * Prints Addresses + * + * @author Jorg Janke + * @version $Id: LocationElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class LocationElement extends GridElement +{ + /** + * Constructor + * @param ctx context + * @param C_Location_ID location + * @param font font + * @param color color + */ + public LocationElement(Properties ctx, int C_Location_ID, Font font, Paint color) + { + super(10,1); // max + setGap(0,0); + MLocation ml = MLocation.get (ctx, C_Location_ID, null); + // log.fine("C_Location_ID=" + C_Location_ID); + if (ml != null) + { + int index = 0; + if (ml.isAddressLinesReverse()) + { + setData(index++, 0, ml.getCountry(true), font, color); + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(ml.getCityRegionPostal()); + for (int i = 0; i < lines.length; i++) + setData(index++, 0, lines[i], font, color); + if (ml.getAddress4() != null && ml.getAddress4().length() > 0) + setData(index++, 0, ml.getAddress4(), font, color); + if (ml.getAddress3() != null && ml.getAddress3().length() > 0) + setData(index++, 0, ml.getAddress3(), font, color); + if (ml.getAddress2() != null && ml.getAddress2().length() > 0) + setData(index++, 0, ml.getAddress2(), font, color); + if (ml.getAddress1() != null && ml.getAddress1().length() > 0) + setData(index++, 0, ml.getAddress1(), font, color); + } + else + { + if (ml.getAddress1() != null && ml.getAddress1().length() > 0) + setData(index++, 0, ml.getAddress1(), font, color); + if (ml.getAddress2() != null && ml.getAddress2().length() > 0) + setData(index++, 0, ml.getAddress2(), font, color); + if (ml.getAddress3() != null && ml.getAddress3().length() > 0) + setData(index++, 0, ml.getAddress3(), font, color); + if (ml.getAddress4() != null && ml.getAddress4().length() > 0) + setData(index++, 0, ml.getAddress4(), font, color); + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(ml.getCityRegionPostal()); + for (int i = 0; i < lines.length; i++) + setData(index++, 0, lines[i], font, color); + setData(index++, 0, ml.getCountry(true), font, color); + } + } + } // LocationElement + +} // LocationElement diff --git a/print/src/org/compiere/print/layout/Page.java b/print/src/org/compiere/print/layout/Page.java new file mode 100644 index 0000000000..e84ced851e --- /dev/null +++ b/print/src/org/compiere/print/layout/Page.java @@ -0,0 +1,218 @@ +/****************************************************************************** + * 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.*; +import java.util.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Layout Page + * + * @author Jorg Janke + * @version $Id: Page.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class Page +{ + /** + * Layout for Page + * @param pageNo page + * @param ctx context + */ + public Page (Properties ctx, int pageNo) + { + m_ctx = ctx; + m_pageNo = pageNo; + if (m_pageInfo == null || m_pageInfo.length() == 0) + m_pageInfo = String.valueOf(m_pageNo); + } // Page + + /** Current Page No (set here) */ + public static final String CONTEXT_PAGE = "*Page"; + /** Page Count (set in Layout Emgine */ + public static final String CONTEXT_PAGECOUNT = "*PageCount"; + /** Multi Page Info (set here) */ + public static final String CONTEXT_MULTIPAGE = "*MultiPageInfo"; + /** Copy Info (set here) */ + public static final String CONTEXT_COPY = "*CopyInfo"; + + /** Report Name (set in Layout Engine) */ + public static final String CONTEXT_REPORTNAME = "*ReportName"; + /** Report Header (set in Layout Engine) */ + public static final String CONTEXT_HEADER = "*Header"; + /** Current Date (set in Layout Engine) */ + public static final String CONTEXT_DATE = "*CurrentDate"; + /** Current Time (set in Layout Engine) */ + public static final String CONTEXT_TIME = "*CurrentDateTime"; + + /** Page Number */ + private int m_pageNo; + /** Page Number */ + private int m_pageCount = 1; + /** Page Count */ + private String m_pageInfo; + /** Context */ + private Properties m_ctx; + /** Page content */ + private ArrayList m_elements = new ArrayList(); + + /** + * Get Page No + * @return page no + */ + public int getPageNo() + { + return m_pageNo; + } // getPageNo + + /** + * Get Page Info + * @return page info + */ + public String getPageInfo() + { + return m_pageInfo; + } // getPageInfo + + /** + * Set Page Info. + * Enhanced pagae no, e.g., 7(2,3) + * @param pageInfo page info + */ + public void setPageInfo (String pageInfo) + { + if (m_pageInfo == null || m_pageInfo.length() == 0) + m_pageInfo = String.valueOf(m_pageNo); + m_pageInfo = pageInfo; + } // getPageInfo + + /** + * Set Page Info + * @param pageCount page count + */ + public void setPageCount (int pageCount) + { + m_pageCount = pageCount; + } // setPageCount + + /** + * Add Print Element to Page + * @param element print element + */ + public void addElement (PrintElement element) + { + if (element != null) + m_elements.add(element); + } // addElement + + /*************************************************************************/ + + /** + * Paint Page on Graphics in Bounds + * + * @param g2D graphics + * @param bounds page bounds + * @param isView true if online view (IDs are links) + * @param isCopy this print is a copy + */ + public void paint (Graphics2D g2D, Rectangle bounds, boolean isView, boolean isCopy) + { + m_ctx.put (CONTEXT_PAGE, m_pageInfo); + // log.finest( "PrintContext", CONTEXT_PAGE + "=" + m_pageInfo); + // + StringBuffer sb = new StringBuffer(); + if (m_pageCount != 1) // set to "Page 1 of 2" + sb.append(Msg.getMsg(m_ctx, "Page")).append(" ") + .append(m_pageNo) + .append(" ").append(Msg.getMsg(m_ctx, "of")).append(" ") + .append(m_pageCount); + else + sb.append(" "); + m_ctx.put(CONTEXT_MULTIPAGE, sb.toString()); + // log.finest( "PrintContext", CONTEXT_MULTIPAGE + "=" + sb.toString()); + // + sb = new StringBuffer(); + if (isCopy) // set to "(Copy)" + sb.append("(") + .append(Msg.getMsg(m_ctx, "DocumentCopy")) + .append(")"); + else + sb.append(" "); + m_ctx.put(CONTEXT_COPY, sb.toString()); + // log.finest( "PrintContext copy=" + isCopy, CONTEXT_COPY + "=" + sb.toString()); + + // Paint Background + g2D.setColor(Color.white); + g2D.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + // + Point pageStart = new Point(bounds.getLocation()); + for (int i = 0; i < m_elements.size(); i++) + { + PrintElement e = (PrintElement)m_elements.get(i); + e.paint(g2D, m_pageNo, pageStart, m_ctx, isView); + } + } // paint + + /*************************************************************************/ + + /** + * Get DrillDown value + * @param relativePoint relative Point + * @return if found NamePait or null + */ + public MQuery getDrillDown (Point relativePoint) + { + MQuery retValue = null; + for (int i = 0; i < m_elements.size() && retValue == null; i++) + { + PrintElement element = (PrintElement)m_elements.get(i); + retValue = element.getDrillDown (relativePoint, m_pageNo); + } + return retValue; + } // getDrillDown + + /** + * Get DrillAcross value + * @param relativePoint relative Point + * @return if found Query or null + */ + public MQuery getDrillAcross (Point relativePoint) + { + MQuery retValue = null; + for (int i = 0; i < m_elements.size() && retValue == null; i++) + { + PrintElement element = (PrintElement)m_elements.get(i); + retValue = element.getDrillAcross (relativePoint, m_pageNo); + } + return retValue; + } // getDrillAcross + + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("Page["); + sb.append(m_pageNo).append(",Elements=").append(m_elements.size()); + sb.append("]"); + return sb.toString(); + } // toString + +} // Page diff --git a/print/src/org/compiere/print/layout/ParameterElement.java b/print/src/org/compiere/print/layout/ParameterElement.java new file mode 100644 index 0000000000..9245e658a8 --- /dev/null +++ b/print/src/org/compiere/print/layout/ParameterElement.java @@ -0,0 +1,54 @@ +/****************************************************************************** + * 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.util.*; +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * Parameter Table + * + * @author Jorg Janke + * @version $Id: ParameterElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class ParameterElement extends GridElement +{ + /** + * Parameter Element. + *
+	 *  Parameter fromValue - toValue
+	 *  
+ * @param query query + * @param ctx context + * @param tFormat Table Format + */ + public ParameterElement(MQuery query, Properties ctx, MPrintTableFormat tFormat) + { + super (query.getRestrictionCount(), 4); + setData (0, 0, Msg.getMsg(ctx, "Parameter") + ":", tFormat.getPageHeader_Font(), tFormat.getPageHeaderFG_Color()); + for (int r = 0; r < query.getRestrictionCount(); r++) + { + setData (r, 1, query.getInfoName(r), tFormat.getParameter_Font(), tFormat.getParameter_Color()); + setData (r, 2, query.getInfoOperator(r), tFormat.getParameter_Font(), tFormat.getParameter_Color()); + setData (r, 3, query.getInfoDisplayAll(r), tFormat.getParameter_Font(), tFormat.getParameter_Color()); + } + } // ParameterElement + +} // ParameterElement + diff --git a/print/src/org/compiere/print/layout/PrintElement.java b/print/src/org/compiere/print/layout/PrintElement.java new file mode 100644 index 0000000000..1e6c49920f --- /dev/null +++ b/print/src/org/compiere/print/layout/PrintElement.java @@ -0,0 +1,348 @@ +/****************************************************************************** + * 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.*; +import java.awt.geom.*; +import java.awt.image.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * 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 +{ + /** + * 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()); + + + /************************************************************************** + * 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 + * Set p_width & p_height + * @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 == 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(), lauout(), 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 absolite position + */ + protected Point2D.Double getAbsoluteLocation(Point2D pageStart) + { + Point2D.Double retValue = new Point2D.Double( + p_pageLocation.x + pageStart.getX(), p_pageLocation.y + pageStart.getY()); + // log.finest( "PrintElement.getAbsoluteLocation", "PageStart=" + pageStart.getX() + "/" + pageStart.getY() + // + ",PageLocaton=" + p_pageLocation.x + "/" + p_pageLocation.y + " => " + retValue.x + "/" + retValue.y); + return retValue; + } // getAbsoluteLocation + + /** + * Get relative Bounds of Element + * @return bounds relative position on page + */ + 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 value + * @param relativePoint relative Point + * @param pageNo page number + * @return null (subclasses overwrite) + */ + public MQuery getDrillDown (Point relativePoint, int pageNo) + { + return null; + } // getDrillDown + + /** + * Get Drill Across value + * @param relativePoint relative Point + * @param pageNo page number + * @return null (subclasses overwrite) + */ + public MQuery getDrillAcross (Point relativePoint, int pageNo) + { + return null; + } // getDrillAcross + + + /************************************************************************** + * Translate Context 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 + */ + 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 (CLogMgt.isLevelFinest()) + 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) + log.fine((System.currentTimeMillis()-start) + "ms - #" + count); + return true; + } // waitForLoad + + /** + * Get Detail Info from Sub-Class + * @return detail info + */ + protected String getDetailInfo() + { + return ""; + } // getDetailInfo + + /** + * String Representation + * @return info + */ + public String toString() + { + String cn = getClass().getName(); + StringBuffer sb = new StringBuffer(); + 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 + +} // PrintElement diff --git a/print/src/org/compiere/print/layout/StringElement.java b/print/src/org/compiere/print/layout/StringElement.java new file mode 100644 index 0000000000..2c381e128e --- /dev/null +++ b/print/src/org/compiere/print/layout/StringElement.java @@ -0,0 +1,606 @@ +/****************************************************************************** + * 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.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.*; +import java.util.regex.*; +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * String Form Print ELement. + * The input can be multiple lines. The first tab is expanded. + * + * @author Jorg Janke + * @version $Id: StringElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class StringElement extends PrintElement +{ + /** + * Standard Field Constructor. + * Created in LayoutEngine + * @param inText text + * @param font font + * @param paint paint + * @param ID optional ID (null if document) + * @param translateText if true, check for optional text translation + */ + public StringElement (String inText, Font font, Paint paint, NamePair ID, boolean translateText) + { + super(); + log.finest("Text=" + inText + ", ID=" + ID + ", Translate=" + translateText); + m_font = font; + m_paint = paint; + if (translateText) + { + int count = Util.getCount(inText, '@'); + if (count > 0 && count % 2 == 0) + { + m_originalString = inText; + // Translate it to get rough space (not correct context) = may be too small + inText = Msg.parseTranslation(Env.getCtx(), m_originalString); + } + } + m_ID = ID; + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(inText); + m_string_paper = new AttributedString[lines.length]; + m_string_view = new AttributedString[lines.length]; + for (int i = 0; i < lines.length; i++) + { + String line = Util.removeCRLF (lines[i]); + m_string_paper[i] = new AttributedString(line); + if (line.length() == 0) + continue; + log.finest(" - line=" + i + " - " + line); + m_string_paper[i].addAttribute(TextAttribute.FONT, font); + m_string_paper[i].addAttribute(TextAttribute.FOREGROUND, paint); + if (m_ID != null && i == 0) // first line only - create special Attributed String + { + m_string_view[i] = new AttributedString(line); + m_string_view[i].addAttribute(TextAttribute.FONT, font); + int endIndex = line.length(); + m_string_view[i].addAttribute(TextAttribute.FOREGROUND, LINK_COLOR); + m_string_view[i].addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL, 0, endIndex); + } + else + m_string_view[i] = m_string_paper[i]; + } + // Load Image + waitForLoad(LayoutEngine.IMAGE_TRUE); + waitForLoad(LayoutEngine.IMAGE_FALSE); + } // StringElement + + /** + * Attributed String Constructor + * @param string attributed string + */ + public StringElement(AttributedString string) + { + super(); + m_string_paper = new AttributedString[] {string}; + m_string_view = m_string_paper; + } // StringElement + + /** + * Field Constructor. + * Created in LayoutEngine + * @param content text or boolean + * @param font font + * @param paint paint + * @param ID optional ID (null if document) + * @param label optional label + * @param labelSuffix optional label suffix + */ + public StringElement (Object content, Font font, Paint paint, NamePair ID, String label, String labelSuffix) + { + super(); + log.finest("Label=" + label + "|" + labelSuffix + + ", Content=" + content + ", ID=" + ID); + m_font = font; + m_paint = paint; + int startIndex = 0; + int endOffset = 0; + + StringBuffer text = new StringBuffer(); + if (label != null && label.length() > 0) + { + text.append(label).append(" "); + startIndex = label.length() + 1; + } + if (content instanceof Boolean) + m_check = (Boolean)content; + else + text.append(content); + if (labelSuffix != null && labelSuffix.length() > 0) + { + text.append(labelSuffix); + endOffset = labelSuffix.length(); + } + m_ID = ID; + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(text); + m_string_paper = new AttributedString[lines.length]; + m_string_view = new AttributedString[lines.length]; + for (int i = 0; i < lines.length; i++) + { + String line = Util.removeCRLF (lines[i]); + m_string_paper[i] = new AttributedString(line); + if (line.length() == 0) + continue; + log.finest(" - line=" + i + " - " + line); + m_string_paper[i].addAttribute(TextAttribute.FONT, font); + m_string_paper[i].addAttribute(TextAttribute.FOREGROUND, paint); + if (m_ID != null && i == 0) // first line only - create special Attributed String + { + m_string_view[i] = new AttributedString(line); + m_string_view[i].addAttribute(TextAttribute.FONT, font); + m_string_view[i].addAttribute(TextAttribute.FOREGROUND, paint); + int endIndex = line.length() - endOffset; + if (endIndex > startIndex) + { + m_string_view[i].addAttribute (TextAttribute.FOREGROUND, LINK_COLOR, startIndex, endIndex); + m_string_view[i].addAttribute (TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL, startIndex, endIndex); + } + } + else + m_string_view[i] = m_string_paper[i]; + } + } // StringElement + + + /** Actual Elements - Viewer */ + private AttributedString[] m_string_view = null; + /** Actual Elements - Printer */ + private AttributedString[] m_string_paper = null; + /** To be translated String */ + private String m_originalString = null; + /** Font used */ + private Font m_font = null; + /** Paint used */ + private Paint m_paint = null; + /** Optional ID of String */ + private NamePair m_ID = null; + /** Optional CheckBox */ + private Boolean m_check = null; + + /** + * Get optional ID + * @return ID or null + */ + public NamePair getID() + { + return m_ID; + } // getID + + /** + * Get Original String + * @return original (may be null) + */ + public String getOriginalString() + { + return m_originalString; + } // getOrig + + /** + * Translate Context 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) + { + if (m_originalString == null) + return; + String inText = Msg.parseTranslation(ctx, m_originalString); + // log.fine( "StringElement.translate", inText); + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(inText); + m_string_paper = new AttributedString[lines.length]; + for (int i = 0; i < lines.length; i++) + { + String line = Util.removeCRLF (lines[i]); + m_string_paper[i] = new AttributedString(line); + if (line.length() > 0) + { + m_string_paper[i].addAttribute(TextAttribute.FONT, m_font); + m_string_paper[i].addAttribute(TextAttribute.FOREGROUND, m_paint); + } + } + m_string_view = m_string_paper; + } // translate + + + /************************************************************************** + * Layout and Calculate Size. + * Set p_width & p_height + * @return Size + */ + protected boolean calculateSize() + { + if (p_sizeCalculated) + return true; + // + FontRenderContext frc = new FontRenderContext(null, true, true); + TextLayout layout = null; + p_height = 0f; + p_width = 0f; + + // No Limit + if (p_maxWidth == 0f && p_maxHeight == 0f) + { + for (int i = 0; i < m_string_paper.length; i++) + { + AttributedCharacterIterator iter = m_string_paper[i].getIterator(); + if (iter.getBeginIndex() == iter.getEndIndex()) + continue; + + // Check for Tab (just first) + int tabPos = -1; + for (char c = iter.first(); c != CharacterIterator.DONE && tabPos == -1; c = iter.next()) + { + if (c == '\t') + tabPos = iter.getIndex(); + } + + if (tabPos == -1) + { + layout = new TextLayout (iter, frc); + p_height += layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (p_width < layout.getAdvance()) + p_width = layout.getAdvance(); + } + else // with tab + { + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc); + layout = measurer.nextLayout(9999, tabPos, false); + p_height += layout.getAscent() + layout.getDescent() + layout.getLeading(); + float width = getTabPos (0, layout.getAdvance()); + layout = measurer.nextLayout(9999, iter.getEndIndex(), true); + width += layout.getAdvance(); + if (p_width < width) + p_width = width; + } + } // for all strings + + // Add CheckBox Size + if (m_check != null) + { + p_width += LayoutEngine.IMAGE_SIZE.width; + if (p_height < LayoutEngine.IMAGE_SIZE.height) + p_height = LayoutEngine.IMAGE_SIZE.height; + } + } + // Size Limits + else + { + p_width = p_maxWidth; + for (int i = 0; i < m_string_paper.length; i++) + { + AttributedCharacterIterator iter = m_string_paper[i].getIterator(); + if (iter.getBeginIndex() == iter.getEndIndex()) + continue; + + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc); + // System.out.println("StringLength=" + m_originalString.length() + " MaxWidth=" + p_maxWidth + " MaxHeight=" + p_maxHeight); + while (measurer.getPosition() < iter.getEndIndex()) + { + // no need to expand tab space for limited space + layout = measurer.nextLayout(p_maxWidth); + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + // System.out.println(" LineWidth=" + layout.getAdvance() + " LineHeight=" + lineHeight); + if (p_maxHeight == -1f && i == 0) // one line only + p_maxHeight = lineHeight; + if (p_maxHeight == 0f || (p_height + lineHeight) <= p_maxHeight) + p_height += lineHeight; + } + } // for all strings + + // Add CheckBox Size + if (m_check != null) + { + // p_width += LayoutEngine.IMAGE_SIZE.width; + if (p_height < LayoutEngine.IMAGE_SIZE.height) + p_height = LayoutEngine.IMAGE_SIZE.height; + } + // System.out.println(" Width=" + p_width + " Height=" + p_height); + } + // System.out.println("StringElement.calculate size - Width=" + // + p_width + "(" + p_maxWidth + ") - Height=" + p_height + "(" + p_maxHeight + ")"); + + // Enlarge Size when aligned and max size is given + if (p_FieldAlignmentType != null) + { + boolean changed = false; + if (p_height < p_maxHeight) + { + p_height = p_maxHeight; + changed = true; + } + if (p_width < p_maxWidth) + { + p_width = p_maxWidth; + changed = true; + } + // if (changed) + // System.out.println("StringElement.calculate size - Width=" + // + p_width + "(" + p_maxWidth + ") - Height=" + p_height + "(" + p_maxHeight + ")"); + } + return true; + } // calculateSize + + + /************************************************************************** + * Get Drill Down value + * @param relativePoint relative Point + * @param pageNo page number (ignored) + * @return if found query or null + */ + public MQuery getDrillDown (Point relativePoint, int pageNo) + { + if (m_ID != null && getBounds().contains(relativePoint)) + { + log.fine(toString()); + String columnName = MQuery.getZoomColumnName(m_ID.getName()); + String tableName = MQuery.getZoomTableName(columnName); + Object code = m_ID.getID(); + if (m_ID instanceof KeyNamePair) + code = new Integer(((KeyNamePair)m_ID).getKey()); + // + MQuery query = new MQuery(tableName); + query.addRestriction(columnName, MQuery.EQUAL, code); + return query; + } + return null; + } // getDrillDown + + /** + * Get Drill Across value + * @param relativePoint relative Point + * @param pageNo page number (ignored) + * @return null - not implemented + */ + public MQuery getDrillAcross (Point relativePoint, int pageNo) + { + // log.fine( "StringElement.getDrillAcross"); + // if (getBounds().contains(relativePoint)); + return null; + } // getDrillAcross + + + /************************************************************************** + * Paint/Print. + * Calculate actual Size. + * The text is printed in the topmost left position - i.e. the leading is below the line + * @param g2D Graphics + * @param pageStart top left Location of page + * @param pageNo page number for multi page support (0 = header/footer) - ignored + * @param ctx print context + * @param isView true if online view (IDs are links) + */ + public void paint (Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + // log.finest( "StringElement.paint", "<" + m_originalString + "> " + p_pageLocation.x + "/" + p_pageLocation.y + // + ", Clip=" + g2D.getClip() + // + ", Translate=" + g2D.getTransform().getTranslateX() + "/" + g2D.getTransform().getTranslateY() + // + ", Scale=" + g2D.getTransform().getScaleX() + "/" + g2D.getTransform().getScaleY() + // + ", Shear=" + g2D.getTransform().getShearX() + "/" + g2D.getTransform().getShearY()); + Point2D.Double location = getAbsoluteLocation(pageStart); + // + if (m_originalString != null) + translate(ctx); + + AttributedString aString = null; + AttributedCharacterIterator iter = null; + AttributedCharacterIterator iter2 = null; + float xPos = (float)location.x; + float yPos = (float)location.y; + float yPen = 0f; + float height = 0f; + float width = 0f; + // for all lines + for (int i = 0; i < m_string_paper.length; i++) + { + // Get Text + if (isView) + { + if (m_string_view[i] == null) + continue; + aString = m_string_view[i]; + } + else + { + if (m_string_paper[i] == null) + continue; + aString = m_string_paper[i]; + } + iter = aString.getIterator(); + // Zero Length + if (iter.getBeginIndex() == iter.getEndIndex()) + continue; + + + // Check for Tab (just first) and 16 bit characters + int tabPos = -1; + boolean is8Bit = true; + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '\t' && tabPos == -1) + tabPos = iter.getIndex(); + if (c > 255) + is8Bit = false; + } + + TextLayout layout = null; + float xPen = xPos; + + // No Limit + if (p_maxWidth == 0f) + { + if (tabPos == -1) + { + layout = new TextLayout (iter, g2D.getFontRenderContext()); + yPen = yPos + layout.getAscent(); + // layout.draw(g2D, xPen, yPen); + g2D.setFont(m_font); + g2D.setPaint(m_paint); + g2D.drawString(iter, xPen, yPen); + // + yPos += layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (width < layout.getAdvance()) + width = layout.getAdvance(); + } + else // we have a tab + { + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, g2D.getFontRenderContext()); + layout = measurer.nextLayout(9999, tabPos, false); + float lineHeight_1 = layout.getAscent() + layout.getDescent() + layout.getLeading(); + yPen = yPos + layout.getAscent(); + layout.draw(g2D, xPen, yPen); // first part before tab + xPen = getTabPos (xPos, layout.getAdvance()); + float lineWidth = xPen - xPos; + layout = measurer.nextLayout(9999);//, iter.getEndIndex(), true); + float lineHeight_2 = layout.getAscent() + layout.getDescent() + layout.getLeading(); + layout.draw(g2D, xPen, yPen); // second part after tab + // + yPos += Math.max(lineHeight_1, lineHeight_2); + lineWidth += layout.getAdvance(); + if (width < lineWidth) + width = lineWidth; + } + // log.finest( "StringElement.paint - No Limit - " + location.x + "/" + yPos + // + " w=" + layout.getAdvance() + ",h=" + lineHeight + ", Bounds=" + layout.getBounds()); + } + // Size Limits + else + { + boolean fastDraw = LayoutEngine.s_FASTDRAW; + if (fastDraw && !isView && !is8Bit) + fastDraw = false; + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, g2D.getFontRenderContext()); + while (measurer.getPosition() < iter.getEndIndex()) + { + if (tabPos == -1) + { + layout = measurer.nextLayout(p_maxWidth); + if (iter.getEndIndex() != measurer.nextOffset(p_maxWidth)) + fastDraw = false; + } + else // tab + { + fastDraw = false; + layout = measurer.nextLayout(p_maxWidth, tabPos, false); + } + // Line Height + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (p_maxHeight == -1f && i == 0) // one line only + p_maxHeight = lineHeight; + // If we have hight left over + if (p_maxHeight == 0f || (height + lineHeight) <= p_maxHeight) + { + yPen = (float)location.y + height + layout.getAscent(); + // Tab in Text + if (tabPos != -1) + { + layout.draw(g2D, xPen, yPen); // first part before tab + xPen = getTabPos (xPos, layout.getAdvance()); + layout = measurer.nextLayout(p_width, iter.getEndIndex(), true); + tabPos = -1; // reset (just one tab) + } + else if ((MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight.equals(p_FieldAlignmentType) && layout.isLeftToRight()) + || (MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft.equals(p_FieldAlignmentType) && !layout.isLeftToRight())) + xPen += p_maxWidth - layout.getAdvance(); + else if (MPrintFormatItem.FIELDALIGNMENTTYPE_Center.equals(p_FieldAlignmentType)) + xPen += (p_maxWidth - layout.getAdvance()) / 2; + else if (MPrintFormatItem.FIELDALIGNMENTTYPE_Block.equals(p_FieldAlignmentType) && measurer.getPosition() < iter.getEndIndex()) + { + layout = layout.getJustifiedLayout(p_maxWidth); + fastDraw = false; + } + if (fastDraw) + { + g2D.setFont(m_font); + g2D.setPaint(m_paint); + g2D.drawString(iter, xPen, yPen); + } + else + { + layout.draw(g2D, xPen, yPen); + } + height += lineHeight; + // log.finest( "StringElement.paint - Limit - " + xPen + "/" + yPen + // + " w=" + layout.getAdvance() + ",h=" + lineHeight + ", Align=" + p_FieldAlignmentType + ", Max w=" + p_maxWidth + ",h=" + p_maxHeight + ", Bounds=" + layout.getBounds()); + } + } + width = p_maxWidth; + } // size limits + } // for all strings + if (m_check != null) + { + int x = (int)(location.x + width + 1); + int y = (int)(location.y); + g2D.drawImage(m_check.booleanValue() ? LayoutEngine.IMAGE_TRUE : LayoutEngine.IMAGE_FALSE, x, y, this); + } + } // paint + + /** + * Get Tab Position. + * The Tab position is relative to the string itself, not the absolute + * position; i.e. to have the same tab position on a page, strings need + * to start at the same position. + * The Tab is rounded up to the next 30 dividable position. + * @param xPos starting x position + * @param length length of segment + * @return new x Position (xPos + length + tabSpace) + */ + private float getTabPos (float xPos, float length) + { + float retValue = xPos + length; + int iLength = (int)Math.ceil(length); + int tabSpace = iLength % 30; + retValue += (30 - tabSpace); + return retValue; + } // getTabPos + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("StringElement["); + 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).append(" - "); + for (int i = 0; i < m_string_paper.length; i++) + { + if (m_string_paper.length > 1) + sb.append(Env.NL).append(i).append(":"); + AttributedCharacterIterator iter = m_string_paper[i].getIterator(); + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + } + if (m_ID != null) + sb.append(",ID=(").append(m_ID.toStringX()).append(")"); + sb.append("]"); + return sb.toString(); + } // toString + +} // StringElement diff --git a/print/src/org/compiere/print/layout/TableElement.java b/print/src/org/compiere/print/layout/TableElement.java new file mode 100644 index 0000000000..c5186683cd --- /dev/null +++ b/print/src/org/compiere/print/layout/TableElement.java @@ -0,0 +1,1550 @@ +/****************************************************************************** + * 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.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.*; +import java.util.logging.*; +import java.util.regex.*; + +import org.compiere.model.*; +import org.compiere.print.*; +import org.compiere.util.*; + +/** + * Table Print Element. + * Maintains a logical cross page table, which is "broken up" when printing + *
+ *  The table is 3 pages wide, 2 pages high
+ * 		+-----+-----+-----+
+ *      | 1.1 | 1.2 | 1.3 |
+ * 		+-----+-----+-----+
+ *      | 2.1 | 2.2 | 2.3 |
+ * 		+-----+-----+-----+
+ *  Printed
+ * 		+-----+-----+-----+
+ *      |  1  |  2  |  3  |
+ * 		+-----+-----+-----+
+ *      |  4  |  5  |  6  |
+ * 		+-----+-----+-----+
+ *  
+ * @author Jorg Janke + * @version $Id: TableElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $ + */ +public class TableElement extends PrintElement +{ + /** + * Constructor. + * Created in LayoutEngine. + * The rowCol.. maps are organized as follows - Point (row,col) + * row - data if 0..m - if -1 for the entire column + * column - data if 0..n - if -1 for the entire row + * i.e. Point (-1, -1) is the default for the table + * + * @param columnHeader array with column headers (Key=ColumnName) + * @param columnMaxWidth array with column max width - 0=no restrictions - negative=supress if null + * @param columnMaxHeight array with row max height for a column - 0=no restrictions; -1=one row only + * @param columnJustification field justification for column + * + * @param fixedWidth array with column fixed width + * @param functionRows list of function rows + * @param multiLineHeader if true, the header is not truncated at maxWidth + * + * @param data 2D array with data to be printed [row][col] + * @param pk array of primary keys + * @param pkColumnName primary key name + * + * @param pageNoStart page number of starting page + * @param firstPage bounds on first page + * @param nextPages bounds on following pages + * @param repeatedColumns repeat first x columns on - X Axis follow pages + * @param additionalLines map of old colum to below printed column + * + * @param rowColFont HashMap with Point as key with Font overwrite + * @param rowColColor HashMap with Point as key with foreground Color overwrite + * @param rowColBackground HashMap with Point as key with background Color overwrite + * @param tFormat table format + * @param pageBreak Arraylist of rows with page break + */ + public TableElement (ValueNamePair[] columnHeader, + int[] columnMaxWidth, int[] columnMaxHeight, String[] columnJustification, + boolean[] fixedWidth, ArrayList functionRows, boolean multiLineHeader, + Object[][] data, KeyNamePair[] pk, String pkColumnName, + int pageNoStart, Rectangle firstPage, Rectangle nextPages, int repeatedColumns, HashMap additionalLines, + HashMap rowColFont, HashMap rowColColor, HashMap rowColBackground, + MPrintTableFormat tFormat, ArrayList pageBreak) + { + super(); + log.fine("Cols=" + columnHeader.length + ", Rows=" + data.length); + m_columnHeader = columnHeader; + m_columnMaxWidth = columnMaxWidth; + m_columnMaxHeight = columnMaxHeight; + m_columnJustification = columnJustification; + m_functionRows = functionRows; + m_fixedWidth = fixedWidth; + // + m_multiLineHeader = multiLineHeader; + m_data = data; + m_pk = pk; + m_pkColumnName = pkColumnName; + // + m_pageNoStart = pageNoStart; + m_firstPage = firstPage; + m_nextPages = nextPages; + m_repeatedColumns = repeatedColumns; + m_additionalLines = additionalLines; + // Used Fonts,Colots + Point pAll = new Point (ALL, ALL); + m_rowColFont = rowColFont; + m_baseFont = (Font)m_rowColFont.get(pAll); + if (m_baseFont == null) + m_baseFont = new Font(null); + m_rowColColor = rowColColor; + m_baseColor = (Color)m_rowColColor.get(pAll); + if (m_baseColor == null) + m_baseColor = Color.black; + m_rowColBackground = rowColBackground; + m_baseBackground = (Color)m_rowColBackground.get(pAll); + if (m_baseBackground == null) + m_baseBackground = Color.white; + m_tFormat = tFormat; + + // Page Break - not two after each other + m_pageBreak = pageBreak; + for (int i = 0; i < m_pageBreak.size(); i++) + { + Integer row = (Integer)m_pageBreak.get(i); + while ((i + 1) < m_pageBreak.size()) + { + Integer nextRow = (Integer)m_pageBreak.get(i+1); + if ((row.intValue()+1) == nextRow.intValue()) + { + log.fine("- removing PageBreak row=" + row); + m_pageBreak.remove(i); + row = nextRow; + } + else + break; + } + } // for all page breaks + + // Load Image + waitForLoad(LayoutEngine.IMAGE_TRUE); + waitForLoad(LayoutEngine.IMAGE_FALSE); + } // TableElement + + /** Column Headers */ + private ValueNamePair[] m_columnHeader; + /** Max column widths */ + private int[] m_columnMaxWidth; + /** Max row height per column */ + private int[] m_columnMaxHeight; + /** Field Justification for Column */ + private String[] m_columnJustification; + /** True if column fixed length */ + private boolean[] m_fixedWidth; + /** Create multiple header lines if required */ + private boolean m_multiLineHeader; + /** List of Function Rows */ + private ArrayList m_functionRows; + /** The Data */ + private Object[][] m_data; + /** Primary Keys */ + private KeyNamePair[] m_pk; + /** Primary Key Column Name */ + private String m_pkColumnName; + /** Starting page Number */ + private int m_pageNoStart; + /** Bounds of first Page */ + private Rectangle m_firstPage; + /** Bounds of next Pages */ + private Rectangle m_nextPages; + + /** repeat first x columns on - X Axis follow pages */ + private int m_repeatedColumns; + + /** base font for table */ + private Font m_baseFont; + /** HashMap with Point as key with Font overwrite */ + private HashMap m_rowColFont; + /** base foreground color for table */ + private Color m_baseColor; + /** HashMap with Point as key with foreground Color overwrite */ + private HashMap m_rowColColor; + /** base color for table */ + private Color m_baseBackground; + /** HashMap with Point as key with background Color overwrite */ + private HashMap m_rowColBackground; + /** Format of Table */ + private MPrintTableFormat m_tFormat; + /** Page Break Rows */ + private ArrayList m_pageBreak; + + + /** width of columns (float) */ + private ArrayList m_columnWidths = new ArrayList(); + /** height of rows (float) */ + private ArrayList m_rowHeights = new ArrayList(); + /** height of header */ + private int m_headerHeight = 0; + + /** first data row number per page */ + private ArrayList m_firstRowOnPage = new ArrayList(); + /** first column number per -> page */ + private ArrayList m_firstColumnOnPage = new ArrayList(); + /** Height of page */ + private ArrayList m_pageHeight = new ArrayList(); + + /** Key: Point(row,col) - Value: NamePair */ + private HashMap m_rowColDrillDown = new HashMap(); + + + /** Key: Integer (original Column) - Value: Integer (below column) */ + private HashMap m_additionalLines; + + /*************************************************************************/ + + /** Header Row Indicator */ + public static final int HEADER_ROW = -2; + /** Header Row Indicator */ + public static final int ALL = -1; + + /** Horizontal - GAP between text & line */ + private static final int H_GAP = 2; + /** Vertical | GAP between text & line */ + private static final int V_GAP = 2; + + /** Debug Print Paint */ + private static final boolean DEBUG_PRINT = false; + + + /************************************************************************** + * Layout and Calculate Size. + * Set p_width & p_height + * @return true if calculated + */ + protected boolean calculateSize() + { + if (p_sizeCalculated) + return true; + + p_width = 0; + m_printRows = new ArrayList>>(m_data.length); // reset + + // Max Column Width = 50% of available width (used if maxWidth not set) + float dynMxColumnWidth = m_firstPage.width / 2; + + // Width caolculation + int rows = m_data.length; + int cols = m_columnHeader.length; + // Data Sizes and Header Sizes + Dimension2DImpl[][] dataSizes = new Dimension2DImpl[rows][cols]; + Dimension2DImpl[] headerSizes = new Dimension2DImpl[cols]; + FontRenderContext frc = new FontRenderContext(null, true, true); + + // data columns - rows + for (int dataCol = 0; dataCol < cols; dataCol++) + { + int col = dataCol; + // Print below existing column + if (m_additionalLines.containsKey(new Integer(dataCol))) + { + col = ((Integer)m_additionalLines.get(new Integer(dataCol))).intValue(); + log.finest("DataColumn=" + dataCol + ", BelowColumn=" + col); + } + float colWidth = 0; + for (int row = 0; row < rows; row++) + { + Object dataItem = m_data[row][dataCol]; + if (dataItem == null) + { + dataSizes[row][dataCol] = new Dimension2DImpl(); + continue; + } + String string = dataItem.toString(); + if (string.length() == 0) + { + dataSizes[row][dataCol] = new Dimension2DImpl(); + continue; + } + Font font = getFont(row, dataCol); + + // Print below existing column = (col != dataCol) + addPrintLines(row, col, dataItem); + dataSizes[row][dataCol] = new Dimension2DImpl(); // don't print + + if (dataItem instanceof Boolean) + { + dataSizes[row][col].addBelow(LayoutEngine.IMAGE_SIZE); + continue; + } + else if (dataItem instanceof ImageElement) + { + dataSizes[row][col].addBelow( + new Dimension((int)((ImageElement)dataItem).getWidth(), + (int)((ImageElement)dataItem).getHeight())); + continue; + } + else if (dataItem instanceof BarcodeElement) + { + dataSizes[row][col].addBelow( + new Dimension((int)((BarcodeElement)dataItem).getWidth(), + (int)((BarcodeElement)dataItem).getHeight())); + continue; + } + // No Width Limitations + if (m_columnMaxWidth[col] == 0 || m_columnMaxWidth[col] == -1) + { + // if (HTMLElement.isHTML(string)) + // log.finest( "HTML (no) r=" + row + ",c=" + dataCol); + TextLayout layout = new TextLayout (string, font, frc); + float width = layout.getAdvance() + 2; // buffer + float height = layout.getAscent() + + layout.getDescent() + + layout.getLeading(); + if (width > dynMxColumnWidth) + m_columnMaxWidth[col] = (int)Math.ceil(dynMxColumnWidth); + else if (colWidth < width) + colWidth = width; + if (dataSizes[row][col] == null) + { + dataSizes[row][col] = new Dimension2DImpl(); + log.log(Level.WARNING, "No Size for r=" + row + ",c=" + col); + } + dataSizes[row][col].addBelow(width, height); + } + // Width limitations + if (m_columnMaxWidth[col] != 0 && m_columnMaxWidth[col] != -1) + { + float height = 0; + // + if (HTMLElement.isHTML(string)) + { + // log.finest( "HTML (limit) r=" + row + ",c=" + dataCol); + HTMLRenderer renderer = HTMLRenderer.get(string); + colWidth = renderer.getWidth(); + if (m_columnMaxHeight[col] == -1) // one line only + height = renderer.getHeightOneLine(); + else + height = renderer.getHeight(); + renderer.setAllocation((int)colWidth, (int)height); + // log.finest( "calculateSize HTML - " + renderer.getAllocation()); + m_data[row][dataCol] = renderer; // replace for printing + } + else + { + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(string); + for (int lineNo = 0; lineNo < lines.length; lineNo++) + { + AttributedString aString = new AttributedString(lines[lineNo]); + aString.addAttribute(TextAttribute.FONT, font); + AttributedCharacterIterator iter = aString.getIterator(); + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc); + while (measurer.getPosition() < iter.getEndIndex()) + { + TextLayout layout = measurer.nextLayout(Math.abs(m_columnMaxWidth[col])); + float width = layout.getAdvance(); + if (colWidth < width) + colWidth = width; + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (m_columnMaxHeight[col] == -1) // one line only + { + height = lineHeight; + break; + } + else if (m_columnMaxHeight[col] == 0 || (height + lineHeight) <= m_columnMaxHeight[col]) + height += lineHeight; + } + } // for all lines + } + if (m_fixedWidth[col]) + colWidth = Math.abs(m_columnMaxWidth[col]); + dataSizes[row][col].addBelow(colWidth, height); + } + dataSizes[row][col].roundUp(); + if (dataItem instanceof NamePair) + m_rowColDrillDown.put(new Point(row, col), (NamePair)dataItem); + // + log.finest("Col=" + col + ", row=" + row + + " => " + dataSizes[row][col] + " - ColWidth=" + colWidth); + } // for all data rows + + // Column Width for Header + String string = ""; + if (m_columnHeader[dataCol] != null) + string = m_columnHeader[dataCol].toString(); + + // Print below existing column + if (col != dataCol) + headerSizes[dataCol] = new Dimension2DImpl(); + else if (colWidth == 0 && m_columnMaxWidth[dataCol] < 0 // suppress Null + || string.length() == 0) + headerSizes[dataCol] = new Dimension2DImpl(); + else + { + Font font = getFont(HEADER_ROW, dataCol); + if (!font.isBold()) + font = new Font(font.getName(), Font.BOLD, font.getSize()); + // No Width Limitations + if (m_columnMaxWidth[dataCol] == 0 || m_columnMaxWidth[dataCol] == -1 || !m_multiLineHeader) + { + TextLayout layout = new TextLayout (string, font, frc); + float width = layout.getAdvance() + 3; // buffer + float height = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (width > dynMxColumnWidth) + m_columnMaxWidth[dataCol] = (int)Math.ceil(dynMxColumnWidth); + else if (colWidth < width) + colWidth = width; + headerSizes[dataCol] = new Dimension2DImpl(width, height); + } + // Width limitations + if (m_columnMaxWidth[dataCol] != 0 && m_columnMaxWidth[dataCol] != -1) + { + float height = 0; + // + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(string); + for (int lineNo = 0; lineNo < lines.length; lineNo++) + { + AttributedString aString = new AttributedString(lines[lineNo]); + aString.addAttribute(TextAttribute.FONT, font); + AttributedCharacterIterator iter = aString.getIterator(); + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc); + colWidth = Math.abs(m_columnMaxWidth[dataCol]); + while (measurer.getPosition() < iter.getEndIndex()) + { + TextLayout layout = measurer.nextLayout(colWidth); + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (!m_multiLineHeader) // one line only + { + height = lineHeight; + break; + } + else if (m_columnMaxHeight[dataCol] == 0 + || (height + lineHeight) <= m_columnMaxHeight[dataCol]) + height += lineHeight; + } + } // for all header lines + headerSizes[dataCol] = new Dimension2DImpl(colWidth, height); + } + + } // headerSize + headerSizes[dataCol].roundUp(); + colWidth = (float)Math.ceil(colWidth); + // System.out.println("Col=" + dataCol + " => " + headerSizes[dataCol]); + + // Round Column Width + if (dataCol == 0) + colWidth += m_tFormat.getVLineStroke().floatValue(); + if (colWidth != 0) + colWidth += (2*H_GAP) + m_tFormat.getVLineStroke().floatValue(); + + // Print below existing column + if (col != dataCol) + { + m_columnWidths.add(new Float(0.0)); // for the data column + Float origWidth = (Float)m_columnWidths.get(col); + if (origWidth == null) + log.log(Level.SEVERE, "Column " + dataCol + " below " + col + " - no value for orig width"); + else + { + if (origWidth.compareTo(new Float(colWidth)) >= 0) + { + log.finest("Same Width - Col=" + col + + " - OrigWidth=" + origWidth + " - Width=" + colWidth + " - Total=" + p_width); + } + else + { + m_columnWidths.set(col, new Float(colWidth)); + p_width += (colWidth - origWidth.floatValue()); + log.finest("New Width - Col=" + col + + " - OrigWidth=" + origWidth + " - Width=" + colWidth + " - Total=" + p_width); + } + } + } + // Add new Column + else + { + m_columnWidths.add(new Float(colWidth)); + p_width += colWidth; + log.finest("Width - Col=" + dataCol + + " - Width=" + colWidth + " - Total=" + p_width); + } + } // for all columns + + // Height ********** + p_height = 0; + for (int row = 0; row < rows; row++) + { + float rowHeight = 0f; + for (int col = 0; col < cols; col++) + { + if (dataSizes[row][col].height > rowHeight) // max + rowHeight = (float)dataSizes[row][col].height; + } // for all columns + rowHeight += m_tFormat.getLineStroke().floatValue() + (2*V_GAP); + m_rowHeights.add(new Float(rowHeight)); + p_height += rowHeight; + } // for all rows + // HeaderRow + m_headerHeight = 0; + for (int col = 0; col < cols; col++) + { + if (headerSizes[col].height > m_headerHeight) + m_headerHeight = (int)headerSizes[col].height; + } // for all columns + m_headerHeight += (4*m_tFormat.getLineStroke().floatValue()) + (2*V_GAP); // Thick lines + p_height += m_headerHeight; + + + // Page Layout ******************************************************* + + log.fine("FirstPage=" + m_firstPage + ", NextPages=" + m_nextPages); + // One Page on Y | Axis + if (m_firstPage.height >= p_height && m_pageBreak.size() == 0) + { + log.finest("Page Y=1 - PageHeight=" + m_firstPage.height + " - TableHeight=" + p_height); + m_firstRowOnPage.add(new Integer(0)); // Y + m_pageHeight.add(new Float(p_height)); // Y index only + } + // multiple pages on Y | Axis + else + { + float availableHeight = 0f; + float usedHeight = 0f; + boolean firstPage = true; + int addlRows = 0; + // for all rows + for (int dataRow = 0; dataRow < m_rowHeights.size(); dataRow++) + { + float rowHeight = ((Float)m_rowHeights.get(dataRow)).floatValue(); + // Y page break before + boolean pageBreak = isPageBreak(dataRow); + if (!pageBreak && availableHeight < rowHeight) + { + if (availableHeight > 40 && rowHeight > 40) + { + log.finest("- Split (leave on current) Row=" + dataRow + + " - Available=" + availableHeight + ", RowHeight=" + rowHeight); + // if (splitRow (dataRow)) + // addlRows += 1; + } + // else + pageBreak = true; + } + if (pageBreak) + { + availableHeight = firstPage ? m_firstPage.height : m_nextPages.height; + m_firstRowOnPage.add(new Integer(dataRow+addlRows)); // Y + if (!firstPage) + { + m_pageHeight.add(new Float(usedHeight)); // Y index only + log.finest("Page Y=" + m_pageHeight.size() + + " - PageHeight=" + usedHeight); + } + log.finest("Page Y=" + m_firstRowOnPage.size() + + " - Row=" + dataRow + " - force=" + isPageBreak(dataRow)); + firstPage = false; + // + availableHeight -= m_headerHeight; + usedHeight += m_headerHeight; + } + availableHeight -= rowHeight; + usedHeight += rowHeight; + if (availableHeight < 0) + { + log.finest("- Split (move to next) Row=" + dataRow + + " - Available=" + availableHeight + ", RowHeight=" + rowHeight); + + } + log.finest("Page Y=" + m_pageHeight.size() + + ", Row=" + dataRow + ",AddlRows=" + addlRows + ", Height=" + rowHeight + + " - Available=" + availableHeight + ", Used=" + usedHeight); + } // for all rows + m_pageHeight.add(new Float(usedHeight)); // Y index only + log.finest("Page Y=" + m_pageHeight.size() + + " - PageHeight=" + usedHeight); + } // multiple Y | pages + + // One page on - X Axis + if (m_firstPage.width >= p_width) + { + log.finest("Page X=1 - PageWidth=" + m_firstPage.width + + " - TableWidth=" + p_width); + m_firstColumnOnPage.add(new Integer(0)); // X + // + distributeColumns (m_firstPage.width-(int)p_width, 0, m_columnWidths.size()); + } + // multiple pages on - X Axis + else + { + int availableWidth = 0; + int lastStart = 0; + for (int col = 0; col < m_columnWidths.size(); col++) + { + int columnWidth = ((Float)m_columnWidths.get(col)).intValue(); + // X page preak + if (availableWidth < columnWidth) + { + if (col != 0) + distributeColumns (availableWidth, lastStart, col); + // + m_firstColumnOnPage.add(new Integer(col)); // X + log.finest("Page X=" + m_firstColumnOnPage.size() + + " - Col=" + col); + lastStart = col; + availableWidth = m_firstPage.width; // Width is the same on all pages + // + for (int repCol = 0; repCol < m_repeatedColumns && col > repCol; repCol++) + { + float repColumnWidth = ((Float)m_columnWidths.get(repCol)).floatValue(); + // leave 50% of space available for non repeated columns + if (availableWidth < m_firstPage.width * 0.5) + break; + availableWidth -= repColumnWidth; + } + } // pageBreak + availableWidth -= columnWidth; + } // for acc columns + } // multiple - X pages + + // Last row Lines + p_height += m_tFormat.getLineStroke().floatValue(); // last fat line + + log.fine("Pages=" + getPageCount() + + " X=" + m_firstColumnOnPage.size() + "/Y=" + m_firstRowOnPage.size() + + " - Width=" + p_width + ", Height=" + p_height); + return true; + } // calculateSize + + + /************************************************************************** + * Distribute Columns to fill page + * @param availableWidth width to distribute + * @param fromCol start column + * @param toCol end column (not included) + */ + private void distributeColumns (int availableWidth, int fromCol, int toCol) + { + log.finest("Available=" + availableWidth + ", Columns " + fromCol + "->" + toCol); + int start = fromCol; + if (fromCol == 0 && m_repeatedColumns > 0) + start = m_repeatedColumns; + // calculate total Width + int totalWidth = availableWidth; + for (int col = start; col < toCol; col++) + totalWidth += ((Float)m_columnWidths.get(col)).floatValue(); + int remainingWidth = availableWidth; + // distribute proportionally (does not increase zero width columns) + for (int x = 0; remainingWidth > 0 && x < 5; x++) // max 4 iterations + { + log.finest("TotalWidth=" + totalWidth + ", Remaining=" + remainingWidth); + for (int col = start; col < toCol && remainingWidth != 0; col++) + { + int columnWidth = ((Float)m_columnWidths.get(col)).intValue(); + if (columnWidth != 0) + { + int additionalPart = columnWidth * availableWidth / totalWidth; + if (remainingWidth < additionalPart) + { + m_columnWidths.set(col, new Float(columnWidth+remainingWidth)); + remainingWidth = 0; + } + else + { + m_columnWidths.set(col, new Float(columnWidth+additionalPart)); + remainingWidth -= additionalPart; + } + log.finest(" col=" + col + " - From " + columnWidth + " to " + m_columnWidths.get(col)); + } + } + } + // add remainder to last non 0 width column + for (int c = toCol-1; remainingWidth != 0 && c >=0; c--) + { + int columnWidth = ((Float)m_columnWidths.get(c)).intValue(); + if (columnWidth > 0) + { + m_columnWidths.set(c, new Float(columnWidth+remainingWidth)); + log.finest("Final col=" + c + " - From " + columnWidth + " to " + m_columnWidths.get(c)); + remainingWidth = 0; + } + } + } // distribute Columns + + /** + * Check for for PageBreak + * @param row current row + * @return true if row should be on new page + */ + private boolean isPageBreak (int row) + { + for (int i = 0; i < m_pageBreak.size(); i++) + { + Integer rr = (Integer)m_pageBreak.get(i); + if (rr.intValue()+1 == row) + return true; + else if (rr.intValue() > row) + return false; + } + return false; + } // isPageBreak + + /** + * For Multi-Page Tables, set Height to Height of last Page + */ + public void setHeightToLastPage() + { + int lastLayoutPage = getPageCount() + m_pageNoStart - 1; + log.fine("PageCount - Table=" + getPageCount() + + "(Start=" + m_pageNoStart + + ") Layout=" + lastLayoutPage + + " - Old Height=" + p_height); + p_height = getHeight(lastLayoutPage); + log.fine("New Height=" + p_height); + } // setHeightToLastPage + + + /************************************************************************** + * Get Font. + * Based on Point (row,col). + *
+	 *  Examples:
+	 * 	  From general to specific:
+	 *      (-1,-1) => for entire table
+	 *  	(-1, c) => for entire column c
+	 *  	(r, -1) => for entire row r (overwrites column)
+	 *      (r, c)  => for specific cell (highest priority)
+	 *    Header is row -2
+	 * 		(-2,-1) => for all header columns
+	 * 		(-2, c) => for header column c
+	 *  
+ * @param row row + * @param col column + * @return Font for row/col + */ + private Font getFont (int row, int col) + { + // First specific position + Font font = (Font)m_rowColFont.get(new Point(row, col)); + if (font != null) + return font; + // Row Next + font = (Font)m_rowColFont.get(new Point (row, ALL)); + if (font != null) + return font; + // Column then + font = (Font)m_rowColFont.get(new Point (ALL, col)); + if (font != null) + return font; + // default + return m_baseFont; + } // getFont + + /** + * Get Foreground Color. + * @param row row + * @param col column + * @return Color for row/col + */ + private Color getColor (int row, int col) + { + // First specific position + Color color = (Color)m_rowColColor.get(new Point(row, col)); + if (color != null) + return color; + // Row Next + color = (Color)m_rowColColor.get(new Point (row, ALL)); + if (color != null) + return color; + // Column then + color = (Color)m_rowColColor.get(new Point (ALL, col)); + if (color != null) + return color; + // default + return m_baseColor; + } // getFont + + /** + * Get Foreground Color. + * @param row row + * @param col column + * @return Color for row/col + */ + private Color getBackground (int row, int col) + { + // First specific position + Color color = (Color)m_rowColBackground.get(new Point(row, col)); + if (color != null) + return color; + // Row Next + color = (Color)m_rowColBackground.get(new Point (row, ALL)); + if (color != null) + return color; + // Column then + color = (Color)m_rowColBackground.get(new Point (ALL, col)); + if (color != null) + return color; + // default + return m_baseBackground; + } // getFont + + + /************************************************************************** + * Get Calculated Height on page + * @param pageNo layout page number + * @return Height + */ + public float getHeight (int pageNo) + { + int pageIndex = getPageIndex(pageNo); + int pageYindex = getPageYIndex(pageIndex); + log.fine("Page=" + pageNo + " - PageIndex=" + pageIndex + + ", PageYindex=" + pageYindex); + float pageHeight = ((Float)m_pageHeight.get(pageYindex)).floatValue(); + float pageHeightPrevious = 0f; + if (pageYindex > 0) + pageHeightPrevious = ((Float)m_pageHeight.get(pageYindex-1)).floatValue(); + float retValue = pageHeight - pageHeightPrevious; + log.fine("Page=" + pageNo + " - PageIndex=" + pageIndex + ", PageYindex=" + pageYindex + ", Height=" + String.valueOf(retValue)); + return retValue; + } // getHeight + + /** + * Get Calculated Height on page + * @param pageNo page number + * @return Height + */ + public float getWidth (int pageNo) + { + int pageIndex = getPageIndex(pageNo); + if (pageIndex == 0) + return m_firstPage.width; + return m_nextPages.width; + } // getHeight + + + /************************************************************************** + * Get number of "real" pages. + * @return page count + */ + public int getPageCount() + { + return m_firstRowOnPage.size() * m_firstColumnOnPage.size(); + } // getPageCount + + /** + * Get zero based Page Index within Layout + * @param pageNo real page no + * @return page index + */ + protected int getPageIndex (int pageNo) + { + int index = pageNo - m_pageNoStart; + if (index < 0) + log.log(Level.SEVERE, "index=" + index, new Exception()); + return index; + } // getPageIndex + + /** + * Get "real" page Number within Layout + * @param pageIndex zero based page index + * @return page number + */ + private int getPageNo (int pageIndex) + { + return pageIndex + m_pageNoStart; + } // getPageNo + + + /************************************************************************** + * Get X - Page Index. + * Zero Based; Page No is the "real" page No + *
+	 *  The table is 3 pages wide, 2 pages high - index
+	 * 		+-----+-----+-----+
+	 *      | 0.0 | 0.1 | 0.2 |
+	 * 		+-----+-----+-----+
+	 *      | 1.0 | 1.1 | 1.2 |
+	 * 		+-----+-----+-----+
+	 *  Page Index
+	 * 		+-----+-----+-----+
+	 *      |  0  |  1  |  2  |
+	 * 		+-----+-----+-----+
+	 *      |  3  |  4  |  5  |
+	 * 		+-----+-----+-----+
+	 *  
+ * @param pageIndex zero based page index + * @return page index on X axis + */ + protected int getPageXIndex (int pageIndex) + { + int noXpages = m_firstColumnOnPage.size(); + // int noYpages = m_firstRowOnPage.size(); + int x = pageIndex % noXpages; + return x; + } // getPageXIndex + + /** + * Get X - Page Count + * @return X page count + */ + protected int getPageXCount () + { + return m_firstColumnOnPage.size(); + } // getPageXCount + + /** + * Get Y | Page Index. + * Zero Based; Page No is the "real" page No + *
+	 *  The table is 3 pages wide, 2 pages high - index
+	 * 		+-----+-----+-----+
+	 *      | 0.0 | 0.1 | 0.2 |
+	 * 		+-----+-----+-----+
+	 *      | 1.0 | 1.1 | 1.2 |
+	 * 		+-----+-----+-----+
+	 *  Page Index
+	 * 		+-----+-----+-----+
+	 *      |  0  |  1  |  2  |
+	 * 		+-----+-----+-----+
+	 *      |  3  |  4  |  5  |
+	 * 		+-----+-----+-----+
+	 *  
+ * @param pageIndex zero based page index + * @return page index on Y axis + */ + protected int getPageYIndex (int pageIndex) + { + int noXpages = m_firstColumnOnPage.size(); + // int noYpages = m_firstRowOnPage.size(); + int y = (pageIndex - (pageIndex % noXpages)) / noXpages; + return y; + } // getPageYIndex + + /** + * Get Y | Page Count + * @return Y page count + */ + protected int getPageYCount () + { + return m_firstRowOnPage.size(); + } // getPageYCount + + + /************************************************************************** + * Get Drill Down value + * @param relativePoint relative Point + * @param pageNo page number + * @return if found Qyery or null + */ + public MQuery getDrillDown (Point relativePoint, int pageNo) + { + if (m_rowColDrillDown.size() == 0) + return null; + if (!getBounds(pageNo).contains(relativePoint)) + return null; + int row = getRow (relativePoint.y, pageNo); + if (row == -1) + return null; + int col = getCol (relativePoint.x, pageNo); + if (col == -1) + return null; + log.fine("Row=" + row + ", Col=" + col + ", PageNo=" + pageNo); + // + NamePair pp = (NamePair)m_rowColDrillDown.get(new Point(row,col)); + if (pp == null) + return null; + String columnName = MQuery.getZoomColumnName(m_columnHeader[col].getID()); + String tableName = MQuery.getZoomTableName(columnName); + Object code = pp.getID(); + if (pp instanceof KeyNamePair) + code = new Integer(((KeyNamePair)pp).getKey()); + // + MQuery query = new MQuery(tableName); + query.addRestriction(columnName, MQuery.EQUAL, code, null, pp.toString()); + return query; + } // getDrillDown + + /** + * Get Drill Across value + * @param relativePoint relative Point + * @param pageNo page number + * @return if found Query or null + */ + public MQuery getDrillAcross (Point relativePoint, int pageNo) + { + if (!getBounds(pageNo).contains(relativePoint)) + return null; + int row = getRow (relativePoint.y, pageNo); + if (row == -1) + return null; + log.fine("Row=" + row + ", PageNo=" + pageNo); + // + if (m_pk[row] == null) // FunctionRows + return null; + return MQuery.getEqualQuery(m_pkColumnName, m_pk[row].getKey()); + } // getDrillAcross + + /** + * Get relative Bounds of Element. + * (entire page, not just used portion) + * @param pageNo pageNo + * @return bounds relative position on page + */ + public Rectangle getBounds(int pageNo) + { + int pageIndex = getPageIndex(pageNo); + int pageYindex = getPageYIndex(pageIndex); + if (pageYindex == 0) + return m_firstPage; + else + return m_nextPages; + } // getBounds + + + /** + * Get Row for yPos + * @param yPos y position (page relative) + * @param pageNo page number + * @return row index or -1 + */ + private int getRow (int yPos, int pageNo) + { + int pageIndex = getPageIndex(pageNo); + int pageYindex = getPageYIndex(pageIndex); + // + int curY = (pageYindex == 0 ? m_firstPage.y : m_nextPages.y) + m_headerHeight; + if (yPos < curY) + return -1; // above + // + int firstRow = ((Integer)m_firstRowOnPage.get(pageYindex)).intValue(); + int nextPageRow = m_data.length; // no of rows + if (pageYindex+1 < m_firstRowOnPage.size()) + nextPageRow = ((Integer)m_firstRowOnPage.get(pageYindex+1)).intValue(); + // + for (int row = firstRow; row < nextPageRow; row++) + { + int rowHeight = ((Float)m_rowHeights.get(row)).intValue(); // includes 2*Gaps+Line + if (yPos >= curY && yPos < (curY + rowHeight)) + return row; + curY += rowHeight; + } + // below + return -1; + } // getRow + + /** + * Get Column for xPos + * @param xPos x position (page relative) + * @param pageNo page number + * @return column index or -1 + */ + private int getCol (int xPos, int pageNo) + { + int pageIndex = getPageIndex(pageNo); + int pageXindex = getPageXIndex(pageIndex); + // + int curX = pageXindex == 0 ? m_firstPage.x : m_nextPages.x; + if (xPos < curX) + return -1; // too left + + int firstColumn = ((Integer)m_firstColumnOnPage.get(pageXindex)).intValue(); + int nextPageColumn = m_columnHeader.length; // no of cols + if (pageXindex+1 < m_firstColumnOnPage.size()) + nextPageColumn = ((Integer)m_firstColumnOnPage.get(pageXindex+1)).intValue(); + + // fixed volumns + int regularColumnStart = firstColumn; + for (int col = 0; col < m_repeatedColumns; col++) + { + int colWidth = ((Float)m_columnWidths.get(col)).intValue(); // includes 2*Gaps+Line + if (xPos >= curX && xPos < (curX + colWidth)) + return col; + curX += colWidth; + if (regularColumnStart == col) + regularColumnStart++; + } + // regular columns + for (int col = regularColumnStart; col < nextPageColumn; col++) + { + int colWidth = ((Float)m_columnWidths.get(col)).intValue(); // includes 2*Gaps+Line + if (xPos >= curX && xPos < (curX + colWidth)) + return col; + curX += colWidth; + } // for all columns + // too right + return -1; + } // getCol + + + /************************************************************************** + * 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 void paint (Graphics2D g2D, int pageNo, Point2D pageStart, Properties ctx, boolean isView) + { + int pageIndex = getPageIndex(pageNo); + int pageXindex = getPageXIndex(pageIndex); + int pageYindex = getPageYIndex(pageIndex); + if (DEBUG_PRINT) + log.config("Page=" + pageNo + " [x=" + pageXindex + ", y=" + pageYindex + "]"); + // + int firstColumn = ((Integer)m_firstColumnOnPage.get(pageXindex)).intValue(); + int nextPageColumn = m_columnHeader.length; // no of cols + if (pageXindex+1 < m_firstColumnOnPage.size()) + nextPageColumn = ((Integer)m_firstColumnOnPage.get(pageXindex+1)).intValue(); + // + int firstRow = ((Integer)m_firstRowOnPage.get(pageYindex)).intValue(); + int nextPageRow = m_data.length; // no of rows + if (pageYindex+1 < m_firstRowOnPage.size()) + nextPageRow = ((Integer)m_firstRowOnPage.get(pageYindex+1)).intValue(); + if (DEBUG_PRINT) + log.finest("Col=" + firstColumn + "-" + (nextPageColumn-1) + + ", Row=" + firstRow + "-" + (nextPageRow-1)); + + // Top Left + int startX = (int)pageStart.getX(); + int startY = (int)pageStart.getY(); + // Table Start + startX += pageXindex == 0 ? m_firstPage.x : m_nextPages.x; + startY += pageYindex == 0 ? m_firstPage.y : m_nextPages.y; + if (DEBUG_PRINT) + log.finest("PageStart=" + pageStart + ", StartTable x=" + startX + ", y=" + startY); + + // paint first fixed volumns + boolean firstColumnPrint = true; + int regularColumnStart = firstColumn; + for (int col = 0; col < m_repeatedColumns && col < m_columnWidths.size(); col++) + { + int colWidth = ((Float)m_columnWidths.get(col)).intValue(); // includes 2*Gaps+Line + if (colWidth != 0) + { + printColumn (g2D, col, startX, startY, firstColumnPrint, firstRow, nextPageRow, isView); + startX += colWidth; + firstColumnPrint = false; + } + if (regularColumnStart == col) + regularColumnStart++; + } + + // paint columns + for (int col = regularColumnStart; col < nextPageColumn; col++) + { + int colWidth = ((Float)m_columnWidths.get(col)).intValue(); // includes 2*Gaps+Line + if (colWidth != 0) + { + printColumn (g2D, col, startX, startY, firstColumnPrint, firstRow, nextPageRow, isView); + startX += colWidth; + firstColumnPrint = false; + } + } // for all columns + + } // paint + + + /** + * Print non zero width Column + * @param g2D graphics + * @param col column index + * @param origX start X + * @param origY start Y + * @param leftVline if true print left vertical line (for first column) + * @param firstRow first row index + * @param nextPageRow row index of next page + * @param isView true if online view (IDs are links) + */ + private void printColumn (Graphics2D g2D, int col, + final int origX, final int origY, boolean leftVline, + final int firstRow, final int nextPageRow, boolean isView) + { + int curX = origX; + int curY = origY; // start from top + // + float colWidth = ((Float)m_columnWidths.get(col)).floatValue(); // includes 2*Gaps+Line + float netWidth = colWidth - (2*H_GAP) - m_tFormat.getVLineStroke().floatValue(); + if (leftVline) + netWidth -= m_tFormat.getVLineStroke().floatValue(); + int rowHeight = m_headerHeight; + float netHeight = rowHeight - (4*m_tFormat.getLineStroke().floatValue()) + (2*V_GAP); + + if (DEBUG_PRINT) + log.finer("#" + col + " - x=" + curX + ", y=" + curY + + ", width=" + colWidth + "/" + netWidth + ", HeaderHeight=" + rowHeight + "/" + netHeight); + String alignment = m_columnJustification[col]; + + // paint header *************************************************** + if (leftVline) // draw left | line + { + g2D.setPaint(m_tFormat.getVLine_Color()); + g2D.setStroke(m_tFormat.getVLine_Stroke()); + if (m_tFormat.isPaintBoundaryLines()) // -> | (left) + g2D.drawLine(origX, (int)(origY+m_tFormat.getLineStroke().floatValue()), + origX, (int)(origY+rowHeight-(4*m_tFormat.getLineStroke().floatValue()))); + curX += m_tFormat.getVLineStroke().floatValue(); + } + // X - start line + if (m_tFormat.isPaintHeaderLines()) + { + g2D.setPaint(m_tFormat.getHeaderLine_Color()); + g2D.setStroke(m_tFormat.getHeader_Stroke()); + g2D.drawLine(origX, origY, // -> - (top) + (int)(origX+colWidth-m_tFormat.getVLineStroke().floatValue()), origY); + } + curY += (2 * m_tFormat.getLineStroke().floatValue()); // thick + // Background + Color bg = getBackground(HEADER_ROW, col); + if (!bg.equals(Color.white)) + { + g2D.setPaint(bg); + g2D.fillRect(curX, + (int)(curY-m_tFormat.getLineStroke().floatValue()), + (int)(colWidth-m_tFormat.getVLineStroke().floatValue()), + (int)(rowHeight-(4*m_tFormat.getLineStroke().floatValue()))); + } + curX += H_GAP; // upper left gap + curY += V_GAP; + // Header + AttributedString aString = null; + AttributedCharacterIterator iter = null; + LineBreakMeasurer measurer = null; + float usedHeight = 0; + if (m_columnHeader[col].toString().length() > 0) + { + aString = new AttributedString(m_columnHeader[col].toString()); + aString.addAttribute(TextAttribute.FONT, getFont(HEADER_ROW, col)); + aString.addAttribute(TextAttribute.FOREGROUND, getColor(HEADER_ROW, col)); + // + boolean fastDraw = LayoutEngine.s_FASTDRAW; + if (fastDraw && !isView && !Util.is8Bit(m_columnHeader[col].toString())) + fastDraw = false; + iter = aString.getIterator(); + measurer = new LineBreakMeasurer(iter, g2D.getFontRenderContext()); + while (measurer.getPosition() < iter.getEndIndex()) // print header + { + TextLayout layout = measurer.nextLayout(netWidth + 2); + if (iter.getEndIndex() != measurer.getPosition()) + fastDraw = false; + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if (m_columnMaxHeight[col] <= 0 // -1 = FirstLineOnly + || (usedHeight + lineHeight) <= m_columnMaxHeight[col]) + { + if (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Block)) + { + layout = layout.getJustifiedLayout(netWidth + 2); + fastDraw = false; + } + curY += layout.getAscent(); + float penX = curX; + if (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Center)) + penX += (netWidth-layout.getAdvance())/2; + else if ((alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight) && layout.isLeftToRight()) + || (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft) && !layout.isLeftToRight())) + penX += netWidth-layout.getAdvance(); + // + if (fastDraw) + { // Bug - set Font/Color explicitly + g2D.setFont(getFont(HEADER_ROW, col)); + g2D.setColor(getColor(HEADER_ROW, col)); + g2D.drawString(iter, penX, curY); + } + else + layout.draw(g2D, penX, curY); // -> text + curY += layout.getDescent() + layout.getLeading(); + usedHeight += lineHeight; + } + if (!m_multiLineHeader) // one line only + break; + } + } // length > 0 + curX += netWidth + H_GAP; + curY += V_GAP; + // Y end line + g2D.setPaint(m_tFormat.getVLine_Color()); + g2D.setStroke(m_tFormat.getVLine_Stroke()); + if (m_tFormat.isPaintVLines()) // -> | (right) + g2D.drawLine(curX, (int)(origY+m_tFormat.getLineStroke().floatValue()), + curX, (int)(origY+rowHeight-(4*m_tFormat.getLineStroke().floatValue()))); + curX += m_tFormat.getVLineStroke().floatValue(); + // X end line + if (m_tFormat.isPaintHeaderLines()) + { + g2D.setPaint(m_tFormat.getHeaderLine_Color()); + g2D.setStroke(m_tFormat.getHeader_Stroke()); + g2D.drawLine(origX, curY, // -> - (button) + (int)(origX+colWidth-m_tFormat.getVLineStroke().floatValue()), curY); + } + curY += (2 * m_tFormat.getLineStroke().floatValue()); // thick + + + // paint Data *************************************************** + for (int row = firstRow; row < nextPageRow; row++) + { + rowHeight = ((Float)m_rowHeights.get(row)).intValue(); // includes 2*Gaps+Line + netHeight = rowHeight - (2*V_GAP) - m_tFormat.getLineStroke().floatValue(); + int rowYstart = curY; + + curX = origX; + if (leftVline) // draw left | line + { + g2D.setPaint(m_tFormat.getVLine_Color()); + g2D.setStroke(m_tFormat.getVLine_Stroke()); + if (m_tFormat.isPaintBoundaryLines()) + g2D.drawLine(curX, rowYstart, // -> | (left) + curX, (int)(rowYstart+rowHeight-m_tFormat.getLineStroke().floatValue())); + curX += m_tFormat.getVLineStroke().floatValue(); + } + // Background + bg = getBackground(row, col); + if (!bg.equals(Color.white)) + { + g2D.setPaint(bg); + g2D.fillRect(curX, curY, + (int)(colWidth-m_tFormat.getVLineStroke().floatValue()), + (int)(rowHeight-m_tFormat.getLineStroke().floatValue()) ); + } + curX += H_GAP; // upper left gap + curY += V_GAP; + + // actual data + Object[] printItems = getPrintItems(row,col); + float penY = curY; + for (int index = 0; index < printItems.length; index++) + { + if (printItems[index] == null) + ; + else if (printItems[index] instanceof ImageElement) + { + g2D.drawImage(((ImageElement)printItems[index]).getImage(), + curX, (int)penY, this); + } + else if (printItems[index] instanceof BarcodeElement) + { + ((BarcodeElement)printItems[index]).getBarcode().draw(g2D, curX, (int)penY); + } + else if (printItems[index] instanceof Boolean) + { + int penX = curX + (int)((netWidth-LayoutEngine.IMAGE_SIZE.width)/2); // center + if (((Boolean)printItems[index]).booleanValue()) + g2D.drawImage(LayoutEngine.IMAGE_TRUE, penX, (int)penY, this); + else + g2D.drawImage(LayoutEngine.IMAGE_FALSE, penX, (int)penY, this); + penY += LayoutEngine.IMAGE_SIZE.height; + } + else if (printItems[index] instanceof HTMLRenderer) + { + HTMLRenderer renderer = (HTMLRenderer)printItems[index]; + Rectangle allocation = new Rectangle((int)colWidth, (int)netHeight); + // log.finest( "printColumn HTML - " + allocation); + g2D.translate(curX, penY); + renderer.paint(g2D, allocation); + g2D.translate(-curX, -penY); + penY += allocation.getHeight(); + } + else + { + String str = printItems[index].toString(); + if (DEBUG_PRINT) + log.fine("row=" + row + ",col=" + col + " - " + str + " 8Bit=" + Util.is8Bit(str)); + if (str.length() > 0) + { + usedHeight = 0; + String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(str); + for (int lineNo = 0; lineNo < lines.length; lineNo++) + { + aString = new AttributedString(lines[lineNo]); + aString.addAttribute(TextAttribute.FONT, getFont(row, col)); + if (isView && printItems[index] instanceof NamePair) // ID + { + aString.addAttribute(TextAttribute.FOREGROUND, LINK_COLOR); + aString.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL, 0, str.length()); + } + else + aString.addAttribute(TextAttribute.FOREGROUND, getColor(row, col)); + // + iter = aString.getIterator(); + boolean fastDraw = LayoutEngine.s_FASTDRAW; + if (fastDraw && !isView && !Util.is8Bit(lines[lineNo])) + fastDraw = false; + measurer = new LineBreakMeasurer(iter, g2D.getFontRenderContext()); + while (measurer.getPosition() < iter.getEndIndex()) // print element + { + TextLayout layout = measurer.nextLayout(netWidth + 2); + if (iter.getEndIndex() != measurer.getPosition()) + fastDraw = false; + float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); + if ((m_columnMaxHeight[col] <= 0 + || (usedHeight + lineHeight) <= m_columnMaxHeight[col]) + && (usedHeight + lineHeight) <= netHeight) + { + if (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Block) && measurer.getPosition() < iter.getEndIndex()) + { + layout = layout.getJustifiedLayout(netWidth + 2); + fastDraw = false; + } + penY += layout.getAscent(); + float penX = curX; + if (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_Center)) + penX += (netWidth-layout.getAdvance())/2; + else if ((alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_TrailingRight) && layout.isLeftToRight()) + || (alignment.equals(MPrintFormatItem.FIELDALIGNMENTTYPE_LeadingLeft) && !layout.isLeftToRight())) + penX += netWidth-layout.getAdvance(); + // + if (fastDraw) + { // Bug - set Font/Color explicitly + g2D.setFont(getFont(row, col)); + if (isView && printItems[index] instanceof NamePair) // ID + { + g2D.setColor(LINK_COLOR); + // TextAttribute.UNDERLINE + } + else + g2D.setColor(getColor(row, col)); + g2D.drawString(iter, penX, penY); + } + else + layout.draw(g2D, penX, penY); // -> text + if (DEBUG_PRINT) + log.fine("row=" + row + ",col=" + col + " - " + str + " - x=" + penX + ",y=" + penY); + penY += layout.getDescent() + layout.getLeading(); + usedHeight += lineHeight; + // + if (m_columnMaxHeight[col] == -1) // FirstLineOny + break; + } + } // print element + } // for all lines + } // length > 0 + } // non boolean + } // for all print items + + curY += netHeight + V_GAP; + curX += netWidth + H_GAP; + // Y end line + g2D.setPaint(m_tFormat.getVLine_Color()); + g2D.setStroke(m_tFormat.getVLine_Stroke()); + if (m_tFormat.isPaintVLines()) + g2D.drawLine(curX, rowYstart, // -> | (right) + curX, (int)(rowYstart+rowHeight-m_tFormat.getLineStroke().floatValue())); + curX += m_tFormat.getVLineStroke().floatValue(); + + // X end line + if (row == m_data.length-1) // last Line + { + g2D.setPaint(m_tFormat.getHeaderLine_Color()); + g2D.setStroke(m_tFormat.getHeader_Stroke()); + g2D.drawLine(origX, curY, // -> - (last line) + (int)(origX+colWidth-m_tFormat.getVLineStroke().floatValue()), curY); + curY += (2 * m_tFormat.getLineStroke().floatValue()); // thick + } + else + { + // next line is a funcion column -> underline this + boolean nextIsFunction = m_functionRows.contains(new Integer(row+1)); + if (nextIsFunction && m_functionRows.contains(new Integer(row))) + nextIsFunction = false; // this is a function line too + if (nextIsFunction) + { + g2D.setPaint(m_tFormat.getFunctFG_Color()); + g2D.setStroke(m_tFormat.getHLine_Stroke()); + g2D.drawLine(origX, curY, // -> - (bottom) + (int)(origX+colWidth-m_tFormat.getVLineStroke().floatValue()), curY); + } + else if (m_tFormat.isPaintHLines()) + { + g2D.setPaint(m_tFormat.getHLine_Color()); + g2D.setStroke(m_tFormat.getHLine_Stroke()); + g2D.drawLine(origX, curY, // -> - (bottom) + (int)(origX+colWidth-m_tFormat.getVLineStroke().floatValue()), curY); + } + curY += m_tFormat.getLineStroke().floatValue(); + } + } // for all rows + + } // printColumn + + /** + * Add Additional Lines to row/col + * @param row row + * @param col col + * @param data data + */ + private void addPrintLines (int row, int col, Object data) + { + while (m_printRows.size() <= row) + m_printRows.add(null); + ArrayList> columns = m_printRows.get(row); + if (columns == null) + columns = new ArrayList>(m_columnHeader.length); + while (columns.size() <= col) + columns.add(null); + // + ArrayList coordinate = columns.get(col); + if (coordinate == null) + coordinate = new ArrayList(); + coordinate.add(data); + // + columns.set(col, coordinate); + m_printRows.set(row, columns); + log.finest("row=" + row + ", col=" + col + + " - Rows=" + m_printRows.size() + ", Cols=" + columns.size() + + " - " + data); + } // addAdditionalLines + + /** Print Data */ + private ArrayList>> m_printRows = new ArrayList>>(); + + /** + * Insert empty Row after current Row + * @param currentRow + */ + private void insertRow (int currentRow) + { + + } // inserRow + + + /** + * Get Print Data including additional Lines + * @param row row + * @param col col + * @return non null array of print objects (may be empty) + */ + private Object[] getPrintItems (int row, int col) + { + ArrayList> columns = null; + if (m_printRows.size() > row) + columns = m_printRows.get(row); + if (columns == null) + return new Object[]{}; + ArrayList coordinate = null; + if (columns.size() > col) + coordinate = columns.get(col); + if (coordinate == null) + return new Object[]{}; + // + return coordinate.toArray(); + } // getPrintItems + +} diff --git a/print/src/org/compiere/print/layout/false10.gif b/print/src/org/compiere/print/layout/false10.gif new file mode 100644 index 0000000000000000000000000000000000000000..564b151820bc84b24603b5b7b13c953efadd6483 GIT binary patch literal 471 zcmV;|0Vw{7P)weW5KZ}I0t3Lv?Ok)zXIEs1}eXdTI`(f*?pKxk}yFdglR z&g!NybLn=mvE21409^D(cS5SVL_w%MV5h0Dojct$=IW`3hC4gs7n}n^NFh~SsuPsz zPStiS>s|tY%c0nII1-6_NgXYjW$ri*uSxmm=e^0BhZO<<`}vQrK5dwDsSx_w*$09rdPIF~r*u)Yegi$&Nj3Boi*ZI=PyyieN-`uz(mU!WyZ7iF1S zq*P_iin5q(4{id0bk-Bu3^e)@Zo^__2J5|8+~q=`MNty+cZHc=m-SgG?@~Z$)Zu^9 z^waAa0A$+(!sqoYOU4g_EO#RXkh5q<<~Y>0@jrN`wP`)81~Vyu`~ne#n;1*^ACdq7 N002ovPDHLkV1k;!#Ebv{ literal 0 HcmV?d00001 diff --git a/print/src/org/compiere/print/layout/true10.gif b/print/src/org/compiere/print/layout/true10.gif new file mode 100644 index 0000000000000000000000000000000000000000..2c4a904d8722090be921a5aae137e80ac25851c0 GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4u_bxCyDx`7I;J! z19e;nVMZs7*%d%R_7YEDSN3b%+yeRlFzk+__kuz*b?_le-DjHmp` z2|#dU>55gp4!$8yDewQ+`}|oSzxPa98c=-3o`BS?&DQLf=dGQ;-pIhf;7S?iN>4BE zH_wv9C#I$(r2aqt!+CDyHLtTzy}VW_+Su5{iShBsuYD6~?{(Vyz1WlKQ<4*Yoc{3h z_UYOA@wEjBi781bX-^ZgV}ycfGRP zpA>fW&#tzaPq&-#%eSl9?^n>)*O$LP-#%V4ZeLZ+=a-AGm%Y6zA8!bBl!3hckJ*l) zpMOiGU8}zpv!`d4kB_~?e4EO;#~+)oe_Jd1KK`K1@iPYw9AF4ObL7a1?_Xd0A9Md6 qchh|8zUo% + + + + + + +Provides for.... + +

Package Specification

+ + + +

Related Documentation

+ +For overviews, tutorials, examples, guides, and tool documentation, please see: + + + + + +