Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: c34a3ce1e475223b47bb5ed8b0871990baf20d87 (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
/*****************************************************************************
 * Copyright (c) 2015, 2016 Christian W. Damus and others.
 * 
 * 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:
 *   Christian W. Damus - Initial API and implementation
 *   
 *****************************************************************************/

package org.eclipse.papyrus.infra.gmfdiag.welcome.internal.modelelements;

import java.util.function.Supplier;

import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.resource.ResourceAdapter;
import org.eclipse.papyrus.infra.tools.databinding.WritableListWithIterator;
import org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototype;
import org.eclipse.swt.widgets.Display;

/**
 * A list property of notation-observables, tracking all of the diagrams, tables,
 * and such notations available in the resource set in user resources (not in,
 * for example, plug-in deployed models).
 */
public class NotationObservableProperty implements Supplier<IObservableList<NotationObservable>> {
	private TransactionalEditingDomain domain;
	private ResourceAdapter.Transactional diagramsListener;

	private IObservableList<NotationObservable> list;

	public NotationObservableProperty(WelcomeModelElement owner) {
		super();

		this.list = new WritableListWithIterator.Containment<>(NotationObservable.class);
		this.domain = (TransactionalEditingDomain) owner.getDomain();

		hookDiagramsListener();

		list.addDisposeListener(event -> {
			diagramsListener.uninstall(domain);
			diagramsListener = null;
			domain = null;
		});
	}

	@Override
	public IObservableList<NotationObservable> get() {
		return list;
	}

	void hookDiagramsListener() {
		diagramsListener = new ResourceAdapter.Transactional() {

			@Override
			public void resourceSetChanged(ResourceSetChangeEvent event) {
				// I have to run on the UI thread in order to operate on observables
				if (Display.getCurrent() != null) {
					basicResourceSetChanged(event);
				} else {
					try {
						Display.getDefault().syncExec(TransactionUtil.createPrivilegedRunnable(domain,
								new RunnableWithResult.Impl<Void>() {
									@Override
									public void run() {
										basicResourceSetChanged(event);
									}
								}));
					} catch (InterruptedException e) {
						// This can't actually happen (appears to be an error in the
						// specification of the API)
						basicResourceSetChanged(event); // Try, anyways
					}
				}
			}

			/**
			 * Captures the superclass behaviour of
			 * {@link #resourceSetChanged(ResourceSetChangeEvent)}.
			 * 
			 * @param event
			 *            the change event
			 */
			final void basicResourceSetChanged(ResourceSetChangeEvent event) {
				super.resourceSetChanged(event);
			}

			@Override
			protected void handleResourceLoaded(Resource resource) {
				resource.getContents().stream()
						.filter(ViewPrototype::isViewObject)
						.filter(NotationObservableProperty.this::isUserObject)
						// In case of loading a resource, we already added its
						// notations via handleRootAdded()
						.filter(NotationObservableProperty.this::notAddedYet)
						.map(NotationObservable::new)
						.forEach(list::add);
			}

			@Override
			protected void handleRootAdded(Resource resource, EObject root) {
				if (ViewPrototype.isViewObject(root) && isUserObject(root)) {
					list.add(new NotationObservable(root));
				}
			}

			@Override
			protected void handleRootRemoved(Resource resource, EObject root) {
				if (ViewPrototype.isViewObject(root)) {
					list.removeIf(next -> next.getView().getValue() == root);
				}
			}
		};

		diagramsListener.install(domain);
	}

	/**
	 * Is a notation view or other object one that is under the user's control?
	 * That is, in a resource that is normally accessible and editable.
	 * 
	 * @param object
	 *            an object in a model-set
	 * @return whether it is in a user resource
	 */
	boolean isUserObject(EObject object) {
		boolean result;

		Resource resource = object.eResource();
		ResourceSet rset = (resource == null) ? null : resource.getResourceSet();

		if (rset instanceof ModelSet) {
			result = ((ModelSet) rset).isUserModelResource(resource.getURI());
		} else {
			if (resource != null) {
				URI uri = resource.getURI();
				result = uri.isPlatformResource() || uri.isFile();
			} else {
				result = false;
			}
		}

		return result;
	}

	/**
	 * Queries whether an {@code object} has not yet been added to our
	 * observable list.
	 * 
	 * @param object
	 *            an object
	 * @return {@code true} if it is not in the observable list; {@code false}, otherwise
	 */
	private boolean notAddedYet(EObject object) {
		return list.stream().allMatch(obs -> obs.getView().getValue() != object);
	}
}

Back to the top