/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.inspector.widget; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.inspector.InspectableObject; import org.openflexo.inspector.KVUtil; import org.openflexo.inspector.model.PropertyModel; import org.openflexo.kvc.KeyValueCoding; import org.openflexo.letparser.BooleanValue; import org.openflexo.letparser.DoubleValue; import org.openflexo.letparser.Expression; import org.openflexo.letparser.IntValue; import org.openflexo.letparser.Operator; import org.openflexo.letparser.ParseException; import org.openflexo.letparser.Parser; import org.openflexo.letparser.StringValue; import org.openflexo.letparser.Token; import org.openflexo.letparser.Value; import org.openflexo.letparser.Word; import org.openflexo.xmlcode.StringConvertable; // TODO: use AnTAR public class WidgetConditional { static final Logger logger = Logger.getLogger(WidgetConditional.class.getPackage().getName()); protected PropertyModel _propertyModel; private String _depends; private Expression _conditional; private Vector<String> _dependsProperties; public WidgetConditional(PropertyModel propertyModel) { _dependsProperties = new Vector<String>(); _propertyModel = propertyModel; _depends = propertyModel.depends; if (_depends != null) { StringTokenizer st = new StringTokenizer(_depends, ","); while (st.hasMoreTokens()) { _dependsProperties.add(st.nextToken()); } } if (propertyModel.conditional != null) { try { // logger.info("Parse: "+propertyModel.conditional); _conditional = Parser.parseExpression(propertyModel.conditional); if (logger.isLoggable(Level.FINE)) { logger.fine("Conditional: " + _conditional); } } catch (ParseException e) { logger.warning("Invalid conditional for property " + propertyModel.name + ": " + e.getMessage()); } } } /*public boolean checkConditionalValue(InspectableObject inspectable) { if (_conditional != null && !_conditional.equals("")) { try { StringTokenizer or = new StringTokenizer(_conditional, "|"); while (or.hasMoreTokens()) { // OR StringTokenizer or_and = new StringTokenizer(or.nextToken().trim(), "&"); boolean and = true; while (or_and.hasMoreTokens() && and) { // AND String cond = or_and.nextToken().trim(); boolean negate = false; if (cond.indexOf("!=") != -1) { negate = true; } StringTokenizer stk = new StringTokenizer(cond, "!="); String attribute = stk.nextToken().trim(); String value = stk.nextToken().trim(); Object attributeValue = inspectable.objectForKey(attribute); if (attributeValue instanceof KeyValueCoding) { if (_propertyModel.hasFormatter()) { attributeValue = getStringRepresentation(attributeValue); } } if (attributeValue == null && value.equals("null")) and = true; else if (attributeValue != null && attributeValue.equals(value)) and = true; else and = false; if (negate) and = !and; } if (and == true) { return true; } } // if none OR exists => return true. return false; } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) logger.warning("Exception in DenaliWidget.checkConditionalValue (" + _conditional + ") for:" + _propertyModel.label + ""); e.printStackTrace(); } } return true; }*/ public boolean dependsOfProperty(String propertyName) { for (Enumeration en = _dependsProperties.elements(); en.hasMoreElements();) { String nextProperty = (String) en.nextElement(); if (nextProperty.equals(propertyName)) { return true; } } return false; } public boolean isVisible(InspectableObject inspectable) { if (_conditional == null) { return true; } return evaluate(_conditional, inspectable); } private boolean evaluate(Expression expression, InspectableObject object) { Vector<KeyValueInstance> parameters = new Vector<KeyValueInstance>(); for (Enumeration en = _dependsProperties.elements(); en.hasMoreElements();) { String nextProperty = (String) en.nextElement(); if (KVUtil.hasValueForKey(object, nextProperty)) { // Current inspected object might not have this property, ignore it then parameters.add(new KeyValueInstance(object, nextProperty)); } // System.out.println("Add param for "+nextProperty); } boolean returned = evaluate(expression, parameters); if (logger.isLoggable(Level.FINE)) { logger.fine("Evaluate " + expression + " : returns " + returned); } return returned; } private Value evaluateToken(Token token, Vector<KeyValueInstance> parameters) { if (token instanceof Expression) { return new BooleanValue(evaluate((Expression) token, parameters)); } else if (token instanceof Word) { String replacedString = ((Word) token).getValue(); if (replacedString.equals("null")) { return new StringValue("null"); } /*for (Enumeration en = parameters.elements(); en.hasMoreElements();) { KeyValueInstance param = (KeyValueInstance)en.nextElement(); String newValueStringRepresentation = param.getStringRepresentation(); String keyPath = param.getKeyPath(); //System.out.println("replace "+keyPath+" by "+newValueStringRepresentation); System.out.println("param._inspectable: "+param._inspectable); System.out.println("param._keyPath: "+param._keyPath); System.out.println("param._value: "+param._value); System.out.println("replacedString[BEFORE]: "+replacedString); System.out.println("newValueStringRepresentation: "+newValueStringRepresentation); replacedString = ToolBox.replaceStringByStringInString(keyPath, newValueStringRepresentation, replacedString); System.out.println("replacedString[AFTER]: "+replacedString); }*/ Object targetValue = null; boolean targetHasBeenAnalysed = false; if (replacedString.indexOf(".") > -1) { String targetName = replacedString.substring(0, replacedString.indexOf(".")); String keyPath = replacedString.substring(replacedString.indexOf(".") + 1); KeyValueInstance kvInstance = null; for (KeyValueInstance aKVInstance : parameters) { if (aKVInstance.getKeyPath().equals(targetName)) { kvInstance = aKVInstance; } } if (kvInstance != null) { targetValue = kvInstance.getValueForKey(keyPath); targetHasBeenAnalysed = true; } } // else { if (targetValue == null) { KeyValueInstance kvInstance = null; for (KeyValueInstance aKVInstance : parameters) { if (aKVInstance.getKeyPath().equals(replacedString)) { kvInstance = aKVInstance; } } if (kvInstance != null) { targetValue = kvInstance.getValue(); targetHasBeenAnalysed = true; } else { targetValue = replacedString; targetHasBeenAnalysed = true; } } // System.out.println("replacedString="+replacedString); // System.out.println("targetValue="+targetValue+" of "+(targetValue != null ? targetValue.getClass().getSimpleName() : // "null")); if (targetHasBeenAnalysed) { if (targetValue == null) { return new StringValue("null"); } else if (targetValue instanceof Boolean) { return new BooleanValue((Boolean) targetValue); } else if (targetValue instanceof Integer) { return new IntValue((Integer) targetValue); } else if (targetValue instanceof Double) { return new DoubleValue((Double) targetValue); } else if (targetValue instanceof StringConvertable) { return new StringValue(((StringConvertable) targetValue).getConverter().convertToString(targetValue)); } else if (targetValue instanceof Enum) { return new StringValue(((Enum) targetValue).name()); } else if (targetValue instanceof String) { return new StringValue((String) targetValue); } return new StringValue(targetValue.toString()); } else { logger.warning("Could not analyse " + replacedString); return new StringValue(replacedString); } } else if (token instanceof Value) { return (Value) token; } return null; } private boolean evaluate(Expression expression, Vector<KeyValueInstance> parameters) { Value leftValue = evaluateToken(expression.getLeftOperand(), parameters); Value rightValue = evaluateToken(expression.getRightOperand(), parameters); if (expression.getOperator() == Operator.AND) { if (leftValue instanceof BooleanValue && rightValue instanceof BooleanValue) { if (logger.isLoggable(Level.FINE)) { logger.fine("Evaluate AND in " + expression + " : left:" + leftValue + " right:" + rightValue + " returns: " + (((BooleanValue) leftValue).getBooleanValue() && ((BooleanValue) rightValue).getBooleanValue())); } return ((BooleanValue) leftValue).getBooleanValue() && ((BooleanValue) rightValue).getBooleanValue(); } else { logger.warning("Incompatible operands: " + leftValue.getClass().getName() + " AND " + rightValue.getClass().getName()); return true; } } else if (expression.getOperator() == Operator.OR) { if (leftValue instanceof BooleanValue && rightValue instanceof BooleanValue) { if (logger.isLoggable(Level.FINE)) { logger.fine("Evaluate OR in " + expression + " : left:" + leftValue + " right:" + rightValue + " returns: " + (((BooleanValue) leftValue).getBooleanValue() || ((BooleanValue) rightValue).getBooleanValue())); } return ((BooleanValue) leftValue).getBooleanValue() || ((BooleanValue) rightValue).getBooleanValue(); } else { logger.warning("Incompatible operands: " + leftValue.getClass().getName() + " OR " + rightValue.getClass().getName()); return true; } } else if (expression.getOperator() == Operator.EQU) { if (logger.isLoggable(Level.FINE)) { logger.fine("Evaluate EQU in " + expression + " : left:" + leftValue + " right:" + rightValue + " returns: " + (leftValue == null && rightValue == null || leftValue != null && leftValue.equals(rightValue))); } return leftValue == null && rightValue == null || leftValue.equals(rightValue); } else if (expression.getOperator() == Operator.NEQ) { if (logger.isLoggable(Level.FINE)) { logger.fine("Evaluate NEQ in " + expression + " : left:" + leftValue + " right:" + rightValue + " returns: " + leftValue.equals(rightValue)); } return !leftValue.equals(rightValue); } else { logger.warning("Unknown operator: " + expression.getOperator()); return true; } } protected class KeyValueInstance { private InspectableObject _inspectable; private String _keyPath; private Object _value; private PropertyModel _propModel; protected KeyValueInstance(InspectableObject inspectable, String keyPath) { _inspectable = inspectable; _keyPath = keyPath; _value = KVUtil.getValueForKey(inspectable, keyPath); _propModel = null; /*System.out.println("Inspectable: "+inspectable); System.out.println("keyPath: "+keyPath); System.out.println("_value: "+_value);*/ } public InspectableObject getInspectable() { return _inspectable; } public String getKeyPath() { return _keyPath; } public Object getValue() { return _value; } public Object getValueForKey(String aKeyPath) { if (_value == null) { return null; } if (_value instanceof KeyValueCoding) { return KVUtil.getValueForKey((KeyValueCoding) _value, aKeyPath); } logger.warning("Could not access " + aKeyPath + " for " + _value); return null; } public PropertyModel getPropertyModel() { if (_propertyModel == null || _propertyModel.getInspectorModel() == null) { return null; } if (_propModel == null) { _propModel = _propertyModel.getInspectorModel().getPropertyNamed(_keyPath); } if (_propModel == null) { logger.warning("Cannot find PropertyModel for " + _keyPath); // _propertyModel.getInspectorModel().debug(); } return _propModel; } public String getStringRepresentation() { if (_value == null) { return "null"; } if (_value instanceof String) { return (String) _value; } else if (_value instanceof StringConvertable) { return ((StringConvertable) _value).getConverter().convertToString(_value); } else if (_value instanceof KeyValueCoding && getPropertyModel() != null && getPropertyModel().hasIdentifier()) { return getPropertyModel().getIdentifiedObject((KeyValueCoding) _value); } else if (_value instanceof Number) { return _value.toString(); } else if (_value instanceof Boolean) { return _value.toString(); } else { /*if (logger.isLoggable(Level.WARNING)) logger.warning("There is an error in some configuration file :\n the property named '" + _keyPath + "' has no string representation formatter ! Object is a "+(_value!=null?_value.getClass().getName():"null"));*/ return _value.toString(); } } } }