Package com.bbn.openmap.proj

Source Code of com.bbn.openmap.proj.ProjectionStack$ProjHolder

// **********************************************************************
//
// <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/proj/ProjectionStack.java,v $
// $RCSfile: ProjectionStack.java,v $
// $Revision: 1.3.2.2 $
// $Date: 2004/10/14 18:27:38 $
// $Author: dietrick $
//
// **********************************************************************


package com.bbn.openmap.proj;

import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;

import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.MapBean;
import com.bbn.openmap.OMComponent;
import com.bbn.openmap.event.ProjectionEvent;
import com.bbn.openmap.event.ProjectionListener;
import com.bbn.openmap.util.Debug;

/**
*  Provides Projection Stack, to listen for projection changes and
*  remember them as they pass by.  As a Tool, it provides a GUI so
*  that past projections can be retrieved, and, if a past projection
*  is being displayed, a forward projection stack is activated to
*  provide a path to get to the last projection set in the MapBean.
*  ProjectionStackTriggers should hook themselves up to the
*  ProjectionStack.  The ProjectionStack is responsible for finding
*  and connecting to the MapBean.
*/
public class ProjectionStack extends OMComponent
    implements ActionListener, ProjectionListener {

    public final static int DEFAULT_MAX_SIZE = 10;
    public final static int REMEMBER_ALL = -1;
    /**
     * The currentProjection should be the top item on the backStack.
     */
    protected transient ProjHolder currentProjection;
    protected transient String currentProjectionID;
    protected transient Container face;
    protected transient MapBean mapBean;
    protected int stackSize = DEFAULT_MAX_SIZE;

    public final static transient String BackProjCmd = "backProjection";
    public final static transient String ForwardProjCmd = "forwardProjection";
    public final static transient String ClearBackStackCmd = "clearBackStack";
    public final static transient String ClearForwardStackCmd = "clearForwardStack";
    public final static transient String ClearStacksCmd = "clearStacks";

    protected Stack backStack;
    protected Stack forwardStack;

    protected ProjectionStackSupport triggers;

    /**
     * Create the projection submenu.
     */
    public ProjectionStack() {}

    public void setMapBean(MapBean map) {
        if (mapBean != null) {
            mapBean.removeProjectionListener(this);
        }

        if (map != null) {
            map.addProjectionListener(this);
        }
        mapBean = map;
    }

    public MapBean getMapBean() {
        return mapBean;
    }

    public void actionPerformed(ActionEvent ae) {
        String command = ae.getActionCommand().intern();
       
        Debug.message("projectionstack",
                      "ProjectionStack.actionPerformed(): " + command);

        boolean changeProjection = false;

        //  This is important.  We need to set the current projection
        //  before setting the projection in the MapBean.  That way,
        //  the projectionChanged method actions won't get fired
        if (command == BackProjCmd &&
            backStack != null &&
            backStack.size() > 1) {

            pop();
            currentProjection = (ProjHolder)backStack.peek();
            changeProjection = true;
        } else if (command == ForwardProjCmd &&
                   forwardStack != null &&
                   !forwardStack.empty()) {
           
            currentProjection = backPop();
            changeProjection = true;
        } else {
            clearStacks((command == ClearBackStackCmd || command == ClearStacksCmd),
                        (command == ClearForwardStackCmd || command == ClearStacksCmd));
            // fireStackStatus is called in clearStacks
        }

        if (changeProjection && mapBean != null) {
            if (Debug.debugging("projectionstack")) {
                Debug.output("ProjectionStack.actionPerformed() changing mapbean projection to : " + currentProjection);
            }

            Projection currProj =
                currentProjection.create(mapBean.getWidth(),
                                         mapBean.getHeight());
            mapBean.setProjection(currProj);
            fireStackStatus();
        }
    }
 
    //------------------------------------------------------------
    // ProjectionListener interface
    //------------------------------------------------------------
   
    /**
     * The Map projection has changed.
     * @param e ProjectionEvent
     */
    public void projectionChanged(ProjectionEvent e) {
        if (Debug.debugging("projectionstack")) {
            System.out.println("ProjectionStack.projectionChanged()");
        }
        Projection newProj = e.getProjection();
        // If the ProjectionStack doesn't already know about the
        // projection change, that means that it didn't instigate it,
        // and the new projection needs to get added to the stack,
        // with the forwardStack cleared.
        if (currentProjection == null || !currentProjection.equals(newProj)) {
            Debug.message("projectionstack", "ProjectionStack.projectionChanged() pushing projection on backStack");
            // push on the backStack, clear the forwardStack;
            currentProjection = push(new ProjHolder(newProj));
            if (forwardStack != null) {
                forwardStack.clear();
            }
            fireStackStatus();
        } else {
            Debug.message("projectionstack", "ProjectionStack.projectionChanged() new projection matches current projection, no action.");
        }
    }
   
    /**
     * Clear out the chosen projection stacks and fire an event to
     * update the triggers on stack status.
     * @param clearBackStack clear out the backward projection stack.
     * @param clearForwardStack clear out the forward projection stack.
     */
    public synchronized void clearStacks(boolean clearBackStack,
                                         boolean clearForwardStack) {

        if (clearBackStack && backStack != null) {
            ProjHolder currentProj = pop(); // current projection
            backStack.clear();
            push(currentProj);
        }

        if (clearForwardStack && forwardStack != null) {
            forwardStack.clear();
        }
        fireStackStatus();
    }

    /**
     * Take a ProjHolder off the backStack, and push it on the forward
     * stack.
     * @return the ProjHolder pushed onto the forwardStack.
     */
    protected synchronized ProjHolder pop() {
        ProjHolder proj = (ProjHolder)backStack.pop();

        if (forwardStack == null) {
            forwardStack = new Stack();
        }

        while (forwardStack.size() >= stackSize) {
            forwardStack.removeElementAt(0);
        }
        forwardStack.push(proj);
        return proj;
    }

    /**
     * Take a ProjHolder off the forwardStack, and push it on the backStack.
     * @return the ProjHolder pushed on the backStack.
     */
    protected synchronized ProjHolder backPop() {
        ProjHolder proj = (ProjHolder)forwardStack.pop();

        // This has almost no chance of happening...
        if (backStack == null) {
            backStack = new Stack();
        }

        while (backStack.size() >= stackSize) {
            backStack.removeElementAt(0);
        }
        backStack.push(proj);
        return proj;
    }
   
    /**
     * Put a new ProjHolder on the backStack, to remember for later in
     * case we need to back up.
     * @param proj ProjHolder.
     * @return the ProjHolder pushed on the backStack.
     */
    protected synchronized ProjHolder push(ProjHolder proj) {
        if (backStack == null) {
            backStack = new Stack();
        }

        if (backStack.size() >= stackSize) {
            backStack.removeElementAt(0);
        }
        return (ProjHolder)backStack.push(proj);
    }

    public void fireStackStatus() {
        fireStackStatus((backStack != null && backStack.size() > 1),
                        (forwardStack != null && !forwardStack.empty()));
    }

    public void fireStackStatus(boolean enableBackButton,
                                boolean enableForwardButton) {
        if (triggers != null) {
            if (Debug.debugging("projectionstack")) {
                Debug.output("ProjectionStack.fireStackStatus(" +
                             enableBackButton +
                             ", " + enableForwardButton + ")");
            }
            triggers.fireStackStatus(enableBackButton, enableForwardButton);
        }
    }

    /**
     * ProjectionStackTriggers should call this method, and all will be well.
     */
    public void addProjectionStackTrigger(ProjectionStackTrigger trigger) {
        trigger.addActionListener(this);
        if (triggers == null) {
            triggers = new ProjectionStackSupport();
        }
        triggers.add(trigger);
        trigger.updateProjectionStackStatus((backStack != null && backStack.size() > 1), (forwardStack != null && !forwardStack.empty()));
    }

    /**
     * ProjectionStackTriggers should call this method, and all will be well.
     */
    public void removeProjectionStackTrigger(ProjectionStackTrigger trigger) {
        trigger.removeActionListener(this);
        if (triggers != null) {
            triggers.remove(trigger);
            if (triggers.size() == 0) {
                triggers = null;
            }
        }
    }

    //------------------------------------------------------------
    // BeanContextMembershipListener and BeanContextChild interface
    //------------------------------------------------------------

    /**
     * Look at the object received in a MapHandler status message and
     * disconnect from it if necessary. 
     */
    public void findAndUndo(Object someObj) {
        if (someObj instanceof com.bbn.openmap.MapBean) {
            Debug.message("projectionstack","ProjectionStack removing a MapBean.");
            MapBean map = getMapBean();
            if (map != null && map == (MapBean)someObj) {
                setMapBean(null);
            }
        }
    }
 
    /**
     * Look at the object received in a MapHandler status message and
     * connect to it if necessary. 
     */
    public void findAndInit(Object someObj) {
        if (someObj instanceof com.bbn.openmap.MapBean) {
            Debug.message("projectionstack","ProjectionStack found a MapBean.");
            setMapBean((MapBean)someObj);
        }
    }

    public class ProjHolder {

        public Class projClass;
        public float scale;
        public LatLonPoint center;
        protected Point tmpPoint1;
        protected Point tmpPoint2;

        public ProjHolder(Projection proj) {
            projClass = proj.getClass();
            scale = proj.getScale();
            center = proj.getCenter();
        }

        public boolean equals(Projection proj) {
            // For some reason, the ProjectionFactory can mess up the
            // center lat/lons, so that the center isn't EXACTLY what
            // they were when the projection was created.  It's almost
            // like it decides what map it can draw, and then figures
            // out what the coordinate of the center pixel of the
            // projection it created was.  Doing this projection hack
            // seems to accurately determine what projections are
            // acutally identical visually, which is what you want to
            // know anyway.
            Point tmpPoint1 = proj.forward(proj.getCenter());
            Point tmpPoint2 = proj.forward(center);

            boolean same = (projClass == proj.getClass() &&
                            scale == proj.getScale() &&

                            // NOT GOOD ENOUGH!  Sometimes, the
                            // slighest difference causes a false
                            // false.

//                          MoreMath.approximately_equal(center.getLatitude(),
//                                                       proj.getCenter().getLatitude(),
//                                                       .00001f) &&
//                          MoreMath.approximately_equal(center.getLongitude(),
//                                                       proj.getCenter().getLongitude(),
//                                                       .00001f)
                            // This seems to work...
                            tmpPoint1.x == tmpPoint2.x && tmpPoint1.y == tmpPoint2.y
                            );
            return same;
        }

        public Projection create(int width, int height) {
            return ProjectionFactory.makeProjection(projClass,
                                                    center.getLatitude(),
                                                    center.getLongitude(),
                                                    scale, width, height);
        }

        public String toString() {
            return ("[ProjHolder: class(" + projClass.getName() + "), scale(" +
                    scale + "), center(" + center + ")]");
        }

    }
}






TOP

Related Classes of com.bbn.openmap.proj.ProjectionStack$ProjHolder

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.