blob: 3efb5a00c697c49dde7986828b9e113a54bbc3e6 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013, 2017 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST - Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.cdo.internal.ui.editors;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.dawn.appearance.DawnElementStylizer;
import org.eclipse.emf.cdo.dawn.editors.IDawnEditor;
import org.eclipse.emf.cdo.dawn.gmf.appearance.DawnAppearancer;
import org.eclipse.emf.cdo.dawn.gmf.editors.impl.DawnGMFEditorSupport;
import org.eclipse.emf.cdo.dawn.gmf.notifications.impl.DawnGMFHandler;
import org.eclipse.emf.cdo.dawn.gmf.util.DawnDiagramUpdater;
import org.eclipse.emf.cdo.dawn.notifications.BasicDawnListener;
import org.eclipse.emf.cdo.dawn.spi.DawnState;
import org.eclipse.emf.cdo.dawn.ui.stylizer.DawnElementStylizerRegistry;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.parts.DiagramDocumentEditor;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.cdo.internal.core.CDOUtils;
import org.eclipse.papyrus.cdo.internal.ui.util.UIUtil;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/**
* This is the PapyrusGMFEditorSupport type. Enjoy.
*/
public class PapyrusGMFEditorSupport
extends DawnGMFEditorSupport {
private static final Predicate<EStructuralFeature.Setting> IS_VIEW_REFERENCE = new Predicate<EStructuralFeature.Setting>() {
@Override
public boolean apply(EStructuralFeature.Setting input) {
return input.getEStructuralFeature() == NotationPackage.Literals.VIEW__ELEMENT;
}
};
private static final Function<EStructuralFeature.Setting, View> OWNER_VIEW = new Function<EStructuralFeature.Setting, View>() {
@Override
public View apply(EStructuralFeature.Setting input) {
return (View) input.getEObject();
}
};
/**
* @param editor
*/
public PapyrusGMFEditorSupport(IDawnEditor editor) {
super(editor);
}
@Override
protected DawnGMFHandler createDawnGMFHandler(IDawnEditor editor) {
return new PapyrusGMFHandler(editor);
}
@Override
protected BasicDawnListener getLockingHandler() {
return new PapyrusGMFLockingHandler(getEditor());
}
@Override
public void lockObject(Object objectToBeLocked) {
if (objectToBeLocked instanceof EditPart) {
super.lockObject(objectToBeLocked);
// the super implementation locked the semantic element, so update
// its presentation
CDOObject cdo = CDOUtils
.getCDOObject(getSemanticElement((EditPart) objectToBeLocked));
if (cdo != null) {
updateAppearance(cdo);
}
} else {
EObject element = EMFHelper.getEObject(objectToBeLocked);
CDOObject cdo = (element == null)
? null
: CDOUtils.getCDOObject(element);
if (element != null) {
CDOUtils.lock(cdo);
updateAppearance(cdo);
// and update any views in my diagram
for (View next : getViewsOfElement(element)) {
cdo = CDOUtils.getCDOObject(next);
if (cdo != null) {
CDOUtils.lock(cdo);
updateAppearance(cdo);
}
}
refresh();
}
}
}
private void updateAppearance(CDOObject cdoObject) {
EObject element = CDOUtil.getEObject(cdoObject);
DawnElementStylizer stylizer = DawnElementStylizerRegistry.instance
.getStylizer(element);
if (stylizer != null) {
if (cdoObject.cdoConflict()) {
stylizer.setConflicted(element,
DawnAppearancer.TYPE_CONFLICT_REMOTELY_AND_LOCALLY_CHANGED);
} else if (CDOUtils.isLocked(cdoObject, true)) {
stylizer.setLocked(element,
DawnAppearancer.TYPE_LOCKED_GLOBALLY);
} else if (CDOUtils.isLocked(cdoObject, false)) {
stylizer
.setLocked(element, DawnAppearancer.TYPE_LOCKED_LOCALLY);
} else {
stylizer.setDefault(element);
}
}
}
@Override
public void unlockObject(Object objectToBeUnlocked) {
if (objectToBeUnlocked instanceof EditPart) {
super.unlockObject(objectToBeUnlocked);
// the super implementation unlocked the semantic element, so update
// its presentation
CDOObject cdo = CDOUtils
.getCDOObject(getSemanticElement((EditPart) objectToBeUnlocked));
if (cdo != null) {
updateAppearance(cdo);
}
} else {
EObject element = EMFHelper.getEObject(objectToBeUnlocked);
CDOObject cdo = (element == null)
? null
: CDOUtils.getCDOObject(element);
if (element != null) {
CDOUtils.unlock(cdo);
updateAppearance(cdo);
// and update any views in my diagram
for (View next : getViewsOfElement(element)) {
cdo = CDOUtils.getCDOObject(next);
if (cdo != null) {
CDOUtils.unlock(cdo);
updateAppearance(cdo);
}
}
refresh();
}
}
}
@Override
public void handleRemoteLockChanges(Map<Object, DawnState> changedObjects) {
if (UIUtil.ensureUIThread(this, changedObjects)) {
// filter the event to cover only the objects that are views in or
// have views in my diagram
Map<Object, DawnState> filtered = filter(changedObjects);
if (filtered != null) {
super.handleRemoteLockChanges(filtered);
}
}
}
protected Map<Object, DawnState> filter(
Map<Object, DawnState> changedObjects) {
Map<Object, DawnState> result = Maps.newHashMap(changedObjects);
if (filter(result.keySet(), getDiagramEditor(getEditor()))) {
if (result.isEmpty()) {
result = null;
}
}
return result;
}
public static View findView(DiagramDocumentEditor diagramEditor,
EObject element) {
View result = null;
Diagram diagram = diagramEditor.getDiagram();
View view = DawnDiagramUpdater.findViewByContainer(element);
if (view != null) {
if (EcoreUtil.isAncestor(diagram, view)) {
result = view;
}
} else {
// find the view of the element that is in my diagram
for (View next : getViewsOfElement(element)) {
if (EcoreUtil.isAncestor(diagram, next)) {
result = next;
break;
}
}
}
return result;
}
public static Iterable<View> getViewsOfElement(EObject element) {
Iterable<View> result = Collections.emptyList();
ECrossReferenceAdapter xrefs = ECrossReferenceAdapter
.getCrossReferenceAdapter(element);
if (xrefs != null) {
Collection<EStructuralFeature.Setting> settings = xrefs
.getNonNavigableInverseReferences(element);
result = Iterables.transform(
Iterables.filter(settings, IS_VIEW_REFERENCE), OWNER_VIEW);
}
return result;
}
static boolean filter(Collection<?> objects,
DiagramDocumentEditor diagramEditor) {
boolean result = false;
for (Iterator<?> iter = objects.iterator(); iter.hasNext();) {
Object next = iter.next();
if (next instanceof CDOObject) {
EObject element = CDOUtil.getEObject((CDOObject) next);
// get the view of this element in the current diagram
View view = findView(diagramEditor, element);
if (view == null) {
iter.remove();
result = true;
}
}
}
return result;
}
public static EObject getSemanticElement(EditPart editPart) {
EObject result = null;
Object model = editPart.getModel();
if (model instanceof EObject) {
View view = DawnDiagramUpdater.findViewByContainer((EObject) model);
if (view != null) {
result = view.getElement();
}
}
return result;
}
}