diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java index d69ad71bbf..6efd564e81 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java @@ -304,6 +304,8 @@ public class SessionContextListener implements ExecutionInit, if(Executions.getCurrent()==null) return; + desktop.addListener(new ValidateReadonlyComponent()); + if (ServerContext.getCurrentInstance().isEmpty() || !isContextValid()) { setupExecutionContextFromSession(Executions.getCurrent()); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/ValidateReadonlyComponent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/ValidateReadonlyComponent.java new file mode 100644 index 0000000000..e0179fd6ef --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/ValidateReadonlyComponent.java @@ -0,0 +1,116 @@ +/****************************************************************************** + * Product: iDempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2014 T.G.I. * + * 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.session; + +import java.util.logging.Level; + +import org.compiere.util.CLogger; +import org.zkoss.zk.au.AuRequest; +import org.zkoss.zk.au.AuService; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.WrongValueException; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.ext.Disable; +import org.zkoss.zk.ui.ext.Readonly; +import org.zkoss.zul.Button; +import org.zkoss.zul.Checkbox; +import org.zkoss.zul.Combobox; +import org.zkoss.zul.impl.InputElement; + + +/** + * + * this service is interception into desktop process, + * it will denied request to modify a readonly file or action on readonly button + * @author hieplq + * + */ +public class ValidateReadonlyComponent implements AuService { + private static CLogger log = CLogger.getCLogger (ValidateReadonlyComponent.class); + /** + * throw WrongValueException when denied request, other false + */ + @Override + public boolean service(AuRequest request, boolean everError) { + String cmd = request.getCommand(); + + // event is reason change value of component + boolean considerEvent = Events.ON_CHANGE.equals(cmd) || Events.ON_CHECK.equals(cmd) || + Events.ON_SELECT.equals(cmd) || Events.ON_OPEN.equals(cmd) || + Events.ON_CLICK.equals(cmd) || Events.ON_DOUBLE_CLICK.equals(cmd) || Events.ON_OK.equals(cmd) || Events.ON_UPLOAD.equals(cmd); + + if (!considerEvent){ + return false; // don't denied + } + + Component comp = request.getComponent(); + + // get necessary interface + Disable iDisable = null; + Readonly iReadonly = null; + + if (comp instanceof Disable){ + iDisable = (Disable)comp; + } + + if (comp instanceof Readonly){ + iReadonly = (Readonly)comp; + } + + boolean isCannotEdit = (iDisable != null && iDisable.isDisabled()) || (iReadonly != null && iReadonly.isReadonly()); + + // don't care editable component + if (!isCannotEdit){ + return false; + } + + // detect kind of component raise event + InputElement inputComp = null; + Checkbox checkbox = null; + Combobox comb = null; + Button button = null; + + if (comp instanceof Combobox){// have to check before InputElement + comb = (Combobox)comp; + }if (comp instanceof InputElement){ + inputComp = (InputElement)comp;// textbox, datebox, numberbox,... + }else if (comp instanceof Checkbox){ + checkbox = (Checkbox)comp; + }if (comp instanceof Button){// have to check latest + button = (Button)comp; + }else {//HtmlBasedComponent + log.log(Level.SEVERE, String.format("Consider to denied event of control %1$s when it's readonly on event %2$s", comp.getClass(), cmd)); + return false;// just log to investigate don't lock process + } + + + if (isCannotEdit){ + boolean editing = (inputComp != null && Events.ON_CHANGE.equals(cmd)) || + (checkbox != null && Events.ON_CHECK.equals(cmd)) || + (comb != null && (Events.ON_CHANGE.equals(cmd) || Events.ON_SELECT.equals(cmd) || Events.ON_OPEN.equals(cmd))) || + (button != null && (Events.ON_CLICK.equals(cmd) || Events.ON_OK.equals(cmd) || Events.ON_UPLOAD.equals(cmd)));; + + // for combobox each change have both event onchange and onselect, so will have dupplicate message + // dupplicate is acceptable for hack guy + if (editing){ + comp.invalidate(); + throw new WrongValueException ("I know you. Don't try to hack me"); + } + } + + return false; + } + +}