/***************************************************************************** * 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.uml.diagram.common.resourceupdate; import static org.eclipse.papyrus.uml.diagram.common.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.infra.core.editor.IMultiDiagramEditor; import org.eclipse.papyrus.infra.core.lifecycleevents.ILifeCycleEventsProvider; import org.eclipse.papyrus.infra.core.resource.ModelSet; import org.eclipse.papyrus.infra.core.services.IService; import org.eclipse.papyrus.infra.core.services.ServiceException; import org.eclipse.papyrus.infra.core.services.ServicesRegistry; import org.eclipse.papyrus.uml.diagram.common.Activator; 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.setModificationData(changedResource.getFullPath(), delta, true, resource.isModified()); } } // Changed resource does not belong to the model, it might however belong to a referenced model. // Since the referenced model may be editable (case of controlled sub-model with write access), // it must not be unloaded without asking the user. User will be asked when activating the editor. else if(resource.isLoaded()) { EList<EObject> contents = resource.getContents(); if((contents.size() > 0) && (contents.get(0) instanceof Profile)) { // don't touch profiles } else if(!saveListener.isSaveActive()) { partActivationListener.setModificationData(changedResource.getFullPath(), delta, false, resource.isModified()); } } } } 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; }