Package com.bbn.openmap.layer.location

Source Code of com.bbn.openmap.layer.location.LocationLayer

// **********************************************************************
//
// <copyright>
//
//  BBN Technologies
//  10 Moulton Street
//  Cambridge, MA 02138
//  (617) 873-8000
//
//  Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/location/LocationLayer.java,v $
// $RCSfile: LocationLayer.java,v $
// $Revision: 1.6.2.2 $
// $Date: 2006/01/18 17:51:02 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.layer.location;

/*  Java Core  */
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

import com.bbn.openmap.I18n;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.Layer;
import com.bbn.openmap.MapBean;
import com.bbn.openmap.event.InfoDisplayEvent;
import com.bbn.openmap.event.LayerStatusEvent;
import com.bbn.openmap.event.MapMouseListener;
import com.bbn.openmap.event.ProjectionEvent;
import com.bbn.openmap.event.SelectMouseMode;
import com.bbn.openmap.gui.WindowSupport;
import com.bbn.openmap.layer.DeclutterMatrix;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PaletteHelper;
import com.bbn.openmap.util.PropUtils;
import com.bbn.openmap.util.SwingWorker;

/**
* The LocationLayer is a layer that displays graphics supplied by
* LocationHandlers. When the layer receives a new projection, it goes to each
* LocationHandler and asks it for additions to the layer's graphic list. The
* LocationHandlers maintain the graphics, and the layer maintains the overall
* list.
*
* The whole idea behind locations is that there are geographic places that are
* to be marked with a graphic, and/or a text label. The location handler
* handles the interface with the source and type of location to be displayed,
* and the LocationLayer deals with all the locations in a generic way. The
* LocationLayer is capable of using more than one LocationHandler.
* <P>
*
* As a side note, a Link is nothing more than a connection between Locations,
* and is an extension of the Location Class. They have a graphic representing
* the link, an optional label, and an extra set of location coordinates.
* <P>
*
* The layer responds to gestures with pop-up menus. Which menu appears depends
* if the gesture affects a graphic.
* <P>
*
* The properties for this layer are:
* <P>
*
* <pre>
*   ####################################
*   # Properties for LocationLayer
*   # Use the DeclutterMatrix to declutter the labels.
*   locationlayer.useDeclutter=false
*   # Which declutter matrix class to use.
*   locationlayer.declutterMatrix=com.bbn.openmap.layer.DeclutterMatrix
*   # Let the DeclutterMatrix have labels that run off the edge of the map.
*   locationlayer.allowPartials=true
*   # The list of location handler prefixes - each prefix should then
*   # be used to further define the location handler properties.
*   locationlayer.locationHandlers=handler1 handler2
*   # Then come the handler properties...
*   # At the least, each handler should have a .class property
*   handler1.class=&lt;handler classname&gt;
*   # plus any other properties handler1 needs - check the handler1 documentation.
*   ####################################
*  
* </pre>
*/
public class LocationLayer extends Layer implements MapMouseListener {

    /** The declutter matrix to use, if desired. */
    protected DeclutterMatrix declutterMatrix = null;
    /** Flag to use declutter matrix or not. */
    protected boolean useDeclutterMatrix = false;
    /**
     * Flag to let objects appear partially off the edges of the map, when
     * decluttering through the decluterr matrix.
     */
    protected boolean allowPartials = true;
    /** The graphic list of objects to draw. */
    protected Vector omGraphics;
    /** Handlers load the data, and manage it for the layer. */
    protected LocationHandler[] dataHandlers;
    /** Pretty names for the handlers, for GUIs and such. */
    protected String[] dataHandlerNames;

    // ///////////////////
    // Variables to manage the gesturing mechanisms

    /** Used for recentering commands off the pop-up menu. */
    protected MapBean map;
    /**
     * What pops up if someone clicks on the background. The handler is
     * responsible for suppling the pop-up menu when one of its objects is
     * selected.
     */
    protected LocationPopupMenu backgroundMenu;
    /** What pops up if someone clicks on a location. */
    protected LocationPopupMenu locMenu;

    static final public String recenter = "Re-center map";
    static final public String cancel = "Cancel";

    public static final String UseDeclutterMatrixProperty = "useDeclutter";
    public static final String DeclutterMatrixClassProperty = "declutterMatrix";
    public static final String AllowPartialsProperty = "allowPartials";
    public static final String LocationHandlerListProperty = "locationHandlers";

    /**
     * The swing worker that goes off in it's own thread to get graphics.
     */
    protected LocationWorker currentWorker;
    /**
     * Set when the projection has changed while a swing worker is gathering
     * graphics, and we want him to stop early.
     */
    protected boolean cancelled = false;

    /**
     * Since we can't have the main thread taking up the time to create images,
     * we use this worker thread to do it.
     */
    class LocationWorker extends SwingWorker {
        /** Constructor used to create a worker thread. */
        public LocationWorker() {
            super();
        }

        /**
         * Compute the value to be returned by the <code>get</code> method.
         */
        public Object construct() {
            if (Debug.debugging("location")) {
                Debug.output(getName() + "|LocationWorker.construct()");
            }
            fireStatusUpdate(LayerStatusEvent.START_WORKING);
            try {
                return prepare();
            } catch (OutOfMemoryError e) {
                String msg = getName()
                        + "|LocationLayer.LocationWorker.construct(): " + e;
                Debug.error(msg);
                e.printStackTrace();
                fireRequestMessage(new InfoDisplayEvent(this, msg));
                fireStatusUpdate(LayerStatusEvent.FINISH_WORKING);
                return null;
            }
        }

        /**
         * Called on the event dispatching thread (not on the worker thread)
         * after the <code>construct</code> method has returned.
         */
        public void finished() {
            workerComplete(this);
            fireStatusUpdate(LayerStatusEvent.FINISH_WORKING);
        }
    }

    /**
     * The default constructor for the Layer. All of the attributes are set to
     * their default values.
     */
    public LocationLayer() {}

    /**
     * The properties and prefix are managed and decoded here, for the standard
     * uses of the LocationLayer.
     *
     * @param prefix string prefix used in the properties file for this layer.
     * @param properties the properties set in the properties file.
     */
    public void setProperties(String prefix, Properties properties) {
        super.setProperties(prefix, properties);
        String realPrefix = "";

        if (prefix != null) {
            realPrefix = prefix + ".";
        }

        setLocationHandlers(realPrefix, properties);
        declutterMatrix = (DeclutterMatrix) PropUtils.objectFromProperties(properties,
                realPrefix + DeclutterMatrixClassProperty);
        allowPartials = PropUtils.booleanFromProperties(properties, realPrefix
                + AllowPartialsProperty, true);

        if (declutterMatrix != null) {
            useDeclutterMatrix = PropUtils.booleanFromProperties(properties,
                    realPrefix + UseDeclutterMatrixProperty,
                    useDeclutterMatrix);
            declutterMatrix.setAllowPartials(allowPartials);
            Debug.message("location",
                    "LocationLayer: Found DeclutterMatrix to use");
            // declutterMatrix.setXInterval(3);
            // declutterMatrix.setYInterval(3);
        } else {
            useDeclutterMatrix = false;
        }
    }

    /**
     * Sets the current graphics list to the given list.
     *
     * @param aList a vector of OMGraphics
     */
    public synchronized void setGraphicList(Vector aList) {
        omGraphics = aList;
    }

    /**
     * Retrieves a vector of the current graphics list.
     *
     * @return vector of OMGraphics.
     */
    public synchronized Vector getGraphicList() {
        return omGraphics;
    }

    public void setDeclutterMatrix(DeclutterMatrix dm) {
        declutterMatrix = dm;
    }

    public DeclutterMatrix getDeclutterMatrix() {
        return declutterMatrix;
    }

    public void setUseDeclutterMatrix(boolean set) {
        useDeclutterMatrix = set;
    }

    public boolean getUseDeclutterMatrix() {
        return useDeclutterMatrix;
    }

    /**
     * Used to set the cancelled flag in the layer. The swing worker checks this
     * once in a while to see if the projection has changed since it started
     * working. If this is set to true, the swing worker quits when it is safe.
     */
    public synchronized void setCancelled(boolean set) {
        cancelled = set;
    }

    /** Check to see if the cancelled flag has been set. */
    public synchronized boolean isCancelled() {
        return cancelled;
    }

    public synchronized MapMouseListener getMapMouseListener() {
        return this;
    }

    /**
     * Tell the location handlers to reload their data from their sources. If
     * you want these changes to appear on the map, you should call doPrepare()
     * after this call.
     */
    public void reloadData() {
        if (dataHandlers != null) {
            for (int i = 0; i < dataHandlers.length; i++) {
                dataHandlers[i].reloadData();
            }
        }
    }

    /**
     * Implementing the ProjectionPainter interface.
     */
    public synchronized void renderDataForProjection(Projection proj,
                                                     java.awt.Graphics g) {
        if (proj == null) {
            Debug.error("LocationLayer.renderDataForProjection: null projection!");
            return;
        } else if (!proj.equals(getProjection())) {
            setProjection(proj.makeClone());
            setGraphicList(prepare());
        }
        paint(g);
    }

    /**
     * The projectionListener interface method that lets the Layer know when the
     * projection has changes, and therefore new graphics have to created
     * /supplied for the screen.
     *
     * @param e The projection event, most likely fired from a map bean.
     */
    public void projectionChanged(ProjectionEvent e) {
        if (Debug.debugging("basic")) {
            Debug.output(getName() + "|LocationLayer.projectionChanged()");
        }

        if (setProjection(e) == null) {
            // Nothing to do, already have it and have acted on it...
            repaint();
            return;
        }
        setGraphicList(null);

        // If there isn't a worker thread working on this already,
        // create a thread that will do the real work. If there is
        // a thread working on this, then set the cancelled flag
        // in the layer.

        doPrepare();
    }

    /**
     * The LocationWorker calls this method on the layer when it is done
     * working. If the calling worker is not the same as the "current" worker,
     * then a new worker is created.
     *
     * @param worker the worker that has the graphics.
     */
    protected synchronized void workerComplete(LocationWorker worker) {
        if (!isCancelled()) {
            currentWorker = null;
            setGraphicList((Vector) worker.get());
            repaint();
        } else {
            setCancelled(false);
            currentWorker = new LocationWorker();
            currentWorker.execute();
        }
    }

    /**
     * A method that will launch a Worker to fetch the data. This is the method
     * to call if you want the layer to refresh it's graphics from the location
     * handlers. The layer will repaint itself automatically.
     */
    public void doPrepare() {
        // If there isn't a worker thread working on a projection
        // changed or other doPrepare call, then create a thread that
        // will do the real work. If there is a thread working on
        // this, then set the cancelled flag in the layer.
        if (currentWorker == null) {
            currentWorker = new LocationWorker();
            currentWorker.execute();
        } else
            setCancelled(true);
    }

    /**
     * Prepares the graphics for the layer. This is where the getRectangle()
     * method call is made on the location.
     * <p>
     * Occasionally it is necessary to abort a prepare call. When this happens,
     * the map will set the cancel bit in the LayerThread, (the thread that is
     * running the prepare). If this Layer needs to do any cleanups during the
     * abort, it should do so, but return out of the prepare asap.
     */
    public synchronized Vector prepare() {

        if (isCancelled()) {
            if (Debug.debugging("location")) {
                Debug.output(getName() + "|LocationLayer.prepare(): aborted.");
            }
            return null;
        }

        Vector omGraphicList = new Vector();
        Projection projection = getProjection();
        if (projection == null) {
            if (Debug.debugging("location")) {
                Debug.output(getName()
                        + "|LocationLayer.prepare(): null projection, layer not ready.");
            }
            return omGraphicList;
        }

        if (Debug.debugging("location")) {
            Debug.output(getName() + "|LocationLayer.prepare(): doing it");
        }

        if (useDeclutterMatrix && declutterMatrix != null) {
            declutterMatrix.setWidth(projection.getWidth());
            declutterMatrix.setHeight(projection.getHeight());
            declutterMatrix.create();
        }

        // Setting the OMGraphicsList for this layer. Remember, the
        // Vector is made up of OMGraphics, which are generated
        // (projected) when the graphics are added to the list. So,
        // after this call, the list is ready for painting.

        // call getRectangle();
        if (Debug.debugging("location")) {
            Debug.output(getName() + "|LocationLayer.prepare(): "
                    + "calling prepare with projection: " + projection
                    + " ul = " + projection.getUpperLeft() + " lr = "
                    + projection.getLowerRight());
        }

        LatLonPoint ul = projection.getUpperLeft();
        LatLonPoint lr = projection.getLowerRight();

        if (Debug.debugging("location")) {
            float delta = lr.getLongitude() - ul.getLongitude();
            Debug.output(getName() + "|LocationLayer.prepare(): " + " ul.lon ="
                    + ul.getLongitude() + " lr.lon = " + lr.getLongitude()
                    + " delta = " + delta);
        }
        if (dataHandlers != null) {
            for (int i = 0; i < dataHandlers.length; i++) {
                ((LocationHandler) dataHandlers[i]).get(ul.getLatitude(),
                        ul.getLongitude(),
                        lr.getLatitude(),
                        lr.getLongitude(),
                        omGraphicList);
            }
        }

        // ///////////////////
        // safe quit
        int size = 0;
        if (omGraphicList != null) {
            size = omGraphicList.size();
            if (Debug.debugging("basic")) {
                Debug.output(getName()
                        + "|LocationLayer.prepare(): finished with " + size
                        + " graphics");
            }

            // Don't forget to project them. Since they are only
            // being recalled if the projection hase changed, then
            // we need to force a reprojection of all of them
            // because the screen position has changed.
            Enumeration things = omGraphicList.elements();
            while (things.hasMoreElements()) {
                OMGraphic thingy = (OMGraphic) things.nextElement();

                if (useDeclutterMatrix && thingy instanceof Location) {
                    Location loc = (Location) thingy;
                    loc.generate(projection, declutterMatrix);
                } else {
                    thingy.generate(projection);
                }
            }
        } else if (Debug.debugging("basic")) {
            Debug.output(getName()
                    + "|LocationLayer.prepare(): finished with null graphics list");
        }

        return omGraphicList;
    }

    /**
     * Paints the layer.
     *
     * @param g the Graphics context for painting
     */
    public void paint(java.awt.Graphics g) {
        if (Debug.debugging("location")) {
            Debug.output(getName() + "|LocationLayer.paint()");
        }
        Vector vlist = getGraphicList();
        Object[] list = null;

        if (vlist != null)
            list = vlist.toArray();

        if (list != null) {
            int i;
            OMGraphic loc;
            // Draw from the bottom up, so it matches the palette, and
            // the order in which the handlers were loaded - the first
            // in the list is on top.

            // We need to go through list twice. The first time, draw
            // all the regular OMGraphics, and also draw all of the
            // graphics for the locations. The second time through,
            // draw the labels. This way, the labels won't be covered
            // up by graphics.
            for (int j = 0; j < 2; j++) {
                for (i = list.length - 1; i >= 0; i--) {
                    loc = (OMGraphic) list[i];
                    if (j == 0) {
                        if (loc instanceof Location) {
                            ((Location) loc).renderLocation(g);
                        } else {
                            loc.render(g);
                        }
                    } else if (loc instanceof Location) {
                        ((Location) loc).renderName(g);
                    }
                }
            }
        } else {
            if (Debug.debugging("location")) {
                Debug.error(getName() + "|LocationLayer: paint(): Null list...");
            }
        }
    }

    /**
     * Parse the properties and set up the location handlers. The prefix will
     * should be null, or a prefix string with a period at the end, for scoping
     * purposes.
     */
    protected void setLocationHandlers(String prefix, Properties p) {

        String handlersValue = p.getProperty(prefix
                + LocationHandlerListProperty);

        if (Debug.debugging("location")) {
            Debug.output(getName() + "| handlers = \"" + handlersValue + "\"");
        }

        if (handlersValue == null) {
            if (Debug.debugging("location")) {
                Debug.output("No property \"" + prefix
                        + LocationHandlerListProperty
                        + "\" found in application properties.");
            }
            return;
        }

        // Divide up the names ...
        StringTokenizer tokens = new StringTokenizer(handlersValue, " ");
        Vector handlerNames = new Vector();
        while (tokens.hasMoreTokens()) {
            handlerNames.addElement(tokens.nextToken());
        }

        if (Debug.debugging("location")) {
            Debug.output("OpenMap.getLocationHandlers(): " + handlerNames);
        }

        int nHandlerNames = handlerNames.size();
        Vector handlers = new Vector(nHandlerNames);
        Vector goodNames = new Vector(nHandlerNames);
        for (int i = 0; i < nHandlerNames; i++) {
            String handlerName = (String) handlerNames.elementAt(i);
            String classProperty = handlerName + ".class";
            String className = p.getProperty(classProperty);

            String nameProperty = handlerName + ".prettyName";
            String prettyName = p.getProperty(nameProperty);

            if (className == null) {
                Debug.error("Failed to locate property \"" + classProperty
                        + "\"\nSkipping handler \"" + handlerName + "\"");
                continue;
            }
            try {
                if (Debug.debugging("location")) {
                    Debug.output("OpenMap.getHandlers():instantiating handler \""
                            + className + "\"");
                }

                Object obj = Class.forName(className).newInstance();// Works
                // for
                // applet!
                if (obj instanceof LocationHandler) {
                    LocationHandler lh = (LocationHandler) obj;
                    lh.setProperties(handlerName, p);
                    lh.setLayer(this);
                    handlers.addElement(lh);
                    goodNames.addElement(prettyName != null ? prettyName : "");
                }
                if (false)
                    throw new java.io.IOException();// fool javac
                // compiler
            } catch (java.lang.ClassNotFoundException e) {
                Debug.error("Handler class not found: \"" + className
                        + "\"\nSkipping handler \"" + handlerName + "\"");
            } catch (java.io.IOException e) {
                Debug.error("IO Exception instantiating class \"" + className
                        + "\"\nSkipping handler \"" + handlerName + "\"");
            } catch (Exception e) {
                Debug.error("Exception instantiating class \"" + className
                        + "\": " + e);
            }
        }

        int nHandlers = handlers.size();

        dataHandlers = new LocationHandler[nHandlers];
        dataHandlerNames = new String[nHandlers];

        if (nHandlers != 0) {
            handlers.copyInto(dataHandlers);
            goodNames.copyInto(dataHandlerNames);
        }

    }

    /**
     * Let the LocationHandlers know that the layer has been removed.
     */
    public void removed(java.awt.Container cont) {
        if (dataHandlers != null) {
            for (int i = 0; i < dataHandlers.length; i++) {
                ((LocationHandler) dataHandlers[i]).removed(cont);
            }
        }
    }

    /**
     * Set the LocationHandlers for the layer. Make sure you update the
     * LocationHandler names, too, so the names coorespond to these.
     *
     * @param handlers an array of LocationHandlers.
     */
    public void setLocationHandlers(LocationHandler[] handlers) {
        dataHandlers = handlers;
        // Need to set the layer on the handlers.
        for (int i = 0; i < handlers.length; i++) {
            handlers[i].setLayer(this);
        }
        resetPalette();
    }

    /**
     * Get the LocationHandlers for this layer.
     */
    public LocationHandler[] getLocationHandlers() {
        return dataHandlers;
    }

    /**
     * Set the LocationHandler names suitable for a GUI. Make sure these end up
     * cooresponding to the LocationHandlers.
     *
     * @param handlerNames an array of Strings.
     */
    public void setLocationHandlerNames(String[] handlerNames) {
        dataHandlerNames = handlerNames;
        resetPalette();
    }

    /**
     * Get the LocationHandlers for this layer.
     */
    public String[] getLocationHandlerNames() {
        return dataHandlerNames;
    }

    /**
     * Called when the LocationHandlers are reset, or their names are reset, to
     * refresh the palette with the new information.
     */
    protected void resetPalette() {
        box = null;
        super.resetPalette();
    }

    /**
     * Overridden from Layer because we are placing our own scroll pane around
     * the LocationHandler GUIs.
     */
    protected WindowSupport createWindowSupport() {
        return new WindowSupport(getGUI(), getName());
    }

    // ----------------------------------------------------------------------
    // GUI
    // ----------------------------------------------------------------------

    protected Box box = null;

    /**
     * Provides the palette widgets to control the options of showing maps, or
     * attribute text.
     *
     * @return Component object representing the palette widgets.
     */
    public java.awt.Component getGUI() {
        if (box == null) {
            box = Box.createVerticalBox();
            int nHandlers = 0;

            if (dataHandlers != null) {
                nHandlers = dataHandlers.length;
            }

            JPanel[] panels = new JPanel[nHandlers];
            Box box2 = Box.createVerticalBox();
            for (int i = 0; i < nHandlers; i++) {

                String handlerName;
                if (dataHandlerNames != null && i < dataHandlerNames.length) {
                    handlerName = dataHandlerNames[i];
                } else {
                    handlerName = "";
                }

                panels[i] = PaletteHelper.createPaletteJPanel(handlerName);
                panels[i].add(dataHandlers[i].getGUI());
                // box.add(panels[i]);
                box2.add(panels[i]);
            }

            JScrollPane scrollPane = new JScrollPane(box2, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

            scrollPane.setAlignmentX(java.awt.Component.CENTER_ALIGNMENT);
            scrollPane.setAlignmentY(java.awt.Component.TOP_ALIGNMENT);

            box.add(scrollPane);

            if (declutterMatrix != null) {
                JPanel dbp = new JPanel(new GridLayout(0, 1));

                JCheckBox declutterButton = new JCheckBox(i18n.get(LocationLayer.class,
                        "declutterNames",
                        "Declutter Names"), useDeclutterMatrix);
                declutterButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        JCheckBox jcb = (JCheckBox) ae.getSource();
                        useDeclutterMatrix = jcb.isSelected();
                        if (isVisible()) {
                            doPrepare();
                        }
                    }
                });
                declutterButton.setToolTipText(i18n.get(LocationLayer.class,
                        "declutterNames",
                        I18n.TOOLTIP,
                        "<HTML><BODY>Move location names so they don't overlap.<br>This may take awhile if you are zoomed out.</BODY></HTML>"));
                dbp.add(declutterButton);
                box.add(dbp);
            }
        }
        return box;
    }

    // ------------------------------------------------------------
    // MapMouseListener implementation
    // ------------------------------------------------------------

    /** Given a mouse event, find the closest location on the screen. */
    public Location findClosestLocation(MouseEvent evt) {
        Vector graphics = getGraphicList();
        if (graphics != null) {
            int x = evt.getX();
            int y = evt.getY();
            float limit = 4.0f;
            Location ret = null;
            Location loc;

            float closestDistance = Float.MAX_VALUE;
            float currentDistance;
            int i;
            int size = graphics.size();

            for (i = 0; i < size; i++) {
                loc = (Location) graphics.elementAt(i);
                currentDistance = loc.distance(x, y);
                if (currentDistance < closestDistance) {
                    ret = loc;
                    closestDistance = currentDistance;
                }
            }
            if (closestDistance <= limit)
                return ret;
        }
        return null;
    }

    public String[] getMouseModeServiceList() {
        String[] services = { SelectMouseMode.modeID };
        return services;
    }

    protected void showMapPopup(MouseEvent evt, MapBean map) {
        if (backgroundMenu == null) {
            backgroundMenu = new LocationPopupMenu();
            backgroundMenu.add(new LocationMenuItem(recenter, backgroundMenu, this));
            backgroundMenu.add(new LocationMenuItem(cancel, backgroundMenu, this));
            backgroundMenu.setMap(map);
        }
        backgroundMenu.setEvent(evt);
        backgroundMenu.show(this, evt.getX(), evt.getY());
    }

    protected void showLocationPopup(MouseEvent evt, Location loc, MapBean map) {
        if (locMenu == null) {
            locMenu = new LocationPopupMenu();
            locMenu.setMap(map);
        }
        locMenu.removeAll();

        locMenu.setEvent(evt);
        locMenu.setLoc(loc);

        locMenu.add(new LocationMenuItem(LocationLayer.recenter, locMenu, this));
        locMenu.add(new LocationMenuItem(LocationLayer.cancel, locMenu, this));
        locMenu.addSeparator();

        LocationHandler lh = loc.getLocationHandler();
        if (lh != null) {
            lh.fillLocationPopUpMenu(locMenu);
        }

        locMenu.show(this, evt.getX(), evt.getY());
    }

    public boolean mousePressed(MouseEvent evt) {
        if (!isVisible())
            return false;

        Location loc = findClosestLocation(evt);
        if (map == null) {
            try {
                map = (MapBean) SwingUtilities.getAncestorOfClass(Class.forName("com.bbn.openmap.MapBean"),
                        this);
            } catch (java.lang.ClassNotFoundException e) {
                Debug.error("LocationLayer: Whatza MapBean??");
            }
        }
        if (loc == null) {
            // user clicked on map
            Debug.message("location", "Clicked on background");
            showMapPopup(evt, map);
        } else {
            // user clicked on rate center
            Debug.message("location", "Clicked on location");
            showLocationPopup(evt, loc, map);
        }

        return true;
    }

    public boolean mouseReleased(MouseEvent e) {
        return false;
    }

    public boolean mouseClicked(MouseEvent evt) {
        return false;
    }

    public void mouseEntered(MouseEvent e) {}

    public void mouseExited(MouseEvent e) {}

    public boolean mouseDragged(MouseEvent e) {
        return false;
    }

    boolean setNameOnLine = false;

    public boolean mouseMoved(MouseEvent evt) {
        if (!isVisible())
            return false;

        Location loc = findClosestLocation(evt);
        if (loc == null) {
            if (setNameOnLine) { // only do this once.
                fireRequestInfoLine("");
                setNameOnLine = false;
            }
            return false; // pass through!!
        } else {
            fireRequestInfoLine(loc.getName());
            setNameOnLine = true;
            return true;
        }
    }

    public void mouseMoved() {
    // fireRequestInfoLine("");
    }

    /**
     * PropertyConsumer method, to fill in a Properties object, reflecting the
     * current values of the layer. If the layer has a propertyPrefix set, the
     * property keys should have that prefix plus a separating '.' prepended to
     * each propery key it uses for configuration.
     *
     * @param props a Properties object to load the PropertyConsumer properties
     *        into. If props equals null, then a new Properties object should be
     *        created.
     * @return Properties object containing PropertyConsumer property values. If
     *         getList was not null, this should equal getList. Otherwise, it
     *         should be the Properties object created by the PropertyConsumer.
     */
    public Properties getProperties(Properties props) {
        props = super.getProperties(props);

        String prefix = PropUtils.getScopedPropertyPrefix(this);

        props.put(prefix + UseDeclutterMatrixProperty,
                new Boolean(useDeclutterMatrix).toString());

        if (declutterMatrix != null) {
            props.put(prefix + DeclutterMatrixClassProperty,
                    declutterMatrix.getClass().getName());
            props.put(prefix + AllowPartialsProperty,
                    new Boolean(declutterMatrix.isAllowPartials()).toString());
        }

        StringBuffer handlerList = new StringBuffer();

        // Need to hand this off to the location handlers, and build a
        // list of marker names to use in the LocationLayer property
        // list.
        if (dataHandlers != null) {
            for (int i = 0; i < dataHandlers.length; i++) {
                String pp = dataHandlers[i].getPropertyPrefix();
                handlerList.append(" " + pp);
                props.put(pp + ".prettyName", dataHandlerNames[i]);
                dataHandlers[i].getProperties(props);
            }
        }

        props.put(prefix + LocationHandlerListProperty, handlerList.toString());

        return props;
    }

    /**
     * Method to fill in a Properties object with values reflecting the
     * properties able to be set on this PropertyConsumer. The key for each
     * property should be the raw property name (without a prefix) with a value
     * that is a String that describes what the property key represents, along
     * with any other information about the property that would be helpful
     * (range, default value, etc.). For Layer, this method should at least
     * return the 'prettyName' property.
     *
     * @param list a Properties object to load the PropertyConsumer properties
     *        into. If getList equals null, then a new Properties object should
     *        be created.
     * @return Properties object containing PropertyConsumer property values. If
     *         getList was not null, this should equal getList. Otherwise, it
     *         should be the Properties object created by the PropertyConsumer.
     */
    public Properties getPropertyInfo(Properties list) {
        list = super.getPropertyInfo(list);

        PropUtils.setI18NPropertyInfo(i18n,
                list,
                LocationLayer.class,
                UseDeclutterMatrixProperty,
                "Use Declutter Matrix",
                "Flag for using the declutter matrix.",
                "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");

        PropUtils.setI18NPropertyInfo(i18n,
                list,
                LocationLayer.class,
                DeclutterMatrixClassProperty,
                "Declutter Matrix Class",
                "Class name of the declutter matrix to use (com.bbn.openmap.layer.DeclutterMatrix).",
                null);

        PropUtils.setI18NPropertyInfo(i18n,
                list,
                LocationLayer.class,
                AllowPartialsProperty,
                "Allow partials",
                "Flag to allow labels to run off the edge of the map.",
                "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");

        PropUtils.setI18NPropertyInfo(i18n,
                list,
                LocationLayer.class,
                LocationHandlerListProperty,
                "Location Handlers",
                "Space-separated list of unique names to use to scope the LocationHandler property definitions.",
                null);

        if (dataHandlers != null) {
            for (int i = 0; i < dataHandlers.length; i++) {
                dataHandlers[i].getPropertyInfo(list);
            }
        }

        return list;
    }
}
TOP

Related Classes of com.bbn.openmap.layer.location.LocationLayer

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.