blob: 9b475bcbcc97d78c68631f01200d9188ce951a2b (
plain) (
tree)
|
|
package org.openslx.dozmod.gui.changemonitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor.ValidationConstraint;
/**
* Control/element wrapper
*/
public abstract class AbstractControlWrapper<T> {
private final DialogChangeMonitor dcm;
protected boolean wasEverChanged;
protected boolean isCurrentlyChanged;
private T originalContent;
private List<ValidationConstraint<T>> constraints;
private final Comparator<T> cmp;
protected String currentError = null;
/**
* If muted, this wrapper will not react to changes of the underlying
* control.
*/
private boolean muted = false;
protected AbstractControlWrapper(DialogChangeMonitor dcm, Comparator<T> comp) {
this.dcm = dcm;
this.cmp = comp;
}
public boolean hasChangedSinceInit() {
return wasEverChanged;
}
public boolean isCurrentlyChanged() {
return isCurrentlyChanged;
}
/**
* Returns the current error message for the first failed constraint. If no
* constraint currently yields invalid, null is returned.
*
* @return
*/
public String currentConstraintError() {
return currentError;
}
public AbstractControlWrapper<T> addConstraint(ValidationConstraint<T> constraint) {
if (constraints == null) {
constraints = new ArrayList<>();
}
constraints.add(constraint);
return this;
}
/**
* Resets the change state of this control
* and removes the "muted" flag, if set.
*/
public void reset() {
boolean wasChanged = wasEverChanged;
resetChangeState();
if (wasChanged) {
// It's possible that the global change state changed
dcm.contentChanged(this);
}
}
protected final void resetChangeState() {
muted = false;
isCurrentlyChanged = wasEverChanged = false;
originalContent = getCurrentValue();
checkValid(originalContent);
}
/**
* To be called by the implementation whenever the content of the control
* changed and according checks should be triggered.
*/
protected final void contentChanged() {
T text = getCurrentValue();
checkChanged(text);
checkValid(text);
}
/**
* Ignore any changes, don't trigger callbacks regarding
* this component. This flag can be removed by calling
* reset() on this ControlWrapper or the enclosing
* DialogChangeMonitor.
*/
public void mute() {
muted = true;
}
/**
* Method MUST return the current value of the monitored component, so
* that the current state can be considered as the original unmodified
* state.
*/
abstract T getCurrentValue();
protected void checkChanged(T newContent) {
if (muted)
return;
final boolean changed;
if (newContent == originalContent) {
changed = false; // This also covers null == null
} else if (newContent == null || originalContent == null) {
changed = true; // So here we know either/or is null, not both
} else if (newContent instanceof Collection
&& ((Collection<?>) newContent).size() != ((Collection<?>) originalContent).size()) {
changed = true;
} else if (newContent instanceof Map
&& ((Map<?, ?>) newContent).size() != ((Map<?, ?>) originalContent).size()) {
changed = true;
} else if (cmp == null) {
changed = !originalContent.equals(newContent);
} else {
// User supplied comparator
changed = cmp.compare(originalContent, newContent) != 0;
}
if (isCurrentlyChanged != changed) {
isCurrentlyChanged = changed;
dcm.contentChanged(this);
}
}
protected void checkValid(T text) {
if (muted || constraints == null || constraints.isEmpty())
return;
String error = null;
for (ValidationConstraint<T> i : constraints) {
error = i.checkStateValid(text);
if (error != null)
break;
}
if ((error == null && currentError != null) || (error != null && currentError == null)
|| (error != null && !error.equals(currentError))) {
currentError = error;
dcm.validityChanged(this);
}
}
}
|