package interactors; import java.awt.event.*; import java.util.Vector; import java.awt.*; import javax.swing.*; /** * The EventHandler class is responsible for receiving events from a * JPanel and distributing the events to the appropriate interactor. * It distributes events as follows: * * 1. If there is an interactor that is current operating, then * that interactor receives the current event * 2. If an interactor's start event matches the current event and the * interactor operates on an object that contains the mouse, then * that interactor is started and made to operate on the selected object. * * An interactor ceases to operate when either its stop event is encountered * or the programmer changes its state to STOP. * */ public class EventHandler implements MouseListener, MouseMotionListener { // The set of interactors associated with this event handler Vector registeredInteractors = new Vector(); // the interactor that is currently active and receiving events Interactor activeInteractor = null; // In order to receive all mouse events, the event handler must register // itself as both a mouse and mousemotion listener with the appropriate // JPanel public EventHandler(JPanel panel) { panel.addMouseListener(this); panel.addMouseMotionListener(this); } // methods for registering and de-registering interactors with the // event handler public void addInteractor(Interactor obj) { registeredInteractors.add(obj); } public void removeInteractor(Interactor obj) { registeredInteractors.remove(obj); } // a sample event matching procedure that compares the event id of the // start event and the received event, such as MOUSE_PRESSED, MOUSE_CLICKED, // etc. A real event matching procedure would need to consider which // mouse button was selected as well as keyboard modifiers, such as // CTRL and SHIFT boolean eventMatch(int event, MouseEvent receivedEvent) { return (event == receivedEvent.getID()); } // handleEvent distributes events to interactors based on the algorithm // described in the header to this file. To avoid having to write // the same handleEvent code for each type of mouse event (e.g., // MousePressed, MouseClicked, MouseMoved, etc), handleEvent uses // a variation of the Template Design Pattern. At the point where it // determines which interactor should handle the event, it uses a // command object passed to it by the original mouse listener methods // (i.e., mousePressed, mouseClicked) to ensure that the same method // gets called in the interactor void handleEvent(MouseEvent e, MouseCmdObject cmdObject) { // if an interactor is already running, pass it the event if (activeInteractor != null) cmdObject.eventHandler(e, activeInteractor); else { // otherwise try to find an interactor to handle this event for (Interactor inter : registeredInteractors) { // if the event matches the interactors start event and // the event occurs over an object registered with the // interactor, then call the appropriate event handler // in the interactor if (eventMatch(inter.getStartEvent(), e)) { if (inter.findObject(e) != null) { inter.setState(Interactor.RUNNING); cmdObject.eventHandler(e, inter); activeInteractor = inter; break; } } } } // de-activate the interactor when either its stop event is // received or the programmer sets its state to STOP if ((activeInteractor != null) && ((eventMatch(activeInteractor.getStopEvent(), e)) || (activeInteractor.getState() == Interactor.STOP))) { activeInteractor.setState(Interactor.START); activeInteractor = null; } } // The following methods intercept all mouse events from the JPanel // and sent them to the handleEvent method for distribution to the // appropriate interactor. Each method passes an appropriate command // object to the event handler, so that the appropriate mouse event // handler will be called in the interactor. public void mousePressed(MouseEvent e) { handleEvent(e, MousePressedCmdObject.getMousePressedCmdObject()); } public void mouseReleased(MouseEvent e) { handleEvent(e, MouseReleasedCmdObject.getMouseReleasedCmdObject()); } public void mouseClicked(MouseEvent e) { handleEvent(e, MouseClickedCmdObject.getMouseClickedCmdObject()); } // ignore mouseEntered and mouseExited events. They can require a // great deal of special purpose code to ensure that the appropriate // object is notified when either the mouse enters it or leaves it public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseMoved(MouseEvent e) { handleEvent(e, MouseMovedCmdObject.getMouseMovedCmdObject()); } public void mouseDragged(MouseEvent e) { handleEvent(e, MouseDraggedCmdObject.getMouseDraggedCmdObject()); } } // The command object interface. There is a command object for each of // the mouse handling events (e.g., MousePressed, MouseClicked, MouseMoved) // that takes an interactor and an event as parameters, and calls the // appropriate event handlng method for that interactor (e.g., mousePressed, // mouseClicked, mouseMoved, etc.). // // The command objects use the singleton pattern to ensure that only one // command object is ever allocated for each event type. It would be extremely // wasteful to generate a new command object each time an event occurs. interface MouseCmdObject { public void eventHandler(MouseEvent e, Interactor inter); } class MousePressedCmdObject implements MouseCmdObject { static MouseCmdObject cmdObject; static { cmdObject = new MousePressedCmdObject(); } static public MouseCmdObject getMousePressedCmdObject() { return cmdObject; } public void eventHandler(MouseEvent e, Interactor inter) { inter.mousePressed(e); } } class MouseReleasedCmdObject implements MouseCmdObject { static MouseCmdObject cmdObject; static { cmdObject = new MouseReleasedCmdObject(); } static public MouseCmdObject getMouseReleasedCmdObject() { return cmdObject; } public void eventHandler(MouseEvent e, Interactor inter) { inter.mouseReleased(e); } } class MouseClickedCmdObject implements MouseCmdObject { static MouseCmdObject cmdObject; static { cmdObject = new MouseClickedCmdObject(); } static public MouseCmdObject getMouseClickedCmdObject() { return cmdObject; } public void eventHandler(MouseEvent e, Interactor inter) { inter.mouseClicked(e); } } class MouseMovedCmdObject implements MouseCmdObject { static MouseCmdObject cmdObject; static { cmdObject = new MouseMovedCmdObject(); } static public MouseCmdObject getMouseMovedCmdObject() { return cmdObject; } public void eventHandler(MouseEvent e, Interactor inter) { inter.mouseMoved(e); } } class MouseDraggedCmdObject implements MouseCmdObject { static MouseCmdObject cmdObject; static { cmdObject = new MouseDraggedCmdObject(); } static public MouseCmdObject getMouseDraggedCmdObject() { return cmdObject; } public void eventHandler(MouseEvent e, Interactor inter) { inter.mouseDragged(e); } }