alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

// $Id: StateDiagramGraphModel.java,v 1.46 2004/09/28 11:12:21 bobtarling Exp $
// Copyright (c) 1996-2004 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies. This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason. IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

// File: StateDiagramGraphModel.java
// Classes: StateDiagramGraphModel
// Original Author: your email address here
package org.argouml.uml.diagram.state;

import java.beans.PropertyChangeEvent;
import java.beans.VetoableChangeListener;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.argouml.kernel.ProjectManager;
import org.argouml.model.ModelFacade;
import org.argouml.model.uml.UmlFactory;
import org.argouml.model.uml.behavioralelements.statemachines.StateMachinesFactory;
import org.argouml.model.uml.behavioralelements.statemachines.StateMachinesHelper;
import org.argouml.uml.diagram.UMLMutableGraphSupport;
import org.argouml.uml.diagram.static_structure.ui.CommentEdge;

/**
 * This class defines a bridge between the UML meta-model representation of the
 * design and the GraphModel interface used by GEF. This class handles only UML
 * MState Digrams.
 */

public class StateDiagramGraphModel extends UMLMutableGraphSupport implements
        VetoableChangeListener {

    private static final Logger LOG = 
        Logger.getLogger(StateDiagramGraphModel.class);
    /**
     * The "home" UML model of this diagram, not all ModelElements in
     * this graph are in the home model, but if they are added and
     * don't already have a model, they are placed in the "home
     * model". Also, elements from other models will have their
     * FigNodes add a line to say what their model is.
     */
    private Object namespace;

    /** The statemachine we are diagramming */
    private Object machine;

    ////////////////////////////////////////////////////////////////
    // accessors

    /**
     * @see org.argouml.uml.diagram.UMLMutableGraphSupport#getNamespace()
     */
    public Object getNamespace() {
        return namespace;
    }

    /**
     * @param ns the namespace
     */
    public void setNamespace(Object ns) {

        if (!ModelFacade.isANamespace(ns))
                throw new IllegalArgumentException();
        namespace = ns;
    }

    /**
     * @return the statemachine of this diagram
     */
    public Object getMachine() {
        return machine;
    }

    /**
     * @param sm   the statemachine of this diagram
     */
    public void setMachine(Object sm) {

        if (!ModelFacade.isAStateMachine(sm))
                throw new IllegalArgumentException();

        if (sm != null) {
            machine = sm;
        }
    }

    ////////////////////////////////////////////////////////////////
    // GraphModel implementation

    /**
     * Return all ports on node or edge.
     *
     * @return The ports.
     * @param nodeOrEdge The node or the edge.
     */
    public List getPorts(Object nodeOrEdge) {
        Vector res = new Vector(); //wasteful!
        if (ModelFacade.isAState(nodeOrEdge)) {
	    res.addElement(nodeOrEdge);
	}
        if (ModelFacade.isAPseudostate(nodeOrEdge)) {
	    res.addElement(nodeOrEdge);
	}
        return res;
    }

    /**
     * Return the node or edge that owns the given port.
     *
     * @param port the port
     * @return The owner of the port.
     * @see org.tigris.gef.graph.BaseGraphModel#getOwner(java.lang.Object)
     */
    public Object getOwner(Object port) {
        return port;
    }

    /** Return all edges going to given port 
     * 
     * @see org.tigris.gef.graph.GraphModel#getInEdges(java.lang.Object)
     */
    public List getInEdges(Object port) {
        if (ModelFacade.isAStateVertex(port)) {
	    return new Vector(ModelFacade.getIncomings(port));
	}
        LOG.debug("TODO: getInEdges of MState");
        return new Vector(); //wasteful!
    }

    /** Return all edges going from given port
     * 
     * @see org.tigris.gef.graph.GraphModel#getOutEdges(java.lang.Object)
     */
    public List getOutEdges(Object port) {
        if (ModelFacade.isAStateVertex(port)) {
	    return new Vector(ModelFacade.getOutgoings(port));
	}
        LOG.debug("TODO: getOutEdges of MState");
        return new Vector(); //wasteful!
    }

    /** Return one end of an edge
     * 
     * @see org.tigris.gef.graph.BaseGraphModel#getSourcePort(java.lang.Object)
     */
    public Object getSourcePort(Object edge) {
        if (ModelFacade.isATransition(edge)) {
	    return StateMachinesHelper.getHelper()
		.getSource(/* (MTransition) */edge);
	}
        LOG.debug("TODO: getSourcePort of MTransition");
        return null;
    }

    /** Return the other end of an edge 
     *
     * @see org.tigris.gef.graph.BaseGraphModel#getDestPort(java.lang.Object)
     */
    public Object getDestPort(Object edge) {
        if (ModelFacade.isATransition(edge)) {
	    return StateMachinesHelper.getHelper()
		.getDestination(/* (MTransition) */edge);
	}
        LOG.debug("TODO: getDestPort of MTransition");
        return null;
    }

    ////////////////////////////////////////////////////////////////
    // MutableGraphModel implementation

    /** Return true if the given object is a valid node in this graph
     * 
     * @see org.tigris.gef.graph.MutableGraphModel#canAddNode(java.lang.Object)
     */
    public boolean canAddNode(Object node) {
        if (node == null) return false;
        if (containsNode(node)) return false;
        return (ModelFacade.isAStateVertex(node) 
                || ModelFacade.isAPartition(node) 
                || ModelFacade.isAComment(node));
    }

    /** Return true if the given object is a valid edge in this graph
     * 
     * @see org.tigris.gef.graph.MutableGraphModel#canAddEdge(java.lang.Object)
     */
    public boolean canAddEdge(Object edge) {
        if (super.canAddEdge(edge)) {
            return true;
        }
        if (edge == null) return false;
        if (containsEdge(edge)) return false;
        Object end0 = null, end1 = null, state = null;

        if (ModelFacade.isATransition(edge)) {
            state = ModelFacade.getState(edge);
            end0 = ModelFacade.getSource(edge);
            end1 = ModelFacade.getTarget(edge);
            // it's not allowed to directly draw a transition 
            // from a composite state to one of it's substates.
            if (ModelFacade.isACompositeState(end0) 
                    && StateMachinesHelper.getHelper().getAllSubStates(end0)
                                                        .contains(end1)) {
                return false;
            }
        }

        if (end0 == null || end1 == null) return false;
        // if all states are equal it is an internal transition
        if ((state == end0) && (state == end1)) return false;
        if (!containsNode(end0)) return false;
        if (!containsNode(end1)) return false;
        
        return true;
    }

    /** Add the given node to the graph, if valid.
     * 
     * @see org.tigris.gef.graph.MutableGraphModel#addNode(java.lang.Object)
     */
    public void addNode(Object node) {
        LOG.debug("adding statechart diagram node: " + node);
        if (!canAddNode(node)) return;
        if (!(ModelFacade.isAStateVertex(node))) {
            LOG.error("internal error: got past canAddNode");
            return;
        }
        Object sv = /* (MStateVertex) */node;

        if (containsNode(sv)) return;
        getNodes().add(sv);
        // TODO: assumes public, user pref for default visibility?
        //if (sv.getNamespace() == null)
        //_namespace.addOwnedElement(sv);
        // TODO: assumes not nested in another composite state
        Object top = /* (MCompositeState) */StateMachinesHelper.getHelper()
                .getTop(getMachine());

        ModelFacade.addSubvertex(top, sv);
        //       sv.setParent(top); this is done in setEnclosingFig!!
        //      if ((sv instanceof MState) &&
        //      (sv.getNamespace()==null))
        //      ((MState)sv).setStateMachine(_machine);
        fireNodeAdded(node);
    }

    /** Add the given edge to the graph, if valid.     
     * @see org.tigris.gef.graph.MutableGraphModel#addEdge(java.lang.Object)
     */
    public void addEdge(Object edge) {
        LOG.debug("adding statechart diagram edge!!!!!!");

        if (!canAddEdge(edge)) return;
        Object transition = /* (MTransition) */edge;
        getEdges().add(transition);
        fireEdgeAdded(edge);
    }

    /**
     * @see org.tigris.gef.graph.MutableGraphModel#addNodeRelatedEdges(java.lang.Object)
     */
    public void addNodeRelatedEdges(Object node) {
        if (ModelFacade.isAStateVertex(node)) {
            Vector transen = new Vector(ModelFacade.getOutgoings(node));
            transen.addAll(ModelFacade.getIncomings(node));
            Iterator iter = transen.iterator();
            while (iter.hasNext()) {
                Object dep = /* (MTransition) */iter.next();
                if (canAddEdge(dep)) addEdge(dep);
            }
        }
    }

    /**
     * Return true if the two given ports can be connected by a kind of edge to
     * be determined by the ports.
     *
     * @see org.tigris.gef.graph.MutableGraphModel#canConnect(java.lang.Object, 
     * java.lang.Object)
     */
    public boolean canConnect(Object fromPort, Object toPort) {
        if (!(ModelFacade.isAStateVertex(fromPort))) {
            LOG.error("internal error not from sv");
            return false;
        }
        if (!(ModelFacade.isAStateVertex(toPort))) {
            LOG.error("internal error not to sv");
            return false;
        }

        if (ModelFacade.isAFinalState(fromPort)) { return false; }
        if (ModelFacade.isAPseudostate(toPort)) {
            if ((ModelFacade.INITIAL_PSEUDOSTATEKIND).equals(ModelFacade
                    .getKind(toPort))) { return false; }
        }        
        return true;
    }

    /** Contruct and add a new edge of the given kind
     * 
     * @see org.tigris.gef.graph.MutableGraphModel#connect(java.lang.Object, 
     * java.lang.Object, java.lang.Class)
     */
    public Object connect(Object fromPort, Object toPort,
			  Class edgeClass) {

        if (ModelFacade.isAFinalState(fromPort)) {
	    return null;
	}
        if (ModelFacade.isAPseudostate(toPort)) {
	    if ((ModelFacade.INITIAL_PSEUDOSTATEKIND).equals(
			ModelFacade.getKind(toPort))) {
		return null;
	    }
	}

        if (edgeClass == (Class) ModelFacade.TRANSITION) {
            Object tr = null;
            Object comp = ModelFacade.getContainer(fromPort);
            tr = StateMachinesFactory.getFactory()
                    .buildTransition(fromPort, toPort);
            if (canAddEdge(tr)) {
                addEdge(tr);
            } else {
                ProjectManager.getManager().getCurrentProject().moveToTrash(tr);
                tr = null;
            }
            return tr;
        } else
            if (edgeClass == CommentEdge.class) {
                try {
                    Object connection = UmlFactory.getFactory()
                        .buildConnection(edgeClass, fromPort, null, 
                                                toPort, null, null);
                    addEdge(connection);
                    return connection;
                }
                catch (Exception ex) {
                    // fail silently                
                }
                return null;
            }
            
            else {
                LOG.debug("wrong kind of edge in StateDiagram connect3 "
                        + edgeClass);
                return null;
            }
    }

    ////////////////////////////////////////////////////////////////
    // VetoableChangeListener implementation

    /**
     * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
     */
    public void vetoableChange(PropertyChangeEvent pce) {
        //throws PropertyVetoException

        if ("ownedElement".equals(pce.getPropertyName())) {
            Vector oldOwned = (Vector) pce.getOldValue();
            Object eo = /* (MElementImport) */pce.getNewValue();
            Object me = ModelFacade.getModelElement(eo);
            if (oldOwned.contains(eo)) {
                LOG.debug("model removed " + me);
                if (ModelFacade.isAState(me)) removeNode(me);
                if (ModelFacade.isAPseudostate(me)) removeNode(me);
                if (ModelFacade.isATransition(me)) removeEdge(me);
            } else {
                LOG.debug("model added " + me);
            }
        }
    }

    static final long serialVersionUID = -8056507319026044174L;

    /**
     * @param newNode
     *            this is the new node that one of the ends is dragged to.
     * @param oldNode
     *            this is the existing node that is already connected.
     * @param edge
     *            this is the edge that is being dragged/rerouted
     * @return true if a transition is being rerouted between two states.
     */
    public boolean canChangeConnectedNode(Object newNode, Object oldNode,
            Object edge) {
        // prevent no changes...
        if (newNode == oldNode) return false;

        // check parameter types:
        if (!(ModelFacade.isAState(newNode)
	      || ModelFacade.isAState(oldNode)
	      || ModelFacade.isATransition(edge))) {
	    return false;
	}

        return true;
    }

    /**
     * Reroutes the connection to the old node to be connected to the new node.
     * 
     * @param newNode
     *            this is the new node that one of the ends is dragged to.
     * @param oldNode
     *            this is the existing node that is already connected.
     * @param edge
     *            this is the edge that is being dragged/rerouted
     * @param isSource
     *            tells us which end is being rerouted.
     */
    public void changeConnectedNode(Object newNode, Object oldNode,
            Object edge, boolean isSource) {

        if (isSource)
            ModelFacade.setSource(edge, newNode);
        else
            ModelFacade.setTarget(edge, newNode);

    }

} /* end class StateDiagramGraphModel */
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.