Ptidej-v5.2-master/POM Tests/data/ArgoUML_0.28/src/org/argouml/uml/diagram/state/ui/FigConcurrentRegion.java
// $Id: FigConcurrentRegion.java 16794 2009-02-12 18:41:41Z mvw $
// Copyright (c) 1996-2009 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.

package org.argouml.uml.diagram.state.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.JSeparator;

import org.argouml.model.Model;
import org.argouml.model.UmlChangeEvent;
import org.argouml.ui.ProjectActions;
import org.argouml.uml.diagram.DiagramSettings;
import org.argouml.uml.diagram.ui.ActionAddConcurrentRegion;
import org.tigris.gef.base.Globals;
import org.tigris.gef.base.Layer;
import org.tigris.gef.base.Selection;
import org.tigris.gef.graph.GraphModel;
import org.tigris.gef.presentation.Fig;
import org.tigris.gef.presentation.FigLine;
import org.tigris.gef.presentation.FigRect;
import org.tigris.gef.presentation.FigText;
import org.tigris.gef.presentation.Handle;

/**
 * Class to display graphics for a UML ConcurrentRegion in a diagram.
 *
 * @author pepargouml@yahoo.es *
 */
public class FigConcurrentRegion extends FigState
        implements
        MouseListener,
        MouseMotionListener {

    /**
     * The horizontal margin between the region and its composite parent state.
     */
    public static final int INSET_HORZ = 3;
    /**
     * The vertical margin between the region and its composite parent state.
     */
    public static final int INSET_VERT = 5;

    private FigRect cover;
    /**
     * The divider line is the horizontal dashed line
     * shown at the top side for
     * every region except the first one.
     */
    private FigLine dividerline;
    private static Handle curHandle = new Handle(-1);

    /**
     * The constructor.
     * @deprecated for 0.27.4 by tfmorris.  Use 
     * {@link #FigConcurrentRegion(Object, Rectangle, DiagramSettings)}.
     */
    @SuppressWarnings("deprecation")
    @Deprecated
    public FigConcurrentRegion() {
        super();
        initialize();
    }

    private void initialize() {
        cover =
            new FigRect(getInitialX(),
                getInitialY(),
                getInitialWidth(), getInitialHeight(),
                INVISIBLE_LINE_COLOR, FILL_COLOR);
        dividerline = new FigLine(getInitialX(),
                getInitialY(),
                getInitialWidth(),
                getInitialY(),
                getInitialColor());
        dividerline.setDashed(true);
        getBigPort().setLineWidth(0);
        cover.setLineWidth(0);

        // add Figs to the FigNode in back-to-front order
        addFig(getBigPort());
        addFig(cover);
        addFig(getNameFig());
        addFig(dividerline);
        addFig(getInternal());

        setShadowSize(0);
    }

    /**
     * The constructor.
     *
     * @param gm (not used)
     * @param node the UML model element represented by this Fig
     * @deprecated for 0.27.4 by tfmorris.  Use 
     * {@link #FigConcurrentRegion(Object, Rectangle, DiagramSettings)}.
     */
    @SuppressWarnings("deprecation")
    @Deprecated
    public FigConcurrentRegion(GraphModel gm, Object node) {
        this();
        setOwner(node);
    }

    /**
     * The constructor.
     *
     * @param gm (not used)
     * @param node the UML model element represented by this Fig
     * @param col the line color
     * @param width the width
     * @param height the height
     * @deprecated for 0.27.4 by tfmorris.  Use 
     * {@link #FigConcurrentRegion(Object, Rectangle, DiagramSettings)}.
     */
    @Deprecated
    public FigConcurrentRegion(GraphModel gm, Object node,
                               Color col, int width, int height) {
        this(gm, node);
        setLineColor(col);
        Rectangle r = getBounds();
        setBounds(r.x, r.y, width, height);
    }

    /**
     * Construct a new concurrent region fig.
     * 
     * @param node owning UML element
     * @param bounds position and size
     * @param settings render settings
     */
    public FigConcurrentRegion(Object node, Rectangle bounds, DiagramSettings
            settings) {
        super(node, bounds, settings);
        initialize();
        if (bounds != null) {
            /* We have to use the specific methods written for this Fig: 
             * This fixes issue 5070. */
            setBounds(bounds.x - _x, bounds.y - _y, bounds.width, 
                    bounds.height - _h, true);
        }
        updateNameText();
    }

    /**
     * The moment we add this fig to a layer, 
     * especially during load,
     * it needs to be made aware that it 
     * is enclosed by a FigCompositeState.
     * This fixes issue 3736.
     * 
     * @param lay the layer
     * @see org.argouml.uml.diagram.ui.FigNodeModelElement#setLayer(org.tigris.gef.base.Layer)
     */
    @Override
    public void setLayer(Layer lay) {
        super.setLayer(lay);
        for (Fig f : lay.getContents()) {
            if (f instanceof FigCompositeState) {
                if (f.getOwner() 
                        == Model.getFacade().getContainer(getOwner())) {
                    setEnclosingFig(f);
                    break; // there can only be one
                }
            }
        }
    }
    
    /*
     * @see java.lang.Object#clone()
     */
    @Override
    public Object clone() {
        FigConcurrentRegion figClone = (FigConcurrentRegion) super.clone();
        Iterator it = figClone.getFigs().iterator();
        figClone.setBigPort((FigRect) it.next());
        figClone.cover = (FigRect) it.next();
        figClone.setNameFig((FigText) it.next());
        figClone.dividerline = (FigLine) it.next();
        figClone.setInternal((FigText) it.next());
        return figClone;
    }

    /*
     * @see org.tigris.gef.ui.PopupGenerator#getPopUpActions(java.awt.event.MouseEvent)
     */
    @Override
    public Vector getPopUpActions(MouseEvent me) {
        Vector popUpActions = super.getPopUpActions(me);
        popUpActions.remove(
                ProjectActions.getInstance().getRemoveFromDiagramAction());
        popUpActions.add(new JSeparator());
        // TODO: There's a cyclic dependency between FigConcurrentRegion and
        // the actions ActionAddConcurrentRegion
        popUpActions.addElement(
                new ActionAddConcurrentRegion());
        return popUpActions;
    }


    /*
     * @see org.tigris.gef.presentation.Fig#getMinimumSize()
     */
    @Override
    public Dimension getMinimumSize() {
        Dimension nameDim = getNameFig().getMinimumSize();
        Dimension internalDim = getInternal().getMinimumSize();
        int h = nameDim.height + 4 + internalDim.height;
        int w = nameDim.width + 2 * MARGIN;
        return new Dimension(w, h);
    }

    /*
     * @see org.tigris.gef.presentation.Fig#getUseTrapRect()
     */
    @Override
    public boolean getUseTrapRect() {
        return true;
    }

    /**
     * Override setBounds to keep shapes looking right. <p>
     *
     * When resized by this way, it only changes the height and the
     * adjacent region's height.
     *
     * {@inheritDoc}
     */
    @Override
    protected void setStandardBounds(int x, int y, int w, int h) {
        if (getNameFig() == null) {
            return;
        }
        Rectangle oldBounds = getBounds();
        Dimension nameDim = getNameFig().getMinimumSize();
        int adjacentindex = -1;
        List regionsList = null;
        int index = 0;
        if (getEnclosingFig() != null) {
            x = oldBounds.x;
            w = oldBounds.width;
            FigCompositeState f = ((FigCompositeState) getEnclosingFig());
            regionsList = f.getEnclosedFigs();
            index = regionsList.indexOf(this);

            /* if curHandle.index is 0 or 2,
             * the adjacent region is the previous region
             * but if it is 5 or 7, the adjacent region is the next region.
             * curHandle.index show which corner of the bound we are dragging.
             */
            if (((curHandle.index == 0) || (curHandle.index == 2))
                    && index > 0) {
                adjacentindex = index - 1;
            }
            if (((curHandle.index == 5) || (curHandle.index == 7))
                    && (index < (regionsList.size() - 1))) {
                adjacentindex = index + 1;
            }
            if (h <= getMinimumSize().height) {
                if (h <= oldBounds.height) {
                    h = oldBounds.height;
                    y = oldBounds.y;
                }
            }

            /* We aren't able to resize neither the top bound
             * from the first region nor
             * the bottom bound from the last region.
             */

            if (adjacentindex == -1) {
                x = oldBounds.x;
                y = oldBounds.y;
                h = oldBounds.height;

                /*The group must be resized if a text field exceed the bounds*/
                if (w > f.getBounds().width) {
                    Rectangle fR = f.getBounds();
                    f.setBounds(fR.x, fR.y, w + 6, fR.height);
                }
            } else {
                int hIncrement = oldBounds.height - h;
                FigConcurrentRegion adjacentFig =
                    ((FigConcurrentRegion)
                        regionsList.get(adjacentindex));
                if ((adjacentFig.getBounds().height + hIncrement)
                        <= adjacentFig.getMinimumSize().height) {
                    y = oldBounds.y;
                    h = oldBounds.height;
                } else {
                    if ((curHandle.index == 0) || (curHandle.index == 2)) {
                        ((FigConcurrentRegion) regionsList.
                            get(adjacentindex)).setBounds(0, hIncrement);
                    }
                    if ((curHandle.index == 5) || (curHandle.index == 7)) {
                        ((FigConcurrentRegion) regionsList.
                            get(adjacentindex)).setBounds(-hIncrement,
                                    hIncrement);
                    }
                }
            }
        }

        dividerline.setShape(x, y, x + w, y);
        getNameFig().setBounds(x + MARGIN,
                y + SPACE_TOP,
                w - 2 * MARGIN,
                nameDim.height);
        getInternal().setBounds(
                x + MARGIN,
                y + nameDim.height + SPACE_TOP + SPACE_MIDDLE,
                w - 2 * MARGIN,
                h - nameDim.height - SPACE_TOP - SPACE_MIDDLE - SPACE_BOTTOM);
        getBigPort().setBounds(x, y, w, h);
        cover.setBounds(x, y, w, h);

        calcBounds(); //_x = x; _y = y; _w = w; _h = h;
        updateEdges();
        firePropChange("bounds", oldBounds, getBounds());
    }

    /**
     * To resize with X and Y increments, absolute width and keeping the height.
     * @param xInc the x increment
     * @param yInc the y increment
     * @param w the width
     * @param concurrency is concurrent?
     */
    public void setBounds(int xInc, int yInc, int w, boolean concurrency) {
        if (getNameFig() == null) {
            return;
        }
        Rectangle oldBounds = getBounds();
        Dimension nameDim = getNameFig().getMinimumSize();
        int x = oldBounds.x + xInc;
        int y = oldBounds.y + yInc;
        int h = oldBounds.height;

        dividerline.setShape(x, y, x + w , y);
        getNameFig().setBounds(x + 2, y + 2, w - 4, nameDim.height);
        getInternal().setBounds(x + 2, y + nameDim.height + 4,
                w - 4, h - nameDim.height - 8);
        getBigPort().setBounds(x, y, w, h);
        cover.setBounds(x, y, w, h);

        calcBounds(); //_x = x; _y = y; _w = w; _h = h;
        updateEdges();
        firePropChange("bounds", oldBounds, getBounds());
    }

    /**
     * To resize with X, Y and height increments and absolute width.
     * The boolean parameter is added in order to override the method.
     *
     * @param xInc the x increment
     * @param yInc the y increment
     * @param w the width
     * @param concurrency is concurrent?
     * @param hInc the height increment
     */
    public void setBounds(int xInc, int yInc, int w, int hInc,
            boolean concurrency) {
        if (getNameFig() == null) {
            return;
        }
        Rectangle oldBounds = getBounds();
        Dimension nameDim = getNameFig().getMinimumSize();
        int x = oldBounds.x + xInc;
        int y = oldBounds.y + yInc;
        int h = oldBounds.height + hInc;

        dividerline.setShape(x, y,
                x + w , y);
        getNameFig().setBounds(x + 2, y + 2, w - 4, nameDim.height);
        getInternal().setBounds(x + 2, y + nameDim.height + 4,
                w - 4, h - nameDim.height - 8);
        getBigPort().setBounds(x, y, w, h);
        cover.setBounds(x, y, w, h);

        calcBounds(); //_x = x; _y = y; _w = w; _h = h;
        updateEdges();
        firePropChange("bounds", oldBounds, getBounds());
    }

    /**
     * To resize with Y increments, height increment and
     * keeping the X and width.
     *
     * @param yInc the y increment
     * @param hInc the height increment
     */
    public void setBounds(int yInc, int hInc) {
        if (getNameFig() == null) {
            return;
        }
        Rectangle oldBounds = getBounds();
        Dimension nameDim = getNameFig().getMinimumSize();
        int x = oldBounds.x;
        int y = oldBounds.y + yInc;
        int w = oldBounds.width;
        int h = oldBounds.height + hInc;

        dividerline.setShape(x, y, x + w , y);
        getNameFig().setBounds(x + 2, y + 2, w - 4, nameDim.height);
        getInternal().setBounds(x + 2, y + nameDim.height + 4,
                w - 4, h - nameDim.height - 8);
        getBigPort().setBounds(x, y, w, h);
        cover.setBounds(x, y, w, h);

        calcBounds(); //_x = x; _y = y; _w = w; _h = h;
        updateEdges();
        firePropChange("bounds", oldBounds, getBounds());
    }

    ////////////////////////////////////////////////////////////////
    // fig accessors

    /*
     * This function only sets the color of the divider line 
     * (since that is the only visible part), and can be used to make 
     * the divider line invisible for the top region in a composite state.
     * 
     * @see org.tigris.gef.presentation.Fig#setLineColor(java.awt.Color)
     */
    @Override
    public void setLineColor(Color col) {
        cover.setLineColor(INVISIBLE_LINE_COLOR);
        dividerline.setLineColor(col);
    }

    /*
     * @see org.tigris.gef.presentation.Fig#getLineColor()
     */
    @Override
    public Color getLineColor() {
        return dividerline.getLineColor();
    }

    /*
     * @see org.tigris.gef.presentation.Fig#setFillColor(java.awt.Color)
     */
    @Override
    public void setFillColor(Color col) {
        cover.setFillColor(col);
    }

    /*
     * @see org.tigris.gef.presentation.Fig#getFillColor()
     */
    @Override
    public Color getFillColor() {
        return cover.getFillColor();
    }

    /*
     * @see org.tigris.gef.presentation.Fig#setFilled(boolean)
     */
    @Override
    public void setFilled(boolean f) {
        cover.setFilled(f);
        getBigPort().setFilled(f);
    }


    @Override
    public boolean isFilled() {
        return cover.isFilled();
    }

    /*
     * @see org.tigris.gef.presentation.Fig#setLineWidth(int)
     */
    @Override
    public void setLineWidth(int w) {
        dividerline.setLineWidth(w);
    }

    /*
     * @see org.tigris.gef.presentation.Fig#getLineWidth()
     */
    @Override
    public int getLineWidth() {
        return dividerline.getLineWidth();
    }

    ////////////////////////////////////////////////////////////////
    // event processing

    protected void modelChanged(PropertyChangeEvent mee) {
        if ("container".equals(mee.getPropertyName())
                || "isConcurrent".equals(mee.getPropertyName())
                || "subvertex".equals(mee.getPropertyName())) {
            //do nothing
            // this only happens at creation time - I hope
        } else {
            super.modelChanged(mee);
        }
    }
    
    /*
     * @see org.tigris.gef.presentation.Fig#makeSelection()
     */
    @Override
    public Selection makeSelection() {
        Selection sel = new SelectionState(this);
        ((SelectionState) sel).setIncomingButtonEnabled(false);
        ((SelectionState) sel).setOutgoingButtonEnabled(false);
        return sel;
    }

    /*
     * @see org.argouml.uml.diagram.state.ui.FigState#getInitialHeight()
     */
    public int getInitialHeight() {
        return 130;
    }

    /*
     * @see org.argouml.uml.diagram.state.ui.FigState#getInitialWidth()
     */
    protected int getInitialWidth() {
        return 30;
    }

    /*
     * @see org.argouml.uml.diagram.state.ui.FigState#getInitialX()
     */
    protected int getInitialX() {
        return 0;
    }

    /*
     * @see org.argouml.uml.diagram.state.ui.FigState#getInitialY()
     */
    protected int getInitialY() {
        return 0;
    }

    /**
     * @return the initial color
     */
    protected Color getInitialColor() {
        return LINE_COLOR;
    }

    /////////////////////////////////////////////////////////////////////////
    // event handlers - MouseListener and MouseMotionListener implementation

    @Override
    protected void updateLayout(UmlChangeEvent event) {
        if (!"container".equals(event.getPropertyName()) &&
                !"isConcurrent".equals(event.getPropertyName())) {
            super.updateLayout(event);
        }
        final String eName = event.getPropertyName();
        /*
         * A Concurrent region cannot have incoming or outgoing transitions so
         * incoming or outgoing transitions are redirected to its concurrent
         * composite state container.
         */
        // TODO: This comparison is very suspect, it should use equals
        // method. The code within the block is in fact never executed.
        // I hesitate to change this now as it will trigger code has never been
        // used before and am not aware of any problems that it usage may
        // introduce.
        // I do think that we need to be able to find a different way to
        // implement the intent here which seems to be to correct edge drawings
        // that should actually not be allowed - Bob
        if (eName == "incoming" || eName == "outgoing") {
            final Object owner = getOwner();
            final Collection transactions = (Collection) event.getNewValue();
            if (!transactions.isEmpty()) {
                final Object transition = transactions.iterator().next();
                if (eName == "incoming") {
                    if (Model.getFacade().isATransition(transition)) {
                        Model.getCommonBehaviorHelper().setTarget(transition,
                                Model.getFacade().getContainer(owner));
                    }
                } else {
                    if (Model.getFacade().isATransition(transition)) {
                        Model.getStateMachinesHelper().setSource(transition,
                                Model.getFacade().getContainer(owner));
                    }
                }
            }
        }
    }

    /*
     * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
     */
    @Override
    public void mousePressed(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        Globals.curEditor().getSelectionManager().hitHandle(
                new Rectangle(x - 4, y - 4, 8, 8), curHandle);
    }

    /*
     * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseReleased(MouseEvent e) {
        curHandle.index = -1;
    }

    /*
     * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
     */
    public void mouseDragged(MouseEvent e) {
        if (curHandle.index == -1) {
            Globals.curEditor().getSelectionManager().select(getEnclosingFig());
        }
    }

    /*
     * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
     */
    public void mouseMoved(MouseEvent e) {
        // ignored
    }

    /**
     * The UID.
     */
    private static final long serialVersionUID = -7228935179004210975L;
}
