Ptidej-v5.2-master/POM Tests/data/ArgoUML_0.28/src/org/argouml/uml/diagram/ui/UMLDiagram.java
// $Id: UMLDiagram.java 16702 2009-01-25 20:23:28Z bobtarling $
// Copyright (c) 1996-2008 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.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.beans.PropertyVetoException;

import javax.swing.Action;
import javax.swing.ButtonModel;
import javax.swing.JToolBar;

import org.apache.log4j.Logger;
import org.argouml.gefext.ArgoModeCreateFigCircle;
import org.argouml.gefext.ArgoModeCreateFigInk;
import org.argouml.gefext.ArgoModeCreateFigLine;
import org.argouml.gefext.ArgoModeCreateFigPoly;
import org.argouml.gefext.ArgoModeCreateFigRRect;
import org.argouml.gefext.ArgoModeCreateFigRect;
import org.argouml.gefext.ArgoModeCreateFigSpline;
import org.argouml.i18n.Translator;
import org.argouml.kernel.Project;
import org.argouml.model.Model;
import org.argouml.ui.CmdCreateNode;
import org.argouml.uml.UUIDHelper;
import org.argouml.uml.diagram.ArgoDiagramImpl;
import org.argouml.uml.diagram.DiagramSettings;
import org.argouml.uml.diagram.Relocatable;
import org.argouml.uml.diagram.UMLMutableGraphSupport;
import org.argouml.util.ToolBarUtility;
import org.tigris.gef.base.LayerPerspective;
import org.tigris.gef.base.ModeBroom;
import org.tigris.gef.base.ModeCreatePolyEdge;
import org.tigris.gef.base.ModePlace;
import org.tigris.gef.base.ModeSelect;
import org.tigris.gef.graph.GraphFactory;
import org.tigris.gef.graph.GraphModel;
import org.tigris.gef.presentation.FigNode;
import org.tigris.toolbar.ToolBarFactory;
import org.tigris.toolbar.ToolBarManager;
import org.tigris.toolbar.toolbutton.ToolButton;

/**
 * This class provides support for writing a UML diagram for argo using
 * the GEF framework. <p>
 *
 * It adds common buttons, and some help
 * with creating a valid diagram name. <p>
 *
 * There are various methods for returning 'structures' of Actions
 * which are used to build toolbars and dropdown buttons within toolbars.
 * These structures are arrays of Objects.
 * An array element is actually either an Action, null or another array.
 * When building a toolbar an Action is used to create a button and null
 * is used to create a spacer in the toolbar.
 * An element containing an array results in a dropdown toolbar button
 * being created which contains all the items in that array. <p>
 *
 * The "owner" of the UMLDiagram needs to be set to the
 * UML modelelement of which the diagram depends.
 * For a class diagram is that its namespace.
 * For a collaboration diagram is that the Collaboration UML object.
 * For a sequence diagram is that the collaboration.
 * For a deployment diagram is that the namespace.
 * For a statechart diagram is that the statemachine.
 * For a activitydiagram is that the activitygraph.
 * Override the getOwner method to return the owner. <p>
 *
 * The "owner" is shown in the diagram's properties
 * panel as the "home model". <p>
 */
public abstract class UMLDiagram
    extends ArgoDiagramImpl
    implements Relocatable {

    private static final Logger LOG = Logger.getLogger(UMLDiagram.class);

    /**
     * Tool to add a comment node.
     */
    private static Action actionComment =
        new RadioAction(new ActionAddNote());

    /**
     * Tool to create an relationship between a comment node and some other node
     * using a polyedge.<p>
     */
    private static Action actionCommentLink =
        new RadioAction(new ActionSetAddCommentLinkMode());


    private static Action actionSelect =
        new ActionSetMode(ModeSelect.class, "button.select");

    private static Action actionBroom =
        new ActionSetMode(ModeBroom.class, "button.broom");

    private static Action actionRectangle =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigRect.class, 
                "Rectangle", "misc.primitive.rectangle"));

    private static Action actionRRectangle =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigRRect.class, 
                "RRect", "misc.primitive.rounded-rectangle"));

    private static Action actionCircle =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigCircle.class, 
                "Circle", "misc.primitive.circle"));

    private static Action actionLine =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigLine.class, 
                "Line", "misc.primitive.line"));

    private static Action actionText =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigText.class, 
                "Text", "misc.primitive.text"));

    private static Action actionPoly =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigPoly.class, 
                "Polygon", "misc.primitive.polygon"));

    private static Action actionSpline =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigSpline.class, 
                "Spline", "misc.primitive.spline"));

    private static Action actionInk =
        new RadioAction(new ActionSetMode(ArgoModeCreateFigInk.class, 
                "Ink", "misc.primitive.ink"));

    private JToolBar toolBar;

    private Action selectedAction;
    
    /**
     * Default constructor will become protected. All subclasses should have
     * their constructors invoke the 3-arg version of the constructor.
     * 
     * @deprecated for 0.27.2 by tfmorris. Use
     *             {@link #UMLDiagram(String, Object, GraphModel)} or another
     *             explicit constructor.
     */
    @SuppressWarnings("deprecation")
    @Deprecated
    public UMLDiagram() {
        super();
    }

    /**
     * @param ns the UML namespace of this diagram
     * @deprecated for 0.27.2 by tfmorris. Use
     *             {@link #UMLDiagram(String, Object, GraphModel)}.
     */
    @Deprecated
    public UMLDiagram(Object ns) {
        this();
        if (!Model.getFacade().isANamespace(ns)) {
            throw new IllegalArgumentException();
        }
        // TODO: Should we require a GraphModel in the constructor since 
        // our implementations of setNamespace are going to try and set
        // the namespace on the graphmodel as well?
        setNamespace(ns);
    }
   
    /**
     * @param name the name of the diagram
     * @param ns the UML namespace of this diagram
     * @deprecated for 0.27.2 by tfmorris. Use
     *             {@link #UMLDiagram(String, Object, GraphModel)}.
     */
    @Deprecated
    public UMLDiagram(String name, Object ns) {
        this(ns);
        try {
            setName(name);
        } catch (PropertyVetoException pve) {
            LOG.fatal("Name not allowed in construction of diagram");
        }
    }

   
    /**
     * Construct a new ArgoUML diagram.  This is the fully specified form
     * of the constructor typically used by subclasses.
     * 
     * @param name the name of the new diagram
     * @param graphModel graph model to associate with diagram
     * @param ns the namespace which will "own" the diagram
     */
    public UMLDiagram(String name, Object ns, GraphModel graphModel) {
        super(name, graphModel, new LayerPerspective(name, graphModel));
        setNamespace(ns);
    }

    /**
     * Construct an unnamed diagram using the given GraphModel.
     * 
     * @param graphModel graph model to associate with diagram
     */
    public UMLDiagram(GraphModel graphModel) {    
        super("", graphModel, new LayerPerspective("", graphModel));
    }
    
    /**
     * Method called by PGML parser during diagram load to initialize a diagram
     * after it's been constructed. Order of method invocations currently is:
     * <ul>
     * <li>0-arg constructor
     * <li>setDiagramSettings
     * <li>initialize(Object) // UML element representing owner/home model
     * <li>setName(String)
     * <li>setScale(double)
     * <li>setShowSingleMultiplicity(boolean)
     * <ul>
     * 
     * @param owner UML model element representing owner/namespace/home model
     * @see org.tigris.gef.base.Diagram#initialize(java.lang.Object)
     */
    @Override
    public void initialize(Object owner) {
        super.initialize(owner);
        /* The following is the default implementation
         * for diagrams of which the owner is a namespace.
         */
        if (Model.getFacade().isANamespace(owner)) {
            setNamespace(owner);
        }
    }

    /*
     * @see org.tigris.gef.base.Diagram#getClassAndModelID()
     */
    public String getClassAndModelID() {
        String s = super.getClassAndModelID();
        if (getOwner() == null) {
            return s;
        }
        String id = UUIDHelper.getUUID(getOwner());
        return s + "|" + id;
    }

    /**
     * Get the toolbar for the diagram.
     * @return the diagram toolbar
     */
    public JToolBar getJToolBar() {
        if (toolBar == null) {
            initToolBar();
            toolBar.setName("misc.toolbar.diagram");
        }
        return toolBar;
    }

    /**
     * Create the toolbar based on actions for the specific diagram
     * subclass.
     * @see org.tigris.gef.base.Diagram#initToolBar()
     */
    public void initToolBar() {
        ToolBarFactory factory = new ToolBarFactory(getActions());
        factory.setRollover(true);
        factory.setFloatable(false);
        
        toolBar = factory.createToolBar();
        toolBar.putClientProperty("ToolBar.toolTipSelectTool", 
                Translator.localize("action.select"));
    }

    /**
     * Return actions available for building toolbar or similar.
     * @return an array of available actions.
     */
    public Object[] getActions() {
        Object[] manipulateActions = getManipulateActions();
        Object[] umlActions = getUmlActions();
        Object[] commentActions = getCommentActions();
        Object[] shapeActions = getShapeActions();

        Object[] actions =
            new Object[manipulateActions.length
                + umlActions.length
                + commentActions.length
                + shapeActions.length];

        int posn = 0;
        System.arraycopy(
            manipulateActions,           // source
            0,                           // source position
            actions,                     // destination
            posn,                        // destination position
            manipulateActions.length);   // number of objects to be copied
        posn += manipulateActions.length;

        System.arraycopy(umlActions, 0, actions, posn, umlActions.length);
        posn += umlActions.length;

        System.arraycopy(commentActions, 0, actions, posn,
                commentActions.length);
        posn += commentActions.length;

        System.arraycopy(shapeActions, 0, actions, posn, shapeActions.length);

        return actions;
    }

    /**
     * Implement in the ancestor to get a 'structure' of actions for
     * appending the UML creation tools to the toolbar.
     * @return the actions structure
     */
    protected abstract Object[] getUmlActions();

    /**
     * Get a 'structure' of actions for appending the manipulation
     * mode tools to the toolbar.
     * @return the actions structure
     */
    private Object[] getManipulateActions() {
        Object[] actions =
        {
	    new RadioAction(actionSelect),
	    new RadioAction(actionBroom),
	    null,
	};
        return actions;
    }

    /**
     * Get a 'structure' of actions for appending the comment
     * tools to the toolbar.
     * @return the actions structure
     */
    private Object[] getCommentActions() {
        Object[] actions =
        {
            null,
            actionComment,
            actionCommentLink,
        };
        return actions;
    }

    /**
     * Get a 'structure' of actions for appending primitive drawing
     * tools to the toolbar.
     * @return the actions structure
     */
    private Object[] getShapeActions() {
        Object[] actions = {
	    null,
            getShapePopupActions(),
	};
        return actions;
    }

    /**
     * Get a 'structure' of actions for showing in the shape
     * primitives popup tool button.
     * @return the actions structure
     */
    private Object[] getShapePopupActions() {
        Object[][] actions = {
	    {actionRectangle, actionRRectangle },
	    {actionCircle,    actionLine },
            {actionText,      actionPoly },
            {actionSpline,    actionInk },
        };

        ToolBarUtility.manageDefault(actions, "diagram.shape");
        return actions;
    }

    /**
     * Set the given action as the selected action (ie pressed down on the
     * diagram toolbar). All other actions become unselected.
     *
     * @param theAction the action to become selected
     */
    public void setSelectedAction(Action theAction) {
        selectedAction = theAction;
        int toolCount = toolBar.getComponentCount();
        for (int i = 0; i < toolCount; ++i) {
            Component c = toolBar.getComponent(i);
            if (c instanceof ToolButton) {
                ToolButton tb = (ToolButton) c;
                Action action = tb.getRealAction();
                if (action instanceof RadioAction) {
                    action = ((RadioAction) action).getAction();
                }
                Action otherAction = theAction;
                if (theAction instanceof RadioAction) {
                    otherAction = ((RadioAction) theAction).getAction();
                }
                if (action != null && !action.equals(otherAction)) {
                    tb.setSelected(false);
                    ButtonModel bm = tb.getModel();
                    bm.setRollover(false);
                    bm.setSelected(false);
                    bm.setArmed(false);
                    bm.setPressed(false);
                    if (!ToolBarManager.alwaysUseStandardRollover()) {
                        tb.setBorderPainted(false);
                    }
                } else {
                    tb.setSelected(true);
                    ButtonModel bm = tb.getModel();
                    bm.setRollover(true);
                    if (!ToolBarManager.alwaysUseStandardRollover()) {
                        tb.setBorderPainted(true);
                    }
                }
            }
        }
    }

    /**
     * Get the selected action.
     * 
     * @return the selected action
     */
    public Action getSelectedAction() {
        return selectedAction;
    }

    /**
     * Unselect all the toolbar buttons.
     */
    public void deselectAllTools() {
        setSelectedAction(actionSelect);
        actionSelect.actionPerformed(null);
    }

    /**
     * Factory method to build an Action for creating a node in the
     * diagram.
     *
     * @param modelElement identifies the model element type to make
     * @param descr the description to give this action.
     * @return The action to create a new node.
     */
    protected Action makeCreateNodeAction(Object modelElement, String descr) {
        return new RadioAction(new CmdCreateNode(modelElement, descr));
    }

    /**
     * Factory method to build an Action for creating an edge in the
     * diagram.
     *
     * @param modelElement identifies the model element type to make
     * @param descr the description to give this action.
     * @return The action to create a new node.
     */
    protected Action makeCreateEdgeAction(Object modelElement, String descr) {
        return new RadioAction(
            new ActionSetMode(ModeCreatePolyEdge.class, "edgeClass",
                    modelElement, descr));
    }

    /**
     * Factory method to build an Action for creating an edge in the
     * diagram.
     *
     * @param modeClass the mode class to instantiate drawing
     * @param metaType identifies the model element type to make
     * @param descr the description to give this action.
     * @return The action to create a new node.
     */
    protected Action makeCreateDependencyAction(
	    Class modeClass, 
	    Object metaType, 
	    String descr) {
        return new RadioAction(
            new ActionSetMode(modeClass, "edgeClass", metaType, descr));
    }

    /**
     * Factory method to build an Action for creating an edge in the
     * diagram.
     * @return The action to create a new generalization mode.
     */
    protected Action makeCreateGeneralizationAction() {
        return new RadioAction(
            new ActionSetMode(
        	    ModeCreateGeneralization.class, 
        	    "edgeClass", 
        	    Model.getMetaTypes().getGeneralization(), 
        	    "button.new-generalization"));
    }

    /**
     * Factory method to build an Action for creating an association edge in
     * the diagram.
     *
     * @param aggregationKind the type of aggregation for this association
     * @param unidirectional true if this is a one way association.
     * @param descr the description to give this action.
     * @return The action to create a new association.
     */
    protected Action makeCreateAssociationAction(
            Object aggregationKind,
            boolean unidirectional,
            String descr) {

        return new RadioAction(
            new ActionSetAddAssociationMode(aggregationKind,
                unidirectional, descr));
    }

    /**
     * Factory method to build an Action for creating an association end edge
     * in the diagram.
     *
     * @param descr the description to give this action.
     * @return The action to create a new association.
     */
    protected Action makeCreateAssociationEndAction(String descr) {

        return new RadioAction(new ActionSetAddAssociationEndMode(descr));
    }

    /**
     * Factory method to build an Action for creating an edge in the
     * diagram.
     *
     * @param descr the description to give this action.
     * @return The action to create a new node.
     */
    protected Action makeCreateAssociationClassAction(String descr) {
        return new RadioAction(new ActionSetAddAssociationClassMode(descr));
    }

    /**
     * Reset the diagram serial counter to the initial value. This should e.g.
     * be done when the menuitem File->New is activated.
     * 
     * @deprecated for 0.27.3 by tfmorris. This is a noop. Diagram name
     *             duplication is checked for and managed at the project level.
     */
    @Deprecated
    public void resetDiagramSerial() {
    }

    /**
     * @return Returns the diagramSerial.
     * @deprecated for 0.27.3 by tfmorris. This is always returns 1. Diagram
     *             naming is managed at the project level.
     */
    @Deprecated
    protected int getNextDiagramSerial() {
        return 1;
    }

    /**
     * @return a string that can be used as a label for this kind of diagram
     */
    public abstract String getLabelName();

    /*
     * @see org.argouml.ui.explorer.Relocatable#isRelocationAllowed(java.lang.Object)
     */
    public abstract boolean isRelocationAllowed(Object base);

    /*
     * @see org.argouml.ui.explorer.Relocatable#relocate(java.lang.Object)
     */
    public abstract boolean relocate(Object base);

    @Override
    public final void setProject(Project p) {
	super.setProject(p);
	UMLMutableGraphSupport gm = (UMLMutableGraphSupport) getGraphModel();
	gm.setProject(p);
    }
    
    /**
     * Create a new diagram name.
     * @return String
     */
    protected String getNewDiagramName() {
        // TODO: Add "unnamed" or "new" or something? (Localized, of course)
        return /*"unnamed " + */ getLabelName();
    }

    /**
     * Method to test it the diagram can accept a certain object.
     * This should be overridden by any diagram that wants to accept a certain
     * type of object. All other diagrams should not bother since the default
     * answer is false, ie. don't accept the object.
     * @param objectToAccept The object which acceptability will be checked.
     * @return True if it can accept it, false otherwise.
     */
    public boolean doesAccept(
            @SuppressWarnings("unused") Object objectToAccept) {
        return false;
    }

    /**
     * Handles elements dropped over.
     * @param droppedObject The dropped object.
     * @param location The location in the diagram where the object is dropped.
     * @return The object that has been added to the diagram.
     */
    @SuppressWarnings("unused")
    public FigNode drop(Object droppedObject, Point location) {
        return null;
    }
    
    /**
     * Gets the instructions to be displayed on the status bar.
     * @param droppedObject The object for which instructions will be given.
     * @return The instructions.
     */
    public String getInstructions(Object droppedObject) {
        return Translator.localize("misc.message.click-on-diagram-to-add", 
                new Object[] {Model.getFacade().toString(droppedObject), });
    }
    
    /**
     * Creates a diagram specific @see org.tigris.gef.base.ModePlace that 
     * allows the diagram to place an accepted type of object 
     * [ @see #doesAccept(Object) ] as it should. This is required 1. since a 
     * diagram may receive an object that can't be placed as is, but needs some
     * transformation and 2. diagrams in modules should be independent from the
     * main app, and should use their own implementation of ModePlace if it's
     * required.
     * @param gf TODO
     * @param instructions a help string for the user
     * @return The created ModePlace.
     */
    public ModePlace getModePlace(GraphFactory gf, String instructions) {
        return new ModePlace(gf, instructions);
    }
    
    /**
     * Create a nary association diamond shaped FigNode on this diagram.
     *  
     * @param modelElement the model element this FigNode is to represent
     * @param bounds the position and size for the diamond node.
     * @param settings the diagram setting for presentation.
     * @return The FigNode of the diamond representing the model element
     */
    protected FigNode createNaryAssociationNode(
            final Object modelElement,
            final Rectangle bounds,
            final DiagramSettings settings) {
        
        final FigNodeAssociation diamondFig =
            new FigNodeAssociation(modelElement, bounds, settings);
        if (Model.getFacade().isAAssociationClass(modelElement)
                && bounds != null) {
            final FigClassAssociationClass classBoxFig =
                new FigClassAssociationClass(
                        modelElement, bounds, settings);
            final FigEdgeAssociationClass dashEdgeFig =
                new FigEdgeAssociationClass(
                        classBoxFig, diamondFig, settings);
            classBoxFig.renderingChanged();
            
            // TODO: Why isn't this calculation for location working?
            Point location = bounds.getLocation();
            location.y = (location.y - diamondFig.getHeight()) - 32;
            if (location.y < 16) {
                location.y = 16;
            }
            classBoxFig.setLocation(location);
            this.add(diamondFig);
            this.add(classBoxFig);
            this.add(dashEdgeFig);
        }
        return diamondFig;
    }
}
