blob: cd4fa602f69fa0a96dc953dd8a2bd97e979f2f3c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2020 THALES GLOBAL SERVICES and others.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.transaction.ResourceSetListener;
import org.eclipse.emf.transaction.ResourceSetListenerImpl;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.properties.WorkspaceViewerProperties;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.sirius.business.api.session.ModelChangeTrigger;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionEventBroker;
import org.eclipse.sirius.business.internal.session.SessionEventBrokerImpl;
import org.eclipse.sirius.common.ui.tools.api.util.EclipseUIUtil;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutCommand;
import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutScope;
import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutTrigger;
import org.eclipse.sirius.diagram.sequence.business.internal.refresh.SequenceCanonicalSynchronizerAdapter;
import org.eclipse.sirius.diagram.sequence.business.internal.refresh.SequenceCanonicalSynchronizerAdapterScope;
import org.eclipse.sirius.diagram.sequence.ui.business.internal.refresh.VisibilityEventHandler;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceEMFCommandFactory;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ExecutionOperations;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceContainerCreationPolicy;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.LabelsOverlayFigure;
import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceZOrderingRefresher;
import org.eclipse.sirius.diagram.tools.api.command.IDiagramCommandFactory;
import org.eclipse.sirius.diagram.tools.api.command.IDiagramCommandFactoryProvider;
import org.eclipse.sirius.diagram.ui.graphical.edit.policies.ContainerCreationEditPolicy;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DDiagramEditPart;
import org.eclipse.sirius.diagram.ui.tools.api.editor.DDiagramEditor;
import org.eclipse.sirius.diagram.ui.tools.api.properties.PropertiesService;
import org.eclipse.sirius.diagram.ui.tools.internal.graphical.edit.part.DDiagramRootEditPart;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.base.Options;
import org.eclipse.sirius.tools.api.ui.property.IPropertiesProvider;
import org.eclipse.sirius.ui.business.api.dialect.DialectUIManager;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* The edit part for sequence diagrams themselves.
*
* @author pcdavid
*/
public class SequenceDiagramEditPart extends DDiagramEditPart {
/**
* The listener in charge with refreshing the graphical ordering and layout
* when the model and/or graphics positions change.
*/
private final VisibilityEventHandler semanticOrderingSynchronizer;
private IDiagramCommandFactoryProvider previousProvider;
private ModelChangeTrigger refreshLayout;
private ModelChangeTrigger sequenceCanonicalSynchronizer;
private ResourceSetListener refreshZorder = new ResourceSetListenerImpl() {
@Override
public boolean isPostcommitOnly() {
return true;
}
@Override
public void resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent event) {
new SequenceZOrderingRefresher(SequenceDiagramEditPart.this).run();
refreshConnectionsBendpoints();
}
};
private IPropertyChangeListener snapDisabler;
private IFigure labelsOverlayFigure;
/**
* Constructor.
*
* @param diagramView
* the view.
*/
public SequenceDiagramEditPart(final View diagramView) {
super(diagramView);
this.semanticOrderingSynchronizer = new VisibilityEventHandler();
}
@Override
protected void createDefaultEditPolicies() {
super.createDefaultEditPolicies();
ExecutionOperations.replaceEditPolicy(this, EditPolicy.CONTAINER_ROLE, new SequenceContainerCreationPolicy(), ContainerCreationEditPolicy.class);
// Handle $endBefore for launch tools.
installEditPolicy(org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
}
@Override
public void addNotify() {
SequenceEditPartsOperations.registerDiagramElement(this, resolveSemanticElement());
super.addNotify();
Object property = getViewer().getProperty(DDiagramEditor.EDITOR_ID);
if (property instanceof DDiagramEditor) {
DDiagramEditor diagramEditor = (DDiagramEditor) property;
setCustomCommandFactoryProvider(diagramEditor);
}
}
@Override
public void removeNotify() {
super.removeNotify();
SequenceEditPartsOperations.unregisterDiagramElement(this, resolveSemanticElement());
Object property = getViewer().getProperty(DDiagramEditor.EDITOR_ID);
if (property instanceof DDiagramEditor && this.previousProvider != null) {
DDiagramEditor diagramEditor = (DDiagramEditor) property;
diagramEditor.setEmfCommandFactoryProvider(this.previousProvider);
this.previousProvider = null;
}
}
/**
* Overridden to do some initialization and add a post-commit listener.
* <p>
* {@inheritDoc}
*/
@Override
public void activate() {
super.activate();
final EditPartViewer viewer = getViewer();
if (viewer instanceof DiagramGraphicalViewer) {
final IPreferenceStore workspaceViewerPreferenceStore = ((DiagramGraphicalViewer) viewer).getWorkspaceViewerPreferenceStore();
if (workspaceViewerPreferenceStore != null) {
workspaceViewerPreferenceStore.setDefault(WorkspaceViewerProperties.SNAPTOGRID, false);
workspaceViewerPreferenceStore.setValue(WorkspaceViewerProperties.SNAPTOGRID, false);
workspaceViewerPreferenceStore.setDefault(WorkspaceViewerProperties.SNAPTOGEOMETRY, false);
workspaceViewerPreferenceStore.setValue(WorkspaceViewerProperties.SNAPTOGEOMETRY, false);
snapDisabler = new IPropertyChangeListener() {
@Override
public void propertyChange(org.eclipse.jface.util.PropertyChangeEvent event) {
if (event.getNewValue() instanceof Boolean && ((Boolean) event.getNewValue()).booleanValue()) {
if (WorkspaceViewerProperties.SNAPTOGEOMETRY.equals(event.getProperty())) {
EclipseUIUtil.displayAsyncExec(new Runnable() {
@Override
public void run() {
workspaceViewerPreferenceStore.setValue(WorkspaceViewerProperties.SNAPTOGEOMETRY, Boolean.FALSE);
}
});
} else if (WorkspaceViewerProperties.SNAPTOGRID.equals(event.getProperty())) {
EclipseUIUtil.displayAsyncExec(new Runnable() {
@Override
public void run() {
workspaceViewerPreferenceStore.setValue(WorkspaceViewerProperties.SNAPTOGRID, Boolean.FALSE);
}
});
}
}
}
};
workspaceViewerPreferenceStore.addPropertyChangeListener(snapDisabler);
}
}
/*
* Once the diagram (and all its children) is active, refresh the
* various ordering. This is especially needed when creating/opening a
* diagram as some commands need a properly initialized graphically
* ordering to work.
*/
boolean autoRefresh = PropertiesService.getInstance().getPropertiesProvider().getProperty(IPropertiesProvider.KEY_AUTO_REFRESH);
boolean refreshOnOpen = DialectUIManager.INSTANCE.isRefreshActivatedOnRepresentationOpening();
getEditingDomain().getCommandStack().execute(new RefreshLayoutCommand(getEditingDomain(), getDiagramView(), autoRefresh || refreshOnOpen));
getEditingDomain().addResourceSetListener(semanticOrderingSynchronizer);
getEditingDomain().addResourceSetListener(refreshZorder);
Option<SessionEventBroker> broker = getSessionBroker();
if (broker.some()) {
SessionEventBroker sessionEventBroker = broker.get();
Predicate<Notification> refreshLayoutScope = new RefreshLayoutScope();
refreshLayout = new RefreshLayoutTrigger(getDiagramView());
sessionEventBroker.addLocalTrigger(SessionEventBrokerImpl.asFilter(refreshLayoutScope), refreshLayout);
Predicate<Notification> sequenceCanonicalSynchronizerLayoutScope = new SequenceCanonicalSynchronizerAdapterScope();
sequenceCanonicalSynchronizer = new SequenceCanonicalSynchronizerAdapter();
sessionEventBroker.addLocalTrigger(SessionEventBrokerImpl.asFilter(sequenceCanonicalSynchronizerLayoutScope), sequenceCanonicalSynchronizer);
}
IFigure overlayLayer = getLayer(DDiagramRootEditPart.OVERLAY_LAYER);
if (overlayLayer != null) {
this.labelsOverlayFigure = new LabelsOverlayFigure(this.getFigure(), this);
overlayLayer.add(this.labelsOverlayFigure);
}
}
private Option<SessionEventBroker> getSessionBroker() {
DDiagramEditor diagramEditor = (DDiagramEditor) this.getViewer().getProperty(DDiagramEditor.EDITOR_ID);
if (diagramEditor != null) {
Session session = diagramEditor.getSession();
if (session != null && session.isOpen()) {
return Options.newSome(diagramEditor.getSession().getEventBroker());
}
}
return Options.newNone();
}
private void setCustomCommandFactoryProvider(DDiagramEditor diagramEditor) {
previousProvider = diagramEditor.getEmfCommandFactoryProvider();
diagramEditor.setEmfCommandFactoryProvider(new IDiagramCommandFactoryProvider() {
/** the EMF command factory */
private IDiagramCommandFactory commandFactory;
@Override
public IDiagramCommandFactory getCommandFactory(final TransactionalEditingDomain editingDomain) {
if (commandFactory == null) {
commandFactory = new SequenceEMFCommandFactory(SequenceDiagramEditPart.this);
}
return commandFactory;
}
});
}
/**
* Overridden to remove the post-commit listener and other initializations.
* <p>
* {@inheritDoc}
*/
@Override
public void deactivate() {
EditPartViewer viewer = getViewer();
if (snapDisabler != null && viewer instanceof DiagramGraphicalViewer && ((DiagramGraphicalViewer) viewer).getWorkspaceViewerPreferenceStore() != null) {
((DiagramGraphicalViewer) viewer).getWorkspaceViewerPreferenceStore().removePropertyChangeListener(snapDisabler);
snapDisabler = null;
}
IFigure overlayLayer = getLayer(DDiagramRootEditPart.OVERLAY_LAYER);
if (labelsOverlayFigure != null && overlayLayer != null) {
overlayLayer.remove(labelsOverlayFigure);
labelsOverlayFigure = null;
}
getEditingDomain().removeResourceSetListener(refreshZorder);
getEditingDomain().removeResourceSetListener(semanticOrderingSynchronizer);
Option<SessionEventBroker> broker = getSessionBroker();
if (broker.some()) {
SessionEventBroker sessionEventBroker = broker.get();
sessionEventBroker.removeLocalTrigger(refreshLayout);
sessionEventBroker.removeLocalTrigger(sequenceCanonicalSynchronizer);
}
super.deactivate();
}
/**
* {@inheritDoc}
*
* Overridden to be accessible from {@link SequenceZOrderingRefresher}.
*/
@Override
public void reorderChild(EditPart child, int index) {
super.reorderChild(child, index);
}
@Override
protected void refreshChildren() {
super.refreshChildren();
refreshConnectionsBendpoints();
new SequenceZOrderingRefresher(this).run();
}
/**
* Refresh the bendpoints of source & target connections.
*/
protected void refreshConnectionsBendpoints() {
for (SequenceMessageEditPart connectionEditPart : Iterables.filter(getConnections(), SequenceMessageEditPart.class)) {
connectionEditPart.refreshBendpoints();
}
}
/**
* Returns the underlying sequence diagram element.
*
* @return the underlying sequence diagram element.
*/
public SequenceDiagram getSequenceDiagram() {
return ISequenceElementAccessor.getSequenceDiagram(getDiagramView()).get();
}
}