All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.gov.nasa.worldwind.render.airspaces.editor.AirspaceEditorController Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show newest version
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.render.airspaces.editor;

import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.pick.PickedObjectList;
import gov.nasa.worldwind.render.airspaces.Airspace;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

/**
 * @author dcollins
 * @version $Id: AirspaceEditorController.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class AirspaceEditorController implements KeyListener, MouseListener, MouseMotionListener
{
    private boolean active;
    private String activeAction;
    private AirspaceEditor editor; // Can be null
    private WorldWindow wwd; // Can be null
    // Current selection and device state.
    private Point mousePoint;
    private Airspace activeAirspace;
    private AirspaceControlPoint activeControlPoint;
    // Action/Cursor pairings.
    private Map actionCursorMap = new HashMap();

    protected static final String MOVE_AIRSPACE_LATERALLY = "AirspaceEdiorController.MoveAirspaceLaterally";
    protected static final String MOVE_AIRSPACE_VERTICALLY = "AirspaceEdiorController.MoveAirspaceVertically";
    protected static final String RESIZE_AIRSPACE = "AirspaceEdiorController.ResizeAirspace";
    protected static final String ADD_CONTROL_POINT = "AirspaceEdiorController.AddControlPoint";
    protected static final String REMOVE_CONTROL_POINT = "AirspaceEdiorController.RemoveControlPoint";
    protected static final String MOVE_CONTROL_POINT = "AirspaceEdiorController.MoveControlPoint";

    // TODO
    // enable/disable individual editor actions
    // 1. add control point
    // 2. remove control point
    // 3. move control point
    // 4. resize
    // 5. move airspace

    // TODO: allow the editor to define the action/behavior associated with a control point, so the correct cursor
    // will be displayed (or some future UI affordance). Currently the controller assumes that a control point implies
    // a move action. This really only affects the cursor display, since the editor ultimately decides what to do when
    // a control point is moved.

    public AirspaceEditorController(WorldWindow wwd)
    {
        this.active = false;
        this.setWorldWindow(wwd);
        this.setupActionCursorMap();
    }

    public AirspaceEditorController()
    {
        this(null);
    }

    public boolean isActive()
    {
        return this.active;
    }

    protected void setActive(boolean active)
    {
        this.active = active;
    }

    public String getActiveAction()
    {
        return activeAction;
    }

    protected void setActiveAction(String action)
    {
        this.activeAction = action;
    }

    public AirspaceEditor getEditor()
    {
        return this.editor;
    }

    public void setEditor(AirspaceEditor editor)
    {
        this.editor = editor;
    }

    public WorldWindow getWorldWindow()
    {
        return this.wwd;
    }

    public void setWorldWindow(WorldWindow wwd)
    {
        if (this.wwd == wwd)
            return;

        if (this.wwd != null)
        {
            this.wwd.getInputHandler().removeKeyListener(this);
            this.wwd.getInputHandler().removeMouseListener(this);
            this.wwd.getInputHandler().removeMouseMotionListener(this);
        }

        this.wwd = wwd;

        if (this.wwd != null)
        {
            this.wwd.getInputHandler().addKeyListener(this);
            this.wwd.getInputHandler().addMouseListener(this);
            this.wwd.getInputHandler().addMouseMotionListener(this);
        }
    }

    protected Point getMousePoint()
    {
        return this.mousePoint;
    }

    protected void setMousePoint(Point point)
    {
        this.mousePoint = point;
    }

    protected AirspaceControlPoint getActiveControlPoint()
    {
        return this.activeControlPoint;
    }

    protected void setActiveControlPoint(AirspaceControlPoint controlPoint)
    {
        this.activeControlPoint = controlPoint;
    }

    protected Airspace getActiveAirspace()
    {
        return activeAirspace;
    }

    protected void setActiveAirspace(Airspace airspace)
    {
        this.activeAirspace = airspace;
    }

    protected Airspace getTopOwnedAirspaceAtCurrentPosition()
    {
        // Without an editor, we cannot know if the airspace belongs to us.
        if (this.getEditor() == null)
            return null;

        Object obj = this.getTopPickedObject();
        // Airspace is compared by reference, because we're only concerned about the exact reference
        // an editor refers to, rather than an equivalent object.
        if (this.getEditor().getAirspace() != obj)
            return null;

        return (Airspace) obj;
    }

    protected AirspaceControlPoint getTopOwnedControlPointAtCurrentPosition()
    {
        // Without an editor, we cannot know if the airspace belongs to us.
        if (this.getEditor() == null)
            return null;

        Object obj = this.getTopPickedObject();
        if (!(obj instanceof AirspaceControlPoint))
            return null;

        // AirspaceEditor is compared by reference, because we're only concerned about the exact reference
        // a control point refers to, rather than an equivalent object.
        if (this.getEditor() != (((AirspaceControlPoint) obj).getEditor()))
            return null;

        return (AirspaceControlPoint) obj;
    }

    //protected AirspaceControlPoint getFirstOwnedControlPointAtCurrentPosition()
    //{
    //    // Without an editor, we cannot know if the control point belongs to us.
    //    if (this.getEditor() == null)
    //        return null;
    //
    //    PickedObjectList pickedObjects = this.getWorldWindow().getObjectsAtCurrentPosition();
    //    if (pickedObjects == null)
    //        return null;
    //
    //    AirspaceControlPoint controlPoint = null;
    //
    //    for (int i = 0; i < pickedObjects.size() && controlPoint == null; i++)
    //    {
    //        PickedObject po = pickedObjects.get(i);
    //        if (!po.isTerrain() && po.getObject() instanceof AirspaceControlPoint)
    //        {
    //            AirspaceControlPoint pickedPoint = (AirspaceControlPoint) po.getObject();
    //            // Editor is compared by reference, because we're only concerned about the exact reference
    //            // a control point refers to, rather than an equivalent object.
    //            if (this.getEditor() == pickedPoint.getEditor())
    //            {
    //                controlPoint = pickedPoint;
    //            }
    //        }
    //    }
    //
    //    return controlPoint;
    //}
    
    protected Object getTopPickedObject()
    {
        if (this.getWorldWindow() == null)
            return null;

        PickedObjectList pickedObjects = this.getWorldWindow().getObjectsAtCurrentPosition();
        if (pickedObjects == null || pickedObjects.getTopPickedObject() == null
            || pickedObjects.getTopPickedObject().isTerrain())
        {
            return null;
        }

        return pickedObjects.getTopPickedObject().getObject();
    }

    protected Map getActionCursorMap()
    {
        return this.actionCursorMap;
    }

    //**************************************************************//
    //********************  Key Events  ****************************//
    //**************************************************************//

    public void keyTyped(KeyEvent e)
    {
    }

    public void keyPressed(KeyEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            //noinspection UnnecessaryReturnStatement
            return;
        }
    }

    public void keyReleased(KeyEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.updateCursor(e);
        
        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            //noinspection UnnecessaryReturnStatement
            return;
        }
    }

    //**************************************************************//
    //********************  Mouse Events  **************************//
    //**************************************************************//

    public void mouseClicked(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            return;
        }

        AirspaceControlPoint topControlPoint = this.getTopOwnedControlPointAtCurrentPosition();

        if (e.getButton() == MouseEvent.BUTTON1)
        {
            if (e.isControlDown())
            {
                if (topControlPoint != null)
                {
                    this.handleControlPointRemoved(topControlPoint, e);
                }
                e.consume();
            }
            //else if (e.isAltDown())
            //{
            //    // Actual logic is handled in mousePressed, but we consume the event here to keep the any other
            //    // system from receiving it.
            //    e.consume();
            //}
        }
    }

    public void mousePressed(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.setMousePoint(new Point(e.getPoint())); // copy to insulate us from changes by the caller
        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            return;
        }

        Airspace topAirspace = this.getTopOwnedAirspaceAtCurrentPosition();        
        AirspaceControlPoint topControlPoint = this.getTopOwnedControlPointAtCurrentPosition();

        if (e.getButton() == MouseEvent.BUTTON1)
        {
            if (e.isControlDown())
            {
                // Actual logic is handled in mouseClicked, but we consume the event here to keep the any other
                // system from receiving it.
                this.setActive(true);
                this.setActiveAction(REMOVE_CONTROL_POINT);
                e.consume();
            }
            else if (e.isAltDown())
            {
                this.setActive(true);
                this.setActiveAction(ADD_CONTROL_POINT);
                if (topControlPoint == null)
                {
                    AirspaceControlPoint p = this.handleControlPointAdded(this.getEditor().getAirspace(), e);
                    if (p != null)
                    {
                        this.setActiveControlPoint(p);
                    }
                }                
                e.consume();
            }
            else
            {
                if (topControlPoint != null)
                {
                    this.setActive(true);
                    this.setActiveAction(null); // Don't know what action we'll perform until mouseDragged().
                    this.setActiveControlPoint(topControlPoint);
                    e.consume();
                }
                else if (topAirspace != null)
                {
                    this.setActive(true);
                    this.setActiveAction(null); // Don't know what action we'll perform until mouseDragged().
                    this.setActiveAirspace(topAirspace);
                    e.consume();
                }
            }
        }
    }

    public void mouseReleased(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.setMousePoint(new Point(e.getPoint())); // copy to insulate us from changes by the caller
        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            return;
        }

        if (e.getButton() == MouseEvent.BUTTON1)
        {
            if (this.isActive())
            {
                this.setActive(false);
                this.setActiveAction(null);
                this.setActiveAirspace(null);
                this.setActiveControlPoint(null);
                e.consume();
            }
        }
    }

    public void mouseEntered(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            //noinspection UnnecessaryReturnStatement
            return;
        }
    }

    public void mouseExited(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            //noinspection UnnecessaryReturnStatement
            return;
        }
    }

    protected AirspaceControlPoint handleControlPointAdded(Airspace airspace, MouseEvent mouseEvent)
    {
        AirspaceControlPoint controlPoint = this.getEditor().addControlPoint(this.getWorldWindow(), airspace,
            mouseEvent.getPoint());
        this.getWorldWindow().redraw();

        return controlPoint;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    protected void handleControlPointRemoved(AirspaceControlPoint controlPoint, MouseEvent mouseEvent)
    {
        this.getEditor().removeControlPoint(this.getWorldWindow(), controlPoint);
    }

    //**************************************************************//
    //********************  Mouse Motion Events  *******************//
    //**************************************************************//

    public void mouseDragged(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        Point lastMousePoint = this.getMousePoint();
        this.setMousePoint(new Point(e.getPoint())); // copy to insulate us from changes by the caller
        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            return;
        }
        
        if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0)
        {
            if (this.isActive())
            {
                if (this.getActiveControlPoint() != null)
                {
                    this.handleControlPointDragged(this.getActiveControlPoint(), e, lastMousePoint);
                }
                else if (this.getActiveAirspace() != null)
                {
                    this.handleAirspaceDragged(this.getActiveAirspace(), e, lastMousePoint);
                }
                e.consume();
            }
        }
    }

    public void mouseMoved(MouseEvent e)
    {
        if (e == null)
        {
            return;
        }

        this.setMousePoint(new Point(e.getPoint())); // copy to insulate us from changes by the caller
        this.updateCursor(e);

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            //noinspection UnnecessaryReturnStatement
            return;
        }
    }

    protected void handleControlPointDragged(AirspaceControlPoint controlPoint, MouseEvent e, Point lastMousePoint)
    {
        if (e.isShiftDown())
        {
            this.setActiveAction(RESIZE_AIRSPACE);
            this.getEditor().resizeAtControlPoint(this.getWorldWindow(), controlPoint, e.getPoint(), lastMousePoint);
        }
        else
        {
            this.setActiveAction(MOVE_CONTROL_POINT);
            this.getEditor().moveControlPoint(this.getWorldWindow(), controlPoint, e.getPoint(), lastMousePoint);
        }
    }

    protected void handleAirspaceDragged(Airspace airspace, MouseEvent e, Point lastMousePoint)
    {
        if (e.isShiftDown())
        {
            this.setActiveAction(MOVE_AIRSPACE_VERTICALLY);
            this.getEditor().moveAirspaceVertically(this.getWorldWindow(), airspace, e.getPoint(), lastMousePoint);
        }
        else
        {
            this.setActiveAction(MOVE_AIRSPACE_LATERALLY);
            this.getEditor().moveAirspaceLaterally(this.getWorldWindow(), airspace, e.getPoint(), lastMousePoint);
        }
    }

    //**************************************************************//
    //********************  Action/Cursor Pairing  *****************//
    //**************************************************************//

    protected void setupActionCursorMap()
    {
        // TODO: find more suitable cursors for the remove control point action, and the move vertically action.
        this.getActionCursorMap().put(MOVE_AIRSPACE_LATERALLY, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        this.getActionCursorMap().put(MOVE_AIRSPACE_VERTICALLY, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
        this.getActionCursorMap().put(RESIZE_AIRSPACE, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
        this.getActionCursorMap().put(ADD_CONTROL_POINT, Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        this.getActionCursorMap().put(REMOVE_CONTROL_POINT, Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        this.getActionCursorMap().put(MOVE_CONTROL_POINT, Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    }

    protected void updateCursor(InputEvent e)
    {
        // Include this test to ensure any derived implementation performs it.
        if (e == null || e.getComponent() == null)
        {
            return;
        }

        Cursor cursor = this.getCursorFor(e);
        e.getComponent().setCursor(cursor);
        e.getComponent().repaint();
    }

    protected Cursor getCursorFor(InputEvent e)
    {
        // If we're actively engaged in some action, then return the cursor associated with that action. Otherwise
        // return the cursor representing the action that would be invoked (if the user pressed the mouse) given the
        // current modifiers and pick list.

        if (e == null)
        {
            return null;
        }

        // Include this test to ensure any derived implementation performs it.
        if (this.getEditor() == null || !this.getEditor().isArmed())
        {
            return null;
        }

        String action = this.isActive() ? this.getActiveAction() : this.getPotentialActionFor(e);
        return this.getActionCursorMap().get(action);
    }

    protected String getPotentialActionFor(InputEvent e)
    {
        Airspace topAirspace = this.getTopOwnedAirspaceAtCurrentPosition();
        AirspaceControlPoint topControlPoint = this.getTopOwnedControlPointAtCurrentPosition();

        if (e.isAltDown())
        {
            if (topControlPoint == null)
            {
                return ADD_CONTROL_POINT;
            }
        }
        else if (e.isControlDown())
        {
            if (topControlPoint != null)
            {
                return REMOVE_CONTROL_POINT;
            }
        }
        else if (e.isShiftDown())
        {
            if (topControlPoint != null)
            {
                return RESIZE_AIRSPACE;
            }
            else if (topAirspace != null)
            {
                return MOVE_AIRSPACE_VERTICALLY;
            }
        }
        else
        {
            if (topControlPoint != null)
            {
                return MOVE_CONTROL_POINT;
            }
            else if (topAirspace != null)
            {
                return MOVE_AIRSPACE_LATERALLY;
            }
        }

        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy