PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/base/src/org/adempiere/impexp/AbstractExcelExporter.java

https://bitbucket.org/sthamthum/adempiere361
Java | 473 lines | 326 code | 33 blank | 114 comment | 61 complexity | 4e80b12708a60a947d9b7c23cd66ba00 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /******************************************************************************
  2. * Product: Adempiere ERP & CRM Smart Business Solution *
  3. * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. *
  4. * This program is free software; you can redistribute it and/or modify it *
  5. * under the terms version 2 of the GNU General Public License as published *
  6. * by the Free Software Foundation. This program is distributed in the hope *
  7. * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
  8. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
  9. * See the GNU General Public License for more details. *
  10. * You should have received a copy of the GNU General Public License along *
  11. * with this program; if not, write to the Free Software Foundation, Inc., *
  12. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
  13. *****************************************************************************/
  14. package org.adempiere.impexp;
  15. import java.io.File;
  16. import java.io.FileOutputStream;
  17. import java.io.OutputStream;
  18. import java.sql.Timestamp;
  19. import java.text.DecimalFormat;
  20. import java.text.NumberFormat;
  21. import java.util.HashMap;
  22. import java.util.Properties;
  23. import java.util.logging.Level;
  24. import org.apache.poi.hssf.usermodel.HSSFCell;
  25. import org.apache.poi.hssf.usermodel.HSSFCellStyle;
  26. import org.apache.poi.hssf.usermodel.HSSFDataFormat;
  27. import org.apache.poi.hssf.usermodel.HSSFFont;
  28. import org.apache.poi.hssf.usermodel.HSSFFooter;
  29. import org.apache.poi.hssf.usermodel.HSSFHeader;
  30. import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
  31. import org.apache.poi.hssf.usermodel.HSSFRichTextString;
  32. import org.apache.poi.hssf.usermodel.HSSFRow;
  33. import org.apache.poi.hssf.usermodel.HSSFSheet;
  34. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  35. import org.compiere.Adempiere;
  36. import org.compiere.util.CLogMgt;
  37. import org.compiere.util.CLogger;
  38. import org.compiere.util.DisplayType;
  39. import org.compiere.util.Env;
  40. import org.compiere.util.Ini;
  41. import org.compiere.util.Language;
  42. import org.compiere.util.Msg;
  43. import org.compiere.util.Util;
  44. /**
  45. * Abstract MS Excel Format (xls) Exporter
  46. * @author Teo Sarca, SC ARHIPAC SERVICE SRL
  47. */
  48. public abstract class AbstractExcelExporter
  49. {
  50. /**
  51. * Is the current Row a Function Row
  52. * @return true if function row
  53. */
  54. public abstract boolean isFunctionRow();
  55. /**
  56. * Get Columns Count
  57. * @return number of columns
  58. */
  59. public abstract int getColumnCount();
  60. /**
  61. * Get Rows Count
  62. * @return number of rows
  63. */
  64. public abstract int getRowCount();
  65. /**
  66. * Set current row
  67. * @param row row index
  68. */
  69. protected abstract void setCurrentRow(int row);
  70. /**
  71. * Check if column is printed (displayed)
  72. * @param col column index
  73. * @return true if is visible
  74. */
  75. public abstract boolean isColumnPrinted(int col);
  76. /**
  77. * Get column header name
  78. * @param col column index
  79. * @return header name
  80. */
  81. public abstract String getHeaderName(int col);
  82. /**
  83. * Get cell display type (see {@link DisplayType})
  84. * @param row row index
  85. * @param col column index
  86. * @return display type
  87. */
  88. public abstract int getDisplayType(int row, int col);
  89. /**
  90. * Get cell value
  91. * @param row row index
  92. * @param col column index
  93. * @return cell value
  94. */
  95. public abstract Object getValueAt(int row, int col);
  96. /**
  97. * Check if there is a page break on given cell
  98. * @param row row index
  99. * @param col column index
  100. * @return true if there is a page break
  101. */
  102. public abstract boolean isPageBreak(int row, int col);
  103. /** Logger */
  104. protected final CLogger log = CLogger.getCLogger(getClass());
  105. //
  106. private HSSFWorkbook m_workbook;
  107. private HSSFDataFormat m_dataFormat;
  108. private HSSFFont m_fontHeader = null;
  109. private HSSFFont m_fontDefault = null;
  110. private Language m_lang = null;
  111. private int m_sheetCount = 0;
  112. //
  113. private int m_colSplit = 1;
  114. private int m_rowSplit = 1;
  115. /** Styles cache */
  116. private HashMap<String, HSSFCellStyle> m_styles = new HashMap<String, HSSFCellStyle>();
  117. public AbstractExcelExporter() {
  118. m_workbook = new HSSFWorkbook();
  119. m_dataFormat = m_workbook.createDataFormat();
  120. }
  121. protected Properties getCtx() {
  122. return Env.getCtx();
  123. }
  124. protected void setFreezePane(int colSplit, int rowSplit) {
  125. m_colSplit = colSplit;
  126. m_rowSplit = rowSplit;
  127. }
  128. private String fixString(String str)
  129. {
  130. // ms excel doesn't support UTF8 charset
  131. return Util.stripDiacritics(str);
  132. }
  133. protected Language getLanguage() {
  134. if (m_lang == null)
  135. m_lang = Env.getLanguage(getCtx());
  136. return m_lang;
  137. }
  138. private HSSFFont getFont(boolean isHeader) {
  139. HSSFFont font = null;
  140. if (isHeader) {
  141. if (m_fontHeader == null) {
  142. m_fontHeader = m_workbook.createFont();
  143. m_fontHeader.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
  144. }
  145. font = m_fontHeader;
  146. }
  147. else if (isFunctionRow()) {
  148. font = m_workbook.createFont();
  149. font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
  150. font.setItalic(true);
  151. }
  152. else {
  153. if (m_fontDefault == null) {
  154. m_fontDefault = m_workbook.createFont();
  155. }
  156. font = m_fontDefault;
  157. }
  158. return font;
  159. }
  160. /**
  161. * Get Excel number format string by given {@link NumberFormat}
  162. * @param df number format
  163. * @param isHighlightNegativeNumbers highlight negative numbers using RED color
  164. * @return number excel format string
  165. */
  166. private String getFormatString(NumberFormat df, boolean isHighlightNegativeNumbers) {
  167. StringBuffer format = new StringBuffer();
  168. int integerDigitsMin = df.getMinimumIntegerDigits();
  169. int integerDigitsMax = df.getMaximumIntegerDigits();
  170. for (int i = 0; i < integerDigitsMax; i++) {
  171. if (i < integerDigitsMin)
  172. format.insert(0, "0");
  173. else
  174. format.insert(0, "#");
  175. if (i == 2) {
  176. format.insert(0, ",");
  177. }
  178. }
  179. int fractionDigitsMin = df.getMinimumFractionDigits();
  180. int fractionDigitsMax = df.getMaximumFractionDigits();
  181. for (int i = 0; i < fractionDigitsMax; i++) {
  182. if (i == 0)
  183. format.append(".");
  184. if (i < fractionDigitsMin)
  185. format.append("0");
  186. else
  187. format.append("#");
  188. }
  189. if (isHighlightNegativeNumbers) {
  190. String f = format.toString();
  191. format = new StringBuffer(f).append(";[RED]-").append(f);
  192. }
  193. //
  194. if (CLogMgt.isLevelFinest()) log.finest("NumberFormat: "+format);
  195. return format.toString();
  196. }
  197. private HSSFCellStyle getStyle(int row, int col) {
  198. int displayType = getDisplayType(row, col);
  199. String key = "cell-"+col+"-"+displayType;
  200. HSSFCellStyle cs = m_styles.get(key);
  201. if (cs == null) {
  202. boolean isHighlightNegativeNumbers = true;
  203. cs = m_workbook.createCellStyle();
  204. HSSFFont font = getFont(false);
  205. cs.setFont(font);
  206. // Border
  207. cs.setBorderLeft((short)1);
  208. cs.setBorderTop((short)1);
  209. cs.setBorderRight((short)1);
  210. cs.setBorderBottom((short)1);
  211. //
  212. if (DisplayType.isDate(displayType)) {
  213. cs.setDataFormat(m_dataFormat.getFormat("DD.MM.YYYY"));
  214. }
  215. else if (DisplayType.isNumeric(displayType)) {
  216. DecimalFormat df = DisplayType.getNumberFormat(displayType, getLanguage());
  217. String format = getFormatString(df, isHighlightNegativeNumbers);
  218. cs.setDataFormat(m_dataFormat.getFormat(format));
  219. }
  220. m_styles.put(key, cs);
  221. }
  222. return cs;
  223. }
  224. private HSSFCellStyle getHeaderStyle(int col)
  225. {
  226. String key = "header-"+col;
  227. HSSFCellStyle cs_header = m_styles.get(key);
  228. if (cs_header == null) {
  229. HSSFFont font_header = getFont(true);
  230. cs_header = m_workbook.createCellStyle();
  231. cs_header.setFont(font_header);
  232. cs_header.setBorderLeft((short)2);
  233. cs_header.setBorderTop((short)2);
  234. cs_header.setBorderRight((short)2);
  235. cs_header.setBorderBottom((short)2);
  236. cs_header.setDataFormat(HSSFDataFormat.getBuiltinFormat("text"));
  237. cs_header.setWrapText(true);
  238. m_styles.put(key, cs_header);
  239. }
  240. return cs_header;
  241. }
  242. private void fixColumnWidth(HSSFSheet sheet, int lastColumnIndex)
  243. {
  244. for (short colnum = 0; colnum < lastColumnIndex; colnum++)
  245. {
  246. sheet.autoSizeColumn(colnum);
  247. }
  248. }
  249. private void closeTableSheet(HSSFSheet prevSheet, String prevSheetName, int colCount)
  250. {
  251. if (prevSheet == null)
  252. return;
  253. //
  254. fixColumnWidth(prevSheet, colCount);
  255. if (m_colSplit >= 0 || m_rowSplit >= 0)
  256. prevSheet.createFreezePane(m_colSplit >= 0 ? m_colSplit : 0, m_rowSplit >= 0 ? m_rowSplit : 0);
  257. if (!Util.isEmpty(prevSheetName, true) && m_sheetCount > 0) {
  258. int prevSheetIndex = m_sheetCount - 1;
  259. try {
  260. m_workbook.setSheetName(prevSheetIndex, prevSheetName);
  261. }
  262. catch (Exception e) {
  263. log.log(Level.WARNING, "Error setting sheet "+prevSheetIndex+" name to "+prevSheetName, e);
  264. }
  265. }
  266. }
  267. private HSSFSheet createTableSheet()
  268. {
  269. HSSFSheet sheet= m_workbook.createSheet();
  270. formatPage(sheet);
  271. createHeaderFooter(sheet);
  272. createTableHeader(sheet);
  273. m_sheetCount++;
  274. //
  275. return sheet;
  276. }
  277. private void createTableHeader(HSSFSheet sheet)
  278. {
  279. short colnumMax = 0;
  280. HSSFRow row = sheet.createRow(0);
  281. // for all columns
  282. short colnum = 0;
  283. for (int col = 0; col < getColumnCount(); col++)
  284. {
  285. if (colnum > colnumMax)
  286. colnumMax = colnum;
  287. //
  288. if (isColumnPrinted(col))
  289. {
  290. HSSFCell cell = row.createCell(colnum);
  291. // header row
  292. HSSFCellStyle style = getHeaderStyle(col);
  293. cell.setCellStyle(style);
  294. String str = fixString(getHeaderName(col));
  295. cell.setCellValue(new HSSFRichTextString(str));
  296. colnum++;
  297. } // printed
  298. } // for all columns
  299. // m_workbook.setRepeatingRowsAndColumns(m_sheetCount, 0, 0, 0, 0);
  300. }
  301. protected void createHeaderFooter(HSSFSheet sheet)
  302. {
  303. // Sheet Header
  304. HSSFHeader header = sheet.getHeader();
  305. header.setRight(HSSFHeader.page()+ " / "+HSSFHeader.numPages());
  306. // Sheet Footer
  307. HSSFFooter footer = sheet.getFooter();
  308. footer.setLeft(Adempiere.ADEMPIERE_R);
  309. footer.setCenter(Env.getHeader(getCtx(), 0));
  310. Timestamp now = new Timestamp(System.currentTimeMillis());
  311. footer.setRight(DisplayType.getDateFormat(DisplayType.DateTime, getLanguage()).format(now));
  312. }
  313. protected void formatPage(HSSFSheet sheet)
  314. {
  315. sheet.setFitToPage(true);
  316. // Print Setup
  317. HSSFPrintSetup ps = sheet.getPrintSetup();
  318. ps.setFitWidth((short)1);
  319. ps.setNoColor(true);
  320. ps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);
  321. ps.setLandscape(false);
  322. }
  323. /**
  324. * Export to given stream
  325. * @param out
  326. * @throws Exception
  327. */
  328. private void export(OutputStream out)
  329. throws Exception
  330. {
  331. HSSFSheet sheet= createTableSheet();
  332. String sheetName = null;
  333. //
  334. short colnumMax = 0;
  335. for (int rownum = 0, xls_rownum = 1; rownum < getRowCount(); rownum++, xls_rownum++)
  336. {
  337. setCurrentRow(rownum);
  338. boolean isPageBreak = false;
  339. HSSFRow row = sheet.createRow(xls_rownum);
  340. // for all columns
  341. short colnum = 0;
  342. for (int col = 0; col < getColumnCount(); col++)
  343. {
  344. if (colnum > colnumMax)
  345. colnumMax = colnum;
  346. //
  347. if (isColumnPrinted(col))
  348. {
  349. HSSFCell cell = row.createCell(colnum);
  350. cell.setEncoding(HSSFCell.ENCODING_UTF_16); // Bug-2017673 - Export Report as Excel - Bad Encoding
  351. // line row
  352. Object obj = getValueAt(rownum, col);
  353. int displayType = getDisplayType(rownum, col);
  354. if (obj == null)
  355. ;
  356. else if (DisplayType.isDate(displayType)) {
  357. Timestamp value = (Timestamp)obj;
  358. cell.setCellValue(value);
  359. }
  360. else if (DisplayType.isNumeric(displayType)) {
  361. double value = 0;
  362. if (obj instanceof Number) {
  363. value = ((Number)obj).doubleValue();
  364. }
  365. cell.setCellValue(value);
  366. }
  367. else if (DisplayType.YesNo == displayType) {
  368. boolean value = false;
  369. if (obj instanceof Boolean)
  370. value = (Boolean)obj;
  371. else
  372. value = "Y".equals(obj);
  373. cell.setCellValue(new HSSFRichTextString(Msg.getMsg(getLanguage(), value == true ? "Y" : "N")));
  374. }
  375. else {
  376. String value = fixString(obj.toString()); // formatted
  377. cell.setCellValue(new HSSFRichTextString(value));
  378. }
  379. //
  380. HSSFCellStyle style = getStyle(rownum, col);
  381. cell.setCellStyle(style);
  382. // Page break
  383. if (isPageBreak(rownum, col)) {
  384. isPageBreak = true;
  385. sheetName = fixString(cell.getRichStringCellValue().getString());
  386. }
  387. //
  388. colnum++;
  389. } // printed
  390. } // for all columns
  391. //
  392. // Page Break
  393. if (isPageBreak) {
  394. closeTableSheet(sheet, sheetName, colnumMax);
  395. sheet = createTableSheet();
  396. xls_rownum = 0;
  397. isPageBreak = false;
  398. }
  399. } // for all rows
  400. closeTableSheet(sheet, sheetName, colnumMax);
  401. //
  402. m_workbook.write(out);
  403. out.close();
  404. //
  405. // Workbook Info
  406. if (CLogMgt.isLevelFine()) {
  407. log.fine("Sheets #"+m_sheetCount);
  408. log.fine("Styles used #"+m_styles.size());
  409. }
  410. }
  411. /**
  412. * Export to file
  413. * @param file
  414. * @param language reporting language
  415. * @throws Exception
  416. */
  417. public void export(File file, Language language)
  418. throws Exception
  419. {
  420. export(file, language, true);
  421. }
  422. /**
  423. * Export to file
  424. * @param file
  425. * @param language reporting language
  426. * @param autoOpen auto open file after generated
  427. * @throws Exception
  428. */
  429. public void export(File file, Language language, boolean autoOpen)
  430. throws Exception
  431. {
  432. m_lang = language;
  433. if (file == null)
  434. file = File.createTempFile("Report_", ".xls");
  435. FileOutputStream out = new FileOutputStream(file);
  436. export(out);
  437. if (autoOpen && Ini.isClient())
  438. Env.startBrowser(file.toURI().toString());
  439. }
  440. }