org.bidib.wizard.api.model.Macro Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-api Show documentation
Show all versions of bidibwizard-api Show documentation
jBiDiB BiDiB Wizard API POM
The newest version!
package org.bidib.wizard.api.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.bidib.wizard.api.model.function.EmptyFunction;
import org.bidib.wizard.api.model.function.Function;
import org.bidib.wizard.api.model.function.InputFunction;
import org.bidib.wizard.api.model.function.PortAware;
import org.bidib.wizard.api.model.listener.MacroListener;
import org.bidib.wizard.api.utils.MacroUtils;
import org.bidib.wizard.model.ports.Port;
import org.bidib.wizard.model.status.BidibStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jgoodies.binding.beans.Model;
public class Macro extends Model implements LabelAware, TooltipAware {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(Macro.class);
public static final String PROPERTY_PENDING_CHANGES = "pendingChanges";
public static final String PROPERTY_LABEL = "label";
public static final int REPEAT_INFINITE_CYCLES = 0;
public static final int REPEAT_RANGE_MIN_VALUE = 0;
public static final int REPEAT_RANGE_MAX_VALUE = 250;
private static final int DEFAULT_CYCLES = 1;
private static final int DEFAULT_SLOWDOWN = 1;
public static final int SLOWDOWN_RANGE_MIN_VALUE = 1;
public static final int SLOWDOWN_RANGE_MAX_VALUE = 250;
public static final Macro NONE = new Macro.Builder(-1).build();
private final Collection listeners = new LinkedList();
private int cycles = DEFAULT_CYCLES;
private List> functions = new ArrayList>();
/**
* the maximum number of functions that can be stored in this macro
*/
private int functionSize;
private int id;
private String label;
private int speed = DEFAULT_SLOWDOWN;
private Set startConditions = new HashSet();
private boolean containsError;
private MacroSaveState macroSaveState = MacroSaveState.PENDING_CHANGES;
private boolean flatPortModel;
/**
* This should be only called by xml decoder ...
*/
public Macro() {
}
/**
* Create a new instance of Macro.
*
* @param functionSize
* the maximum number of functions that can be stored in this macro.
*/
public Macro(int functionSize) {
this.functionSize = functionSize;
}
private Macro(Builder builder) {
setId(builder.id);
setLabel(builder.label);
}
public void addMacroListener(MacroListener l) {
listeners.add(l);
}
public void removeMacroListener(MacroListener l) {
listeners.remove(l);
}
/**
* Initialize the macro with default values.
*/
public void initialize() {
setCycles(DEFAULT_CYCLES);
setSpeed(DEFAULT_SLOWDOWN);
startConditions.clear();
clearFunctions();
setContainsError(false);
}
public boolean isValid() {
for (Function extends BidibStatus> function : functions) {
if (function instanceof EmptyFunction) {
LOGGER.warn("Found EmptyFunction in functions list! This is not allowed!");
return false;
}
else if (function instanceof PortAware) {
PortAware> portAction = (PortAware>) function;
if (portAction.getPort() == null || portAction.getPort().getId() < 0) {
LOGGER
.warn(
"Found illegal portnumber in PortFunction in functions list! This is not allowed! Current portAction: {}",
portAction);
return false;
}
}
else if (function instanceof InputFunction) {
InputFunction portAction = (InputFunction) function;
if (portAction.getInput() == null || portAction.getInput().getId() < 0) {
LOGGER
.warn(
"Found illegal portnumber in InputFunction in functions list! This is not allowed! Current portAction: {}",
portAction);
return false;
}
}
}
return true;
}
// equals method is overwritten, so we have to find the correct value
// manually
public int getFunctionIndex(Function extends BidibStatus> function) {
int result = -1;
for (int index = 0; index < functions.size(); index++) {
if (functions.get(index) == function) {
result = index;
break;
}
}
return result;
}
/**
* Add a function at the specified index if the index is lower than the maximum number of functions that can be
* stored in this macro.
*
* @param index
* the index to set the function at
* @param function
* the new function
* @return function successfully added
*/
private boolean addFunction(int index, Function extends BidibStatus> function) {
boolean result = false;
if (functions.size() < functionSize) {
this.functions.add(index, function);
result = true;
}
setMacroSaveState(MacroSaveState.PENDING_CHANGES);
return result;
}
public void addFunctionsAfter(int row, Function extends BidibStatus>[] functions) {
List> functionsAdded = new LinkedList>();
if (functions != null) {
for (int index = 0; index < functions.length; index++) {
if (addFunction(row + index + 1, functions[index])) {
functionsAdded.add(functions[index]);
}
}
}
else if (addFunction(row + 1, null)) {
functionsAdded.add(null);
}
if (functionsAdded.size() > 0) {
fireFunctionsAdded(row + 1, functionsAdded.toArray(new Function>[0]));
}
}
public void addFunctionsBefore(int row, Function extends BidibStatus>[] functions) {
List> functionsAdded = new LinkedList>();
if (functions != null) {
for (int index = 0; index < functions.length; index++) {
if (addFunction(row + index, functions[index])) {
functionsAdded.add(functions[index]);
}
}
}
else if (addFunction(row, null)) {
functionsAdded.add(null);
}
if (functionsAdded.size() > 0) {
fireFunctionsAdded(row, functionsAdded.toArray(new Function>[0]));
}
}
public void addFunctionsInvertedAfter(int row, Function extends BidibStatus>[] functions) {
List> functionsAdded = new LinkedList>();
if (ArrayUtils.isNotEmpty(functions)) {
for (int index = 0; index < functions.length; index++) {
// invert the action and add the function
Function extends BidibStatus> currentFunction = functions[index];
Function extends BidibStatus> invertedFunction = MacroUtils.getInvertedFunction(currentFunction);
if (invertedFunction == null) {
invertedFunction = currentFunction;
}
if (addFunction(row + index + 1, invertedFunction)) {
functionsAdded.add(invertedFunction);
}
}
}
else if (addFunction(row + 1, null)) {
functionsAdded.add(null);
}
if (functionsAdded.size() > 0) {
fireFunctionsAdded(row + 1, functionsAdded.toArray(new Function>[0]));
}
}
public void clearFunctions() {
functions.clear();
fireFunctionsRemoved();
}
public Function extends BidibStatus> getFunction(int index) {
Function> result = null;
if (index >= 0 && index < functions.size()) {
result = functions.get(index);
}
return result;
}
/**
* @return the number of macro steps
*/
public int getFunctionCount() {
if (CollectionUtils.isNotEmpty(functions)) {
return functions.size();
}
return 0;
}
public List> getFunctions() {
return Collections.unmodifiableList(functions);
}
public void setFunctions(List> functions) {
fireFunctionsRemoved();
if (functions.size() > functionSize) {
// the maximum number of functions that can be stored (defined by hardware) is exceeded
LOGGER
.warn(
"The maximum number of functions ({}) that can be stored is exceeded. Storing sublist of provided functions.",
functionSize);
this.functions = new ArrayList>(functions.subList(0, functionSize - 1));
}
else {
// set the new functions
this.functions = new ArrayList>(functions);
}
fireFunctionsAdded(0, this.functions.toArray(new Function[0]));
setMacroSaveState(MacroSaveState.PENDING_CHANGES);
}
public void removeFunction(int index) {
functions.remove(index);
setMacroSaveState(MacroSaveState.PENDING_CHANGES);
fireFunctionRemoved(index);
}
public void moveFunction(int fromIndex, int toIndex) {
LOGGER.info("Move function from index: {} to index: {}", fromIndex, toIndex);
Function extends BidibStatus> fromFunction = null;
int targetIndex = toIndex;
if (targetIndex > (functions.size() - 1)) {
targetIndex = functions.size() - 1;
LOGGER.info("Move function to end targetIndex: {}", targetIndex);
fromFunction = functions.remove(fromIndex);
LOGGER
.info("Removed from fromIndex: {}, fromFunction: {}", fromIndex, Function.getDebugString(fromFunction));
functions.add(targetIndex, fromFunction);
}
else if (targetIndex > fromIndex) {
targetIndex = toIndex - 1;
LOGGER.info("i. Move function targetIndex: {}, fromIndex: {}", targetIndex, fromIndex);
fromFunction = functions.remove(fromIndex);
LOGGER
.info("i. Removed from fromIndex: {}, fromFunction: {}", fromIndex,
Function.getDebugString(fromFunction));
functions.add(targetIndex, fromFunction);
}
else { // targetIndex <= fromIndex
LOGGER.info("ii. Move function targetIndex: {}, fromIndex: {}", targetIndex, fromIndex);
fromFunction = functions.remove(fromIndex);
LOGGER
.info("ii. Removed from fromIndex: {}, fromFunction: {}", fromIndex,
Function.getDebugString(fromFunction));
functions.add(targetIndex, fromFunction);
}
setMacroSaveState(MacroSaveState.PENDING_CHANGES);
fireFunctionMoved(fromIndex, targetIndex, fromFunction);
}
public void replaceFunction(int index, Function extends BidibStatus> function) {
functions.set(index, function);
setMacroSaveState(MacroSaveState.PENDING_CHANGES);
}
/**
* @return the maximum number of functions that can be stored in this macro
*/
public int getFunctionSize() {
return functionSize;
}
/**
* @param functionSize
* the maximum number of functions that can be stored in this macro
*/
public void setFunctionSize(int functionSize) {
this.functionSize = functionSize;
// limit the functions to new max size
if (functions.size() > functionSize) {
for (int index = functions.size() - 1; index >= functionSize; index--) {
functions.remove(index);
}
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String getLabel() {
return label;
}
@Override
public void setLabel(String label) {
String oldValue = this.label;
this.label = label;
firePropertyChange(PROPERTY_LABEL, oldValue, label);
}
/**
* @return the macro slowdown value
*/
public int getSpeed() {
return speed;
}
/**
* Set the macro slowdown value.
*
* @param speed
* the macro slowdown value
*/
public void setSpeed(int speed) {
LOGGER.info("Set the macro slowdown value: {}", speed);
if (speed > SLOWDOWN_RANGE_MAX_VALUE) {
// max speed value is 250
LOGGER.warn("Adjust max value for speed to {}, original value: {}", SLOWDOWN_RANGE_MAX_VALUE, speed);
speed = SLOWDOWN_RANGE_MAX_VALUE;
}
else if (speed < SLOWDOWN_RANGE_MIN_VALUE) {
// min speed value is 1
LOGGER.warn("Adjust min value for speed to {}, original value: {}", SLOWDOWN_RANGE_MIN_VALUE, speed);
speed = SLOWDOWN_RANGE_MIN_VALUE;
}
this.speed = speed;
fireSpeedChanged();
}
/**
* returns the number of cycles for this macro. This is the repeat count before the macro has finished. Be aware
* that a value of '0' means endless execution of the macro.
*
* @return the number of cycles
*/
public int getCycles() {
return cycles;
}
public void setCycles(int cycles) {
if (cycles > REPEAT_RANGE_MAX_VALUE) {
LOGGER.warn("Adjust max value for cycles to {}, original value: {}", REPEAT_RANGE_MAX_VALUE, cycles);
cycles = REPEAT_RANGE_MAX_VALUE;
}
else if (cycles < REPEAT_RANGE_MIN_VALUE) {
LOGGER.warn("Adjust min value for cycles to {}, original value: {}", REPEAT_RANGE_MIN_VALUE, cycles);
cycles = REPEAT_RANGE_MIN_VALUE;
}
this.cycles = cycles;
fireCyclesChanged();
}
/**
* @return the flatPortModel
*/
public boolean isFlatPortModel() {
return flatPortModel;
}
/**
* @param flatPortModel
* the flatPortModel to set
*/
public void setFlatPortModel(boolean flatPortModel) {
this.flatPortModel = flatPortModel;
}
public Collection getStartConditions() {
return Collections.unmodifiableCollection(startConditions);
}
public void clearStartConditions() {
startConditions.clear();
// fire the start conditions have changed
fireStartConditionChanged();
}
public void addStartCondition(StartCondition startCondition) {
LOGGER.debug("Add new start condition: {}", startCondition);
startConditions.add(startCondition);
// fire the start conditions have changed
fireStartConditionChanged();
}
public void removeStartCondition(StartCondition startCondition) {
startConditions.remove(startCondition);
// fire the start conditions have changed
fireStartConditionChanged();
}
public void setStartConditions(Collection startConditions) {
this.startConditions = new HashSet();
if (startConditions != null) {
this.startConditions.addAll(startConditions);
}
// fire the start conditions have changed
fireStartConditionChanged();
}
/**
* @return the containsError
*/
public boolean isContainsError() {
return containsError;
}
/**
* @param containsError
* the containsError to set
*/
public void setContainsError(boolean containsError) {
this.containsError = containsError;
}
private void fireFunctionsAdded(int stepNumber, final Function extends BidibStatus>[] functions) {
for (MacroListener l : listeners) {
l.functionsAdded(id, stepNumber, functions);
}
}
private void fireFunctionRemoved(int stepNumber) {
for (MacroListener l : listeners) {
l.functionRemoved(id, stepNumber);
}
}
private void fireFunctionMoved(int fromIndex, int toIndex, Function extends BidibStatus> fromFunction) {
for (MacroListener l : listeners) {
l.functionMoved(id, fromIndex, toIndex, fromFunction);
}
}
private void fireFunctionsRemoved() {
for (MacroListener l : listeners) {
l.functionsRemoved(id);
}
}
private void fireStartConditionChanged() {
LOGGER.debug("fireStartConditionChanged.");
for (MacroListener l : listeners) {
l.startConditionChanged();
}
}
private void fireSpeedChanged() {
LOGGER.debug("fireSpeedChanged.");
for (MacroListener l : listeners) {
l.slowdownFactorChanged();
}
}
private void fireCyclesChanged() {
LOGGER.debug("fireCyclesChanged.");
for (MacroListener l : listeners) {
l.cyclesChanged();
}
}
/**
* @return the pendingChanges
*/
public MacroSaveState getMacroSaveState() {
return macroSaveState;
}
/**
* @param macroSaveState
* the pendingChanges to set
*/
public void setMacroSaveState(MacroSaveState macroSaveState) {
MacroSaveState oldValue = this.macroSaveState;
this.macroSaveState = macroSaveState;
LOGGER.info("Changed the macro save state, new: {}, old: {}", this.macroSaveState, oldValue);
firePropertyChange(PROPERTY_PENDING_CHANGES, oldValue, this.macroSaveState);
}
@Override
public String getTooltipKey() {
String tootipKey = null;
switch (macroSaveState) {
case NOT_LOADED_FROM_NODE:
tootipKey = "not-loaded-from-node";
break;
case PENDING_CHANGES:
tootipKey = "pending-changes";
break;
case SAVED_ON_NODE:
tootipKey = "saved-on-node";
break;
case PERMANENTLY_STORED_ON_NODE:
tootipKey = "permanently-stored-on-node";
break;
default:
LOGGER.error("Unknown macro save state detected: {}", macroSaveState);
break;
}
return tootipKey;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Macro) {
return ((Macro) obj).getId() == getId();
}
return false;
}
@Override
public int hashCode() {
return getId();
}
public String getDebugString() {
return getClass().getSimpleName() + "[cycles=" + cycles + ",functions=" + functions + ",functionSize="
+ functionSize + ",id=" + id + ",label=" + label + ",speed=" + speed + ",startConditions=" + startConditions
+ ",containsError=" + containsError + ",flatPortModel=" + flatPortModel + "]";
}
@Override
public String toString() {
String result = null;
if (StringUtils.isNotBlank(label)) {
result = label;
}
// else {
// result = Resources.getString(getClass(), "label") + "_" + id;
// }
return result;
}
public static class Builder {
private final int id;
private String label;
public Builder(int id) {
this.id = id;
}
public Builder setLabel(String label) {
this.label = label;
return this;
}
public Macro build() {
return new Macro(this);
}
}
public static Macro cloneMacro(final Macro macro) {
// create a clone of the macro
final Macro macroClone = new Macro(macro.getFunctionSize());
macroClone.setId(macro.getId());
macroClone.setLabel(macro.getLabel());
macroClone.setCycles(macro.getCycles());
macroClone.setSpeed(macro.getSpeed());
macroClone.setStartConditions(macro.getStartConditions());
macroClone.setFunctions(macro.getFunctions());
macroClone.setMacroSaveState(macro.getMacroSaveState());
macroClone.setFlatPortModel(macro.isFlatPortModel());
return macroClone;
}
}