Package org.openquark.gems.client

Source Code of org.openquark.gems.client.DisplayedGem$DisplayedPart

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* DisplayedGem.java
* Creation date: (02/18/02 6:27:00 PM)
* By: Edward Lam
*/
package org.openquark.gems.client;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;

import org.openquark.cal.compiler.CALSourceGenerator;
import org.openquark.cal.compiler.ModuleTypeInfo;
import org.openquark.cal.compiler.Scope;
import org.openquark.cal.compiler.ScopedEntityNamingPolicy;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.valuenode.CALRunner;
import org.openquark.cal.valuenode.Target;
import org.openquark.gems.client.Gem.PartInput;
import org.openquark.gems.client.TableTop.DisplayContext;
import org.openquark.util.EmptyIterator;
import org.openquark.util.Pair;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* The representation of a gem extended with notions of location and size
* @author Edward Lam
*/
public class DisplayedGem implements Graph.Node {

    /** provides context information for calculating display properties of this gem. */
    private final DisplayContext displayContext;
   
    /** The gem (model) which is represented by this DisplayedGem. Should be final once assigned. */
    private final Gem gem;

    /** The body part which you can see */
    private final DisplayedPartBody displayedBodyPart;

    /** The displayed output part */
    private DisplayedPartOutput displayedOutputPart;

    /** The array of displayed input parts */
    private DisplayedPartInput[] displayedInputParts;

    /** Gem location */
    private Point location;
   
    /** Gem shape.  Only intended to be mutated by implementing class.  */
    private DisplayedGemShape displayedGemShape;
   
    /** The provider for the displayed gem's shape. */
    private final DisplayedGemShape.ShapeProvider shapeProvider;

    /**
     * Keys for fields in map used with state editable interface
     */
    private static final String DISPLAYED_INPUT_PARTS_KEY = "DisplayedInputPartsStateKey";
   
    // Listeners
    private DisplayedGemLocationListener gemLocationListener;   // listeners for displayed gem location changes
    private DisplayedGemSizeListener gemSizeListener;           // listeners for displayed gem size changes


    /**
     * Construct a Gem from an initial location
     * @param displayContext provides context information for calculating display properties of this gem
     * @param shapeProvider the provider for this gem's shape.
     * @param gem Gem the gem (model) which is represented by this DisplayedGem
     * @param location Point the initial location of the displayed gem
     */
    public DisplayedGem(DisplayContext displayContext, DisplayedGemShape.ShapeProvider shapeProvider, Gem gem, Point location) {
       
        if (displayContext == null || gem == null || location == null) {
            throw new NullPointerException();
        }
       
        this.displayContext = displayContext;
        this.shapeProvider = shapeProvider;
        this.gem = gem;
        this.location = new Point(location);
       
        // create parts for input, output, and body
        displayedBodyPart = new DisplayedPartBody();

        Gem.PartOutput outputPartModel = gem.getOutputPart();
        if (outputPartModel != null) {
            displayedOutputPart = new DisplayedPartOutput(outputPartModel);
        }

        int nArgs = gem.getNInputs();
        displayedInputParts = new DisplayedPartInput[nArgs];
        for (int i = 0; i < nArgs; i++) {
            displayedInputParts[i] = new DisplayedPartInput(gem.getInputPart(i));
        }
    }

    /**
     * Get the gem.
     * @return Gem the gem to which this displayed part belongs
     */
    public final Gem getGem() {
        return gem;
    }

    /**
     * Get the DisplayedGemShape.
     * @return the displayedGemShape.
     */
    public final DisplayedGemShape getDisplayedGemShape() {
        if (displayedGemShape == null) {
            displayedGemShape = shapeProvider.getDisplayedGemShape(this);
        }
        return displayedGemShape;
    }

    /**
     * Get a Shape representing the body shape of this Gem
     * @return Shape the body Shape
     */
    public final Shape getBodyShape() {
        return getDisplayedGemShape().getBodyShape();
    }
   
    /**
     * Returns the displayed output part.
     * @return DisplayedPartOutput
     */
    public final DisplayedPartOutput getDisplayedOutputPart() {
        return displayedOutputPart;
    }   

    /**
     * Returns the displayed input part.
     * @param n int the index of the displayed input to return
     * @return DisplayedPartInput
     */
    public final DisplayedPartInput getDisplayedInputPart(int n) {
        return displayedInputParts[n];
    }
   
    /**
     * Get the displayed body part.
     * @return DisplayedPartBody the body part
     */
    public final DisplayedPartBody getDisplayedBodyPart() {
        return displayedBodyPart;      
    }

    /**
     * Get the connectable displayed parts on this gem.
     *
     * @return List the list of connectable parts on this gem.
     * The order is: input parts first (in order), then output part.
     */
    public final List<DisplayedPartConnectable> getConnectableDisplayedParts() {
        List<DisplayedPartConnectable> connectableParts = new ArrayList<DisplayedPartConnectable>();

        if (displayedInputParts != null) {
            connectableParts.addAll(Arrays.asList(displayedInputParts));
        }

        if (displayedOutputPart != null) {
            connectableParts.add(displayedOutputPart);
        }
        return connectableParts;
    }

    /**
     * Get the number of displayed inputs on this gem.
     *
     * @return int the number of displayed part in this displayed gem
     */
    final int getNDisplayedArguments() {
        return displayedInputParts == null ? 0 : displayedInputParts.length;
    }

    /**
     * Update the displayed inputs on a displayed gem to reflect any input changes in the underlying gem.
     */
    void updateDisplayedInputs() {
        int nArgs = gem.getNInputs();

        // create a map from input to displayed input for the current displayed inputs
        Map<PartInput, DisplayedPartInput> inputDisplayMap = new HashMap<PartInput, DisplayedPartInput>();
        int nDisplayedArgs = displayedInputParts.length;
        for (int i = 0; i < nDisplayedArgs; i++) {
            DisplayedPartInput dInput = displayedInputParts[i];
            inputDisplayMap.put(dInput.getPartInput(), dInput);
        }

        // create an array for the new displayed inputs
        DisplayedPartInput[] newDisplayedInputs = new DisplayedPartInput[nArgs];
       
        // update the new displayed inputs based on the updated gem model
        for (int i = 0; i < nArgs; i++) {
            Gem.PartInput input = gem.getInputPart(i);
            DisplayedPartInput dInput = inputDisplayMap.get(input);
           
            // A new input - must create a new displayed input
            if (dInput == null) {
                dInput = new DisplayedPartInput(input);
            }

            // update the corresponding new displayed input
            newDisplayedInputs[i] = dInput;
        }
       
        // switch the parts over
        displayedInputParts = newDisplayedInputs;
    }

    /**
     * Set the location of this Gem
     * @param newXY Point the new location
     */
    public void setLocation(Point newXY) {
        // Set the location and delete the cached bounds
        if (!location.equals(newXY)) {
            location = new Point(newXY);

            Rectangle oldBounds = getBounds();
            getDisplayedGemShape().purgeCachedBounds();

            // notify listeners
            if (gemLocationListener != null) {
                gemLocationListener.gemLocationChanged(new DisplayedGemLocationEvent(DisplayedGem.this, oldBounds));
            }
        }
    }

    /**
     * Get the location of this Gem
     * @return Point
     */
    public final Point getLocation() {
        // Get the location and return
        return new Point(location);
    }
   
    /**
     * Get the weighted center point of this Gem's body.
     * In mathematics, this is known as the body shape's "centroid".
     * @return the centroid of the gem body.
     */
    public final Point2D getCenterPoint() {
        return getDisplayedGemShape().getCenterPoint();
    }

    /**
     * Is any part of this DisplayedGem under the given point.
     * @param xy Point the point to test for
     * @return boolean whether we hit
     */
    final boolean anyHit(Point xy) {
        return whatHit(xy) != null;
    }

    /**
     * Determine what part of this Gem has been hit
     * @param xy Point the point to test for
     * @return PartConnectable what we hit or null for nothing
     */
    final DisplayedPart whatHit(Point xy) {
        // Test for body hit
        DisplayedGemShape shape = getDisplayedGemShape();
        if (shape.bodyHit(xy)) {
            return getDisplayedBodyPart();
        }

        // Test for output arrow hit
        if (shape.outputHit(xy)) {
            return getDisplayedOutputPart();
        }
        // Test for input blob hit
        int blobNum = shape.inputHit(xy);
        if (blobNum >= 0) {
            return getDisplayedInputPart(blobNum);
        }

        // Nothing was hit
        return null;
    }   

    /**
     * Return the Gem's bounds.
     * @return the bounds of the Gem
     */
    public final Rectangle getBounds() {
        return getDisplayedGemShape().getBounds();
    }

    /**
     * Handle a gem size change.
     */
    void sizeChanged() {
        Rectangle oldBounds = getBounds();
       
        // Null out the displayed gem shape reference.  It will be instantiated the next time it is needed (with fresh bounds..).
        displayedGemShape = null;

        // notify listeners
        if (gemSizeListener != null) {
            gemSizeListener.gemSizeChanged(new DisplayedGemSizeEvent(DisplayedGem.this, oldBounds));
        }
    }   

    /**
     * The textual representation of the gem used for display.
     * @return the String to display
     */
    public final String getDisplayText() {
        if (gem instanceof CodeGem) {
            return ((CodeGem)gem).getUnqualifiedName();

        } else if (gem instanceof CollectorGem) {
            return ((CollectorGem)gem).getUnqualifiedName();

        } else if (gem instanceof RecordFieldSelectionGem) {
            return ((RecordFieldSelectionGem)gem).getDisplayedText();

        } else if (gem instanceof RecordCreationGem) {
            return ((RecordCreationGem)gem).getDisplayName();

        } else if (gem instanceof FunctionalAgentGem) {
            ModuleTypeInfo moduleTypeInfo = displayContext.getContextModuleTypeInfo();
            ScopedEntityNamingPolicy namingPolicy = moduleTypeInfo == null ?
                                                    namingPolicy = ScopedEntityNamingPolicy.FULLY_QUALIFIED :
                                                    new ScopedEntityNamingPolicy.UnqualifiedUnlessAmbiguous(moduleTypeInfo);
            return ((FunctionalAgentGem)gem).getGemEntity().getAdaptedName(namingPolicy);     
       
        } else if (gem instanceof ReflectorGem) {
            return ((ReflectorGem)gem).getUnqualifiedName();
       
        } else if (gem instanceof ValueGem) {
            return GemCutter.getResourceString("ValueGemDisplayText");
       
        } else {
            throw new IllegalArgumentException("Unknown gem class: " + this.getClass());
        }
       
    }

    /**
     * Describe this Gem
     * @return the description
     */
    @Override
    public final String toString() {
        return "DisplayedGem.  Location: (" + location + ").  Gem: " + gem;
    }  

    /*
     * Methods implementing Graph.Node ********************************************************************
     */

    /**
     * Return the degree of this gem. i.e. how many connections it supports.
     * @return double
     */
    public final double degree() {
        return getConnectableDisplayedParts().size();
    }      

    /**
     * Get an iterator over the incoming edges.
     * @param validNodes the list of nodes that you would count as incoming edges
     *                   this is used for selective graph traversal
     * @return Iterator
     */
    public final Iterator<Graph.Edge> getInEdges(List<Graph.Node> validNodes) {
        int nDisplayedArgs = getNDisplayedArguments();
        if (nDisplayedArgs == 0) {
            return EmptyIterator.emptyIterator();
        }
       
        List<Graph.Edge> inEdgeList = new ArrayList<Graph.Edge>();
        for (int i = 0; i < nDisplayedArgs; ++i) {
            DisplayedConnection dConn = getDisplayedInputPart(i).getDisplayedConnection();
            if (dConn != null) {
                // We only count the edge if the node is valid
                if (validNodes.contains(dConn.getSourceNode())) {
                    inEdgeList.add (dConn);
                }
            }
        }
       
        return inEdgeList.iterator();
    }

    /**
     * Get an iterator over the outgoing edges.
     * @param validNodes the list of nodes that you want to count
     * @return Iterator
     */
    public final Iterator<Graph.Edge> getOutEdges(List<Graph.Node> validNodes) {
       
        // get the output part
        DisplayedGem.DisplayedPartOutput partOutput = getDisplayedOutputPart();
       
        // get the connection. If there is no connection or no partOutput, then there are no out edges
        DisplayedConnection displayedConnection = partOutput == null ? null : partOutput.getDisplayedConnection();
        if (displayedConnection == null) {
            return EmptyIterator.emptyIterator();
        }
       
        Graph.Node node = displayedConnection.getTargetNode();
       
        // if the node is not valid, then we don't count it
        if (!validNodes.contains(node)) {
            return EmptyIterator.emptyIterator();
        }

        List<Graph.Edge> outEdgeList = new ArrayList<Graph.Edge>();
        outEdgeList.add (getDisplayedOutputPart().getDisplayedConnection());
        return outEdgeList.iterator();
    }

    /*
     * Methods implementing Target     ****************************************************************
     */

    /**
     * @return a target corresponding to this DisplayedGem.
     */
    public Target getTarget() {
       
        // if this gem is a Collector Gem then use its name else use the general name
        String targetName = (gem instanceof CollectorGem) ? ((CollectorGem)gem).getUnqualifiedName() : CALRunner.TEST_SC_NAME;

        return new Target(targetName) {
            @Override
            protected SourceModel.FunctionDefn getSCDefn(String scName) {
                // Build the new SC definition and return
                return CALSourceGenerator.getFunctionSourceModel(scName, gem, Scope.PRIVATE);
            }
        };
    }

    /**
     * Return the arguments as would be required by current definition of the Gem tree at the Target.
     * @return the list of arguments required by the target.
     */
    public final List<PartInput> getTargetArguments() {
        return gem.getTargetInputs();
    }

    /*
     * Methods supporting XMLPersistable                 ********************************************
     */

    /**
     * Attach the saved form of this object as a child XML node.
     * @param parentNode Node the node that will be the parent of the generated XML. 
     *   The generated XML will be appended as a subtree of this node. 
     * Note: parentNode must be a node type that can accept children (eg. an Element or a DocumentFragment)
     * @param gemContext the context in which the gem is saved.
     */
    public void saveXML(Node parentNode, GemContext gemContext) {
       
        Document document = (parentNode instanceof Document) ? (Document)parentNode : parentNode.getOwnerDocument();

        // Create the displayed gem element
        Element resultElement = document.createElement(GemPersistenceConstants.DISPLAYED_GEM_TAG);
        parentNode.appendChild(resultElement);

        // Add an element for the info for the underlying gem.
        gem.saveXML(resultElement, gemContext);

        // Add a child location element
        Element locationElement = GemCutterPersistenceHelper.pointToElement(getLocation(), document);
        resultElement.appendChild(locationElement);
    }

    /*
     * Methods supporting undo.StateEditable ********************************************
     */

    /**
     * Restore the stored displayed input state.
     * @param state Hashtable the stored state
     */
    void restoreDisplayedInputState(Hashtable<Pair<DisplayedGem, String>, DisplayedPartInput[]> state) {

        DisplayedPartInput[] displayedInputParts =
            state.get(new Pair<DisplayedGem, String>(DisplayedGem.this, DISPLAYED_INPUT_PARTS_KEY));

        if (displayedInputParts != null) {
            this.displayedInputParts = displayedInputParts.clone();
        }
    }

    /**
     * Save the displayed input state.
     * @param state Hashtable the table in which to store the displayed input state
     */
    void storeDisplayedInputState(Hashtable<Pair<DisplayedGem, String>, DisplayedPartInput[]> state) {

        state.put(new Pair<DisplayedGem, String>(DisplayedGem.this, DISPLAYED_INPUT_PARTS_KEY), displayedInputParts.clone());
    }

    /*
     * Methods to handle listeners     ****************************************************************
     */

    /**
     * Adds the specified location change listener to receive location change events from this gem .
     * If l is null, no exception is thrown and no action is performed.
     *
     * @param    l   the location listener.
     */
    public synchronized void addLocationChangeListener(DisplayedGemLocationListener l) {
        if (l == null) {
            return;
        }
        gemLocationListener = GemEventMulticaster.add(gemLocationListener, l);
    }

    /**
     * Removes the specified location change listener so that it no longer receives location change events from this gem.
     * This method performs no function, nor does it throw an exception, if the listener specified by
     * the argument was not previously added to this component.
     * If l is null, no exception is thrown and no action is performed.
     *
     * @param    l   the location listener.
     */
    public synchronized void removeLocationChangeListener(DisplayedGemLocationListener  l) {
        if (l == null) {
            return;
        }
        gemLocationListener = GemEventMulticaster.remove(gemLocationListener, l);
    }

    /**
     * Adds the specified size change listener to receive size change events from this gem .
     * If l is null, no exception is thrown and no action is performed.
     *
     * @param    l   the size listener.
     */
    public synchronized void addSizeChangeListener(DisplayedGemSizeListener l) {
        if (l == null) {
            return;
        }
        gemSizeListener = GemEventMulticaster.add(gemSizeListener, l);
    }

    /**
     * Removes the specified size change listener so that it no longer receives size change events from this gem.
     * This method performs no function, nor does it throw an exception, if the listener specified by
     * the argument was not previously added to this component.
     * If l is null, no exception is thrown and no action is performed.
     *
     * @param    l   the size listener.
     */
    public synchronized void removeSizeChangeListener(DisplayedGemSizeListener  l) {
        if (l == null) {
            return;
        }
        gemSizeListener = GemEventMulticaster.remove(gemSizeListener, l);
    }

    /**
     * A part of a Gem
     * @author Edward Lam
     */
    public abstract class DisplayedPart {

        /**
         * Default constructor for a DisplayedPart
         */
        public DisplayedPart() {
        }

        /**
         * Get the gem to which this displayed part belongs.
         * @return Gem the gem to which this displayed part belongs
         */
        public Gem getGem() {
            return gem;
        }

        /**
         * Get the displayed gem of which this is part
         * @return DisplayedGem the displayed gem to which this displayed part belongs
         */
        public DisplayedGem getDisplayedGem() {
            return DisplayedGem.this;
        }

        /**
         * Get the bounds of this part
         * @return Rectangle the bounds
         */
        public abstract Rectangle getBounds();
    }

    /**
     * A connectable PartConnectable has both a type and a bind point for a Connector.
     * @author Edward Lam
     */
    public abstract class DisplayedPartConnectable extends DisplayedPart {

        /** the PartConnectable represented by this DisplayedPartConnectable */
        private final Gem.PartConnectable partConnectable;

        /** the displayed connection associated with this connectable part*/
        private DisplayedConnection dConnection;

        /**
         * Default constructor for a DisplayedPartConnectable
         */
        DisplayedPartConnectable(Gem.PartConnectable partConnectable) {
            super();
            this.partConnectable = partConnectable;
        }

        /**
         * Get the connectable part.
         * @return Gem.PartConnectable the part to which this displayed part belongs
         */
        public final Gem.PartConnectable getPartConnectable() {
            return partConnectable;
        }

        /**
         * Get the connection point for this part
         * @return the point at which components will connect
         */
        public abstract Point getConnectionPoint();

        /**
         * Repaint this PartConnectable's connection (if it has one!)
         * @param c JComponent the component to paint on 
         */
        public void repaintConnection(JComponent c) {
            if (isConnected()) {
                c.repaint(dConnection.getBounds());
            }
        }
       
        /**
         * Bind a connection to this part.
         * @param dConn DisplayedConnection the connection to connect
         */
        public void bindDisplayedConnection(DisplayedConnection dConn) {
            dConnection = dConn;
        }  

        /**
         * Get the displayed connection at this part.
         * @return conn DisplayedConnection the connection bound to this part
         */
        public final DisplayedConnection getDisplayedConnection() {
            return dConnection;
        }  

        /**
         * Check if this part is connected.
         * @return boolean whether it is already connected
         */
        public final boolean isConnected() {
            return (dConnection != null);
        }
       
        /**
         * Purge this PartConnectable's connection route (if it has one)
         */
        public void purgeConnectionRoute() {
            if (dConnection != null) {
                dConnection.purgeRoute();
            }
        }

        /**
         * Get the source of this edge.
         * @return Graph.Node
         */
        public final Graph.Node getSourceNode() {
            if (isConnected()) {
                return dConnection.getSourceNode();
            }
           
            return null;
        }

        /**
         * Get the destination of this edge.
         * @return Graph.Node
         */
        public final Graph.Node getTargetNode() {
            if (isConnected()) {
                return dConnection.getTargetNode();
            }
           
            return null;
        }
    }

    /**
     * The PartConnectable representing the body of the Gem
     * @author Edward Lam
     */
    public class DisplayedPartBody extends DisplayedPart {

        /**
         * Default constructor for a DisplayedPartBody
         */
        private DisplayedPartBody() {
        }

        /**
         * Get the bounds of this part
         * @return Rectangle the bounds
         */
        @Override
        public final Rectangle getBounds() {
            return getDisplayedGemShape().getBodyBounds();
        }
    }

    /**
     * A PartInput is a connectable part which is a sink (destination).
     * @author Edward Lam
     */
    public class DisplayedPartInput extends DisplayedPartConnectable {
       
        /**
         * Default constructor for a DisplayedPartInput
         * @param partInput the input corresponding to this displayed input.
         */
        public DisplayedPartInput(Gem.PartInput partInput) {
            super(partInput);
        }

        /**
         * Get the input part.
         * @return Gem.PartInput the part to which this displayed part belongs
         */
        public final Gem.PartInput getPartInput() {
            return (Gem.PartInput)getPartConnectable();
        }

        /**
         * Get the connection point for this part
         * @return the point at which components will connect
         */
        @Override
        public Point getConnectionPoint() {
            return getDisplayedGemShape().getInputConnectPoint(getPartInput().getInputNum());
        }

        /**
         * Get the bounds of this part foo.
         * @return Rectangle the bounds
         */
        @Override
        public Rectangle getBounds() {
            return getDisplayedGemShape().getInBounds();
        }
    }

    /**
     * A PartOutput is a connectable part which is a source/output.
     * @author Edward Lam
     */
    public class DisplayedPartOutput extends DisplayedPartConnectable {

        /**
         * Default constructor for a DisplayedPartOutput
         * @param partOutput the output corresponding to this displayed output.
         */
        DisplayedPartOutput(Gem.PartOutput partOutput) {
            super(partOutput);
        }

        /**
         * Get the output part.
         * @return Gem.PartOutput the part to which this displayed part belongs
         */
        public final Gem.PartOutput getPartOutput() {
            return (Gem.PartOutput)getPartConnectable();
        }

        /**
         * Get the connection point for this part
         * @return the point at which components will connect
         */
        @Override
        public Point getConnectionPoint() {
            return getDisplayedGemShape().getOutputConnectPoint();
        }

        /**
         * Get the bounds of this part
         * @return Rectangle the bounds
         */
        @Override
        public Rectangle getBounds() {
            return getDisplayedGemShape().getOutBounds();
        }
    }
}


TOP

Related Classes of org.openquark.gems.client.DisplayedGem$DisplayedPart

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.