78
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2008 Matthew Hall and others.
|
|
3 * All rights reserved. This program and the accompanying materials
|
|
4 * are made available under the terms of the Eclipse Public License v1.0
|
|
5 * which accompanies this distribution, and is available at
|
|
6 * http://www.eclipse.org/legal/epl-v10.html
|
|
7 *
|
|
8 * Contributors:
|
|
9 * Matthew Hall - initial API and implementation (bug 124684)
|
|
10 * IBM Corporation - through ListBinding.java
|
|
11 ******************************************************************************/
|
|
12
|
|
13 module org.eclipse.core.databinding.SetBinding;
|
|
14
|
|
15 import java.lang.all;
|
|
16
|
|
17 import java.util.Collections;
|
|
18 import java.util.Iterator;
|
|
19
|
|
20 import org.eclipse.core.databinding.observable.Diffs;
|
|
21 import org.eclipse.core.databinding.observable.set.IObservableSet;
|
|
22 import org.eclipse.core.databinding.observable.set.ISetChangeListener;
|
|
23 import org.eclipse.core.databinding.observable.set.SetChangeEvent;
|
|
24 import org.eclipse.core.databinding.observable.set.SetDiff;
|
|
25 import org.eclipse.core.databinding.observable.value.IObservableValue;
|
|
26 import org.eclipse.core.databinding.observable.value.WritableValue;
|
|
27 import org.eclipse.core.internal.databinding.BindingStatus;
|
|
28 import org.eclipse.core.runtime.IStatus;
|
|
29 import org.eclipse.core.runtime.MultiStatus;
|
|
30 import org.eclipse.core.runtime.Status;
|
|
31
|
|
32 /**
|
|
33 * @since 1.1
|
|
34 *
|
|
35 */
|
|
36 public class SetBinding : Binding {
|
|
37
|
|
38 private UpdateSetStrategy targetToModel;
|
|
39 private UpdateSetStrategy modelToTarget;
|
|
40 private IObservableValue validationStatusObservable;
|
|
41 private bool updatingTarget;
|
|
42 private bool updatingModel;
|
|
43
|
|
44 private ISetChangeListener targetChangeListener = new class() ISetChangeListener {
|
|
45 public void handleSetChange(SetChangeEvent event) {
|
|
46 if (!updatingTarget) {
|
|
47 doUpdate(cast(IObservableSet) getTarget(),
|
|
48 cast(IObservableSet) getModel(), event.diff, targetToModel,
|
|
49 false, false);
|
|
50 }
|
|
51 }
|
|
52 };
|
|
53
|
|
54 private ISetChangeListener modelChangeListener = new class() ISetChangeListener {
|
|
55 public void handleSetChange(SetChangeEvent event) {
|
|
56 if (!updatingModel) {
|
|
57 doUpdate(cast(IObservableSet) getModel(),
|
|
58 cast(IObservableSet) getTarget(), event.diff,
|
|
59 modelToTarget, false, false);
|
|
60 }
|
|
61 }
|
|
62 };
|
|
63
|
|
64 /**
|
|
65 * @param target
|
|
66 * @param model
|
|
67 * @param modelToTargetStrategy
|
|
68 * @param targetToModelStrategy
|
|
69 */
|
|
70 public this(IObservableSet target, IObservableSet model,
|
|
71 UpdateSetStrategy targetToModelStrategy,
|
|
72 UpdateSetStrategy modelToTargetStrategy) {
|
|
73 super(target, model);
|
|
74 this.targetToModel = targetToModelStrategy;
|
|
75 this.modelToTarget = modelToTargetStrategy;
|
|
76 if ((targetToModel.getUpdatePolicy() & UpdateSetStrategy.POLICY_UPDATE) !is 0) {
|
|
77 target.addSetChangeListener(targetChangeListener);
|
|
78 } else {
|
|
79 targetChangeListener = null;
|
|
80 }
|
|
81 if ((modelToTarget.getUpdatePolicy() & UpdateSetStrategy.POLICY_UPDATE) !is 0) {
|
|
82 model.addSetChangeListener(modelChangeListener);
|
|
83 } else {
|
|
84 modelChangeListener = null;
|
|
85 }
|
|
86 }
|
|
87
|
|
88 public IObservableValue getValidationStatus() {
|
|
89 return validationStatusObservable;
|
|
90 }
|
|
91
|
|
92 protected void preInit() {
|
|
93 validationStatusObservable = new WritableValue(context
|
|
94 .getValidationRealm(), Status.OK_STATUS, IStatus.classinfo);
|
|
95 }
|
|
96
|
|
97 protected void postInit() {
|
|
98 if (modelToTarget.getUpdatePolicy() is UpdateSetStrategy.POLICY_UPDATE) {
|
|
99 updateModelToTarget();
|
|
100 }
|
|
101 if (targetToModel.getUpdatePolicy() !is UpdateSetStrategy.POLICY_NEVER) {
|
|
102 validateTargetToModel();
|
|
103 }
|
|
104 }
|
|
105
|
|
106 public void updateModelToTarget() {
|
|
107 final IObservableSet modelSet = cast(IObservableSet) getModel();
|
|
108 modelSet.getRealm().exec(new class() Runnable {
|
|
109 public void run() {
|
|
110 SetDiff diff = Diffs.computeSetDiff(Collections.EMPTY_SET,
|
|
111 modelSet);
|
|
112 doUpdate(modelSet, cast(IObservableSet) getTarget(), diff,
|
|
113 modelToTarget, true, true);
|
|
114 }
|
|
115 });
|
|
116 }
|
|
117
|
|
118 public void updateTargetToModel() {
|
|
119 final IObservableSet targetSet = cast(IObservableSet) getTarget();
|
|
120 targetSet.getRealm().exec(new class() Runnable {
|
|
121 public void run() {
|
|
122 SetDiff diff = Diffs.computeSetDiff(Collections.EMPTY_SET,
|
|
123 targetSet);
|
|
124 doUpdate(targetSet, cast(IObservableSet) getModel(), diff,
|
|
125 targetToModel, true, true);
|
|
126 }
|
|
127 });
|
|
128 }
|
|
129
|
|
130 public void validateModelToTarget() {
|
|
131 // nothing for now
|
|
132 }
|
|
133
|
|
134 public void validateTargetToModel() {
|
|
135 // nothing for now
|
|
136 }
|
|
137
|
|
138 /*
|
|
139 * This method may be moved to UpdateSetStrategy in the future if clients
|
|
140 * need more control over how the two sets are kept in sync.
|
|
141 */
|
|
142 private void doUpdate(IObservableSet source,
|
|
143 IObservableSet destination, SetDiff diff,
|
|
144 UpdateSetStrategy updateSetStrategy, bool explicit,
|
|
145 bool clearDestination) {
|
|
146 final int policy = updateSetStrategy.getUpdatePolicy();
|
|
147 if (policy is UpdateSetStrategy.POLICY_NEVER)
|
|
148 return;
|
|
149 if (policy is UpdateSetStrategy.POLICY_ON_REQUEST && !explicit)
|
|
150 return;
|
|
151 destination.getRealm().exec(dgRunnable((IObservableSet destination_, SetDiff diff_, UpdateSetStrategy updateSetStrategy_, bool clearDestination_) {
|
|
152 if (destination_ is getTarget()) {
|
|
153 updatingTarget = true;
|
|
154 } else {
|
|
155 updatingModel = true;
|
|
156 }
|
|
157 MultiStatus multiStatus = BindingStatus.ok();
|
|
158
|
|
159 try {
|
|
160 if (clearDestination_) {
|
|
161 destination_.clear();
|
|
162 }
|
|
163
|
|
164 for (Iterator iterator = diff_.getRemovals().iterator(); iterator
|
|
165 .hasNext();) {
|
|
166 IStatus setterStatus = updateSetStrategy_.doRemove(
|
|
167 destination_, updateSetStrategy_.convert(iterator
|
|
168 .next()));
|
|
169
|
|
170 mergeStatus(multiStatus, setterStatus);
|
|
171 // TODO - at this point, the two sets
|
|
172 // will be out of sync if an error
|
|
173 // occurred...
|
|
174 }
|
|
175
|
|
176 for (Iterator iterator = diff_.getAdditions().iterator(); iterator
|
|
177 .hasNext();) {
|
|
178 IStatus setterStatus = updateSetStrategy_.doAdd(
|
|
179 destination_, updateSetStrategy_.convert(iterator
|
|
180 .next()));
|
|
181
|
|
182 mergeStatus(multiStatus, setterStatus);
|
|
183 // TODO - at this point, the two sets
|
|
184 // will be out of sync if an error
|
|
185 // occurred...
|
|
186 }
|
|
187 } finally {
|
|
188 validationStatusObservable.setValue(multiStatus);
|
|
189
|
|
190 if (destination_ is getTarget()) {
|
|
191 updatingTarget = false;
|
|
192 } else {
|
|
193 updatingModel = false;
|
|
194 }
|
|
195 }
|
|
196 }, destination, diff, updateSetStrategy, clearDestination_));
|
|
197 }
|
|
198
|
|
199 /**
|
|
200 * Merges the provided <code>newStatus</code> into the
|
|
201 * <code>multiStatus</code>.
|
|
202 *
|
|
203 * @param multiStatus
|
|
204 * @param newStatus
|
|
205 */
|
|
206 /* package */void mergeStatus(MultiStatus multiStatus, IStatus newStatus) {
|
|
207 if (!newStatus.isOK()) {
|
|
208 multiStatus.add(newStatus);
|
|
209 }
|
|
210 }
|
|
211
|
|
212 public void dispose() {
|
|
213 if (targetChangeListener !is null) {
|
|
214 (cast(IObservableSet) getTarget())
|
|
215 .removeSetChangeListener(targetChangeListener);
|
|
216 targetChangeListener = null;
|
|
217 }
|
|
218 if (modelChangeListener !is null) {
|
|
219 (cast(IObservableSet) getModel())
|
|
220 .removeSetChangeListener(modelChangeListener);
|
|
221 modelChangeListener = null;
|
|
222 }
|
|
223 super.dispose();
|
|
224 }
|
|
225 }
|