Initial implementation of display logic support
authorIván Perdomo <ivan.perdomo@openbravo.com>
Wed, 12 Jan 2011 18:01:02 +0100
changeset 9737 078027b29e33
parent 9736 beff16ac0034
child 9738 3a464c5af075
Initial implementation of display logic support
- Added a DynamicParserException to handle old pseudo-js code, removed the
parser from the FormInitializationComponent
- OBViewFormComponent:
* Changed the boolean values to be booleans instead of string
* Added redrawOnChange on fields part of a dynamic expression
* Added showIf on fields that have a display logic
- RequestContext: Added a default content-type used for unit testing
modules/org.openbravo.client.application/src/org/openbravo/client/application/DynamicExpressionParser.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/layout.js.ftl
modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java
modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/RequestContext.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/DynamicExpressionParser.java	Wed Jan 12 18:01:02 2011 +0100
@@ -0,0 +1,189 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License.
+ * The Original Code is Openbravo ERP.
+ * The Initial Developer of the Original Code is Openbravo SLU
+ * All portions are Copyright (C) 2011 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+package org.openbravo.client.application;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.hibernate.criterion.Expression;
+import org.openbravo.client.kernel.KernelUtils;
+import org.openbravo.client.kernel.RequestContext;
+import org.openbravo.dal.service.OBCriteria;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.erpCommon.utility.Utility;
+import org.openbravo.model.ad.ui.AuxiliaryInput;
+import org.openbravo.model.ad.ui.Field;
+import org.openbravo.model.ad.ui.Tab;
+import org.openbravo.service.db.DalConnectionProvider;
+
+/**
+ * Parses a dynamic expressions and extracts information, e.g. The expression is using a field or an
+ * auxiliary input, etc. <br/>
+ * The transformation of @Expression@ is the following:
+ * <ul>
+ * <li>@ColumnName@ are transformed into property name, e.g. @DocStatus@ into <b>documentStatus</b></li>
+ * <li>@AuxiliarInput@ is transformed just removes the <b>@</b>, e.g. @FinancialManagementDep@ into
+ * <b>FinancialManagementDep</b></li>
+ * </ul>
+ * 
+ */
+public class DynamicExpressionParser {
+
+  private static final String[][] COMPARATIONS = { { "==", " === " }, { "=", " === " },
+      { "!", " !== " }, { "^", " !== " }, { "-", " !== " } };
+
+  private static final String[][] UNIONS = { { "|", " || " }, { "&", " && " } };
+
+  private static Map<String, String> exprToJSMap;
+
+  static {
+    exprToJSMap = new HashMap<String, String>();
+    exprToJSMap.put("'Y'", "true");
+  }
+
+  private List<Field> fieldsInExpression = new ArrayList<Field>();
+  private List<AuxiliaryInput> auxInputsInExpression = new ArrayList<AuxiliaryInput>();
+
+  private String code;
+  private Tab tab;
+  private StringBuffer jsCode;
+
+  public DynamicExpressionParser(String code, Tab tab) {
+    this.code = code;
+    this.tab = tab;
+    parse();
+  }
+
+  /*
+   * Note: This method was partially copied from WadUtility.
+   */
+  public void parse() {
+    StringTokenizer st = new StringTokenizer(code, "|&", true);
+    String token, token2;
+    String strAux;
+    jsCode = new StringBuffer();
+    while (st.hasMoreTokens()) {
+      strAux = st.nextToken().trim();
+      int i[] = getFirstElement(UNIONS, strAux);
+      if (i[0] != -1) {
+        strAux = strAux.substring(0, i[0]) + UNIONS[i[1]][1]
+            + strAux.substring(i[0] + UNIONS[i[1]][0].length());
+      }
+
+      int pos[] = getFirstElement(COMPARATIONS, strAux);
+      token = strAux;
+      token2 = "";
+      if (pos[0] >= 0) {
+        token = strAux.substring(0, pos[0]);
+        token2 = strAux.substring(pos[0] + COMPARATIONS[pos[1]][0].length(), strAux.length());
+        strAux = strAux.substring(0, pos[0]) + COMPARATIONS[pos[1]][1]
+            + strAux.substring(pos[0] + COMPARATIONS[pos[1]][0].length(), strAux.length());
+      }
+
+      jsCode.append(getDisplayLogicText(token));
+
+      if (pos[0] >= 0) {
+        jsCode.append(COMPARATIONS[pos[1]][1]);
+      }
+
+      jsCode.append(getDisplayLogicText(token2));
+    }
+  }
+
+  public String getJSExpression() {
+    return jsCode.toString();
+  }
+
+  public String toString() {
+    return getJSExpression();
+  }
+
+  public List<Field> getFields() {
+    return fieldsInExpression;
+  }
+
+  /*
+   * This method was partially copied from WadUtility.
+   */
+  private String getDisplayLogicText(String token) {
+    StringBuffer strOut = new StringBuffer();
+    String localToken = token;
+    int i = localToken.indexOf("@");
+    while (i != -1) {
+      strOut.append(localToken.substring(0, i));
+      localToken = localToken.substring(i + 1);
+      i = localToken.indexOf("@");
+      if (i != -1) {
+        String strAux = localToken.substring(0, i);
+        localToken = localToken.substring(i + 1);
+        String st = getDisplayLogicTextTranslate(strAux);
+        strOut.append(st);
+      }
+      i = localToken.indexOf("@");
+    }
+    strOut.append(exprToJSMap.get(localToken) != null ? exprToJSMap.get(localToken) : localToken);
+    return strOut.toString();
+  }
+
+  /*
+   * This method is a different reimplementation of an equivalent method in WadUtility
+   */
+  private String getDisplayLogicTextTranslate(String token) {
+    if (token == null || token.trim().equals(""))
+      return "";
+    for (Field field : tab.getADFieldList()) {
+      if (token.equalsIgnoreCase(field.getColumn().getDBColumnName())) {
+        fieldsInExpression.add(field);
+        return "form.getValue('"
+            + KernelUtils.getInstance().getPropertyFromColumn(field.getColumn()).getName() + "')";
+      }
+    }
+    OBCriteria<AuxiliaryInput> auxInC = OBDal.getInstance().createCriteria(AuxiliaryInput.class);
+    auxInC.add(Expression.eq(AuxiliaryInput.PROPERTY_TAB, tab));
+    List<AuxiliaryInput> auxInputs = auxInC.list();
+    for (AuxiliaryInput auxIn : auxInputs) {
+      if (token.equalsIgnoreCase(auxIn.getName())) {
+        auxInputsInExpression.add(auxIn);
+        return "form.auxInputs['" + auxIn.getName() + "']";
+      }
+    }
+    return "'"
+        + Utility.getContext(new DalConnectionProvider(false), RequestContext.get()
+            .getVariablesSecureApp(), token, tab.getWindow().getId()) + "'";
+  }
+
+  /*
+   * This method was partially copied from WadUtility.
+   */
+  private static int[] getFirstElement(String[][] array, String token) {
+    int min[] = { -1, -1 }, aux;
+    for (int i = 0; i < array.length; i++) {
+      aux = token.indexOf(array[i][0]);
+      if (aux != -1 && (aux < min[0] || min[0] == -1)) {
+        min[0] = aux;
+        min[1] = i;
+      }
+    }
+    return min;
+  }
+
+}
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/layout.js.ftl	Wed Jan 12 17:37:50 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/layout.js.ftl	Wed Jan 12 18:01:02 2011 +0100
@@ -126,7 +126,7 @@
   width: '100%',
   height: '100%',
   
-  destroyPanes: false,
+  destroyPanes: true,
   
   stateAsString: null,
     
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Wed Jan 12 17:37:50 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Wed Jan 12 18:01:02 2011 +0100
@@ -26,8 +26,8 @@
         parentProperty: ${fieldDefinition.parentProperty?string},
         colSpan: ${fieldDefinition.colSpan},
         rowSpan: ${fieldDefinition.rowSpan},
-        startRow: ${fieldDefinition.startRow},
-        endRow: ${fieldDefinition.endRow},
+        startRow: ${fieldDefinition.startRow?string},
+        endRow: ${fieldDefinition.endRow?string},
         width: '*',
         <#if fieldDefinition.standardField>
         columnName: '${fieldDefinition.columnName?string}',
@@ -35,6 +35,13 @@
         referencedKeyColumnName: '${fieldDefinition.referencedKeyColumnName?string}',
         targetEntity: '${fieldDefinition.targetEntity?string}',
         required: ${fieldDefinition.required?string},
+        redrawOnChange: ${fieldDefinition.redrawOnChange?string},
+          <#if fieldDefinition.showIf != "">
+          showIf: function(item, value, form) {
+                    // debug console.log('%o', form);
+                    return form.auxInputs && (${fieldDefinition.showIf});
+                  },
+          </#if>
           <#if fieldDefinition.searchField>
           displayField: '${fieldDefinition.name?js_string}._identifier',
           valueField: '${fieldDefinition.name?js_string}',
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java	Wed Jan 12 17:37:50 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java	Wed Jan 12 18:01:02 2011 +0100
@@ -28,7 +28,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import org.apache.log4j.Logger;
 import org.codehaus.jettison.json.JSONArray;
@@ -336,24 +335,6 @@
             }
           }
           finalObject.put("dynamicCols", new JSONArray(changeEventCols));
-          // And we also include information related to the displaylogic and readonlylogic
-          // expressions
-          JSONObject displaylogics = new JSONObject();
-          for (Field field : fields) {
-            if (field.getDisplayLogic() != null) {
-              String dl = parseDisplayLogic(field);
-              displaylogics.put(field.getColumn().getDBColumnName(), dl);
-            }
-          }
-          finalObject.put("displaylogic", displaylogics);
-          JSONObject readonlylogics = new JSONObject();
-          for (Field field : fields) {
-            if (field.getColumn().getReadOnlyLogic() != null) {
-              String dl = parseReadOnlyLogic(field.getColumn(), tab);
-              readonlylogics.put(field.getColumn().getDBColumnName(), dl);
-            }
-          }
-          finalObject.put("readonlylogic", readonlylogics);
         }
 
         if (mode.equals("EDIT") && row != null) {
@@ -406,115 +387,6 @@
     return referencedEntity.equals(parentEntity);
   }
 
-  private String parseDisplayLogic(Field field) {
-    String displaylogic = field.getDisplayLogic();
-    return parseDLExpression(displaylogic, field.getTab());
-  }
-
-  private String parseReadOnlyLogic(Column col, Tab tab) {
-    String readonlylogic = col.getReadOnlyLogic();
-    return parseDLExpression(readonlylogic, tab);
-  }
-
-  private static String[][] comparations = { { "==", " == " }, { "=", " == " }, { "!", " != " },
-      { "^", " != " }, { "-", " != " } };
-  private static String[][] unions = { { "|", " || " }, { "&", " && " } };
-
-  /*
-   * This method was partially copied from WadUtility.
-   */
-  private String parseDLExpression(String code, Tab tab) {
-    StringTokenizer st = new StringTokenizer(code, "|&", true);
-    String token, token2;
-    String strAux;
-    StringBuffer strOut = new StringBuffer();
-    while (st.hasMoreTokens()) {
-      strAux = st.nextToken().trim();
-      int i[] = getFirstElement(unions, strAux);
-      if (i[0] != -1) {
-        strAux = strAux.substring(0, i[0]) + unions[i[1]][1]
-            + strAux.substring(i[0] + unions[i[1]][0].length());
-      }
-
-      int pos[] = getFirstElement(comparations, strAux);
-      token = strAux;
-      token2 = "";
-      if (pos[0] >= 0) {
-        token = strAux.substring(0, pos[0]);
-        token2 = strAux.substring(pos[0] + comparations[pos[1]][0].length(), strAux.length());
-        strAux = strAux.substring(0, pos[0]) + comparations[pos[1]][1]
-            + strAux.substring(pos[0] + comparations[pos[1]][0].length(), strAux.length());
-      }
-      strOut.append(getDisplayLogicText(token, tab));
-      if (pos[0] >= 0)
-        strOut.append(comparations[pos[1]][1]);
-      strOut.append(getDisplayLogicText(token2, tab));
-    }
-    return strOut.toString();
-  }
-
-  /*
-   * This method was partially copied from WadUtility.
-   */
-  private String getDisplayLogicText(String token, Tab tab) {
-    StringBuffer strOut = new StringBuffer();
-    String localToken = token;
-    int i = localToken.indexOf("@");
-    while (i != -1) {
-      strOut.append(localToken.substring(0, i));
-      localToken = localToken.substring(i + 1);
-      i = localToken.indexOf("@");
-      if (i != -1) {
-        String strAux = localToken.substring(0, i);
-        localToken = localToken.substring(i + 1);
-        String st = getDisplayLogicTextTranslate(strAux, tab);
-        strOut.append(st);
-      }
-      i = localToken.indexOf("@");
-    }
-    strOut.append(localToken);
-    return strOut.toString();
-  }
-
-  /*
-   * This method is a different reimplementation of an equivalent method in WadUtility
-   */
-  private String getDisplayLogicTextTranslate(String token, Tab tab) {
-    if (token == null || token.trim().equals(""))
-      return "";
-    for (Field field : tab.getADFieldList()) {
-      if (token.equalsIgnoreCase(field.getName())) {
-        return field.getName();
-      }
-    }
-    OBCriteria<AuxiliaryInput> auxInC = OBDal.getInstance().createCriteria(AuxiliaryInput.class);
-    auxInC.add(Expression.eq(AuxiliaryInput.PROPERTY_TAB, tab));
-    List<AuxiliaryInput> auxInputs = auxInC.list();
-    for (AuxiliaryInput auxIn : auxInputs) {
-      if (token.equalsIgnoreCase(auxIn.getName())) {
-        return auxIn.getName();
-      }
-    }
-    return "'"
-        + Utility.getContext(new DalConnectionProvider(false), RequestContext.get()
-            .getVariablesSecureApp(), token, tab.getWindow().getId()) + "'";
-  }
-
-  /*
-   * This method was partially copied from WadUtility.
-   */
-  private static int[] getFirstElement(String[][] array, String token) {
-    int min[] = { -1, -1 }, aux;
-    for (int i = 0; i < array.length; i++) {
-      aux = token.indexOf(array[i][0]);
-      if (aux != -1 && (aux < min[0] || min[0] == -1)) {
-        min[0] = aux;
-        min[1] = i;
-      }
-    }
-    return min;
-  }
-
   private void computeListOfColumnsSortedByValidationDependencies(Tab tab,
       ArrayList<String> sortedColumns, HashMap<String, List<String>> columnsInValidation,
       List<String> changeEventCols) {
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Wed Jan 12 17:37:50 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Wed Jan 12 18:01:02 2011 +0100
@@ -21,12 +21,15 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 import org.openbravo.base.model.Property;
 import org.openbravo.base.model.domaintype.ForeignKeyDomainType;
 import org.openbravo.client.application.ApplicationUtils;
+import org.openbravo.client.application.DynamicExpressionParser;
 import org.openbravo.client.kernel.BaseTemplateComponent;
 import org.openbravo.client.kernel.KernelUtils;
 import org.openbravo.client.kernel.Template;
@@ -75,6 +78,30 @@
     final List<Field> adFields = new ArrayList<Field>(tab.getADFieldList());
     Collections.sort(adFields, new FormFieldComparator());
 
+    final List<Field> fieldsInDynamicExpression = new ArrayList<Field>();
+    final Map<Field, String> fieldsExpressionMap = new HashMap<Field, String>();
+
+    // Processing dynamic expressions (display logic)
+    for (Field f : adFields) {
+      if (f.getDisplayLogic() == null || f.getDisplayLogic().equals("") || !f.isActive()
+          || !f.isDisplayed()) {
+        continue;
+      }
+
+      final DynamicExpressionParser parser = new DynamicExpressionParser(f.getDisplayLogic(), tab);
+      fieldsExpressionMap.put(f, parser.getJSExpression());
+
+      // log.debug(f.getTab().getId() + " - " + f.getName() + " >>> " + parser.getJSExpression());
+
+      for (Field fieldExpression : parser.getFields()) {
+        if (!fieldsInDynamicExpression.contains(fieldExpression)) {
+          fieldsInDynamicExpression.add(fieldExpression);
+        }
+      }
+    }
+
+    // log.debug(tab.getId() + " - " + fieldsInDynamicExpression);
+
     OBViewFieldGroup currentFieldGroup = null;
     FieldGroup currentADFieldGroup = null;
     int colNum = 1;
@@ -94,13 +121,15 @@
       final OBViewField viewField = new OBViewField();
       viewField.setField(field);
       viewField.setProperty(property);
+      viewField.setReadrawOnChange(fieldsInDynamicExpression.contains(field));
+      viewField.setShowIf(fieldsExpressionMap.get(field) != null ? fieldsExpressionMap.get(field)
+          : "");
 
       // Positioning some fields in odd-columns
       if (colNum % 2 == 0
           && (field.isStartinoddcolumn() || !field.isDisplayOnSameLine() || viewField.getColSpan() == 2)) {
         final OBViewFieldSpacer spacer = new OBViewFieldSpacer();
         fields.add(spacer);
-        log.debug("colNum: " + colNum + " - field: [spacer]");
         colNum++;
         if (colNum > 4) {
           colNum = 1;
@@ -119,8 +148,6 @@
       }
 
       fields.add(viewField);
-      log.debug("colNum: " + colNum + " - field: " + field.getName() + " - issameline: "
-          + field.isDisplayOnSameLine() + " - startinoddcolumn: " + field.isStartinoddcolumn());
 
       if (currentFieldGroup != null) {
         currentFieldGroup.addChild(viewField);
@@ -159,9 +186,9 @@
 
     public String getTargetEntity();
 
-    public String getStartRow();
+    public boolean getStartRow();
 
-    public String getEndRow();
+    public boolean getEndRow();
 
     public long getColSpan();
 
@@ -170,6 +197,10 @@
     public boolean isReadOnly();
 
     public boolean isParentProperty();
+
+    public boolean getRedrawOnChange();
+
+    public String getShowIf();
   }
 
   public class OBViewField implements OBViewFieldDefinition {
@@ -178,6 +209,8 @@
     private String label;
     private UIDefinition uiDefinition;
     private Boolean isParentProperty = null;
+    private boolean redrawOnChange = false;
+    private String showIf = "";
 
     public boolean isReadOnly() {
       return isParentProperty() || !property.isUpdatable();
@@ -311,16 +344,32 @@
       return field.getDisplayedLength() > ONE_COLUMN_MAX_LENGTH || getRowSpan() == 2 ? 2 : 1;
     }
 
-    public String getEndRow() {
-      return "false";
+    public boolean getEndRow() {
+      return false;
     }
 
     public long getRowSpan() {
       return property.getDomainType().getReference().getId().equals(TEXT_AD_REFERENCE_ID) ? 2 : 1;
     }
 
-    public String getStartRow() {
-      return field.isStartnewline().toString();
+    public boolean getStartRow() {
+      return field.isStartnewline();
+    }
+
+    public void setReadrawOnChange(boolean redrawOnChange) {
+      this.redrawOnChange = redrawOnChange;
+    }
+
+    public boolean getRedrawOnChange() {
+      return redrawOnChange;
+    }
+
+    public void setShowIf(String showIf) {
+      this.showIf = showIf;
+    }
+
+    public String getShowIf() {
+      return showIf;
     }
 
   }
@@ -355,38 +404,40 @@
       return 4;
     }
 
-    public String getEndRow() {
-      return "true";
+    public boolean getEndRow() {
+      return true;
     }
 
     public long getRowSpan() {
       return 1;
     }
 
-    public String getStartRow() {
-      return "true";
+    public boolean getStartRow() {
+      return true;
     }
 
     public boolean getStandardField() {
       return false;
     }
 
-    @Override
     public String getLabel() {
-      // TODO Auto-generated method stub
-      return null;
+      return "";
     }
 
-    @Override
     public String getName() {
-      // TODO Auto-generated method stub
-      return null;
+      return "";
     }
 
-    @Override
     public String getType() {
-      // TODO Auto-generated method stub
-      return null;
+      return "";
+    }
+
+    public boolean getRedrawOnChange() {
+      return false;
+    }
+
+    public String getShowIf() {
+      return "";
     }
 
   }
@@ -443,14 +494,31 @@
       return "dummy";
     }
 
+    public boolean getEndRow() {
+      return true;
+    }
+
     public List<OBViewFieldDefinition> getChildren() {
       return Collections.singletonList(childField);
+
     }
 
     public String getType() {
       return "OBLinkedItemSectionItem";
     }
 
+    public boolean getStartRow() {
+      return true;
+    }
+
+    public boolean getRedrawOnChange() {
+      return false;
+    }
+
+    public String getShowIf() {
+      return "";
+    }
+
     public String getName() {
       return "_linkedItems_";
     }
@@ -492,8 +560,8 @@
       return 1;
     }
 
-    public String getEndRow() {
-      return "false";
+    public boolean getEndRow() {
+      return false;
     }
 
     public boolean isReadOnly() {
@@ -536,14 +604,22 @@
       return false;
     }
 
-    public String getStartRow() {
-      return "false";
+    public boolean getStartRow() {
+      return false;
     }
 
     public String getType() {
       return "spacer";
     }
 
+    public boolean getRedrawOnChange() {
+      return false;
+    }
+
+    public String getShowIf() {
+      return "";
+    }
+
   }
 
   public static class FormFieldComparator implements Comparator<Field> {
--- a/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/RequestContext.java	Wed Jan 12 17:37:50 2011 +0100
+++ b/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/RequestContext.java	Wed Jan 12 18:01:02 2011 +0100
@@ -225,6 +225,9 @@
     }
 
     public String getContentType() {
+      if (delegate == null) {
+        return "text/html";
+      }
       return delegate.getContentType();
     }