/*
* (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.model;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.kvc.KeyValueCoding;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.xmlcode.AccessorInvocationException;
import org.openflexo.xmlcode.InvalidObjectSpecificationException;
import org.openflexo.xmlcode.KeyValueProperty;
import org.openflexo.xmlcode.StringConvertable;
import org.openflexo.xmlcode.StringRepresentable;
public class PropertyModel extends ParametersContainerModelObject implements InnerTabWidget/*,PropertyParameter<Object>*/
{
private static final Logger logger = Logger.getLogger(PropertyModel.class.getPackage().getName());
public String _tabModelName;
public String name;
public String label;
private String widget;
public int constraint;
public String depends;
public String help;
public String conditional;
public String widgetLayout;
private TabModel tabModel;
private String _localizedLabel = null;
public PropertyModel() {
super();
}
public PropertyModel(String aName) {
this();
name = aName;
finalizePropertyModelDecoding();
}
public String getLocalizedLabel() {
return _localizedLabel;
}
public void setLocalizedLabel(String aString) {
_localizedLabel = aString;
}
public void finalizePropertyModelDecoding() {
}
public int getGridHeight() {
if (hasValueForParameter("height")) {
return Integer.parseInt(getValueForParameter("height"));
}
return 24;
}
@Override
public int getIndex() {
return constraint;
}
public boolean hasStaticList() {
return hasValueForParameter("staticlist");
}
public List<String> getStaticList() {
if (hasStaticList()) {
String list = getValueForParameter("staticlist");
StringTokenizer strTok = new StringTokenizer(list, ",");
List<String> answer = new ArrayList<String>();
while (strTok.hasMoreTokens()) {
answer.add(strTok.nextToken());
}
return answer;
} else {
return Collections.emptyList();
}
}
public boolean hasDynamicList() {
return hasValueForParameter("dynamiclist");
}
public List<?> getDynamicList(InspectableObject object) {
if (hasDynamicList()) {
try {
String listAccessor = getValueForParameter("dynamiclist");
Object currentObject = getObjectForMultipleAccessors(object, listAccessor);
if (currentObject instanceof List) {
return (List) currentObject;
} else if (currentObject == null) {
return Collections.emptyList();
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Succeeded access to " + listAccessor + " but answer is not a List but a :"
+ currentObject.getClass().getName() + " value=" + currentObject);
}
return Collections.emptyList();
}
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getDynamicList() failed for property " + name + " for object " + object + " : exception "
+ e.getMessage());
}
e.printStackTrace();
return Collections.emptyList();
}
} else {
return Collections.emptyList();
}
}
public boolean hasDynamicHashtable() {
return hasValueForParameter("dynamichash");
}
public static Object getObjectForMultipleAccessors(KeyValueCoding object, String listAccessor) {
// logger.info("list accessor = "+listAccessor+" for "+object);
if (listAccessor != null && listAccessor.equals("this")) {
return object;
}
StringTokenizer strTok = new StringTokenizer(listAccessor, ".");
String accessor;
Object currentObject = object;
while (strTok.hasMoreTokens() && currentObject != null && currentObject instanceof KeyValueCoding) {
accessor = strTok.nextToken();
if (currentObject != null) {
currentObject = ((KeyValueCoding) currentObject).objectForKey(accessor);
}
}
return currentObject;
}
public Hashtable getDynamicHashtable(InspectableObject object) {
if (hasDynamicHashtable()) {
try {
String listAccessor = getValueForParameter("dynamichash");
Object currentObject = getObjectForMultipleAccessors(object, listAccessor);
if (currentObject instanceof Hashtable) {
return (Hashtable) currentObject;
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Succeeded acces to " + listAccessor + " but answer is not a Hashtable");
}
return new Hashtable();
}
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getDynamicList() failed for property " + name + " for object " + object + " : exception "
+ e.getMessage());
}
return new Hashtable();
}
} else {
return new Hashtable();
}
}
public boolean hasFormatter() {
return hasValueForParameter("format");
}
public String getFormattedObject(KeyValueCoding object) {
if (hasFormatter()) {
try {
String listAccessor = getValueForParameter("format");
if (logger.isLoggable(Level.FINE)) {
logger.fine("Format object " + object + " with format " + getValueForParameter("format"));
}
Object currentObject = getObjectForMultipleAccessors(object, listAccessor);
if (currentObject instanceof String) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Format object " + object + " with format " + getValueForParameter("format") + " returns "
+ currentObject);
}
return (String) currentObject;
} else if (currentObject == null) {
return "";
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Property " + name + ": succeeded acces to " + listAccessor + " but answer is not a String "
+ currentObject + " of " + currentObject.getClass().getName());
}
return null;
}
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getDynamicList() failed for property " + name + " for object " + object + " : exception "
+ e.getMessage());
}
return null;
}
}
return null;
}
public String getStringRepresentation(Object object) {
if (object instanceof String) {
return (String) object;
} else if (object instanceof KeyValueCoding && hasFormatter()) {
return getFormattedObject((KeyValueCoding) object);
} else if (object instanceof StringConvertable) {
return ((StringConvertable) object).getConverter().convertToString(object);
} else if (object instanceof Number) {
return object.toString();
} else if (object instanceof Boolean) {
return object.toString();
} else if (object instanceof File) {
return object.toString();
} else if (object instanceof StringRepresentable) {
return object.toString();
} else if (object instanceof Enum) {
return FlexoLocalization.localizedForKey(((Enum) object).name().toLowerCase());
} else {
if (object == null) {
return "";
}
if (logger.isLoggable(Level.WARNING)) {
logger.warning("There is an error in some configuration file :\n the property named '" + name
+ "' has no string representation formatter ! Object is a "
+ (object != null ? object.getClass().getName() : "null"));
}
return object.toString();
}
}
public boolean isEditable(Object object) {
if (hasValueForParameter("isEditable") && object instanceof KeyValueCoding) {
Object currentObject = getObjectForMultipleAccessors((KeyValueCoding) object, getValueForParameter("isEditable"));
if (currentObject instanceof Boolean) {
return (Boolean) currentObject;
}
if (logger.isLoggable(Level.WARNING)) {
logger.warning("There is an error in model: parameter 'isEditable' seems to be defined but not on a boolean: "
+ getValueForParameter("isEditable"));
}
}
return true;
}
public boolean hasIdentifier() {
return hasValueForParameter("identifier");
}
public String getIdentifiedObject(KeyValueCoding object) {
if (hasFormatter()) {
try {
String listAccessor = getValueForParameter("identifier");
if (logger.isLoggable(Level.FINE)) {
logger.fine("Identify object " + object + " with identifier " + getValueForParameter("identifier"));
}
Object currentObject = getObjectForMultipleAccessors(object, listAccessor);
if (currentObject instanceof String) {
return (String) currentObject;
} else if (currentObject == null) {
return "null";
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Property " + name + ": succeeded acces to " + listAccessor + " but answer is not a String");
}
return null;
}
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getDynamicList() failed for property " + name + " for object " + object + " : exception "
+ e.getMessage());
}
return null;
}
} else {
return null;
}
}
public InspectorModel getInspectorModel() {
if (tabModel != null) {
return tabModel.getInspectorModel();
} else {
logger.warning("TabModel is null !");
return null;
}
}
public TabModel getTabModel() {
return tabModel;
}
public void setTabModel(TabModel tm) {
this.tabModel = tm;
_tabModelName = tm.name;
}
// =================================================================
// ==================== Dynamic access to values ===================
// =================================================================
public static String getLastAccessor(String keyPath) {
KeyValueProperty.PathTokenizer strTok = new KeyValueProperty.PathTokenizer(keyPath);
String accessor = null;
while (strTok.hasMoreTokens()) {
accessor = strTok.nextToken();
}
return accessor;
/* int lastDotPosition = keyPath.lastIndexOf(".");
if (lastDotPosition < 0)
return keyPath;
return keyPath.substring(lastDotPosition + 1, keyPath.length());*/
}
public static KeyValueCoding getTargetObject(KeyValueCoding object, String keyPath) {
StringTokenizer strTok = new StringTokenizer(keyPath, ".");
String accessor;
Object currentObject = object;
while (strTok.hasMoreTokens() && currentObject != null && currentObject instanceof KeyValueCoding) {
accessor = strTok.nextToken();
if (strTok.hasMoreTokens()) {
if (currentObject != null) {
currentObject = ((KeyValueCoding) currentObject).objectForKey(accessor);
// System.out.println ("accessor: "+ accessor+",
// currentObject="+currentObject);
}
}
}
if (currentObject instanceof KeyValueCoding) {
return (KeyValueCoding) currentObject;
} else if (currentObject != null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find target object for object=" + object + " keyPath=" + keyPath
+ ": must be a KeyValueCoding object (getting " + currentObject + ")");
}
return null;
} else {
return null;
}
}
public KeyValueCoding getTargetObject(KeyValueCoding inspectable) {
return PropertyModel.getTargetObject(inspectable, name);
}
private String _lastAccessor;
public String getLastAccessor() {
if (_lastAccessor == null) {
_lastAccessor = PropertyModel.getLastAccessor(name);
}
return _lastAccessor;
}
public synchronized boolean hasObjectValue(KeyValueCoding inspectable) throws AccessorInvocationException {
if (inspectable == null) {
return false;
}
try {
KeyValueCoding target = getTargetObject(inspectable);
if (target != null) {
String lastAccessor = getLastAccessor();
if (lastAccessor != null) {
target.objectForKey(lastAccessor);
} else {
return false;
}
return true;
} else {
return false;
}
} catch (InvalidObjectSpecificationException e) {
return false;
} catch (AccessorInvocationException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getObjectValue() failed for property " + name + " for object " + inspectable.getClass().getName()
+ " : exception " + e.getMessage());
}
return false;
}
}
public synchronized Object getObjectValue(KeyValueCoding inspectable) throws AccessorInvocationException {
if (inspectable == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Inspectable object is null for key " + name + ". We should definitely investigate this.");
}
return null;
}
try {
KeyValueCoding target = getTargetObject(inspectable);
if (target != null) {
return target.objectForKey(getLastAccessor());
} else {
return null;
}
} catch (AccessorInvocationException e) {
throw e;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("getObjectValue() failed for property " + name + " for object " + inspectable.getClass().getName()
+ " : exception " + e.getMessage());
}
return null;
}
}
/**
* This method can be called to store the newValue in the model.
*
* @param newValue
*/
public synchronized void setObjectValue(KeyValueCoding inspectable, Object newValue) throws AccessorInvocationException {
if (inspectable == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Inspectable object is null for key " + name + ". We should definitely investigate this.");
}
return;
}
Object oldValue = getObjectValue(inspectable);
// logger.info("Old value="+oldValue+" New value="+newValue);
if (oldValue == null) {
if (newValue == null) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Same null value. Ignored.");
}
return;
}
} else if (newValue != null && oldValue.equals(newValue)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Same value. Ignored.");
}
return;
}
try {
KeyValueCoding target = getTargetObject(inspectable);
if (target != null) {
target.setObjectForKey(newValue, getLastAccessor());
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Target object is null for key " + name + ". We should definitely investigate this.");
}
return;
} catch (AccessorInvocationException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
if (logger.isLoggable(Level.WARNING)) {
logger.warning("setObjectValue() with " + newValue + " failed for property " + name + " for object "
+ inspectable.getClass().getName() + " : exception " + e.getMessage());
}
}
}
public String getKey() {
return name;
}
public boolean allowDelegateHandling() {
return true;
}
public boolean isEditionPatternProperty() {
return false;
}
public boolean isEditionPatternPropertyList() {
return false;
}
public String getWidget() {
return widget;
}
public void setWidget(String widget) {
this.widget = widget;
}
}