package com.framsticks.gui.controls; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import com.framsticks.params.CastFailure; import com.framsticks.params.ParamFlags; import com.framsticks.params.PrimitiveParam; import com.framsticks.params.ReassignResult; import com.framsticks.params.SetStateFlags; import com.framsticks.util.FramsticksException; import com.framsticks.util.lang.FlagsUtil; import com.framsticks.util.swing.TooltipConstructor; /** * @author Piotr Sniegowski */ @SuppressWarnings("serial") public abstract class ValueControl extends Control { private static final Logger log = LogManager.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", FlagsUtil.write(ParamFlags.class, 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 {} failed: {}", param, FlagsUtil.write(SetStateFlags.class, res.getFlags(), "0")); } return res.getValue(); } catch (CastFailure e) { //TODO just throw here, but check where that function is being used handle(new FramsticksException().msg("invalid value in control").arg("param", param).arg("value", candidate).cause(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; } }