Skip to content

Package: TreeContentProvider$1

TreeContentProvider$1

nameinstructionbranchcomplexitylinemethod
run()
M: 15 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
{...}
M: 15 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /********************************************************************************
2: * Copyright (c) 2011 Eike Stepper (Berlin, Germany) and others.
3: *
4: * All rights reserved. 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: * Eike Stepper - initial API and implementation
13: ********************************************************************************/
14: package org.eclipse.emf.ecp.internal.ui.model;
15:
16: import java.util.HashMap;
17: import java.util.Map;
18: import java.util.WeakHashMap;
19:
20: import org.eclipse.emf.ecore.EObject;
21: import org.eclipse.emf.ecp.core.ECPProject;
22: import org.eclipse.emf.ecp.core.util.ECPUtil;
23: import org.eclipse.emf.ecp.internal.core.util.ChildrenListImpl;
24: import org.eclipse.emf.ecp.internal.ui.Activator;
25: import org.eclipse.emf.ecp.internal.ui.Messages;
26: import org.eclipse.emf.ecp.spi.core.InternalProvider;
27: import org.eclipse.emf.ecp.spi.core.util.InternalChildrenList;
28: import org.eclipse.jface.viewers.ITreeContentProvider;
29: import org.eclipse.jface.viewers.TreeViewer;
30: import org.eclipse.swt.widgets.Control;
31: import org.eclipse.swt.widgets.Display;
32:
33: /**
34: * @author Eike Stepper
35: * @param <INPUT> The type of input (root of the tree)
36: */
37: public abstract class TreeContentProvider<INPUT> extends StructuredContentProvider<INPUT> implements
38:         ITreeContentProvider {
39:         private static final Object[] NO_CHILDREN = new Object[0];
40:
41:         private final Map<Object, Object> parentsCache = new WeakHashMap<Object, Object>();
42:
43:         private final Map<Object, InternalChildrenList> slowLists = new HashMap<Object, InternalChildrenList>();
44:
45:         @Override
46:         public TreeViewer getViewer() {
47:                 return (TreeViewer) super.getViewer();
48:         }
49:
50:         /** {@inheritDoc} */
51:         @Override
52:         public final Object[] getElements(Object parent) {
53:                 return getChildren(parent);
54:         }
55:
56:         /** {@inheritDoc} */
57:         @Override
58:         public final boolean hasChildren(Object parent) {
59:                 if (parent instanceof SyntheticElement || ECPUtil.isDisposed(parent) || ECPUtil.isClosed(parent)) {
60:                         return false;
61:                 }
62:
63:                 final InternalChildrenList childrenList = getChildrenList(parent);
64:                 synchronized (childrenList) {
65:                         if (!childrenList.isComplete()) {
66:                                 return true;
67:                         }
68:
69:                         return childrenList.hasChildren();
70:                 }
71:         }
72:
73:         /** {@inheritDoc} */
74:         @Override
75:         public final Object[] getChildren(Object parent) {
76:                 if (parent instanceof SyntheticElement || ECPUtil.isDisposed(parent) || ECPUtil.isClosed(parent)) {
77:                         return NO_CHILDREN;
78:                 }
79:
80:                 Object[] result;
81:                 boolean complete;
82:
83:                 final InternalChildrenList childrenList = getChildrenList(parent);
84:                 synchronized (childrenList) {
85:                         result = childrenList.getChildren();
86:                         complete = childrenList.isComplete();
87:                 }
88:
89:                 for (int i = 0; i < result.length; i++) {
90:                         final Object child = result[i];
91:                         parentsCache.put(child, parent);
92:                 }
93:
94:                 if (!complete) {
95:                         final Object[] withPending = new Object[result.length + 1];
96:                         System.arraycopy(result, 0, withPending, 0, result.length);
97:                         withPending[result.length] = new SlowElement(parent);
98:                         result = withPending;
99:                 }
100:
101:                 return result;
102:         }
103:
104:         /** {@inheritDoc} */
105:         @Override
106:         public final Object getParent(Object child) {
107:                 if (child instanceof SyntheticElement) {
108:                         return ((SyntheticElement) child).getParent();
109:                 }
110:
111:                 Object result = parentsCache.get(child);
112:                 if (result == null && EObject.class.isInstance(child)) {
113:                         final EObject childEObject = (EObject) child;
114:                         result = childEObject.eContainer();
115:                         if (result != null && parentsCache.containsKey(result)) {
116:                                 return result;
117:
118:                         }
119:                 }
120:                 return result;
121:         }
122:
123:         public final void refreshViewer(final boolean isStructuralChange, final Object... objects) {
124:                 if (objects.length == 0) {
125:                         return;
126:                 }
127:
128:                 final TreeViewer viewer = getViewer();
129:                 final Control control = viewer.getControl();
130:                 if (!control.isDisposed()) {
131:                         final Display display = control.getDisplay();
132:                         final ECPProject ecpProject = ECPUtil.getECPProjectManager()
133:                                 .getProject(objects[0]);
134:                         boolean isThreadSafe = true;
135:                         if (ecpProject != null) {
136:                                 final InternalProvider provider = (InternalProvider) ecpProject.getProvider();
137:                                 isThreadSafe = provider.isThreadSafe();
138:                         }
139:                         if (display.getSyncThread() != Thread.currentThread()) {
140:                                 final Runnable refreshRunnable = createRefreshRunnable(isStructuralChange, viewer, objects);
141:                                 if (Boolean.getBoolean("enableDisplaySync") && !isThreadSafe) {
142:                                         display.syncExec(refreshRunnable);
143:                                 } else {
144:                                         display.asyncExec(refreshRunnable);
145:                                 }
146:                         } else {
147:                                 if (isStructuralChange) {
148:                                         refresh(viewer, objects);
149:                                 } else {
150:                                         update(viewer, objects);
151:                                 }
152:                         }
153:                 }
154:         }
155:
156:         private Runnable createRefreshRunnable(final boolean isStructuralChange, final TreeViewer viewer,
157:                 final Object... objects) {
158:                 return new Runnable() {
159:                         @Override
160:                         public void run() {
161:•                                if (isStructuralChange) {
162:                                         refresh(viewer, objects);
163:                                 } else {
164:                                         update(viewer, objects);
165:                                 }
166:                         }
167:                 };
168:         }
169:
170:         protected boolean isSlow(Object parent) {
171:                 return false;
172:         }
173:
174:         protected InternalChildrenList getChildrenList(Object parent) {
175:                 InternalChildrenList childrenList;
176:                 if (isSlow(parent)) {
177:                         SlowChildrenList newList = null;
178:                         synchronized (slowLists) {
179:                                 childrenList = slowLists.get(parent);
180:                                 if (childrenList == null) {
181:                                         newList = new SlowChildrenList(parent);
182:                                         childrenList = newList;
183:                                         slowLists.put(parent, childrenList);
184:                                 }
185:                         }
186:
187:                         if (newList != null) {
188:                                 newList.startThread();
189:                         }
190:                 } else {
191:                         childrenList = new ChildrenListImpl(parent);
192:                         fillChildrenDetectError(parent, childrenList);
193:                 }
194:
195:                 return childrenList;
196:         }
197:
198:         protected void fillChildrenDetectError(Object parent, InternalChildrenList childrenList) {
199:                 try {
200:                         fillChildren(parent, childrenList);
201:                 } catch (final Throwable t) {
202:                         Activator.log(t);
203:                         final ErrorElement errorElement = new ErrorElement(parent, t);
204:                         childrenList.addChildWithoutRefresh(errorElement);
205:                 }
206:         }
207:
208:         protected abstract void fillChildren(Object parent, InternalChildrenList childrenList);
209:
210:         public static void refresh(TreeViewer viewer, Object... objects) {
211:                 if (!viewer.getControl().isDisposed()) {
212:                         for (final Object object : objects) {
213:                                 viewer.refresh(object);
214:                         }
215:                 }
216:         }
217:
218:         public static void update(TreeViewer viewer, Object... objects) {
219:                 if (!viewer.getControl().isDisposed()) {
220:                         for (final Object object : objects) {
221:                                 if (object != null) {
222:                                         viewer.update(object, null);
223:                                 }
224:                         }
225:                 }
226:         }
227:
228:         /**
229:          * @author Eike Stepper
230:          */
231:         public static class SyntheticElement {
232:                 private final Object parent;
233:
234:                 public SyntheticElement(Object parent) {
235:                         this.parent = parent;
236:                 }
237:
238:                 public final Object getParent() {
239:                         return parent;
240:                 }
241:         }
242:
243:         /**
244:          * @author Eike Stepper
245:          */
246:         public static final class ErrorElement extends SyntheticElement {
247:                 private final Throwable cause;
248:
249:                 public ErrorElement(Object parent, Throwable cause) {
250:                         super(parent);
251:                         this.cause = cause;
252:                 }
253:
254:                 public Throwable getCause() {
255:                         return cause;
256:                 }
257:
258:                 @Override
259:                 public String toString() {
260:                         return Messages.TreeContentProvider_ErrorElement_Error;
261:                 }
262:         }
263:
264:         /**
265:          * @author Eike Stepper
266:          */
267:         public static final class SlowElement extends SyntheticElement {
268:                 public SlowElement(Object parent) {
269:                         super(parent);
270:                 }
271:
272:                 @Override
273:                 public String toString() {
274:                         return Messages.TreeContentProvider_SlowElement_Pending;
275:                 }
276:         }
277:
278:         /**
279:          * @author Eike Stepper
280:          */
281:         private final class SlowChildrenList extends ChildrenListImpl implements Runnable {
282:                 private static final long serialVersionUID = 1L;
283:
284:                 private boolean complete;
285:
286:                 SlowChildrenList(Object parent) {
287:                         super(parent);
288:                 }
289:
290:                 public void startThread() {
291:                         final Thread thread = new Thread(this, "SlowChildrenList"); //$NON-NLS-1$
292:                         thread.setDaemon(true);
293:                         thread.start();
294:                 }
295:
296:                 @Override
297:                 public void run() {
298:                         fillChildrenDetectError(getParent(), this);
299:                         setComplete();
300:                 }
301:
302:                 @Override
303:                 public boolean isSlow() {
304:                         return true;
305:                 }
306:
307:                 @Override
308:                 public boolean isComplete() {
309:                         return complete;
310:                 }
311:
312:                 @Override
313:                 public void setComplete() {
314:                         if (!complete) {
315:                                 try {
316:                                         complete = true;
317:                                         childrenAdded();
318:                                 } finally {
319:                                         synchronized (slowLists) {
320:                                                 slowLists.remove(getParent());
321:                                         }
322:                                 }
323:                         }
324:                 }
325:
326:                 @Override
327:                 protected void childrenAdded() {
328:                         final TreeViewer viewer = getViewer();
329:                         final Control control = viewer.getControl();
330:                         if (!control.isDisposed()) {
331:                                 final Display display = control.getDisplay();
332:
333:                                 // asyncExec() would lead to infinite recursion in setComplete()
334:                                 display.syncExec(new Runnable() {
335:                                         @Override
336:                                         public void run() {
337:                                                 if (!control.isDisposed()) {
338:                                                         refresh(viewer, getParent());
339:                                                 }
340:                                         }
341:                                 });
342:                         }
343:                 }
344:
345:                 // private void dumpStack(String msg)
346:                 // {
347:                 // try
348:                 // {
349:                 // Object parent = getParent();
350:                 // throw new RuntimeException(msg + " for " + parent + " (" + System.identityHashCode(parent) + ")");
351:                 // }
352:                 // catch (Exception ex)
353:                 // {
354:                 // ex.printStackTrace();
355:                 // }
356:                 // }
357:         }
358: }