package com.framsticks.gui.controls; import org.apache.log4j.Logger; import com.framsticks.params.CastFailure; import com.framsticks.params.Flags; import com.framsticks.params.PrimitiveParam; import com.framsticks.params.ReassignResult; import com.framsticks.util.swing.TooltipConstructor; /** * @author Piotr Sniegowski */ @SuppressWarnings("serial") public abstract class ValueControl extends Control { private static final Logger log = Logger.getLogger(ValueControl.class); /** * */ protected ValueControlListener listener; public ValueControl(PrimitiveParam primitiveParam) { super(primitiveParam); this.setToolTipText(new TooltipConstructor() .append("name", primitiveParam.getName()) .append("id", primitiveParam.getId()) .append("help", primitiveParam.getHelp()) .append("def", primitiveParam.getDef(Object.class)) .append("min", primitiveParam.getMin(Object.class)) .append("max", primitiveParam.getMax(Object.class)) .append("flags", Flags.write(primitiveParam.getFlags(), null)) .append("group", primitiveParam.getGroup()) .append("extra", primitiveParam.getExtra()) .build()) ; } @Override public PrimitiveParam getParam() { return (PrimitiveParam) param; } protected abstract void pushValueToUserInterfaceImpl(Object value); /** I consider this an ugly solution, but I was unable to find proper * action listeners for underlying swing controls, that would only fire * on user change and on programmatic change. */ protected boolean programmaticChange = false; public void pushValueToUserInterface(Object value) { programmaticChange = true; pushValueToUserInterfaceImpl(value); programmaticChange = false; } public abstract Object pullValueFromUserInterface(); public void setListener(ValueControlListener listener) { this.listener = listener; } protected Object filterValueThroughConstraints(Object candidate) { Object oldValue = pullValueFromUserInterface(); try { ReassignResult res = getParam().reassign(candidate, oldValue); if (res.getFlags() != 0) { log.warn("filter of param " + param + " failed: " + Flags.write(res.getFlags(), "0")); } return res.getValue(); } catch (CastFailure e) { log.error("cast failure when setting param " + param + " to value " + candidate + ": " + e); } return oldValue; } /** This method is meant as a public interface to obtain current and correct value from control. * */ public final Object getCurrentValue() { return filterValueThroughConstraints(pullValueFromUserInterface()); } protected boolean notifyOfChange() { if (!programmaticChange) { if (listener == null) { return true; } return listener.onChange(getCurrentValue()); } return true; } public final boolean isReadOnly() { return (param.getFlags() & Flags.READONLY) != 0; } }