Skip to main content
summaryrefslogtreecommitdiffstats
blob: 889ca0137505a4d5a215adf5c8aa80e9d14499b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*****************************************************************************
 * Copyright (c) 2012 CEA LIST.
 * 
 * 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:
 *  Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
 *****************************************************************************/
package org.eclipse.papyrus.infra.emf.providers.strategy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.facet.infra.facet.FacetReference;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.widgets.providers.IAdaptableContentProvider;
import org.eclipse.papyrus.infra.widgets.strategy.ProviderBasedBrowseStrategy;
import org.eclipse.swt.widgets.TreeItem;

/**
 * A TreeBrowseStrategy based on the semantic model.
 * It can also retrieve a semantic element in a MoDisco tree, when the tree structure is close
 * to the semantic one (With optional EReferences).
 * 
 * Container1::Container2::EObject1 can be retrieved in a Tree representing
 * Container1::(Reference1)::Container2::(Reference2)::EObject1
 * 
 * @author Camille Letavernier
 */
public class ContainmentBrowseStrategy extends ProviderBasedBrowseStrategy {

	protected IAdaptableContentProvider adaptableProvider;

	protected TreeViewer viewer;

	public ContainmentBrowseStrategy(ITreeContentProvider provider) {
		if(!(provider instanceof IAdaptableContentProvider)) {
			throw new IllegalArgumentException("The provider must be an IAdaptableContentProvider");
		}

		setProvider(provider);
		this.adaptableProvider = (IAdaptableContentProvider)super.provider;
	}

	//
	//	Elements filtering
	//

	@Override
	protected boolean browseElement(Object containerElement) {
		Object semanticElement = adaptableProvider.getAdaptedValue(containerElement);

		//Only browse Containment references and Facet references
		if(semanticElement instanceof EReference) {
			if(semanticElement instanceof FacetReference) {
				return true;
			}

			return ((EReference)semanticElement).isContainment() && !((EReference)semanticElement).isDerived();
		}

		return true;
	}

	//
	//	Elements search
	//

	//	/**
	//	 * {@inheritDoc}
	//	 */
	//	@Override
	//	public TreePath findPath(Object semanticElement, Object[] rootElements) {
	//		List<Object> semanticPath = new LinkedList<Object>();
	//		findSemanticPath(semanticElement, semanticPath);
	//		return searchPath(semanticPath, rootElements);
	//	}

	//	/**
	//	 * Fills the semantic path to the given element
	//	 * 
	//	 * @param element
	//	 *        The element to retrieve
	//	 * @param currentPath
	//	 *        The path to fill (in-out)
	//	 */
	//	protected void findSemanticPath(Object element, List<Object> currentPath) {
	//		if(element != null && element instanceof EObject) {
	//			findSemanticPath(getSemanticParent(element), currentPath);
	//			currentPath.add(element);
	//		}
	//	}
	//
	//	protected Object getSemanticParent(Object element) {
	//		if(element instanceof EObject) {
	//			return ((EObject)element).eContainer();
	//		}
	//		return null;
	//	}
	//
	//	/**
	//	 * Retrieve the graphical TreePath from the given semantic path
	//	 * 
	//	 * @param semanticPath
	//	 * @return
	//	 */
	//	protected TreePath searchPath(List<Object> semanticPath, Object input) {
	//		List<Object> graphicalPath = new LinkedList<Object>();
	//		Object[] graphicalRootObjects = (Object[])input;
	//		if(!searchPath(semanticPath, graphicalPath, graphicalRootObjects)) {
	//			//Object not found
	//			graphicalPath.clear();
	//		}
	//
	//		return new TreePath(graphicalPath.toArray());
	//	}
	//
	//	protected boolean searchPath(List<Object> semanticPath, List<Object> graphicalPath, Object[] graphicalRootObjects) {
	//		if(semanticPath.isEmpty()) {
	//			return true;
	//		}
	//
	//		if(graphicalRootObjects == null) {
	//			return false;
	//		}
	//
	//		Object currentElement = semanticPath.get(0);
	//		for(Object graphicalElement : graphicalRootObjects) {
	//			Object semanticValue = adaptableProvider.getAdaptedValue(graphicalElement);
	//
	//			//Specific case for containment EReference
	//			if(semanticValue instanceof EReference) {
	//				EReference referenceToBrowse = (EReference)semanticValue;
	//				if(referenceToBrowse.isContainment()) {
	//					graphicalPath.add(graphicalElement);
	//
	//					if(searchPath(semanticPath, graphicalPath, provider.getChildren(graphicalElement))) {
	//						//The element has been found
	//						return true;
	//					}
	//
	//					//The element has not been found ; we revert the modifications
	//					graphicalPath.remove(graphicalElement);
	//				}
	//			}
	//
	//			if(semanticValue == currentElement) {
	//				semanticPath.remove(0);
	//				graphicalPath.add(graphicalElement);
	//				if(searchPath(semanticPath, graphicalPath, provider.getChildren(graphicalElement))) {
	//					return true;
	//				}
	//			}
	//		}
	//
	//		return false;
	//	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		if(viewer instanceof TreeViewer) {
			this.viewer = (TreeViewer)viewer;
		}
		super.inputChanged(viewer, oldInput, newInput);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void revealSemanticElement(List<?> elementList) {
		//for each element we reveal it
		Iterator<?> elementListIterator = elementList.iterator();
		ArrayList<Object> treeElementToSelect = new ArrayList<Object>();
		while(elementListIterator.hasNext()) {
			Object currentElement = elementListIterator.next();
			//test if the type is an EObject
			if(currentElement instanceof EObject) {
				EObject currentEObject = (EObject)currentElement;
				//the content provider exist?
				if(provider != null) {
					//need the root in order to find all element in the tree
					Object root = provider.getElements(null)[0];
					//look for the path in order to access to this element
					List<Object> path = searchPath(currentEObject, Arrays.asList(provider.getElements(root)));
					if(path.size() > 0) {
						//expand in the common viewer the path
						expandItems(path, viewer.getTree().getItems());
						treeElementToSelect.add(path.get(path.size() - 1));
					}
				}
			}
			selectReveal(new StructuredSelection(treeElementToSelect));
		}
	}

	public void expandItems(List<Object> treeElementList, TreeItem[] list) {
		//the treeElement has more tan one element
		viewer.getTree().setRedraw(false);
		if(treeElementList.size() > 0) {
			for(int i = 0; i < list.length; i++) {
				if(list[i].getData() != null && list[i].getData().equals(treeElementList.get(0))) {
					if(treeElementList.size() > 1) {//Do no expand the last element
						Object[] toexpand = { treeElementList.get(0) };
						viewer.setExpandedElements(toexpand);
					}
					ArrayList<Object> tmpList = new ArrayList<Object>();
					tmpList.addAll(treeElementList);
					tmpList.remove(tmpList.get(0));
					expandItems(tmpList, list[i].getItems());
				}
			}
		}
		viewer.getTree().setRedraw(true);
	}

	public void selectReveal(ISelection selection) {
		if(viewer != null) {
			viewer.setSelection(selection, true);
		}
	}

	/**
	 * Simple search, based on containment references
	 * 
	 * @param eobject
	 * @param objects
	 * @return
	 */
	protected List<Object> searchDirectContainmentPath(EObject eobject, List<Object> wrappedElements) {
		List<Object> path = new ArrayList<Object>();

		List<EObject> emfPath = EMFHelper.getContainmentPath(eobject);

		for(Object wrappedElement : wrappedElements) {
			EObject element = EMFHelper.getEObject(wrappedElement);

			if(eobject.equals(element)) {
				//We found the leaf element
				return Collections.singletonList(wrappedElement);
			}

			if(browseElementForDirectContainment(emfPath, element)) {
				List<Object> wrappedChildren = Arrays.asList(provider.getChildren(wrappedElement));
				List<Object> childPath = searchDirectContainmentPath(eobject, wrappedChildren);
				if(!childPath.isEmpty()) {
					//We (indirectly) found the leaf element
					path.add(wrappedElement);
					path.addAll(childPath);
					break;
				}
			} //Else: dead end
		}

		return path;
	}

	protected boolean browseElementForDirectContainment(List<EObject> emfPath, EObject element) {
		if(emfPath.contains(element)) {
			return true;
		}

		if(element instanceof EReference) {
			EReference reference = (EReference)element;
			if(reference.isContainment() && !reference.isDerived()) {
				return true;
			}
		}

		return false;
	}

	/**
	 * look for the path the list of element (from the content provider) to go the eObject
	 * 
	 * @param eobject
	 *        that we look for.
	 * @param objects
	 *        a list of elements where eobject can be wrapped.
	 * @return the list of modelElementItem (from the root to the element that wrap the eobject)
	 */
	protected List<Object> searchPath(EObject eobject, List<Object> objects) {
		//Simple/quick search (Based on containment)
		List<Object> path = searchDirectContainmentPath(eobject, objects);
		if(!path.isEmpty()) {
			return path;
		}

		//Advanced search
		path = new ArrayList<Object>();

		for(Object o : objects) {
			// Search matches in this level
			if(!(o instanceof Diagram)) {
				if(eobject.equals(EMFHelper.getEObject(o))) {
					path.add(o);
					return path;
				}
			}

			// Find childs only for feature container
			for(int i = 0; i < provider.getChildren(o).length; i++) {
				Object treeItem = provider.getChildren(o)[i];

				List<Object> tmppath = new ArrayList<Object>();
				Object element = EMFHelper.getEObject(treeItem);

				if(browseElement(element)) {
					List<Object> childs = new ArrayList<Object>();
					childs.add(treeItem);
					tmppath = searchPath(eobject, childs);
				}

				// if tmppath contains the wrapped eobject we have found the good path
				if(tmppath.size() > 0) {
					Object last = tmppath.get(tmppath.size() - 1);
					EObject lastEObject = EMFHelper.getEObject(last);
					if(eobject.equals(lastEObject)) {
						path.add(o);
						path.addAll(tmppath);
						return path;
					}
				}
			}
		}

		return new ArrayList<Object>();
	}

}

Back to the top