Skip to main content
summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorBrian Vosburgh2016-06-22 15:17:49 +0000
committerBrian Vosburgh2017-05-18 22:37:18 +0000
commitc365116e80731e93f6c6e33dbfc0bf859de0fd4e (patch)
tree13fdc8c421d4daa85fdf6f61bdf89587fcdc531e /common
parentc1937f9ef0069ffcffddd8b5860ceb0a3ec2195c (diff)
downloadwebtools.dali-c365116e80731e93f6c6e33dbfc0bf859de0fd4e.tar.gz
webtools.dali-c365116e80731e93f6c6e33dbfc0bf859de0fd4e.tar.xz
webtools.dali-c365116e80731e93f6c6e33dbfc0bf859de0fd4e.zip
rework PropertyValueModel adapters
Diffstat (limited to 'common')
-rw-r--r--common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/properties/JptProjectPropertiesPage.java6
-rw-r--r--common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/AddRemovePane.java22
-rw-r--r--common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java9
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPluggablePropertyValueModel.java239
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModelAdapter.java118
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPluggablePropertyValueModelAdapter.java169
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPropertyValueModelAdapter.java174
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelTools.java342
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelWrapper.java13
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeBooleanPropertyValueModel.java350
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModel.java197
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModelAdapter.java266
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ElementPropertyValueModelAdapter.java131
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/FilteringCollectionValueModel.java43
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCompositePropertyValueModelAdapter.java284
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPluggablePropertyValueModelAdapter.java189
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPropertyValueModelAdapter.java176
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListValueModelTools.java222
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModel.java60
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModelAdapter.java93
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggablePropertyValueModel.java39
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java (renamed from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ValueModelTools.java)30
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java4
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java8
-rw-r--r--common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/model/value/PropertyValueModel.java18
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java220
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionValueModelToolsTests.java438
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeAndBooleanPropertyValueModelTests.java (renamed from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeBooleanPropertyValueModelTests.java)68
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeOrBooleanPropertyValueModelTests.java227
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositePropertyValueModelTests.java144
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoubleModifiablePropertyValueModelTests.java12
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoublePropertyValueModelTests.java4
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/FilteringCollectionValueModelTests.java119
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java8
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCompositePropertyValueModelTests.java304
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListPropertyValueModelAdapterTests.java316
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListValueModelToolsTests.java438
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyValueModelToolsTests.java175
38 files changed, 4263 insertions, 1412 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 373833d6a6..df59dc5316 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 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.
@@ -73,7 +73,7 @@ public abstract class JptProjectPropertiesPage
public JptProjectPropertiesPage() {
super();
- this.projectModel = new SimplePropertyValueModel<IProject>();
+ this.projectModel = new SimplePropertyValueModel<>();
this.trigger = new BufferedModifiablePropertyValueModel.Trigger();
this.buildModels();
@@ -438,7 +438,7 @@ public abstract class JptProjectPropertiesPage
@Override
protected IStatus performValidation() {
- HashMap<Integer, ArrayList<IStatus>> statuses = new HashMap<Integer, ArrayList<IStatus>>();
+ HashMap<Integer, ArrayList<IStatus>> statuses = new HashMap<>();
statuses.put(ERROR_STATUS, new ArrayList<IStatus>());
statuses.put(WARNING_STATUS, new ArrayList<IStatus>());
statuses.put(INFO_STATUS, new ArrayList<IStatus>());
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/AddRemovePane.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/AddRemovePane.java
index c743b4d086..cd88a5a9f9 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/AddRemovePane.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/AddRemovePane.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 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.
@@ -16,7 +16,7 @@ import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable;
import org.eclipse.jpt.common.utility.internal.iterable.EmptyListIterable;
import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
import org.eclipse.jpt.common.utility.internal.iterable.SingleElementIterable;
-import org.eclipse.jpt.common.utility.internal.model.value.CollectionPropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
import org.eclipse.jpt.common.utility.model.Model;
import org.eclipse.jpt.common.utility.model.event.ListAddEvent;
import org.eclipse.jpt.common.utility.model.event.ListChangeEvent;
@@ -753,25 +753,15 @@ public abstract class AddRemovePane<T extends Model, E extends Object> extends P
}
protected PropertyValueModel<Boolean> buildSingleSelectedItemEnabledModel(CollectionValueModel<E> selectedItemsModel) {
- return new CollectionPropertyValueModelAdapter<Boolean, Object>(selectedItemsModel) {
- @Override
- protected Boolean buildValue() {
- return Boolean.valueOf(this.collectionModel.size() == 1);
- }
- };
+ return CollectionValueModelTools.containsSingleElementPropertyValueModel(selectedItemsModel);
}
public PropertyValueModel<Boolean> buildRemoveButtonEnabledModel(CollectionValueModel<E> selectedItemsModel) {
- return this.buildMultipleSelectedItemsEnabledModel(selectedItemsModel);
+ return this.buildOneOrMoreSelectedItemsEnabledModel(selectedItemsModel);
}
- protected PropertyValueModel<Boolean> buildMultipleSelectedItemsEnabledModel(CollectionValueModel<E> selectedItemsModel) {
- return new CollectionPropertyValueModelAdapter<Boolean, E>(selectedItemsModel) {
- @Override
- protected Boolean buildValue() {
- return Boolean.valueOf(this.collectionModel.size() >= 1);
- }
- };
+ protected PropertyValueModel<Boolean> buildOneOrMoreSelectedItemsEnabledModel(CollectionValueModel<E> selectedItemsModel) {
+ return CollectionValueModelTools.isNotEmptyPropertyValueModel(selectedItemsModel);
}
/*
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java
index 93616257cc..f6d95bbaed 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 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.
@@ -27,7 +27,7 @@ import org.eclipse.jpt.common.ui.internal.swt.TriStateCheckBoxModelAdapter;
import org.eclipse.jpt.common.ui.internal.swt.bindings.SWTBindingTools;
import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter;
import org.eclipse.jpt.common.ui.internal.swt.listeners.SWTListenerTools;
-import org.eclipse.jpt.common.utility.internal.model.value.CompositeBooleanPropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.NullCheckPropertyValueModelWrapper;
import org.eclipse.jpt.common.utility.internal.model.value.PredicatePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
@@ -334,11 +334,10 @@ public abstract class Pane<T extends Model> {
* pane is <em>enabled</em> <em>and</em> the pane's model indicates the
* pane should be <em>enabled</em>.
*/
- @SuppressWarnings("unchecked")
private static PropertyValueModel<Boolean> andEnabledModel(Pane<?> pane, PropertyValueModel<Boolean> enabledModel) {
enabledModel = buildNonNullModel(enabledModel);
// NB: we fetch private state from the pane
- return (pane == null) ? enabledModel : CompositeBooleanPropertyValueModel.and(pane.enabledModel, enabledModel);
+ return (pane == null) ? enabledModel : CollectionValueModelTools.and(pane.enabledModel, enabledModel);
}
/**
@@ -351,7 +350,7 @@ public abstract class Pane<T extends Model> {
* (which is typical with aspect adapters etc.).
*/
private static PropertyValueModel<Boolean> buildNonNullModel(PropertyValueModel<Boolean> booleanModel) {
- return new NullCheckPropertyValueModelWrapper<Boolean>(booleanModel, Boolean.FALSE);
+ return new NullCheckPropertyValueModelWrapper<>(booleanModel, Boolean.FALSE);
}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPluggablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPluggablePropertyValueModel.java
new file mode 100644
index 0000000000..7dcf3cc7c9
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPluggablePropertyValueModel.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 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.ObjectTools;
+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 class provides the infrastructure needed to wrap
+ * a model, "lazily" listen to it, and convert
+ * its change notifications into <em>property</em> value model change
+ * notifications.
+ *
+ * @param <V> the type of the model's derived value
+ */
+public abstract class AbstractPluggablePropertyValueModel<V, A extends AbstractPluggablePropertyValueModel.Adapter<V>>
+ extends AbstractModel
+ implements PropertyValueModel<V>
+{
+ /**
+ * Adapter that listens to some model and
+ * calls back whenever that model changes in a way that
+ * affects this model's value.
+ */
+ protected final A adapter;
+
+ /**
+ * Cache the current value so we can pass an "old value" when
+ * we fire a property change event.
+ * We need this because the value may be calculated and we may
+ * not able to derive the "old value" from any fired events.
+ */
+ protected volatile V value;
+
+
+ // ********** constructor/initialization **********
+
+ protected AbstractPluggablePropertyValueModel(Adapter.Factory<V, A> adapterFactory) {
+ super();
+ if (adapterFactory == null) {
+ throw new NullPointerException();
+ }
+ // a bit of instance leakage...
+ this.adapter = adapterFactory.buildAdapter(new AdapterListener());
+ // our value is null when we are not listening to the model
+ this.value = null;
+ }
+
+ @Override
+ protected ChangeSupport buildChangeSupport() {
+ return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE);
+ }
+
+
+ // ********** PropertyValueModel implementation **********
+
+ /**
+ * Return the cached value.
+ */
+ public V getValue() {
+ return this.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);
+ }
+
+ /**
+ * Start listening to the underlying model and build the value.
+ */
+ protected void engageModel() {
+ this.adapter.engageModel();
+ // sync our value *after* we start listening to the model,
+ // since the model's value might change when a listener is added
+ this.value = this.adapter.getValue();
+ }
+
+ /**
+ * Clear the value and stop listening to the underlying model.
+ */
+ private void disengageModel() {
+ // clear out our value when we are not listening to the model
+ this.value = null;
+ this.adapter.disengageModel();
+ }
+
+
+ // ********** Misc **********
+
+ /**
+ * The underlying model changed in some fashion.
+ * Notify our listeners.
+ */
+ /* CU private */ void valueChanged(V newValue) {
+ Object old = this.value;
+ this.firePropertyChanged(VALUE, old, this.value = newValue);
+ }
+
+ @Override
+ public void toString(StringBuilder sb) {
+ sb.append(this.value);
+ }
+
+
+ // ********** Adapter Listener **********
+
+ /**
+ * Simple callback.
+ */
+ /* CU private */ class AdapterListener
+ implements Adapter.Listener<V>
+ {
+ public void valueChanged(V newValue) {
+ AbstractPluggablePropertyValueModel.this.valueChanged(newValue);
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+
+
+ // ********** Adapter interfaces **********
+
+ /**
+ * Minimal methods necessary to adapt some model to {@link PropertyValueModel}.
+ * This adapter is expected to listen to its adapted model and notify the
+ * listener passed to it via its {@link Adapter.Factory factory}
+ * about any model changes.
+ */
+ public interface Adapter<AV> {
+ /**
+ * Return the current property value, as derived from the
+ * current state of the adapted model.
+ */
+ AV getValue();
+
+ /**
+ * Start listening to the adapted model.
+ */
+ void engageModel();
+
+ /**
+ * Stop listening to the adapted model.
+ */
+ void disengageModel();
+
+ /**
+ * Callback interface.
+ */
+ interface Listener<ALV> {
+ /**
+ * Callback to notify listener that the adapted model has changed.
+ */
+ void valueChanged(ALV newValue);
+ }
+
+ /**
+ * Adapter factory interface.
+ * This factory allows both the pluggable property value model and its
+ * adapter to have circular <em>final</em> references to each other.
+ */
+ interface Factory<AFV, A extends Adapter<AFV>> {
+ /**
+ * Create an adapter with the specified listener.
+ */
+ A buildAdapter(Listener<AFV> listener);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModelAdapter.java
deleted file mode 100644
index a77b11b6cf..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008, 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.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a model, "lazily" listen to it, and convert
- * its change notifications into <em>property</em> value model change
- * notifications.
- * <p>
- * Subclasses must implement:<ul>
- * <li>{@link #buildValue()}<p>
- * to return the current property value, as derived from the
- * current state of the underlying model
- * <li>{@link #engageModel_()}<p>
- * to start listening to the underlying (adapted) model
- * <li>{@link #disengageModel_()}<p>
- * to stop listening to the underlying (adapted) model
- * </ul>
- * Subclasses can call {@link #propertyChanged()} whenever the calculated
- * value of the property changes (as determined by the subclass).
- *
- * @param <V> the type of the model's value
- */
-public abstract class AbstractPropertyValueModelAdapter<V>
- extends AbstractPropertyValueModel
- implements PropertyValueModel<V>
-{
- /**
- * Cache the current value so we can pass an "old value" when
- * we fire a property change event.
- * We need this because the value may be calculated and we may
- * not able to derive the "old value" from any fired events.
- */
- protected volatile V value;
-
-
- // ********** constructor/initialization **********
-
- protected AbstractPropertyValueModelAdapter() {
- super();
- // our value is null when we are not listening to the model
- this.value = null;
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- /**
- * Return the cached value.
- */
- public V getValue() {
- return this.value;
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the underlying model and build the value.
- */
- @Override
- protected void engageModel() {
- this.engageModel_();
- // sync our value *after* we start listening to the model,
- // since the model's value might change when a listener is added
- this.value = this.buildValue();
- }
-
- /**
- * Start listening to the underlying model.
- */
- protected abstract void engageModel_();
-
- /**
- * Build and return the current value, as derived from the
- * current state of the underlying model.
- */
- protected abstract V buildValue();
-
- /**
- * Stop listening to the underlying model and clear the value.
- */
- @Override
- protected void disengageModel() {
- this.disengageModel_();
- // clear out our value when we are not listening to the model
- this.value = null;
- }
-
- /**
- * Stop listening to the underlying model.
- */
- protected abstract void disengageModel_();
-
- /**
- * The underlying model changed in some fashion.
- * Recalculate the model's value and notify listeners.
- */
- protected void propertyChanged() {
- Object old = this.value;
- this.firePropertyChanged(VALUE, old, this.value = this.buildValue());
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.value);
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPluggablePropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPluggablePropertyValueModelAdapter.java
new file mode 100644
index 0000000000..4f2c0387c0
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPluggablePropertyValueModelAdapter.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggablePropertyValueModel.Adapter;
+import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener;
+import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * Adapt a {@link CollectionValueModel collection value model} to
+ * a {@link PropertyValueModel property value model}, sorta.
+ * <p>
+ * This adapter is constructed with a {@link CollectionValueModel
+ * collection value model} and a {@link Transformer transformer} that can
+ * transform the collection to a single value.
+ * <p>
+ * This is an adapter that can be plugged into a {@link PluggablePropertyValueModel}.
+ *
+ * @param <E> the type of the adapted collection value model's elements
+ * @param <V> the type of the model's derived value
+ *
+ * @see PluggablePropertyValueModel
+ */
+public final class CollectionPluggablePropertyValueModelAdapter<E, V>
+ implements PluggablePropertyValueModel.Adapter<V>, CollectionChangeListener
+{
+ private final Factory<E, V> factory;
+
+ /** The <em>real</em> adapter. */
+ private final AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener;
+
+ /** Cached copy of model's elements. */
+ private final LinkedList<E> collection;
+
+ /** Protects {@link #collection} from {@link Factory#transformer}. */
+ private final Collection<E> unmodifiableCollection;
+
+ /** The derived value. */
+ private volatile V value;
+
+
+ // ********** constructors **********
+
+ public CollectionPluggablePropertyValueModelAdapter(Factory<E, V> factory, AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.factory = factory;
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ this.collection = new LinkedList<>();
+ this.unmodifiableCollection = Collections.unmodifiableCollection(this.collection);
+ }
+
+
+ // ********** PropertyValueModelAdapter.Adapter **********
+
+ public V getValue() {
+ return this.value;
+ }
+
+ public void engageModel() {
+ this.factory.collectionModel.addCollectionChangeListener(CollectionValueModel.VALUES, this);
+ CollectionTools.addAll(this.collection, this.factory.collectionModel);
+ this.value = this.buildValue();
+ }
+
+ public void disengageModel() {
+ this.value = null;
+ this.collection.clear();
+ this.factory.collectionModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this);
+ }
+
+
+ // ********** CollectionChangeListener **********
+
+ @SuppressWarnings("unchecked")
+ public void itemsAdded(CollectionAddEvent event) {
+ CollectionTools.addAll(this.collection, (Iterable<E>) event.getItems());
+ this.update();
+ }
+
+ public void itemsRemoved(CollectionRemoveEvent event) {
+ CollectionTools.removeAll(this.collection, event.getItems());
+ this.update();
+ }
+
+ public void collectionCleared(CollectionClearEvent event) {
+ this.collection.clear();
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void collectionChanged(CollectionChangeEvent event) {
+ this.collection.clear();
+ CollectionTools.addAll(this.collection, (Iterable<E>) event.getCollection());
+ this.update();
+ }
+
+
+ // ********** misc **********
+
+ private void update() {
+ V newValue = this.buildValue();
+ this.value = newValue;
+ this.listener.valueChanged(newValue);
+ }
+
+ private V buildValue() {
+ return this.factory.transformer.transform(this.unmodifiableCollection);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.value);
+ }
+
+
+ // ********** PluggablePropertyValueModel.Adapter.Factory **********
+
+ public static class Factory<E, V>
+ implements PluggablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final CollectionValueModel<? extends E> collectionModel;
+ /* CU private */ final Transformer<? super Collection<E>, V> transformer;
+
+ public Factory(CollectionValueModel<? extends E> collectionModel, Transformer<? super Collection<E>, V> transformer) {
+ super();
+ if (collectionModel == null) {
+ throw new NullPointerException();
+ }
+ this.collectionModel = collectionModel;
+ if (transformer == null) {
+ throw new NullPointerException();
+ }
+ this.transformer = transformer;
+ }
+
+ public Adapter<V> buildAdapter(AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new CollectionPluggablePropertyValueModelAdapter<>(this, listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPropertyValueModelAdapter.java
deleted file mode 100644
index 1f636e5fd1..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,174 +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.model.event.CollectionAddEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent;
-import org.eclipse.jpt.common.utility.model.listener.CollectionChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a collection value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- * <p>
- * Subclasses must override:<ul>
- * <li>{@link #buildValue()}<p>
- * to return the current property value, as derived from the
- * current collection value
- * </ul>
- * Subclasses might want to override the following methods
- * to improve performance (by not recalculating the value, if possible):<ul>
- * <li>{@link #itemsAdded(CollectionAddEvent event)}
- * <li>{@link #itemsAdded(Iterable)}
- * <li>{@link #itemsRemoved(CollectionRemoveEvent event)}
- * <li>{@link #itemsRemoved(Iterable)}
- * <li>{@link #collectionCleared(CollectionClearEvent event)}
- * <li>{@link #collectionChanged(CollectionChangeEvent event)}
- * </ul>
- *
- * @param <V> the type of the model's value
- * @param <E> the type of the wrapped collection value model's elements
- */
-public abstract class CollectionPropertyValueModelAdapter<V, E>
- extends AbstractPropertyValueModelAdapter<V>
-{
- /** The wrapped collection value model. */
- protected final CollectionValueModel<? extends E> collectionModel;
-
- /** A listener that allows us to sync with changes to the wrapped collection model. */
- protected final CollectionChangeListener collectionListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * collection value model.
- */
- protected CollectionPropertyValueModelAdapter(CollectionValueModel<? extends E> collectionModel) {
- super();
- if (collectionModel == null) {
- throw new NullPointerException();
- }
- this.collectionModel = collectionModel;
- this.collectionListener = this.buildCollectionListener();
- }
-
- protected CollectionChangeListener buildCollectionListener() {
- return new CollectionListener();
- }
-
- /**
- * Straightforward callbacks to the adapter.
- */
- protected class CollectionListener
- extends CollectionChangeAdapter
- {
- @Override
- public void itemsAdded(CollectionAddEvent event) {
- CollectionPropertyValueModelAdapter.this.itemsAdded(event);
- }
- @Override
- public void itemsRemoved(CollectionRemoveEvent event) {
- CollectionPropertyValueModelAdapter.this.itemsRemoved(event);
- }
- @Override
- public void collectionCleared(CollectionClearEvent event) {
- CollectionPropertyValueModelAdapter.this.collectionCleared(event);
- }
- @Override
- public void collectionChanged(CollectionChangeEvent event) {
- CollectionPropertyValueModelAdapter.this.collectionChanged(event);
- }
- }
-
-
- // ********** listener **********
-
- /**
- * Start listening to the collection holder.
- */
- @Override
- protected void engageModel_() {
- this.collectionModel.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionListener);
- }
-
- /**
- * Stop listening to the collection holder.
- */
- @Override
- protected void disengageModel_() {
- this.collectionModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionListener);
- }
-
-
- // ********** collection change support **********
-
- /**
- * Items were added to the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsAdded(CollectionAddEvent event) {
- @SuppressWarnings("unchecked")
- Iterable<E> items = (Iterable<E>) event.getItems();
- this.itemsAdded(items);
- }
-
- /**
- * The specified items were added to the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsAdded(@SuppressWarnings("unused") Iterable<E> items) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were removed from the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsRemoved(CollectionRemoveEvent event) {
- @SuppressWarnings("unchecked")
- Iterable<E> items = (Iterable<E>) event.getItems();
- this.itemsRemoved(items);
- }
-
- /**
- * The specified items were removed from the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsRemoved(@SuppressWarnings("unused") Iterable<E> items) {
- // by default, simply recalculate the value and fire an event if necessary
- this.propertyChanged();
- }
-
- /**
- * The wrapped collection holder was cleared;
- * propagate the change notification appropriately.
- */
- protected void collectionCleared(@SuppressWarnings("unused") CollectionClearEvent event) {
- // by default, simply recalculate the value and fire an event if necessary
- this.propertyChanged();
- }
-
- /**
- * The value of the wrapped collection holder has changed;
- * propagate the change notification appropriately.
- */
- protected void collectionChanged(@SuppressWarnings("unused") CollectionChangeEvent event) {
- // by default, simply recalculate the value and fire an event if necessary
- this.propertyChanged();
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelTools.java
new file mode 100644
index 0000000000..cf3ab7d6ae
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelTools.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.Arrays;
+import java.util.Collection;
+import org.eclipse.jpt.common.utility.closure.Closure;
+import org.eclipse.jpt.common.utility.internal.closure.BooleanClosure;
+import org.eclipse.jpt.common.utility.internal.closure.ClosureTools;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerTools;
+import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.predicate.Predicate;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * {@link CollectionValueModel Collection value model} utility methods.
+ */
+public final class CollectionValueModelTools {
+
+ // ********** composite PVMs **********
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * transformer and property value models.
+ */
+ @SafeVarargs
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(Transformer<? super Collection<E>, V> transformer, PropertyValueModel<? extends E>... propertyValueModels) {
+ return compositePropertyValueModel(Arrays.asList(propertyValueModels), transformer);
+ }
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * property value models and transformer.
+ */
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(Collection<? extends PropertyValueModel<? extends E>> propertyValueModels, Transformer<? super Collection<E>, V> transformer) {
+ return compositePropertyValueModel(new StaticCollectionValueModel<>(propertyValueModels), transformer);
+ }
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * collection value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(CollectionValueModel<? extends PropertyValueModel<? extends E>> collectionModel, Transformer<? super Collection<E>, V> transformer) {
+ return PropertyValueModelTools.propertyValueModel(new CompositePropertyValueModelAdapter.Factory<>(collectionModel, transformer));
+ }
+
+
+ // ********** collection meta data adapters **********
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model.
+ * If the collection is empty, the model's value is <code>null</code>;
+ * otherwise, it is the first element in the collection.
+ */
+ public static <E> PropertyValueModel<E> firstElementPropertyValueModel(CollectionValueModel<? extends E> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionFirstElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model.
+ * If the collection is empty, the model's value is <code>null</code>;
+ * otherwise, it is the last element in the collection.
+ */
+ public static <E> PropertyValueModel<E> lastElementPropertyValueModel(CollectionValueModel<? extends E> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionLastElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model.
+ * If the collection contains <em>only</em> a single element,
+ * the model's value is that element; otherwise,
+ * the model's value is <code>null</code>.
+ */
+ public static <E> PropertyValueModel<E> singleElementPropertyValueModel(CollectionValueModel<? extends E> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionSingleElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model that returns whether the collection is <em>not</em> empty.
+ */
+ public static PropertyValueModel<Boolean> isNotEmptyPropertyValueModel(CollectionValueModel<?> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionIsNotEmptyTransformer());
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * collection value model that returns whether the collection is <em>not</em> empty.
+ * This model can also be used to populate or clear the collection value model.
+ * The specified collection mutator is used to convert the collection value model:
+ * it should populate the collection value model when passed <code>true</code>
+ * and clear the collection value model when passed <code>false</code>.
+ */
+ public static ModifiablePropertyValueModel<Boolean> isNotEmptyModifiablePropertyValueModel(CollectionValueModel<?> collectionModel, BooleanClosure.Adapter collectionMutator) {
+ return booleanModifiablePropertyValueModel(collectionModel, TransformerTools.collectionIsNotEmptyTransformer(), collectionMutator);
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model that returns whether the collection is empty.
+ */
+ public static PropertyValueModel<Boolean> isEmptyPropertyValueModel(CollectionValueModel<?> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionIsEmptyTransformer());
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * collection value model that returns whether the collection is empty.
+ * This model can also be used to populate or clear the collection value model.
+ * The specified collection mutator is used to convert the collection value model:
+ * it should clear the collection value model when passed <code>true</code>
+ * and populate the collection value model when passed <code>false</code>.
+ */
+ public static ModifiablePropertyValueModel<Boolean> isEmptyModifiablePropertyValueModel(CollectionValueModel<?> collectionModel, BooleanClosure.Adapter collectionMutator) {
+ return booleanModifiablePropertyValueModel(collectionModel, TransformerTools.collectionIsEmptyTransformer(), collectionMutator);
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model that returns whether the collection contains
+ * exactly one element.
+ */
+ public static PropertyValueModel<Boolean> containsSingleElementPropertyValueModel(CollectionValueModel<?> collectionModel) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionContainsSingleElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * collection value model that returns whether the collection's size
+ * equals the specified size.
+ */
+ public static PropertyValueModel<Boolean> sizeEqualsPropertyValueModel(CollectionValueModel<?> collectionModel, int size) {
+ return propertyValueModel(collectionModel, TransformerTools.collectionSizeEqualsTransformer(size));
+ }
+
+
+ // ********** boolean PVM adapters **********
+
+ /**
+ * Construct a boolean property value model that is a composite AND of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#TRUE}
+ * if all the contained models' values are {@link Boolean#TRUE},
+ * otherwise its value is {@link Boolean#FALSE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#TRUE}.
+ */
+ @SafeVarargs
+ public static PropertyValueModel<Boolean> and(PropertyValueModel<Boolean>... models) {
+ return compositePropertyValueModel(AND_TRANSFORMER, models);
+ }
+
+ /**
+ * Construct a boolean property value model that is a composite AND of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#TRUE}
+ * if all the contained models' values are {@link Boolean#TRUE},
+ * otherwise its value is {@link Boolean#FALSE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#TRUE}.
+ */
+ public static PropertyValueModel<Boolean> and(Collection<? extends PropertyValueModel<Boolean>> models) {
+ return compositePropertyValueModel(models, AND_TRANSFORMER);
+ }
+
+ /**
+ * Construct a boolean property value model that is a composite AND of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#TRUE}
+ * if all the contained models' values are {@link Boolean#TRUE},
+ * otherwise its value is {@link Boolean#FALSE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#TRUE}.
+ */
+ public static PropertyValueModel<Boolean> and(CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
+ return compositePropertyValueModel(collectionModel, AND_TRANSFORMER);
+ }
+
+ /**
+ * @see AndTransformer
+ */
+ public static final Transformer<Collection<Boolean>, Boolean> AND_TRANSFORMER = new AndTransformer();
+
+ /**
+ * A transformer that transforms a collection of {@link Boolean}s into a single
+ * {@link Boolean} by ANDing them together. Its default value is {@link Boolean#TRUE}.
+ * @see #and(CollectionValueModel)
+ */
+ public static final class AndTransformer
+ extends TransformerAdapter<Collection<Boolean>, Boolean>
+ {
+ @Override
+ public Boolean transform(Collection<Boolean> booleans) {
+ for (Boolean b : booleans) {
+ if ( ! b.booleanValue()) {
+ return Boolean.FALSE;
+ }
+ }
+ return Boolean.TRUE;
+ }
+ }
+
+ /**
+ * Construct a boolean property value model that is a composite OR of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#FALSE}
+ * if all the contained models' values are {@link Boolean#FALSE},
+ * otherwise its value is {@link Boolean#TRUE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#FALSE}.
+ */
+ @SafeVarargs
+ public static PropertyValueModel<Boolean> or(PropertyValueModel<Boolean>... models) {
+ return compositePropertyValueModel(OR_TRANSFORMER, models);
+ }
+
+ /**
+ * Construct a boolean property value model that is a composite OR of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#FALSE}
+ * if all the contained models' values are {@link Boolean#FALSE},
+ * otherwise its value is {@link Boolean#TRUE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#FALSE}.
+ */
+ public static PropertyValueModel<Boolean> or(Collection<? extends PropertyValueModel<Boolean>> models) {
+ return compositePropertyValueModel(models, OR_TRANSFORMER);
+ }
+
+ /**
+ * Construct a boolean property value model that is a composite OR of the
+ * specified boolean property value models; i.e. the model's value is {@link Boolean#FALSE}
+ * if all the contained models' values are {@link Boolean#FALSE},
+ * otherwise its value is {@link Boolean#TRUE}.
+ * The model's default value, when it contains no nested models, is {@link Boolean#FALSE}.
+ */
+ public static PropertyValueModel<Boolean> or(CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
+ return compositePropertyValueModel(collectionModel, OR_TRANSFORMER);
+ }
+
+ /**
+ * @see OrTransformer
+ */
+ public static final Transformer<Collection<Boolean>, Boolean> OR_TRANSFORMER = new OrTransformer();
+
+ /**
+ * A transformer that transforms a collection of {@link Boolean}s into a single
+ * {@link Boolean} by ORing them together. Its default value is {@link Boolean#FALSE}.
+ * @see #or(CollectionValueModel)
+ */
+ public static final class OrTransformer
+ extends TransformerAdapter<Collection<Boolean>, Boolean>
+ {
+ @Override
+ public Boolean transform(Collection<Boolean> booleans) {
+ for (Boolean b : booleans) {
+ if (b.booleanValue()) {
+ return Boolean.TRUE;
+ }
+ }
+ return Boolean.FALSE;
+ }
+ }
+
+
+ // ********** PVM adapters **********
+
+ /**
+ * Construct a boolean property value model adapter for the specified
+ * collection value model and predicate. The returned model will indicate whether
+ * the collection belongs to the set defined by the predicate.
+ */
+ public static PropertyValueModel<Boolean> booleanPropertyValueModel(CollectionValueModel<?> collectionModel, Predicate<? super Collection<?>> predicate) {
+ return propertyValueModel(collectionModel, TransformerTools.adapt(predicate));
+ }
+
+
+ /**
+ * Construct a property value model adapted to the specified
+ * collection value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PropertyValueModel<V> propertyValueModel(CollectionValueModel<? extends E> collectionModel, Transformer<? super Collection<E>, V> transformer) {
+ return PropertyValueModelTools.propertyValueModel(pluggablePropertyValueModelAdapterFactory(collectionModel, transformer));
+ }
+
+ /**
+ * Construct a pluggable property value model adapter factory for the specified
+ * collection value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PluggablePropertyValueModel.Adapter.Factory<V> pluggablePropertyValueModelAdapterFactory(CollectionValueModel<? extends E> collectionModel, Transformer<? super Collection<E>, V> transformer) {
+ return new CollectionPluggablePropertyValueModelAdapter.Factory<>(collectionModel, transformer);
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapted to the specified
+ * collection value model that returns whether the collection belongs to the set defined
+ * by the specified predicate.
+ * This model will use the specified collection mutator to modify the collection value model.
+ */
+ public static ModifiablePropertyValueModel<Boolean> booleanModifiablePropertyValueModel(CollectionValueModel<?> collectionModel, Predicate<? super Collection<?>> predicate, BooleanClosure.Adapter collectionMutator) {
+ return booleanModifiablePropertyValueModel(collectionModel, TransformerTools.adapt(predicate), collectionMutator);
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * collection value model that returns whether the collection belongs to the set defined
+ * by the specified transformer.
+ * This model will use the specified collection mutator to modify the collection value model.
+ */
+ public static ModifiablePropertyValueModel<Boolean> booleanModifiablePropertyValueModel(CollectionValueModel<?> collectionModel, Transformer<? super Collection<?>, Boolean> transformer, BooleanClosure.Adapter collectionMutator) {
+ PluggablePropertyValueModel.Adapter.Factory<Boolean> factory = pluggablePropertyValueModelAdapterFactory(collectionModel, transformer);
+ Closure<Boolean> closure = ClosureTools.booleanClosure(collectionMutator);
+ return PropertyValueModelTools.pluggableModifiablePropertyValueModel(factory, closure);
+ }
+
+
+ // ********** filtering **********
+
+ /**
+ * Construct a collection value model with the specified wrapped collection value model and filter.
+ */
+ public static <E> CollectionValueModel<E> filter(CollectionValueModel<? extends E> collectionModel, Predicate<E> filter) {
+ return new FilteringCollectionValueModel<>(collectionModel, filter);
+ }
+
+
+ // ********** suppressed constructor **********
+
+ /**
+ * Suppress default constructor, ensuring non-instantiability.
+ */
+ private CollectionValueModelTools() {
+ super();
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelWrapper.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelWrapper.java
index 4d36f09f93..377d290b57 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelWrapper.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CollectionValueModelWrapper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * 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.
@@ -21,6 +21,17 @@ import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
* another collection value model, "lazily" listen to it, and propagate
* its change notifications. Subclasses must implement the appropriate
* {@link CollectionValueModel}.
+ * <p>
+ * Subclasses must implement the following methods:<ul>
+ * <li>{@link #itemsAdded(CollectionAddEvent)}<p>
+ * implement this method to handle added items
+ * <li>{@link #itemsRemoved(CollectionRemoveEvent)}<p>
+ * implement this method to handle removed items
+ * <li>{@link #collectionCleared(CollectionClearEvent)}<p>
+ * implement this method to handle cleared collection
+ * <li>{@link #collectionChanged(CollectionChangeEvent)}<p>
+ * implement this method to handle changed collection
+ * </ul>
*
* @param <E> the type of elements held by the model
*/
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeBooleanPropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeBooleanPropertyValueModel.java
deleted file mode 100644
index e032203172..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeBooleanPropertyValueModel.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2010, 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 java.util.Collection;
-import org.eclipse.jpt.common.utility.internal.iterable.TransformationIterable;
-import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.common.utility.transformer.Transformer;
-
-/**
- * A <code>CompositeBooleanPropertyValueModel</code> adapts a
- * {@link CollectionValueModel} holding boolean {@link PropertyValueModel}s
- * to a single boolean {@link PropertyValueModel}. The composite value is
- * determined by the {@link CompositeBooleanPropertyValueModel.Adapter} provided
- * at construction. Typically the composite will be either an AND or an OR of
- * all the boolean values.
- * <p>
- * If there are <em>no</em> boolean {@link PropertyValueModel}s, the composite
- * will return its default value; which, by default, is <code>null</code>.
- * <p>
- * <strong>NB:</strong> None of the wrapped boolean models can return a
- * <code>null</code> value or this class will throw an exception. The assumption
- * is that all the wrapped boolean models are configured with "default" values
- * that determine the model's value (TRUE or FALSE) when <code>null</code>.
- */
-public class CompositeBooleanPropertyValueModel
- extends CompositePropertyValueModel<Boolean, Boolean>
-{
- /**
- * Calculation of the model's value is delegated to this adapter.
- */
- protected final Adapter adapter;
-
- /**
- * The default setting for the composite boolean property value model;
- * for when the underlying collection model is empty.
- * The default [default value] is <code>null</code>.
- */
- private final Boolean defaultValue;
-
-
- // ********** AND factory methods **********
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static CompositeBooleanPropertyValueModel and(PropertyValueModel<Boolean>... array) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, array);
- }
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static CompositeBooleanPropertyValueModel and(Boolean defaultValue, PropertyValueModel<Boolean>... array) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, defaultValue, array);
- }
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel and(Collection<E> collection) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, collection);
- }
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel and(Boolean defaultValue, Collection<E> collection) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, defaultValue, collection);
- }
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static CompositeBooleanPropertyValueModel and(CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, collectionModel);
- }
-
- /**
- * Construct a boolean property value model that is a composite AND of the
- * specified boolean property value models; i.e. the model's value is true
- * if all the contained models are true, otherwise its value is false.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static CompositeBooleanPropertyValueModel and(Boolean defaultValue, CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- return new CompositeBooleanPropertyValueModel(AND_ADAPTER, defaultValue, collectionModel);
- }
-
-
- // ********** OR factory methods **********
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static CompositeBooleanPropertyValueModel or(PropertyValueModel<Boolean>... array) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, array);
- }
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static CompositeBooleanPropertyValueModel or(Boolean defaultValue, PropertyValueModel<Boolean>... array) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, defaultValue, array);
- }
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel or(Collection<E> collection) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, collection);
- }
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel or(Boolean defaultValue, Collection<E> collection) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, defaultValue, collection);
- }
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public static CompositeBooleanPropertyValueModel or(CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, collectionModel);
- }
-
- /**
- * Construct a boolean property value model that is a composite OR of the
- * specified boolean property value models; i.e. the model's value is false
- * if all the contained models are false, otherwise its value is true.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public static CompositeBooleanPropertyValueModel or(Boolean defaultValue, CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- return new CompositeBooleanPropertyValueModel(OR_ADAPTER, defaultValue, collectionModel);
- }
-
-
- // ********** constructors **********
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public CompositeBooleanPropertyValueModel(Adapter adapter, PropertyValueModel<Boolean>... array) {
- this(adapter, null, array);
- }
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public CompositeBooleanPropertyValueModel(Adapter adapter, Boolean defaultValue, PropertyValueModel<Boolean>... array) {
- super(array);
- if (adapter == null) {
- throw new NullPointerException();
- }
- this.adapter = adapter;
- this.defaultValue = defaultValue;
- }
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel(Adapter adapter, Collection<E> collection) {
- this(adapter, null, collection);
- }
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public <E extends PropertyValueModel<Boolean>> CompositeBooleanPropertyValueModel(Adapter adapter, Boolean defaultValue, Collection<E> collection) {
- super(collection);
- if (adapter == null) {
- throw new NullPointerException();
- }
- this.adapter = adapter;
- this.defaultValue = defaultValue;
- }
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * The model's default value, when it contains no nested models, is
- * <code>null</code>.
- */
- public CompositeBooleanPropertyValueModel(Adapter adapter, CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- this(adapter, null, collectionModel);
- }
-
- /**
- * Construct a boolean property value model that is a composite of the specified
- * boolean property value models, as defined by the specified adapter.
- * When the model contains no nested models, its value will be the
- * specified default.
- */
- public CompositeBooleanPropertyValueModel(Adapter adapter, Boolean defaultValue, CollectionValueModel<? extends PropertyValueModel<Boolean>> collectionModel) {
- super(collectionModel);
- if (adapter == null) {
- throw new NullPointerException();
- }
- this.adapter = adapter;
- this.defaultValue = defaultValue;
- }
-
-
- // ********** implementation **********
-
- /**
- * Return the {@link #defaultValue} if the collection is empty;
- * otherwise delegate to the {@link #adapter}.
- */
- @Override
- protected Boolean buildValue() {
- return (this.collectionModel.size() == 0) ? this.defaultValue : this.buildValue_();
- }
-
- protected Boolean buildValue_() {
- return this.adapter.buildValue(this.getBooleans());
- }
-
- protected Iterable<Boolean> getBooleans() {
- return new TransformationIterable<PropertyValueModel<? extends Boolean>, Boolean>(this.collectionModel, BOOLEAN_TRANSFORMER);
- }
-
- protected static final Transformer<PropertyValueModel<? extends Boolean>, Boolean> BOOLEAN_TRANSFORMER = new BooleanTransformer();
- protected static class BooleanTransformer
- implements Transformer<PropertyValueModel<? extends Boolean>, Boolean>
- {
- public Boolean transform(PropertyValueModel<? extends Boolean> booleanModel) {
- return booleanModel.getValue();
- }
- @Override
- public String toString() {
- return this.getClass().getSimpleName();
- }
- }
-
-
- // ********** adapter **********
-
- /**
- * This adapter allows the {@link CompositeBooleanPropertyValueModel} to be
- * pluggable.
- */
- public interface Adapter {
- /**
- * Return the composite boolean value of the specified collection
- * of booleans.
- */
- Boolean buildValue(Iterable<Boolean> booleans);
- }
-
- /**
- * Return <code>true</code> if all the booleans are <code>true</code>;
- * otherwise return <code>false</code>.
- */
- public static final Adapter AND_ADAPTER = new Adapter() {
- public Boolean buildValue(Iterable<Boolean> booleans) {
- for (Boolean b : booleans) {
- if ( ! b.booleanValue()) {
- return Boolean.FALSE;
- }
- }
- return Boolean.TRUE;
- }
- @Override
- public String toString() {
- return "AND_ADAPTER"; //$NON-NLS-1$
- }
- };
-
- /**
- * Return <code>false</code> if all the booleans are <code>false</code>;
- * otherwise return <code>true</code>.
- */
- public static final Adapter OR_ADAPTER = new Adapter() {
- public Boolean buildValue(Iterable<Boolean> booleans) {
- for (Boolean b : booleans) {
- if (b.booleanValue()) {
- return Boolean.TRUE;
- }
- }
- return Boolean.FALSE;
- }
- @Override
- public String toString() {
- return "OR_ADAPTER"; //$NON-NLS-1$
- }
- };
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModel.java
deleted file mode 100644
index 796c53b7d6..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModel.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import org.eclipse.jpt.common.utility.internal.collection.IdentityHashBag;
-import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent;
-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.CollectionValueModel;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-
-/**
- * A <code>CompositePropertyValueModel</code> adapts a
- * {@link CollectionValueModel} holding other {@link PropertyValueModel}s
- * to a single {@link PropertyValueModel}.
- * <p>
- * Subclasses must implement:<ul>
- * <li>{@link #buildValue()}<p>
- * to return the current property value, as derived from the
- * component values
- * </ul>
- * <strong>NB:</strong> The wrapped collection must not contain any duplicates
- * or this class will throw an exception.
- *
- * @param <V> the type of the model's value
- * @param <E> the type of the wrapped collection value model's
- * property value model's values
- */
-public abstract class CompositePropertyValueModel<V, E>
- extends CollectionPropertyValueModelAdapter<V, PropertyValueModel<? extends E>>
-{
- /**
- * Cache the component property value models so we can stop listening to
- * them when they are removed from the collection value model.
- */
- protected final IdentityHashBag<PropertyValueModel<? extends E>> componentPVMs =
- new IdentityHashBag<PropertyValueModel<? extends E>>();
-
- /**
- * Listen to every property value model in the collection value model.
- * If one changes, we need to re-calculate our value.
- */
- protected final PropertyChangeListener componentListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a property value model that is a composite of the specified
- * property value models.
- */
- public CompositePropertyValueModel(PropertyValueModel<? extends E>... collection) {
- this(Arrays.asList(collection));
- }
-
- /**
- * Construct a property value model that is a composite of the specified
- * property value models.
- */
- public <P extends PropertyValueModel<? extends E>> CompositePropertyValueModel(Collection<? extends P> collection) {
- this(new StaticCollectionValueModel<P>(collection));
- }
-
- /**
- * Construct a property value model that is a composite of the specified
- * property value models.
- */
- public <P extends PropertyValueModel<? extends E>> CompositePropertyValueModel(CollectionValueModel<P> collectionModel) {
- super(collectionModel);
- this.componentListener = this.buildComponentListener();
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildComponentListener() {
- return new ComponentListener();
- }
-
- protected class ComponentListener
- extends PropertyChangeAdapter
- {
- @Override
- public void propertyChanged(PropertyChangeEvent event) {
- CompositePropertyValueModel.this.componentChanged(event);
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Subclasses can override this method if the event can be used to improve
- * the performance of building a new value (e.g. some property changes may
- * not necessitate the re-calculation of the value).
- */
- protected void componentChanged(@SuppressWarnings("unused") PropertyChangeEvent event) {
- this.propertyChanged();
- }
-
-
- // ********** CollectionPropertyValueModelAdapter overrides **********
-
- @Override
- protected void engageModel_() {
- super.engageModel_();
- this.addComponentPVMs(this.collectionModel);
- }
-
- protected <P extends PropertyValueModel<? extends E>> void addComponentPVMs(Iterable<P> pvms) {
- for (P each : pvms) {
- this.componentPVMs.add(each);
- each.addPropertyChangeListener(VALUE, this.componentListener);
- }
- }
-
- @Override
- protected void disengageModel_() {
- this.removeComponentPVMs(this.collectionModel);
- super.disengageModel_();
- }
-
- protected <P extends PropertyValueModel<? extends E>> void removeComponentPVMs(Iterable<P> pvms) {
- for (P each : pvms) {
- each.removePropertyChangeListener(VALUE, this.componentListener);
- this.componentPVMs.remove(each);
- }
- }
-
- @Override
- protected void itemsAdded(CollectionAddEvent event) {
- this.addComponentPVMs(this.getItems(event));
- super.itemsAdded(event);
- }
-
- @Override
- protected void itemsRemoved(CollectionRemoveEvent event) {
- this.removeComponentPVMs(this.getItems(event));
- super.itemsRemoved(event);
- }
-
- @Override
- protected void collectionCleared(CollectionClearEvent event) {
- this.removeAllComponentPVMs();
- super.collectionCleared(event);
- }
-
- protected void removeAllComponentPVMs() {
- // copy the list so we don't eat our own tail
- ArrayList<PropertyValueModel<? extends E>> copy = new ArrayList<PropertyValueModel<? extends E>>(this.componentPVMs);
- this.removeComponentPVMs(copy);
- }
-
- @Override
- protected void collectionChanged(CollectionChangeEvent event) {
- this.removeAllComponentPVMs();
- this.addComponentPVMs(this.collectionModel);
- super.collectionChanged(event);
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Our constructor accepts only a
- * {@link CollectionValueModel}{@code<? extends }{@link PropertyValueModel}{@code<? extends E>>}.
- */
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected Iterable<? extends PropertyValueModel<? extends E>> getItems(CollectionAddEvent event) {
- return (Iterable<? extends PropertyValueModel<? extends E>>) event.getItems();
- }
-
- /**
- * Our constructor accepts only a
- * {@link CollectionValueModel}{@code<? extends }{@link PropertyValueModel}{@code<? extends E>>}.
- */
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected Iterable<? extends PropertyValueModel<? extends E>> getItems(CollectionRemoveEvent event) {
- return (Iterable<? extends PropertyValueModel<? extends E>>) event.getItems();
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModelAdapter.java
new file mode 100644
index 0000000000..3ae453b06d
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositePropertyValueModelAdapter.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.collection.ListTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggablePropertyValueModel.Adapter;
+import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
+import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener;
+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.CollectionValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * Adapt a {@link CollectionValueModel collection value model} holding
+ * {@link PropertyValueModel property value models}
+ * to a single {@link PropertyValueModel property value model}, sorta.
+ * <p>
+ * This adapter is constructed with a {@link CollectionValueModel
+ * collection value model} and a {@link Transformer transformer} that can
+ * transform the collection's property value models' values to a single value.
+ * <p>
+ * This is an adapter that can be plugged into a {@link PluggablePropertyValueModel}.
+ * <p>
+ * <strong>NB:</strong> The wrapped collection value model must not contain any
+ * <code>null</code>s or duplicate property value models.
+ *
+ * @param <E> the type of the adapted collection value model's
+ * property value models' values
+ * @param <V> the type of the model's derived value
+ *
+ * @see PluggablePropertyValueModel
+ * @see CollectionPluggablePropertyValueModelAdapter
+ */
+public final class CompositePropertyValueModelAdapter<E, V>
+ implements PluggablePropertyValueModel.Adapter<V>, CollectionChangeListener
+{
+ private final Factory<E, V> factory;
+
+ /**
+ * The <em>real</em> adapter, passed to us as a listener.
+ */
+ private final AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener;
+
+ /**
+ * Listen to every property value model in the collection value model.
+ * If one changes, we need to re-calculate {@link #value}
+ * and notify @{link #listener}.
+ */
+ private final PropertyChangeListener componentListener;
+
+ /**
+ * Cached copy of {@link Factory#collectionModel}'s elements
+ * and their values.
+ */
+ private final IdentityHashMap<PropertyValueModel<? extends E>, E> values;
+
+ /**
+ * Protects {@link #values} from {@link Factory#transformer}.
+ */
+ private final Collection<E> unmodifiableValues;
+
+ /**
+ * The derived value.
+ */
+ private volatile V value;
+
+
+ // ********** constructor **********
+
+ public CompositePropertyValueModelAdapter(Factory<E, V> factory, AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.factory = factory;
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ this.componentListener = this.buildComponentListener();
+ this.values = new IdentityHashMap<>();
+ this.unmodifiableValues = Collections.unmodifiableCollection(this.values.values());
+ }
+
+
+ // ********** PropertyValueModelAdapter.Adapter **********
+
+ public V getValue() {
+ return this.value;
+ }
+
+ public void engageModel() {
+ this.factory.collectionModel.addCollectionChangeListener(CollectionValueModel.VALUES, this);
+ this.addComponentPVMs(this.factory.collectionModel);
+ this.value = this.buildValue();
+ }
+
+ public void disengageModel() {
+ this.value = null;
+ this.removeComponentPVMs(this.factory.collectionModel);
+ if ( ! this.values.isEmpty()) {
+ throw new IllegalStateException("extraneous values: " + this.values); //$NON-NLS-1$
+ }
+ this.factory.collectionModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this);
+ }
+
+
+ // ********** CollectionChangeListener **********
+
+ @SuppressWarnings("unchecked")
+ public void itemsAdded(CollectionAddEvent event) {
+ this.addComponentPVMs((Iterable<? extends PropertyValueModel<? extends E>>) event.getItems());
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void itemsRemoved(CollectionRemoveEvent event) {
+ this.removeComponentPVMs((Iterable<? extends PropertyValueModel<? extends E>>) event.getItems());
+ this.update();
+ }
+
+ public void collectionCleared(CollectionClearEvent event) {
+ this.removeCachedPVMs();
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void collectionChanged(CollectionChangeEvent event) {
+ this.removeCachedPVMs();
+ this.addComponentPVMs((Iterable<? extends PropertyValueModel<? extends E>>) event.getCollection());
+ this.update();
+ }
+
+
+ // ********** add/remove component PVMs **********
+
+ private void addComponentPVMs(Iterable<? extends PropertyValueModel<? extends E>> pvms) {
+ for (PropertyValueModel<? extends E> pvm : pvms) {
+ this.addComponentPVM(pvm);
+ }
+ }
+
+ private void addComponentPVM(PropertyValueModel<? extends E> pvm) {
+ if (pvm == null) {
+ throw new NullPointerException();
+ }
+ if (this.values.containsKey(pvm)) {
+ throw new IllegalStateException("duplicate component: " + pvm); //$NON-NLS-1$
+ }
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, this.componentListener);
+ this.values.put(pvm, pvm.getValue());
+ }
+
+ private void removeCachedPVMs() {
+ // copy the list so we don't eat our own tail
+ ArrayList<PropertyValueModel<? extends E>> copy = ListTools.arrayList(this.values.keySet());
+ this.removeComponentPVMs(copy);
+ }
+
+ private void removeComponentPVMs(Iterable<? extends PropertyValueModel<? extends E>> pvms) {
+ for (PropertyValueModel<? extends E> pvm : pvms) {
+ this.removeComponentPVM(pvm);
+ }
+ }
+
+ private void removeComponentPVM(PropertyValueModel<? extends E> pvm) {
+ if ( ! this.values.containsKey(pvm)) {
+ throw new IllegalStateException("missing component: " + pvm); //$NON-NLS-1$
+ }
+ this.values.remove(pvm);
+ pvm.removePropertyChangeListener(PropertyValueModel.VALUE, this.componentListener);
+ }
+
+
+ // ********** misc **********
+
+ private void update() {
+ this.listener.valueChanged(this.value = this.buildValue());
+ }
+
+ private V buildValue() {
+ return this.factory.transformer.transform(this.unmodifiableValues);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.value);
+ }
+
+
+ // ********** component listener **********
+
+ private PropertyChangeListener buildComponentListener() {
+ return new ComponentListener();
+ }
+
+ /* CU private */ class ComponentListener
+ extends PropertyChangeAdapter
+ {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ CompositePropertyValueModelAdapter.this.componentChanged(event);
+ }
+ }
+
+ /* CU private */ void componentChanged(PropertyChangeEvent event) {
+ @SuppressWarnings("unchecked")
+ PropertyValueModel<? extends E> source = (PropertyValueModel<? extends E>) event.getSource();
+ if ( ! this.values.containsKey(source)) {
+ throw new IllegalStateException("invalid component: " + source); //$NON-NLS-1$
+ }
+ @SuppressWarnings("unchecked")
+ E newValue = (E) event.getNewValue();
+ this.values.put(source, newValue);
+ this.update();
+ }
+
+
+ // ********** PluggablePropertyValueModel.Adapter.Factory **********
+
+ public static class Factory<E, V>
+ implements PluggablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final CollectionValueModel<? extends PropertyValueModel<? extends E>> collectionModel;
+ /* CU private */ final Transformer<? super Collection<E>, V> transformer;
+
+ public Factory(CollectionValueModel<? extends PropertyValueModel<? extends E>> collectionModel, Transformer<? super Collection<E>, V> transformer) {
+ super();
+ if (collectionModel == null) {
+ throw new NullPointerException();
+ }
+ this.collectionModel = collectionModel;
+ if (transformer == null) {
+ throw new NullPointerException();
+ }
+ this.transformer = transformer;
+ }
+
+ public Adapter<V> buildAdapter(AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new CompositePropertyValueModelAdapter<>(this, listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ElementPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ElementPropertyValueModelAdapter.java
deleted file mode 100644
index 8cc9d6f8ae..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ElementPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2011, 2013 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.CollectionChangeEvent;
-import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
-import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.common.utility.predicate.Predicate;
-
-/**
- * Adapt an element in a collection value model to a property value model.
- * The property model's value is determined by whether the collection model
- * contains the value: If the collection model contains the value,
- * the property model's value is <em>that</em> element; otherwise, the property
- * model's value is <code>null</code>. A {@link #predicate} is used to determine
- * whether the collection model contains the relevant value.
- * <p>
- * This is useful for a client (e.g. a UI widget) that is longer-living than its
- * underlying model. Obviously, the client must be prepared to handle a value of
- * <code>null</code>.
- *
- * @param <V> the type of the both the model's value and
- * the wrapped collection value model's elements
- */
-public class ElementPropertyValueModelAdapter<V>
- extends CollectionPropertyValueModelAdapter<V, V>
-{
- /**
- * A predicate used to determine whether an element in the wrapped
- * collection model is the model's value.
- */
- protected final Predicate<V> predicate;
-
-
- /**
- * Construct a property value model whose value depends on whether the
- * specified collection value model contains the value. The specified
- * filter is used to determine whether an element in the specified
- * collection model is the property value.
- */
- public ElementPropertyValueModelAdapter(CollectionValueModel<? extends V> collectionModel, Predicate<V> predicate) {
- super(collectionModel);
- if (predicate == null) {
- throw new NullPointerException();
- }
- this.predicate = predicate;
- }
-
- /**
- * If the collection model contains the property model's {@link #value},
- * return that element; otherwise return <code>null</code>.
- */
- @Override
- protected V buildValue() {
- for (V each : this.collectionModel) {
- if (this.predicate.evaluate(each)) {
- return each;
- }
- }
- return null;
- }
-
- /**
- * Check whether the wrapped collection model now contains the
- * {@link #value}.
- */
- @Override
- protected void itemsAdded(Iterable<V> items) {
- if (this.value == null) {
- this.itemsAdded_(items);
- }
- }
-
- protected void itemsAdded_(Iterable<V> items) {
- for (V each : items) {
- if (this.predicate.evaluate(each)) {
- this.firePropertyChanged(VALUE, null, this.value = each);
- return;
- }
- }
- }
-
- /**
- * Check whether the wrapped collection model no longer contains the
- * {@link #value}.
- */
- @Override
- protected void itemsRemoved(Iterable<V> items) {
- if (this.value != null) {
- this.itemsRemoved_(items);
- }
- }
-
- protected void itemsRemoved_(Iterable<V> items) {
- for (V each : items) {
- if (ObjectTools.equals(each, this.value)) {
- V old = this.value;
- this.firePropertyChanged(VALUE, old, this.value = null);
- return;
- }
- }
- }
-
- /**
- * The {@link #value} must now be <code>null</code>.
- */
- @Override
- protected void collectionCleared(CollectionClearEvent event) {
- if (this.value != null) {
- V old = this.value;
- this.firePropertyChanged(VALUE, old, this.value = null);
- }
- }
-
- /**
- * Re-calculate the {@link #value}.
- */
- @Override
- protected void collectionChanged(CollectionChangeEvent event) {
- V old = this.value;
- this.firePropertyChanged(VALUE, old, this.value = this.buildValue());
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/FilteringCollectionValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/FilteringCollectionValueModel.java
index ca51df9aae..95bf6e8abd 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/FilteringCollectionValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/FilteringCollectionValueModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * 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.
@@ -9,18 +9,16 @@
******************************************************************************/
package org.eclipse.jpt.common.utility.internal.model.value;
-import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.collection.HashBag;
import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
-import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent;
import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent;
import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent;
import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent;
import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.common.utility.model.value.ListValueModel;
import org.eclipse.jpt.common.utility.predicate.Predicate;
/**
@@ -48,25 +46,17 @@ public class FilteringCollectionValueModel<E>
extends CollectionValueModelWrapper<E>
implements CollectionValueModel<E>
{
- /** This filters the items in the nested collection. */
- private Predicate<E> filter;
+ /** This filters the items in the wrapped collection. */
+ private volatile Predicate<E> filter;
/** Cache the items that were accepted by the filter */
- private final ArrayList<E> filteredItems = new ArrayList<E>();
+ private final HashBag<E> filteredItems = new HashBag<>();
// ********** constructors **********
/**
* Construct a collection value model with the specified wrapped
- * collection value model and a filter that simply accepts every object.
- */
- public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionModel) {
- this(collectionModel, PredicateTools.<E>true_());
- }
-
- /**
- * Construct a collection value model with the specified wrapped
* collection value model and filter.
*/
public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionModel, Predicate<E> filter) {
@@ -77,22 +67,6 @@ public class FilteringCollectionValueModel<E>
this.filter = filter;
}
- /**
- * Construct a collection value model with the specified wrapped
- * list value model and a filter that simply accepts every object.
- */
- public FilteringCollectionValueModel(ListValueModel<? extends E> listModel) {
- this(new ListCollectionValueModelAdapter<E>(listModel));
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * list value model and filter.
- */
- public FilteringCollectionValueModel(ListValueModel<? extends E> listModel, Predicate<E> filter) {
- this(new ListCollectionValueModelAdapter<E>(listModel), filter);
- }
-
// ********** CollectionValueModel implementation **********
@@ -150,6 +124,13 @@ public class FilteringCollectionValueModel<E>
// ********** miscellaneous **********
/**
+ * Return the current filter.
+ */
+ public Predicate<E> getFilter() {
+ return this.filter;
+ }
+
+ /**
* Change the filter and rebuild the collection.
*/
public void setFilter(Predicate<E> filter) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCompositePropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCompositePropertyValueModelAdapter.java
new file mode 100644
index 0000000000..48804c2f1c
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCompositePropertyValueModelAdapter.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.jpt.common.utility.Association;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.SimpleAssociation;
+import org.eclipse.jpt.common.utility.internal.collection.ListTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggablePropertyValueModel.Adapter;
+import org.eclipse.jpt.common.utility.model.event.ListAddEvent;
+import org.eclipse.jpt.common.utility.model.event.ListChangeEvent;
+import org.eclipse.jpt.common.utility.model.event.ListClearEvent;
+import org.eclipse.jpt.common.utility.model.event.ListMoveEvent;
+import org.eclipse.jpt.common.utility.model.event.ListRemoveEvent;
+import org.eclipse.jpt.common.utility.model.event.ListReplaceEvent;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.ListChangeListener;
+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.ListValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * Adapt a {@link ListValueModel list value model} holding
+ * {@link PropertyValueModel property value models}
+ * to a single {@link PropertyValueModel property value model}, sorta.
+ * <p>
+ * This adapter is constructed with a {@link ListValueModel
+ * list value model} and a {@link Transformer transformer} that can
+ * transform the list's property value models' values to a single value.
+ * <p>
+ * This is an adapter that can be plugged into a {@link PluggablePropertyValueModel}.
+ * <p>
+ * <strong>NB:</strong> The wrapped list value model must not contain any
+ * <code>null</code>s or duplicate property value models.
+ *
+ * @param <E> the type of the adapted list value model's
+ * property value models' values
+ * @param <V> the type of the model's derived value
+ *
+ * @see PluggablePropertyValueModel
+ * @see ListPluggablePropertyValueModelAdapter
+ */
+public final class ListCompositePropertyValueModelAdapter<E, V>
+ implements PluggablePropertyValueModel.Adapter<V>, ListChangeListener
+{
+ private final Factory<E, V> factory;
+
+ /**
+ * The <em>real</em> adapter, passed to us as a listener.
+ */
+ private final AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener;
+
+ /**
+ * Listen to every property value model in the list value model.
+ * If one changes, we need to re-calculate {@link #value}
+ * and notify @{link #listener}.
+ */
+ private final PropertyChangeListener componentListener;
+
+ /**
+ * Cached copy of {@link Factory#listModel}'s elements' values.
+ */
+ private final ArrayList<SimpleAssociation<PropertyValueModel<? extends E>, E>> values;
+
+ /**
+ * The derived value.
+ */
+ private volatile V value;
+
+
+ // ********** constructor **********
+
+ public ListCompositePropertyValueModelAdapter(Factory<E, V> factory, AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.factory = factory;
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ this.componentListener = this.buildComponentListener();
+ this.values = new ArrayList<>();
+ }
+
+
+ // ********** PropertyValueModelAdapter.Adapter **********
+
+ public V getValue() {
+ return this.value;
+ }
+
+ public void engageModel() {
+ this.factory.listModel.addListChangeListener(ListValueModel.LIST_VALUES, this);
+ this.addComponentPVMs(0, this.factory.listModel);
+ this.value = this.buildValue();
+ }
+
+ public void disengageModel() {
+ this.value = null;
+ this.removeComponentPVMs(0, this.factory.listModel.size(), this.factory.listModel);
+ if ( ! this.values.isEmpty()) {
+ throw new IllegalStateException("extraneous values: " + this.values); //$NON-NLS-1$
+ }
+ this.factory.listModel.removeListChangeListener(ListValueModel.LIST_VALUES, this);
+ }
+
+
+ // ********** ListChangeListener **********
+
+ @SuppressWarnings("unchecked")
+ public void itemsAdded(ListAddEvent event) {
+ this.addComponentPVMs(event.getIndex(), (Iterable<? extends PropertyValueModel<? extends E>>) event.getItems());
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void itemsRemoved(ListRemoveEvent event) {
+ this.removeComponentPVMs(event.getIndex(), event.getItemsSize(), (Iterable<? extends PropertyValueModel<? extends E>>) event.getItems());
+ this.update();
+ }
+
+ public void itemsMoved(ListMoveEvent event) {
+ ListTools.move(this.values, event.getTargetIndex(), event.getSourceIndex(), event.getLength());
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void itemsReplaced(ListReplaceEvent event) {
+ this.removeComponentPVMs(event.getIndex(), event.getItemsSize(), (Iterable<? extends PropertyValueModel<? extends E>>) event.getOldItems());
+ this.addComponentPVMs(event.getIndex(), (Iterable<? extends PropertyValueModel<? extends E>>) event.getNewItems());
+ this.update();
+ }
+
+ public void listCleared(ListClearEvent event) {
+ this.removeCachedPVMs();
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void listChanged(ListChangeEvent event) {
+ this.removeCachedPVMs();
+ this.addComponentPVMs(0, (Iterable<? extends PropertyValueModel<? extends E>>) event.getList());
+ this.update();
+ }
+
+
+ // ********** add/remove component PVMs **********
+
+ private void addComponentPVMs(int index, Iterable<? extends PropertyValueModel<? extends E>> pvms) {
+ for (PropertyValueModel<? extends E> pvm : pvms) {
+ this.addComponentPVM(index++, pvm);
+ }
+ }
+
+ private void addComponentPVM(int index, PropertyValueModel<? extends E> pvm) {
+ if (pvm == null) {
+ throw new NullPointerException();
+ }
+ for (SimpleAssociation<PropertyValueModel<? extends E>, E> each : this.values) {
+ if (each.getKey() == pvm) {
+ throw new IllegalStateException("duplicate component: " + pvm); //$NON-NLS-1$
+ }
+ }
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, this.componentListener);
+ this.values.add(index, new SimpleAssociation<>(pvm, pvm.getValue()));
+ }
+
+ private void removeCachedPVMs() {
+ @SuppressWarnings("unchecked")
+ Transformer<SimpleAssociation<PropertyValueModel<? extends E>, E>, PropertyValueModel<? extends E>> transformer = Association.KEY_TRANSFORMER;
+ this.removeComponentPVMs(this.values, ListTools.transform(this.values, transformer));
+ }
+
+ private void removeComponentPVMs(int index, int length, Iterable<? extends PropertyValueModel<? extends E>> expectedPVMs) {
+ this.removeComponentPVMs(this.values.subList(index, index + length), expectedPVMs);
+ }
+
+ private void removeComponentPVMs(List<SimpleAssociation<PropertyValueModel<? extends E>, E>> subList, Iterable<? extends PropertyValueModel<? extends E>> expectedPVMs) {
+ Iterator<? extends PropertyValueModel<? extends E>> stream = expectedPVMs.iterator();
+ for (SimpleAssociation<PropertyValueModel<? extends E>, E> each : subList) {
+ PropertyValueModel<? extends E> pvm = each.getKey();
+ PropertyValueModel<? extends E> expectedPVM = stream.next();
+ if (pvm != expectedPVM) {
+ throw new IllegalStateException("inconsistent component: " + pvm + " - expected: " + expectedPVM); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ pvm.removePropertyChangeListener(PropertyValueModel.VALUE, this.componentListener);
+ }
+ subList.clear();
+ }
+
+
+ // ********** misc **********
+
+ private void update() {
+ this.listener.valueChanged(this.value = this.buildValue());
+ }
+
+ private V buildValue() {
+ @SuppressWarnings("unchecked")
+ Transformer<SimpleAssociation<PropertyValueModel<? extends E>, E>, E> transformer = Association.VALUE_TRANSFORMER;
+ return this.factory.transformer.transform(ListTools.transform(this.values, transformer));
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.value);
+ }
+
+
+ // ********** component listener **********
+
+ private PropertyChangeListener buildComponentListener() {
+ return new ComponentListener();
+ }
+
+ /* CU private */ class ComponentListener
+ extends PropertyChangeAdapter
+ {
+ @Override
+ public void propertyChanged(PropertyChangeEvent event) {
+ ListCompositePropertyValueModelAdapter.this.componentChanged(event);
+ }
+ }
+
+ /* CU private */ void componentChanged(PropertyChangeEvent event) {
+ @SuppressWarnings("unchecked")
+ PropertyValueModel<? extends E> source = (PropertyValueModel<? extends E>) event.getSource();
+ for (SimpleAssociation<PropertyValueModel<? extends E>, E> each : this.values) {
+ if (each.getKey() == source) {
+ @SuppressWarnings("unchecked")
+ E newValue = (E) event.getNewValue();
+ each.setValue(newValue);
+ this.update();
+ return;
+ }
+ }
+ throw new IllegalStateException("invalid component: " + source); //$NON-NLS-1$
+ }
+
+
+ // ********** PluggablePropertyValueModel.Adapter.Factory **********
+
+ public static class Factory<E, V>
+ implements PluggablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final ListValueModel<? extends PropertyValueModel<? extends E>> listModel;
+ /* CU private */ final Transformer<? super List<E>, V> transformer;
+
+ public Factory(ListValueModel<? extends PropertyValueModel<? extends E>> listModel, Transformer<? super List<E>, V> transformer) {
+ super();
+ if (listModel == null) {
+ throw new NullPointerException();
+ }
+ this.listModel = listModel;
+ if (transformer == null) {
+ throw new NullPointerException();
+ }
+ this.transformer = transformer;
+ }
+
+ public Adapter<V> buildAdapter(AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new ListCompositePropertyValueModelAdapter<>(this, listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPluggablePropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPluggablePropertyValueModelAdapter.java
new file mode 100644
index 0000000000..d1c4eb1536
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPluggablePropertyValueModelAdapter.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.collection.ListTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggablePropertyValueModel.Adapter;
+import org.eclipse.jpt.common.utility.model.event.ListAddEvent;
+import org.eclipse.jpt.common.utility.model.event.ListChangeEvent;
+import org.eclipse.jpt.common.utility.model.event.ListClearEvent;
+import org.eclipse.jpt.common.utility.model.event.ListMoveEvent;
+import org.eclipse.jpt.common.utility.model.event.ListRemoveEvent;
+import org.eclipse.jpt.common.utility.model.event.ListReplaceEvent;
+import org.eclipse.jpt.common.utility.model.listener.ListChangeListener;
+import org.eclipse.jpt.common.utility.model.value.ListValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * Adapt a {@link ListValueModel list value model} to
+ * a {@link PropertyValueModel property value model}, sorta.
+ * <p>
+ * This adapter is constructed with a {@link ListValueModel
+ * list value model} and a {@link Transformer transformer} that can
+ * transform the list to a single value.
+ * <p>
+ * This is an adapter that can be plugged into a {@link PluggablePropertyValueModel}.
+ *
+ * @param <E> the type of the adapted list value model's elements
+ * @param <V> the type of the model's derived value
+ *
+ * @see PluggablePropertyValueModel
+ */
+public final class ListPluggablePropertyValueModelAdapter<E, V>
+ implements PluggablePropertyValueModel.Adapter<V>, ListChangeListener
+{
+ private final Factory<E, V> factory;
+
+ /** The <em>real</em> adapter. */
+ private final AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener;
+
+ /** Cached copy of model's elements. */
+ private final ArrayList<E> list;
+
+ /** Protects {@link #list} from {@link Factory#transformer}. */
+ private final List<E> unmodifiableList;
+
+ /** The derived value. */
+ private volatile V value;
+
+
+ // ********** constructors **********
+
+ public ListPluggablePropertyValueModelAdapter(Factory<E, V> factory, AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.factory = factory;
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ this.listener = listener;
+ this.list = new ArrayList<>();
+ this.unmodifiableList = Collections.unmodifiableList(this.list);
+ }
+
+
+ // ********** PropertyValueModelAdapter.Adapter **********
+
+ public V getValue() {
+ return this.value;
+ }
+
+ public void engageModel() {
+ this.factory.listModel.addListChangeListener(ListValueModel.LIST_VALUES, this);
+ ListTools.addAll(this.list, 0, this.factory.listModel);
+ this.value = this.buildValue();
+ }
+
+ public void disengageModel() {
+ this.value = null;
+ this.list.clear();
+ this.factory.listModel.removeListChangeListener(ListValueModel.LIST_VALUES, this);
+ }
+
+
+ // ********** ListChangeListener **********
+
+ @SuppressWarnings("unchecked")
+ public void itemsAdded(ListAddEvent event) {
+ ListTools.addAll(this.list, event.getIndex(), (Iterable<E>) event.getItems(), event.getItemsSize());
+ this.update();
+ }
+
+ public void itemsRemoved(ListRemoveEvent event) {
+ ListTools.removeElementsAtIndex(this.list, event.getIndex(), event.getItemsSize());
+ this.update();
+ }
+
+ public void itemsReplaced(ListReplaceEvent event) {
+ @SuppressWarnings("unchecked")
+ Iterable<E> newItems = (Iterable<E>) event.getNewItems();
+ Iterator<E> stream = newItems.iterator();
+ int last = event.getIndex() + event.getItemsSize();
+ for (int i = event.getIndex(); i < last; i++) {
+ this.list.set(i, stream.next());
+ }
+ this.update();
+ }
+
+ public void itemsMoved(ListMoveEvent event) {
+ ListTools.move(this.list, event.getTargetIndex(), event.getSourceIndex(), event.getLength());
+ this.update();
+ }
+
+ public void listCleared(ListClearEvent event) {
+ this.list.clear();
+ this.update();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void listChanged(ListChangeEvent event) {
+ this.list.clear();
+ CollectionTools.addAll(this.list, (Iterable<E>) event.getList());
+ this.update();
+ }
+
+
+ // ********** misc **********
+
+ private void update() {
+ V newValue = this.buildValue();
+ this.value = newValue;
+ this.listener.valueChanged(newValue);
+ }
+
+ private V buildValue() {
+ return this.factory.transformer.transform(this.unmodifiableList);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.value);
+ }
+
+
+ // ********** PluggablePropertyValueModel.Adapter.Factory **********
+
+ public static class Factory<E, V>
+ implements PluggablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final ListValueModel<? extends E> listModel;
+ /* CU private */ final Transformer<? super List<E>, V> transformer;
+
+ public Factory(ListValueModel<? extends E> listModel, Transformer<? super List<E>, V> transformer) {
+ super();
+ if (listModel == null) {
+ throw new NullPointerException();
+ }
+ this.listModel = listModel;
+ if (transformer == null) {
+ throw new NullPointerException();
+ }
+ this.transformer = transformer;
+ }
+
+ public Adapter<V> buildAdapter(AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new ListPluggablePropertyValueModelAdapter<>(this, listener);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPropertyValueModelAdapter.java
deleted file mode 100644
index de238160c9..0000000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008, 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.model.event.ListAddEvent;
-import org.eclipse.jpt.common.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.common.utility.model.event.ListClearEvent;
-import org.eclipse.jpt.common.utility.model.event.ListMoveEvent;
-import org.eclipse.jpt.common.utility.model.event.ListRemoveEvent;
-import org.eclipse.jpt.common.utility.model.event.ListReplaceEvent;
-import org.eclipse.jpt.common.utility.model.listener.ListChangeAdapter;
-import org.eclipse.jpt.common.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.common.utility.model.value.ListValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a list value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- * <p>
- * Subclasses must override:<ul>
- * <li>{@link #buildValue()}<p>
- * to return the current property value, as derived from the
- * current list value
- * </ul>
- * Subclasses might want to override the following methods
- * to improve performance (by not recalculating the value, if possible):<ul>
- * <li>{@link #itemsAdded(ListAddEvent event)}
- * <li>{@link #itemsRemoved(ListRemoveEvent event)}
- * <li>{@link #itemsReplaced(ListReplaceEvent event)}
- * <li>{@link #itemsMoved(ListMoveEvent event)}
- * <li>{@link #listCleared(ListClearEvent event)}
- * <li>{@link #listChanged(ListChangeEvent event)}
- * </ul>
- */
-public abstract class ListPropertyValueModelAdapter<T>
- extends AbstractPropertyValueModelAdapter<T>
-{
- /** The wrapped list value model. */
- protected final ListValueModel<?> listModel;
-
- /** A listener that allows us to sync with changes to the wrapped list model. */
- protected final ListChangeListener listListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * list value model.
- */
- protected ListPropertyValueModelAdapter(ListValueModel<?> listModel) {
- super();
- if (listModel == null) {
- throw new NullPointerException();
- }
- this.listModel = listModel;
- this.listListener = this.buildListListener();
- }
-
- protected ListChangeListener buildListListener() {
- return new ListListener();
- }
-
- protected class ListListener
- extends ListChangeAdapter
- {
- @Override
- public void itemsAdded(ListAddEvent event) {
- ListPropertyValueModelAdapter.this.itemsAdded(event);
- }
- @Override
- public void itemsRemoved(ListRemoveEvent event) {
- ListPropertyValueModelAdapter.this.itemsRemoved(event);
- }
- @Override
- public void itemsReplaced(ListReplaceEvent event) {
- ListPropertyValueModelAdapter.this.itemsReplaced(event);
- }
- @Override
- public void itemsMoved(ListMoveEvent event) {
- ListPropertyValueModelAdapter.this.itemsMoved(event);
- }
- @Override
- public void listCleared(ListClearEvent event) {
- ListPropertyValueModelAdapter.this.listCleared(event);
- }
- @Override
- public void listChanged(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.listChanged(event);
- }
- }
-
-
- // ********** listener **********
-
- /**
- * Start listening to the list holder.
- */
- @Override
- protected void engageModel_() {
- this.listModel.addListChangeListener(ListValueModel.LIST_VALUES, this.listListener);
- }
-
- /**
- * Stop listening to the list holder.
- */
- @Override
- protected void disengageModel_() {
- this.listModel.removeListChangeListener(ListValueModel.LIST_VALUES, this.listListener);
- }
-
-
- // ********** list change support **********
-
- /**
- * Items were added to the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsAdded(@SuppressWarnings("unused") ListAddEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were removed from the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsRemoved(@SuppressWarnings("unused") ListRemoveEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were replaced in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsReplaced(@SuppressWarnings("unused") ListReplaceEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were moved in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsMoved(@SuppressWarnings("unused") ListMoveEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The wrapped list holder was cleared;
- * propagate the change notification appropriately.
- */
- protected void listCleared(@SuppressWarnings("unused") ListClearEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The value of the wrapped list holder has changed;
- * propagate the change notification appropriately.
- */
- protected void listChanged(@SuppressWarnings("unused") ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListValueModelTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListValueModelTools.java
new file mode 100644
index 0000000000..1e49f0a853
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListValueModelTools.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 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 java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.jpt.common.utility.closure.Closure;
+import org.eclipse.jpt.common.utility.internal.closure.BooleanClosure;
+import org.eclipse.jpt.common.utility.internal.closure.ClosureTools;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerTools;
+import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
+import org.eclipse.jpt.common.utility.model.value.ListValueModel;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.predicate.Predicate;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * {@link ListValueModel List value model} utility methods.
+ */
+public final class ListValueModelTools {
+
+ // ********** composite PVMs **********
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * transformer and property value models.
+ */
+ @SafeVarargs
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(Transformer<? super List<E>, V> transformer, PropertyValueModel<? extends E>... propertyValueModels) {
+ return compositePropertyValueModel(Arrays.asList(propertyValueModels), transformer);
+ }
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * property value models and transformer.
+ */
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(Collection<? extends PropertyValueModel<? extends E>> propertyValueModels, Transformer<? super List<E>, V> transformer) {
+ return compositePropertyValueModel(new StaticListValueModel<>(propertyValueModels), transformer);
+ }
+
+ /**
+ * Construct a composite property value model adapter for the specified
+ * list value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PropertyValueModel<V> compositePropertyValueModel(ListValueModel<? extends PropertyValueModel<? extends E>> listModel, Transformer<? super List<E>, V> transformer) {
+ return PropertyValueModelTools.propertyValueModel(new ListCompositePropertyValueModelAdapter.Factory<>(listModel, transformer));
+ }
+
+
+ // ********** list meta data adapters **********
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model.
+ * If the list is empty, the model's value is <code>null</code>;
+ * otherwise, it is the first element in the list.
+ */
+ public static <E> PropertyValueModel<E> firstElementPropertyValueModel(ListValueModel<? extends E> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionFirstElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model.
+ * If the list is empty, the model's value is <code>null</code>;
+ * otherwise, it is the last element in the list.
+ */
+ public static <E> PropertyValueModel<E> lastElementPropertyValueModel(ListValueModel<? extends E> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionLastElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model.
+ * If the list contains <em>only</em> a single element,
+ * the model's value is that element; otherwise,
+ * the model's value is <code>null</code>.
+ */
+ public static <E> PropertyValueModel<E> singleElementPropertyValueModel(ListValueModel<? extends E> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionSingleElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model that returns whether the list is <em>not</em> empty.
+ */
+ public static PropertyValueModel<Boolean> isNotEmptyPropertyValueModel(ListValueModel<?> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionIsNotEmptyTransformer());
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * list value model that returns whether the list is <em>not</em> empty.
+ * This model can also be used to populate or clear the list value model.
+ * The specified list mutator is used to convert the list value model:
+ * it should populate the list value model when passed <code>true</code>
+ * and clear the list value model when passed <code>false</code>.
+ */
+ public static ModifiablePropertyValueModel<Boolean> isNotEmptyModifiablePropertyValueModel(ListValueModel<?> listModel, BooleanClosure.Adapter listMutator) {
+ return booleanModifiablePropertyValueModel(listModel, TransformerTools.collectionIsNotEmptyTransformer(), listMutator);
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model that returns whether the list is empty.
+ */
+ public static PropertyValueModel<Boolean> isEmptyPropertyValueModel(ListValueModel<?> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionIsEmptyTransformer());
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * list value model that returns whether the list is empty.
+ * This model can also be used to populate or clear the list value model.
+ * The specified list mutator is used to convert the list value model:
+ * it should populate the list value model when passed <code>true</code>
+ * and clear the list value model when passed <code>false</code>.
+ */
+ public static ModifiablePropertyValueModel<Boolean> isEmptyModifiablePropertyValueModel(ListValueModel<?> listModel, BooleanClosure.Adapter listMutator) {
+ return booleanModifiablePropertyValueModel(listModel, TransformerTools.collectionIsEmptyTransformer(), listMutator);
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model that returns whether the list contains
+ * exactly one element.
+ */
+ public static PropertyValueModel<Boolean> containsSingleElementPropertyValueModel(ListValueModel<?> listModel) {
+ return propertyValueModel(listModel, TransformerTools.collectionContainsSingleElementTransformer());
+ }
+
+ /**
+ * Construct a property value model adapter for the specified
+ * list value model that returns whether the list's size
+ * equals the specified size.
+ */
+ public static PropertyValueModel<Boolean> sizeEqualsPropertyValueModel(ListValueModel<?> listModel, int size) {
+ return propertyValueModel(listModel, TransformerTools.collectionSizeEqualsTransformer(size));
+ }
+
+ // ********** PVM adapters **********
+
+ /**
+ * Construct a boolean property value model adapter for the specified
+ * list value model and predicate. The returned model will indicate whether
+ * the list belongs to the set defined by the predicate.
+ */
+ public static PropertyValueModel<Boolean> booleanPropertyValueModel(ListValueModel<?> listModel, Predicate<? super List<?>> predicate) {
+ return propertyValueModel(listModel, TransformerTools.adapt(predicate));
+ }
+
+ /**
+ * Construct a property value model adapted to the specified
+ * list value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PropertyValueModel<V> propertyValueModel(ListValueModel<? extends E> listModel, Transformer<? super List<E>, V> transformer) {
+ return PropertyValueModelTools.propertyValueModel(pluggablePropertyValueModelAdapterFactory(listModel, transformer));
+ }
+
+ /**
+ * Construct a pluggable property value model adapter factory for the specified
+ * list value model and transformer.
+ * @see PluggablePropertyValueModel
+ */
+ public static <E, V> PluggablePropertyValueModel.Adapter.Factory<V> pluggablePropertyValueModelAdapterFactory(ListValueModel<? extends E> listModel, Transformer<? super List<E>, V> transformer) {
+ return new ListPluggablePropertyValueModelAdapter.Factory<>(listModel, transformer);
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * list value model that returns whether the list belongs to the set defined
+ * by the specified predicate.
+ * This model will use the specified list mutator to modify the list value model.
+ */
+ public static ModifiablePropertyValueModel<Boolean> booleanModifiablePropertyValueModel(ListValueModel<?> listModel, Predicate<? super Collection<?>> predicate, BooleanClosure.Adapter listMutator) {
+ return booleanModifiablePropertyValueModel(listModel, TransformerTools.adapt(predicate), listMutator);
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapted to the specified
+ * list value model that returns whether the list belongs to the set defined
+ * by the specified transformer.
+ * This model will use the specified list mutator to modify the list value model.
+ */
+ public static ModifiablePropertyValueModel<Boolean> booleanModifiablePropertyValueModel(ListValueModel<?> listModel, Transformer<? super Collection<?>, Boolean> transformer, BooleanClosure.Adapter listMutator) {
+ PluggablePropertyValueModel.Adapter.Factory<Boolean> factory = pluggablePropertyValueModelAdapterFactory(listModel, transformer);
+ Closure<Boolean> closure = ClosureTools.booleanClosure(listMutator);
+ return PropertyValueModelTools.pluggableModifiablePropertyValueModel(factory, closure);
+ }
+
+
+ // ********** filtering **********
+
+ /**
+ * Construct a collection value model with the specified wrapped list value model and filter.
+ */
+ public static <E> CollectionValueModel<E> filter(ListValueModel<? extends E> listModel, Predicate<E> filter) {
+ return CollectionValueModelTools.filter(new ListCollectionValueModelAdapter<E>(listModel), filter);
+ }
+
+
+ // ********** suppressed constructor **********
+
+ /**
+ * Suppress default constructor, ensuring non-instantiability.
+ */
+ private ListValueModelTools() {
+ super();
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModel.java
new file mode 100644
index 0000000000..b9bbf39ca6
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModel.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 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.model.value.ModifiablePropertyValueModel;
+
+/**
+ * This class provides the infrastructure needed to wrap
+ * a <em>modifiable</em> model, "lazily" listen to it, and convert
+ * its change notifications into <em>property</em> value model change
+ * notifications.
+ *
+ * @param <V> the type of the model's derived value
+ */
+public class PluggableModifiablePropertyValueModel<V>
+ extends AbstractPluggablePropertyValueModel<V, PluggableModifiablePropertyValueModel.Adapter<V>>
+ implements ModifiablePropertyValueModel<V>
+{
+ public PluggableModifiablePropertyValueModel(Adapter.Factory<V> adapterFactory) {
+ super(adapterFactory);
+ }
+
+
+ // ********** ModifiablePropertyValueModel implementation **********
+
+ /**
+ * Forward the new value to the adapter.
+ * Our value will be updated by notification from the adapter,
+ * if appropriate.
+ */
+ public void setValue(V value) {
+ this.adapter.setValue(value);
+ }
+
+
+ // ********** Adapter interfaces **********
+
+ public interface Adapter<AV>
+ extends AbstractPluggablePropertyValueModel.Adapter<AV>
+ {
+ /**
+ * Set the adapted model's value,
+ * based on the specified new value of the property value model.
+ */
+ void setValue(AV value);
+
+ interface Factory<AFV>
+ extends AbstractPluggablePropertyValueModel.Adapter.Factory<AFV, Adapter<AFV>>
+ {
+ // NOP
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModelAdapter.java
new file mode 100644
index 0000000000..409b8991d1
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggableModifiablePropertyValueModelAdapter.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 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.closure.Closure;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+
+/**
+ * This class adds support for plugging in a closure that can be used to set
+ * the model's value.
+ * <p>
+ * This class is most useful when the adapted model is changed <em>outside</em>
+ * the property value model; typically by modifying the original
+ * <em>domain</em> model.
+ *
+ * @param <V> the type of the model's derived value
+ */
+public class PluggableModifiablePropertyValueModelAdapter<V>
+ implements PluggableModifiablePropertyValueModel.Adapter<V>
+{
+ /** Read the adapted model with this. */
+ private final AbstractPluggablePropertyValueModel.Adapter<V> adapter;
+
+ /** Write the adapted model with this. */
+ private final Closure<V> closure;
+
+
+ public PluggableModifiablePropertyValueModelAdapter(AbstractPluggablePropertyValueModel.Adapter<V> adapter, Closure<V> closure) {
+ super();
+ if (adapter == null) {
+ throw new NullPointerException();
+ }
+ this.adapter = adapter;
+ if (closure == null) {
+ throw new NullPointerException();
+ }
+ this.closure = closure;
+ }
+
+ public V getValue() {
+ return this.adapter.getValue();
+ }
+
+ public void setValue(V value) {
+ this.closure.execute(value);
+ }
+
+ public void engageModel() {
+ this.adapter.engageModel();
+ }
+
+ public void disengageModel() {
+ this.adapter.disengageModel();
+ }
+
+
+ // ********** PluggableModifiablePropertyValueModel.Adapter.Factory **********
+
+ public static class Factory<V>
+ implements PluggableModifiablePropertyValueModel.Adapter.Factory<V>
+ {
+ /* CU private */ final AbstractPluggablePropertyValueModel.Adapter.Factory<V, ? extends AbstractPluggablePropertyValueModel.Adapter<V>> factory;
+ /* CU private */ final Closure<V> closure;
+
+ public Factory(AbstractPluggablePropertyValueModel.Adapter.Factory<V, ? extends AbstractPluggablePropertyValueModel.Adapter<V>> factory, Closure<V> closure) {
+ super();
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.factory = factory;
+ if (closure == null) {
+ throw new NullPointerException();
+ }
+ this.closure = closure;
+ }
+
+ public PluggableModifiablePropertyValueModel.Adapter<V> buildAdapter(AbstractPluggablePropertyValueModel.Adapter.Listener<V> listener) {
+ return new PluggableModifiablePropertyValueModelAdapter<>(this.factory.buildAdapter(listener), this.closure);
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this);
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggablePropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggablePropertyValueModel.java
new file mode 100644
index 0000000000..42f248d7c1
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PluggablePropertyValueModel.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 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;
+
+/**
+ * This class provides the infrastructure needed to wrap
+ * a model, "lazily" listen to it, and convert
+ * its change notifications into <em>property</em> value model change
+ * notifications.
+ *
+ * @param <V> the type of the model's derived value
+ */
+public class PluggablePropertyValueModel<V>
+ extends AbstractPluggablePropertyValueModel<V, PluggablePropertyValueModel.Adapter<V>>
+{
+ public PluggablePropertyValueModel(Adapter.Factory<V> adapterFactory) {
+ super(adapterFactory);
+ }
+
+
+ // ********** Adapter interfaces **********
+
+ public interface Adapter<AV>
+ extends AbstractPluggablePropertyValueModel.Adapter<AV>
+ {
+ interface Factory<AFV>
+ extends AbstractPluggablePropertyValueModel.Adapter.Factory<AFV, Adapter<AFV>>
+ {
+ // NOP
+ }
+ }
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ValueModelTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java
index 79c106fe24..7b1835cbe6 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ValueModelTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/PropertyValueModelTools.java
@@ -9,13 +9,39 @@
******************************************************************************/
package org.eclipse.jpt.common.utility.internal.model.value;
+import org.eclipse.jpt.common.utility.closure.Closure;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
/**
* Value Model utility methods.
*/
-public final class ValueModelTools {
+public final class PropertyValueModelTools {
+
+ /**
+ * Construct a property value model adapter for the specified adapter factory.
+ * @see PluggablePropertyValueModel
+ */
+ public static <V> PropertyValueModel<V> propertyValueModel(PluggablePropertyValueModel.Adapter.Factory<V> adapterFactory) {
+ return new PluggablePropertyValueModel<>(adapterFactory);
+ }
+
+ /**
+ * Construct a modifiable property value model adapter for the specified adapter factory.
+ * @see PluggableModifiablePropertyValueModel
+ */
+ public static <V> ModifiablePropertyValueModel<V> modifiablePropertyValueModel(PluggableModifiablePropertyValueModel.Adapter.Factory<V> adapterFactory) {
+ return new PluggableModifiablePropertyValueModel<>(adapterFactory);
+ }
+
+ /**
+ * Construct a <em>modifiable</em> property value model adapter for the specified
+ * property value model adapter adapter factory and closure.
+ * The specified closure is invoked when the model's value is set.
+ */
+ public static <V> ModifiablePropertyValueModel<V> pluggableModifiablePropertyValueModel(AbstractPluggablePropertyValueModel.Adapter.Factory<V, ? extends AbstractPluggablePropertyValueModel.Adapter<V>> factory, Closure<V> setValueClosure) {
+ return new PluggableModifiablePropertyValueModel<>(new PluggableModifiablePropertyValueModelAdapter.Factory<>(factory, setValueClosure));
+ }
// ********** double PVMs **********
@@ -44,7 +70,7 @@ public final class ValueModelTools {
/**
* Suppress default constructor, ensuring non-instantiability.
*/
- private ValueModelTools() {
+ private PropertyValueModelTools() {
super();
throw new UnsupportedOperationException();
}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
index 3842893b13..c7dcb27ea9 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2015 Oracle. All rights reserved.
+ * 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.
@@ -62,7 +62,7 @@ public class SimpleCollectionValueModel<E>
// ********** CollectionValueModel implementation **********
public Iterator<E> iterator() {
- return new LocalIterator<E>(this.collection.iterator());
+ return new LocalIterator<>(this.collection.iterator());
}
public int size() {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
index da81f0c2de..3c633626b7 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2015 Oracle. All rights reserved.
+ * 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.
@@ -65,11 +65,11 @@ public class SimpleListValueModel<E>
// ********** ListValueModel implementation **********
public Iterator<E> iterator() {
- return new LocalIterator<E>(this.list.iterator());
+ return new LocalIterator<>(this.list.iterator());
}
public ListIterator<E> listIterator() {
- return new LocalListIterator<E>(this.list.listIterator());
+ return new LocalListIterator<>(this.list.listIterator());
}
public int size() {
@@ -186,7 +186,7 @@ public class SimpleListValueModel<E>
}
public ListIterator<E> listIterator(int index) {
- return new LocalListIterator<E>(this.list.listIterator(index));
+ return new LocalListIterator<>(this.list.listIterator(index));
}
public List<E> subList(int fromIndex, int toIndex) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/model/value/PropertyValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/model/value/PropertyValueModel.java
index c098c884de..c39b5df007 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/model/value/PropertyValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/model/value/PropertyValueModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * 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.
@@ -9,7 +9,9 @@
******************************************************************************/
package org.eclipse.jpt.common.utility.model.value;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.model.Model;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
/**
* Interface used to abstract property accessing and
@@ -31,4 +33,18 @@ public interface PropertyValueModel<V>
*/
V getValue();
String VALUE = "value"; //$NON-NLS-1$
+
+ @SuppressWarnings("rawtypes")
+ Transformer VALUE_TRANSFORMER = new ValueTransformer();
+ class ValueTransformer<V>
+ implements Transformer<PropertyValueModel<V>, V>
+ {
+ public V transform(PropertyValueModel<V> pvm) {
+ return pvm.getValue();
+ }
+ @Override
+ public String toString() {
+ return ObjectTools.singletonToString(this);
+ }
+ }
}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
index bdf7a7e20b..bc9ae272a0 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2015 Oracle. All rights reserved.
+ * 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.
@@ -10,13 +10,12 @@
package org.eclipse.jpt.common.utility.tests.internal.model.value;
import java.util.Collection;
-
-import junit.framework.TestCase;
-
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
-import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.common.utility.internal.model.value.CollectionPropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionPluggablePropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
@@ -24,13 +23,16 @@ 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.CollectionValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
@SuppressWarnings("nls")
-public class CollectionPropertyValueModelAdapterTests extends TestCase {
- private ModifiablePropertyValueModel<Boolean> adapter;
- private SimpleCollectionValueModel<String> wrappedCollectionHolder;
+public class CollectionPropertyValueModelAdapterTests
+ extends TestCase
+{
+ private PropertyValueModel<Boolean> adapter;
+ private SimpleCollectionValueModel<String> collectionModel;
PropertyChangeEvent event;
public CollectionPropertyValueModelAdapterTests(String name) {
@@ -40,8 +42,8 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- this.wrappedCollectionHolder = new SimpleCollectionValueModel<String>();
- this.adapter = new LocalAdapter(this.wrappedCollectionHolder, "666");
+ this.collectionModel = new SimpleCollectionValueModel<>();
+ this.adapter = CollectionValueModelTools.propertyValueModel(this.collectionModel, new LocalTransformer("666"));
this.event = null;
}
@@ -52,11 +54,12 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
}
private boolean booleanValue() {
- return this.adapter.getValue().booleanValue();
+ Boolean value = this.adapter.getValue();
+ return (value != null) && value.booleanValue();
}
private Collection<String> wrappedCollection() {
- return CollectionTools.hashBag(this.wrappedCollectionHolder.iterator());
+ return CollectionTools.hashBag(this.collectionModel.iterator());
}
public void testValue() {
@@ -66,41 +69,25 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
assertFalse(this.booleanValue());
assertFalse(this.wrappedCollection().contains("666"));
- this.wrappedCollectionHolder.add("111");
+ this.collectionModel.add("111");
assertFalse(this.booleanValue());
- this.wrappedCollectionHolder.add("222");
+ this.collectionModel.add("222");
assertFalse(this.booleanValue());
- this.wrappedCollectionHolder.add("666");
+ this.collectionModel.add("666");
assertTrue(this.booleanValue());
assertTrue(this.wrappedCollection().contains("666"));
- this.wrappedCollectionHolder.remove("666");
+ this.collectionModel.remove("666");
assertFalse(this.booleanValue());
assertFalse(this.wrappedCollection().contains("666"));
- this.wrappedCollectionHolder.add("666");
+ this.collectionModel.add("666");
assertTrue(this.booleanValue());
assertTrue(this.wrappedCollection().contains("666"));
- this.wrappedCollectionHolder.clear();
- assertFalse(this.booleanValue());
- assertFalse(this.wrappedCollection().contains("666"));
- }
-
- public void testSetValue() {
- this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent e) {/* OK */}
- });
- assertFalse(this.booleanValue());
- assertFalse(this.wrappedCollection().contains("666"));
-
- this.adapter.setValue(Boolean.TRUE);
- assertTrue(this.booleanValue());
- assertTrue(this.wrappedCollection().contains("666"));
-
- this.adapter.setValue(Boolean.FALSE);
+ this.collectionModel.clear();
assertFalse(this.booleanValue());
assertFalse(this.wrappedCollection().contains("666"));
}
@@ -113,22 +100,22 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
});
assertNull(this.event);
- this.wrappedCollectionHolder.add("111");
+ this.collectionModel.add("111");
assertNull(this.event);
- this.wrappedCollectionHolder.add("222");
+ this.collectionModel.add("222");
assertNull(this.event);
- this.wrappedCollectionHolder.add("666");
+ this.collectionModel.add("666");
this.verifyEvent(false, true);
- this.wrappedCollectionHolder.remove("666");
+ this.collectionModel.remove("666");
this.verifyEvent(true, false);
- this.wrappedCollectionHolder.add("666");
+ this.collectionModel.add("666");
this.verifyEvent(false, true);
- this.wrappedCollectionHolder.clear();
+ this.collectionModel.clear();
this.verifyEvent(true, false);
}
@@ -144,7 +131,7 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
public void propertyChanged(PropertyChangeEvent e) {/* OK */}
};
this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
- this.wrappedCollectionHolder.add("666");
+ this.collectionModel.add("666");
assertTrue(this.booleanValue());
assertTrue(this.wrappedCollection().contains("666"));
@@ -159,7 +146,7 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
public void testHasListeners() {
assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertFalse(((AbstractModel) this.wrappedCollectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertFalse(((AbstractModel) this.collectionModel).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
ChangeListener listener = new ChangeAdapter() {
@Override
@@ -167,73 +154,130 @@ public class CollectionPropertyValueModelAdapterTests extends TestCase {
};
this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
assertTrue(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.wrappedCollectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertTrue(((AbstractModel) this.collectionModel).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
this.adapter.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertFalse(((AbstractModel) this.wrappedCollectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertFalse(((AbstractModel) this.collectionModel).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
this.adapter.addChangeListener(listener);
assertTrue(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertTrue(((AbstractModel) this.wrappedCollectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertTrue(((AbstractModel) this.collectionModel).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
this.adapter.removeChangeListener(listener);
assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
- assertFalse(((AbstractModel) this.wrappedCollectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertFalse(((AbstractModel) this.collectionModel).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ }
+
+ public void testToString1() {
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ });
+ assertTrue(this.adapter.toString().endsWith("(false)"));
+ this.collectionModel.add("666");
+ assertTrue(this.adapter.toString().endsWith("(true)"));
+ }
+
+ public void testToString3() {
+ CollectionPluggablePropertyValueModelAdapter.Factory<String, Boolean> f = new CollectionPluggablePropertyValueModelAdapter.Factory<>(this.collectionModel, new LocalTransformer("666"));
+ assertTrue(f.toString().indexOf("Factory") != -1);
+ }
+
+ public void testToString4() {
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ };
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ Object a = ObjectTools.get(this.adapter, "adapter");
+ Object l = ObjectTools.get(a, "listener");
+ assertTrue(l.toString().indexOf("AdapterListener") != -1);
+ }
+
+ public void testCtor_NPE1A() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = CollectionValueModelTools.propertyValueModel(null, new LocalTransformer("666"));
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE1B() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = CollectionValueModelTools.propertyValueModel(null, new LocalTransformer("666"));
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2A() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = CollectionValueModelTools.propertyValueModel(this.collectionModel, null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2B() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = CollectionValueModelTools.propertyValueModel(this.collectionModel, null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE4() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = PropertyValueModelTools.propertyValueModel(null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
}
// ********** member class **********
/**
- * the value is true if the wrapped collection contains the specified item,
- * otherwise the value is false
+ * Transform the collection to <code>true</code> if it contains the specified item,
+ * otherwise transform it to <code>false</code>.
*/
- static class LocalAdapter
- extends CollectionPropertyValueModelAdapter<Boolean, String>
- implements ModifiablePropertyValueModel<Boolean>
+ static class LocalTransformer
+ implements Transformer<Collection<String>, Boolean>
{
- private String item;
+ private final String item;
- LocalAdapter(CollectionValueModel<String> collectionHolder, String item) {
- super(collectionHolder);
+ LocalTransformer(String item) {
+ super();
this.item = item;
}
- // ********** CollectionPropertyValueModelAdapter implementation **********
- /**
- * always return a Boolean
- */
- @Override
- public Boolean getValue() {
- Boolean result = super.getValue();
- return (result == null) ? Boolean.FALSE : result;
- }
- @SuppressWarnings("unchecked")
- public void setValue(Boolean value) {
- if (this.booleanValue()) {
- if ( ! this.booleanValueOf(value)) {
- // the value is changing from true to false
- ((SimpleCollectionValueModel<String>) this.collectionModel).remove(this.item);
- }
- } else {
- if (this.booleanValueOf(value)) {
- // the value is changing from false to true
- ((SimpleCollectionValueModel<String>) this.collectionModel).add(this.item);
- }
- }
- }
- @Override
- protected Boolean buildValue() {
- return Boolean.valueOf(IteratorTools.contains(this.collectionModel.iterator(), this.item));
+ public Boolean transform(Collection<String> collection) {
+ return Boolean.valueOf(collection.contains(this.item));
}
- // ********** internal methods **********
- private boolean booleanValue() {
- return this.booleanValueOf(this.value);
- }
- private boolean booleanValueOf(Object b) {
- return (b == null) ? false : ((Boolean) b).booleanValue();
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.item);
}
}
}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionValueModelToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionValueModelToolsTests.java
new file mode 100644
index 0000000000..e7f0f726a1
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionValueModelToolsTests.java
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ * Copyright (c) 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.tests.internal.model.value;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.closure.BooleanClosure;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
+import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
+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.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class CollectionValueModelToolsTests
+ extends TestCase
+{
+ public CollectionValueModelToolsTests(String name) {
+ super(name);
+ }
+
+ public void testFirstElementPVMAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<String> pvm = CollectionValueModelTools.firstElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().equals("foo") || pvm.getValue().equals("bar"));
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ // unpredictable
+ // assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testLastElementPVMAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<String> pvm = CollectionValueModelTools.lastElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().equals("foo") || pvm.getValue().equals("bar"));
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ // unpredictable
+ // assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testSingleElementPVMAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<String> pvm = CollectionValueModelTools.singleElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testIsNotEmptyPropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<Boolean> pvm = CollectionValueModelTools.isNotEmptyPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public void testIsNotEmptyModifiablePropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ BooleanClosure.Adapter adapter = new NotEmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = CollectionValueModelTools.isNotEmptyModifiablePropertyValueModel(cvm, adapter);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ pvm.setValue(Boolean.FALSE);
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ assertEquals(0, cvm.size());
+
+ listener.event = null;
+ pvm.setValue(Boolean.TRUE);
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ assertEquals(2, cvm.size());
+ assertTrue(cvm.contains("baz"));
+ assertTrue(cvm.contains("xxx"));
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("xxx");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public static class NotEmptyBooleanClosureAdapter
+ implements BooleanClosure.Adapter
+ {
+ final SimpleCollectionValueModel<String> cvm;
+ public NotEmptyBooleanClosureAdapter(SimpleCollectionValueModel<String> cvm) {
+ this.cvm = cvm;
+ }
+ public void execute(boolean argument) {
+ if (argument) {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("baz");
+ list.add("xxx");
+ this.cvm.setValues(list);
+ } else {
+ this.cvm.clear();
+ }
+ }
+ }
+
+ public void testIsEmptyPropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<Boolean> pvm = CollectionValueModelTools.isEmptyPropertyValueModel(cvm);
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ private void verifyIsEmptyPropertyValueModelAdapter(SimpleCollectionValueModel<String> cvm, PropertyValueModel<Boolean> pvm) {
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ }
+
+ public void testBooleanPVM() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<Boolean> pvm = CollectionValueModelTools.booleanPropertyValueModel(cvm, PredicateTools.collectionIsEmptyPredicate());
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ public void testIsEmptyModifiablePropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ BooleanClosure.Adapter adapter = new EmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = CollectionValueModelTools.isEmptyModifiablePropertyValueModel(cvm, adapter);
+ this.verifyIsEmptyModifiablePropertyValueModelAdapter(cvm, pvm);
+ }
+
+ public void testBooleanModifiablePVM() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ BooleanClosure.Adapter adapter = new EmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = CollectionValueModelTools.booleanModifiablePropertyValueModel(cvm, PredicateTools.collectionIsEmptyPredicate(), adapter);
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ private void verifyIsEmptyModifiablePropertyValueModelAdapter(SimpleCollectionValueModel<String> cvm, ModifiablePropertyValueModel<Boolean> pvm) {
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ pvm.setValue(Boolean.TRUE);
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ assertEquals(0, cvm.size());
+
+ listener.event = null;
+ pvm.setValue(Boolean.FALSE);
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ assertEquals(2, cvm.size());
+ assertTrue(cvm.contains("baz"));
+ assertTrue(cvm.contains("xxx"));
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("xxx");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ }
+
+ public static class EmptyBooleanClosureAdapter
+ implements BooleanClosure.Adapter
+ {
+ final SimpleCollectionValueModel<String> cvm;
+ public EmptyBooleanClosureAdapter(SimpleCollectionValueModel<String> cvm) {
+ this.cvm = cvm;
+ }
+ public void execute(boolean argument) {
+ if (argument) {
+ this.cvm.clear();
+ } else {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("baz");
+ list.add("xxx");
+ this.cvm.setValues(list);
+ }
+ }
+ }
+
+ public void testContainsSingleElementPropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<Boolean> pvm = CollectionValueModelTools.containsSingleElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public void testSizeEqualsPropertyValueModelAdapter() {
+ SimpleCollectionValueModel<String> cvm = new SimpleCollectionValueModel<>();
+ PropertyValueModel<Boolean> pvm = CollectionValueModelTools.sizeEqualsPropertyValueModel(cvm, 2);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("baz");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+ }
+
+ public static class LocalPropertyChangeListener
+ extends PropertyChangeAdapter
+ {
+ public PropertyChangeEvent event;
+ public LocalPropertyChangeListener() {
+ super();
+ }
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ this.event = e;
+ }
+ }
+
+ public void testConstructor() {
+ boolean exCaught = false;
+ try {
+ Object o = ClassTools.newInstance(CollectionValueModelTools.class);
+ fail("bogus: " + o);
+ } catch (RuntimeException ex) {
+ if (ex.getCause() instanceof InvocationTargetException) {
+ if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+ exCaught = true;
+ }
+ }
+ }
+ assertTrue(exCaught);
+ }
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeBooleanPropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeAndBooleanPropertyValueModelTests.java
index 29201ce800..a6de1c427a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeBooleanPropertyValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeAndBooleanPropertyValueModelTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2015 Oracle. All rights reserved.
+ * Copyright (c) 2010, 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.
@@ -10,22 +10,23 @@
package org.eclipse.jpt.common.utility.tests.internal.model.value;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jpt.common.utility.internal.model.value.CompositeBooleanPropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
-public class CompositeBooleanPropertyValueModelTests extends TestCase {
+public class CompositeAndBooleanPropertyValueModelTests
+ extends TestCase
+{
private SimplePropertyValueModel<Boolean> pvm1;
private ModifiablePropertyValueModel<Boolean> pvm2;
private ModifiablePropertyValueModel<Boolean> pvm3;
@@ -36,29 +37,29 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
PropertyChangeEvent event;
- public CompositeBooleanPropertyValueModelTests(String name) {
+ public CompositeAndBooleanPropertyValueModelTests(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
- this.pvm1 = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
- this.pvm2 = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
- this.pvm3 = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
- this.pvm4 = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
- this.collection = new ArrayList<ModifiablePropertyValueModel<Boolean>>();
+ this.pvm1 = new SimplePropertyValueModel<>(Boolean.TRUE);
+ this.pvm2 = new SimplePropertyValueModel<>(Boolean.TRUE);
+ this.pvm3 = new SimplePropertyValueModel<>(Boolean.TRUE);
+ this.pvm4 = new SimplePropertyValueModel<>(Boolean.TRUE);
+ this.collection = new ArrayList<>();
this.collection.add(this.pvm1);
this.collection.add(this.pvm2);
this.collection.add(this.pvm3);
this.collection.add(this.pvm4);
- this.cvm = new SimpleCollectionValueModel<ModifiablePropertyValueModel<Boolean>>(this.collection);
+ this.cvm = new SimpleCollectionValueModel<>(this.collection);
this.compositePVM = this.buildCompositePVM(this.cvm);
}
private PropertyValueModel<Boolean> buildCompositePVM(CollectionValueModel<ModifiablePropertyValueModel<Boolean>> pvms) {
- return CompositeBooleanPropertyValueModel.and(pvms);
+ return CollectionValueModelTools.and(pvms);
}
@Override
@@ -67,7 +68,23 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
super.tearDown();
}
- public void testGetValue() {
+ public void testGetValue1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertTrue(this.compositePVM.getValue().booleanValue());
+ }
+
+ public void testGetValue2() {
+ this.compositePVM = CollectionValueModelTools.and(this.pvm1, this.pvm2, this.pvm3, this.pvm4);
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertTrue(this.compositePVM.getValue().booleanValue());
+ }
+
+ public void testGetValue3() {
+ this.compositePVM = CollectionValueModelTools.and(Arrays.asList(this.pvm1, this.pvm2, this.pvm3, this.pvm4));
assertNull(this.compositePVM.getValue());
ChangeListener listener = this.buildListener();
this.compositePVM.addChangeListener(listener);
@@ -136,7 +153,7 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
private void verifyCollectionChange() {
this.event = null;
- ModifiablePropertyValueModel<Boolean> pvm = new SimplePropertyValueModel<Boolean>(Boolean.FALSE);
+ ModifiablePropertyValueModel<Boolean> pvm = new SimplePropertyValueModel<>(Boolean.FALSE);
this.cvm.add(pvm);
this.verifyEvent(true, false);
@@ -145,15 +162,23 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
this.verifyEvent(false, true);
this.event = null;
+ this.cvm.add(pvm);
+ this.verifyEvent(true, false);
+
+ this.event = null;
this.cvm.clear();
- this.verifyEvent(Boolean.TRUE, null);
+ this.verifyEvent(false, true);
- Collection<ModifiablePropertyValueModel<Boolean>> c2 = new ArrayList<ModifiablePropertyValueModel<Boolean>>();
+ this.event = null;
+ this.cvm.add(pvm);
+ this.verifyEvent(true, false);
+
+ Collection<ModifiablePropertyValueModel<Boolean>> c2 = new ArrayList<>();
c2.add(this.pvm1);
c2.add(this.pvm2);
this.event = null;
this.cvm.setValues(c2);
- this.verifyEvent(null, Boolean.TRUE);
+ this.verifyEvent(false, true);
}
public void testLazyListening1() {
@@ -182,7 +207,7 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
return new ChangeAdapter() {
@Override
public void propertyChanged(PropertyChangeEvent e) {
- CompositeBooleanPropertyValueModelTests.this.event = e;
+ CompositeAndBooleanPropertyValueModelTests.this.event = e;
}
};
}
@@ -192,6 +217,7 @@ public class CompositeBooleanPropertyValueModelTests extends TestCase {
}
private void verifyEvent(Boolean oldValue, Boolean newValue) {
+ assertNotNull(this.event);
assertEquals(this.compositePVM, this.event.getSource());
assertEquals(PropertyValueModel.VALUE, this.event.getPropertyName());
assertEquals(oldValue, this.event.getOldValue());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeOrBooleanPropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeOrBooleanPropertyValueModelTests.java
new file mode 100644
index 0000000000..a85722c639
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeOrBooleanPropertyValueModelTests.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 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.tests.internal.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
+import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
+import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+public class CompositeOrBooleanPropertyValueModelTests
+ extends TestCase
+{
+ private SimplePropertyValueModel<Boolean> pvm1;
+ private ModifiablePropertyValueModel<Boolean> pvm2;
+ private ModifiablePropertyValueModel<Boolean> pvm3;
+ private ModifiablePropertyValueModel<Boolean> pvm4;
+ private Collection<ModifiablePropertyValueModel<Boolean>> collection;
+ private SimpleCollectionValueModel<ModifiablePropertyValueModel<Boolean>> cvm;
+ private PropertyValueModel<Boolean> compositePVM;
+ PropertyChangeEvent event;
+
+
+ public CompositeOrBooleanPropertyValueModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.pvm1 = new SimplePropertyValueModel<>(Boolean.FALSE);
+ this.pvm2 = new SimplePropertyValueModel<>(Boolean.FALSE);
+ this.pvm3 = new SimplePropertyValueModel<>(Boolean.FALSE);
+ this.pvm4 = new SimplePropertyValueModel<>(Boolean.FALSE);
+ this.collection = new ArrayList<>();
+ this.collection.add(this.pvm1);
+ this.collection.add(this.pvm2);
+ this.collection.add(this.pvm3);
+ this.collection.add(this.pvm4);
+ this.cvm = new SimpleCollectionValueModel<>(this.collection);
+
+ this.compositePVM = this.buildCompositePVM(this.cvm);
+ }
+
+ private PropertyValueModel<Boolean> buildCompositePVM(CollectionValueModel<ModifiablePropertyValueModel<Boolean>> pvms) {
+ return CollectionValueModelTools.or(pvms);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetValue1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertFalse(this.compositePVM.getValue().booleanValue());
+ }
+
+ public void testGetValue2() {
+ this.compositePVM = CollectionValueModelTools.or(this.pvm1, this.pvm2, this.pvm3, this.pvm4);
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertFalse(this.compositePVM.getValue().booleanValue());
+ }
+
+ public void testGetValue3() {
+ this.compositePVM = CollectionValueModelTools.or(Arrays.asList(this.pvm1, this.pvm2, this.pvm3, this.pvm4));
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertFalse(this.compositePVM.getValue().booleanValue());
+ }
+
+ public void testValueAndListeners1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertFalse(this.compositePVM.getValue().booleanValue());
+ this.compositePVM.removeChangeListener(listener);
+ assertNull(this.compositePVM.getValue());
+ }
+
+ public void testValueAndListeners2() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertFalse(this.compositePVM.getValue().booleanValue());
+ this.compositePVM.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertNull(this.compositePVM.getValue());
+ }
+
+ public void testPropertyChange1() {
+ this.compositePVM.addChangeListener(this.buildListener());
+ this.verifyPropertyChange();
+ }
+
+ public void testPropertyChange2() {
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, this.buildListener());
+ this.verifyPropertyChange();
+ }
+
+ private void verifyPropertyChange() {
+ this.event = null;
+ this.pvm1.setValue(Boolean.TRUE);
+ this.verifyEvent(false, true);
+
+ this.event = null;
+ this.pvm2.setValue(Boolean.TRUE);
+ assertNull(this.event); // no change
+
+ this.event = null;
+ this.pvm2.setValue(Boolean.FALSE);
+ assertNull(this.event); // no change
+
+ this.event = null;
+ this.pvm1.setValue(Boolean.FALSE);
+ this.verifyEvent(true, false);
+
+ this.event = null;
+ this.pvm4.setValue(Boolean.TRUE);
+ this.verifyEvent(false, true);
+ }
+
+ public void testCollectionChange1() {
+ this.compositePVM.addChangeListener(this.buildListener());
+ this.verifyCollectionChange();
+ }
+
+ public void testCollectionChange2() {
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, this.buildListener());
+ this.verifyCollectionChange();
+ }
+
+ private void verifyCollectionChange() {
+ this.event = null;
+ ModifiablePropertyValueModel<Boolean> pvm = new SimplePropertyValueModel<>(Boolean.TRUE);
+ this.cvm.add(pvm);
+ this.verifyEvent(false, true);
+
+ this.event = null;
+ this.cvm.remove(pvm);
+ this.verifyEvent(true, false);
+
+ this.event = null;
+ this.cvm.add(pvm);
+ this.verifyEvent(false, true);
+
+ this.event = null;
+ this.cvm.clear();
+ this.verifyEvent(true, false);
+
+ this.event = null;
+ this.cvm.add(pvm);
+ this.verifyEvent(false, true);
+
+ Collection<ModifiablePropertyValueModel<Boolean>> c2 = new ArrayList<>();
+ c2.add(this.pvm1);
+ c2.add(this.pvm2);
+ this.event = null;
+ this.cvm.setValues(c2);
+ this.verifyEvent(true, false);
+ }
+
+ public void testLazyListening1() {
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ ChangeListener listener = this.buildListener();
+
+ this.compositePVM.addChangeListener(listener);
+ assertTrue(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ this.compositePVM.removeChangeListener(listener);
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ }
+
+ public void testLazyListening2() {
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ ChangeListener listener = this.buildListener();
+
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertTrue(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ this.compositePVM.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ }
+
+ private ChangeListener buildListener() {
+ return new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ CompositeOrBooleanPropertyValueModelTests.this.event = e;
+ }
+ };
+ }
+
+ private void verifyEvent(boolean oldValue, boolean newValue) {
+ this.verifyEvent(Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
+ }
+
+ private void verifyEvent(Boolean oldValue, Boolean newValue) {
+ assertNotNull(this.event);
+ assertEquals(this.compositePVM, this.event.getSource());
+ assertEquals(PropertyValueModel.VALUE, this.event.getPropertyName());
+ assertEquals(oldValue, this.event.getOldValue());
+ assertEquals(newValue, this.event.getNewValue());
+ }
+
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositePropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositePropertyValueModelTests.java
index 56acea9e90..47f632d08f 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositePropertyValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositePropertyValueModelTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2015 Oracle. All rights reserved.
+ * 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.
@@ -11,27 +11,32 @@ package org.eclipse.jpt.common.utility.tests.internal.model.value;
import java.util.ArrayList;
import java.util.Collection;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jpt.common.utility.internal.model.value.CompositePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.exception.RuntimeExceptionHandler;
+import org.eclipse.jpt.common.utility.internal.model.ChangeSupport;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
-public class CompositePropertyValueModelTests extends TestCase {
+@SuppressWarnings("nls")
+public class CompositePropertyValueModelTests
+ extends TestCase
+{
private SimplePropertyValueModel<Integer> pvm1;
private ModifiablePropertyValueModel<Integer> pvm2;
private ModifiablePropertyValueModel<Integer> pvm3;
private ModifiablePropertyValueModel<Integer> pvm4;
- private Collection<ModifiablePropertyValueModel<Integer>> collection;
- private SimpleCollectionValueModel<ModifiablePropertyValueModel<Integer>> cvm;
+ private Collection<PropertyValueModel<Integer>> collection;
+ private SimpleCollectionValueModel<PropertyValueModel<Integer>> cvm;
private PropertyValueModel<Integer> compositePVM;
PropertyChangeEvent event;
@@ -43,31 +48,49 @@ public class CompositePropertyValueModelTests extends TestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- this.pvm1 = new SimplePropertyValueModel<Integer>(Integer.valueOf(1));
- this.pvm2 = new SimplePropertyValueModel<Integer>(Integer.valueOf(2));
- this.pvm3 = new SimplePropertyValueModel<Integer>(Integer.valueOf(3));
- this.pvm4 = new SimplePropertyValueModel<Integer>(Integer.valueOf(4));
- this.collection = new ArrayList<ModifiablePropertyValueModel<Integer>>();
+ this.pvm1 = new SimplePropertyValueModel<>(Integer.valueOf(1));
+ this.pvm2 = new SimplePropertyValueModel<>(Integer.valueOf(2));
+ this.pvm3 = new SimplePropertyValueModel<>(Integer.valueOf(3));
+ this.pvm4 = new SimplePropertyValueModel<>(Integer.valueOf(4));
+ this.collection = new ArrayList<>();
this.collection.add(this.pvm1);
this.collection.add(this.pvm2);
this.collection.add(this.pvm3);
this.collection.add(this.pvm4);
- this.cvm = new SimpleCollectionValueModel<ModifiablePropertyValueModel<Integer>>(this.collection);
+ this.cvm = new LocalSimpleCollectionValueModel<>(this.collection);
this.compositePVM = this.buildCompositePVM(this.cvm);
}
- private <T extends PropertyValueModel<Integer>> PropertyValueModel<Integer> buildCompositePVM(CollectionValueModel<T> pvms) {
- return new CompositePropertyValueModel<Integer, Integer>(pvms) {
- @Override
- protected Integer buildValue() {
- int sum = 0;
- for (PropertyValueModel<? extends Integer> each : this.collectionModel) {
- sum += each.getValue().intValue();
+ public static class LocalSimpleCollectionValueModel<E>
+ extends SimpleCollectionValueModel<E>
+ {
+ public LocalSimpleCollectionValueModel(Collection<E> collection) {
+ super(collection);
+ }
+ @Override
+ protected ChangeSupport buildChangeSupport() {
+ return new ChangeSupport(this, RuntimeExceptionHandler.instance());
+ }
+ }
+
+ private PropertyValueModel<Integer> buildCompositePVM(CollectionValueModel<PropertyValueModel<Integer>> pvms) {
+ return CollectionValueModelTools.compositePropertyValueModel(pvms, new LocalTransformer());
+ }
+
+ public static class LocalTransformer
+ extends TransformerAdapter<Collection<Integer>, Integer>
+ {
+ @Override
+ public Integer transform(Collection<Integer> integers) {
+ int sum = 0;
+ for (Integer integer : integers) {
+ if (integer != null) {
+ sum += integer.intValue();
}
- return Integer.valueOf(sum);
}
- };
+ return Integer.valueOf(sum);
+ }
}
@Override
@@ -76,7 +99,25 @@ public class CompositePropertyValueModelTests extends TestCase {
super.tearDown();
}
- public void testGetValue() {
+ public void testGetValue1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals(10, this.compositePVM.getValue().intValue());
+ }
+
+ public void testGetValue2() {
+ ArrayList<PropertyValueModel<Integer>> list = new ArrayList<>();
+ CollectionTools.addAll(list, this.cvm);
+ this.compositePVM = CollectionValueModelTools.compositePropertyValueModel(list, new LocalTransformer());
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals(10, this.compositePVM.getValue().intValue());
+ }
+
+ public void testGetValue3() {
+ this.compositePVM = CollectionValueModelTools.compositePropertyValueModel(new LocalTransformer(), this.pvm1, this.pvm2, this.pvm3, this.pvm4);
assertNull(this.compositePVM.getValue());
ChangeListener listener = this.buildListener();
this.compositePVM.addChangeListener(listener);
@@ -133,7 +174,7 @@ public class CompositePropertyValueModelTests extends TestCase {
private void verifyCollectionChange() {
this.event = null;
- ModifiablePropertyValueModel<Integer> pvm = new SimplePropertyValueModel<Integer>(Integer.valueOf(77));
+ ModifiablePropertyValueModel<Integer> pvm = new SimplePropertyValueModel<>(Integer.valueOf(77));
this.cvm.add(pvm);
this.verifyEvent(10, 87);
@@ -145,7 +186,7 @@ public class CompositePropertyValueModelTests extends TestCase {
this.cvm.clear();
this.verifyEvent(10, 0);
- Collection<ModifiablePropertyValueModel<Integer>> c2 = new ArrayList<ModifiablePropertyValueModel<Integer>>();
+ Collection<PropertyValueModel<Integer>> c2 = new ArrayList<>();
c2.add(this.pvm1);
c2.add(this.pvm2);
this.event = null;
@@ -175,6 +216,54 @@ public class CompositePropertyValueModelTests extends TestCase {
assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
}
+ public void testCtor_NPE1() {
+ boolean exCaught = false;
+ try {
+ this.compositePVM = this.buildCompositePVM(null);
+ fail("bogus: " + this.compositePVM);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2() {
+ boolean exCaught = false;
+ try {
+ this.compositePVM = CollectionValueModelTools.compositePropertyValueModel((CollectionValueModel<PropertyValueModel<Integer>>) this.cvm, (TransformerAdapter<Collection<Integer>, Integer>) null);
+ fail("bogus: " + this.compositePVM);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testNullPVM() {
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ boolean exCaught = false;
+ try {
+ this.cvm.add(null);
+ fail("bogus: " + this.cvm);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testDuplicatePVM() {
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ boolean exCaught = false;
+ try {
+ this.cvm.add(this.pvm1);
+ fail("bogus: " + this.cvm);
+ } catch (IllegalStateException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
private ChangeListener buildListener() {
return new ChangeAdapter() {
@Override
@@ -185,6 +274,7 @@ public class CompositePropertyValueModelTests extends TestCase {
}
private void verifyEvent(int oldValue, int newValue) {
+ assertNotNull(this.event);
assertEquals(this.compositePVM, this.event.getSource());
assertEquals(PropertyValueModel.VALUE, this.event.getPropertyName());
assertEquals(Integer.valueOf(oldValue), this.event.getOldValue());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoubleModifiablePropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoubleModifiablePropertyValueModelTests.java
index 369d19e5f5..af4dc8ab43 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoubleModifiablePropertyValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoubleModifiablePropertyValueModelTests.java
@@ -10,7 +10,7 @@
package org.eclipse.jpt.common.utility.tests.internal.model.value;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
-import org.eclipse.jpt.common.utility.internal.model.value.ValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
@@ -24,7 +24,7 @@ public class DoubleModifiablePropertyValueModelTests
@Override
protected PropertyValueModel<String> buildDoubleModel(ModifiablePropertyValueModel<ModifiablePropertyValueModel<String>> modelModel) {
- return ValueModelTools.wrapModifiable(modelModel);
+ return PropertyValueModelTools.wrapModifiable(modelModel);
}
protected ModifiablePropertyValueModel<String> getDoubleModel() {
@@ -44,7 +44,13 @@ public class DoubleModifiablePropertyValueModelTests
this.stringModelModel.setValue(null);
assertNull(this.doubleModel.getValue());
- this.getDoubleModel().setValue("TTT"); // NOP?
+ boolean exCaught = false;
+ try {
+ this.getDoubleModel().setValue("TTT"); // unsupported?
+ } catch (IllegalStateException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
assertEquals("bar", this.stringModel.getValue());
assertNull(this.doubleModel.getValue());
}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoublePropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoublePropertyValueModelTests.java
index fef14c236c..d6a5fe85e9 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoublePropertyValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/DoublePropertyValueModelTests.java
@@ -11,7 +11,7 @@ package org.eclipse.jpt.common.utility.tests.internal.model.value;
import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
-import org.eclipse.jpt.common.utility.internal.model.value.ValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
@@ -55,7 +55,7 @@ public class DoublePropertyValueModelTests
}
protected PropertyValueModel<String> buildDoubleModel(ModifiablePropertyValueModel<ModifiablePropertyValueModel<String>> modelModel) {
- return ValueModelTools.wrap(modelModel);
+ return PropertyValueModelTools.wrap(modelModel);
}
@Override
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/FilteringCollectionValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/FilteringCollectionValueModelTests.java
index 92362adabc..011cf3f978 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/FilteringCollectionValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/FilteringCollectionValueModelTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * 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.
@@ -15,6 +15,7 @@ import java.util.Vector;
import junit.framework.TestCase;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
import org.eclipse.jpt.common.utility.internal.model.value.FilteringCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.predicate.PredicateAdapter;
@@ -31,13 +32,13 @@ import org.eclipse.jpt.common.utility.tests.internal.TestTools;
@SuppressWarnings("nls")
public class FilteringCollectionValueModelTests extends TestCase {
- private SimpleCollectionValueModel<String> collectionHolder;
+ private SimpleCollectionValueModel<String> simpleCVM;
CollectionAddEvent addEvent;
CollectionRemoveEvent removeEvent;
CollectionClearEvent collectionClearedEvent;
CollectionChangeEvent collectionChangedEvent;
- private CollectionValueModel<String> filteredCollectionHolder;
+ private CollectionValueModel<String> filteredCVM;
CollectionAddEvent filteredAddEvent;
CollectionRemoveEvent filteredRemoveEvent;
CollectionClearEvent filteredCollectionClearedEvent;
@@ -50,12 +51,12 @@ public class FilteringCollectionValueModelTests extends TestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- this.collectionHolder = new SimpleCollectionValueModel<String>(buildCollection());
- this.filteredCollectionHolder = new FilteringCollectionValueModel<String>(this.collectionHolder, this.buildFilter());
+ this.simpleCVM = new SimpleCollectionValueModel<>(buildCollection());
+ this.filteredCVM = CollectionValueModelTools.filter(this.simpleCVM, this.buildFilter());
}
private Collection<String> buildCollection() {
- Collection<String> collection = new Vector<String>();
+ Collection<String> collection = new Vector<>();
collection.add("foo");
return collection;
}
@@ -81,72 +82,72 @@ public class FilteringCollectionValueModelTests extends TestCase {
public void testIterator() {
// add a listener to "activate" the wrapper
- this.filteredCollectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
+ this.filteredCVM.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
- assertEquals("foo", this.collectionHolder.iterator().next());
- assertFalse(this.filteredCollectionHolder.iterator().hasNext());
+ assertEquals("foo", this.simpleCVM.iterator().next());
+ assertFalse(this.filteredCVM.iterator().hasNext());
- this.collectionHolder.add("bar");
- Iterator<String> collectionHolderValue = this.collectionHolder.iterator();
+ this.simpleCVM.add("bar");
+ Iterator<String> collectionHolderValue = this.simpleCVM.iterator();
assertEquals("foo", collectionHolderValue.next());
assertEquals("bar", collectionHolderValue.next());
- assertTrue(this.filteredCollectionHolder.iterator().hasNext());
- assertEquals("bar", this.filteredCollectionHolder.iterator().next());
+ assertTrue(this.filteredCVM.iterator().hasNext());
+ assertEquals("bar", this.filteredCVM.iterator().next());
- this.collectionHolder.remove("bar");
- assertEquals("foo", this.collectionHolder.iterator().next());
- assertFalse(this.filteredCollectionHolder.iterator().hasNext());
+ this.simpleCVM.remove("bar");
+ assertEquals("foo", this.simpleCVM.iterator().next());
+ assertFalse(this.filteredCVM.iterator().hasNext());
- this.collectionHolder.remove("foo");
- assertFalse(this.collectionHolder.iterator().hasNext());
- assertFalse(this.filteredCollectionHolder.iterator().hasNext());
+ this.simpleCVM.remove("foo");
+ assertFalse(this.simpleCVM.iterator().hasNext());
+ assertFalse(this.filteredCVM.iterator().hasNext());
- this.collectionHolder.add("foo");
- assertEquals("foo", this.collectionHolder.iterator().next());
- assertFalse(this.filteredCollectionHolder.iterator().hasNext());
+ this.simpleCVM.add("foo");
+ assertEquals("foo", this.simpleCVM.iterator().next());
+ assertFalse(this.filteredCVM.iterator().hasNext());
}
public void testSetValue() {
// add a listener to "activate" the wrapper
- this.filteredCollectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
+ this.filteredCVM.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
- Collection<String> newCollection = new Vector<String>();
+ Collection<String> newCollection = new Vector<>();
newCollection.add("fox");
newCollection.add("baz");
- this.collectionHolder.setValues(newCollection);
+ this.simpleCVM.setValues(newCollection);
- Iterator<String> collectionValues = this.collectionHolder.iterator();
+ Iterator<String> collectionValues = this.simpleCVM.iterator();
assertEquals("fox", collectionValues.next());
assertEquals("baz", collectionValues.next());
- Iterator<String> filteredCollectionValues = this.filteredCollectionHolder.iterator();
+ Iterator<String> filteredCollectionValues = this.filteredCVM.iterator();
assertEquals("baz", filteredCollectionValues.next());
assertFalse(filteredCollectionValues.hasNext());
}
public void testLazyListening() {
- assertTrue(((AbstractModel) this.collectionHolder).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
+ assertTrue(((AbstractModel) this.simpleCVM).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
ChangeListener listener = this.buildFilteredChangeListener();
- this.filteredCollectionHolder.addChangeListener(listener);
- assertTrue(((AbstractModel) this.collectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
- this.filteredCollectionHolder.removeChangeListener(listener);
- assertTrue(((AbstractModel) this.collectionHolder).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
-
- this.filteredCollectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
- assertTrue(((AbstractModel) this.collectionHolder).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
- this.filteredCollectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
- assertTrue(((AbstractModel) this.collectionHolder).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
+ this.filteredCVM.addChangeListener(listener);
+ assertTrue(((AbstractModel) this.simpleCVM).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ this.filteredCVM.removeChangeListener(listener);
+ assertTrue(((AbstractModel) this.simpleCVM).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
+
+ this.filteredCVM.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
+ assertTrue(((AbstractModel) this.simpleCVM).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+ this.filteredCVM.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
+ assertTrue(((AbstractModel) this.simpleCVM).hasNoCollectionChangeListeners(CollectionValueModel.VALUES));
}
public void testCollectionChange1() {
- this.collectionHolder.addChangeListener(this.buildChangeListener());
- this.filteredCollectionHolder.addChangeListener(this.buildFilteredChangeListener());
+ this.simpleCVM.addChangeListener(this.buildChangeListener());
+ this.filteredCVM.addChangeListener(this.buildFilteredChangeListener());
this.verifyCollectionChanges();
}
public void testCollectionChange2() {
- this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildListener());
- this.filteredCollectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
+ this.simpleCVM.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildListener());
+ this.filteredCVM.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
this.verifyCollectionChanges();
}
@@ -163,48 +164,48 @@ public class FilteringCollectionValueModelTests extends TestCase {
private void verifyCollectionChanges() {
clearEvents();
- this.collectionHolder.add("bar");
- Collection<String> tempCollection = new Vector<String>();
+ this.simpleCVM.add("bar");
+ Collection<String> tempCollection = new Vector<>();
tempCollection.add("bar");
- this.verifyEvent(this.addEvent, this.collectionHolder, tempCollection);
- this.verifyEvent(this.filteredAddEvent, this.filteredCollectionHolder, tempCollection);
+ this.verifyEvent(this.addEvent, this.simpleCVM, tempCollection);
+ this.verifyEvent(this.filteredAddEvent, this.filteredCVM, tempCollection);
clearEvents();
- this.collectionHolder.remove("foo");
+ this.simpleCVM.remove("foo");
tempCollection.remove("bar");
tempCollection.add("foo");
- this.verifyEvent(this.removeEvent, this.collectionHolder, tempCollection);
+ this.verifyEvent(this.removeEvent, this.simpleCVM, tempCollection);
assertNull(this.filteredRemoveEvent);
clearEvents();
- this.collectionHolder.remove("bar");
+ this.simpleCVM.remove("bar");
tempCollection.add("bar");
tempCollection.remove("foo");
- this.verifyEvent(this.removeEvent, this.collectionHolder, tempCollection);
- this.verifyEvent(this.filteredRemoveEvent, this.filteredCollectionHolder, tempCollection);
+ this.verifyEvent(this.removeEvent, this.simpleCVM, tempCollection);
+ this.verifyEvent(this.filteredRemoveEvent, this.filteredCVM, tempCollection);
clearEvents();
- this.collectionHolder.add("foo");
+ this.simpleCVM.add("foo");
tempCollection.remove("bar");
tempCollection.add("foo");
- this.verifyEvent(this.addEvent, this.collectionHolder, tempCollection);
+ this.verifyEvent(this.addEvent, this.simpleCVM, tempCollection);
assertNull(this.filteredAddEvent);
clearEvents();
- Collection<String> newCollection = new Vector<String>();
+ Collection<String> newCollection = new Vector<>();
newCollection.add("fox");
newCollection.add("baz");
- this.collectionHolder.setValues(newCollection);
+ this.simpleCVM.setValues(newCollection);
- this.verifyEvent(this.collectionChangedEvent, this.collectionHolder);
+ this.verifyEvent(this.collectionChangedEvent, this.simpleCVM);
tempCollection.remove("foo");
tempCollection.add("baz");
- this.verifyEvent(this.filteredCollectionChangedEvent, this.filteredCollectionHolder);
+ this.verifyEvent(this.filteredCollectionChangedEvent, this.filteredCVM);
}
@@ -303,8 +304,8 @@ public class FilteringCollectionValueModelTests extends TestCase {
public void testRemoveFilteredItem() {
// build collection with TestItems
- SimpleCollectionValueModel<TestItem> tiHolder = new SimpleCollectionValueModel<TestItem>(this.buildCollection2());
- CollectionValueModel<TestItem> filteredTIHolder = new FilteringCollectionValueModel<TestItem>(tiHolder, this.buildFilter2());
+ SimpleCollectionValueModel<TestItem> tiHolder = new SimpleCollectionValueModel<>(this.buildCollection2());
+ CollectionValueModel<TestItem> filteredTIHolder = new FilteringCollectionValueModel<>(tiHolder, this.buildFilter2());
// add a listener to "activate" the wrapper
filteredTIHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.buildFilteredListener());
@@ -325,7 +326,7 @@ public class FilteringCollectionValueModelTests extends TestCase {
}
private Collection<TestItem> buildCollection2() {
- Collection<TestItem> collection = new Vector<TestItem>();
+ Collection<TestItem> collection = new Vector<>();
collection.add(new TestItem("foo"));
return collection;
}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
index ea56db400d..ab6f729e9b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/JptCommonUtilityModelValueTests.java
@@ -27,9 +27,11 @@ public class JptCommonUtilityModelValueTests {
suite.addTestSuite(CollectionAspectAdapterTests.class);
suite.addTestSuite(CollectionListValueModelAdapterTests.class);
suite.addTestSuite(CollectionPropertyValueModelAdapterTests.class);
- suite.addTestSuite(CompositeBooleanPropertyValueModelTests.class);
+ suite.addTestSuite(CollectionValueModelToolsTests.class);
+ suite.addTestSuite(CompositeAndBooleanPropertyValueModelTests.class);
suite.addTestSuite(CompositeCollectionValueModelTests.class);
suite.addTestSuite(CompositeListValueModelTests.class);
+ suite.addTestSuite(CompositeOrBooleanPropertyValueModelTests.class);
suite.addTestSuite(CompositePropertyValueModelTests.class);
suite.addTestSuite(DoubleModifiablePropertyValueModelTests.class);
suite.addTestSuite(DoublePropertyValueModelTests.class);
@@ -42,13 +44,17 @@ public class JptCommonUtilityModelValueTests {
suite.addTestSuite(ItemStateListValueModelAdapterTests.class);
suite.addTestSuite(ListAspectAdapterTests.class);
suite.addTestSuite(ListCollectionValueModelAdapterTests.class);
+ suite.addTestSuite(ListCompositePropertyValueModelTests.class);
suite.addTestSuite(ListCuratorTests.class);
+ suite.addTestSuite(ListPropertyValueModelAdapterTests.class);
+ suite.addTestSuite(ListValueModelToolsTests.class);
suite.addTestSuite(NullCollectionValueModelTests.class);
suite.addTestSuite(NullListValueModelTests.class);
suite.addTestSuite(NullPropertyValueModelTests.class);
suite.addTestSuite(PropertyAspectAdapterTests.class);
suite.addTestSuite(PropertyCollectionValueModelAdapterTests.class);
suite.addTestSuite(PropertyListValueModelAdapterTests.class);
+ suite.addTestSuite(PropertyValueModelToolsTests.class);
suite.addTestSuite(ReadOnlyModifiablePropertyValueModelWrapperTests.class);
suite.addTestSuite(SetCollectionValueModelTests.class);
suite.addTestSuite(SimpleCollectionValueModelTests.class);
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCompositePropertyValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCompositePropertyValueModelTests.java
new file mode 100644
index 0000000000..4f28cd8185
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCompositePropertyValueModelTests.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * 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.tests.internal.model.value;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.jpt.common.utility.internal.collection.ListTools;
+import org.eclipse.jpt.common.utility.internal.exception.RuntimeExceptionHandler;
+import org.eclipse.jpt.common.utility.internal.model.ChangeSupport;
+import org.eclipse.jpt.common.utility.internal.model.value.ListValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleListValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
+import org.eclipse.jpt.common.utility.model.listener.ChangeListener;
+import org.eclipse.jpt.common.utility.model.value.ListValueModel;
+import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class ListCompositePropertyValueModelTests
+ extends TestCase
+{
+ private SimplePropertyValueModel<String> pvm1;
+ private ModifiablePropertyValueModel<String> pvm2;
+ private ModifiablePropertyValueModel<String> pvm3;
+ private ModifiablePropertyValueModel<String> pvm4;
+ private List<PropertyValueModel<String>> collection;
+ private SimpleListValueModel<PropertyValueModel<String>> lvm;
+ private PropertyValueModel<String> compositePVM;
+ PropertyChangeEvent event;
+
+
+ public ListCompositePropertyValueModelTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.pvm1 = new SimplePropertyValueModel<>("111");
+ this.pvm2 = new SimplePropertyValueModel<>("222");
+ this.pvm3 = new SimplePropertyValueModel<>("333");
+ this.pvm4 = new SimplePropertyValueModel<>("444");
+ this.collection = new ArrayList<>();
+ this.collection.add(this.pvm1);
+ this.collection.add(this.pvm2);
+ this.collection.add(this.pvm3);
+ this.collection.add(this.pvm4);
+ this.lvm = new LocalSimpleListValueModel<>(this.collection);
+
+ this.compositePVM = this.buildCompositePVM(this.lvm);
+ }
+
+ public static class LocalSimpleListValueModel<E>
+ extends SimpleListValueModel<E>
+ {
+ public LocalSimpleListValueModel(List<E> list) {
+ super(list);
+ }
+ @Override
+ protected ChangeSupport buildChangeSupport() {
+ return new ChangeSupport(this, RuntimeExceptionHandler.instance());
+ }
+ }
+
+ private PropertyValueModel<String> buildCompositePVM(ListValueModel<PropertyValueModel<String>> pvms) {
+ return ListValueModelTools.compositePropertyValueModel(pvms, new LocalTransformer());
+ }
+
+ public static class LocalTransformer
+ extends TransformerAdapter<List<String>, String>
+ {
+ @Override
+ public String transform(List<String> strings) {
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<String> stream = strings.iterator(); stream.hasNext(); ) {
+ String string = stream.next();
+ sb.append(string);
+ if (stream.hasNext()) {
+ sb.append("-");
+ }
+ }
+ return sb.toString();
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ public void testGetValue1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals("111-222-333-444", this.compositePVM.getValue());
+ }
+
+ public void testGetValue2() {
+ ArrayList<PropertyValueModel<String>> list = new ArrayList<>();
+ ListTools.addAll(list, 0, this.lvm);
+ this.compositePVM = ListValueModelTools.compositePropertyValueModel(list, new LocalTransformer());
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals("111-222-333-444", this.compositePVM.getValue());
+ }
+
+ public void testGetValue3() {
+ this.compositePVM = ListValueModelTools.compositePropertyValueModel(new LocalTransformer(), this.pvm1, this.pvm2, this.pvm3, this.pvm4);
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals("111-222-333-444", this.compositePVM.getValue());
+ }
+
+ public void testValueAndListeners1() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ assertEquals("111-222-333-444", this.compositePVM.getValue());
+ this.compositePVM.removeChangeListener(listener);
+ assertNull(this.compositePVM.getValue());
+ }
+
+ public void testValueAndListeners2() {
+ assertNull(this.compositePVM.getValue());
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertEquals("111-222-333-444", this.compositePVM.getValue());
+ this.compositePVM.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertNull(this.compositePVM.getValue());
+ }
+
+ public void testPropertyChange1() {
+ this.compositePVM.addChangeListener(this.buildListener());
+ this.verifyPropertyChange();
+ }
+
+ public void testPropertyChange2() {
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, this.buildListener());
+ this.verifyPropertyChange();
+ }
+
+ private void verifyPropertyChange() {
+ this.event = null;
+ this.pvm1.setValue("555");
+ this.verifyEvent("111-222-333-444", "555-222-333-444");
+
+ this.event = null;
+ this.pvm4.setValue("000");
+ this.verifyEvent("555-222-333-444", "555-222-333-000");
+ }
+
+ public void testListChange1() {
+ this.compositePVM.addChangeListener(this.buildListener());
+ this.verifyListChange();
+ }
+
+ public void testListChange2() {
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, this.buildListener());
+ this.verifyListChange();
+ }
+
+ private void verifyListChange() {
+ this.event = null;
+ ModifiablePropertyValueModel<String> pvm7 = new SimplePropertyValueModel<>("777");
+ this.lvm.add(pvm7);
+ this.verifyEvent("111-222-333-444", "111-222-333-444-777");
+
+ this.event = null;
+ this.lvm.remove(pvm7);
+ this.verifyEvent("111-222-333-444-777", "111-222-333-444");
+
+ this.event = null;
+ ModifiablePropertyValueModel<String> pvmX = new SimplePropertyValueModel<>("XXX");
+ this.lvm.add(2, pvmX);
+ this.verifyEvent("111-222-333-444", "111-222-XXX-333-444");
+
+ this.event = null;
+ this.lvm.move(3, 2);
+ this.verifyEvent("111-222-XXX-333-444", "111-222-333-XXX-444");
+
+ this.event = null;
+ ModifiablePropertyValueModel<String> pvmZ = new SimplePropertyValueModel<>("ZZZ");
+ this.lvm.set(3, pvmZ);
+ this.verifyEvent("111-222-333-XXX-444", "111-222-333-ZZZ-444");
+
+ this.event = null;
+ this.lvm.remove(3);
+ this.verifyEvent("111-222-333-ZZZ-444", "111-222-333-444");
+
+ this.event = null;
+ this.lvm.clear();
+ this.verifyEvent("111-222-333-444", "");
+
+ List<PropertyValueModel<String>> c2 = new ArrayList<>();
+ c2.add(this.pvm1);
+ c2.add(this.pvm2);
+ this.event = null;
+ this.lvm.setListValues(c2);
+ this.verifyEvent("", "111-222");
+ }
+
+ public void testLazyListening1() {
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ ChangeListener listener = this.buildListener();
+
+ this.compositePVM.addChangeListener(listener);
+ assertTrue(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ this.compositePVM.removeChangeListener(listener);
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ }
+
+ public void testLazyListening2() {
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ ChangeListener listener = this.buildListener();
+
+ this.compositePVM.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertTrue(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+ this.compositePVM.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertFalse(this.pvm1.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ }
+
+ public void testCtor_NPE1() {
+ boolean exCaught = false;
+ try {
+ this.compositePVM = this.buildCompositePVM(null);
+ fail("bogus: " + this.compositePVM);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2() {
+ boolean exCaught = false;
+ try {
+ this.compositePVM = ListValueModelTools.compositePropertyValueModel((ListValueModel<PropertyValueModel<String>>) this.lvm, (TransformerAdapter<List<String>, String>) null);
+ fail("bogus: " + this.compositePVM);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testNullPVM() {
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ boolean exCaught = false;
+ try {
+ this.lvm.add(null);
+ fail("bogus: " + this.lvm);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testDuplicatePVM() {
+ ChangeListener listener = this.buildListener();
+ this.compositePVM.addChangeListener(listener);
+ boolean exCaught = false;
+ try {
+ this.lvm.add(this.pvm1);
+ fail("bogus: " + this.lvm);
+ } catch (IllegalStateException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ private ChangeListener buildListener() {
+ return new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ ListCompositePropertyValueModelTests.this.event = e;
+ }
+ };
+ }
+
+ private void verifyEvent(String oldValue, String newValue) {
+ assertNotNull(this.event);
+ assertEquals(this.compositePVM, this.event.getSource());
+ assertEquals(PropertyValueModel.VALUE, this.event.getPropertyName());
+ assertEquals(oldValue, this.event.getOldValue());
+ assertEquals(newValue, this.event.getNewValue());
+ }
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListPropertyValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListPropertyValueModelAdapterTests.java
new file mode 100644
index 0000000000..84ffde9534
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListPropertyValueModelAdapterTests.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * 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.tests.internal.model.value;
+
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
+import org.eclipse.jpt.common.utility.internal.model.value.ListPluggablePropertyValueModelAdapter;
+import org.eclipse.jpt.common.utility.internal.model.value.ListValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleListValueModel;
+import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
+import org.eclipse.jpt.common.utility.model.listener.ChangeAdapter;
+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.ListValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class ListPropertyValueModelAdapterTests
+ extends TestCase
+{
+ private PropertyValueModel<Boolean> adapter;
+ private SimpleListValueModel<String> listModel;
+ PropertyChangeEvent event;
+
+ public ListPropertyValueModelAdapterTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.listModel = new SimpleListValueModel<>();
+ this.adapter = ListValueModelTools.propertyValueModel(this.listModel, new LocalTransformer(2, "666"));
+ this.event = null;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ TestTools.clear(this);
+ super.tearDown();
+ }
+
+ private boolean booleanValue() {
+ Boolean value = this.adapter.getValue();
+ return (value != null) && value.booleanValue();
+ }
+
+ private boolean listModelContains(int index, String value) {
+ return (this.listModel.size() > index) && ObjectTools.equals(this.listModel.get(index), value);
+ }
+
+ public void testValue() {
+ assertNull(this.adapter.getValue());
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ });
+ assertFalse(this.booleanValue());
+ assertFalse(this.listModelContains(2, "666"));
+
+ this.listModel.add("111");
+ assertFalse(this.booleanValue());
+
+ this.listModel.add("222");
+ assertFalse(this.booleanValue());
+
+ this.listModel.add("666");
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.listModel.remove("666");
+ assertFalse(this.booleanValue());
+ assertFalse(this.listModelContains(2, "666"));
+
+ this.listModel.add("666");
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.listModel.clear();
+ assertFalse(this.booleanValue());
+ assertFalse(this.listModelContains(2, "666"));
+
+ this.listModel.add("111");
+ this.listModel.add("222");
+ this.listModel.add("666");
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.listModel.set(2, "333");
+ assertFalse(this.booleanValue());
+ assertFalse(this.listModelContains(2, "666"));
+
+ this.listModel.set(2, "666");
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.listModel.move(0, 2);
+ assertFalse(this.booleanValue());
+ assertTrue(this.listModelContains(0, "666"));
+
+ this.listModel.setListValues(Arrays.asList("111", "222", "666"));
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+ }
+
+ public void testEventFiring() {
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {
+ ListPropertyValueModelAdapterTests.this.event = e;
+ }
+ });
+ assertNull(this.event);
+
+ this.listModel.add("111");
+ assertNull(this.event);
+
+ this.listModel.add("222");
+ assertNull(this.event);
+
+ this.listModel.add("666");
+ this.verifyEvent(false, true);
+
+ this.listModel.remove("666");
+ this.verifyEvent(true, false);
+
+ this.listModel.add("666");
+ this.verifyEvent(false, true);
+
+ this.listModel.clear();
+ this.verifyEvent(true, false);
+ }
+
+ private void verifyEvent(boolean oldValue, boolean newValue) {
+ assertEquals(this.adapter, this.event.getSource());
+ assertEquals(Boolean.valueOf(oldValue), this.event.getOldValue());
+ assertEquals(Boolean.valueOf(newValue), this.event.getNewValue());
+ this.event = null;
+ }
+
+ public void testStaleValue() {
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ };
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ this.listModel.add("111");
+ this.listModel.add("222");
+ this.listModel.add("666");
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.adapter.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertFalse(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertTrue(this.booleanValue());
+ assertTrue(this.listModelContains(2, "666"));
+ }
+
+ public void testHasListeners() {
+ assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertFalse(((AbstractModel) this.listModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ ChangeListener listener = new ChangeAdapter() {
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ };
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertTrue(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.listModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ this.adapter.removePropertyChangeListener(PropertyValueModel.VALUE, listener);
+ assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertFalse(((AbstractModel) this.listModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ this.adapter.addChangeListener(listener);
+ assertTrue(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertTrue(((AbstractModel) this.listModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+ this.adapter.removeChangeListener(listener);
+ assertFalse(((AbstractModel) this.adapter).hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+ assertFalse(((AbstractModel) this.listModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+ }
+
+ public void testToString1() {
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ });
+ assertTrue(this.adapter.toString().endsWith("(false)"));
+ this.listModel.add("111");
+ this.listModel.add("222");
+ this.listModel.add("666");
+ assertTrue(this.adapter.toString().endsWith("(true)"));
+ }
+
+ public void testToString3() {
+ ListPluggablePropertyValueModelAdapter.Factory<String, Boolean> f = new ListPluggablePropertyValueModelAdapter.Factory<>(this.listModel, new LocalTransformer(2, "666"));
+ assertTrue(f.toString().indexOf("Factory") != -1);
+ }
+
+ public void testToString4() {
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {/* OK */}
+ };
+ this.adapter.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ Object a = ObjectTools.get(this.adapter, "adapter");
+ Object l = ObjectTools.get(a, "listener");
+ assertTrue(l.toString().indexOf("AdapterListener") != -1);
+ }
+
+ public void testCtor_NPE1A() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = ListValueModelTools.propertyValueModel(null, new LocalTransformer(2, "666"));
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE1B() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = ListValueModelTools.propertyValueModel(null, new LocalTransformer(2, "666"));
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2A() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = ListValueModelTools.propertyValueModel(this.listModel, null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE2B() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = ListValueModelTools.propertyValueModel(this.listModel, null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testCtor_NPE4() {
+ Object object;
+ boolean exCaught = false;
+ try {
+ object = PropertyValueModelTools.propertyValueModel(null);
+ fail("bogus: " + object);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+
+ // ********** member class **********
+
+ /**
+ * Transform the list to <code>true</code> if it contains the specified item
+ * at the specified index, otherwise transform it to <code>false</code>.
+ */
+ static class LocalTransformer
+ implements Transformer<List<String>, Boolean>
+ {
+ private final int index;
+ private final String item;
+
+ LocalTransformer(int index, String item) {
+ super();
+ this.index = index;
+ this.item = item;
+ }
+
+ public Boolean transform(List<String> list) {
+ return Boolean.valueOf(this.transform_(list));
+ }
+
+ public boolean transform_(List<String> list) {
+ return (list.size() > this.index) && ObjectTools.equals(this.item, list.get(this.index));
+ }
+
+ @Override
+ public String toString() {
+ return ObjectTools.toString(this, this.item);
+ }
+ }
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListValueModelToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListValueModelToolsTests.java
new file mode 100644
index 0000000000..12ce703f86
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListValueModelToolsTests.java
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ * Copyright (c) 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.tests.internal.model.value;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.closure.BooleanClosure;
+import org.eclipse.jpt.common.utility.internal.model.value.ListValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleListValueModel;
+import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
+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.value.ModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class ListValueModelToolsTests
+ extends TestCase
+{
+ public ListValueModelToolsTests(String name) {
+ super(name);
+ }
+
+ public void testFirstElementPVMAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<String> pvm = ListValueModelTools.firstElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertEquals("foo", pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testLastElementPVMAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<String> pvm = ListValueModelTools.lastElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertEquals("bar", pvm.getValue());
+ assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testSingleElementPVMAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<String> pvm = ListValueModelTools.singleElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertNull(pvm.getValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertEquals("foo", pvm.getValue());
+ assertEquals("foo", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertEquals("bar", pvm.getValue());
+ assertEquals("bar", listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertNull(pvm.getValue());
+ assertNull(listener.event.getNewValue());
+ }
+
+ public void testIsNotEmptyPropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<Boolean> pvm = ListValueModelTools.isNotEmptyPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public void testIsNotEmptyModifiablePropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ BooleanClosure.Adapter adapter = new NotEmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = ListValueModelTools.isNotEmptyModifiablePropertyValueModel(cvm, adapter);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ pvm.setValue(Boolean.FALSE);
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ assertEquals(0, cvm.size());
+
+ listener.event = null;
+ pvm.setValue(Boolean.TRUE);
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ assertEquals(2, cvm.size());
+ assertTrue(cvm.contains("baz"));
+ assertTrue(cvm.contains("xxx"));
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("xxx");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public static class NotEmptyBooleanClosureAdapter
+ implements BooleanClosure.Adapter
+ {
+ final SimpleListValueModel<String> cvm;
+ public NotEmptyBooleanClosureAdapter(SimpleListValueModel<String> cvm) {
+ this.cvm = cvm;
+ }
+ public void execute(boolean argument) {
+ if (argument) {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("baz");
+ list.add("xxx");
+ this.cvm.setListValues(list);
+ } else {
+ this.cvm.clear();
+ }
+ }
+ }
+
+ public void testIsEmptyPropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<Boolean> pvm = ListValueModelTools.isEmptyPropertyValueModel(cvm);
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ private void verifyIsEmptyPropertyValueModelAdapter(SimpleListValueModel<String> cvm, PropertyValueModel<Boolean> pvm) {
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ }
+
+ public void testBooleanPVM() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<Boolean> pvm = ListValueModelTools.booleanPropertyValueModel(cvm, PredicateTools.collectionIsEmptyPredicate());
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ public void testIsEmptyModifiablePropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ BooleanClosure.Adapter adapter = new EmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = ListValueModelTools.isEmptyModifiablePropertyValueModel(cvm, adapter);
+ this.verifyIsEmptyModifiablePropertyValueModelAdapter(cvm, pvm);
+ }
+
+ public void testBooleanModifiablePVM() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ BooleanClosure.Adapter adapter = new EmptyBooleanClosureAdapter(cvm);
+ ModifiablePropertyValueModel<Boolean> pvm = ListValueModelTools.booleanModifiablePropertyValueModel(cvm, PredicateTools.collectionIsEmptyPredicate(), adapter);
+ this.verifyIsEmptyPropertyValueModelAdapter(cvm, pvm);
+ }
+
+ private void verifyIsEmptyModifiablePropertyValueModelAdapter(SimpleListValueModel<String> cvm, ModifiablePropertyValueModel<Boolean> pvm) {
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertTrue(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ pvm.setValue(Boolean.TRUE);
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ assertEquals(0, cvm.size());
+
+ listener.event = null;
+ pvm.setValue(Boolean.FALSE);
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ assertEquals(2, cvm.size());
+ assertTrue(cvm.contains("baz"));
+ assertTrue(cvm.contains("xxx"));
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.remove("xxx");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+ }
+
+ public static class EmptyBooleanClosureAdapter
+ implements BooleanClosure.Adapter
+ {
+ final SimpleListValueModel<String> cvm;
+ public EmptyBooleanClosureAdapter(SimpleListValueModel<String> cvm) {
+ this.cvm = cvm;
+ }
+ public void execute(boolean argument) {
+ if (argument) {
+ this.cvm.clear();
+ } else {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("baz");
+ list.add("xxx");
+ this.cvm.setListValues(list);
+ }
+ }
+ }
+
+ public void testContainsSingleElementPropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<Boolean> pvm = ListValueModelTools.containsSingleElementPropertyValueModel(cvm);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+ }
+
+ public void testSizeEqualsPropertyValueModelAdapter() {
+ SimpleListValueModel<String> cvm = new SimpleListValueModel<>();
+ PropertyValueModel<Boolean> pvm = ListValueModelTools.sizeEqualsPropertyValueModel(cvm, 2);
+ LocalPropertyChangeListener listener = new LocalPropertyChangeListener();
+ pvm.addPropertyChangeListener(PropertyValueModel.VALUE, listener);
+
+ listener.event = null;
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+
+ listener.event = null;
+ cvm.add("bar");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.add("baz");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("baz");
+ assertTrue(pvm.getValue().booleanValue());
+ assertEquals(Boolean.TRUE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("foo");
+ assertFalse(pvm.getValue().booleanValue());
+ assertEquals(Boolean.FALSE, listener.event.getNewValue());
+
+ listener.event = null;
+ cvm.remove("bar");
+ assertFalse(pvm.getValue().booleanValue());
+ assertNull(listener.event);
+ }
+
+ public static class LocalPropertyChangeListener
+ extends PropertyChangeAdapter
+ {
+ public PropertyChangeEvent event;
+ public LocalPropertyChangeListener() {
+ super();
+ }
+ @Override
+ public void propertyChanged(PropertyChangeEvent e) {
+ this.event = e;
+ }
+ }
+
+ public void testConstructor() {
+ boolean exCaught = false;
+ try {
+ Object o = ClassTools.newInstance(ListValueModelTools.class);
+ fail("bogus: " + o); //$NON-NLS-1$
+ } catch (RuntimeException ex) {
+ if (ex.getCause() instanceof InvocationTargetException) {
+ if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+ exCaught = true;
+ }
+ }
+ }
+ assertTrue(exCaught);
+ }
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyValueModelToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyValueModelToolsTests.java
new file mode 100644
index 0000000000..1943731ab0
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyValueModelToolsTests.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 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.tests.internal.model.value;
+
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.jpt.common.utility.closure.Closure;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.model.value.CollectionValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggableModifiablePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggableModifiablePropertyValueModel.Adapter;
+import org.eclipse.jpt.common.utility.internal.model.value.PluggablePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.PropertyValueModelTools;
+import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
+import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
+import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
+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;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class PropertyValueModelToolsTests
+ extends TestCase
+{
+
+ public PropertyValueModelToolsTests(String name) {
+ super(name);
+ }
+
+ public void testModifiablePropertyValueModel() {
+ ModifiablePropertyValueModel<String> doubleStringModel = new SimplePropertyValueModel<>("foofoo");
+ PluggableModifiablePropertyValueModel.Adapter.Factory<String> factory = new HalfStringModelAdapter.Factory(doubleStringModel);
+ ModifiablePropertyValueModel<String> halfStringModel = PropertyValueModelTools.modifiablePropertyValueModel(factory);
+ HalfStringListener halfStringListener = new HalfStringListener();
+ halfStringModel.addPropertyChangeListener(PropertyValueModel.VALUE, halfStringListener);
+
+ halfStringListener.event = null;
+ assertEquals("foofoo", doubleStringModel.getValue());
+ assertEquals("foo", halfStringModel.getValue());
+ assertNull(halfStringListener.event);
+
+ halfStringListener.event = null;
+ halfStringModel.setValue("bar");
+ assertEquals("bar", halfStringModel.getValue());
+ assertEquals("barbar", doubleStringModel.getValue());
+ assertEquals("bar", halfStringListener.event.getNewValue());
+
+ halfStringListener.event = null;
+ halfStringModel.setValue("bar");
+ assertEquals("bar", halfStringModel.getValue());
+ assertEquals("barbar", doubleStringModel.getValue());
+ assertNull(halfStringListener.event);
+
+ halfStringListener.event = null;
+ doubleStringModel.setValue("xxxxxx");
+ assertEquals("xxx", halfStringModel.getValue());
+ assertEquals("xxxxxx", doubleStringModel.getValue());
+ assertEquals("xxx", halfStringListener.event.getNewValue());
+
+ halfStringListener.event = null;
+ halfStringModel.removePropertyChangeListener(PropertyValueModel.VALUE, halfStringListener);
+ assertNull(halfStringModel.getValue());
+ assertEquals("xxxxxx", doubleStringModel.getValue());
+ assertNull(halfStringListener.event);
+ }
+
+ public static class HalfStringListener
+ implements PropertyChangeListener
+ {
+ public PropertyChangeEvent event;
+ public void propertyChanged(PropertyChangeEvent e) {
+ this.event = e;
+ }
+ }
+
+ public static class HalfStringModelAdapter
+ implements PluggableModifiablePropertyValueModel.Adapter<String>
+ {
+ private final ModifiablePropertyValueModel<String> stringModel;
+ private final PluggableModifiablePropertyValueModel.Adapter.Listener<String> listener;
+ private final PropertyChangeListener stringListener;
+ private volatile String value;
+
+ public HalfStringModelAdapter(ModifiablePropertyValueModel<String> stringModel, PluggableModifiablePropertyValueModel.Adapter.Listener<String> listener) {
+ super();
+ this.stringModel = stringModel;
+ this.listener = listener;
+ this.stringListener = new StringListener();
+ this.value = null;
+ }
+
+ public void engageModel() {
+ this.stringModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+ String v = this.stringModel.getValue();
+ this.value = v.substring(v.length() / 2);
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ this.stringModel.setValue(value + value);
+ }
+
+ public void disengageModel() {
+ this.value = null;
+ this.stringModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+ }
+
+ void stringChanged(String newStringValue) {
+ String newValue = newStringValue.substring(newStringValue.length() / 2);
+ this.value = newValue;
+ this.listener.valueChanged(newValue);
+ }
+
+ public class StringListener
+ implements PropertyChangeListener
+ {
+ public void propertyChanged(PropertyChangeEvent event) {
+ HalfStringModelAdapter.this.stringChanged((String) event.getNewValue());
+ }
+ }
+
+ public static class Factory
+ implements PluggableModifiablePropertyValueModel.Adapter.Factory<String>
+ {
+ private final ModifiablePropertyValueModel<String> stringModel;
+ public Factory(ModifiablePropertyValueModel<String> stringModel) {
+ super();
+ this.stringModel = stringModel;
+ }
+ public Adapter<String> buildAdapter(PluggableModifiablePropertyValueModel.Adapter.Listener<String> listener) {
+ return new HalfStringModelAdapter(this.stringModel, listener);
+ }
+ }
+ }
+
+ public void testPluggableModifiablePropertyValueModel_NPE() {
+ PluggablePropertyValueModel.Adapter.Factory<String> factory = CollectionValueModelTools.pluggablePropertyValueModelAdapterFactory(new SimpleCollectionValueModel<>(), new TransformerAdapter<>());
+ Closure<String> closure = null;
+ boolean exCaught = false;
+ try {
+ ModifiablePropertyValueModel<String> pvm = PropertyValueModelTools.pluggableModifiablePropertyValueModel(factory, closure);
+ fail("bogus: " + pvm);
+ } catch (NullPointerException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testConstructor() {
+ boolean exCaught = false;
+ try {
+ Object o = ClassTools.newInstance(PropertyValueModelTools.class);
+ fail("bogus: " + o);
+ } catch (RuntimeException ex) {
+ if (ex.getCause() instanceof InvocationTargetException) {
+ if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+ exCaught = true;
+ }
+ }
+ }
+ assertTrue(exCaught);
+ }
+}

Back to the top