/*******************************************************************************
* Copyright (c) 2012 VMware, Inc.
* 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.config.graph.parts;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.FanRouter;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.CompoundDirectedGraph;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.RootComponentEditPolicy;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.springframework.ide.eclipse.config.core.preferences.SpringConfigPreferenceConstants;
import org.springframework.ide.eclipse.config.graph.ConfigGraphPlugin;
import org.springframework.ide.eclipse.config.graph.model.AbstractConfigGraphDiagram;
import org.springframework.ide.eclipse.config.graph.model.Activity;
/**
* @author Leo Dos Santos
* @author Christian Dupuis
* @author Terry Denney
*/
public abstract class ActivityDiagramPart extends StructuredActivityPart implements IPropertyChangeListener {
private final AbstractConfigGraphDiagram diagram;
private DelegatingLayoutManager delegatingLayoutManager;
private final int direction;
private boolean isFirstManualLayout;
private boolean isLayoutReset;
private final IPreferenceStore prefStore;
CommandStackListener stackListener = new CommandStackListener() {
public void commandStackChanged(EventObject event) {
if (delegatingLayoutManager.getActiveLayoutManager() instanceof GraphLayoutManager) {
if (GraphAnimation.captureLayout(getFigure())) {
while (GraphAnimation.step()) {
getFigure().getUpdateManager().performUpdate();
}
}
GraphAnimation.end();
}
else {
getFigure().getUpdateManager().performUpdate();
}
}
};
public ActivityDiagramPart(AbstractConfigGraphDiagram diagram, int direction) {
super(diagram);
this.diagram = diagram;
prefStore = ConfigGraphPlugin.getDefault().getPreferenceStore();
if (direction == PositionConstants.EAST) {
this.direction = direction;
}
else {
this.direction = PositionConstants.SOUTH;
}
isFirstManualLayout = true;
}
/**
* @see org.springframework.ide.eclipse.config.graph.parts.ActivityPart#activate()
*/
@Override
public void activate() {
super.activate();
getViewer().getEditDomain().getCommandStack().addCommandStackListener(stackListener);
prefStore.addPropertyChangeListener(this);
}
@Override
protected void applyOwnResults(CompoundDirectedGraph graph, Map<AbstractGraphicalEditPart, Object> map) {
}
/**
* @see org.springframework.ide.eclipse.config.graph.parts.ActivityPart#createEditPolicies()
*/
@Override
protected void createEditPolicies() {
installEditPolicy(EditPolicy.COMPONENT_ROLE, new RootComponentEditPolicy());
// installEditPolicy(EditPolicy.CONTAINER_ROLE, new
// ActivityContainerEditPolicy());
installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, null);
installEditPolicy(EditPolicy.LAYOUT_ROLE, null);
installEditPolicy(EditPolicy.NODE_ROLE, null);
installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, null);
}
@Override
protected IFigure createFigure() {
Figure f = new FreeformLayer() {
@Override
public void setBounds(Rectangle rect) {
int x = bounds.x, y = bounds.y;
boolean resize = (rect.width != bounds.width) || (rect.height != bounds.height), translate = (rect.x != x)
|| (rect.y != y);
if (isVisible() && (resize || translate)) {
erase();
}
if (translate) {
int dx = rect.x - x;
int dy = rect.y - y;
primTranslate(dx, dy);
}
bounds.width = rect.width;
bounds.height = rect.height;
if (resize || translate) {
fireFigureMoved();
fireCoordinateSystemChanged();
repaint();
}
}
};
delegatingLayoutManager = new DelegatingLayoutManager(this);
f.setLayoutManager(delegatingLayoutManager);
f.setOpaque(true);
ConnectionLayer cLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER);
cLayer.setAntialias(SWT.ON);
FanRouter fanRouter = new FanRouter();
fanRouter.setSeparation(20);
ShortestPathConnectionRouter router = new ShortestPathConnectionRouter(f);
fanRouter.setNextRouter(router);
cLayer.setConnectionRouter(fanRouter);
return f;
}
/**
* @see org.springframework.ide.eclipse.config.graph.parts.ActivityPart#deactivate()
*/
@Override
public void deactivate() {
prefStore.removePropertyChangeListener(this);
getViewer().getEditDomain().getCommandStack().removeCommandStackListener(stackListener);
super.deactivate();
}
public int getDirection() {
return direction;
}
private void handleLayoutChange(PropertyChangeEvent event) {
getFigure().setLayoutManager(delegatingLayoutManager);
}
private void handleLayoutReset(PropertyChangeEvent event) {
isLayoutReset = true;
isFirstManualLayout = true;
diagram.doResetCoordinates();
handleLayoutChange(event);
}
public boolean isFirstManualLayout() {
return isFirstManualLayout;
}
public boolean isManualLayout() {
return prefStore.getBoolean(SpringConfigPreferenceConstants.PREF_MANUAL_LAYOUT);
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#isSelectable()
*/
@Override
public boolean isSelectable() {
return false;
}
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
if (SpringConfigPreferenceConstants.PREF_MANUAL_LAYOUT.equals(property)) {
handleLayoutChange(event);
}
else if (SpringConfigPreferenceConstants.PROP_RESET_LAYOUT.equals(property)) {
Object value = event.getNewValue();
if (value != null && value.equals(diagram.getNamespaceUri())) {
handleLayoutReset(event);
}
}
}
@Override
public void refresh() {
((AbstractConfigGraphDiagram) getModelElement()).refreshModelFromXml();
super.refresh();
}
@Override
protected void refreshVisuals() {
// no-op
}
/**
* Updates the bounds of the figure (without invoking any event handling),
* and sets the layout constraint data
*
* @return
*/
public boolean setBoundsOnFigure(boolean updateConstraint) {
List parts = getChildren();
for (Iterator iter = parts.iterator(); iter.hasNext();) {
ActivityPart part = (ActivityPart) iter.next();
Activity activity = part.getModelElement();
Rectangle bounds = activity.getBounds();
if (isFirstManualLayout) {
Rectangle savedBounds = diagram.doReadCoordinates(activity);
if (savedBounds != null) {
bounds = savedBounds;
}
}
IFigure figure = part.getFigure();
if (bounds != null && figure != null && updateConstraint) {
delegatingLayoutManager.setXYLayoutConstraint(figure, new Rectangle(bounds.x, bounds.y, bounds.width,
bounds.height));
activity.setBounds(bounds);
activity.setHasManualBounds(true);
}
}
isFirstManualLayout = false;
return true;
}
/**
* Updates the bounds in the model so that the same bounds can be restored
* after saving
*
* @return
*/
public boolean setBoundsOnModel() {
List parts = getChildren();
for (Iterator iter = parts.iterator(); iter.hasNext();) {
ActivityPart part = (ActivityPart) iter.next();
Activity activity = part.getModelElement();
IFigure figure = part.getFigure();
if (figure != null && (!activity.hasManualBounds() || isLayoutReset)) {
Rectangle bounds = figure.getBounds().getCopy();
activity.setBounds(bounds);
}
}
isLayoutReset = false;
return true;
}
}