Commit 690d5317 authored by Nico Mack's avatar Nico Mack

Major overhaul of InputEvent mechanism.

parent fa8af94e
......@@ -23,7 +23,9 @@ package lu.list.itis.dkd.tui.cps;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
/**
* Class implementing an event holding all necessary information to change {@link Variable}
......@@ -36,22 +38,7 @@ import java.util.EventObject;
@NonNullByDefault
public class InputEvent extends EventObject {
private static final long serialVersionUID = 2884355501325896122L;
/** The turn index the event was triggered at. */
private long tick;
/**
* Constructor initialising the source and all other fields.
*
* @param source
* The source of the event.
* @param tick
* The turn index the event was triggered at.
*/
public InputEvent(Variable<?> source, long tick) {
super(source);
this.tick = tick;
}
private static final int FIRST_ITEM = 0;
/**
* Constructor initialising the source field and setting the tick field to -1.
......@@ -61,20 +48,44 @@ public class InputEvent extends EventObject {
*/
public InputEvent(Variable<?> source) {
super(source);
this.tick = -1;
List<Variable<?>> sources = new ArrayList<>();
sources.add(source);
this.source = sources;
}
/**
* Simple getter method for tick.
*
* @return The value of tick.
*/
public long getTick() {
return tick;
public InputEvent(List<Variable<?>> sources) {
super(sources);
if ((sources == null) || sources.isEmpty())
throw new IllegalArgumentException("Invalid (NULL) or empty sources specified!"); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
public List<Variable<?>> getSources() {
return (List<Variable<?>>) this.source;
}
@Override
public Variable<?> getSource() {
return (Variable<?>) this.source;
return getSources().get(FIRST_ITEM);
}
public boolean originatedFrom(Variable<?> variable) {
return getSources().contains(variable);
}
public boolean originatedFrom(List<Variable<?>> variables) {
if ((variables == null) || variables.isEmpty())
return false;
boolean originatedFrom = false;
List<Variable<?>> sources = this.getSources();
for (Variable<?> variable : variables) {
originatedFrom |= sources.contains(variable);
}
return originatedFrom;
}
}
\ No newline at end of file
......@@ -32,8 +32,10 @@ import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import javax.script.ScriptEngine;
......@@ -125,7 +127,7 @@ public class Equation {
dependentVariables = mapping.getDependentVariables();
boolean consolidated = (dependentVariables.size() > 1);
HashMap<InputChangeListener, Variable<?>> consolidatedListeners = null;
HashMap<InputChangeListener, List<Variable<?>>> consolidatedListeners = null;
if (consolidated)
consolidatedListeners = new HashMap<>();
......@@ -147,9 +149,17 @@ public class Equation {
}
if (!isolated && consolidated && consolidatedListeners != null) {
for (Entry<InputChangeListener, Variable<?>> entry : consolidatedListeners.entrySet()) {
if (entry.getValue().wasModified(false)) {
entry.getKey().inputChanged(new InputEvent(entry.getValue()));
for (Entry<InputChangeListener, List<Variable<?>>> entry : consolidatedListeners.entrySet()) {
List<Variable<?>> variables = entry.getValue();
List<Variable<?>> modified = new ArrayList<>();
for (Variable<?> variable : variables) {
if (variable.wasModified(false)) {
modified.add(variable);
}
}
if (!modified.isEmpty()) {
entry.getKey().inputChanged(new InputEvent(modified));
}
}
}
......
......@@ -821,7 +821,7 @@ public class EquationSystemBuilder {
Preconditions.checkArgument(!variables.isEmpty(), "No variables to update!");
Preconditions.checkArgument(variables.size() == values.size(), "Sizes of variables and values lists must match!");
HashMap<InputChangeListener, Variable<?>> consolidated = new HashMap<>();
HashMap<InputChangeListener, List<Variable<?>>> consolidated = new HashMap<>();
for (int i = 0; i < variables.size(); i++) {
Variable<?> variable = variables.get(i);
......@@ -831,7 +831,7 @@ public class EquationSystemBuilder {
consolidated = variable.consolidateListeners(consolidated);
}
for (Entry<InputChangeListener, Variable<?>> entry : consolidated.entrySet()) {
for (Entry<InputChangeListener, List<Variable<?>>> entry : consolidated.entrySet()) {
entry.getKey().inputChanged(new InputEvent(entry.getValue()));
}
}
......
......@@ -24,6 +24,7 @@ import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
......@@ -151,6 +152,25 @@ public class Mapping {
return false;
}
/**
* Method querying whether the {@link Mapping} instance holds at least one of the {@link Variable}
* instances given as a parameter as an independent {@link Variable} instance.
*
* @param variables
* The set of variables to look up.
* @return <code>True</code> if at least one of the {@link Variable} instances is an independent
* variable managed by this {@link Mapping} instance.
*/
public boolean catersTo(Collection<Variable<?>> variables) {
boolean catersTo = false;
for (Declaration declaration : independentVariables) {
if (variables.contains(declaration.getVariable())) {
catersTo |= declaration.isInvoking();
}
}
return catersTo;
}
/**
* Method for locking the mapping; cloning all variables such that they may not be influenced by the
* evaluation of the equation.
......
......@@ -13,10 +13,18 @@ import java.util.Arrays;
import java.util.List;
import java.util.Properties;
// ***************************************************************************
// * Class Definition *
// ***************************************************************************
abstract public class Executor {
protected CharArrayWriter executionErrors;
protected boolean verbose;
// ***************************************************************************
// * Constants
// ***************************************************************************
private static Logger LOGGER = LoggerFactory.getLogger(Executor.class.getSimpleName());
protected static final String PARAMETER_TEMPLATE = "Parameter -> {} = {}"; //$NON-NLS-1$
......@@ -25,6 +33,10 @@ abstract public class Executor {
protected static final String RESULT_TEMPLATE_INDEX = "Result <- {}'[{}]' = {}"; //$NON-NLS-1$
protected static final String RESULT_TEMPLATE_SCALAR_INDEX = "Result <- {} = [{}] = {}"; //$NON-NLS-1$
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
public Executor() {
executionErrors = new CharArrayWriter();
verbose = true;
......@@ -36,6 +48,12 @@ abstract public class Executor {
verbose = true;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
protected static void addLibraryPath(String pathToAdd) throws Exception {
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); //$NON-NLS-1$
usrPathsField.setAccessible(true);
......@@ -56,29 +74,44 @@ abstract public class Executor {
usrPathsField.set(null, newPaths);
}
// ---------------------------------------------------------------------------
public String getExecutionErrors() {
return executionErrors.toString();
}
// ---------------------------------------------------------------------------
public void resetExecutionErrors() {
executionErrors.reset();
}
// ---------------------------------------------------------------------------
public void setVerbosity(boolean verbose) {
this.verbose = verbose;
}
// ---------------------------------------------------------------------------
abstract public void resetContext();
// ---------------------------------------------------------------------------
@SuppressWarnings("unused")
public void resolve(List<Import> imports) {
LOGGER.warn("Imports not supported by Executor!"); //$NON-NLS-1$
}
// ---------------------------------------------------------------------------
abstract public void set(Declaration declaration);
// ---------------------------------------------------------------------------
abstract public boolean eval(String script);
// ---------------------------------------------------------------------------
abstract public Variable<?> get(Declaration declaration);
}
......@@ -539,8 +539,9 @@ public class SqlExecutor extends Executor {
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public void set(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
......@@ -568,8 +569,9 @@ public class SqlExecutor extends Executor {
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public boolean eval(String script) {
long elapsed = System.currentTimeMillis();
......@@ -625,12 +627,13 @@ public class SqlExecutor extends Executor {
}
// ---------------------------------------------------------------------------
/**
* {@inheritDoc}
*
* @param <B>
*/
// ---------------------------------------------------------------------------
@Override
public Variable<?> get(Declaration declaration) {
Variable<?> variable;
......@@ -643,48 +646,11 @@ public class SqlExecutor extends Executor {
}
return variable;
// if (columnValues.size() > 1) {
// this.retrieveMultipleResults(declaration);
// } else {
// String column = (Strings.isNullOrEmpty(declaration.getEquate())) ? variable.getName() :
// declaration.getEquate();
// int index = columnNames.indexOf(column);
// if (index >= 0) {
// if (!columnValues.isEmpty()) {
// Object[] values = columnValues.get(0);
// Object value = ((index >= 0) && (index < values.length)) ? values[index] : null;
//
// if (LOGGER.isInfoEnabled()) {
// String rendered = (value != null) ? StringUtils.abbreviate(value.toString(), 256) : "NULL";
// LOGGER.info(Executor.RESULT_TEMPLATE_PLAIN, variable.getName(), rendered); // $NON-NLS-1$
// }
// if (variable instanceof VectorVariable) {
// VectorVariable<?> vector = (VectorVariable<?>) variable;
// this.setVector(vector, index);
// } else {
// variable.setValueFromObject(value);
// }
// } else {
// LOGGER.info("Query returned no results!"); //$NON-NLS-1$
// if (variable instanceof VectorVariable) {
// VectorVariable<?> vector = (VectorVariable<?>) variable;
// vector.clear();
// vector.notifyInputChangeListeners();
// } else if (variable instanceof MapVariable) {
// MapVariable<?, ?> map = (MapVariable<?, ?>) variable;
// map.clear();
// map.notifyInputChangeListeners();
// } else {
// variable.setValue(null);
// }
// }
// }
// }
//
// return variable;
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public void resetContext() {
columnNames.clear();
......
......@@ -289,7 +289,7 @@ public class NumericalVariable extends Variable<Double> {
// this.value = newValue;
this.modified = ((newValue != null) && (!isEqual(val, this.value, this.epsilon)));
this.value = val;
if (this.modified) {
if (!this.notificationSuspended() && this.modified) {
this.notifyInputChangeListeners(new InputEvent(this));
}
}
......
......@@ -205,7 +205,10 @@ public abstract class Variable<V> implements Cloneable {
this.modified = ((newValue != null) && (!newValue.equals(this.value)));
this.value = newValue;
this.notifyInputChangeListeners(new InputEvent(this));
if (!this.notificationSuspended()) {
this.notifyInputChangeListeners(new InputEvent(this));
}
}
/**
......@@ -379,6 +382,10 @@ public abstract class Variable<V> implements Cloneable {
}
}
public boolean notificationSuspended() {
return (suspendNotificationSemaphore > 0);
}
/**
* Causes this variable to add its InputChangeListeners to the specified HashMap. HashMap ensures
* that no duplicate listeners will be added to consolidated list.
......@@ -389,11 +396,12 @@ public abstract class Variable<V> implements Cloneable {
* @return specified HashMap enriched by this variables' listeners.
*/
public HashMap<InputChangeListener, Variable<?>> consolidateListeners(HashMap<InputChangeListener, Variable<?>> consolidated) {
public HashMap<InputChangeListener, List<Variable<?>>> consolidateListeners(HashMap<InputChangeListener, List<Variable<?>>> consolidated) {
for (InputChangeListener listener : listeners) {
if (!consolidated.containsKey(listener)) {
consolidated.put(listener, this);
}
List<Variable<?>> variables;
variables = (consolidated.containsKey(listener)) ? consolidated.get(listener) : new ArrayList<>();
variables.add(this);
consolidated.put(listener, variables);
}
return consolidated;
}
......@@ -406,7 +414,7 @@ public abstract class Variable<V> implements Cloneable {
* specifies the event to be passed to each listeners inputChanged method.
*/
protected void notifyInputChangeListeners(InputEvent event) {
if (suspendNotificationSemaphore > 0) {
if (this.notificationSuspended()) {
// if (LOGGER.isTraceEnabled())
// LOGGER.trace("Notification suspend for Variable {}! Semaphore was {}!", this.name,
// suspendNotificationSemaphore); //$NON-NLS-1$
......
......@@ -89,7 +89,9 @@ public class VectorVariable<B> extends Variable<List<B>> implements List<B> {
public void setValue(List<B> values) {
this.value.clear();
this.value.addAll(values);
this.notifyInputChangeListeners(new InputEvent(this));
if (!this.notificationSuspended()) {
this.notifyInputChangeListeners(new InputEvent(this));
}
}
/** {@inheritDoc} */
......
......@@ -64,6 +64,7 @@ public class ScriptableCondition<T> extends Condition<T> implements VariableBase
// ---------------------------------------------------------------------------
public ScriptableCondition(BaseScriptableConditionBuilder<?> builder) {
super(builder);
this.expression = builder.expression;
this.parameters = builder.parameters;
this.setupCondition(expression);
......
......@@ -23,8 +23,9 @@ package lu.list.itis.dkd.tui.widget;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.system.VariableBased;
import lu.list.itis.dkd.tui.cps.variable.NumericalVariable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.event.conditional.Condition;
import lu.list.itis.dkd.tui.event.interaction.Interaction;
import lu.list.itis.dkd.tui.widget.builder.BaseDisplayWidgetBuilder;
import lu.list.itis.dkd.tui.widget.builder.DisplayWidgetBuilder;
import lu.list.itis.dkd.tui.widget.corona.ValueCorona;
......@@ -54,8 +55,9 @@ import java.util.Map;
public class DisplayWidget extends StatefulWidget implements InputChangeListener, VariableBased {
HashMap<String, NumericalVariable> variables;
Multimap<String, ValueCorona> dispatcher;
HashMap<String, Variable<?>> variables;
Multimap<String, ValueCorona> displayDispatcher;
Multimap<String, Condition> conditionDispatcher;
// ***************************************************************************
// * Constants *
......@@ -72,18 +74,18 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
public DisplayWidget(BaseDisplayWidgetBuilder<DisplayWidgetBuilder> builder) {
super(builder);
this.setupDispatcher();
this.setupDisplayDispatcher();
this.variables = new HashMap<>();
this.conditionDispatcher = TreeMultimap.create();
}
// ---------------------------------------------------------------------------
public DisplayWidget(DisplayWidget original) {
super(original);
// TODO figure out to handle multiple instances of the same variables.
this.setupDispatcher();
this.setupDisplayDispatcher();
}
// ---------------------------------------------------------------------------
......@@ -97,8 +99,8 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
*/
// ---------------------------------------------------------------------------
private void setupDispatcher() {
this.dispatcher = TreeMultimap.create();
private void setupDisplayDispatcher() {
this.displayDispatcher = TreeMultimap.create();
// TODO : Should be refactored using VariableBased Interface
......@@ -106,7 +108,7 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
for (ValueCorona display : displays) {
Variable<?> variable = display.getVariable();
if (variable != null) {
dispatcher.put(variable.getName(), display);
displayDispatcher.put(variable.getName(), display);
}
}
}
......@@ -126,7 +128,7 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
if (variable != null) {
// if (variable.wasModified()) {
Object information = variable.getValue();
Collection<ValueCorona> displays = dispatcher.get(variableName);
Collection<ValueCorona> displays = displayDispatcher.get(variableName);
if (displays != null) {
for (ValueCorona display : displays) {
display.setInformation(information);
......@@ -134,12 +136,33 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
} else {
LOGGER.warn("No matching display found for variable {}!", variableName); //$NON-NLS-1$
}
if (variable.wasModified(false) && conditionDispatcher.containsKey(variableName)) {
this.checkConditions(variableName, information);
}
// }
} else {
LOGGER.warn("Required variable {} unkown to display widget!", variableName); //$NON-NLS-1$
}
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
public void checkConditions(String variableName, Object candidate) {
Collection<Condition> affectedConditions = conditionDispatcher.get(variableName);
for (Condition<Object> condition : affectedConditions) {
boolean satisfied = condition.satisfiedBy(candidate);
if (satisfied) {
Interaction ineraction = new Interaction(Interaction.ON_CONDITION_SATISFIED);
ineraction.setDiscriminator(condition.getName());
this.interactionManager.respondTo(ineraction);
}
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
......@@ -159,10 +182,21 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
}
for (Variable<?> variable : connected) {
this.variables.put(variable.getName(), (NumericalVariable) variable);
this.variables.put(variable.getName(), variable);
variable.addListener(this);
}
for (Condition<Object> condition : this.conditions) {
if (condition instanceof VariableBased) {
List<Variable<?>> parameters = ((VariableBased) condition).connectWithSystemVariables(systemVariables);
for (Variable<?> parameter : parameters) {
this.conditionDispatcher.put(parameter.getName(), condition);
this.variables.put(parameter.getName(), parameter);
parameter.addListener(this);
}
}
}
return connected;
}
......@@ -190,8 +224,9 @@ public class DisplayWidget extends StatefulWidget implements InputChangeListener
// mechanism built into the equation system, making sure that equations are
// only evaluated once even though multiple input variables have changed.
for (String variableName : this.variables.keySet()) {
this.updateDisplayFor(variableName);
// for (String variableName : this.variables.keySet()) {
for (Variable<?> variable : input.getSources()) {
this.updateDisplayFor(variable.getName());
}
}
......
......@@ -310,7 +310,7 @@ public class SelectorWidget extends ValueWidget {
if ((presetPosition != NONE) && connected.contains(variable)) {
variable.setValue((double) presetPosition);
variable.notifyInputChangeListeners();
// variable.notifyInputChangeListeners();
}
List<Conditional> conditionalCoronas = getCoronas(Conditional.class);
......
......@@ -338,7 +338,7 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
super.actionMove(tuioObject.constrainedClone(new Point(position.x, position.y, (float) dialAngle, position.getState().getClass())));
}
} else {
dialAngle = AngleUtils.moduloTwoPi(Math.PI + tuioObject.getAngle());
dialAngle = AngleUtils.moduloTwoPi(Math.PI + tuioObject.getAngle() - dropAngle);
super.actionMove(tuioObject.constrainedClone(new Point(tuioObject.getX(), tuioObject.getY(), (float) dialAngle)));
}
......
......@@ -29,18 +29,26 @@ public abstract class BaseDisplayWidgetBuilder<B extends BaseDisplayWidgetBuilde
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
public BaseDisplayWidgetBuilder(Element rootElement) throws BuildException {
super(rootElement);
}
// ---------------------------------------------------------------------------
/**
* Constructor initializing all fields from an {@link Element} containing as child elements all
* the information on fields to initialize.
* Constructor initializing all fields from an {@link Element} containing as child elements all the
* information on fields to initialize.
*
* @param rootElement
* The element harbouring, on child nodes, the necessary information to initialize all
* fields of the builder.
* The element harbouring, on child nodes, the necessary information to initialize all fields
* of the builder.
* @throws BuildException
* Thrown when any of the fields fail to populate due to an error in reading information
* from the XML file.
*/
// ---------------------------------------------------------------------------
public BaseDisplayWidgetBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
super(rootElement, context, callback);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment