Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 83ed7c7f4487d34de6845fea5a4014a2ddde2777 (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
/*****************************************************************************
 * Copyright (c) 2010 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:
 *  Ansgar Radermacher (CEA LIST) ansgar.radermacher@cea.fr - Initial API and implementation
 *
 *****************************************************************************/

package org.eclipse.papyrus.diagram.common.resourceupdate;

import static org.eclipse.papyrus.core.Activator.log;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.common.util.EList;
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.URIConverter;
import org.eclipse.papyrus.core.editor.IMultiDiagramEditor;
import org.eclipse.papyrus.core.lifecycleevents.ILifeCycleEventsProvider;
import org.eclipse.papyrus.core.services.IService;
import org.eclipse.papyrus.core.services.ServiceException;
import org.eclipse.papyrus.core.services.ServicesRegistry;
import org.eclipse.papyrus.diagram.common.Activator;
import org.eclipse.papyrus.resource.ModelSet;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.uml2.uml.Profile;

/**
 * A listener for resource changes, used to trigger an update of
 * models whose underlying resources have been changed.
 * 
 * @author Ansgar Radermacher (CEA LIST)
 */
public class ResourceUpdateService implements IService, IResourceChangeListener, IResourceDeltaVisitor {

	public static final String RESOURCE_UPDATE_ID = Activator.ID + ".resourceUpdate";

	// public init (CoreMultiDiagramEditor editor, ISaveAndDirtyService saveAndDirty, ModelSet modelSet) {
	public void init(ServicesRegistry serviceRegistry) throws ServiceException {
		modelSet = serviceRegistry.getService(ModelSet.class);
		editor = serviceRegistry.getService(IMultiDiagramEditor.class);
		ILifeCycleEventsProvider lcEventsProvider = serviceRegistry.getService(ILifeCycleEventsProvider.class);
		saveListener = new SaveListener();
		lcEventsProvider.addDoSaveListener(saveListener.preSaveListener);
		lcEventsProvider.addPostDoSaveListener(saveListener.postSaveListener);

		partActivationListener = new PartActivationListener(editor);
	}

	/**
	 * The listener operation that is called by the workspace
	 */
	public void resourceChanged(IResourceChangeEvent event) {
		switch(event.getType()) {
		case IResourceChangeEvent.PRE_CLOSE:
		case IResourceChangeEvent.PRE_BUILD:
		case IResourceChangeEvent.POST_BUILD:
		case IResourceChangeEvent.PRE_DELETE:
			// do nothing (only handle change)
			break;
		case IResourceChangeEvent.POST_CHANGE:
			try {
				// delegate to visitor (event.getResource is typically null) and there
				// might be a tree of changed resources
				event.getDelta().accept(this);
			} catch (CoreException coreException) {
				log.error(coreException);
			}
			break;
		}

	}

	/**
	 * A visitor for resource changes. Detects, whether a changed resource belongs to an opened editor
	 */
	public boolean visit(IResourceDelta delta) {
		IResource changedResource = delta.getResource();
		if(delta.getFlags() == IResourceDelta.MARKERS) {
			// only markers have been changed. Refresh their display only (no need to reload resources)
			// TODO called once for each new marker => assure asynchronous refresh
			modelSet.eNotify(new NotificationImpl(Notification.SET, new Object(), delta.getMarkerDeltas()));
			return false;
		}
		// only proceed in case of Files (not projects, folders, ...) for the moment
		if(!(changedResource instanceof IFile)) {
			return true;
		}
		final String changedResourcePath = changedResource.getFullPath().toString();
		IPath changedResourcePathWOExt = changedResource.getFullPath().removeFileExtension();
		URIConverter uriConverter = modelSet.getURIConverter();

		for(Resource resource : modelSet.getResources()) {
			URI uri = resource.getURI();
			URI normalizedURI = uriConverter.normalize(uri);

			// URI path is prefixed with /resource or /plugin (registered model), therefore compare with
			// endsWith.
			// Comparison is done on path level since resource and changedResource are never
			// identical. The latter is a generic system resource (File, ...), the former a
			// model-aware representation of the resource
			if(normalizedURI.path().endsWith(changedResourcePath)) {
				if(changedResourcePathWOExt.equals(modelSet.getFilenameWithoutExtension())) {
					// model itself has changed.
					// mark main resource as changed. User will asked later, when he activates the editor.
					if(!saveListener.isSaveActive() && !partActivationListener.isModied()) {
						partActivationListener.setModificationData(changedResourcePath, delta);
					}
				}
				// changed resource does not belong to the model, it might however belong to a referenced
				// model. Since the referenced model is not editable (TODO: might change? see bug 317430),
				// it can be unloaded without asking the user (it will be reloaded on demand)

				else if(resource.isLoaded()) {
					EList<EObject> contents = resource.getContents();
					if((contents.size() > 0) && (contents.get(0) instanceof Profile)) {
						// don't touch profiles
					} else {
						resource.unload();
					}
				}
			}
		}
		return true;
	}

	private IMultiDiagramEditor editor;

	private ModelSet modelSet;

	// private ILifeCycleEventsProvider lifeCycleEvents;

	/**
	 * Activate the listeners. It will listen to resource changes and to changes of the active editor
	 */
	private void activate() {
		// ... add service to the workspace
		ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
		IWorkbenchPage page = editor.getSite().getPage();
		page.addPartListener(partActivationListener);
	}

	/**
	 * DeActivate the listeners.
	 */
	private void deactivate() {
		// remove it from workspace
		ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
		IWorkbenchPage page = editor.getSite().getPage();
		page.removePartListener(partActivationListener);
	}

	public void startService() throws ServiceException {
		activate();
	}

	public void disposeService() throws ServiceException {
		deactivate();
		// lifeCycleEvents.removeDoSaveListener(listener);
	}

	private PartActivationListener partActivationListener;

	private SaveListener saveListener;
}

Back to the top