package org.framed.orm.ui.editPart;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.AbstractBorder;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.gef.CompoundSnapToHelper;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.SnapToGeometry;
import org.eclipse.gef.SnapToGrid;
import org.eclipse.gef.SnapToHelper;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.SnapFeedbackPolicy;
import org.framed.orm.model.Model;
import org.framed.orm.model.ModelElement;
import org.framed.orm.model.Relation;
import org.framed.orm.model.Shape;
import org.framed.orm.model.Type;
import org.framed.orm.ui.editPolicy.ORMContainerEditPolicy;
import org.framed.orm.ui.editPolicy.ORMModelXYLayoutPolicy;
import org.framed.orm.ui.figure.shapes.ORMCompartmentV2Figure;
import org.framed.orm.ui.figure.ORMFigureFactory;
import org.framed.orm.ui.figure.shapes.ORMRootModelFigure;
import org.framed.orm.ui.figure.shapes.ORMShapeFigure;
/**
* This {@link EditPart} is the controller for the model element {@link Model}.
*
* @author Kay Bierzynski
* */
public class ORMModelEditPart extends AbstractGraphicalEditPart {
/**
* The {@link Adapter} of this controller, which recieves the notifications from the viewer/user.
* This {@link EditPart} reacts on the notifications
*/
private final ORMModelAdapter adapter;
/**
* Constructor of this class. In which the class is initialized through calling the constructor of
* it's parent and initializing it's {@link Adapter}.
*/
public ORMModelEditPart() {
super();
adapter = new ORMModelAdapter();
}
/**
* {@inheritDoc} {@link Model}s have as a figure a {@link ORMRootModelFigure}. The border of the
* figure is differs depending on if the parent is a {@link Shape} from type Group or a
* {@link Shape} from type comaprtemnt and on the expandstate of the parent figure.
*/
@Override
protected IFigure createFigure() {
final GraphicalEditPart parent = (GraphicalEditPart) getParent();
Figure fig = ORMFigureFactory.createFigure(this);
setFigureBorder(parent, fig);
return fig;
}
/**
* {@inheritDoc} The Model shouldn't be selectable, because for that reason we need to override
* the isSelectable function.
*/
@Override
public boolean isSelectable() {
return false;
}
/** {@inheritDoc} */
@Override
public IFigure getContentPane() {
return getFigure();
}
/**
* A border class where a border is drawn at top side of the figure and on the left side of the
* figure.
* */
public class PartFigureBorderExpand extends AbstractBorder {
/** {@inheritDoc} */
@Override
public Insets getInsets(IFigure figure) {
return new Insets(1, 0, 0, 0);
}
/** {@inheritDoc} */
@Override
public void paint(IFigure figure, Graphics graphics, Insets insets) {
// draw border at the top side of the figure
graphics.drawLine(getPaintRectangle(figure, insets).getTopLeft(), tempRect.getTopRight());
// draw border at the left side of the figure
graphics.drawLine(getPaintRectangle(figure, insets).getTopLeft(), tempRect.getBottomLeft());
}
}
/**
* A border class where a border is drawn at top side of the figure.
* */
public class PartFigureBorderNotExpand extends AbstractBorder {
/** {@inheritDoc} */
@Override
public Insets getInsets(IFigure figure) {
return new Insets(1, 0, 0, 0);
}
/** {@inheritDoc} */
@Override
public void paint(IFigure figure, Graphics graphics, Insets insets) {
// draw border at the top side of the figure
graphics.drawLine(getPaintRectangle(figure, insets).getTopLeft(), tempRect.getTopRight());
}
}
/** {@inheritDoc} */
@Override
protected void createEditPolicies() {
// edit policy, which handles the creation of the children of the compartment diagram and the
// adding of the children to the compartment diagram
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ORMModelXYLayoutPolicy());
installEditPolicy(EditPolicy.CONTAINER_ROLE, new ORMContainerEditPolicy());
installEditPolicy("Snap Feedback", new SnapFeedbackPolicy());
}
/** {@inheritDoc} */
@Override
protected List getModelChildren() {
List contexts = new ArrayList();
Model cd = (Model) getModel();
// all children of compartmentdiagram are model elments
// only relations and the connection anchor shape(for now only the relationship_shape_child) are handled
// in other ways and because of that are not added as a model children
for (ModelElement ele : cd.getElements()) {
if (!(ele instanceof Relation)) {
if (!ele.getType().equals(Type.RELATIONSHIP_SHAPE_CHILD)) {
contexts.add(ele);
}
}
}
return contexts;
}
/**
* {@inheritDoc} The refreshVisuals of this {@link EditPart} updates the borders of the
* {@link ORMRootModelFigure} depending on the expandstate of it's parents figure.
* */
@Override
public void refreshVisuals() {
final Figure figure = (Figure) getFigure();
final GraphicalEditPart parent = (GraphicalEditPart) getParent();
setFigureBorder(parent, figure);
}
/**
* A setter, which sets the border of the {@link ORMRootModelFigure} depending on it's parent and
* the expandstate of the parent figure.
* */
private void setFigureBorder(GraphicalEditPart parent, Figure fig) {
if (getParent().getModel() instanceof Shape) {
ORMShapeFigure parentFigure = (ORMShapeFigure) parent.getFigure();
if (parentFigure instanceof ORMCompartmentV2Figure && parentFigure.isExpanded()) {
fig.setBorder(new PartFigureBorderExpand());
} else {
fig.setBorder(new PartFigureBorderNotExpand());
}
}
}
/** {@inheritDoc} */
@Override
public void activate() {
if (!isActive()) {
((Model) getModel()).eAdapters().add(adapter);
}
super.activate();
}
/** {@inheritDoc} */
@Override
public void deactivate() {
if (isActive()) {
((Model) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
/**
* {@inheritDoc} In this {@link EditPart} this method add adapter types for creating a
* {@link SnapToHelper} when the editor is in snapping mode (either to grid or to shapes).
*/
@Override
public Object getAdapter(final Class key) {
if (key == SnapToHelper.class) {
List<SnapToHelper> helpers = new ArrayList<SnapToHelper>();
if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED))) {
helpers.add(new SnapToGeometry(this));
}
if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGrid.PROPERTY_GRID_ENABLED))) {
helpers.add(new SnapToGrid(this));
}
if (helpers.size() == 0) {
return null;
} else {
return new CompoundSnapToHelper(helpers.toArray(new SnapToHelper[0]));
}
}
return super.getAdapter(key);
}
/**
* The {@link Adapter} of this {@link EditPart}. An adapter is a receiver of notifications and is
* typically associated with a Notifier via an AdapterFactory. This {@link Adapter} calls the
* refreshChildren() method when it gets a change notification.
*
* */
public class ORMModelAdapter implements Adapter {
/** {@inheritDoc} */
@Override
public void notifyChanged(final Notification notification) {
refreshChildren();
}
/** {@inheritDoc} */
@Override
public Notifier getTarget() {
return (Model) getModel();
}
/** {@inheritDoc} */
@Override
public void setTarget(final Notifier newTarget) {
// Do nothing.
}
/** {@inheritDoc} */
@Override
public boolean isAdapterForType(final Object type) {
return type.getClass().equals(Model.class);
}
}
}