/* * (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.awt.Color; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.inspector.AbstractController; import org.openflexo.inspector.InspectableObject; import org.openflexo.inspector.model.PropertyModel; import org.openflexo.kvc.KeyValueCoding; /** * Defines an abstract custom widget * * @author sguerin * */ public abstract class CustomWidget<T> extends DenaliWidget<T> { private static final Logger logger = Logger.getLogger(CustomWidget.class.getPackage().getName()); public CustomWidget(PropertyModel model, AbstractController controller) { super(model, controller); applyCancelListener = new Vector<ApplyCancelListener>(); } @Override public void setModel(InspectableObject value) { super.setModel(value); if (logger.isLoggable(Level.FINE)) { logger.fine("setModel in " + this.getClass().getName() + " with " + value); } performModelUpdating(value); } public boolean hasValueForParameter(String parameterName) { return getPropertyModel().hasValueForParameter(parameterName); } public String getValueForParameter(String parameterName) { return getPropertyModel().getValueForParameter(parameterName); } public boolean getBooleanValueForParameter(String parameterName) { String valueAsString = getPropertyModel().getValueForParameter(parameterName); return valueAsString.equalsIgnoreCase("true") || valueAsString.equalsIgnoreCase("yes"); } public Object getDynamicValueForParameter(String parameterName, InspectableObject object) { if (hasValueForParameter(parameterName)) { try { String listAccessor = getPropertyModel().getValueForParameter(parameterName); Object currentObject = PropertyModel.getObjectForMultipleAccessors(object, listAccessor); return currentObject; } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) { logger.warning("getDynamicValueForParameter() failed for property " + getPropertyModel().name + " for object " + object + " and parameter " + parameterName + ": exception " + e.getMessage()); } e.printStackTrace(); } } return null; } private Method getMethod(String methodPath, Class[] paramClasses) { KeyValueCoding targetObject = PropertyModel.getTargetObject(getModel(), methodPath); String methodName = PropertyModel.getLastAccessor(methodPath); if (targetObject == null) { return null; } Class targetClass = targetObject.getClass(); try { return targetClass.getMethod(methodName, paramClasses); } catch (SecurityException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("SecurityException raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); return null; } catch (NoSuchMethodException e) { // Try to find less specialized methods // The first matching is the good one ! for (Method m : targetClass.getMethods()) { if (m.getName().equals(methodName) && m.getParameterTypes().length == paramClasses.length) { boolean lookedUp = true; int paramId = 0; for (Class c : m.getParameterTypes()) { if (!c.isAssignableFrom(paramClasses[paramId])) { lookedUp = false; } paramId++; } if (lookedUp) { return m; } } } // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("NoSuchMethodException raised: unable to find method " + methodName + " for class " + targetClass); } e.printStackTrace(); return null; } } private Class[] classesArrayFor(Object[] parameters) { Class[] returned = new Class[parameters.length]; for (int i = 0; i < parameters.length; i++) { returned[i] = parameters[i].getClass(); } return returned; } public Object getParameteredValue(String methodPath, Object[] parameters) { Class[] paramClasses = classesArrayFor(parameters); Method method = getMethod(methodPath, paramClasses); if (method != null) { try { KeyValueCoding targetObject = PropertyModel.getTargetObject(getModel(), methodPath); if (logger.isLoggable(Level.FINE)) { logger.fine("invoking " + method + " on object" + targetObject); } return method.invoke(targetObject, parameters); } catch (IllegalArgumentException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); return null; } catch (IllegalAccessException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); return null; } catch (InvocationTargetException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); return null; } } else { logger.warning("Could not find method " + methodPath + " for " + getModel()); return null; } } public Object getParameteredValue(String methodPath, Object parameter) { Object[] params = { parameter }; return getParameteredValue(methodPath, params); } public boolean getBooleanParameteredValue(String methodPath, Object parameter) { Object returned = getParameteredValue(methodPath, parameter); if (returned == null) { return false; } if (returned instanceof Boolean) { return ((Boolean) returned).booleanValue(); } else { logger.warning("Return type mismatch: " + returned.getClass().getName()); return false; } } /** * Must be overriden in sub-classes if required * * @param value */ protected void performModelUpdating(InspectableObject value) { } public void performModelUpdating() { performModelUpdating(getModel()); } public T getEditedValue() { return getObjectValue(); } public void setEditedValue(T newValue) { setObjectValue(newValue); } public Color getColorForObject(T value) { return Color.BLACK; } public static interface ApplyCancelListener { public void fireApplyPerformed(); public void fireCancelPerformed(); } private Vector<ApplyCancelListener> applyCancelListener; public void addApplyCancelListener(ApplyCancelListener l) { applyCancelListener.add(l); } public void removeApplyCancelListener(ApplyCancelListener l) { applyCancelListener.remove(l); } public void notifyApply() { if (logger.isLoggable(Level.FINE)) { logger.fine("notifyApply()"); } Enumeration<ApplyCancelListener> en = applyCancelListener.elements(); while (en.hasMoreElements()) { ApplyCancelListener l = en.nextElement(); l.fireApplyPerformed(); } } public void notifyCancel() { if (logger.isLoggable(Level.FINE)) { logger.fine("notifyCancel()"); } Enumeration<ApplyCancelListener> en = applyCancelListener.elements(); while (en.hasMoreElements()) { ApplyCancelListener l = en.nextElement(); l.fireCancelPerformed(); } } public boolean disableTerminateEditOnFocusLost() { return false; } public abstract void fireEditingCanceled(); public abstract void fireEditingStopped(); }