Refactor model invalidation to dedicated class
This commit is contained in:
parent
a793f27f51
commit
e3eeecd7ae
@ -439,8 +439,10 @@ public class Rocket extends ComponentAssembly {
|
||||
this.configSet.reset();
|
||||
this.configSet.setDefault(new FlightConfiguration(this));
|
||||
for (FlightConfigurationId key : source.configSet.map.keySet()) {
|
||||
FlightConfiguration srcCfg = source.configSet.get(key);
|
||||
FlightConfiguration newCfg = new FlightConfiguration(this, key);
|
||||
newCfg.setName(source.configSet.get(key).getNameRaw()); // Copy config name
|
||||
newCfg.copyStageActiveness(srcCfg);
|
||||
newCfg.setName(srcCfg.getNameRaw()); // Copy config name
|
||||
this.configSet.set(key, newCfg);
|
||||
}
|
||||
this.selectedConfiguration = this.configSet.get(source.getSelectedConfiguration().getId());
|
||||
|
@ -6,6 +6,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
@ -22,8 +23,6 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.ChangeSource;
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.Invalidator;
|
||||
import net.sf.openrocket.util.MemoryManagement;
|
||||
import net.sf.openrocket.util.Reflection;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
@ -44,6 +43,7 @@ import net.sf.openrocket.util.StateChangeListener;
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class BooleanModel extends AbstractAction implements StateChangeListener, ChangeSource, Invalidatable {
|
||||
private final ModelInvalidator modelInvalidator; // Composite pattern because f***ing Java doesn't allow multiple inheritance...
|
||||
private static final long serialVersionUID = -7299680391506320196L;
|
||||
private static final Logger log = LoggerFactory.getLogger(BooleanModel.class);
|
||||
|
||||
@ -68,9 +68,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
|
||||
private boolean oldValue;
|
||||
private boolean oldEnabled;
|
||||
|
||||
private Invalidator invalidator = new Invalidator(this);
|
||||
private final ArrayList<EventListener> listeners = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -79,6 +77,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
* @param initialValue the initial value of the boolean
|
||||
*/
|
||||
public BooleanModel(boolean initialValue) {
|
||||
this.modelInvalidator = new ModelInvalidator(null, this);
|
||||
this.valueName = null;
|
||||
this.source = null;
|
||||
this.getMethod = null;
|
||||
@ -102,13 +101,14 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
* @param valueName the name of the getter/setter method (without the get/is/set prefix)
|
||||
*/
|
||||
public BooleanModel(ChangeSource source, String valueName) {
|
||||
this.modelInvalidator = new ModelInvalidator(source, this);
|
||||
this.source = source;
|
||||
this.valueName = valueName;
|
||||
|
||||
Method getter = null, setter = null;
|
||||
|
||||
if(RocketComponent.class.isAssignableFrom(source.getClass())) {
|
||||
((RocketComponent)source).addChangeListener(this);
|
||||
if (RocketComponent.class.isAssignableFrom(source.getClass())) {
|
||||
source.addChangeListener(this);
|
||||
}
|
||||
|
||||
// Try get/is and set
|
||||
@ -172,7 +172,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
}
|
||||
|
||||
public void setValue(boolean b) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
log.debug("Setting value of " + this + " to " + b);
|
||||
|
||||
if (setMethod != null) {
|
||||
@ -200,7 +200,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
* @param enableState the state in which the component should be enabled.
|
||||
*/
|
||||
public void addEnableComponent(Component component, boolean enableState) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
components.add(component);
|
||||
componentEnableState.add(enableState);
|
||||
updateEnableStatus();
|
||||
@ -211,7 +211,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
* @param component component to remove from the list
|
||||
*/
|
||||
public void removeEnableComponent(Component component) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
components.remove(component);
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
* @see #addEnableComponent(Component, boolean)
|
||||
*/
|
||||
public void addEnableComponent(Component component) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
addEnableComponent(component, true);
|
||||
}
|
||||
|
||||
@ -250,10 +250,14 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
throw Reflection.handleWrappedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<EventListener> getListeners() {
|
||||
return modelInvalidator.listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(EventObject event) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
if (firing > 0) {
|
||||
log.debug("Ignoring stateChanged of " + this + ", currently firing events");
|
||||
@ -277,7 +281,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
setEnabled(e);
|
||||
}
|
||||
|
||||
for (EventListener listener : listeners) {
|
||||
for (EventListener listener : getListeners()) {
|
||||
if (listener instanceof StateChangeListener) {
|
||||
((StateChangeListener) listener).stateChanged(event);
|
||||
} else if (listener instanceof ChangeListener) {
|
||||
@ -308,7 +312,7 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
firing--;
|
||||
}
|
||||
|
||||
for (EventListener listener : listeners) {
|
||||
for (EventListener listener : getListeners()) {
|
||||
if (listener instanceof StateChangeListener) {
|
||||
((StateChangeListener) listener).stateChanged(e);
|
||||
} else if (listener instanceof ChangeListener) {
|
||||
@ -321,36 +325,18 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
super.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to the model. Adds the model as a listener to the value source if this
|
||||
* is the first listener.
|
||||
* @param listener Listener to add.
|
||||
*/
|
||||
@Override
|
||||
public void addChangeListener(StateChangeListener listener) {
|
||||
checkState(true);
|
||||
|
||||
if (listeners.add(listener)) {
|
||||
log.trace(this + " adding listener (total " + listeners.size() + "): " + listener);
|
||||
}
|
||||
modelInvalidator.addChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener from the model. Removes the model from being a listener to the Component
|
||||
* if this was the last listener of the model.
|
||||
* @param listener Listener to remove.
|
||||
*/
|
||||
@Override
|
||||
public void removeChangeListener(StateChangeListener listener) {
|
||||
checkState(false);
|
||||
|
||||
if (listeners.remove(listener)) {
|
||||
log.trace(this + " removing listener (total " + listeners.size() + "): " + listener);
|
||||
}
|
||||
modelInvalidator.removeChangeListener(listener);
|
||||
}
|
||||
|
||||
|
||||
@ -361,31 +347,16 @@ public class BooleanModel extends AbstractAction implements StateChangeListener,
|
||||
*/
|
||||
@Override
|
||||
public void invalidate() {
|
||||
invalidator.invalidate();
|
||||
|
||||
PropertyChangeListener[] listeners = this.getPropertyChangeListeners();
|
||||
if (listeners.length > 0) {
|
||||
log.warn("Invalidating " + this + " while still having listeners " + listeners);
|
||||
log.warn("Invalidating " + this + " while still having listeners " + Arrays.toString(listeners));
|
||||
for (PropertyChangeListener l : listeners) {
|
||||
this.removePropertyChangeListener(l);
|
||||
}
|
||||
}
|
||||
if (!this.listeners.isEmpty()) {
|
||||
log.warn("Invalidating " + this + " while still having listeners " + this.listeners);
|
||||
}
|
||||
this.listeners.clear();
|
||||
if (source != null) {
|
||||
source.removeChangeListener(this);
|
||||
}
|
||||
MemoryManagement.collectable(this);
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
|
||||
private void checkState(boolean error) {
|
||||
invalidator.check(error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -8,6 +8,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.AbstractSpinnerModel;
|
||||
@ -29,9 +30,7 @@ import net.sf.openrocket.util.ChangeSource;
|
||||
import net.sf.openrocket.util.ExpressionParser;
|
||||
import net.sf.openrocket.util.InvalidExpressionException;
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.Invalidator;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.MemoryManagement;
|
||||
import net.sf.openrocket.util.Reflection;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
@ -52,7 +51,7 @@ import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
public class DoubleModel implements StateChangeListener, ChangeSource, Invalidatable {
|
||||
private static final Logger log = LoggerFactory.getLogger(DoubleModel.class);
|
||||
|
||||
private final ModelInvalidator modelInvalidator; // Composite pattern because f***ing Java doesn't allow multiple inheritance...
|
||||
|
||||
public static final DoubleModel ZERO = new DoubleModel(0);
|
||||
|
||||
@ -613,8 +612,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
|
||||
private final Method getAutoMethod;
|
||||
private final Method setAutoMethod;
|
||||
|
||||
private final ArrayList<EventListener> listeners = new ArrayList<EventListener>();
|
||||
|
||||
|
||||
private UnitGroup units;
|
||||
private Unit currentUnit;
|
||||
@ -632,8 +630,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
private double lastValue = 0;
|
||||
private boolean lastAutomatic = false;
|
||||
|
||||
private Invalidator invalidator = new Invalidator(this);
|
||||
|
||||
|
||||
/**
|
||||
* Generate a DoubleModel that contains an internal double value.
|
||||
@ -674,6 +670,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* @param max maximum value.
|
||||
*/
|
||||
public DoubleModel(double value, UnitGroup unit, double min, double max) {
|
||||
this.modelInvalidator = new ModelInvalidator(null, this);
|
||||
this.lastValue = value;
|
||||
this.minValue = min;
|
||||
this.maxValue = max;
|
||||
@ -701,6 +698,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
*/
|
||||
public DoubleModel(Object source, String valueName, double multiplier, UnitGroup unit,
|
||||
double min, double max) {
|
||||
this.modelInvalidator = new ModelInvalidator(source, this);
|
||||
this.source = source;
|
||||
this.valueName = valueName;
|
||||
this.multiplier = multiplier;
|
||||
@ -808,7 +806,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* @param v New value for parameter in SI units.
|
||||
*/
|
||||
public void setValue(double v) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
double clampedValue = MathUtil.clamp(v, minValue, maxValue);
|
||||
if (clampedValue != v) {
|
||||
@ -871,7 +869,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* state change event if automatic setting is not available.
|
||||
*/
|
||||
public void setAutomatic(boolean auto) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
if (setAutoMethod == null) {
|
||||
log.debug("Setting automatic to " + auto + " for " + this + ", automatic not available");
|
||||
@ -906,7 +904,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* @param u The unit to set active.
|
||||
*/
|
||||
public void setCurrentUnit(Unit u) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
if (currentUnit == u)
|
||||
return;
|
||||
log.debug("Setting unit for " + this + " to '" + u + "'");
|
||||
@ -930,7 +928,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
public UnitGroup getUnitGroup() {
|
||||
return units;
|
||||
}
|
||||
|
||||
|
||||
private List<EventListener> getListeners() {
|
||||
return modelInvalidator.listeners;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -950,17 +951,16 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* @param l Listener to add.
|
||||
*/
|
||||
public void addChangeListener(EventListener l) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
if (listeners.isEmpty()) {
|
||||
if (getListeners().isEmpty()) {
|
||||
if (source != null) {
|
||||
lastValue = getValue();
|
||||
lastAutomatic = isAutomatic();
|
||||
}
|
||||
}
|
||||
|
||||
listeners.add(l);
|
||||
log.trace(this + " adding listener (total " + listeners.size() + "): " + l);
|
||||
|
||||
modelInvalidator.addChangeListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -979,10 +979,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* @param l Listener to remove.
|
||||
*/
|
||||
public void removeChangeListener(EventListener l) {
|
||||
checkState(false);
|
||||
|
||||
listeners.remove(l);
|
||||
log.trace(this + " removing listener (total " + listeners.size() + "): " + l);
|
||||
modelInvalidator.removeChangeListener(l);
|
||||
}
|
||||
|
||||
|
||||
@ -993,31 +990,15 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
*/
|
||||
@Override
|
||||
public void invalidate() {
|
||||
log.trace("Invalidating " + this);
|
||||
invalidator.invalidate();
|
||||
|
||||
if (!listeners.isEmpty()) {
|
||||
log.warn("Invalidating " + this + " while still having listeners " + listeners);
|
||||
}
|
||||
listeners.clear();
|
||||
if (source instanceof ChangeSource) {
|
||||
((ChangeSource) source).removeChangeListener(this);
|
||||
}
|
||||
MemoryManagement.collectable(this);
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
|
||||
private void checkState(boolean error) {
|
||||
invalidator.check(error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO MEDIUM: finalize is deprecated, replace with something better
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!listeners.isEmpty()) {
|
||||
log.warn(this + " being garbage-collected while having listeners " + listeners);
|
||||
}
|
||||
modelInvalidator.finalize();
|
||||
};
|
||||
|
||||
|
||||
@ -1025,13 +1006,13 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
* Fire a ChangeEvent to all listeners.
|
||||
*/
|
||||
protected void fireStateChanged() {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
EventObject event = new EventObject(this);
|
||||
ChangeEvent cevent = new ChangeEvent(this);
|
||||
firing++;
|
||||
// Copy the list before iterating to prevent concurrent modification exceptions.
|
||||
EventListener[] ls = listeners.toArray(new EventListener[0]);
|
||||
EventListener[] ls = getListeners().toArray(new EventListener[0]);
|
||||
for (EventListener l : ls) {
|
||||
if (l instanceof StateChangeListener) {
|
||||
((StateChangeListener) l).stateChanged(event);
|
||||
@ -1048,7 +1029,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
*/
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
checkState(true);
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
double v = getValue();
|
||||
boolean b = isAutomatic();
|
||||
|
@ -7,13 +7,15 @@ import javax.swing.AbstractListModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.MutableComboBoxModel;
|
||||
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.Reflection;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
|
||||
public class EnumModel<T extends Enum<T>> extends AbstractListModel<T>
|
||||
implements ComboBoxModel<T>, MutableComboBoxModel<T>, StateChangeListener {
|
||||
implements ComboBoxModel<T>, MutableComboBoxModel<T>, StateChangeListener, Invalidatable {
|
||||
private static final long serialVersionUID = 7766446027840316797L;
|
||||
private final ModelInvalidator modelInvalidator;
|
||||
private final Object source;
|
||||
private final String valueName;
|
||||
private final String nullText;
|
||||
@ -39,6 +41,7 @@ public class EnumModel<T extends Enum<T>> extends AbstractListModel<T>
|
||||
@SuppressWarnings("unchecked")
|
||||
public EnumModel(Object source, String valueName, T[] values, String nullText) {
|
||||
Class<? extends Enum<T>> enumClass;
|
||||
this.modelInvalidator = new ModelInvalidator(source, this);
|
||||
this.source = source;
|
||||
this.valueName = valueName;
|
||||
|
||||
@ -124,6 +127,8 @@ public class EnumModel<T extends Enum<T>> extends AbstractListModel<T>
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
T value = (T) getMethod.invoke(source);
|
||||
if (value != currentValue) {
|
||||
currentValue = value;
|
||||
@ -163,4 +168,8 @@ public class EnumModel<T extends Enum<T>> extends AbstractListModel<T>
|
||||
this.displayedValues.remove( index );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package net.sf.openrocket.gui.adaptors;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
|
||||
@ -13,6 +12,7 @@ import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -24,10 +24,12 @@ import net.sf.openrocket.util.Reflection;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
|
||||
public class IntegerModel implements StateChangeListener {
|
||||
public class IntegerModel implements StateChangeListener, Invalidatable {
|
||||
private static final Logger log = LoggerFactory.getLogger(IntegerModel.class);
|
||||
|
||||
|
||||
|
||||
private final ModelInvalidator modelInvalidator;
|
||||
|
||||
|
||||
//////////// JSpinner Model ////////////
|
||||
|
||||
private class IntegerSpinnerModel extends SpinnerNumberModel {
|
||||
@ -139,8 +141,7 @@ public class IntegerModel implements StateChangeListener {
|
||||
|
||||
private final Method getMethod;
|
||||
private final Method setMethod;
|
||||
|
||||
private final ArrayList<EventListener> listeners = new ArrayList<EventListener>();
|
||||
|
||||
|
||||
private final int minValue;
|
||||
private final int maxValue;
|
||||
@ -166,6 +167,7 @@ public class IntegerModel implements StateChangeListener {
|
||||
* @param max Maximum value allowed (in SI units)
|
||||
*/
|
||||
public IntegerModel(ChangeSource source, String valueName, int min, int max) {
|
||||
this.modelInvalidator = new ModelInvalidator(source, this);
|
||||
this.source = source;
|
||||
this.valueName = valueName;
|
||||
|
||||
@ -237,13 +239,7 @@ public class IntegerModel implements StateChangeListener {
|
||||
* @param l Listener to add.
|
||||
*/
|
||||
public void addChangeListener(EventListener l) {
|
||||
if (listeners.isEmpty()) {
|
||||
source.addChangeListener(this);
|
||||
lastValue = getValue();
|
||||
}
|
||||
|
||||
listeners.add(l);
|
||||
log.trace(this + " adding listener (total " + listeners.size() + "): " + l);
|
||||
modelInvalidator.addChangeListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,25 +248,19 @@ public class IntegerModel implements StateChangeListener {
|
||||
* @param l Listener to remove.
|
||||
*/
|
||||
public void removeChangeListener(ChangeListener l) {
|
||||
listeners.remove(l);
|
||||
if (listeners.isEmpty()) {
|
||||
source.removeChangeListener(this);
|
||||
}
|
||||
log.trace(this + " removing listener (total " + listeners.size() + "): " + l);
|
||||
modelInvalidator.removeChangeListener(l);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!listeners.isEmpty()) {
|
||||
log.warn(this + " being garbage-collected while having listeners " + listeners);
|
||||
}
|
||||
modelInvalidator.finalize();
|
||||
};
|
||||
|
||||
|
||||
public void fireStateChanged() {
|
||||
EventListener[] list = listeners.toArray(new EventListener[0] );
|
||||
EventListener[] list = modelInvalidator.listeners.toArray(new EventListener[0] );
|
||||
EventObject event = new EventObject(this);
|
||||
ChangeEvent cevent = new ChangeEvent(this);
|
||||
firing++;
|
||||
@ -290,6 +280,8 @@ public class IntegerModel implements StateChangeListener {
|
||||
*/
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
modelInvalidator.checkState(true);
|
||||
|
||||
int v = getValue();
|
||||
if (lastValue == v)
|
||||
return;
|
||||
@ -307,5 +299,10 @@ public class IntegerModel implements StateChangeListener {
|
||||
}
|
||||
return toString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,11 +17,13 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.Reflection;
|
||||
|
||||
public class MaterialModel extends AbstractListModel<Material> implements
|
||||
ComboBoxModel<Material>, ComponentChangeListener, DatabaseListener<Material> {
|
||||
ComboBoxModel<Material>, ComponentChangeListener, DatabaseListener<Material>, Invalidatable {
|
||||
private static final long serialVersionUID = 4552478532933113655L;
|
||||
private final ModelInvalidator modelInvalidator;
|
||||
|
||||
|
||||
private final Material custom;
|
||||
@ -46,6 +48,7 @@ public class MaterialModel extends AbstractListModel<Material> implements
|
||||
|
||||
public MaterialModel(Component parent, RocketComponent component, Material.Type type,
|
||||
String name) {
|
||||
this.modelInvalidator = new ModelInvalidator(component, this);
|
||||
this.parentUIComponent = parent;
|
||||
this.rocketComponent = component;
|
||||
this.type = type;
|
||||
@ -166,5 +169,15 @@ public class MaterialModel extends AbstractListModel<Material> implements
|
||||
public void elementRemoved(Material element, Database<Material> source) {
|
||||
this.fireContentsChanged(this, 0, database.size());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
modelInvalidator.finalize();
|
||||
}
|
||||
}
|
||||
|
129
swing/src/net/sf/openrocket/gui/adaptors/ModelInvalidator.java
Normal file
129
swing/src/net/sf/openrocket/gui/adaptors/ModelInvalidator.java
Normal file
@ -0,0 +1,129 @@
|
||||
package net.sf.openrocket.gui.adaptors;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.ChangeSource;
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import net.sf.openrocket.util.Invalidator;
|
||||
import net.sf.openrocket.util.MemoryManagement;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A helper model for invalidating value models.
|
||||
* This class has nothing to do with the actual setting/getting of the value, it's just here to avoid duplicate code
|
||||
* in invalidating value models.
|
||||
* This model should probably be used in a composition pattern, where this model is instantiated in a class.
|
||||
* This class should then delegate the methods of the interface
|
||||
* to this class.
|
||||
* Thanks, Java, for not allowing multiple inheritance.
|
||||
*/
|
||||
public class ModelInvalidator implements StateChangeListener, Invalidatable, ChangeSource {
|
||||
private static final Logger log = LoggerFactory.getLogger(ModelInvalidator.class);
|
||||
|
||||
private final Invalidator invalidator;
|
||||
private final Object source;
|
||||
private final EventListener model;
|
||||
protected final List<EventListener> listeners = new ArrayList<>();
|
||||
|
||||
public ModelInvalidator(Object source, EventListener model) {
|
||||
this.source = source;
|
||||
this.model = model;
|
||||
this.invalidator = new Invalidator(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to the model. Adds the model as a listener to the value source if this
|
||||
* is the first listener.
|
||||
* @param listener Listener to add.
|
||||
*/
|
||||
@Override
|
||||
public void addChangeListener(StateChangeListener listener) {
|
||||
addChangeListener((EventListener) listener);
|
||||
}
|
||||
|
||||
public void addChangeListener(EventListener listener) {
|
||||
checkState(true);
|
||||
|
||||
if (listeners.add(listener)) {
|
||||
log.trace(this + " adding listener (total " + listeners.size() + "): " + listener);
|
||||
} else {
|
||||
log.warn(this + " adding listener that was already registered: " + listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener from the model. Removes the model from being a listener to the Component
|
||||
* if this was the last listener of the model.
|
||||
* @param listener Listener to remove.
|
||||
*/
|
||||
@Override
|
||||
public void removeChangeListener(StateChangeListener listener) {
|
||||
removeChangeListener((EventListener) listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener from the model. Removes the model from being a listener to the Component
|
||||
* if this was the last listener of the model.
|
||||
* @param l Listener to remove.
|
||||
*/
|
||||
public void removeChangeListener(EventListener l) {
|
||||
checkState(false);
|
||||
|
||||
if (listeners.remove(l)) {
|
||||
log.trace(this + " removing listener (total " + listeners.size() + "): " + l);
|
||||
} else {
|
||||
log.warn(this + " removing listener that was not registered: " + l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the state of this model. If the model is invalid, throw an IllegalStateException if `errpr` is true.
|
||||
* @param error If true, throw an IllegalStateException if the model is invalid.
|
||||
*/
|
||||
protected void checkState(boolean error) {
|
||||
invalidator.check(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates this model by removing all listeners and removing this from
|
||||
* listening to the source. After invalidation no listeners can be added to this
|
||||
* model and the value cannot be set.
|
||||
*/
|
||||
@Override
|
||||
public void invalidate() {
|
||||
log.trace("Invalidating " + this);
|
||||
invalidator.invalidate();
|
||||
|
||||
if (!listeners.isEmpty()) {
|
||||
log.warn("Invalidating " + this + " while still having listeners " + listeners);
|
||||
}
|
||||
listeners.clear();
|
||||
if (source instanceof ChangeSource && model instanceof StateChangeListener) {
|
||||
((ChangeSource) source).removeChangeListener((StateChangeListener) model);
|
||||
} else if (source instanceof RocketComponent && model instanceof ComponentChangeListener) {
|
||||
((RocketComponent) source).removeComponentChangeListener((ComponentChangeListener) model);
|
||||
}
|
||||
MemoryManagement.collectable(model);
|
||||
MemoryManagement.collectable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!listeners.isEmpty()) {
|
||||
log.warn(model + " being garbage-collected while having listeners " + listeners);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(EventObject e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import java.util.List;
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -22,10 +23,12 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
|
||||
public class PresetModel extends AbstractListModel implements ComboBoxModel, ComponentChangeListener, DatabaseListener<ComponentPreset> {
|
||||
public class PresetModel extends AbstractListModel
|
||||
implements ComboBoxModel, ComponentChangeListener, DatabaseListener<ComponentPreset>, Invalidatable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PresetModel.class);
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private final ModelInvalidator modelInvalidator;
|
||||
|
||||
private static final String NONE_SELECTED = String.format("<html><i>%s</i></html>", trans.get("PresetModel.lbl.custompreset"));
|
||||
|
||||
@ -37,6 +40,7 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
|
||||
private List<ComponentPreset> presets;
|
||||
|
||||
public PresetModel(Component parent, OpenRocketDocument document, RocketComponent component) {
|
||||
this.modelInvalidator = new ModelInvalidator(component, this);
|
||||
this.parent = parent;
|
||||
this.document = document;
|
||||
presets = Application.getComponentPresetDao().listForType(component.getPresetType(), true);
|
||||
@ -102,5 +106,15 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
|
||||
presets = Application.getComponentPresetDao().listForType(component.getPresetType(), true);
|
||||
this.fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
modelInvalidator.finalize();
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,20 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.Transition;
|
||||
import net.sf.openrocket.util.Invalidatable;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.ComboBoxModel;
|
||||
|
||||
public class TransitionShapeModel extends AbstractListModel<Transition.Shape>
|
||||
implements ComboBoxModel<Transition.Shape>, ComponentChangeListener {
|
||||
implements ComboBoxModel<Transition.Shape>, ComponentChangeListener, Invalidatable {
|
||||
private final ModelInvalidator modelInvalidator;
|
||||
private final RocketComponent component;
|
||||
private final Transition.Shape[] typeList = Transition.Shape.values();
|
||||
private Transition.Shape previousType;
|
||||
|
||||
public TransitionShapeModel(RocketComponent component) {
|
||||
this.modelInvalidator = new ModelInvalidator(component, this);
|
||||
this.component = component;
|
||||
if (component instanceof Transition) {
|
||||
previousType = ((Transition) component).getShapeType();
|
||||
@ -61,4 +64,15 @@ public class TransitionShapeModel extends AbstractListModel<Transition.Shape>
|
||||
fireContentsChanged(this, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
modelInvalidator.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
modelInvalidator.finalize();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user