
org.nakedobjects.plugins.dnd.viewer.InteractionHandler Maven / Gradle / Ivy
The newest version!
package org.nakedobjects.plugins.dnd.viewer;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import org.apache.log4j.Logger;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.plugins.dnd.Click;
import org.nakedobjects.plugins.dnd.ContentDrag;
import org.nakedobjects.plugins.dnd.Drag;
import org.nakedobjects.plugins.dnd.DragStart;
import org.nakedobjects.plugins.dnd.InteractionSpy;
import org.nakedobjects.plugins.dnd.NullContent;
import org.nakedobjects.plugins.dnd.View;
import org.nakedobjects.plugins.dnd.ViewAreaType;
import org.nakedobjects.plugins.dnd.viewer.drawing.Location;
import org.nakedobjects.plugins.dnd.viewer.view.simple.AbstractView;
public class InteractionHandler implements MouseMotionListener, MouseListener, KeyListener {
private static final Logger LOG = Logger.getLogger(InteractionHandler.class);
private final static int THRESHOLD = 7;
private boolean canDrag;
/*
* The location within the frame where the mouse button was pressed down.
*/
private Location downAt;
private Drag drag;
private final KeyboardManager keyboardManager;
private View identifiedView;
private final InteractionSpy spy;
private final XViewer viewer;
private KeyEvent lastTyped;
private View draggedView;
private final XFeedbackManager feedbackManager;
public InteractionHandler(
final XViewer viewer,
final XFeedbackManager feedbackManager,
final KeyboardManager keyboardManager,
final InteractionSpy spy) {
this.viewer = viewer;
this.feedbackManager = feedbackManager;
this.spy = spy;
this.keyboardManager = keyboardManager;
}
private void drag(final MouseEvent me) {
final Location location = createLocation(me.getPoint());
spy.addAction("Mouse dragged " + location);
final View target = viewer.identifyView(new Location(location), false);
drag.drag(target, location, me.getModifiers());
}
private Location createLocation(final Point point) {
return new Location(point.x, point.y);
}
private void dragStart(final MouseEvent me) {
if (!isOverThreshold(downAt, me.getPoint())) {
return;
}
spy.addAction("Drag start at " + downAt);
drag = viewer.dragStart(new DragStart(downAt, me.getModifiers()));
if (drag == null) {
spy.addAction("drag start ignored");
canDrag = false;
} else {
spy.addAction("drag start " + drag);
final View overlay = drag.getOverlay();
if (overlay != null) {
viewer.setOverlayView(overlay);
}
final View target = viewer.identifyView(createLocation(me.getPoint()), false);
drag.drag(target, createLocation(me.getPoint()), me.getModifiers());
}
identifiedView = null;
}
/**
* Returns true when the point is outside the area around the downAt location
*/
private boolean isOverThreshold(final Location pressed, final Point dragged) {
final int xDown = pressed.getX();
final int yDown = pressed.getY();
final int x = dragged.x;
final int y = dragged.y;
return x > xDown + THRESHOLD || x < xDown - THRESHOLD || y > yDown + THRESHOLD || y < yDown - THRESHOLD;
}
/**
* Listener for key presses. Cancels popup and drags, and forwards key presses to the view that has the
* keyboard focus.
*
* @see java.awt.event.KeyListener#keyPressed(KeyEvent)
*/
public void keyPressed(final KeyEvent ke) {
if (isBusy(identifiedView)) {
return;
}
lastTyped = null;
try {
if (ke.getKeyCode() == KeyEvent.VK_ESCAPE && drag != null) {
if (drag != null) {
drag.cancel(viewer);
drag = null;
}
viewer.clearAction();
} else if (ke.getKeyCode() == KeyEvent.VK_F5) {
draggedView = identifiedView;
} else if (draggedView != null && ke.getKeyCode() == KeyEvent.VK_F6) {
final ContentDrag content = new ContentDrag(draggedView, new Location(), new AbstractView(new NullContent()) {});
if (identifiedView != null) {
identifiedView.drop(content);
}
draggedView = null;
} else {
keyboardManager.pressed(ke.getKeyCode(), ke.getModifiers());
}
// ke.consume();
redraw();
} catch (final Exception e) {
interactionException("keyPressed", e);
}
}
/**
* Listener for key releases and forward them to the view that has the keyboard focus.
*
* @see java.awt.event.KeyListener#keyReleased(KeyEvent)
*/
public void keyReleased(final KeyEvent ke) {
if (isBusy(identifiedView)) {
return;
}
// LOG.debug("key " + KeyEvent.getKeyText(ke.getKeyCode()) + " released\n");
try {
if (lastTyped == null && ke.getKeyCode() != KeyEvent.VK_SHIFT && ke.getKeyCode() != KeyEvent.VK_ALT
&& ke.getKeyCode() != KeyEvent.VK_CONTROL) {
if (ke.getKeyCode() >= KeyEvent.VK_0 && ke.getKeyCode() <= KeyEvent.VK_DIVIDE) {
LOG.error("no type event for '" + KeyEvent.getKeyText(ke.getKeyCode()) + "': " + ke);
}
}
keyboardManager.released(ke.getKeyCode(), ke.getModifiers());
ke.consume();
redraw();
} catch (final Exception e) {
interactionException("keyReleased", e);
}
}
/**
* Listener for key press, and subsequent release, and forward it as one event to the view that has the
* keyboard focus.
*
* @see java.awt.event.KeyListener#keyTyped(KeyEvent)
*/
public void keyTyped(final KeyEvent ke) {
if (isBusy(identifiedView)) {
return;
}
final char keyChar = ke.getKeyChar();
if (!Character.isISOControl(keyChar)) {
// ignoring control keys and the delete key
// LOG.debug("typed '" + keyChar + "': " + ke);
// LOG.debug("typed " + (int) keyChar);
keyboardManager.typed(keyChar);
ke.consume();
lastTyped = ke;
redraw();
}
}
private void interactionException(final String action, final Exception e) {
LOG.error("error during user interaction: " + action, e);
feedbackManager.showException(e);
}
/**
* Responds to mouse click events by calling firstClick
, secondClick
, and
* thirdClick
on the view that the mouse is over. Ignored if the mouse is not over a view.
*
* @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
*/
public void mouseClicked(final MouseEvent me) {
if (isBusy(identifiedView)) {
return;
}
try {
final Click click = new Click(identifiedView, downAt, me.getModifiers());
spy.addAction("Mouse clicked " + click.getLocation());
if (click.button3() && identifiedView != null) {
// ignore popup trigger - dealt with by mousePressed or mouseReleased (depending on platform)
} else if (viewer.isOverlayAvailable()) {
overlayClick(click);
// } else if (click.button3() && identifiedView != null) {
// fireMenuPopup(click);
} else {
fireClick(click, me.getClickCount());
}
redraw();
} catch (final Exception e) {
interactionException("mouseClicked", e);
}
}
private void overlayClick(final Click click) {
final View overlayView = viewer.getOverlayView();
if (overlayView == identifiedView
|| (identifiedView != null && identifiedView.getParent() != null && overlayView == identifiedView.getParent())) {
viewer.firstClick(click);
} else {
viewer.clearAction();
}
}
private void fireMenuPopup(final Click click) {
if (identifiedView != null) {
spy.addAction(" popup " + downAt + " over " + identifiedView);
boolean forView = viewer.viewAreaType(new Location(click.getLocation())) == ViewAreaType.VIEW;
forView = click.isAlt() ^ forView;
final boolean includeExploration = click.isCtrl();
final boolean includeDebug = click.isShift();
final Location at = click.getLocation();
at.move(-14, -10);
viewer.popupMenu(identifiedView, at, forView, includeExploration, includeDebug);
}
}
private void fireClick(final Click click, final int clickCount) {
viewer.setKeyboardFocus(identifiedView);
switch (clickCount) {
case 1:
viewer.firstClick(click);
break;
case 2:
viewer.secondClick(click);
break;
case 3:
viewer.thirdClick(click);
break;
default:
break;
}
}
/**
* Responds to mouse dragged according to the button used. If the left button then identified view is
* moved.
*
* @see java.awt.event.MouseMotionListener#mouseDragged(MouseEvent)
*/
public void mouseDragged(final MouseEvent me) {
if (isBusy(identifiedView)) {
return;
}
try {
viewer.translate(me);
final Location location = createLocation(me.getPoint());
spy.setLocationInViewer(location);
if (canDrag) {
// checked to ensure that dragging over a view doesn't start a
// drag - it should only start when already over a view.
spy.reset();
// viewer.translate(me);
if (drag == null) {
// no drag in progress yet
dragStart(me);
redraw();
} else {
drag(me);
redraw();
}
}
} catch (final Exception e) {
interactionException("mouseDragged", e);
}
}
/**
* event ignored
*
* @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
*/
public void mouseEntered(final MouseEvent arg0) {}
/**
* event ignored
*
* @see java.awt.event.MouseListener#mouseExited(MouseEvent)
*/
public void mouseExited(final MouseEvent arg0) {}
/**
* responds to mouse moved event by setting the view found underneath the mouse as the idetified view.
* Views normally respond by changing the colour of themselves so they are visual distinct and hence shows
* itself as special compared to the rest.
*
* @see java.awt.event.MouseMotionListener#mouseMoved(MouseEvent)
*/
public void mouseMoved(final MouseEvent me) {
try {
if (drag == null) {
spy.reset();
viewer.translate(me);
final Location location = createLocation(me.getPoint());
spy.setLocationInViewer(location);
final View overView = viewer.identifyView(new Location(location), true);
spy.setOver(overView);
spy.addAction("moved " + location);
if (overView != null) {
if (overView != identifiedView) {
if (identifiedView != null) {
spy.addAction("exited " + identifiedView);
identifiedView.exited();
}
if (overView != null) {
spy.addAction("entered " + overView);
overView.entered();
}
redraw();
feedbackManager.showBusyState(overView);
}
identifiedView = overView;
spy.addTrace("--> mouse moved");
viewer.mouseMoved(location);
spy.addTrace(overView, " mouse location", location);
if ((me.getModifiers() & InputEvent.ALT_MASK) > 0 && overView.getContent() != null) {
final NakedObject object = overView.getContent().getNaked();
final ViewAreaType area = overView.viewAreaType(location);
feedbackManager.setViewDetail("Over " + location + " [" + area + "] " + object);
}
redraw();
}
}
} catch (final Exception e) {
interactionException("mouseMoved", e);
}
}
private boolean isBusy(final View view) {
return feedbackManager != null && feedbackManager.isBusy(view);
}
/**
* Responds to the mouse pressed event (with the left button pressed) by initiating a drag. This sets up
* the View
's dragging state to the view that the mouse was over when the button was
* pressed.
*
* @see java.awt.event.MouseListener#mousePressed(MouseEvent)
*/
public void mousePressed(final MouseEvent me) {
try {
if (isBusy(identifiedView)) {
return;
}
spy.reset();
viewer.translate(me);
downAt = createLocation(me.getPoint());
spy.setDownAt(downAt);
final Location location = createLocation(me.getPoint());
spy.setLocationInViewer(location);
final View overView = viewer.identifyView(new Location(location), true);
spy.setOver(overView);
spy.addAction("Mouse pressed " + location);
drag = null;
final Click click = new Click(null, downAt, me.getModifiers());
if (me.isPopupTrigger()) {
if (overView != null) {
fireMenuPopup(click);
}
} else {
viewer.mouseDown(click);
// drag should not be valid after double/triple click
canDrag = overView != null && me.getClickCount() == 1;
identifiedView = overView;
}
redraw();
} catch (final Exception e) {
interactionException("mousePressed", e);
}
}
/**
* Responds to the mouse released event (with the left button pressed) by telling the identified view (the
* drop zone) that the dragged object is being dropped on it (via the views drop
method).
* If the drop takes place outside of all of the other views then the workspaceDrop
method
* is called instead to indicate a drop onto the workspace.
*
* @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
*/
public void mouseReleased(final MouseEvent me) {
if (isBusy(identifiedView) || downAt == null) {
return;
}
try {
if (drag != null) {
mouseDragged(me);
final Location location = createLocation(me.getPoint());
final View target = viewer.identifyView(new Location(location), false);
drag.drag(target, location, me.getModifiers());
// viewer.clearStatus();
drag.end(viewer);
redraw();
drag = null;
}
final Click click = new Click(identifiedView, downAt, me.getModifiers());
if (me.isPopupTrigger()) {
if (identifiedView != null) {
fireMenuPopup(click);
}
} else {
viewer.mouseUp(click);
}
redraw();
} catch (final Exception e) {
interactionException("mouseReleased", e);
}
}
private void redraw() {
viewer.scheduleRepaint();
}
}
// Copyright (c) Naked Objects Group Ltd.
© 2015 - 2025 Weber Informatics LLC | Privacy Policy