/****************************************************************************** * Product: Posterita Ajax UI * * Copyright (C) 2007 Posterita Ltd. 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 * * Posterita Ltd., 3, Draper Avenue, Quatre Bornes, Mauritius * * or via info@posterita.org or http://www.posterita.org/ * *****************************************************************************/ package org.adempiere.webui.component; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.adempiere.util.Callback; import org.adempiere.webui.AdempiereIdGenerator; import org.adempiere.webui.ClientInfo; import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.editor.WEditor; import org.adempiere.webui.editor.WStringEditor; import org.adempiere.webui.event.ValueChangeEvent; import org.adempiere.webui.event.ValueChangeListener; import org.adempiere.webui.factory.ButtonFactory; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.util.ZKUpdateUtil; import org.compiere.model.MSysConfig; import org.compiere.model.SystemProperties; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; import org.zkoss.zhtml.Text; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.WrongValueException; 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.select.annotation.Listen; import org.zkoss.zul.Hbox; import org.zkoss.zul.Image; import org.zkoss.zul.Vbox; /** * Messagebox : Replaces ZK's Messagebox * * @author Niraj Sohun * @date Jul 31, 2007 * @contributor Andreas Sumerauer IDEMPIERE-4702 */ public class Messagebox extends Window implements EventListener { /** * generated serial id */ private static final long serialVersionUID = 8928526331932742124L; private static final String MESSAGE_PANEL_STYLE = "text-align:left; word-break: break-all; overflow: auto; max-height: 350pt; min-width: 230pt; max-width: 450pt;"; private static final String SMALLER_MESSAGE_PANEL_STYLE = "text-align:left; word-break: break-all; overflow: auto; max-height: 350pt; min-width: 180pt; "; private String msg = ""; private String imgSrc = ""; private Text lblMsg = new Text(); private Button btnOk; private Button btnCancel; private Button btnYes; private Button btnNo; private Button btnAbort; private Button btnRetry; private Button btnIgnore; private WEditor inputField; private boolean isInputMandatory; private boolean isExceptionThrown = false; private Image img = new Image(); /** button constant for button pressed by user */ private int returnValue; @SuppressWarnings("rawtypes") private Callback callback; private boolean isInput = false; /** A OK button. */ public static final int OK = 0x0001; /** A Cancel button. */ public static final int CANCEL = 0x0002; /** A Yes button. */ public static final int YES = 0x0010; /** A No button. */ public static final int NO = 0x0020; /** A Abort button. */ public static final int ABORT = 0x0100; /** A Retry button. */ public static final int RETRY = 0x0200; /** A IGNORE button. */ public static final int IGNORE = 0x0400; /** A INPUT Textfield*/ public static final int INPUT = 0x0800; /** A symbol consisting of a question mark in a circle. */ public static final String QUESTION = "~./zul/img/msgbox/question-btn.png"; /** A symbol consisting of an exclamation point in a triangle with a yellow background. */ public static final String EXCLAMATION = "~./zul/img/msgbox/warning-btn.png"; /** A symbol of a lowercase letter i in a circle. */ public static final String INFORMATION = "~./zul/img/msgbox/info-btn.png"; /** A symbol consisting of a white X in a circle with a red background. */ public static final String ERROR = "~./zul/img/msgbox/stop-btn.png"; /** Contains no symbols. */ public static final String NONE = null; /* SysConfig USE_ESC_FOR_TAB_CLOSING */ private boolean isUseEscForTabClosing = MSysConfig.getBooleanValue(MSysConfig.USE_ESC_FOR_TAB_CLOSING, false, Env.getAD_Client_ID(Env.getCtx())); /** * Default constructor */ public Messagebox() { super(); } /** * Layout dialog */ private void init() { setSclass("popup-dialog"); Properties ctx = Env.getCtx(); lblMsg.setEncode(false); lblMsg.setValue(msg); lblMsg.setClientAttribute("style", "word-break: normal;"); // Invert - Unify OK/Cancel IDEMPIERE-77 btnOk = ButtonFactory.createNamedButton(ConfirmPanel.A_OK); btnOk.setId("btnOk"); btnOk.addEventListener(Events.ON_CLICK, this); btnCancel = ButtonFactory.createNamedButton(ConfirmPanel.A_CANCEL); btnCancel.addEventListener(Events.ON_CLICK, this); btnCancel.setId("btnCancel"); String yesLabel = Util.cleanAmp(Msg.getMsg(ctx, "Yes")); btnYes = ButtonFactory.createButton(ButtonFactory.isWithText() ? yesLabel : null, ButtonFactory.isWithImage() ? (ButtonFactory.isWithText() ? ThemeManager.getThemeResource("images/Ok16.png") : ThemeManager.getThemeResource("images/Ok24.png")) : null, ButtonFactory.isWithText() ? null : yesLabel); btnYes.addEventListener(Events.ON_CLICK, this); btnYes.setId("btnYes"); String noLabel = Util.cleanAmp(Msg.getMsg(ctx, "No")); btnNo = ButtonFactory.createButton(ButtonFactory.isWithText() ? noLabel : null, ButtonFactory.isWithImage() ? ( ButtonFactory.isWithText() ? ThemeManager.getThemeResource("images/Cancel16.png") : ThemeManager.getThemeResource("images/Cancel24.png")) : null, ButtonFactory.isWithText() ? null : noLabel); btnNo.addEventListener(Events.ON_CLICK, this); btnNo.setId("btnNo"); btnAbort = ButtonFactory.createButton("Abort", null, null); btnAbort.addEventListener(Events.ON_CLICK, this); btnAbort.setId("btnAbort"); btnRetry = ButtonFactory.createButton("Retry", null, null); btnRetry.addEventListener(Events.ON_CLICK, this); btnRetry.setId("btnRetry"); btnIgnore = ButtonFactory.createNamedButton("Ignore"); btnIgnore.addEventListener(Events.ON_CLICK, this); btnIgnore.setId("btnIgnore"); Panel pnlMessage = new Panel(); if (ClientInfo.maxWidth(399)) { pnlMessage.setStyle(SMALLER_MESSAGE_PANEL_STYLE); this.setWidth("100%"); } else pnlMessage.setStyle(MESSAGE_PANEL_STYLE); pnlMessage.appendChild(lblMsg); ZKUpdateUtil.setHflex(pnlMessage, "min"); Panel pnlInput= new Panel(); pnlInput.setStyle(MESSAGE_PANEL_STYLE); pnlInput.appendChild(inputField.getComponent()); Vbox pnlText = new Vbox(); pnlText.appendChild(pnlMessage); pnlText.appendChild(pnlInput); Hbox pnlImage = new Hbox(); String iconSclass = null; Label label = null; if (ThemeManager.isUseFontIconForImage()) { if (imgSrc.equals(QUESTION)) iconSclass = "z-icon-QuestionMessageBox"; else if (imgSrc.equals(EXCLAMATION)) iconSclass = "z-icon-ExclamationMessageBox"; else if (imgSrc.equals(INFORMATION)) iconSclass = "z-icon-InformationMessageBox"; else if (imgSrc.equals(ERROR)) iconSclass = "z-icon-ErrorMessageBox"; } if (ThemeManager.isUseFontIconForImage() && iconSclass != null) { label = new Label(); label.setSclass(iconSclass); } else img.setSrc(imgSrc); ZKUpdateUtil.setWidth(pnlImage, "72px"); pnlImage.setAlign("center"); pnlImage.setPack("center"); if (ThemeManager.isUseFontIconForImage() && iconSclass != null) pnlImage.appendChild(label); else pnlImage.appendChild(img); Hbox north = new Hbox(); north.setAlign("center"); this.appendChild(north); north.appendChild(pnlImage); north.appendChild(pnlText); north.setSclass("dialog-content"); north.setWidth("100%");; Hbox pnlButtons = new Hbox(); pnlButtons.setAlign("center"); pnlButtons.setPack("end"); pnlButtons.appendChild(btnOk); pnlButtons.appendChild(btnCancel); pnlButtons.appendChild(btnYes); pnlButtons.appendChild(btnNo); pnlButtons.appendChild(btnAbort); pnlButtons.appendChild(btnRetry); pnlButtons.appendChild(btnIgnore); ZKUpdateUtil.setWidth(pnlButtons, "100%"); this.appendChild(pnlButtons); pnlButtons.setSclass("dialog-footer"); this.setBorder("normal"); this.setContentStyle("background-color:#ffffff;"); this.setPosition("left, top"); inputField.getComponent().addEventListener(Events.ON_OK, this); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL sfor message box icon * @return button constant for button press by user */ public int show(String message, String title, int buttons, String icon) { return show(message, title, buttons, icon, null); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param callback * @return button constant for button press by user */ public int show(String message, String title, int buttons, String icon, Callback callback) { return show(message, title, buttons, icon, callback, false); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param callback * @param modal * @return button constant for button press by user */ public int show(String message, String title, int buttons, String icon, Callback callback, boolean modal) { return show(message, title, buttons, icon, null, false, callback, modal); } /** * Show message box dialog with optional input editor * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param editor optional input editor * @param isInputMandatory true if editor input is mandatory * @param callback * @param modal * @return button constant for button press by user */ public int show(String message, String title, int buttons, String icon, WEditor editor, boolean isInputMandatory, Callback callback, boolean modal) { this.msg = message; this.imgSrc = icon; this.callback = callback; if (editor == null) inputField = new WStringEditor(); else inputField = editor; this.isInputMandatory = isInputMandatory; init(); btnOk.setVisible(false); btnCancel.setVisible(false); btnYes.setVisible(false); btnNo.setVisible(false); btnRetry.setVisible(false); btnAbort.setVisible(false); btnIgnore.setVisible(false); inputField.setVisible(false); if ((buttons & OK) != 0) btnOk.setVisible(true); if ((buttons & CANCEL) != 0) btnCancel.setVisible(true); if ((buttons & YES) != 0) btnYes.setVisible(true); if ((buttons & NO) != 0) btnNo.setVisible(true); if ((buttons & RETRY) != 0) btnRetry.setVisible(true); if ((buttons & ABORT) != 0) btnAbort.setVisible(true); if ((buttons & IGNORE) != 0) btnIgnore.setVisible(true); if ((buttons & INPUT) != 0) { inputField.setVisible(true); isInput = true; inputField.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent evt) { isExceptionThrown = false; } }); } this.setTitle(title); this.setPosition("center"); this.setClosable(true); this.setAttribute(Window.MODE_KEY, modal ? Window.MODE_MODAL : Window.MODE_HIGHLIGHTED); this.setSizable(true); this.setVisible(true); if (SystemProperties.isZkUnitTest()) { String id = "MessageBox_"+AdempiereIdGenerator.escapeId(title); //make sure id is unique Page page = AEnv.getDesktop().getFirstPage(); Component fellow = page.getFellowIfAny(id); if (fellow != null) { int count = 0; String newId = null; while (fellow != null) { newId = id + "_" + ++count; fellow = page.getFellowIfAny(newId); } id = newId; } this.setId(id); } AEnv.showCenterScreen(this); return returnValue; } /** * Show message box dialog * @param message * @param title * @param buttons * @param icon image URL for message box icon * @return button constant for button press by user */ public static int showDialog(String message, String title, int buttons, String icon) { return showDialog(message, title, buttons, icon, null); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param callback * @return button constant for button press by user */ public static int showDialog(String message, String title, int buttons, String icon, Callback callback) { return showDialog(message, title, buttons, icon, callback, false); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param callback * @param modal * @return button constant for button press by user */ public static int showDialog(String message, String title, int buttons, String icon, Callback callback, boolean modal) { return showDialog(message, title, buttons, icon, null, false, callback, modal); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param editor * @param callback * @param modal * @return button constant for button press by user */ public static int showDialog(String message, String title, int buttons, String icon, WEditor editor, Callback callback, boolean modal) { return showDialog(message, title, buttons, icon, editor, false, callback, modal); } /** * Show message box dialog * @param message * @param title * @param buttons buttons to be shown in the dialog. use the | operator to combine multiple button constant. * @param icon image URL for message box icon * @param editor optional input editor * @param isInputMandatory true if input editor is mandatory * @param callback * @param modal * @return button constant for button press by user */ public static int showDialog(String message, String title, int buttons, String icon, WEditor editor, boolean isInputMandatory, Callback callback, boolean modal) { Messagebox msg = new Messagebox(); return msg.show(message, title, buttons, icon, editor, isInputMandatory, callback, modal); } @Listen("onCancel") public void onCancel() throws Exception { returnValue = CANCEL; close(); } @Override public void onEvent(Event event) throws Exception { if (event == null) return; if (event.getTarget() == btnOk || (event.getTarget() == inputField.getComponent() && event.getName().equals(Events.ON_OK))) { returnValue = OK; } else if (event.getTarget() == btnCancel) { returnValue = CANCEL; } else if (event.getTarget() == btnYes) { returnValue = YES; } else if (event.getTarget() == btnNo) { returnValue = NO; } else if (event.getTarget() == btnAbort) { returnValue = ABORT; } else if (event.getTarget() == btnRetry) { returnValue = RETRY; } else if (event.getTarget() == btnIgnore) { returnValue = IGNORE; } //TODO else { returnValue = 0; } validateOnClose(); } /** * Perform validation before closing of dialog.
* Throw {@link WrongValueException} if there's any validation error. */ private void validateOnClose() { // Don't close on OK if input is mandatory while input field is empty if ((returnValue == CANCEL) || !isInputMandatory || (isInputMandatory && !Util.isEmpty(String.valueOf(inputField.getValue())))) // if Valid Input is defined, don't close on OK until user types the Valid Input if(!Util.isEmpty(inputField.getValidInput())) { if((returnValue == CANCEL) || (inputField.isValid(String.valueOf(inputField.getValue())) && returnValue == OK)) { close(); } else { isExceptionThrown = true; returnValue = 0; throw new WrongValueException(inputField.getComponent(), Msg.getMsg(Env.getCtx(), "ValueNotCorrect")); } } else { close(); } // else { isExceptionThrown = true; returnValue = 0; throw new WrongValueException(inputField.getComponent(), Msg.getMsg(Env.getCtx(), "AnswerMandatory")); } // } /** * Close dialog */ private void close() { try { // do not allow to close tab for Events.ON_CTRL_KEY event if(isUseEscForTabClosing) SessionManager.getAppDesktop().setCloseTabWithShortcut(false); this.detach(); } catch (NullPointerException npe) { if (! (SessionManager.getSessionApplication() == null)) // IDEMPIERE-1937 - ignore when session was closed throw npe; } } @SuppressWarnings("unchecked") @Override public void onPageDetached(Page page) { super.onPageDetached(page); if (callback != null && !isInput) { callback.onCallback(returnValue); } else if (callback != null && isInput && !btnCancel.isVisible() && !btnNo.isVisible()) { callback.onCallback(inputField.getValue()); } else if (callback != null && isInput && (btnCancel.isVisible() || btnNo.isVisible())) { Map map = new HashMap(); map.put(returnValue == OK || returnValue == YES, isExceptionThrown ? "" : inputField.getValue()); callback.onCallback(map.entrySet().iterator().next()); } } }