1 /*******************************************************************************
2  * Copyright (c) 2010, 2017 Ovidio Mallo 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  *     Ovidio Mallo - initial API and implementation (bug 305367)
13  *     Stefan Xenos <sxenos@gmail.com> - Bug 335792
14  ******************************************************************************/
15 
16 package org.eclipse.core.internal.databinding.observable.masterdetail;
17 
18 import java.util.HashMap;
19 import java.util.Map;
20 
21 import org.eclipse.core.databinding.observable.IObserving;
22 import org.eclipse.core.databinding.observable.IStaleListener;
23 import org.eclipse.core.databinding.observable.ObservableTracker;
24 import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
25 import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
26 import org.eclipse.core.databinding.observable.set.IObservableSet;
27 import org.eclipse.core.databinding.observable.value.IObservableValue;
28 import org.eclipse.core.internal.databinding.identity.IdentitySet;
29 
30 /**
31  * @param <M>
32  *            type of the master observables in the master set
33  * @param <E>
34  *            type of the detail elements
35  * @since 1.4
36  */
37 public class SetDetailValueObservableMap<M, E> extends
38 		ComputedObservableMap<M, E> implements IObserving {
39 
40 	private IObservableFactory<? super M, IObservableValue<E>> observableValueFactory;
41 
42 	private Map<M, IObservableValue<E>> detailObservableValueMap = new HashMap<>();
43 
44 	private IdentitySet<IObservableValue<?>> staleDetailObservables = new IdentitySet<>();
45 
46 	private IStaleListener detailStaleListener = staleEvent -> addStaleDetailObservable(
47 			(IObservableValue<?>) staleEvent.getObservable());
48 
49 	/**
50 	 * @param masterKeySet
51 	 * @param observableValueFactory
52 	 * @param detailValueType
53 	 */
SetDetailValueObservableMap( IObservableSet<M> masterKeySet, IObservableFactory<? super M, IObservableValue<E>> observableValueFactory, Object detailValueType)54 	public SetDetailValueObservableMap(
55 			IObservableSet<M> masterKeySet,
56 			IObservableFactory<? super M, IObservableValue<E>> observableValueFactory,
57 			Object detailValueType) {
58 		super(masterKeySet, detailValueType);
59 		this.observableValueFactory = observableValueFactory;
60 	}
61 
62 	@Override
hookListener(final M addedKey)63 	protected void hookListener(final M addedKey) {
64 		final IObservableValue<E> detailValue = getDetailObservableValue(addedKey);
65 
66 		detailValue.addValueChangeListener(event -> {
67 			if (!event.getObservableValue().isStale()) {
68 				staleDetailObservables.remove(detailValue);
69 			}
70 
71 			fireSingleChange(addedKey, event.diff.getOldValue(), event.diff.getNewValue());
72 		});
73 
74 		detailValue.addStaleListener(detailStaleListener);
75 	}
76 
77 	@Override
unhookListener(Object removedKey)78 	protected void unhookListener(Object removedKey) {
79 		if (isDisposed()) {
80 			return;
81 		}
82 
83 		IObservableValue<E> detailValue = detailObservableValueMap.remove(removedKey);
84 		staleDetailObservables.remove(detailValue);
85 		detailValue.dispose();
86 	}
87 
getDetailObservableValue(M masterKey)88 	private IObservableValue<E> getDetailObservableValue(M masterKey) {
89 		IObservableValue<E> detailValue = detailObservableValueMap.get(masterKey);
90 
91 		if (detailValue == null) {
92 			ObservableTracker.setIgnore(true);
93 			try {
94 				detailValue = observableValueFactory.createObservable(masterKey);
95 			} finally {
96 				ObservableTracker.setIgnore(false);
97 			}
98 
99 			detailObservableValueMap.put(masterKey, detailValue);
100 
101 			if (detailValue.isStale()) {
102 				addStaleDetailObservable(detailValue);
103 			}
104 		}
105 
106 		return detailValue;
107 	}
108 
addStaleDetailObservable(IObservableValue<?> detailObservable)109 	private void addStaleDetailObservable(IObservableValue<?> detailObservable) {
110 		boolean wasStale = isStale();
111 		staleDetailObservables.add(detailObservable);
112 		if (!wasStale) {
113 			fireStale();
114 		}
115 	}
116 
117 	@Override
doGet(M key)118 	protected E doGet(M key) {
119 		IObservableValue<E> detailValue = getDetailObservableValue(key);
120 		return detailValue.getValue();
121 	}
122 
123 	@Override
doPut(M key, E value)124 	protected E doPut(M key, E value) {
125 		IObservableValue<E> detailValue = getDetailObservableValue(key);
126 		E oldValue = detailValue.getValue();
127 		detailValue.setValue(value);
128 		return oldValue;
129 	}
130 
131 	@Override
containsKey(Object key)132 	public boolean containsKey(Object key) {
133 		getterCalled();
134 
135 		return keySet().contains(key);
136 	}
137 
138 	@Override
remove(Object key)139 	public E remove(Object key) {
140 		checkRealm();
141 
142 		if (!containsKey(key)) {
143 			return null;
144 		}
145 
146 		@SuppressWarnings("unchecked")
147 		IObservableValue<E> detailValue = getDetailObservableValue((M) key);
148 		E oldValue = detailValue.getValue();
149 
150 		keySet().remove(key);
151 
152 		return oldValue;
153 	}
154 
155 	@Override
size()156 	public int size() {
157 		getterCalled();
158 
159 		return keySet().size();
160 	}
161 
162 	@Override
isStale()163 	public boolean isStale() {
164 		return super.isStale() || staleDetailObservables != null
165 				&& !staleDetailObservables.isEmpty();
166 	}
167 
168 	@Override
getObserved()169 	public Object getObserved() {
170 		return keySet();
171 	}
172 
173 	@Override
dispose()174 	public synchronized void dispose() {
175 		super.dispose();
176 
177 		observableValueFactory = null;
178 		detailObservableValueMap = null;
179 		detailStaleListener = null;
180 		staleDetailObservables = null;
181 	}
182 
getterCalled()183 	private void getterCalled() {
184 		ObservableTracker.getterCalled(this);
185 	}
186 }
187