/*******************************************************************************
* Copyright (c) 2010-2015 Henshin developers. 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:
* TU Berlin, University of Luxembourg, SES S.A.
*******************************************************************************/
package de.tub.tfs.henshin.tggeditor.editparts.rule;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.henshin.model.And;
import org.eclipse.emf.henshin.model.Formula;
import org.eclipse.emf.henshin.model.HenshinPackage;
import org.eclipse.emf.henshin.model.Mapping;
import org.eclipse.emf.henshin.model.NestedCondition;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Not;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.gef.EditPolicy;
import de.tub.tfs.henshin.tgg.TNode;
import de.tub.tfs.henshin.tgg.TggPackage;
import de.tub.tfs.henshin.tgg.interpreter.util.ExceptionUtil;
import de.tub.tfs.henshin.tgg.interpreter.util.RuleUtil;
import de.tub.tfs.henshin.tggeditor.commands.create.rule.MarkCommand;
import de.tub.tfs.henshin.tggeditor.editparts.graphical.TNodeObjectEditPart;
import de.tub.tfs.henshin.tggeditor.editpolicies.graphical.NodeComponentEditPolicy;
import de.tub.tfs.henshin.tggeditor.editpolicies.graphical.NodeGraphicalEditPolicy;
import de.tub.tfs.henshin.tggeditor.editpolicies.rule.RuleNodeXYLayoutEditPolicy;
import de.tub.tfs.henshin.tggeditor.figures.NodeFigure;
import de.tub.tfs.henshin.tggeditor.util.GraphicalNodeUtil;
import de.tub.tfs.muvitor.commands.SimpleDeleteEObjectCommand;
/**
* The class RuleNodeEditPart.
*/
public class RuleNodeEditPart extends TNodeObjectEditPart {
/** The NACs mappings. (NACs mappings only!!)*/
protected List<Mapping> mappings;
/** the lhs node belongs to model (which is the rhs node) */
TNode lhsNode;
/** the rhs node (which is the model) */
TNode rhsNode;
/**
* Instantiates a new rule node edit part.
*
* @param model the model
*/
public RuleNodeEditPart(TNode model) {
super(model);
rhsNode = model;
//NodeUtil.refreshIsMarked(rhsNode);
mappings = new ArrayList<Mapping>();
setRuleMapping(model);
setNacMappings(model);
cleanUpRule();
}
private void cleanUpRule() {
// remove node duplicates in LHS
ArrayList<Node> lhsNodeList = RuleUtil
.getAllLHSNodes(rhsNode);
// remove duplicates
while (lhsNodeList.size() > 1) {
Node lhsNode = lhsNodeList.get(0);
lhsNodeList.remove(0);
SimpleDeleteEObjectCommand cmd = new SimpleDeleteEObjectCommand(
lhsNode);
cmd.execute();
}
// remove lhs node, if rule creates the node
if( rhsNode.getMarkerType()!=null
&& rhsNode.getMarkerType().equals(RuleUtil.NEW)){
if (lhsNodeList.size()==1)
{
Node lhsNode = lhsNodeList.get(0);
lhsNodeList.remove(0);
if(lhsNode.getGraph()!=null){
// don't delete the node instead remove the marker
rhsNode.setMarkerType(null);
lhsNodeList.clear();
}
else // parent reference of node is missing, thus remove it directly
rhsNode.getGraph().getRule().getLhs().getNodes().remove(lhsNode);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
*/
@Override
protected IFigure createFigure() {
super.createFigure();
return figure;
}
@Override
protected void createEditPolicies() {
installEditPolicy(EditPolicy.LAYOUT_ROLE, new RuleNodeXYLayoutEditPolicy());
installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeComponentEditPolicy());
installEditPolicy(EditPolicy.NODE_ROLE, new NodeGraphicalEditPolicy());
}
// @Override
// protected void refreshVisuals() {
// super.refreshVisuals();
// updateMarker();
// }
// //@Override
// protected void updateMarker() {
//// if (rhsNode==null) return;
//// NodeFigure figure = this.getNodeFigure();
//// if (rhsNode.getMarkerType() != null) {
//// if (rhsNode.getMarkerType().equals(RuleUtil.NEW)) {
//// // node marker type is "shall be created"
//// if (rhsNode.getMarkerType() != null)
//// figure.setMarked(true);
//// }
//// else if (rhsNode.getMarkerType().equals(RuleUtil.Translated)) {
//// // node marker type is "shall be translated"
//// if (rhsNode.getMarkerType() != null)
//// figure.setTranslated(true);
//// }
//// } else {
//// figure.setTranslated(false);
//// }
// }
@Override
protected void notifyChanged(Notification notification) {
if (notification.getNotifier() instanceof Node) {
int featureId = notification.getFeatureID(HenshinPackage.class);
int type = notification.getEventType();
final Object newValue = notification.getNewValue();
final Object oldValue = notification.getOldValue();
switch (type) {
case Notification.SET:
case Notification.UNSET:
refreshFigureName();
refreshVisuals();
break;
case Notification.ADD:
case Notification.ADD_MANY:
if (type == Notification.ADD && newValue instanceof Mapping) {
final Mapping m = (Mapping) newValue;
// NAC mapping only
if (this.mapping != null
// && m.getOrigin() == this.mapping.getOrigin()
&& m.getImage() != getModel()) {
if (!mappings.contains(m)) {
mappings.add(m);
if (this.index == -1)
this.index = this.mapping.getOrigin().getGraph().getNodes().indexOf(this.mapping.getOrigin());
refreshFigureName();
refreshVisuals();
break;
}
}
}
break;
case Notification.REMOVE:
case Notification.REMOVE_MANY:
if (type == Notification.REMOVE && oldValue instanceof Mapping) {
final Mapping m = (Mapping) oldValue;
// NAC mapping only
if (mappings.contains(m)
&& m.getImage() != getModel()) {
mappings.remove(m);
if (mappings.size() == 0) {
this.index = -1;
refreshFigureName();
refreshVisuals();
break;
}
}
}
break;
}
switch (featureId) {
case -1:
refreshSourceConnections();
refreshTargetConnections();
refreshChildren();
break;
case HenshinPackage.NODE__NAME:
if (lhsNode != null && (lhsNode.getName() == null || !lhsNode.getName().equals(getCastedModel().getName()))) {
lhsNode.setName(getCastedModel().getName());
}
refreshFigureName();
refreshVisuals();
break;
case HenshinPackage.NODE__TYPE:
case TggPackage.TNODE__MARKER_TYPE: // is always triggered by case above
refreshVisuals();
break;
case HenshinPackage.NODE__INCOMING:
refreshTargetConnections();
break;
case HenshinPackage.NODE__OUTGOING:
refreshSourceConnections();
break;
case HenshinPackage.NODE__ATTRIBUTES:
refreshChildren();
refreshVisuals();
break;
//case HenshinPackage.LAYOUT_ELEMENT__X:
//case HenshinPackage.MARKED_ELEMENT__IS_MARKED:
// duplicates to NODE__NAME
case TggPackage.TNODE__X:
case TggPackage.TNODE__Y:
refreshVisuals();
break;
}
}
if (notification.getNotifier() instanceof Mapping
&& this.mapping != null) {
int type = notification.getEventType();
final Object newValue = notification.getNewValue();
final Object oldValue = notification.getOldValue();
switch (type) {
case Notification.SET:
if (newValue instanceof Node) {
final Mapping m = (Mapping) notification.getNotifier();
// NAC mapping only
if (m.getOrigin() == this.mapping.getOrigin()
&& m.getImage() != getModel()) {
if (!mappings.contains(m)) {
mappings.add(m);
}
if (this.index == -1)
this.index = this.mapping.getOrigin().getGraph().getNodes().indexOf(this.mapping.getOrigin());
refreshFigureName();
refreshVisuals();
break;
}
}
break;
case Notification.ADD:
case Notification.ADD_MANY:
if (newValue instanceof Mapping) {
final Mapping m = (Mapping) newValue;
// NAC mapping only
if (m.getOrigin() == this.mapping.getOrigin()
&& m.getImage() != getModel()) {
if (!mappings.contains(m)) {
mappings.add(m);
if (this.index == -1)
this.index = this.mapping.getOrigin().getGraph().getNodes().indexOf(this.mapping.getOrigin());
refreshFigureName();
refreshVisuals();
break;
}
}
}
break;
case Notification.UNSET:
if (newValue instanceof Node) {
final Mapping m = (Mapping) notification.getNotifier();
// NAC mapping only
if (mappings.contains(m)
&& m.getOrigin() == this.mapping.getOrigin()
&& m.getImage() != getModel()) {
mappings.remove(m);
if (mappings.size() == 0) {
this.index = -1;
refreshFigureName();
refreshVisuals();
break;
}
}
}
break;
case Notification.REMOVE:
case Notification.REMOVE_MANY:
if (oldValue instanceof Mapping) {
final Mapping m = (Mapping) oldValue;
// NAC mapping only
if (mappings.contains(m)
&& m.getOrigin() == this.mapping.getOrigin()
&& m.getImage() != getModel()) {
mappings.remove(m);
if (mappings.size() == 0) {
this.index = -1;
refreshFigureName();
refreshVisuals();
break;
}
}
}
break;
}
}
}
/**
* iterates over all rule mappings and sets the right mapping and lhs node
* @param model the node
*/
private void setRuleMapping(TNode model) {
if ( model.getGraph().getRule() == null)
return;
EList<Mapping> maps = model.getGraph().getRule().getMappings();
for (Mapping m: maps) {
if (m.getImage() == model && m.getOrigin() instanceof TNode) {
this.mapping = m;
lhsNode = (TNode) this.mapping.getOrigin();
break;
}
}
}
/**
* gets the rule mapping
* @return the rule mapping
*/
public Mapping getRuleMapping() {
return this.mapping;
}
@Override
public Mapping getNacMapping() {
{ExceptionUtil.error("NAC mapping was requested but not computed for this node."); return null;}
}
@Override
protected void setNacMapping(Node model) {
}
@Override
public void setNacMapping(Mapping m) {
}
/**
* sets the nac mappings belongs to model
* @param model the model
*/
private void setNacMappings(TNode model) {
// NodeLayout layoutModel = getLayoutModel();
if (getCastedModel().getGraph().eContainer() instanceof Rule
//&& model.getIsMarked()!=null && model.getIsMarked()
) {
Formula f = ((Rule) getCastedModel().getGraph().eContainer()).getLhs().getFormula();
if (f != null) {
addNacMappings(f, model);
if (this.mappings.size() > 0)
this.index = model.getGraph().getNodes().indexOf(getModel());
}
}
}
/**
* adds nac mappings
* @param f the formula
* @param model the node
*/
private void addNacMappings(Formula f, TNode model) {
if (f instanceof And) {
if (((And)f).getLeft() instanceof And)
addNacMappings(((And)f).getLeft(), model);
else
addNacMaps(((And)f).getLeft(), model);
if (((And)f).getRight() instanceof And)
addNacMappings(((And)f).getRight(), model);
else
addNacMaps(((And)f).getRight(), model);
}
else
addNacMaps(f, model);
}
/**
* helper method for addNacMappings
* @param f the Formula
* @param model the model
*/
private void addNacMaps(Formula f, Node model) {
EList<Mapping> maps = ((NestedCondition)((Not)f).getChild()).getMappings();
for (Mapping m : maps) {
if (m.getOrigin() == RuleUtil.getLHSNode(model))
this.mappings.add(m);
}
}
/**
* adds a mapping to mappings
* @param m the new mapping
*/
public void addMapping(Mapping m) {
if (!this.mappings.contains(m)) {
this.mappings.add(m);
registerAdapter(m);
}
}
@Override
protected void performOpen() {
// do nothing
}
}