Skip to main content
summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java13
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java125
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java2
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java398
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java349
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java30
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelWrapper.java124
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedModifiablePropertyValueModelTests.java504
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/BufferedPropertyValueModelTests.java597
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java2
10 files changed, 985 insertions, 1159 deletions
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
index df59dc5316..78fc9c36d1 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java
@@ -28,7 +28,8 @@ import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jpt.common.ui.internal.plugin.JptCommonUiPlugin;
import org.eclipse.jpt.common.utility.internal.ArrayTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.model.value.BufferedModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.BufferedPropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.model.Model;
import org.eclipse.jpt.common.utility.model.listener.AbstractChangeListener;
@@ -65,7 +66,7 @@ public abstract class JptProjectPropertiesPage
protected volatile boolean engaged = false;
protected final ModifiablePropertyValueModel<IProject> projectModel;
- protected final BufferedModifiablePropertyValueModel.Trigger trigger;
+ protected final BufferedPropertyValueModelAdapter.Trigger trigger;
protected final ChangeListener validationListener;
@@ -74,7 +75,7 @@ public abstract class JptProjectPropertiesPage
super();
this.projectModel = new SimplePropertyValueModel<>();
- this.trigger = new BufferedModifiablePropertyValueModel.Trigger();
+ this.trigger = PropertyValueModelTools.bufferedPropertyValueModelAdapterTrigger();
this.buildModels();
@@ -350,15 +351,15 @@ public abstract class JptProjectPropertiesPage
* Return whether any of the models are buffering a change.
*/
private boolean isBuffering() {
- for (BufferedModifiablePropertyValueModel<?> model : this.buildBufferedModels()) {
- if (model.isBuffering()) {
+ for (PropertyValueModel<Boolean> flag : this.buildBufferingFlags()) {
+ if (flag.getValue().booleanValue()) {
return true;
}
}
return false;
}
- protected abstract BufferedModifiablePropertyValueModel<?>[] buildBufferedModels();
+ protected abstract PropertyValueModel<Boolean>[] buildBufferingFlags();
@Override
protected void performDefaults() {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java
deleted file mode 100644
index aeb34de889..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModel.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2016 Oracle. 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:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.model.value;
-
-import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.common.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.common.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure for "lazily" adding/removing
- * listeners to/from an underlying model as <em>property</em> change
- * listeners are added to/removed from itself.
- * Subclasses will need to engage and disengage the underlying model
- * appropriately and fire the appropriate <em>property</em>
- * change events.
- * <p>
- * Subclasses must implement the appropriate {@link PropertyValueModel}.
- * <p>
- * Subclasses must implement the following methods:<ul>
- * <li>{@link #engageModel()}<p>
- * implement this method to add the appropriate listener(s) to the
- * underlying model
- * <li>{@link #disengageModel()}<p>
- * implement this method to remove the appropriate listener(s) from the
- * underlying model
- * </ul>
- */
-public abstract class AbstractPropertyValueModel
- extends AbstractModel
-{
- // ********** constructor/initialization **********
-
- protected AbstractPropertyValueModel() {
- super();
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE);
- }
-
-
- // ********** listeners **********
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public synchronized void addChangeListener(ChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying model if necessary.
- */
- @Override
- public synchronized void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- if (propertyName.equals(PropertyValueModel.VALUE) && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addPropertyChangeListener(propertyName, listener);
- }
-
- /**
- * Extend to stop listening to the underlying model if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- super.removePropertyChangeListener(propertyName, listener);
- if (propertyName.equals(PropertyValueModel.VALUE) && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Return whether the model has no property value listeners.
- */
- public boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
- /**
- * Return whether the model has any property value listeners.
- */
- public boolean hasListeners() {
- return this.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE);
- }
-
-
- // ********** subclass implementation **********
-
- /**
- * Engage the underlying model.
- */
- protected abstract void engageModel();
-
- /**
- * Stop listening to the underlying model.
- */
- protected abstract void disengageModel();
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
index 69538412e0..6b94a430d8 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BasePluggablePropertyValueModel.java
@@ -174,7 +174,7 @@ public abstract class BasePluggablePropertyValueModel<V, A extends BasePluggable
// ********** Adapter Listener **********
/**
- * Simple callback.
+ * Simple callback. Allows us to keep the callback method internal.
*/
/* CU private */ class AdapterListener
implements Adapter.Listener<V>
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java
deleted file mode 100644
index 8dbd7b2f56..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedModifiablePropertyValueModel.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. 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:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.model.value;
-
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
-
-/**
- * A <code>BufferedModifiablePropertyValueModel</code> is used to hold a temporary
- * copy of the value
- * in another property value model (the "wrapped" value model). The application
- * can modify this temporary copy, ad nauseam; but the temporary copy is only
- * passed through to the "wrapped" value model when the trigger "accepts" the
- * buffered value. Alternatively, the application can "reset" the buffered value
- * to the original, "wrapped" value.
- * <p>
- * The trigger is another {@link PropertyValueModel} that holds a
- * {@link Boolean} and the application changes the trigger's value to
- * <code>true</code> on "accept", <code>false</code> on "reset".
- * <p>
- * Typically, in a dialog:<ul>
- * <li>pressing the "OK" button will trigger an "accept" and close the dialog
- * <li>pressing the "Cancel" button will simply close the dialog,
- * dropping the "buffered" values into the bit bucket
- * <li>pressing the "Apply" button will trigger an "accept" and leave the
- * dialog open
- * <li>pressing the "Restore" button will trigger a "reset" and leave the
- * dialog open
- * </ul>
- * A number of buffered property value models can wrap another set of
- * property aspect adapters that adapt the various aspects of a single
- * domain model. All the buffered property value models can be hooked to the
- * same trigger, and that trigger is controlled by the application, typically
- * via the "OK" button in a dialog.
- *
- * @param <V> the type of the model's value
- * @see PropertyAspectAdapter
- */
-public class BufferedModifiablePropertyValueModel<V>
- extends PropertyValueModelWrapper<V>
- implements ModifiablePropertyValueModel<V>
-{
- /**
- * We cache the value here until it is accepted and passed
- * through to the wrapped value model.
- */
- protected volatile V bufferedValue;
-
- /**
- * This is set to true when we are "accepting" the buffered value
- * and passing it through to the wrapped value model. This allows
- * us to ignore the property change event fired by the wrapped
- * value model.
- * (We can't stop listening to the wrapped value model, because
- * if we are the only listener that could "deactivate" the wrapped
- * value model.)
- */
- protected volatile boolean accepting;
-
- /**
- * This is the trigger that indicates whether the buffered value
- * should be accepted or reset.
- */
- protected final PropertyValueModel<Boolean> triggerModel;
-
- /** This listens to the trigger model. */
- protected final PropertyChangeListener triggerListener;
-
- /**
- * This flag indicates whether our buffered value has been assigned
- * a value and is possibly out of sync with the wrapped value.
- */
- protected volatile boolean buffering;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a buffered property value model with the specified wrapped
- * property value model and trigger model.
- */
- // TODO wrap the value model in a CachingPVMWrapper and get rid of accepting flag
- public BufferedModifiablePropertyValueModel(ModifiablePropertyValueModel<V> valueModel, PropertyValueModel<Boolean> triggerModel) {
- super(valueModel);
- if (triggerModel == null) {
- throw new NullPointerException();
- }
- this.triggerModel = triggerModel;
- this.bufferedValue = null;
- this.buffering = false;
- this.accepting = false;
- this.triggerListener = this.buildTriggerListener();
- }
-
- protected PropertyChangeListener buildTriggerListener() {
- return new TriggerListener();
- }
-
- protected class TriggerListener
- extends PropertyChangeAdapter
- {
- @Override
- public void propertyChanged(PropertyChangeEvent event) {
- BufferedModifiablePropertyValueModel.this.triggerChanged(event);
- }
- }
-
-
- // ********** value **********
-
- /**
- * If we are currently "buffering" a value, return that;
- * otherwise, return the wrapped value.
- */
- public V getValue() {
- return this.buffering ? this.bufferedValue : this.valueModel.getValue();
- }
-
- /**
- * Assign the new value to our "buffered" value.
- * It will be pushed to the wrapped value model
- * when the trigger is "accepted".
- */
- public void setValue(V value) {
- if (this.buffering) {
- if (ObjectTools.equals(value, this.valueModel.getValue())) {
- // the buffered value is being set back to the original value
- this.reset();
- } else {
- // the buffered value is being changed
- Object old = this.bufferedValue;
- this.bufferedValue = value;
- this.firePropertyChanged(VALUE, old, value);
- }
- } else {
- if (ObjectTools.equals(value, this.valueModel.getValue())) {
- // the buffered value is being set to the same value as the original value - ignore
- } else {
- // the buffered value is being set for the first time
- Object old = this.valueModel.getValue();
- this.bufferedValue = value;
- this.buffering = true;
- this.firePropertyChanged(VALUE, old, value);
- }
- }
- }
-
-
- // ********** PropertyValueModelWrapper extensions **********
-
- /**
- * Extend to engage the trigger model also.
- */
- @Override
- protected void engageModel() {
- super.engageModel();
- this.triggerModel.addPropertyChangeListener(VALUE, this.triggerListener);
- }
-
- /**
- * Extend to disengage the trigger model also.
- */
- @Override
- protected void disengageModel() {
- this.triggerModel.removePropertyChangeListener(VALUE, this.triggerListener);
- super.disengageModel();
- }
-
-
- // ********** behavior **********
-
- /**
- * If we are currently "accepting" the value (i.e passing it on to the
- * "wrapped" model), ignore change notifications, since we caused
- * them and our own listeners are already aware of the change.
- */
- @Override
- protected void wrappedValueChanged(PropertyChangeEvent event) {
- if ( ! this.accepting) {
- this.wrappedValueChanged_(event);
- }
- }
-
- /**
- * If we have a "buffered" value, check whether the "wrapped" value has
- * changed to be the same as the "buffered" value. If it has, stop "buffering";
- * if not, do nothing.
- * If we do not yet have a "buffered" value, simply propagate the
- * change notification with the buffered model as the source.
- */
- protected void wrappedValueChanged_(PropertyChangeEvent event) {
- if (this.buffering) {
- if (ObjectTools.equals(event.getNewValue(), this.bufferedValue)) {
- // the buffered value is being set back to the original value
- this.reset();
- } else {
- this.handleChangeConflict(event);
- }
- } else {
- this.firePropertyChanged(event.clone(this));
- }
- }
-
- /**
- * By default, if we have a "buffered" value and the "wrapped" value changes,
- * we simply ignore the new "wrapped" value and simply overlay it with the
- * "buffered" value if it is "accepted". ("Last One In Wins" concurrency model)
- * Subclasses can override this method to change that behavior with a
- * different concurrency model. For example, you could drop the "buffered" value
- * and replace it with the new "wrapped" value, or you could throw an
- * exception.
- */
- protected void handleChangeConflict(@SuppressWarnings("unused") PropertyChangeEvent event) {
- // the default is to do nothing
- }
-
- protected void triggerChanged(PropertyChangeEvent event) {
- this.triggerChanged(((Boolean) event.getNewValue()).booleanValue());
- }
-
- /**
- * The trigger changed:<ul>
- * <li>If it is now <code>true</code>, "accept" the buffered value and push
- * it to the wrapped value model.
- * <li>If it is now <code>false</code>, "reset" the buffered value to its
- * original value.
- * </ul>
- */
- protected void triggerChanged(boolean triggerValue) {
- // if nothing has been "buffered", we don't need to do anything:
- // nothing needs to be passed through; nothing needs to be reset;
- if (this.buffering) {
- if (triggerValue) {
- this.accept();
- } else {
- this.reset();
- }
- }
- }
-
- protected void accept() {
- // set the accepting flag so we ignore any events
- // fired by the wrapped value model
- this.accepting = true;
- try {
- this.getValueModel().setValue(this.bufferedValue);
- } finally {
- this.bufferedValue = null;
- this.buffering = false;
- // clear the flag once the "accept" is complete
- this.accepting = false;
- }
- }
-
- protected void reset() {
- // notify our listeners that our value has been reset
- Object old = this.bufferedValue;
- this.bufferedValue = null;
- this.buffering = false;
- this.firePropertyChanged(VALUE, old, this.valueModel.getValue());
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.getValue());
- }
-
-
- // ********** misc **********
-
- /**
- * Return whether the buffered model is currently "buffering"
- * a value.
- */
- public boolean isBuffering() {
- return this.buffering;
- }
-
- /**
- * Our constructor accepts only a {@link ModifiablePropertyValueModel}{@code<T>}.
- */
- @SuppressWarnings("unchecked")
- protected ModifiablePropertyValueModel<V> getValueModel() {
- return (ModifiablePropertyValueModel<V>) this.valueModel;
- }
-
-
- // ********** trigger **********
-
- /**
- * <code>Trigger</code> is a special property value model that only maintains its
- * value (of <code>true</code> or <code>false</code>) during the change notification caused by
- * {@link #setValue(Object)}. In other words, a <code>Trigger</code>
- * only has a valid value when it is being set.
- */
- public static class Trigger
- extends SimplePropertyValueModel<Boolean>
- {
- /**
- * Construct a trigger with a null value.
- */
- public Trigger() {
- super();
- }
-
-
- // ********** ValueModel implementation **********
-
- /**
- * Extend so that this method can only be invoked during
- * change notification triggered by {@link #setValue(Object)}.
- */
- @Override
- public Boolean getValue() {
- if (this.value == null) {
- throw new IllegalStateException("The method Trigger.getValue() may only be called during change notification."); //$NON-NLS-1$
- }
- return this.value;
- }
-
- /**
- * Extend to reset the value to <code>null</code> once all the
- * listeners have been notified.
- */
- @Override
- public void setValue(Boolean value) {
- super.setValue(value);
- this.value = null;
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Set the trigger's value:<ul>
- * <li><code>true</code> indicates "accept"
- * <li><code>false</code> indicates "reset"
- * </ul>
- */
- public void setValue(boolean value) {
- this.setValue(Boolean.valueOf(value));
- }
-
- /**
- * Return the trigger's value:<ul>
- * <li><code>true</code> indicates "accept"
- * <li><code>false</code> indicates "reset"
- * </ul>
- * This method can only be invoked during change notification.
- */
- public boolean booleanValue() {
- return this.getValue().booleanValue();
- }
-
- /**
- * Accept the trigger (i.e. set its value to <code>true</code>).
- */
- public void accept() {
- this.setValue(true);
- }
-
- /**
- * Return whether the trigger has been accepted
- * (i.e. its value was changed to <code>true</code>).
- * This method can only be invoked during change notification.
- */
- public boolean isAccepted() {
- return this.booleanValue();
- }
-
- /**
- * Reset the trigger (i.e. set its value to <code>false</code>).
- */
- public void reset() {
- this.setValue(false);
- }
-
- /**
- * Return whether the trigger has been reset
- * (i.e. its value was changed to <code>false</code>).
- * This method can only be invoked during change notification.
- */
- public boolean isReset() {
- return ! this.booleanValue();
- }
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java
new file mode 100644
index 0000000000..8ac19c8530
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/BufferedPropertyValueModelAdapter.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 Oracle. 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:
+ * Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.jpt.common.utility.internal.model.value;
+
+import org.eclipse.jpt.common.utility.internal.ListenerList;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.model.ModelTools;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+
+/**
+ * This adapter is used to hold a temporary copy of the value
+ * in another property value model (the <em>wrapped</em> value model). The application
+ * can modify this temporary copy, ad nauseam; but the temporary copy is only
+ * passed through to the <em>wrapped</em> value model when the trigger <em>accepts</em> the
+ * buffered value. Alternatively, the application can <em>reset</em> the buffered value
+ * to the original, <em>wrapped</em> value.
+ * <p>
+ * The trigger is an object that can be used to <em>accept</em> or <em>reset</em>
+ * the buffered value on one or more buffered value models.
+ * <p>
+ * Typically, in a dialog:<ul>
+ * <li>pressing the "OK" button will trigger an <em>accept</em> and close the dialog
+ * <li>pressing the "Cancel" button will simply close the dialog,
+ * dropping the <em>buffered</em> values into the bit bucket
+ * <li>pressing the "Apply" button will trigger an <em>accept</em> and leave the
+ * dialog open
+ * <li>pressing the "Restore" button will trigger a <em>reset</em> and leave the
+ * dialog open
+ * </ul>
+ * As an example: A number of buffered property value models can wrap another set of
+ * property aspect adapters that adapt the various aspects of a single
+ * domain model. All the buffered property value models can be hooked to the
+ * same trigger, and that trigger is controlled by the application, typically
+ * via the "OK" button in a dialog.
+ *
+ * @param <V> the type of the model's value
+ * @see PropertyAspectAdapter
+ */
+public class BufferedPropertyValueModelAdapter<V>
+ implements PluggableModifiablePropertyValueModel.Adapter<V>, PropertyChangeListener
+{
+ /**
+ * The <em>wrapped</em> model.
+ */
+ private final ModifiablePropertyValueModel<V> wrappedValueModel;
+
+ /**
+ * The cached value