/****************************************************************************** * 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.File; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.compiere.Adempiere; import org.compiere.print.util.SerializableMatrix; import org.compiere.print.util.SerializableMatrixImpl; import org.compiere.report.MReportLine; import org.compiere.util.CLogger; import org.compiere.util.DisplayType; import org.compiere.util.Trace; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Print Data Structure.
* Created by DataEngine.
* A Structure has rows, which 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 { /** * generated serial id */ private static final long serialVersionUID = 3493453909439452289L; /** * @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; m_matrix = new SerializableMatrixImpl(name); } // PrintData /** * @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; m_matrix = new SerializableMatrixImpl(name); if (nodes != null) addRow(false, 0, nodes); } // PrintData private SerializableMatrix m_matrix; /** Context */ private Properties m_ctx; /** Data Structure Name */ private String m_name; /** 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 */ @Override public String toString() { StringBuilder sb = new StringBuilder("PrintData["); sb.append(m_name).append(",Rows=").append(m_matrix.getRowCount()); if (m_TableName != null) sb.append(",TableName=").append(m_TableName); sb.append("]"); return sb.toString(); } // toString /** * Is with 0 rows or 0 nodes/columns * @return true if 0 rows or 0 nodes/columns */ public boolean isEmpty() { return m_matrix.getRowCount() == 0 || m_matrix.getRowData().isEmpty(); } // isEmpty /** * Get Number of nodes/columns in row * @return number of nodes/columns in row */ public int getNodeCount() { if (m_matrix.getRowCount() == 0) return 0; return m_matrix.getRowData().size(); } // getNodeCount /** * Add data row * @param functionRow * @param levelNo */ public void addRow (boolean functionRow, int levelNo) { addRow(functionRow, levelNo, new ArrayList()); } /** * Add Data Row * @param functionRow true if function row * @param levelNo Line detail Level Number 0=Normal */ public void addRow (boolean functionRow, int levelNo, List nodes) { m_matrix.addRow(nodes); if (functionRow) m_functionRows.add(Integer.valueOf(m_matrix.getRowIndex())); if (m_hasLevelNo && levelNo != 0) addNode(new PrintDataElement(0, LEVEL_NO, Integer.valueOf(levelNo), DisplayType.Integer, null)); } // addRow /** * Set Row Index * @param row row index * @return true if success */ public boolean setRowIndex (int row) { return m_matrix.setRowIndex(row); } /** * Set Row Index to next * @return true if success */ public boolean setRowNext() { return m_matrix.setRowNext(); } // setRowNext /** * Get Row Count * @return row count */ public int getRowCount() { return getRowCount(true); } // getRowCount /** * Get row count * @param includeFunctionRows * @return row count */ public int getRowCount(boolean includeFunctionRows) { return includeFunctionRows ? m_matrix.getRowCount() : m_matrix.getRowCount() - m_functionRows.size(); } /** * Get Current Row Index * @return row index */ public int getRowIndex() { return m_matrix.getRowIndex(); } // 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(Integer.valueOf(row)); } // isFunctionRow /** * Is current Row a Function Row * @return true if current row is a function row */ public boolean isFunctionRow () { return m_functionRows.contains(Integer.valueOf(m_matrix.getRowIndex())); } // isFunctionRow /** * Is current Row a page break row * @return true if current row is a page break row */ public boolean isPageBreak () { // page break requires function and meta data List nodes = m_matrix.getRowData(); if (isFunctionRow() && nodes != null) { for (int i = 0; i < nodes.size(); i++) { Object o = nodes.get(i); if (o instanceof PrintDataElement) { PrintDataElement pde = (PrintDataElement)o; if (pde.isPageBreak()) return true; } } } return false; } // isPageBreak /** * Set PrintData has Level No * @param hasLevelNo true if sql includes LevelNo */ public void setHasLevelNo (boolean hasLevelNo) { m_hasLevelNo = hasLevelNo; } // hasLevelNo /** * Is PrintData has Level No * @return true if sql includes LevelNo */ public boolean hasLevelNo() { return m_hasLevelNo; } // hasLevelNo /** * Get Line Level Number for current row * @return line level no, 0 = default */ public int getLineLevelNo () { List nodes = m_matrix.getRowData(); if (nodes == null || !m_hasLevelNo) return 0; for (int i = 0; i < nodes.size(); i++) { Object o = 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 current row * @param parent parent */ public void addNode (PrintData parent) { if (parent == null) throw new IllegalArgumentException("Parent cannot be null"); List nodes = m_matrix.getRowData(); if (nodes == null) { nodes = new ArrayList(); addRow(false, 0, nodes); } nodes.add (parent); } // addNode /** * Add node to current row * @param node node */ public void addNode (PrintDataElement node) { if (node == null) throw new IllegalArgumentException("Node cannot be null"); List nodes = m_matrix.getRowData(); if (nodes == null) { nodes = new ArrayList(); addRow(false, 0, nodes); } nodes.add (node); } // addNode /** * Get node with index in current row * @param index index * @return PrintData(Element) of index or null */ public Object getNode (int index) { List nodes = m_matrix.getRowData(); if (nodes == null || index < 0 || index >= nodes.size()) return null; return nodes.get(index); } // getNode /** * Get node with name in current row * @param name node name * @return PrintData(Element) with Name or null */ public Object getNode (String name) { int index = getIndex (name); if (index < 0) return null; List nodes = m_matrix.getRowData(); return nodes.get(index); } // getNode /** * Get Node with AD_Column_ID in current row * @param AD_Column_ID AD_Column_ID * @return PrintData(Element) with AD_Column_ID or null * @deprecated replace by {@link #getNodeByPrintFormatItemId(int)} */ @Deprecated public Object getNode (Integer AD_Column_ID) { int index = getIndex (AD_Column_ID.intValue()); if (index < 0) return null; List nodes = m_matrix.getRowData(); return nodes.get(index); } // getNode /** * Get node with print format item id in current row * @param item * @return PrintData(Element) with AD_PrintFormatItem_ID or null */ public Object getNodeByPrintFormatItem(MPrintFormatItem item) { return getNodeByPrintFormatItemId(item.getAD_PrintFormatItem_ID()); } /** * Get Node with AD_PrintFormatItem_ID in current row * @param AD_PrintFormatItem_ID AD_PrintFormatItem_ID * @return PrintData(Element) with AD_PrintFormatItem_ID or null */ public Object getNodeByPrintFormatItemId (int AD_PrintFormatItem_ID) { int index = getIndexOfPrintFormatItem(AD_PrintFormatItem_ID); if (index < 0) return null; List nodes = m_matrix.getRowData(); return nodes.get(index); } // getNode /** * Get Primary Key node in current row * @return PK or null */ public PrintDataElement getPKey() { List nodes = m_matrix.getRowData(); if (nodes == null) return null; for (int i = 0; i < nodes.size(); i++) { Object o = nodes.get(i); if (o instanceof PrintDataElement) { PrintDataElement pde = (PrintDataElement)o; if (pde.isPKey()) return pde; } } return null; } // getPKey /** * Get Index of Node in current row * @param columnName name * @return index or -1 */ public int getIndex (String columnName) { List nodes = m_matrix.getRowData(); if (nodes == null) return -1; for (int i = 0; i < nodes.size(); i++) { Object o = 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 return -1; } // getIndex /** * Get Index of Node in current row * @param AD_Column_ID AD_Column_ID * @return index or -1 */ @Deprecated 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 /** * Get Index of Node in current row * @param AD_PrintFormatItem_ID AD_PrintFormatItem_ID * @return index or -1 */ public int getIndexOfPrintFormatItem(int AD_PrintFormatItem_ID) { List nodes = m_matrix.getRowData(); if (nodes == null) return -1; for (int i = 0; i < nodes.size(); i++) { Object o = nodes.get(i); if (o instanceof PrintDataElement) { if (AD_PrintFormatItem_ID == ((PrintDataElement)o).getAD_PrintFormatItem_ID()) return i; } else if (o instanceof PrintData) { continue; } else log.log(Level.SEVERE, "Element not PrintData(Element) " + o.getClass().getName()); } // As Data is stored sparse, there might be lots of NULL values return -1; } /** * 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_matrix.getRowIndex()); } // 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) { if (log.isLoggable(Level.INFO)) log.info(pd.toString()); if (pd.getColumnInfo() != null) { for (int i = 0; i < pd.getColumnInfo().length; i++) if (log.isLoggable(Level.CONFIG)) log.config(i + ": " + pd.getColumnInfo()[i]); } } // dump /** * Dump Row * @param pd print data * @param row row */ private static void dumpRow (PrintData pd, int row) { if (log.isLoggable(Level.INFO)) 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) { if (log.isLoggable(Level.CONFIG)) log.config(((PrintDataElement)obj).toStringX()); } else if (log.isLoggable(Level.CONFIG)) 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 if (document != null) { 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 and append to XML document * @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_PRINTFORMATITEM_ID, Integer.toString(pde.getAD_PrintFormatItem_ID())); 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) { if (log.isLoggable(Level.CONFIG)) 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 /** * Get MReportLine for current row * @return MReportLine */ public MReportLine getMReportLine() { List nodes = m_matrix.getRowData(); if (nodes == null || !m_hasLevelNo) return null; for (int i = 0; i < nodes.size(); i++) { Object o = nodes.get(i); if (o instanceof PrintDataElement) { PrintDataElement pde = (PrintDataElement) o; if (MReportLine.COLUMNNAME_PA_ReportLine_ID.equals(pde.getColumnName())) { Integer ii = (Integer) pde.getValue(); if (ii > 0) { return new MReportLine(m_ctx, ii, null); } } } } return null; } // getMReportLine /** * Add row * @param functionRow * @param levelNo * @param reportLineID */ public void addRow(boolean functionRow, int levelNo, int reportLineID) { addRow(functionRow, levelNo); if (m_hasLevelNo && reportLineID != 0) addNode(new PrintDataElement(0, "PA_ReportLine_ID", reportLineID, DisplayType.Integer, null)); } } // PrintData