blob: 83cfc76a6d3a608e707925d1bd8944826e52d4ee [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Tasktop Technologies.
* 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.mft.gmf.ui;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramGraphicalViewer;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.mylyn.context.core.AbstractContextListener;
import org.eclipse.mylyn.context.core.ContextChangeEvent;
import org.eclipse.mylyn.context.core.ContextChangeEvent.ContextChangeKind;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IInteractionElement;
import org.eclipse.mylyn.internal.emf.mft.ui.ModelingUiPlugin;
import org.eclipse.mylyn.mft.emf.core.EmfStructureBridge;
import org.eclipse.mylyn.mft.emf.ui.DiagramUiBridge;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPageListener;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
/**
* @author Miles Parker
*/
public abstract class ContextDecoratorProvider extends AbstractProvider implements IDecoratorProvider, IPartListener,
INotifyChangedListener {
public static final String MYLYN_MARKER = "mylyn-marker"; //$NON-NLS-1$
public static final String MYLYN_DETAIL = "mylyn-detail"; //$NON-NLS-1$
public static final String MYLYN_INTERESTING = "mylyn-interesting"; //$NON-NLS-1$
public static final String MYLYN_BORING = "mylyn-boring"; //$NON-NLS-1$
private final Map<String, Collection<ContextDecorator>> decoratorsForModel;
private final Map<RootEditPart, RevealMouseListener> listenerForRoot;
private EmfStructureBridge structure;
private boolean anyContextActive;
private boolean enabled;
private final AbstractContextListener contextListenerAdapter = new AbstractContextListener() {
@Override
public void contextChanged(ContextChangeEvent event) {
ContextDecoratorProvider.this.contextChanged(event);
}
};
private final Collection<RootEditPart> diagramParts;
private final IPropertyChangeListener preferenceListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(ModelingUiPlugin.FOCUSSING_ENABLED)) {
enabled = Boolean.parseBoolean(event.getNewValue().toString());
refresh();
}
}
};
public ContextDecoratorProvider() {
ContextCore.getContextManager().addListener(contextListenerAdapter);
decoratorsForModel = new HashMap<String, Collection<ContextDecorator>>();
listenerForRoot = new HashMap<RootEditPart, RevealMouseListener>();
// workbench should be active as this is instantiated by GMF
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow.getActivePage() == null) {
activeWorkbenchWindow.addPageListener(new IPageListener() {
public void pageOpened(IWorkbenchPage page) {
}
public void pageClosed(IWorkbenchPage page) {
}
public void pageActivated(IWorkbenchPage page) {
page.addPartListener(ContextDecoratorProvider.this);
}
});
} else {
// Not sure if we'll ever get this situation, but it's worth covering
activeWorkbenchWindow.getActivePage().addPartListener(ContextDecoratorProvider.this);
}
diagramParts = new HashSet<RootEditPart>();
ModelingUiPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(preferenceListener);
enabled = ModelingUiPlugin.getDefault().getPreferenceStore().getBoolean(ModelingUiPlugin.FOCUSSING_ENABLED);
anyContextActive = ContextCore.getContextManager().isContextActive();
}
public boolean provides(IOperation operation) {
if (operation instanceof CreateDecoratorsOperation) {
CreateDecoratorsOperation cdo = (CreateDecoratorsOperation) operation;
IDecoratorTarget target = cdo.getDecoratorTarget();
IGraphicalEditPart targetPart = (IGraphicalEditPart) target.getAdapter(IGraphicalEditPart.class);
return accepts(targetPart);
}
return false;
}
private boolean accepts(IGraphicalEditPart targetPart) {
if (targetPart instanceof ConnectionEditPart) {
ConnectionEditPart connection = (ConnectionEditPart) targetPart;
// TODO How could there not be graphical? Why doesn't the GEF API
// make that assumption?
IGraphicalEditPart connectionSource = (IGraphicalEditPart) connection.getSource();
IGraphicalEditPart connectionTarget = (IGraphicalEditPart) connection.getTarget();
// Only care if we care about sources and target
return connectionSource != null && connectionTarget != null && accepts(connectionSource)
&& accepts(connectionTarget);
} else {
Object candidate = getStructure().getDomainObject(targetPart.getModel());
if (candidate instanceof EObject) {
EObject domainObject = (EObject) candidate;
return getStructure().acceptsObject(domainObject)
&& getDomainUIBridge().acceptsViewObject(domainObject, targetPart);
}
}
return false;
}
public void createDecorators(IDecoratorTarget target) {
IGraphicalEditPart targetPart = (IGraphicalEditPart) target.getAdapter(IGraphicalEditPart.class);
if (targetPart instanceof ConnectionEditPart) {
ConnectionEditPart connectionPart = (ConnectionEditPart) targetPart;
EObject domainSource = (EObject) getStructure().getDomainObject(connectionPart.getSource().getModel());
EObject domainTarget = (EObject) getStructure().getDomainObject(connectionPart.getTarget().getModel());
ContextDecorator edgeDecorator = new EdgeDecorator(this, target, domainSource, domainTarget);
target.installDecorator(MYLYN_DETAIL, edgeDecorator);
addDecorator(domainSource, edgeDecorator);
addDecorator(domainTarget, edgeDecorator);
} else {
Object model = targetPart.getModel();
View view = null;
if (model instanceof View) {
view = (View) model;
model = view.getElement();
}
EObject domainObject = (EObject) getStructure().getDomainObject(model);
ContextDecorator mylynDecorator = new NodeDecorator(this, target, domainObject);
addDecorator(domainObject, mylynDecorator);
}
}
private void addDecorator(EObject domainObject, ContextDecorator mylynDecorator) {
String handle = structure.getHandleIdentifier(domainObject);
Collection<ContextDecorator> list = decoratorsForModel.get(handle);
if (list == null) {
list = new HashSet<ContextDecorator>();
decoratorsForModel.put(handle, list);
}
list.add(mylynDecorator);
}
public Collection<RootEditPart> getRootEditParts() {
return diagramParts;
}
private RootEditPart getRootEditPart(IWorkbenchPart editor) {
if (getDomainUIBridge().acceptsPart(editor)) {
if (editor instanceof DiagramEditor) {
DiagramEditor de = (DiagramEditor) editor;
return de.getDiagramEditPart().getRoot();
} else {
// Seems to be the only way to get Papyrus root edit
// part w/o explicit dependencies..
IDiagramGraphicalViewer viewer = (IDiagramGraphicalViewer) editor.getAdapter(IDiagramGraphicalViewer.class);
if (viewer != null) {
return viewer.getRootEditPart();
}
}
}
return null;
}
private IInteractionElement getRecentInteraction(EObject object) {
return ContextCore.getContextManager().getActiveContext().get(getStructure().getHandleIdentifier(object));
}
public boolean isInteresting(EObject object) {
IInteractionElement interation = getRecentInteraction(object);
return interation != null && interation.getInterest().isInteresting();
}
public boolean isLandmark(EObject object) {
IInteractionElement interation = getRecentInteraction(object);
return interation != null && interation.getInterest().isLandmark();
}
public boolean isInteresting(IGraphicalEditPart editPart) {
Object domainObject = getStructure().getDomainObject(editPart.getModel());
return domainObject instanceof EObject && getDomainUIBridge().acceptsViewObject(domainObject, editPart)
&& isInteresting((EObject) domainObject);
}
public Object getDomainObject(IGraphicalEditPart editPart) {
return getStructure().getDomainObject(editPart.getModel());
}
/**
* Should Mylyn manage this object?
*
* @param object
* @return
*/
public boolean isFocussed() {
return enabled && anyContextActive;
}
private void deactivate(IWorkbenchPart part) {
RootEditPart rootEditPart = getRootEditPart(part);
if (rootEditPart != null) {
//TODO are we confident that this won't be removed?
diagramParts.remove(rootEditPart);
for (Collection<ContextDecorator> values : decoratorsForModel.values()) {
Collection<ContextDecorator> removedDecorators = new HashSet<ContextDecorator>();
for (ContextDecorator decorator : values) {
IGraphicalEditPart decoratorEditPart = (IGraphicalEditPart) decorator.getTarget().getAdapter(
IGraphicalEditPart.class);
if (decoratorEditPart.getRoot() == rootEditPart) {
decorator.deactivate();
removedDecorators.add(decorator);
}
}
values.removeAll(removedDecorators);
}
listenerForRoot.remove(rootEditPart);
}
}
void refresh(RootEditPart root) {
diagramParts.add(root);
RevealMouseListener revealMouseListener = listenerForRoot.get(root);
if (revealMouseListener == null) {
IFigure rootFigure = ((AbstractGraphicalEditPart) root.getViewer().getRootEditPart()).getFigure();
revealMouseListener = new RevealMouseListener(rootFigure);
listenerForRoot.put(root, revealMouseListener);
root.getViewer().getControl().addMouseMoveListener(revealMouseListener);
root.getViewer().getControl().addMouseTrackListener(revealMouseListener);
}
root.refresh();
}
void refresh(IWorkbenchPart part) {
RootEditPart rootEditPart = getRootEditPart(part);
if (rootEditPart != null) {
refresh(rootEditPart);
}
}
void refresh() {
if (anyContextActive) {
for (RootEditPart root : getRootEditParts()) {
refresh(root);
}
for (Collection<ContextDecorator> values : decoratorsForModel.values()) {
refresh(values);
}
} else {
for (Collection<ContextDecorator> values : decoratorsForModel.values()) {
for (ContextDecorator decorator : values) {
decorator.deactivate();
}
}
for (RootEditPart root : getRootEditParts()) {
RevealMouseListener revealMouseListener = listenerForRoot.get(root);
if (revealMouseListener != null) {
root.getViewer().getControl().removeMouseMoveListener(revealMouseListener);
}
root.refresh();
}
decoratorsForModel.clear();
listenerForRoot.clear();
}
}
void refresh(IInteractionElement element) {
if (element.getContentType().equals(getDomainUIBridge().getContentType())) {
String handleIdentifier = element.getHandleIdentifier();
Collection<ContextDecorator> values = decoratorsForModel.get(handleIdentifier);
if (values != null) {
refresh(values);
}
}
}
private void refresh(Collection<ContextDecorator> values) {
for (ContextDecorator decorator : values) {
decorator.refresh();
}
}
void refresh(ContextChangeEvent event) {
List<IInteractionElement> elements = event.getElements();
for (IInteractionElement element : elements) {
refresh(element);
}
}
public EmfStructureBridge getStructure() {
if (structure == null) {
structure = (EmfStructureBridge) ContextCore.getStructureBridge(getDomainUIBridge().getContentType());
}
return structure;
}
public void notifyChanged(Notification notification) {
if (notification.getFeature() == getStructure().getNameFeature(notification.getNotifier())) {
EObject eo = (EObject) notification.getNotifier();
String newHandleID = structure.getHandleIdentifier(eo);
String oldHandleID = newHandleID.replaceFirst(notification.getNewStringValue(),
notification.getOldStringValue());
IInteractionElement oldElement = ContextCore.getContextManager().getElement(oldHandleID);
if (oldElement != null) {
ContextCore.getContextManager().updateHandle(oldElement, newHandleID);
}
}
}
public void partActivated(IWorkbenchPart part) {
refresh(part);
}
public void partBroughtToTop(IWorkbenchPart part) {
refresh(part);
}
public void partClosed(IWorkbenchPart part) {
deactivate(part);
}
public void partDeactivated(IWorkbenchPart part) {
}
public void partOpened(IWorkbenchPart part) {
//Listen for changes in the model
if (getDomainUIBridge().acceptsPart(part) && part instanceof IEditorPart) {
IEditorPart ep = (IEditorPart) part;
AdapterFactoryEditingDomain domain = (AdapterFactoryEditingDomain) getEditingDomain(ep);
ComposedAdapterFactory caf = (ComposedAdapterFactory) domain.getAdapterFactory();
caf.addListener(this);
}
}
public static EditingDomain getEditingDomain(Object object) {
if (object instanceof IEditingDomainProvider) {
return ((IEditingDomainProvider) object).getEditingDomain();
}
if (object instanceof IAdaptable) {
IAdaptable adapt = (IAdaptable) object;
Object candidate = adapt.getAdapter(EditingDomain.class);
if (candidate instanceof EditingDomain) {
return (EditingDomain) candidate;
}
candidate = adapt.getAdapter(IEditingDomainProvider.class);
if (candidate instanceof IEditingDomainProvider) {
return ((IEditingDomainProvider) candidate).getEditingDomain();
}
}
return null;
}
public void contextChanged(ContextChangeEvent event) {
if (event.getEventKind() == ContextChangeKind.ACTIVATED) {
anyContextActive = true;
refresh();
} else if (event.getEventKind() == ContextChangeKind.DEACTIVATED) {
anyContextActive = false;
refresh();
} else {
refresh(event);
}
}
public RevealMouseListener getListenerForRoot(RootEditPart part) {
return listenerForRoot.get(part);
}
public abstract DiagramUiBridge getDomainUIBridge();
}