1 /******************************************************************************* 2 * Copyright (c) 2008, 2017 Matthew Hall and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Matthew Hall - initial API and implementation (bug 194734) 13 * Matthew Hall - bug 195222 14 * Ovidio Mallo - bug 331348 15 * Stefan Xenos <sxenos@gmail.com> - Bug 335792 16 ******************************************************************************/ 17 18 package org.eclipse.core.databinding.property.set; 19 20 import java.util.Collections; 21 import java.util.Set; 22 23 import org.eclipse.core.databinding.observable.Diffs; 24 import org.eclipse.core.databinding.observable.Realm; 25 import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory; 26 import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables; 27 import org.eclipse.core.databinding.observable.set.IObservableSet; 28 import org.eclipse.core.databinding.observable.set.SetDiff; 29 import org.eclipse.core.databinding.observable.value.IObservableValue; 30 import org.eclipse.core.databinding.property.map.IMapProperty; 31 import org.eclipse.core.databinding.property.value.IValueProperty; 32 import org.eclipse.core.internal.databinding.identity.IdentitySet; 33 import org.eclipse.core.internal.databinding.property.SetPropertyDetailValuesMap; 34 35 /** 36 * Abstract implementation of ISetProperty 37 * 38 * @param <S> type of the source object 39 * @param <E> type of the elements in the set 40 * @since 1.2 41 * @implNote If methods are added to the interface which this class implements 42 * then implementations of those methods must be added to this class. 43 */ 44 public abstract class SetProperty<S, E> implements ISetProperty<S, E> { 45 46 /** 47 * By default, this method returns <code>Collections.EMPTY_SET</code> in 48 * case the source object is <code>null</code>. Otherwise, this method 49 * delegates to {@link #doGetSet(Object)}. 50 * 51 * <p> 52 * Clients may override this method if they e.g. want to return a specific 53 * default set in case the source object is <code>null</code>. 54 * </p> 55 * 56 * @see #doGetSet(Object) 57 * 58 * @since 1.3 59 */ 60 @Override getSet(S source)61 public Set<E> getSet(S source) { 62 if (source == null) { 63 return Collections.emptySet(); 64 } 65 return Collections.unmodifiableSet(doGetSet(source)); 66 } 67 68 /** 69 * Returns a Set with the current contents of the source's set property 70 * 71 * @param source 72 * the property source 73 * @return a Set with the current contents of the source's set property 74 * @since 1.6 75 * @noreference This method is not intended to be referenced by clients. 76 */ doGetSet(S source)77 protected Set<E> doGetSet(S source) { 78 IObservableSet<E> observable = observe(source); 79 try { 80 return new IdentitySet<>(observable); 81 } finally { 82 observable.dispose(); 83 } 84 } 85 86 /** 87 * @since 1.3 88 */ 89 @Override setSet(S source, Set<E> set)90 public final void setSet(S source, Set<E> set) { 91 if (source != null) { 92 doSetSet(source, set); 93 } 94 } 95 96 /** 97 * Updates the property on the source with the specified change. 98 * 99 * @param source 100 * the property source 101 * @param set 102 * the new set 103 * @since 1.6 104 * @noreference This method is not intended to be referenced by clients. 105 */ doSetSet(S source, Set<E> set)106 protected void doSetSet(S source, Set<E> set) { 107 doUpdateSet(source, Diffs.computeSetDiff(doGetSet(source), set)); 108 } 109 110 /** 111 * @since 1.3 112 */ 113 @Override updateSet(S source, SetDiff<E> diff)114 public final void updateSet(S source, SetDiff<E> diff) { 115 if (source != null && !diff.isEmpty()) { 116 doUpdateSet(source, diff); 117 } 118 } 119 120 /** 121 * Updates the property on the source with the specified change. 122 * 123 * @param source 124 * the property source 125 * @param diff 126 * a diff describing the change 127 * @since 1.6 128 * @noreference This method is not intended to be referenced by clients. 129 */ doUpdateSet(S source, SetDiff<E> diff)130 protected void doUpdateSet(S source, SetDiff<E> diff) { 131 IObservableSet<E> observable = observe(source); 132 try { 133 diff.applyTo(observable); 134 } finally { 135 observable.dispose(); 136 } 137 } 138 139 @Override observe(S source)140 public IObservableSet<E> observe(S source) { 141 return observe(Realm.getDefault(), source); 142 } 143 144 @Override setFactory()145 public IObservableFactory<S, IObservableSet<E>> setFactory() { 146 return this::observe; 147 } 148 149 @Override setFactory(final Realm realm)150 public IObservableFactory<S, IObservableSet<E>> setFactory(final Realm realm) { 151 return target -> observe(realm, target); 152 } 153 154 @Override observeDetail(IObservableValue<U> master)155 public <U extends S> IObservableSet<E> observeDetail(IObservableValue<U> master) { 156 return MasterDetailObservables.detailSet(master, setFactory(master.getRealm()), getElementType()); 157 } 158 159 @Override values(IValueProperty<? super E, T> detailValues)160 public final <T> IMapProperty<S, E, T> values(IValueProperty<? super E, T> detailValues) { 161 return new SetPropertyDetailValuesMap<>(this, detailValues); 162 } 163 } 164