Package com.bbn.openmap.gui

Source Code of com.bbn.openmap.gui.LayersPanel

// **********************************************************************
//
// <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/gui/LayersPanel.java,v $
// $RCSfile: LayersPanel.java,v $
// $Revision: 1.9.2.7 $
// $Date: 2006/07/10 23:26:55 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Properties;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import com.bbn.openmap.BufferedLayerMapBean;
import com.bbn.openmap.I18n;
import com.bbn.openmap.Layer;
import com.bbn.openmap.LayerHandler;
import com.bbn.openmap.LightMapHandlerChild;
import com.bbn.openmap.MapHandler;
import com.bbn.openmap.event.LayerEvent;
import com.bbn.openmap.event.LayerListener;
import com.bbn.openmap.util.ComponentFactory;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;

/**
* The LayersPanel displays the list of layers that OpenMap can display. The
* layer name is displayed accompanied by an on/off button and a tool palette
* button. Pressing the on/off button will cause the the map to display/remove
* the layer. Pressing the tool palette button will cause a window to be
* displayed containing widgets specific to that layer.
* <p>
*
* The order of the layers in the list reflects the order that the layers are
* displayed on the map, with the bottom-most layer listed on the panel
* underneath all the the other layers displayed on the map. The order of the
* layers is determined by their order in the Layer[] passed in the setLayers
* method.
* <p>
*
* The order of the layers can be changed by sending the LayersPanel an
* ActionEvent with one of the string commands in the class, or by sending a
* PropertyChangeEvent with a command and a Layer as the new value.
* <P>
*
* In the standard GUI, the order can be changed by selecting a layer by
* clicking on the layer's name (or on either of buttons), then clicking on one
* of the four buttons on the left side of the panel. The four buttons signify,
* from top to bottom: Move the selected layer to the top; Move the selected
* layer up one position; Move the selected layer down one position; Move the
* selected layer to the bottom.
* <P>
*
* The LayersPanel can be used within a BeanContext. If it is added to a
* BeanConext, it will look for a LayerHandler to add itself to as a
* LayerListener. The LayersPanel can only listen to one LayerHandler, so if
* more than one is found, only the last one found will be used. If another
* LayerHandler is added to the BeanContext later, the new LayerHandler will be
* used. The LayersPanel is also considered to be a Tool, which will cause a
* button that will bring up the LayersPanel to be automatically added to the
* ToolPanel if a ToolPanel is part of the BeanContext.
* <P>
*
* When the LayersPanel discovers a BufferedLayerMapBean is being used, it adds
* a special LayerPane to its LayerPane list that shows which layers are being
* buffered in the MapBean. This special LayerPane shows up as a line in the
* list, and all layers below that line are being specially buffered by the
* BufferedLayerMapBean.
* <P>
*
* The properties that can be set for the LayersPanel:
*
* <pre>
*      
*       
*        
*          # Use LayerStatusPanes for the layers if true, otherwise
*          # LayerPanes.  LayerStatusPanes turn the on/off bulbs to green/red
*          # bulbs when the layer is resting/working.  LayerPanes just show
*          # yellow bulbs when the layer is part of the map.
*          showStatus=true
*          # When the BufferedLayerMapBean is used, a divider will be
*          # displayed in the list of layers showing which layers are in the
*          # MapBean buffer (below the line).  Commands to move layers, by
*          # default, respect this divider, requiring more commands to have
*          # layers cross it.
*          boundary=true
*          # Add control buttons - use &quot;none&quot; for no button.  If undefined,
*          # the LayerControlButtonPanel will be created automatically.
*          controls=com.bbn.openmap.gui.LayerControlButtonPanel
*          # Any control properties added here, prepended by &quot;controls&quot;...
*          controls.configuration=WEST
*         
*        
*       
* </pre>
*/
public class LayersPanel extends OMToolComponent implements Serializable,
        ActionListener, LayerListener, PropertyChangeListener {
    /** Action command for the layer order buttons. */
    public final static String LayerTopCmd = "LayerTopCmd";
    /** Action command for the layer order buttons. */
    public final static String LayerBottomCmd = "LayerBottomCmd";
    /** Action command for the layer order buttons. */
    public final static String LayerUpCmd = "LayerUpCmd";
    /** Action command for the layer order buttons. */
    public final static String LayerDownCmd = "LayerDownCmd";
    /** Action command removing a layer. */
    public final static String LayerRemoveCmd = "LayerRemoveCmd";
    /** Action command adding a layer. */
    public final static String LayerAddCmd = "LayerAddCmd";
    /** Action command for notification that a layer has been selected. */
    public final static String LayerSelectedCmd = "LayerSelected";
    /**
     * Action command for notification that a layer has been deselected. Not so
     * reliable. Usually a selection notification means that others are
     * deselected.
     */
    public final static String LayerDeselectedCmd = "LayerDeselected";

    /**
     * A property to set the class to create for layer order controls. If
     * undefined, a LayerControlButtonPanel in its default configuration will be
     * created. For no controls added, use (none) for this property.
     */
    public final static String ControlButtonsProperty = "controls";
    /**
     * A property that can be used for controlling how the to top and to bottom
     * cammands will be interpreted when a BufferedLayerMapBean is used. See the
     * definition of bufferedBoundary.
     */
    public final static String BufferedBoundaryProperty = "boundary";
    /**
     * A property that can be used for controlling what type of LayerPanes are
     * used. If true (default) a LayerStatusPane will be created for each layer.
     * Otherwise, a LayerPane will be used.
     */
    public final static String ShowStatusProperty = "showStatus";

    /**
     * A value for the (controls) property to not include control buttons in the
     * interface.
     */
    public final static String NO_CONTROLS = "none";

    /** Default key for the LayersPanel Tool. */
    public final static String defaultKey = "layerspanel";

    /**
     * The LayerHandler to listen to for LayerEvents, and also to notify if the
     * layer order should change.
     */
    protected transient LayerHandler layerHandler = null;
    /**
     * Panel that lets you dynamically add and configure layers.
     */
    protected transient LayerAddPanel layerAddPanel = null;
    /**
     * The components holding the layer name label, the on/off indicator and on
     * button, and the palette on/off indicator and palette on button.
     */
    protected transient LinkedList panes;
    /** The internal component that holds the panes. */
    protected transient JPanel panesPanel;
    /** The scroll pane to use for panes. */
    protected transient JScrollPane scrollPane;
    /** The Layer order adjustment button group. */
    protected transient ButtonGroup bg;
    /** The ActionListener that will bring up the LayersPanel. */
    protected ActionListener actionListener;
    /** The set of buttons that control the layers. */
    protected LayerControlButtonPanel controls = null;
    /**
     * Hashtable that tracks LayerPanes for layers, with the layer as the key
     * and LayerPane as the value.
     */
    protected Hashtable paneLookUp = new Hashtable();
    /**
     * A special LayerPane used when the LayersPanel senses that a
     * BufferedLayerMapBean is being used. This LayersPanel is a separating line
     * showing which layers are part of the MapBean's buffer, and which are not.
     */
    protected LayerPane backgroundLayerSeparator = null;
    /**
     * Behavior flag so that if there is a background buffered layer on the
     * MapBean, and a buffered layer divider in the LayersPanel, whether
     * commands instructing a layer to the top or bottom of the list should
     * honor the virtual boundary between buffered and unbuffered layers. That
     * is, if a layer is on the bottom of the buffered list and is instructed to
     * go to the top of the overal list, it will only first travel to the top of
     * the buffered layers. On a subsequent top command, it will go to the top
     * of the list. The same behavior applies for going down. True is default.
     * If set to false, these commands will just send the selected layer to the
     * top and bottom of the entire list.
     */
    protected boolean bufferedBoundary = true;

    /**
     * Behavior flag that determines what kind of LayerPane is used for the
     * layers. If true (default) the LayerStatusPane will be used. Otherwise,
     * the LayerPane will be used instead.
     */
    protected boolean showStatus = true;

    /**
     * Construct the LayersPanel.
     */
    public LayersPanel() {
        super();
        setKey(defaultKey);
        setLayout(new BorderLayout());
        // setWindowSupport(new WindowSupport(this, i18n.get(LayersPanel.class,
        // "title",
        // "Layers")));
    }

    /**
     * Construct the LayersPanel.
     *
     * @param lHandler the LayerHandler controlling the layers.
     */
    public LayersPanel(LayerHandler lHandler) {
        this();
        setLayerHandler(lHandler);
    }

    /**
     * Set the LayerHandler that the LayersPanel listens to. If the LayerHandler
     * passed in is not null, the LayersMenu will be added to the LayerHandler
     * LayerListener list, and the LayersMenu will receive a LayerEvent with the
     * current layers.
     * <P>
     *
     * If there is a LayerHandler that is already being listened to, then the
     * LayersPanel will remove itself from current LayerHandler as a
     * LayerListener, before adding itself to the new LayerHandler.
     * <P>
     *
     * Lastly, if the LayerHandler passed in is null, the LayersPanel will
     * disconnect itself from any LayerHandler currently held, and reset itself
     * with no layers.
     *
     * @param lh LayerHandler to listen to, and to use to reorder the layers.
     */
    public void setLayerHandler(LayerHandler lh) {
        if (layerHandler != null) {
            layerHandler.removeLayerListener(this);
        }
        layerHandler = lh;
        if (layerHandler != null) {
            layerHandler.addLayerListener(this);
        } else {
            setLayers(new Layer[0]);
        }
        updateLayerPanes(layerHandler);
    }

    /**
     * Get the LayerHandler that the LayersPanel listens to and uses to reorder
     * layers.
     *
     * @return LayerHandler.
     */
    public LayerHandler getLayerHandler() {
        return layerHandler;
    }

    /**
     * Set the layerpanes with the given layerhandler
     *
     * @param layerHandler The LayerHandler controlling the layers
     */
    protected void updateLayerPanes(LayerHandler layerHandler) {
        Iterator it = getPanes().iterator();
        while (it.hasNext()) {
            ((LayerPane) it.next()).setLayerHandler(layerHandler);
        }
    }

    /**
     * LayerListener interface method. A list of layers will be added, removed,
     * or replaced based on on the type of LayerEvent. The LayersPanel only
     * reacts to LayerEvent.ALL events, to reset the components in the
     * LayersPanel.
     *
     * @param evt a LayerEvent.
     */
    public void setLayers(LayerEvent evt) {
        Layer[] layers = evt.getLayers();
        int type = evt.getType();

        if (type == LayerEvent.ALL) {
            Debug.message("layerspanel", "LayersPanel received layers update");
            setLayers(layers);
        }
    }

    /**
     * Tool interface method. The retrieval tool's interface. This method
     * creates a button that will bring up the LayersPanel.
     *
     * @return String The key for this tool.
     */
    public Container getFace() {
        JButton layerButton = null;

        if (getUseAsTool()) {
            layerButton = new JButton(new ImageIcon(OMToolSet.class.getResource("layers.gif"), "Layer Controls"));
            layerButton.setBorderPainted(false);
            // layerButton.setToolTipText("Layer Controls");
            layerButton.setToolTipText(i18n.get(LayersPanel.class,
                    "layerButton",
                    I18n.TOOLTIP,
                    "Layer Controls"));
            layerButton.setMargin(new Insets(0, 0, 0, 0));
            layerButton.addActionListener(getActionListener());
        }

        return layerButton;
    }

    /**
     * Get the ActionListener that triggers the LayersPanel. Useful to have to
     * provide an alternative way to bring up the LayersPanel.
     *
     * @return ActionListener
     */
    public ActionListener getActionListener() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                WindowSupport ws = getWindowSupport();

                if (ws == null) {
                    ws = new WindowSupport(LayersPanel.this, i18n.get(LayersPanel.class,
                            "title",
                            "Layers"));
                    setWindowSupport(ws);
                }

                // Initial settings.
                int w = 328;
                int h = 300;

                Dimension dim = ws.getComponentSize();
                if (dim != null) {
                    w = (int) dim.getWidth();
                    h = (int) dim.getHeight();
                }

                int x = -1;
                int y = -1;

                Point loc = ws.getComponentLocation();
                if (loc != null) {
                    x = (int) loc.getX();
                    y = (int) loc.getY();
                }

                MapHandler mh = (MapHandler) getBeanContext();
                Frame frame = null;
                if (mh != null) {
                    frame = (Frame) mh.get(java.awt.Frame.class);
                }

                ws.displayInWindow(frame, x, y, w, h);
            }
        };
    }

    /**
     * Set the layers that are in the LayersPanel. Make sure that the layer[] is
     * the same as that passed to any other OpenMap component, like the
     * LayersMenu. This method checks to see if the layer[] has actually
     * changed, in order or in size. If it has, then createPanel() is called to
     * rebuild the LayersPanel.
     *
     * @param inLayers the array of layers.
     */
    public void setLayers(Layer[] inLayers) {
        Layer[] layers = inLayers;

        if (inLayers == null) {
            layers = new Layer[0];
        }

        if (Debug.debugging("layerspanel")) {
            Debug.output("LayersPanel.setLayers() with " + layers.length
                    + " layers.");
        }

        LinkedList panes = getPanes();
        int separatorOffset = 0;
        if (backgroundLayerSeparator != null
                && panes.contains(backgroundLayerSeparator)) {
            separatorOffset = 1;
        }

        if (panes.size() - separatorOffset != layers.length) {
            // if the panel hasn't been created yet, or if someone has
            // changed the layers on us, rebuild the panel.
            createPanel(layers);
            return;
        }

        int i = 0;
        Iterator it = panes.iterator();
        while (it.hasNext() && i < layers.length) {
            LayerPane pane = (LayerPane) it.next();

            if (pane == backgroundLayerSeparator) {
                continue;
            }

            if (pane.getLayer() != layers[i]) {
                // If the layer order sways at all, then we start over
                // and rebuild the panel
                createPanel(layers);
                return;
            } else {
                pane.updateLayerLabel();
            }

            // Do this just in case someone has changed something
            // somewhere else...
            pane.setLayerOn(layers[i].isVisible());
            i++;
        }

        // One last check for a mismatch...
        if (it.hasNext() || i < layers.length) {
            createPanel(layers);
        }
        // If we get here, it means that what we had is what we
        // wanted.
    }

    protected LinkedList getPanes() {
        if (panes == null) {
            panes = new LinkedList();
        }
        return panes;
    }

    protected void setPanes(LinkedList lpa) {
        panes = lpa;
    }

    GridBagLayout gridbag;
    GridBagConstraints c;

    /**
     * Create the panel that shows the LayerPanes. This method creates the
     * on/off buttons, palette buttons, and layer labels, and adds them to the
     * scrollPane used to display all the layers.
     *
     * @param inLayers the Layer[] that reflects all possible layers that can be
     *        added to the map.
     */
    public void createPanel(Layer[] inLayers) {
        Debug.message("layerspanel", "LayersPanel.createPanel()");

        // if (scrollPane != null) {
        // remove(scrollPane);
        // }

        Layer[] layers = inLayers;
        if (layers == null) {
            layers = new Layer[0];
        }

        if (panesPanel == null) {
            panesPanel = new JPanel();
            gridbag = new GridBagLayout();
            c = new GridBagConstraints();

            panesPanel.setLayout(gridbag);

            c.gridwidth = GridBagConstraints.REMAINDER;
            c.anchor = GridBagConstraints.NORTHWEST;
            c.fill = GridBagConstraints.HORIZONTAL;
            c.weightx = 1.0f;

            // panesPanel.setLayout(new BoxLayout(panesPanel,
            // BoxLayout.Y_AXIS));
            // panesPanel.setAlignmentX(LEFT_ALIGNMENT);
            // panesPanel.setAlignmentY(BOTTOM_ALIGNMENT);
        } else {
            ((GridBagLayout) panesPanel.getLayout()).invalidateLayout(panesPanel);
            panesPanel.removeAll();
        }

        if (bg == null) {
            bg = new ButtonGroup();
        }

        LinkedList panes = new LinkedList();
        LinkedList backgroundPanes = new LinkedList();

        // populate the arrays of CheckBoxes and strings used to fill
        // the JPanel for the panes
        for (int i = 0; i < layers.length; i++) {
            Layer layer = layers[i];
            if (layer == null) {
                Debug.output("LayersPanel caught null layer, " + i + " out of "
                        + layers.length);
                continue;
            }

            LayerPane lpane = (LayerPane) paneLookUp.get(layer);

            if (lpane == null) {
                if (Debug.debugging("layercontrol")) {
                    Debug.output("LayersPanel: Creating LayerPane for "
                            + layer.getName());
                }
                lpane = createLayerPaneForLayer(layer, layerHandler, bg);
                lpane.addPropertyChangeListener(LayerSelectedCmd, this);
                lpane.addPropertyChangeListener(LayerDeselectedCmd, this);
                paneLookUp.put(layer, lpane);
            } else {
                // In case this has been modified elsewhere...
                lpane.setLayerOn(layer.isVisible());
            }

            if (layer.getAddAsBackground() && backgroundLayerSeparator != null) {
                backgroundPanes.add(lpane);
            } else {
                panes.add(lpane);

                gridbag.setConstraints(lpane, c);
                panesPanel.add(lpane);
            }
        }

        if (backgroundPanes.size() != 0) {
            if (Debug.debugging("layerspanel")) {
                Debug.output("Adding BackgroundLayerSeparator");
            }
            panes.add(backgroundLayerSeparator);
            gridbag.setConstraints(backgroundLayerSeparator, c);
            panesPanel.add(backgroundLayerSeparator);
            panes.addAll(backgroundPanes);

            Iterator it = backgroundPanes.iterator();
            while (it.hasNext()) {
                LayerPane lp = (LayerPane) it.next();
                gridbag.setConstraints(lp, c);
                panesPanel.add(lp);
            }

        } else if (backgroundLayerSeparator != null) {
            if (Debug.debugging("layerspanel")) {
                Debug.output("No layers are background layers, adding separator");
            }
            panes.add(backgroundLayerSeparator);
            gridbag.setConstraints(backgroundLayerSeparator, c);
            panesPanel.add(backgroundLayerSeparator);
        }

        addFillerToPanesPanel();

        setPanes(panes);

        // if (scrollPane != null) {
        // remove(scrollPane);
        // scrollPane.removeAll();
        // scrollPane = null;
        // }
        //
        // scrollPane = new JScrollPane(panesPanel,
        // ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
        // ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        if (scrollPane == null) {
            scrollPane = new JScrollPane(panesPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            add(scrollPane, BorderLayout.CENTER);
        }

        revalidate();
    }

    protected void addFillerToPanesPanel() {
        JPanel filler = new JPanel();
        c.fill = GridBagConstraints.BOTH;
        c.weighty = 1.0f;
        gridbag.setConstraints(filler, c);
        panesPanel.add(filler);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weighty = 0.0f;
    }

    /**
     * Called when a new LayerPane needs to be created for a layer. You can use
     * this to extend LayerPane and return something else that fits your GUI.
     */
    protected LayerPane createLayerPaneForLayer(Layer layer,
                                                LayerHandler layerHandler,
                                                ButtonGroup bg) {
        if (showStatus) {
            return new LayerStatusPane(layer, layerHandler, bg);
        } else {
            return new LayerPane(layer, layerHandler, bg);
        }
    }

    public void deletePanes(LinkedList dpanes) {
        Debug.message("layerspanel", "LayersPanel.deletePanes()");
        if (dpanes != null) {
            paneLookUp.clear();
            Iterator it = dpanes.iterator();
            while (it.hasNext()) {
                LayerPane pane = (LayerPane) it.next();
                if (pane != null && pane != backgroundLayerSeparator) {
                    pane.removePropertyChangeListener(this);
                    pane.cleanup(bg);
                }
            }
        }

        // Shouldn't call this, but it's the only thing
        // that seems to make it work...
        if (Debug.debugging("helpgc")) {
            System.gc();
        }
    }

    /**
     * Set up the buttons used to move layers up and down, or add/remove layers.
     * The button component should hook itself up to the LayersPanel, and assume
     * that the LayersPanel has a BorderLayout with the list in the center spot.
     */
    protected void createControlButtons() {
        controls = new LayerControlButtonPanel(this);
    }

    /**
     * Should be called internally, when the LayersPanel creates the
     * LayerControlButtonPanel. If called from the LCBP, a loop will ensue.
     *
     * @param lcbp
     */
    protected void setControlsAndNotify(LayerControlButtonPanel lcbp) {
        setControls(lcbp);
        if (lcbp != null) {
            lcbp.setLayersPanel(this);
        }
    }

    /**
     * Simply sets the controls.
     *
     * @param lcbp
     */
    public void setControls(LayerControlButtonPanel lcbp) {
        controls = lcbp;
    }

    public LayerControlButtonPanel getControls() {
        return controls;
    }

    /**
     * Method associated with the ActionListener interface. This method listens
     * for action events meant to change the order of the layers, as fired by
     * the layer order buttons.
     *
     * @param e ActionEvent
     */
    public void actionPerformed(java.awt.event.ActionEvent e) {
        String command = e.getActionCommand();
        if (Debug.debugging("layerspanel")) {
            Debug.output("LayersPanel.actionPerformed(): " + command);
        }

        try {
            LayerPane pane = findSelectedPane();
            if (pane != null) {
                moveLayer(pane, command);
            }
        } catch (NullPointerException npe) {
        } catch (ArrayIndexOutOfBoundsException aioobe) {
        }
    }

    /**
     * Change a layer's position.
     */
    public void moveLayer(Layer layer, String command) {
        if (Debug.debugging("layercontrol")) {
            Debug.output("LayersPanel.moveLayer(): " + command + " for "
                    + layer.getName());
        }

        moveLayer((LayerPane) paneLookUp.get(layer), command);
    }

    /**
     * Change a layer's position, with the layer represented by a LayerPane.
     */
    protected void moveLayer(LayerPane lp, String command) {

        if (lp == null) {

            if (Debug.debugging("layercontrol")) {
                Debug.output("LayersPanel.moveLayer(): LayerPane not represented on list");
            }

            if (command == LayerRemoveCmd) {
                // OK, here's a hidden trick. If no layers are
                // selected
                // and the minus sign is clicked, then this is called.
                System.gc();
            }
            return;
        }

        LinkedList panes = getPanes();
        int row = panes.indexOf(lp);

        boolean boundary = false;
        int bls_row = -1;
        if (backgroundLayerSeparator != null) {
            bls_row = panes.indexOf(backgroundLayerSeparator);
            boundary = bufferedBoundary;
        }

        if (command.equals(LayerTopCmd)) {
            // Move layer selected layer to top
            panes.remove(lp);
            if (boundary && bls_row > 0 && row > bls_row + 1) {
                // If the backgroundLayerSeparator is more than one
                // above it, move to just below it on the first top
                // command.
                panes.add(bls_row + 1, lp);
            } else {
                panes.addFirst(lp);
            }

            rejiggerMapLayers();
        } else if (command.equals(LayerBottomCmd)) {
            // Move layer selected layer to bottom
            panes.remove(lp);

            if (boundary && bls_row > 0 && row < bls_row - 1) {
                // If the backgroundLayerSeparator is more than one
                // below it, move to just above it on the first top
                // command.
                panes.add(bls_row - 1, lp);
            } else {
                panes.addLast(lp);
            }

            rejiggerMapLayers();
        } else if (command.equals(LayerUpCmd)) {
            // Move layer selected layer up one
            if (row <= 0)
                return;
            panes.remove(row);
            panes.add(row - 1, lp);
            rejiggerMapLayers();
        } else if (command.equals(LayerDownCmd)) {
            // Move layer selected layer up one
            if (row < 0 || row == panes.size() - 1)
                return;
            panes.remove(row);
            panes.add(row + 1, lp);
            rejiggerMapLayers();
        } else if (command.equals(LayerRemoveCmd)) {

            if (layerHandler == null || !lp.getLayer().removeConfirmed()) {
                return;
            }

            // This order is somewhat important. lp.getLayer() will
            // be null after lp.cleanup. lp.setSelected() will cause
            // a series of property change notifications.
            lp.setSelected(false);
            lp.getLayer().setPaletteVisible(false);
            paneLookUp.remove(lp.getLayer());
            layerHandler.removeLayer(lp.getLayer());
            lp.cleanup(bg);

            // Shouldn't call this, but it's the only thing
            // that seems to make it work...
            if (Debug.debugging("helpgc")) {
                System.gc();
            }

            return;

        } else if (command.equals(LayerAddCmd)) {
            if (layerAddPanel != null) {
                layerAddPanel.showPanel();
            }
        }
    }

    /**
     * Find the selected LayerPane in the current LayerPane list. Will return
     * null if there isn't a selected pane.
     */
    protected LayerPane findSelectedPane() {
        Iterator it = getPanes().iterator();
        while (it.hasNext()) {
            LayerPane pane = (LayerPane) it.next();
            if (pane.isSelected()) {
                return pane;
            }
        }
        return null;
    }

    /**
     * Makes a new layer cake of active layers to send to
     * LayerHandler.setLayers().
     */
    protected void rejiggerMapLayers() {
        Debug.message("layerspanel", "LayersPanel.rejiggerMapLayers()");

        if (layerHandler == null) {
            // Why bother doing anything??
            return;
        }

        int selectedRow = -1;

        panesPanel.removeAll();
        gridbag.invalidateLayout(panesPanel);

        LinkedList panes = getPanes();
        LinkedList layerList = new LinkedList();

        int bufferIndex = Integer.MAX_VALUE;

        int i = 0; // track layer index
        Iterator it = panes.iterator();
        while (it.hasNext()) {

            LayerPane pane = (LayerPane) it.next();

            if (pane == backgroundLayerSeparator) {
                gridbag.setConstraints(pane, c);
                panesPanel.add(backgroundLayerSeparator);
                bufferIndex = i++;
                continue;
            }

            Layer layer = pane.getLayer();
            layer.setAddAsBackground(i > bufferIndex);
            gridbag.setConstraints(pane, c);
            panesPanel.add(pane);
            layerList.add(layer);

            if (pane.isSelected()) {
                selectedRow = i;
            }
            i++;
        }

        addFillerToPanesPanel();

        scrollPane.revalidate();

        // Scroll up or down as necessary to keep selected row
        // viewable
        if (selectedRow >= 0) {
            int spheight = scrollPane.getHeight();
            JScrollBar sb = scrollPane.getVerticalScrollBar();
            int sv = sb.getValue();
            int paneheight = ((LayerPane) panes.get(selectedRow)).getHeight();
            int rowvalue = selectedRow * paneheight;
            // Don't reset scrollBar unless the selected row
            // is not in the viewable range
            if (!((rowvalue > sv) && (rowvalue < spheight + sv))) {
                sb.setValue(rowvalue);
            }
        }

        Object[] layerArray = layerList.toArray();
        int length = layerArray.length;
        Layer[] newLayers = new Layer[length];

        for (int j = 0; j < length; j++) {
            newLayers[j] = (Layer) layerArray[j];
        }

        layerHandler.setLayers(newLayers);
    }

    /**
     * Update the layer names - if a layer name has changed, tell the LayerPanes
     * to check with their layers to update their labels.
     */
    public synchronized void updateLayerLabels() {
        Iterator it = getPanes().iterator();
        while (it.hasNext()) {
            ((LayerPane) it.next()).updateLayerLabel();
        }
    }

    public void propertyChange(PropertyChangeEvent pce) {
        String command = pce.getPropertyName();
        Object obj = pce.getNewValue();

        if (Debug.debugging("layercontrol")) {
            Debug.output("LayersPanel receiving PropertyChangeEvent " + command
                    + ", " + pce.toString());
        }

        if ((command == LayerSelectedCmd || command == LayerDeselectedCmd)
                && obj instanceof Layer) {

            if (Debug.debugging("layercontrol")) {
                Debug.output("LayersPanel: layer panel notification that layer is selected: "
                        + ((Layer) obj).getName());
            }
            firePropertyChange(command, null, ((Layer) obj));

        } else if ((command == LayersPanel.LayerTopCmd
                || command == LayersPanel.LayerBottomCmd
                || command == LayersPanel.LayerUpCmd
                || command == LayersPanel.LayerDownCmd || command == LayersPanel.LayerRemoveCmd)
                && obj instanceof Layer) {
            if (Debug.debugging("layercontrol")) {
                Debug.output("LayersPanel: layer panel notification that layer should be raised: "
                        + ((Layer) obj).getName());
            }
            moveLayer((Layer) obj, command);
        }
    }

    /**
     * Called when the LayersPanel is added the BeanContext, or when another
     * object is added to the BeanContext after the LayerHandler has been added.
     * This allows the LayersPanel to keep up-to-date with any objects that it
     * may be interested in, namely, the LayerHandler. If a LayerHandler has
     * already been added, the new LayerHandler will replace it.
     *
     * @param someObj the object being added to the BeanContext
     */
    public void findAndInit(Object someObj) {
        if (someObj instanceof LayerHandler) {
            // do the initializing that need to be done here
            Debug.message("layerspanel", "LayersPanel found a LayerHandler");
            setLayerHandler((LayerHandler) someObj);
        }

        if (someObj instanceof BufferedLayerMapBean) {
            if (Debug.debugging("layerspanel")) {
                Debug.output("LayersPanel found BufferedLayerMapBean, creating separator panel");
            }
            backgroundLayerSeparator = LayerPane.getBackgroundLayerSeparator(" --- Background Layers --- ");
        }

        // Don't want to forward ourselves on to controls, supposedly
        // they already know.
        if (controls instanceof LightMapHandlerChild && someObj != this) {
            ((LightMapHandlerChild) controls).findAndInit(someObj);
        }
    }

    /**
     * BeanContextMembershipListener method. Called when an object has been
     * removed from the parent BeanContext. If a LayerHandler is removed, and
     * it's the current one being listened to, then the layers in the panel will
     * be wiped clean.
     *
     * @param someObj the object being removed from the BeanContext
     */
    public void findAndUndo(Object someObj) {
        if (someObj instanceof LayerHandler) {
            // do the initializing that need to be done here
            Debug.message("layerspanel", "LayersPanel removing LayerHandler");
            if (getLayerHandler() == (LayerHandler) someObj) {
                setLayerHandler(null);
            }
        }

        // Don't want to forward ourselves on to controls, supposedly
        // they already know.
        if (controls instanceof LightMapHandlerChild && someObj != this) {
            ((LightMapHandlerChild) controls).findAndUndo(someObj);
        }
    }

    public void setProperties(String prefix, Properties props) {
        super.setProperties(prefix, props);
        prefix = PropUtils.getScopedPropertyPrefix(prefix);

        String controlString = props.getProperty(prefix
                + ControlButtonsProperty);

        if (controlString != NO_CONTROLS) {
            if (controlString == null) {
                createControlButtons();
            } else {
                Object obj = ComponentFactory.create(controlString, prefix
                        + ControlButtonsProperty, props);

                if (obj instanceof LayerControlButtonPanel) {
                    setControlsAndNotify((LayerControlButtonPanel) obj);
                }
            }
        }

        bufferedBoundary = PropUtils.booleanFromProperties(props, prefix
                + BufferedBoundaryProperty, bufferedBoundary);
        showStatus = PropUtils.booleanFromProperties(props, prefix
                + ShowStatusProperty, showStatus);
    }

    public Properties getProperties(Properties props) {
        props = super.getProperties(props);

        String prefix = PropUtils.getScopedPropertyPrefix(this);
        LayerControlButtonPanel controls = getControls();
        if (controls != null) {
            props.put(prefix + ControlButtonsProperty, controls.getClass()
                    .getName());
            controls.getProperties(props);
        }
        props.put(prefix + BufferedBoundaryProperty,
                new Boolean(bufferedBoundary).toString());
        props.put(prefix + ShowStatusProperty,
                new Boolean(showStatus).toString());
        return props;
    }

    public Properties getPropertyInfo(Properties props) {
        props = super.getPropertyInfo(props);

        String interString = i18n.get(LayersPanel.class,
                ControlButtonsProperty,
                I18n.TOOLTIP,
                "Class to use for layer control buttons (Optional)");
        props.put(ControlButtonsProperty, interString);
        interString = i18n.get(LayersPanel.class,
                ControlButtonsProperty,
                "Button Panel Control");
        props.put(ControlButtonsProperty + LabelEditorProperty, interString);

        LayerControlButtonPanel controls = getControls();
        if (controls != null) {
            controls.getPropertyInfo(props);
        }

        interString = i18n.get(LayersPanel.class,
                BufferedBoundaryProperty,
                I18n.TOOLTIP,
                "Force layer movement to respect background layer boundary.");
        props.put(BufferedBoundaryProperty, interString);
        interString = i18n.get(LayersPanel.class,
                BufferedBoundaryProperty,
                "Use Background Layers");
        props.put(BufferedBoundaryProperty + LabelEditorProperty, interString);
        props.put(BufferedBoundaryProperty + ScopedEditorProperty,
                "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");

        interString = i18n.get(LayersPanel.class,
                ShowStatusProperty,
                I18n.TOOLTIP,
                "Use Layer Panes that show layer status.");
        props.put(ShowStatusProperty, interString);
        interString = i18n.get(LayersPanel.class,
                ShowStatusProperty,
                "Show Layer Status");
        props.put(ShowStatusProperty + LabelEditorProperty, interString);
        props.put(ShowStatusProperty + ScopedEditorProperty,
                "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");

        return props;
    }
}
TOP

Related Classes of com.bbn.openmap.gui.LayersPanel

TOP
Copyright © 2015 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.