/* $Id: SimpleStateTransformer.java 18634 2010-08-09 07:56:08Z mvw $
*******************************************************************************
* Copyright (c) 2010 Contributors - see below
* 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:
* mvw
*******************************************************************************
*/
package org.argouml.transformer;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.Action;
import org.apache.log4j.Logger;
import org.argouml.i18n.Translator;
import org.argouml.kernel.Project;
import org.argouml.model.Model;
import org.argouml.uml.diagram.DiagramSettings;
import org.argouml.uml.diagram.state.ui.FigCompositeState;
import org.argouml.uml.diagram.state.ui.FigSimpleState;
import org.argouml.uml.diagram.state.ui.FigTransition;
import org.argouml.uml.diagram.ui.FigEdgeModelElement;
import org.argouml.uml.diagram.ui.FigNodeModelElement;
import org.tigris.gef.base.Layer;
import org.tigris.gef.base.LayerPerspective;
import org.tigris.gef.presentation.Fig;
import org.tigris.gef.presentation.FigEdge;
import org.tigris.gef.presentation.FigNode;
/**
* This class transforms a SimpleState into a CompositeState. <p>
*
* This involves copying the following:
* from State:
* entry : Action
* exit : Action
* deferrableEvent : Event
* internalTransition : Transition
* doActivity : Action
* stateMachine : StateMachine
* from StateVertex:
* container : CompositeState
* outgoing : Transition
* incoming : Transition
* from ModelElement:
* name
* and maybe others...
*
* @author michiel
*/
class SimpleStateTransformer implements Transformer {
private static final Logger LOG =
Logger.getLogger(SimpleStateTransformer.class);
public List<Action> actions(Project p, Object sourceModelElement) {
assert Model.getFacade().isASimpleState(sourceModelElement);
List<Action> result = new ArrayList<Action>();
result.add(new SimpleStateToCompositeState(p, sourceModelElement));
return result;
}
public boolean canTransform(Object sourceModelElement) {
return Model.getFacade().isASimpleState(sourceModelElement);
}
class SimpleStateToCompositeState extends TransformerAction {
SimpleStateToCompositeState(Project project, Object sourceModelElement) {
super(Translator.localize("transform.button.new-compositestate"),
project, sourceModelElement);
}
public void actionPerformed(ActionEvent e) {
LOG.debug("Transforming a SimpleState into a CompositeState");
// Editor editor = Globals.curEditor();
// GraphModel gm = editor.getGraphModel();
// LayerDiagram lay =
// ((LayerDiagram) editor.getLayerManager().getActiveLayer());
super.actionPerformed(e);
Object entry = Model.getFacade().getEntry(getSource());
Object exit = Model.getFacade().getExit(getSource());
/* Need to copy the lists since we will be moving the elements: */
Collection deferEvts = new ArrayList(Model.getFacade().getDeferrableEvents(getSource()));
Collection intTrans = new ArrayList(Model.getFacade().getInternalTransitions(getSource()));
Object doActivity = Model.getFacade().getDoActivity(getSource());
Object sm = Model.getFacade().getStateMachine(getSource());
Object container = Model.getFacade().getContainer(getSource());
Collection outgoings = new ArrayList(Model.getFacade().getOutgoings(getSource()));
Collection incomings = new ArrayList(Model.getFacade().getIncomings(getSource()));
outgoings.removeAll(intTrans);
incomings.removeAll(intTrans);
LOG.debug("Transformer found " + intTrans.size() + " internal transitions.");
LOG.debug("Transformer found " + incomings.size() + " incoming transitions.");
LOG.debug("Transformer found " + outgoings.size() + " outgoing transitions.");
String name = Model.getFacade().getName(getSource());
Object cs = Model.getStateMachinesFactory().buildCompositeState(container);
Model.getStateMachinesHelper().setEntry(getSource(), null);
Model.getStateMachinesHelper().setEntry(cs, entry);
Model.getStateMachinesHelper().setExit(getSource(), null);
Model.getStateMachinesHelper().setExit(cs, exit);
for (Object de : deferEvts) {
Model.getStateMachinesHelper().removeDeferrableEvent(getSource(), de);
Model.getStateMachinesHelper().addDeferrableEvent(cs, de);
}
Model.getStateMachinesHelper().setInternalTransitions(getSource(), Collections.EMPTY_LIST);
Model.getStateMachinesHelper().setInternalTransitions(cs, intTrans);
Model.getStateMachinesHelper().setDoActivity(getSource(), null);
Model.getStateMachinesHelper().setDoActivity(cs, doActivity);
Model.getStateMachinesHelper().setStateMachine(cs, sm);
for (Object to : outgoings) {
Model.getStateMachinesHelper().setSource(to, null);
Model.getStateMachinesHelper().setSource(to, cs);
}
for (Object ti : incomings) {
Model.getCommonBehaviorHelper().setTarget(ti, null);
Model.getCommonBehaviorHelper().setTarget(ti, cs);
}
Model.getCoreHelper().setName(cs, name);
// This is not necessarily the current diagram!
Collection<Fig> figs = getProject().findAllPresentationsFor(getSource());
LOG.debug("Transformer found " + figs.size() + " representations (Figs).");
for (Fig ssFig : figs) {
LOG.debug("Transformer found a Fig: " + ssFig);
assert ssFig.getOwner() == getSource();
assert ssFig instanceof FigSimpleState;
Rectangle bounds = ssFig.getBounds();
DiagramSettings settings = ((FigNodeModelElement) ssFig).getSettings();
Layer lay = ssFig.getLayer();
/* Remove the old fig from the diagram, so we can draw the
* new one in its place: */
ssFig.removeFromDiagram();
FigCompositeState fcs =
new FigCompositeState(cs, bounds, settings);
lay.add(fcs);
fcs.setBounds(bounds);
((LayerPerspective) lay).putInPosition(fcs);
fcs.renderingChanged();
for (Object to : outgoings) {
makeTransition(settings, lay, to);
}
for (Object ti : incomings) {
makeTransition(settings, lay, ti);
}
}
Model.getUmlFactory().delete(getSource());
// p.moveToTrash(source);
}
private void makeTransition(DiagramSettings settings, Layer lay,
Object transUml) {
FigTransition transFig = new FigTransition(transUml, settings);
setPorts(lay, transFig);
lay.add(transFig);
transFig.computeRoute();
transFig.renderingChanged();
}
/**
* TODO: Copied from UmlDiagramRenderer.
*
* Find the Figs in the given layer that should be the source and
* destination and attach these to either end of the FigEdge
* @param layer the layer to look for the FigNodes
* @param newEdge The edge to attach
*/
protected final void setPorts(Layer layer, FigEdge newEdge) {
Object modelElement = newEdge.getOwner();
if (newEdge.getSourcePortFig() == null) {
Object tSource;
tSource = Model.getUmlHelper().getSource(modelElement);
FigNode sourceNode = getNodePresentationFor(layer, tSource);
assert (sourceNode != null) : "No FigNode found for " + tSource;
setSourcePort(newEdge, sourceNode);
}
if (newEdge.getDestPortFig() == null) {
Object tDest;
tDest = Model.getUmlHelper().getDestination(newEdge.getOwner());
setDestPort(newEdge, getNodePresentationFor(layer, tDest));
}
if (newEdge.getSourcePortFig() == null
|| newEdge.getDestPortFig() == null) {
throw new IllegalStateException("Edge of type "
+ newEdge.getClass().getName()
+ " created with no source or destination port");
}
}
private void setSourcePort(FigEdge edge, FigNode source) {
edge.setSourcePortFig(source);
edge.setSourceFigNode(source);
}
private void setDestPort(FigEdge edge, FigNode dest) {
edge.setDestPortFig(dest);
edge.setDestFigNode(dest);
}
/**
* TODO: Copied from UmlDiagramRenderer.
*
* Get the FigNode from the given layer that represents the given
* model element.
* The FigNode portion of an association class is returned in preference
* to the FigEdge portion.
* If no FigNode is found then a FIgEdge is searched for and the FigNode
* that acts as its edge port is returned.
* @param lay the layer containing the Fig
* @param modelElement the model element to find presentation for
* @return the FigNode presentation of the model element
*/
private FigNode getNodePresentationFor(Layer lay, Object modelElement) {
assert modelElement != null : "A modelElement must be supplied";
for (Object fig : lay.getContentsNoEdges()) {
if (fig instanceof FigNode
&& modelElement.equals(((FigNode) fig).getOwner())) {
return ((FigNode) fig);
}
}
for (Object fig : lay.getContentsEdgesOnly()) {
if (fig instanceof FigEdgeModelElement
&& modelElement.equals(((FigEdgeModelElement) fig)
.getOwner())) {
return ((FigEdgeModelElement) fig).getEdgePort();
}
}
return null;
}
}
}