Ptidej-v5.2-master/POM Tests/data/ArgoUML_0.28/src/org/argouml/uml/diagram/ui/FigNodeAssociation.java
// $Id: FigNodeAssociation.java 16704 2009-01-25 20:47:39Z bobtarling $
// Copyright (c) 2005-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.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.argouml.model.Model;
import org.argouml.model.RemoveAssociationEvent;
import org.argouml.model.UmlChangeEvent;
import org.argouml.uml.diagram.DiagramSettings;
import org.tigris.gef.base.LayerPerspective;
import org.tigris.gef.graph.GraphEdgeRenderer;
import org.tigris.gef.graph.GraphModel;
import org.tigris.gef.graph.MutableGraphModel;
import org.tigris.gef.presentation.FigDiamond;
import org.tigris.gef.presentation.FigEdge;
import org.tigris.gef.presentation.FigNode;
import org.tigris.gef.presentation.FigText;

/**
 * Class to display graphics for N-ary association (association node),
 * i.e. the diamond. <p>
 * 
 * TODO: Improve the location of the stereotypes!
 *
 * @author pepargouml@yahoo.es
 */
public class FigNodeAssociation extends FigNodeModelElement {
    
    private static final int X = 0;
    private static final int Y = 0;

    private FigDiamond head;

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

    private void initFigs() {
        setEditable(false);
        setBigPort(new FigDiamond(0, 0, 70, 70, DEBUG_COLOR, DEBUG_COLOR));
        head = new FigDiamond(0, 0, 70, 70, LINE_COLOR, FILL_COLOR);

        getNameFig().setFilled(false);
        getNameFig().setLineWidth(0);
//      The following does not seem to work - centered the Fig instead.
//        getNameFig().setJustificationByName("center");

        getStereotypeFig().setBounds(X + 10, Y + NAME_FIG_HEIGHT + 1, 
                0, NAME_FIG_HEIGHT);
        getStereotypeFig().setFilled(false);
        getStereotypeFig().setLineWidth(0);

        // add Figs to the FigNode in back-to-front order
        addFig(getBigPort());
        addFig(head);
        if (!Model.getFacade().isAAssociationClass(getOwner())) {
            addFig(getNameFig());
            addFig(getStereotypeFig());
        }

        setBlinkPorts(false); //make port invisible unless mouse enters
        Rectangle r = getBounds();
        setBounds(r);
        setResizable(true);
    }

    /**
     * The constructor.
     * 
     * @param gm the graphmodel
     * @param node the owner (UML association)
     * @deprecated by for 0.27.4 by tfmorris. Use
     *          {@link #FigNodeAssociation(Object, Rectangle, DiagramSettings)}
     */
    @SuppressWarnings("deprecation")
    @Deprecated
    public FigNodeAssociation(@SuppressWarnings("unused") GraphModel gm, 
            Object node) {
        this();
        setOwner(node);
    }
    
    
    /**
     * Construct a new FigNodeAssociation.
     * 
     * @param owner owning UML element
     * @param bounds position and size
     * @param settings render settings
     */
    public FigNodeAssociation(Object owner, Rectangle bounds,
            DiagramSettings settings) {
        super(owner, bounds, settings);
        initFigs();
    }

    /*
     * @see java.lang.Object#clone()
     */
    @Override
    public Object clone() {
        FigNodeAssociation figClone = (FigNodeAssociation) super.clone();
        Iterator it = figClone.getFigs().iterator();
        figClone.setBigPort((FigDiamond) it.next());
        figClone.head = (FigDiamond) it.next();
        figClone.setNameFig((FigText) it.next());
        return figClone;
    }


    /**
     * Called when a model event is received from model subsystem.
     * handles when a n-ary association becomes a binary association.
     *
     * @param mee the event
     */
    @Override
    protected void updateLayout(UmlChangeEvent mee) {
        super.updateLayout(mee);
        if (mee.getSource() == getOwner()
                && mee instanceof RemoveAssociationEvent
                && "connection".equals(mee.getPropertyName())
                && Model.getFacade().getConnections(getOwner()).size() == 2) {
            reduceToBinary();
        }
    }

    /**
     * Called when deletion of an association end reduces the number of ends
     * of an association down to only two. This Fig which represent the diamond
     * node of a n-ary association needs to be replaced by a FigAssociation
     * representing the binary relationship.
     */
    private void reduceToBinary() {
        final Object association = getOwner();
        assert (Model.getFacade().getConnections(association).size() == 2);
        
        // Detach any non-associationend edges (such as comment edges) already
        // attached before this association node is removed.
        // They'll later be re-attached to the new FigAssociation
        final Collection<FigEdge> existingEdges = getEdges();
        for (Iterator<FigEdge> it = existingEdges.iterator(); it.hasNext(); ) {
            FigEdge edge = it.next();
            if (edge instanceof FigAssociationEnd) {
                it.remove();
            } else {
                removeFigEdge(edge);
            }
        }
        
        // Now we can remove ourself (which will also remove the
        // attached association ends edges)
        final LayerPerspective lay = (LayerPerspective) getLayer();
        final MutableGraphModel gm = (MutableGraphModel) lay.getGraphModel();
        gm.removeNode(association);
        removeFromDiagram();
        
        // Create the new FigAssociation edge to replace the node
        final GraphEdgeRenderer renderer =
            lay.getGraphEdgeRenderer();
        final FigAssociation figEdge = (FigAssociation) renderer.getFigEdgeFor(
                gm, lay, association, null);
        lay.add(figEdge);
        gm.addEdge(association);
        
        // Add the non-associationend edges (such as comment edges) that were
        // originally attached to this and attach them to the new
        // FigAssociation and make sure they are positioned correctly.
        for (FigEdge edge : existingEdges) {
            figEdge.makeEdgePort();
            if (edge.getDestFigNode() == this) {
                edge.setDestFigNode(figEdge.getEdgePort());
                edge.setDestPortFig(figEdge.getEdgePort());
            }
            if (edge.getSourceFigNode() == this) {
                edge.setSourceFigNode(figEdge.getEdgePort());
                edge.setSourcePortFig(figEdge.getEdgePort());
            }
        }
        figEdge.computeRoute();
    }
    
    /*
     * Makes sure that the edges stick to the outline of the fig.
     * @see org.tigris.gef.presentation.Fig#getGravityPoints()
     */
    @Override
    public List getGravityPoints() {
        return getBigPort().getGravityPoints();
    }

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

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

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

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

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

    @Override
    public boolean isFilled() {
        return true;
    }

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

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

    @Override
    protected void setStandardBounds(int x, int y, int w, int h) {
        Rectangle oldBounds = getBounds();

        Rectangle nm = getNameFig().getBounds();
        /* Center the NameFig, since center justification 
         * does not seem to work. */
        getNameFig().setBounds(x + (w - nm.width) / 2, 
                y + h / 2 - nm.height / 2, 
                nm.width, nm.height);
        // TODO: Replace magic numbers with constants
        if (getStereotypeFig().isVisible()) {
            /* TODO: Test this. */
            getStereotypeFig().setBounds(x, y + h / 2 - 20, w, 15);
            int stereotypeHeight = getStereotypeFig().getMinimumSize().height;
            getStereotypeFig().setBounds(
                    x,
                    y,
                    w,
                    stereotypeHeight);
        }
        
        head.setBounds(x, y, w, h);
        getBigPort().setBounds(x, y, w, h);

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

    @Override
    public Dimension getMinimumSize() {
        Dimension aSize = getNameFig().getMinimumSize();
        if (getStereotypeFig().isVisible()) {
            Dimension stereoMin = getStereotypeFig().getMinimumSize();
            aSize.width = Math.max(aSize.width, stereoMin.width);
            aSize.height += stereoMin.height;
        }
        aSize.width = Math.max(70, aSize.width);
        int size = Math.max(aSize.width, aSize.height);
        aSize.width = size;
        aSize.height = size;
        
        return aSize;
    }
    
    
    /**
     * Remove entire composite Fig from Diagram. Discover the attached
     * FigEdgeAssociationClass and the FigClassAssociationClass attached to
     * that. Remove them from the diagram before removing this.
     */
    @Override
    protected void removeFromDiagramImpl() {
        FigEdgeAssociationClass figEdgeLink = null;
        final List edges = getFigEdges();

        if (edges != null) {
            for (Iterator it = edges.iterator(); it.hasNext()
                    && figEdgeLink == null;) {
                Object o = it.next();
                if (o instanceof FigEdgeAssociationClass) {
                    figEdgeLink = (FigEdgeAssociationClass) o;
                }
            }
        }

        if (figEdgeLink != null) {
            FigNode figClassBox = figEdgeLink.getDestFigNode();
            if (!(figClassBox instanceof FigClassAssociationClass)) {
                figClassBox = figEdgeLink.getSourceFigNode();
            }
            figEdgeLink.removeFromDiagramImpl();
            ((FigClassAssociationClass) figClassBox).removeFromDiagramImpl();
        }

        super.removeFromDiagramImpl();
    }

}

