Package edu.mit.blocks.workspace.typeblocking

Source Code of edu.mit.blocks.workspace.typeblocking.FocusTraversalManager

package edu.mit.blocks.workspace.typeblocking;

import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import edu.mit.blocks.codeblocks.Block;
import edu.mit.blocks.codeblocks.BlockConnector;
import edu.mit.blocks.renderable.RenderableBlock;
import edu.mit.blocks.workspace.BlockCanvas.Canvas;
import edu.mit.blocks.workspace.Page;
import edu.mit.blocks.workspace.Workspace;
import edu.mit.blocks.workspace.WorkspaceEvent;
import edu.mit.blocks.workspace.WorkspaceListener;

/**
* The FocusTraversalManager has two function.  First, it
* maintains a pointer to the block, if any, that has
* focus and the corresponding focus point on that block. 
* If the focus is not on the block, then it must be set
* to some point of the block canvas.
*
* The second primary function of the FocusTraversalManager
* is to redirect the focus to the next appropriate block
* in a particular stack.  One could "traverse" the stack
* by moving the focus to one of the following:
*     1. the block after
*     2. the block before
*     3. the next block
*     4. the previous block
*
* The exact definition of what "next", "previous",
* "after", and "before" is described in details in
* their corresponding method summary.
* As a focus manager of the entire system, the class
* must maintain particular invariants at all time. 
* Clients of this module may obtain the focus through
* three observer (getter) methods.  Clients may also
* manualy mutate the focus through three modifier (setter)
* methods.
*
* However, BOTH the value returned in the observer
* methods and the value passed in the modifier methods
* MUST maintain particular invariants described below.
*
* These invariants must hold at all time and check reps
* should be imposed to ensure that any changes to the
* system still holds these crucial invariants.  Clients
* of this module may assume that the invariants mentioned
* below will always hold.
*
* INVARIANT I.
*   If the canvas has focus, then the block does not. Thus
*     1. focusBlock == Block.null
*     2. canvasFocusPoint != null
*     3. blockFocusPoint == null
*
* INVARIANT II.
*   If the block has focus, then the canvas does not. Thus
*     1. focusBlock != Block.null
*     2. canvasFocusPoint == null
*     3. blockFocusPoint != null
*
* @specfield focusBlock : Long //block with focus
* @specfield canvasFocusPoint : Point //focus point on canvas relative to canvas
* @specfield blockFocusPoint : Point //focus point on block relative to block
*
*/
public class FocusTraversalManager implements MouseListener, KeyListener, WorkspaceListener {

    /** this.focuspoint: the point on the block with focus */
    private Point blockFocusPoint = null;
    /** this.focuspoint: the point on the block canvas's last mosue click */
    private Point canvasFocusPoint = new Point(0, 0);
    /** this.focusblock: the Block ID that currently has focus */
    private Long focusBlock = Block.NULL;
    private final Workspace workspace;

    /////////////////
    // Constructor //
    /////////////////
    public FocusTraversalManager(Workspace workspace) {
        this.workspace = workspace;
    }

    ///////////////
    // Observers //
    ///////////////
    /**
     * @return the block that has focus, if any.
     *
     * TODO: finish method documentation
     */
    public Long getFocusBlockID() {
        //DO NOT REMOVE CHECK REP BELOW!!!
        //Many client classes depend on this invariant

        if (invalidBlock(focusBlock)) {
            //If block is null then, focus should be on block on canvas.
            //To test this, we must recall that when focus is on block,
            //the canvas focus point is set to null.
            if (canvasFocusPoint == null) {
                throw new RuntimeException(
                        "Focus has not yet been set to block");
            }
            if (blockFocusPoint != null) {
                throw new RuntimeException(
                        "Focus should be set to block");
            }

        } else {
            //if block is not null, then we need to make sure the
            //focus is on the block.  To test this, we recall
            //that when the focus is on the block, the
            //canvas focus point is set to null
            if (canvasFocusPoint != null) {
                throw new RuntimeException(
                        "Focus has not yet been set to canvas");
            }
            if (blockFocusPoint == null) {
                throw new RuntimeException(
                        "Focus has not been removed from block");
            }
        }
        return focusBlock;
    }

    /**
     * @return point of focus on canvas
     *
     * TODO: finish method documentation
     */
    public Point getCanvasPoint() {
        //DO NOT REMOVE CHECK REP BELOW!!!
        //Many client classes depend on this invariant

        //If focus block is not null, then the focus is
        //currently set on that instance of the block.
        //As a result, you may not request the canvas's
        //focus point because it DOES NOT have focus
        if (!invalidBlock(focusBlock)) {
            throw new RuntimeException(
                    "May not request canvas's focus point if "
                    + "canvas does not have focus. Focus at: " + focusBlock);
        }
        if (blockFocusPoint != null) {
            throw new RuntimeException(
                    "May not request canvas's focus point if "
                    + "canvas does not have focus. Focus at: " + blockFocusPoint);
        }
        if (canvasFocusPoint == null) {
            throw new RuntimeException(
                    "May not request canvas's focus point if "
                    + "canvas does not have focus. Canvas focus is null.");
        }
        //Okay, invariant holds.  So return point of focus on canvas.
        return canvasFocusPoint;
    }

    /**
     * @return point of focus on block
     *
     * TODO: finish method documentation
     */
    public Point getBlockPoint() {
        //DO NOT REMOVE CHECK REP BELOW!!!
        //Many client classes depend on this invariant

        //If focus block is null, then the focus is
        //currently set on canvas.  You may not request
        //the block's focus point because it DOES NOT have focus
        if (invalidBlock(focusBlock)) {
            throw new RuntimeException(
                    "May not request block's focus point if "
                    + "block does not have focus. Focus at: " + focusBlock);
        }
        if (blockFocusPoint == null) {
            throw new RuntimeException(
                    "May not request block's focus point if "
                    + "block does not have focus. Focus at: " + blockFocusPoint);
        }
        if (canvasFocusPoint != null) {
            throw new RuntimeException(
                    "Canvas focus is still valid. May not request"
                    + "block's focus point if block does not have focus.");
        }
        //Okay, invariant holds.  So return point of focus on canvas.
        return blockFocusPoint;
    }

    //////////////////
    // Focus Set Up //
    //////////////////
    /**
     * Sets focus to block
     * @param block
     *
     * TODO: finish method documentation
     */
    public void setFocus(Block block) {
        if (block == null) {
            throw new RuntimeException("Invariant Violated:"
                    + "may not set focus to a null Block instance");
            //Please do not remove exception above.  This class
            //and many other classes within the typeblocking
            //package requires that the following invariant(s) must hold:
            //    MAY NOT SET FOCUS TO NULL BLOCK INSTANCES
        } else {
            setFocus(block.getBlockID());
        }
    }

    public void setFocus(Long blockID) {
        if (blockID == null || blockID == Block.NULL || blockID == -1 || workspace.getEnv().getBlock(blockID) == null) {
            throw new RuntimeException("Invariant Violated:"
                    + "may not set focus to a null Block instance");
            //Please do not remove exception above.  This class
            //and many other classes within the typeblocking
            //package requires that the following invariant(s) must hold:
            //    MAY NOT SET FOCUS TO NULL BLOCK INSTANCES
        }
        //remove focus from old block if one existed
        if (!invalidBlock(this.focusBlock)) {
            getBlock(this.focusBlock).setFocus(false);
            workspace.getEnv().getRenderableBlock(this.focusBlock).repaintBlock();
        }
        //set focus block to blockID
        getBlock(blockID).setFocus(true);
        workspace.getEnv().getRenderableBlock(blockID).requestFocus();
        workspace.getEnv().getRenderableBlock(blockID).repaintBlock();
        //set canvas focus point to be null; canvas no longer has focus
        this.canvasFocusPoint = null;
        //set blockfocus point to new value
        this.blockFocusPoint = new Point(0, 0);
        //set focusblock
        this.focusBlock = blockID;

        //System.out.println("FocusManager: Setting focus to block: " + this.focusBlock+", "+this.blockFocusPoint+", "+this.canvasFocusPoint);
    }

    /**
     * Set Focus to canvas at canvasPoint.  THE BLOCKID MUST BE BLOCK.NULL!!!
     * @param canvasPoint
     * @param blockID
     *
     * TODO: finish method documentation
     */
    public void setFocus(Point canvasPoint, Long blockID) {
        if (blockID == null || blockID == Block.NULL || blockID == -1 || workspace.getEnv().getBlock(blockID) == null) {
            //remove focus form old block if one existed
            if (!invalidBlock(this.focusBlock)) {
                getBlock(this.focusBlock).setFocus(false);
                workspace.getEnv().getRenderableBlock(this.focusBlock).repaintBlock();
            }
            //set block ID to null
            this.focusBlock = Block.NULL;
            //set canvas focus point to canvasPoint
            this.canvasFocusPoint = canvasPoint;
            //set block focus point to null
            this.blockFocusPoint = null;

            //System.out.println("FocusManager: Setting focus to canvas: " + this.focusBlock+", "+this.blockFocusPoint+", "+this.canvasFocusPoint);
        } else {
            throw new RuntimeException("Invariant Violated:"
                    + "may not set new focus point if focus is on a block");
            //Please do not remove exception above.  This class
            //and many other classes within the typeblocking
            //package requires that the following invariant(s) must hold:
            //    CANVAS POINT MAY NOT BE SET UNLESS BLOCK IS NULL
            //    CANVAS POINT MAY NOT BE SET IF FOCUS IS ON BLOCK
        }
    }

    void setFocus(Point location) {
        //please do not remove this method or try to
        //create a method this takes only a point as an argument.
        //The thing is, it's too tricky to create such a method
        //and I want to let users who use this method know that
        //this is a fundalmentally wrong method to invoke.
        //may not use this method as it does not ensure class invariant will hold
        throw new RuntimeException("The use of this method is FORBIDDEN");
    }

    //////////////////////////////////////
    // Focus Traversal Handling Methods //
    //////////////////////////////////////
    /**
     * Reassigns the focus to the "next block" of the current focusBlock.
     * If the current focusblock is at location n of the flatten linear vector
     * of the block tree structure, then the "next block" is located at n+1.
     * In other words, the previous block is the parent block of the next
     * socket of the parent block of the focusblock.
     *
     * @requires   pointFocusOwner != null &&
     *         focusblock.getSockets() != null &&
     *         focusblock.getSockets() is not empty
     * @modifies this.focusblock
     * @effects this.focusblock now points to the "next block"
     *       as described in method overview;
     * @return true if the new focus is on a block that isn't null
     */
    public boolean focusNextBlock() {
        //return focus to canvas if no focusblock does not exist
        if (invalidBlock(focusBlock) || !workspace.getEnv().getRenderableBlock(focusBlock).isVisible()) {
            setFocus(canvasFocusPoint, Block.NULL);
            return false;
        }
        //give focus to any preceeding socket of current block
        Block currentBlock = getBlock(focusBlock);
        for (BlockConnector socket : currentBlock.getSockets()) {
            if (socket != null && !invalidBlock(socket.getBlockID())) {
                //give focus to socket block
                setFocus(socket.getBlockID());
                return true;
            }
        }
        //give focus to after block of current block
        Long afterBlock = currentBlock.getAfterBlockID();
        if (!invalidBlock(afterBlock)) {
            setFocus(afterBlock);
            return true;
        }
        //current block != null.....invariant checke in getNextNode()
        Block nextBlock = this.getNextNode(currentBlock);
        //check invariant
        if (nextBlock == null) {
            throw new RuntimeException("Invariant Violated: return value of getNextNode() may not be null");
        }
        //set focus
        setFocus(nextBlock.getBlockID());
        return true;
    }

    /**
     * Reassigns the focus to the "previous block" of the current focusBlock.
     * If the current focusblock is at location n of the flatten linear vector
     * of the block tree structure, then the "previous block" is located at n-1.
     * In other words, the previous block is the innermost block of the previous
     * socket of the parent block of the focusblock.
     *
     * @requires   pointFocusOwner != null &&
     *         focusblock.getSockets() != null &&
     *         focusblock.getSockets() is not empty
     * @modifies this.focusblock
     * @effects this.focusblock now points to the "previous block"
     *       as described in method overview;
     * @return true if the new focus is on a block that isn't null
     */
    public boolean focusPrevBlock() {
        //return focus to canvas if no focusblock does not exist
        if (invalidBlock(focusBlock) || !workspace.getEnv().getRenderableBlock(focusBlock).isVisible()) {
            setFocus(canvasFocusPoint, Block.NULL);
            return false;
        }

        Block currentBlock = getBlock(focusBlock);
        //set plug to be previous block
        Block previousBlock = getPlugBlock(currentBlock);
        //if plug is null, set before to be previous block
        if (previousBlock == null) {
            previousBlock = getBeforeBlock(currentBlock);
        }
        //If before is ALSO null, jump to bottom of the stack;
        if (previousBlock == null) {
            previousBlock = getBottomRightBlock(currentBlock);
        } else {
            //If at least a plug block OR (but not both) before block exist,
            //then get innermost block of the previous socket of the previous block
            //assumes previousBlock.getSockets is not empty, not null
            Block beforeBlock = previousBlock;
            //ASSUMPTION BEING MADE: assume that the list below is constructed to
            //have all the sockets FOLLOWED by FOLLOWED by the after connector
            //THE ORDER MUST BE KEPT TO WORK CORRECTLY!  We cannot use
            //BlockLinkChecker.getSocketEquivalents because the specification does
            //not guarantee this precise ordering.  Futhermore, an interable
            //has no defined order.  However, as of this writing, the current implementation
            //of that method does seem to produce this ordering.  But we're still not using it.
            List<BlockConnector> connections = new ArrayList<BlockConnector>();
            for (BlockConnector socket : previousBlock.getSockets()) {
                connections.add(socket); //add sockets
            }
            connections.add(previousBlock.getAfterConnector()); //add after connector
            //now traverse the connections
            for (BlockConnector connector : connections) {
                if (connector == null || connector.getBlockID() == Block.NULL || getBlock(connector.getBlockID()) == null) {
                    continue; //if null socket, move on to next socket
                }
                if (connector.getBlockID().equals(currentBlock.getBlockID())) { //reached back to current block
                    if (!beforeBlock.getBlockID().equals(previousBlock.getBlockID())) {
                        //if previous block was never updated, go to bottom of stack
                        previousBlock = getBottomRightBlock(previousBlock);
                    }
                    setFocus(previousBlock.getBlockID());
                    return true;
                }
                //update previous block
                previousBlock = getBlock(connector.getBlockID());
            }
            //so it seems liek all sockets are null (or sockets exist),
            //so just get the bottom of the stack
            previousBlock = getBottomRightBlock(previousBlock);
        }
        setFocus(previousBlock.getBlockID());
        return true;
    }

    /**
     * Gives focus to the first after block down the tree,
     * that is, the next control block in the stack.
     * If next control block does not exist, then give
     * focus to current focusblock.  Otherwise, give
     * focus to block canvas.
     *
     * Expects no wrapping to TopOfStack block, do not use this method for infix blocks
     *
     * @requires focusblock.isMinimized() == false
     * @modifies this.focusblock
     * @effects sets this.focusblock to be the first
     *       after block if possible.  Otherwise, keep
     *       the focus on the current focusblock.
     *       If focus block is an invalid block,
     *       return focus to the default (block canvas)
     * @return true if and only if focus was set to new after block
     */
    public boolean focusAfterBlock() {
        if (invalidBlock(focusBlock) || !workspace.getEnv().getRenderableBlock(focusBlock).isVisible()) {
            //return focus to canvas if no focusblock does not exist
            setFocus(canvasFocusPoint, Block.NULL);
            return false;
        }
        Block currentBlock = getBlock(focusBlock);
        while (currentBlock != null) {
            if (getAfterBlock(currentBlock) != null) {
                //return focus to before block
                setFocus(getAfterBlock(currentBlock));
                return true;
            }
            currentBlock = getPlugBlock(currentBlock);
            if (currentBlock == null) {
                //return focus to old block
                setFocus(focusBlock);
                return true;
            }
        }
        return true;
    }

    /**
     * Gives focus to the first beforeblock up the tree,
     * that is, the previous control block in the stack.
     * If no previous control block exists, then give
     * focus to current focusblock.  Otherwise, give
     * focus to block canvas.
     *
     * Expects no wrapping to bottom block, do not use this method for infix blocks
     *
     * @requires focusblock.isMinimized() == false
     * @modifies this.focusblock
     * @effects sets this.focusblock to be the first
     *       before block if possible.  Otherwise, keep
     *       the focus on the current focusblock.
     *       If focus block is an invalid block,
     *       return focus to the default (block canvas)
     * @return true if and only if focus was set to new before block
     */
    public boolean focusBeforeBlock() {
        if (invalidBlock(focusBlock) || !workspace.getEnv().getRenderableBlock(focusBlock).isVisible()) {
            //return focus to canvas if no focusblock does not exist
            setFocus(canvasFocusPoint, Block.NULL);
            return false;
        }
        Block currentBlock = getBlock(focusBlock);
        while (currentBlock != null) {
            if (getBeforeBlock(currentBlock) != null) {
                //return focus to before block
                setFocus(getBeforeBlock(currentBlock));
                return true;
            }
            currentBlock = getPlugBlock(currentBlock);
            if (currentBlock == null) {
                //return focus to old block
                setFocus(focusBlock);
                return false;
            }
        }
        return false;
    }

    ///////////////////////
    // TRAVERSING STACKS //
    ///////////////////////
    /**
     * @requires currentBlock != null
     * @param currentBlock
     * @return currentBlock or NON-NULL block that is the next node of currentBlock
     */
    private Block getNextNode(Block currentBlock) {
        //check invarient
        if (invalidBlock(currentBlock)) {
            throw new RuntimeException("Invariant Violated: may not resurve over a null instance of currentBlock");
        }
        //if plug not null, then let plug be parent of current block
        Block parentBlock = getBlock(currentBlock.getPlugBlockID());
        //otherwise if after not null, then let after be parent of current block
        if (invalidBlock(parentBlock)) {
            parentBlock = getBlock(currentBlock.getBeforeBlockID());
        }
        //if plug and after are both null, then return currentBlock
        if (invalidBlock(parentBlock)) {
            return currentBlock;
        }
        //socket index of current block with respect to its parent
        int i = parentBlock.getSocketIndex(parentBlock.getConnectorTo(currentBlock.getBlockID()));
        //return socket block of parent if one exist
        //int i == 0 if not current block not a socket of parent
        if (i != -1 && i >= 0) {
            for (BlockConnector parentSocket : parentBlock.getSockets()) {
                if (parentSocket == null || invalidBlock(parentSocket.getBlockID()) || parentBlock.getSocketIndex(parentSocket) <= i) {
                    continue;
                } else {
                    return getBlock(parentSocket.getBlockID());
                }
            }
        }
        //return afterblock of parent
        if (invalidBlock(parentBlock.getAfterBlockID())) {
            return getNextNode(parentBlock);
        }
        if (parentBlock.getAfterBlockID().equals(currentBlock.getBlockID())) {
            return getNextNode(parentBlock);
        }
        //This is top of the block, so return currentBlock
        return getBlock(parentBlock.getAfterBlockID());
    }

    /**
     * For a given block, returns the outermost (top-leftmost)
     * block in the stack.
     * @requires block represented by blockID != null
     * @param blockID any block in a stack.
     * @return  the outermost block (or Top-of-Stack)
     *       such that the outermost  block != null
     */
    Long getTopOfStack(Long blockID) {
        //check invariant
        if (blockID == null || blockID == Block.NULL || workspace.getEnv().getBlock(blockID) == null) {
            throw new RuntimeException("Invariant Violated: may not"
                    + "iterate for outermost block over a null instance of Block");
        }
        //parentBlock is the topmost block in stack
        Block parentBlock = null;
        //go the top most block
        parentBlock = getBeforeBlock(blockID);
        if (parentBlock != null) {
            return getTopOfStack(parentBlock.getBlockID());
        }
        //go to the left most block
        parentBlock = getPlugBlock(blockID);
        if (parentBlock != null) {
            return getTopOfStack(parentBlock.getBlockID());
        }
        //check invariant
        if (parentBlock != null) {
            throw new RuntimeException("Invariant Violated: may not "
                    + "return a null instance of block as the outermost block");
        }
        //If we can't traverse any deeper, then this is innermost Block.
        return blockID;
    }

    /**
     * For a given block, returns the innermost (bottom-rightmost)
     * block in the substack.
     * @requires block !=null block.getBlockID != Block.NULL
     * @param block the top block of the substack.
     * @return the innermost block in the substack.
     *        such that the innermost block != null
     */
    private Block getBottomRightBlock(Block block) {
        //check invariant
        if (block == null || block.getBlockID() == Block.NULL) {
            throw new RuntimeException("Invariant Violated: may not"
                    + "iterate for innermost block over a null instance of Block");
        }
        //returnblock = next deepest node on far right
        Block returnBlock = null;
        // find deepest node, that is, bottom most block in stack.
        returnBlock = getAfterBlock(block);
        if (returnBlock != null) {
            return getBottomRightBlock(returnBlock);
        }
        // move to the next socket in line:
        for (BlockConnector socket : block.getSockets()) {//assumes socket!=null
            Block socketBlock = getBlock(socket.getBlockID());
            if (socketBlock != null) {
                returnBlock = socketBlock;
            }
        }
        if (returnBlock != null) {
            return getBottomRightBlock(returnBlock);
        }
        //check invariant
        if (returnBlock != null) {
            throw new RuntimeException("Invariant Violated: may not "
                    + "return a null instance of block as the innermost block");
        }
        //If we can't traverse any deeper, then this is innermost Block.
        return block;
    }

    //////////////////////
    //Convienence Method//
    //////////////////////
    /**
     * @param block
     * @return   true if and only if block ==null ||
     *       block.getBlockID == null &&
     *       block.getBLockID == Block.NULL
     */
    private boolean invalidBlock(Block block) {
        if (block == null) {
            return true;
        }
        if (block.getBlockID() == null) {
            return true;
        }
        if (block.getBlockID() == Block.NULL) {
            return true;
        }
        return false;
    }

    private boolean invalidBlock(Long blockID) {
        if (blockID == null) {
            return true;
        }
        if (blockID == Block.NULL) {
            return true;
        }
        if (getBlock(blockID) == null) {
            return true;
        }
        return false;
    }

    /**
     * All the private methods below follow a similar
     * specification. They all require that the block
     * referanced by blockID (or block.getBlockID) is
     * non-null.  If getting a socket block, they
     * additionally require that 0<socket< # of sockets in block.
     * All the methods before return a block located
     * at a block connector corresponding to the name
     * of the obserser method.
     *
     * @requires blockID != Block.Null && block !=null
     * @return Block instance located at corresponding
     *       connection or null if non exists
     */
    private Block getBlock(Long blockID) {
        return workspace.getEnv().getBlock(blockID);
    }

    private Block getBeforeBlock(Long blockID) {
        return getBeforeBlock(getBlock(blockID));
    }

    private Block getBeforeBlock(Block block) {
        return getBlock(block.getBeforeBlockID());
    }

    private Block getAfterBlock(Block block) {
        return getBlock(block.getAfterBlockID());
    }

    private Block getPlugBlock(Long blockID) {
        return getPlugBlock(getBlock(blockID));
    }

    private Block getPlugBlock(Block block) {
        return getBlock(block.getPlugBlockID());
    }

    ///////////////////
    // MOUSE METHODS //
    ///////////////////
    /**
     * Action: removes the focus current focused block
     *        and places new focus on e.getSource
     * @requires e != null
     * @modifies this.blockFocusOwner && e.getSource
     * @effects removes focus from this.blockFocusOwner
     *       adds focus to e.getSource iff e.getSource
     *       is instance of BlockCanvas and RenderableBlock
     */
    private void grabFocus(MouseEvent e) {
        //System.out.println("FocusManager: Mouse Event at ("+ e.getX()+", "+e.getY()+") on "+e.getSource());
        if (e.getSource() instanceof Canvas) {
            //get canvas point
            Point canvasPoint = e.getPoint();
            /*          SwingUtilities.convertPoint(
            (BlockCanvas)e.getSource(),
            e.getPoint(),
            ((BlockCanvas)e.getSource()).getCanvas());*/
            setFocus(canvasPoint, Block.NULL);
            ((Canvas) e.getSource()).grabFocus();
        } else if (e.getSource() instanceof RenderableBlock) {
            setFocus(((RenderableBlock) e.getSource()).getBlockID());
            ((RenderableBlock) e.getSource()).grabFocus();
        }
    }

    public void mousePressed(MouseEvent e) {
        grabFocus(e);
    }

    public void mouseReleased(MouseEvent e) {
        grabFocus(e);
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    ///////////////////////////////
    // Key Listeners Method      //
    ///////////////////////////////
  public void keyPressed(KeyEvent e) {
        KeyInputMap.processKeyChar(workspace, e);
    }

    public void keyReleased(KeyEvent e) {
    }

    public void keyTyped(KeyEvent e) {
    }

    ///////////////////////////////
    // WORKSPACE LISTENER METHOD //
    ///////////////////////////////
    /**
     * Subscription: BLOCK_ADDED events.
     * Action: add this.mouselistener to the block referanced by event
     * @requires block reference in event is not null
     * @modifies this.blockFocusOwner && event.block
     * @effects Add this.mouselistener to this.blockFocusOwner
     *       removes focus from this.blockFocusOwner
     *       adds focus to e.getSource iff e.getSource
     *       is instance of BlockCanvas and RenderableBlock
     */
    public void workspaceEventOccurred(WorkspaceEvent event) {
        switch (event.getEventType()) {
            case WorkspaceEvent.BLOCK_ADDED:
                //System.out.println("FocusManager: Block_Added Event at of "+event.getSourceBlockID()+" on "+event.getSourceWidget());
                //only add focus manager as listener to blocks added to pages
                if (!(event.getSourceWidget() instanceof Page)) {
                    break;
                }
                RenderableBlock rb = workspace.getEnv().getRenderableBlock(event.getSourceBlockID());
                if (rb == null) {
                    break;
                }

                //only add once
                for (MouseListener l : rb.getMouseListeners()) {
                    if (l.equals(this)) {
                        return;
                        //TODO: this shouldn't return, it should break
                        //but you can't double break in java
                    }
                }
                rb.addMouseListener(this);
                rb.addKeyListener(this);
                setFocus(event.getSourceBlockID());
                rb.grabFocus();
                break;
        }
    }

  public String toString() {
        return "FocusManager: " + blockFocusPoint + " of " + workspace.getEnv().getBlock(focusBlock);
    }
}
TOP

Related Classes of edu.mit.blocks.workspace.typeblocking.FocusTraversalManager

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.