/****************************************************************************** * Copyright (C) 2012 Trek Global * * Product: iDempiere ERP & CRM Smart Business Solution * * 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. * *****************************************************************************/ package org.adempiere.webui.component; import java.io.File; import java.io.FileInputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.adempiere.webui.ISupportMask; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.event.DialogEvents; import org.adempiere.webui.factory.ButtonFactory; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.window.SimplePDFViewer; import org.compiere.print.ReportEngine; import org.compiere.process.ProcessInfo; import org.compiere.process.ProcessInfoLog; import org.compiere.process.ProcessInfoUtil; import org.compiere.tools.FileUtil; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.Msg; import org.zkoss.zhtml.Text; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Hbox; import org.zkoss.zul.Image; import org.zkoss.zul.Separator; /** * Dialog to display {@link ProcessInfo} details. * @author milap.doshi * @author Deepak Pansheriya */ public class ProcessInfoDialog extends Window implements EventListener { /** * generated serial id */ private static final long serialVersionUID = -1712025652050086903L; private static final String MESSAGE_PANEL_STYLE = "text-align:left; word-break: break-all; overflow: auto; max-height: 250pt; min-width: 230pt; max-width: 450pt;"; private Text lblMsg = new Text(); private Button btnOk = ButtonFactory.createNamedButton(ConfirmPanel.A_OK); /** Button to print document from {@link #m_logs} */ private Button btnPrint = ButtonFactory.createNamedButton(ConfirmPanel.A_PRINT); /** Info or Error image icon */ private Image img = new Image(); /** Array of ProcessInfoLog from ProcessInfo */ private ProcessInfoLog[] m_logs; public static final String INFORMATION = "~./zul/img/msgbox/info-btn.png"; public static final String ERROR = "~./zul/img/msgbox/info-btn.png"; /** If true, auto close dialog after user has click on zoom to window link */ private boolean isAutoCloseAfterZoom = false; /** * @deprecated Should use {@link #ProcessInfoDialog(String, String, ProcessInfo, boolean)} for flexible show message * @param title * @param header * @param m_logs */ public ProcessInfoDialog(String title, String header, ProcessInfoLog[] m_logs) { init(title, header, null, m_logs); } /** * show result after run a process * @deprecated * @param title ignore * @param header ignore * @param pi * @param needFillLogFromDb */ public ProcessInfoDialog(String title, String header, ProcessInfo pi, boolean needFillLogFromDb) { this(pi, needFillLogFromDb); } /** * show result after run a process * @param pi ProcessInfo * @param needFillLogFromDb true to load ProcessInfoLog from DB */ public ProcessInfoDialog(ProcessInfo pi, boolean needFillLogFromDb) { if (needFillLogFromDb) ProcessInfoUtil.setLogFromDB(pi); init(pi.getTitle(), null, pi, null); } /** * Layout dialog * @param title * @param header * @param pi ProcessInfo * @param m_logs ProcessInfoLog[] */ private void init(String title, String header, ProcessInfo pi, ProcessInfoLog[] m_logs) { this.setTitle(title); this.setClosable(true); this.setSizable(true); this.setBorder("normal"); this.setContentStyle("background-color:#ffffff;"); lblMsg.setEncode(false); lblMsg.setValue(header); btnOk.addEventListener(Events.ON_CLICK, this); btnPrint.addEventListener(Events.ON_CLICK, this); Panel pnlMessage = new Panel(); pnlMessage.setStyle(MESSAGE_PANEL_STYLE); pnlMessage.appendChild(lblMsg); Separator sep = new Separator("horizontal"); pnlMessage.appendChild(sep); Hbox pnlImage = new Hbox(); img.setSrc((pi != null && pi.isError()) ? ERROR:INFORMATION); ZKUpdateUtil.setWidth(pnlImage, "72px"); pnlImage.setAlign("center"); pnlImage.setPack("center"); pnlImage.appendChild(img); Hbox north = new Hbox(); north.setAlign("center"); north.setStyle("margin: 20pt 10pt 20pt 10pt;"); // trbl this.appendChild(north); north.appendChild(pnlImage); pnlMessage.appendChild(new Text(Msg.getMsg(Env.getCtx(), pi.isError()?"Error":"Success"))); pnlMessage.appendChild(new Separator("horizontal")); north.appendChild(pnlMessage); Hbox pnlButtons = new Hbox(); ZKUpdateUtil.setHeight(pnlButtons, "52px"); pnlButtons.setAlign("center"); pnlButtons.setPack("end"); btnPrint.setVisible(false); pnlButtons.appendChild(btnPrint); pnlButtons.appendChild(btnOk); Separator separator = new Separator(); ZKUpdateUtil.setWidth(separator, "100%"); separator.setBar(true); this.appendChild(separator); Hbox south = new Hbox(); south.setPack("end"); ZKUpdateUtil.setWidth(south, "100%"); this.appendChild(south); south.appendChild(pnlButtons); if (pi != null){ m_logs = pi.getLogs(); String summary = pi.getSummary(); if (summary != null && summary.indexOf('@') != -1) summary = Msg.parseTranslation(Env.getCtx(), summary); if (summary != null && summary.trim().length() > 0 && !summary.trim().equalsIgnoreCase("Report")){ pnlMessage.appendChild(new Text(summary)); } } this.m_logs = m_logs; if(isPrintable()) btnPrint.setVisible(true); if (m_logs != null && m_logs.length > 0){ separator = new Separator(); ZKUpdateUtil.setWidth(separator, "100%"); separator.setBar(true); pnlMessage.appendChild(separator); for (int loopCtr = 0; loopCtr < m_logs.length; loopCtr++) { ProcessInfoLog log = m_logs[loopCtr]; if (log.getP_Msg() != null || log.getP_Date() != null || log.getP_Number() != null) { SimpleDateFormat dateFormat = DisplayType.getDateFormat(DisplayType.DateTime); StringBuffer sb = new StringBuffer (); // if (log.getP_Date() != null) sb.append(dateFormat.format(log.getP_Date())) .append(" \t"); // if (log.getP_Number() != null) sb.append(log.getP_Number()) .append(" \t"); // if (log.getP_Msg() != null) sb.append(Msg.parseTranslation(Env.getCtx(), log.getP_Msg())); // if (log.getAD_Table_ID() > 0 && log.getRecord_ID() > 0) { DocumentLink recordLink = new DocumentLink(sb.toString(), log.getAD_Table_ID(), log.getRecord_ID()); recordLink.addEventListener(Events.ON_CLICK, e -> { if (isAutoCloseAfterZoom()) this.detach(); }); pnlMessage.appendChild(recordLink); } else { Text recordText = new Text(sb.toString()); pnlMessage.appendChild(recordText); } pnlMessage.appendChild(new Separator("horizontal")); } } } } @Override public void onEvent(Event event) throws Exception { if (event == null) return; if (event.getTarget() == btnOk) { this.detach(); } if(event.getTarget() == btnPrint) { Clients.showBusy(Msg.getMsg(Env.getCtx(), "Processing")); Executions.schedule(this.getDesktop(), e -> onPrint(), new Event("onPrint")); } } /** * Print all printable documents in {@link #m_logs} */ private void onPrint() { Clients.clearBusy(); // Loop through all items List pdfList = new ArrayList(); for (int i = 0; i < m_logs.length; i++) { int recordID = m_logs[i].getRecord_ID(); int reportEngineType = ReportEngine.getReportEngineType(m_logs[i].getAD_Table_ID()); ReportEngine re = null; if((reportEngineType >= 0) && (recordID > 0)) { re = ReportEngine.get (Env.getCtx(), reportEngineType, recordID); pdfList.add(re.getPDF()); } } if (pdfList.size() > 1) { try { File outFile = FileUtil.createTempFile(getTitle(), ".pdf"); AEnv.mergePdf(pdfList, outFile); Window win = new SimplePDFViewer(getTitle(), new FileInputStream(outFile)); SessionManager.getAppDesktop().showWindow(win, "center"); } catch (Exception e) { throw new RuntimeException(e.getLocalizedMessage(), e); } } else if (pdfList.size() > 0) { try { Window win = new SimplePDFViewer(getTitle(), new FileInputStream(pdfList.get(0))); SessionManager.getAppDesktop().showWindow(win, "center"); } catch (Exception e) { throw new RuntimeException(e.getLocalizedMessage(), e); } } this.detach(); } /** * @return true if there are printable document in {@link #m_logs} */ public boolean isPrintable() { if (m_logs == null) return false; for(ProcessInfoLog log : m_logs) { if (log.getAD_Table_ID() > 0 && log.getRecord_ID() > 0 && ReportEngine.getReportEngineType(log.getAD_Table_ID()) >= 0) return true; } return false; } @Override public void focus() { btnOk.focus(); } /** * enable/disable auto close of dialog after zoom using document link * @param autoClose */ public void setAutoCloseAfterZoom(boolean autoClose) { isAutoCloseAfterZoom = autoClose; } /** * * @return auto close after zoom state */ public boolean isAutoCloseAfterZoom() { return isAutoCloseAfterZoom; } /** * after run a process, call this function to show result in a dialog * @param pi ProcessInfo * @param windowNo * @param comp Component * @param needFillLogFromDb if ProcessInfoUtil.setLogFromDB(pi) is called by outer function, * just pass false, otherwise pass true to avoid duplicate message */ public static ProcessInfoDialog showProcessInfo (ProcessInfo pi, int windowNo, final Component comp, boolean needFillLogFromDb) { ProcessInfoDialog dialog = new ProcessInfoDialog(pi, needFillLogFromDb); final ISupportMask supportMask = LayoutUtils.showWindowWithMask(dialog, comp, LayoutUtils.OVERLAP_PARENT); dialog.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() { @Override public void onEvent(Event event) throws Exception { supportMask.hideMask(); } }); Executions.schedule(comp.getDesktop(), e -> dialog.btnOk.focus(), new Event("onPostShowProcessInfoDialog")); return dialog; } }