I am trying to disable movement of the globe on mouse click in World Wind. I expected to be able to do:
void disableGlobeDrag(WorldWindowGLCanvas ww) {
ww.addMouseMotionListener(new MyMouseMotionListener());
}
where MyMouseMotionListener
consumes all of the mouse events. This is not working so instead I have to do:
void disableGlobeDrag(WorldWindowGLCanvas ww) {
for(MouseMotionListener l : ww.getMouseMotionListeners()) {
if(l.getClass().toString().equals("class gov.nasa.worldwind.awt.AWTInputHandler")) {
ww.removeMouseMotionListener(l);
}
}
}
Is it expected that consumed mouse events should still reach the gov.nasa.worldwind.awt.AWTInputHandler
listener?
Update: WorldWindowGLCanvas
is just calling addMouseMotionListener()
on java.awt.Component
so apparently I don't understand how consuming events works.
Update 2: despite sharing interfaces with Swing, calling WorldWindowGLCanvas.removeMouseMotionListener()
with AWTInputHandler
as the argument will prevent all other MouseMotionListener
s from receiving events. The add and remove methods on AWTInputHandler
should be used instead.
Unfortunately removing the MouseMotionListener
as @trashgod suggested does not work since there is some World Wind specific behavior happening: removing gov.nasa.worldwind.awt.AWTInputHandler
causes other MouseMotionListener
s to stop receiving event notifications.
To disable globe dragging and still receive events in another MouseMotionListener
the following steps were necessary:
Get a reference to World Wind's AWTInputHandler
:
AWTInputHandler wwHandler = null;
// get World Wind's AWTInputHandler class:
for (MouseMotionListener l : ww.getMouseMotionListeners()) {
if(l instanceof AWTInputHandler) {
wwHandler = (AWTInputHandler)l;
break;
}
}
Create a MouseMotionListener
which consumes events:
public class MyMouseMotionListener implements MouseMotionListener {
@Override
public void mouseDragged(MouseEvent e) {
// consume the event so the globe position does not change
e.consume();
if (e.getSource() instanceof WorldWindowGLCanvas) {
// get the position of the mouse
final WorldWindowGLCanvas canvas = ((WorldWindowGLCanvas) e.getSource());
final Position p = canvas.getCurrentPosition();
// do something with the position here
}
}
@Override
public void mouseMoved(MouseEvent e) {
e.consume();
}
}
Add the mouse motion listener to the AWTInputHandler
:
if(wwHandler != null) {
wwHandler.addMouseMotionListener(new MyMouseMotionListener());
} else {
// I don't think this should happen unless the AWTInputHandler
// is explicitly removed by client code
logger.error("Couldn't find AWTInputHandler");
}
That said, I have no idea why WorldWindowGLCanvas
is using Component.addMouseMotionListener()
rather than AWTInputHandler.addMouseMotionListener()
.
Why it's not working:
As discussed here, many event sources maintain an EventListenerList
. The prescribed scheme allows an arbitrary number of listeners to be added or removed. This related example lists all instances of DocumentListener
registered to text component's Document
. No one listener preempts another.
What you might do:
Given an instance of a WorldWindowGLCanvas
, you might look at the array returned by getMouseMotionListeners()
and invoke removeMouseMotionListener()
as warranted.
After struggling with a way to do this and stumbling across this solution, I believe I've come up with the "correct" solution. Removing the mouse motion listener completely does technically work, but it breaks other functionality that might be useful (KML tree node selecton, on screen view controls).
Create a subclass an input handler to remove the "move to" functionality
public class MyOrbitViewInputHandler extends OrbitViewInputHandler
{
public MyOrbitViewInputHandler()
{
// Disable single click to pan functionality
ViewInputAttributes.ActionAttributes actionAttrs =
this.getAttributes().getActionMap(ViewInputAttributes.DEVICE_MOUSE).getActionAttributes(ViewInputAttributes.VIEW_MOVE_TO);
actionAttrs.setMouseActionListener(null);
}
}
Specify your new input handler in your worldwind.xml configuration file
<Property name="gov.nasa.worldwind.avkey.ViewInputHandlerClassName"
value="mil.dtra.nucs.coe.ui.map.MyOrbitViewInputHandler"/>
Using this method, all other mouse interactions that take place on the canvas will still work correctly, but the "single click to pan" functionality is removed.
If you're curious about what other behaviors are specified that you could potentially override, you can look at gov.nasa.worldwind.awt.BasicViewInputHandler