/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.utilbox.fields;
import melnorme.utilbox.collections.Indexable;
/**
* Default implementation of a {@link IField}, an observable property.
*/
public class Field<TYPE> implements IField<TYPE> {
protected final ListenerListHelper<FieldValueListener<? super TYPE>> listeners = new ListenerListHelper<>();
private TYPE value; // private to prevent direct modifications.
public Field() {
this(null);
}
public Field(TYPE defaultFieldValue) {
this.value = defaultFieldValue;
}
@Override
public void addListener(FieldValueListener<? super TYPE> listener) {
listeners.addListener(listener);
}
@Override
public void removeListener(FieldValueListener<? super TYPE> listener) {
listeners.removeListener(listener);
}
protected Indexable<FieldValueListener<? super TYPE>> getListeners() {
return listeners.getListeners();
}
/* ----------------- listeners ----------------- */
public void fireFieldValueChanged() {
TYPE newFieldValue = getFieldValue();
fieldValueChanged();
for (FieldValueListener<? super TYPE> listener : listeners.getListeners()) {
listener.fieldValueChanged(newFieldValue);
}
}
// this methos allows listening by means of overriding this class
protected void fieldValueChanged() {
// Default: do nothing
}
@Override
public TYPE getFieldValue() {
return value;
}
@Override
public void setFieldValue(TYPE value) {
doSetFieldValue(value);
}
protected boolean notifyingListeners;
public boolean isNotifyingListeners() {
return notifyingListeners;
}
protected void doSetFieldValue(TYPE newValue) {
if(notifyingListeners) {
handleReentrantSetValue(newValue);
} else {
this.value = newValue;
notifyingListeners = true;
try {
fireFieldValueChanged();
} finally {
notifyingListeners = false;
}
}
}
protected void handleReentrantSetValue(TYPE newValue) {
// This shouldn't happen in the first place, bad style.
this.value = newValue;
}
}