diff --git a/pom.xml b/pom.xml index 154db72e0..3ba816ee4 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,18 @@ A Java Beans based toolkit for building applications and applets needing geographic information http://openmap-java.org + + UTF-8 + 11 + 11 + 2.15.2 + 1.16 + 5.10.0 + 42.7.8 + 2023.1.0 + 3.43.0.0 + + OpenMap Software License @@ -48,23 +60,206 @@ JBoss Thirdparty Releases https://repository.jboss.org/nexus/content/repositories/thirdparty-releases + + central + Maven Central Repository + https://repo1.maven.org/maven2/ + + true + + + false + + + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + org.apache.xmlgraphics + batik-svg-dom + ${batik.version} + + + org.apache.xmlgraphics + batik-rasterizer + ${batik.version} + + + org.apache.xmlgraphics + batik-swing + ${batik.version} + + + org.apache.xmlgraphics + batik-transcoder + ${batik.version} + + + org.apache.xmlgraphics + batik-svggen + ${batik.version} + + + org.apache.xmlgraphics + batik-util + ${batik.version} + + + org.apache.xmlgraphics + batik-dom + ${batik.version} + + + org.apache.xmlgraphics + batik-bridge + ${batik.version} + + + org.apache.xmlgraphics + batik-css + ${batik.version} + + + org.apache.xmlgraphics + batik-codec + ${batik.version} + + + org.apache.xmlgraphics + batik-awt-util + ${batik.version} + + + org.apache.xmlgraphics + batik-ext + ${batik.version} + + + org.apache.xmlgraphics + batik-extension + ${batik.version} + + + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit.version} + test + + + + + org.postgresql + postgresql + ${postgresql.version} + + + org.postgis + postgis-jdbc + ${postgis.version} + + + org.xerial + sqlite-jdbc + ${sqlite.version} + + + + + jakarta.servlet + jakarta.servlet-api + 5.0.0 + provided + + + com.sun.media + jai-codec + 1.1.3 + + + xtiff-jai + xtiff-jai + beta-0.3 + + + jai + jai-codec + + + jai + jai-core + + + + + edu.stanford.ejalbert + BrowserLauncher2 + 1.3 + + + no.ecc.vectortile + java-vector-tile + 1.0.8 + + + java3d + j3d-core-utils + 1.3.1 + + + xml-apis + xml-apis + 1.4.01 + + + + org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.11.0 - 1.7 - 1.7 + 11 org.apache.maven.plugins maven-release-plugin - 2.4.1 + 3.0.1 true @@ -86,9 +281,10 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.6.0 - false + false + private @@ -103,11 +299,11 @@ org.apache.maven.plugins maven-dependency-plugin - 3.1.1 + 3.6.1 copy-dependencies - deploy + package copy-dependencies @@ -116,17 +312,39 @@ - net.ju-n.maven.plugins - checksum-maven-plugin - 1.2 - - - - artifacts - - - - + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + enforce-maven + + enforce + + + + + 3.6.0 + + + 11 + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + diff --git a/src/core/pom.xml b/src/core/pom.xml index 21c51c1a7..d02931059 100644 --- a/src/core/pom.xml +++ b/src/core/pom.xml @@ -2,17 +2,27 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 + + org.openmap-java + openmap-all + 6.0-SNAPSHOT + ../../pom.xml + + openmap - org.openmap-java - 6.0-SNAPSHOT jar openmap - OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information. This project encapsulates the core components of the toolkit. + OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information. This project encapsulates the core components of the toolkit. http://github.com/OpenMap-java/openmap + UTF-8 - 1.7 - 1.7 + 2.15.2 + 1.16 + 5.10.0 + 42.7.8 + 2023.1.0 + 3.43.0.0 @@ -43,46 +53,52 @@ 1.3 - junit - junit - 4.8.2 + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit.version} test com.fasterxml.jackson.core jackson-core - 2.5.3 + ${jackson.version} com.fasterxml.jackson.core jackson-annotations - 2.5.3 + ${jackson.version} com.fasterxml.jackson.core jackson-databind - 2.5.3 + ${jackson.version} - org.postgis + net.postgis postgis-jdbc - 1.3.3 - - - org.postgis - postgis-stubs - - + ${postgis.version} - org.ancoron.postgresql - org.postgresql - 9.1.901.jdbc4.1-rc9 + org.postgresql + postgresql + ${postgresql.version} org.xerial sqlite-jdbc - 3.8.11.2 + ${sqlite.version} no.ecc.vectortile @@ -97,98 +113,89 @@ org.apache.xmlgraphics batik-svg-dom - 1.7 + ${batik.version} org.apache.xmlgraphics batik-rasterizer - 1.7 + ${batik.version} org.apache.xmlgraphics batik-swing - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-transcoder - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-svggen - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-util - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-dom - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-bridge - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-css - 1.7 + ${batik.version} - org.apache.xmlgraphics batik-codec - 1.7 - - - - org.apache.xmlgraphics - batik-awt-util - 1.7 - - - - org.apache.xmlgraphics - batik-ext - 1.7 - - - - org.apache.xmlgraphics - batik-extension - 1.7 + ${batik.version} xml-apis xml-apis 1.4.01 + + jakarta.servlet + jakarta.servlet-api + 5.0.0 + provided + - - + + central + Maven Central Repository + https://repo1.maven.org/maven2/ + + true + + + false + + + ECC https://github.com/ElectronicChartCentre/ecc-mvn-repo/raw/master/releases + - @@ -235,7 +242,14 @@ - + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 8 + + diff --git a/src/core/src/main/java/com/bbn/openmap/MapBean.java b/src/core/src/main/java/com/bbn/openmap/MapBean.java index bf7758a08..70ca19c68 100644 --- a/src/core/src/main/java/com/bbn/openmap/MapBean.java +++ b/src/core/src/main/java/com/bbn/openmap/MapBean.java @@ -19,9 +19,29 @@ // $Author: dietrick $ // // ********************************************************************** - package com.bbn.openmap; +import com.bbn.openmap.event.CenterEvent; +import com.bbn.openmap.event.CenterListener; +import com.bbn.openmap.event.LayerEvent; +import com.bbn.openmap.event.LayerListener; +import com.bbn.openmap.event.PaintListener; +import com.bbn.openmap.event.PaintListenerSupport; +import com.bbn.openmap.event.PanEvent; +import com.bbn.openmap.event.PanListener; +import com.bbn.openmap.event.ProjectionChangeVetoException; +import com.bbn.openmap.event.ProjectionEvent; +import com.bbn.openmap.event.ProjectionListener; +import com.bbn.openmap.event.ProjectionSupport; +import com.bbn.openmap.event.ZoomEvent; +import com.bbn.openmap.event.ZoomListener; +import com.bbn.openmap.geo.Geo; +import com.bbn.openmap.proj.Mercator; +import com.bbn.openmap.proj.Proj; +import com.bbn.openmap.proj.Projection; +import com.bbn.openmap.proj.ProjectionFactory; +import com.bbn.openmap.proj.coords.LatLonPoint; +import com.bbn.openmap.util.Debug; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; @@ -32,6 +52,7 @@ import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Paint; +import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.ComponentEvent; @@ -51,32 +72,9 @@ import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; - import javax.swing.JComponent; import javax.swing.OverlayLayout; -import com.bbn.openmap.event.CenterEvent; -import com.bbn.openmap.event.CenterListener; -import com.bbn.openmap.event.LayerEvent; -import com.bbn.openmap.event.LayerListener; -import com.bbn.openmap.event.PaintListener; -import com.bbn.openmap.event.PaintListenerSupport; -import com.bbn.openmap.event.PanEvent; -import com.bbn.openmap.event.PanListener; -import com.bbn.openmap.event.ProjectionChangeVetoException; -import com.bbn.openmap.event.ProjectionEvent; -import com.bbn.openmap.event.ProjectionListener; -import com.bbn.openmap.event.ProjectionSupport; -import com.bbn.openmap.event.ZoomEvent; -import com.bbn.openmap.event.ZoomListener; -import com.bbn.openmap.geo.Geo; -import com.bbn.openmap.proj.Mercator; -import com.bbn.openmap.proj.Proj; -import com.bbn.openmap.proj.Projection; -import com.bbn.openmap.proj.ProjectionFactory; -import com.bbn.openmap.proj.coords.LatLonPoint; -import com.bbn.openmap.util.Debug; - /** * The MapBean is the main component of the OpenMap Development Kit. It is a * Java Bean that manages and displays a map. A map is comprised of a projection @@ -124,1682 +122,1697 @@ * another round of projection change notifications. The ProjectionListeners * only receive notification of Projections that have passed through the * PropertyChangeListeners. - * + * * @see Layer */ public class MapBean extends JComponent implements ComponentListener, ContainerListener, ProjectionListener, - PanListener, ZoomListener, LayerListener, CenterListener, SoloMapComponent { + PanListener, ZoomListener, LayerListener, CenterListener, SoloMapComponent { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private static Logger logger = Logger.getLogger(MapBean.class.getName()); + private static Logger logger = Logger.getLogger(MapBean.class.getName()); - public static final String LayersProperty = "MapBean.layers"; + public static final String LayersProperty = "MapBean.layers"; - public static final String CursorProperty = "MapBean.cursor"; + public static final String CursorProperty = "MapBean.cursor"; - public static final String BackgroundProperty = "MapBean.background"; + public static final String BackgroundProperty = "MapBean.background"; - public static final String ProjectionProperty = "MapBean.projection"; + public static final String ProjectionProperty = "MapBean.projection"; - public static final String ProjectionVetoedProperty = "MapBean.projectionVetoed"; + public static final String ProjectionVetoedProperty = "MapBean.projectionVetoed"; - /** - * OpenMap title. - */ - public static final String title = "OpenMap(tm)"; + /** + * OpenMap title. + */ + public static final String title = "OpenMap(tm)"; - /** - * OpenMap version. - */ - public static final String version = "6.0b"; + /** + * OpenMap version. + */ + public static final String version = "6.1b"; - /** - * Suppress the copyright message on initialization. - */ - public static boolean suppressCopyright = false; + /** + * Suppress the copyright message on initialization. + */ + public static boolean suppressCopyright = false; - private static boolean DEBUG_TIMESTAMP = false; - - private static boolean DEBUG_THREAD = true; - - private static final String copyrightNotice = "OpenMap(tm) Version " + version + "\r\n" - + " Copyright (C) BBNT Solutions LLC. All rights reserved.\r\n" - + " See http://openmap-java.org/ for details.\r\n"; - - public final static float DEFAULT_CENTER_LAT = 0.0f; - - public final static float DEFAULT_CENTER_LON = 0.0f; - - // zoomed all the way out - public final static float DEFAULT_SCALE = Float.MAX_VALUE; - - public final static int DEFAULT_WIDTH = 640; - - public final static int DEFAULT_HEIGHT = 480; - - protected int minHeight = 100; - - protected int minWidth = 100; - - protected Proj projection = new Mercator(new LatLonPoint.Double(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON), - DEFAULT_SCALE, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - protected final ProjectionSupport projectionSupport; - - /** - * Layers that are removed from the MapBean are held until the next - * projection change. When the projection changes, they are notified that - * they have been removed from the map. This list is kept so that toggling a - * layer on and off won't cause them to get rid of their resources, in case - * the user is just creating different views of the map. - */ - protected final Vector removedLayers = new Vector(0); - - /** - * Some users may want the layers deleted immediately when they are removed - * from the map. This flag controls that. The default behavior is to hold a - * reference to a layer and actually release it when the projection changes - * (default = true). Set to false if you want the MapBean to tell a Layer it - * has been removed immediately when it happens. - */ - protected boolean layerRemovalDelayed = true; - - /** - * This vector is to let the layers know when they have been added to the - * map. - */ - protected final Vector addedLayers = new Vector(0); - - /** - * The PaintListeners want to know when the map has been repainted. - */ - protected final PaintListenerSupport painters; - - /** - * The background color for this particular MapBean. If null, the setting - * for the projection, which in turn is set in the Environment class, will - * be used. - */ - protected Paint background = null; - - /** - * The MapBeanRepaintPolicy to use to handler/filter/pace layer repaint() - * requests. If not set, a StandardMapBeanRepaintPolicy will be used, which - * forwards repaint requests to Swing normally. - */ - protected MapBeanRepaintPolicy repaintPolicy = null; - /** - * The MapBeanBackgroundPolicy is used to manipulate/manage the background - * paint. - */ - protected MapBeanBackgroundPolicy backgroundPolicy = null; - /** - * The angle, in radians, to rotate the map. 0.0 is north-up, clockwise is - * positive. - */ - protected double rotationAngle = 0; - - public final static Color DEFAULT_BACKGROUND_COLOR = new Color(191, 239, 255); - - /** - * Return the OpenMap Copyright message. - * - * @return String Copyright - */ - public static String getCopyrightMessage() { - return copyrightNotice; - } - - /** - * Construct a MapBean. - */ - public MapBean() { - this(true); - } - - @SuppressWarnings("serial") - public MapBean(boolean useThreadedNotification) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("MapBean()"); - } - if (!suppressCopyright) { - Debug.output(copyrightNotice); - } - - background = DEFAULT_BACKGROUND_COLOR; - - // Don't need one for every MapBean, just the first one. - suppressCopyright = true; - - super.setLayout(new OverlayLayout(this)); - projectionSupport = new ProjectionSupport(this, useThreadedNotification); - addComponentListener(this); - addContainerListener(this); - - painters = new PaintListenerSupport(this); - - // ---------------------------------------- - // In a builder tool it seems that the OverlayLayout - // makes the MapBean fail to resize. And since it has - // no children by default, it has no size. So I add - // a null Layer here to give it a default size. - // ---------------------------------------- - if (java.beans.Beans.isDesignTime()) { - add(new Layer() { - public void projectionChanged(ProjectionEvent e) { - } - - public Dimension getPreferredSize() { - return new Dimension(100, 100); - } - }); - } - - setPreferredSize(new Dimension(projection.getWidth(), projection.getHeight())); - - DEBUG_TIMESTAMP = logger.isLoggable(Level.FINER); - DEBUG_THREAD = logger.isLoggable(Level.FINER); - } - - /** - * Return a string-ified representation of the MapBean. - * - * @return String representing mapbean. - */ - public String toString() { - return getClass().getName() + "@" + Integer.toHexString(hashCode()); - } - - /** - * Call when getting rid of the MapBean, it releases pointers to all - * listeners and kills the ProjectionSupport thread. - */ - public void dispose() { - setLayerRemovalDelayed(false); - - projectionSupport.dispose(); - painters.clear(); - addedLayers.removeAllElements(); - - currentLayers = null; - projectionFactory = null; - - removeComponentListener(this); - removeContainerListener(this); - removeAll(); - purgeAndNotifyRemovedLayers(); - } - - /*---------------------------------------------------------------------- + private static boolean DEBUG_TIMESTAMP = false; + + private static boolean DEBUG_THREAD = true; + + private static final String copyrightNotice = "OpenMap(tm) Version " + version + "\r\n" + + " Copyright (C) BBNT Solutions LLC. All rights reserved.\r\n" + + " See http://openmap-java.org/ for details.\r\n"; + + public final static float DEFAULT_CENTER_LAT = 0.0f; + + public final static float DEFAULT_CENTER_LON = 0.0f; + + // zoomed all the way out + public final static float DEFAULT_SCALE = Float.MAX_VALUE; + + public final static int DEFAULT_WIDTH = 640; + + public final static int DEFAULT_HEIGHT = 480; + + protected int minHeight = 100; + + protected int minWidth = 100; + + protected Proj projection = new Mercator(new LatLonPoint.Double(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON), + DEFAULT_SCALE, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + protected final ProjectionSupport projectionSupport; + + /** + * Layers that are removed from the MapBean are held until the next + * projection change. When the projection changes, they are notified that + * they have been removed from the map. This list is kept so that toggling a + * layer on and off won't cause them to get rid of their resources, in case + * the user is just creating different views of the map. + */ + protected final Vector removedLayers = new Vector(0); + + /** + * Some users may want the layers deleted immediately when they are removed + * from the map. This flag controls that. The default behavior is to hold a + * reference to a layer and actually release it when the projection changes + * (default = true). Set to false if you want the MapBean to tell a Layer it + * has been removed immediately when it happens. + */ + protected boolean layerRemovalDelayed = true; + + /** + * This vector is to let the layers know when they have been added to the + * map. + */ + protected final Vector addedLayers = new Vector(0); + + /** + * The PaintListeners want to know when the map has been repainted. + */ + protected final PaintListenerSupport painters; + + /** + * The background color for this particular MapBean. If null, the setting + * for the projection, which in turn is set in the Environment class, will + * be used. + */ + protected Paint background = null; + + /** + * The MapBeanRepaintPolicy to use to handler/filter/pace layer repaint() + * requests. If not set, a StandardMapBeanRepaintPolicy will be used, which + * forwards repaint requests to Swing normally. + */ + protected MapBeanRepaintPolicy repaintPolicy = null; + /** + * The MapBeanBackgroundPolicy is used to manipulate/manage the background + * paint. + */ + protected MapBeanBackgroundPolicy backgroundPolicy = null; + /** + * The angle, in radians, to rotate the map. 0.0 is north-up, clockwise is + * positive. + */ + protected double rotationAngle = 0; + + public final static Color DEFAULT_BACKGROUND_COLOR = new Color(191, 239, 255); + + /** + * Return the OpenMap Copyright message. + * + * @return String Copyright + */ + public static String getCopyrightMessage() { + return copyrightNotice; + } + + /** + * Construct a MapBean. + */ + public MapBean() { + this(true); + } + + @SuppressWarnings("serial") + public MapBean(boolean useThreadedNotification) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("MapBean()"); + } + if (!suppressCopyright) { + Debug.output(copyrightNotice); + } + + background = DEFAULT_BACKGROUND_COLOR; + + // Don't need one for every MapBean, just the first one. + suppressCopyright = true; + + super.setLayout(new OverlayLayout(this)); + projectionSupport = new ProjectionSupport(this, useThreadedNotification); + addComponentListener(this); + addContainerListener(this); + + painters = new PaintListenerSupport(this); + + // ---------------------------------------- + // In a builder tool it seems that the OverlayLayout + // makes the MapBean fail to resize. And since it has + // no children by default, it has no size. So I add + // a null Layer here to give it a default size. + // ---------------------------------------- + if (java.beans.Beans.isDesignTime()) { + add(new Layer() { + public void projectionChanged(ProjectionEvent e) { + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + }); + } + + setPreferredSize(new Dimension(projection.getWidth(), projection.getHeight())); + + DEBUG_TIMESTAMP = logger.isLoggable(Level.FINER); + DEBUG_THREAD = logger.isLoggable(Level.FINER); + } + + /** + * Return a string-ified representation of the MapBean. + * + * @return String representing mapbean. + */ + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } + + /** + * Call when getting rid of the MapBean, it releases pointers to all + * listeners and kills the ProjectionSupport thread. + */ + public void dispose() { + setLayerRemovalDelayed(false); + + projectionSupport.dispose(); + painters.clear(); + addedLayers.removeAllElements(); + + currentLayers = null; + projectionFactory = null; + + removeComponentListener(this); + removeContainerListener(this); + removeAll(); + purgeAndNotifyRemovedLayers(); + } + + /*---------------------------------------------------------------------- * Window System overrides *----------------------------------------------------------------------*/ - - /** - * Adds additional constraints on possible children components. The new - * component must be a Layer. This method included as a good container - * citizen, and should not be called directly. Use the add() methods - * inherited from java.awt.Container instead. - * - * @param comp Component - * @param constraints Object - * @param index int location - */ - protected final void addImpl(Component comp, Object constraints, int index) { - if (comp instanceof Layer) { - super.addImpl(comp, constraints, index); - } else { - throw new IllegalArgumentException("only Layers can be added to a MapBean"); - } - } - - /** - * Prevents changing the LayoutManager. Don't let anyone change the - * LayoutManager! This is called by the parent component and should not be - * called directly. - */ - public final void setLayout(LayoutManager mgr) { - throw new IllegalArgumentException("cannot change layout of Map"); - } - - /** - * Return the minimum size of the MapBean window. Included here to be a good - * citizen. - */ - public Dimension getMinimumSize() { - return new Dimension(minWidth, minHeight); - } - - /** - * Set the minimum size of the MapBean window. Included here to be a good - * citizen. - */ - public void setMinimumSize(Dimension dim) { - minWidth = (int) dim.getWidth(); - minHeight = (int) dim.getHeight(); - } - - /** - * Get the Insets of the MapBean. This returns 0-length Insets. - *

- * This makes sure that there will be no +x,+y offset when drawing graphics. - * This is ok since any borders around the MapBean will get drawn afterwards - * on top. - * - * @return Insets 0-length Insets - */ - public final Insets getInsets() { - return insets; - } - - private final transient static Insets insets = new Insets(0, 0, 0, 0); - - /*---------------------------------------------------------------------- + /** + * Adds additional constraints on possible children components. The new + * component must be a Layer. This method included as a good container + * citizen, and should not be called directly. Use the add() methods + * inherited from java.awt.Container instead. + * + * @param comp Component + * @param constraints Object + * @param index int location + */ + protected final void addImpl(Component comp, Object constraints, int index) { + if (comp instanceof Layer) { + super.addImpl(comp, constraints, index); + } else { + throw new IllegalArgumentException("only Layers can be added to a MapBean"); + } + } + + /** + * Prevents changing the LayoutManager. Don't let anyone change the + * LayoutManager! This is called by the parent component and should not be + * called directly. + */ + public final void setLayout(LayoutManager mgr) { + throw new IllegalArgumentException("cannot change layout of Map"); + } + + /** + * Return the minimum size of the MapBean window. Included here to be a good + * citizen. + */ + public Dimension getMinimumSize() { + return new Dimension(minWidth, minHeight); + } + + /** + * Set the minimum size of the MapBean window. Included here to be a good + * citizen. + */ + public void setMinimumSize(Dimension dim) { + minWidth = (int) dim.getWidth(); + minHeight = (int) dim.getHeight(); + } + + /** + * Get the Insets of the MapBean. This returns 0-length Insets. + *

+ * This makes sure that there will be no +x,+y offset when drawing graphics. + * This is ok since any borders around the MapBean will get drawn afterwards + * on top. + * + * @return Insets 0-length Insets + */ + public final Insets getInsets() { + return insets; + } + + private final transient static Insets insets = new Insets(0, 0, 0, 0); + + /*---------------------------------------------------------------------- * ComponentListener implementation *----------------------------------------------------------------------*/ - - /** - * ComponentListener interface method. Should not be called directly. - * Invoked when component has been resized, and kicks off a projection - * change. - * - * @param e ComponentEvent - */ - public void componentResized(ComponentEvent e) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Size changed: " + getWidth() + " x " + getHeight()); - } - - projection.setWidth(getWidth()); - projection.setHeight(getHeight()); - fireProjectionChanged(); - } - - /** - * ComponentListener interface method. Should not be called directly. - * Invoked when component has been moved. - * - * @param e ComponentEvent - */ - public void componentMoved(ComponentEvent e) { - } - - /** - * ComponentListener interface method. Should not be called directly. - * Invoked when component has been shown. - * - * @param e ComponentEvent - */ - public void componentShown(ComponentEvent e) { - } - - /** - * ComponentListener interface method. Should not be called directly. - * Invoked when component has been hidden. - * - * @param e ComponentEvent - */ - public void componentHidden(ComponentEvent e) { - } - - /*---------------------------------------------------------------------- + /** + * ComponentListener interface method. Should not be called directly. + * Invoked when component has been resized, and kicks off a projection + * change. + * + * @param e ComponentEvent + */ + public void componentResized(ComponentEvent e) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Size changed: " + getWidth() + " x " + getHeight()); + } + + projection.setWidth(getWidth()); + projection.setHeight(getHeight()); + fireProjectionChanged(); + } + + /** + * ComponentListener interface method. Should not be called directly. + * Invoked when component has been moved. + * + * @param e ComponentEvent + */ + public void componentMoved(ComponentEvent e) { + } + + /** + * ComponentListener interface method. Should not be called directly. + * Invoked when component has been shown. + * + * @param e ComponentEvent + */ + public void componentShown(ComponentEvent e) { + } + + /** + * ComponentListener interface method. Should not be called directly. + * Invoked when component has been hidden. + * + * @param e ComponentEvent + */ + public void componentHidden(ComponentEvent e) { + } + + /*---------------------------------------------------------------------- * *----------------------------------------------------------------------*/ - - /** - * Add a ProjectionListener to the MapBean. You do not need to call this - * method to add layers as ProjectionListeners. This method is called for - * the layer when it is added to the MapBean. Use this method for other - * objects that you want to know about the MapBean's projection. - * - * @param l ProjectionListener - */ - public synchronized void addProjectionListener(ProjectionListener l) { - projectionSupport.add(l); - - // Assume the listener wants the current projection - try { - l.projectionChanged(new ProjectionEvent(this, getRotatedProjection())); - } catch (Exception e) { - if (logger.isLoggable(Level.FINER)) { - logger.fine("ProjectionListener not handling projection well: " + l.getClass().getName() + " : " - + e.getClass().getName() + " : " + e.getMessage()); - e.printStackTrace(); - } - } - } - - /** - * Remove a ProjectionListener from the MapBean. You do not need to call - * this method to remove layers that are ProjectionListeners. This method is - * called for the layer when it is removed from the MapBean. Use this method - * for other objects that you want to remove from receiving projection - * events. - * - * @param l ProjectionListener - */ - public synchronized void removeProjectionListener(ProjectionListener l) { - projectionSupport.remove(l); - } - - /** - * Called from within the MapBean when its projection listeners need to know - * about a projection change. - */ - protected void fireProjectionChanged() { - - // This handles setting up the RotationHelper if it's needed. - Projection proj = getRotatedProjection(); - - // Fire the property change, so the messages get cleared out. - // Then, if any of the layers have a problem with their new - // projection, their messages will be displayed. - if (logger.isLoggable(Level.FINE)) { - logger.fine("MapBean firing projection property change, vetoable: " + proj); - } - try { - firePropertyChange(ProjectionProperty, null, proj); - } catch (ProjectionChangeVetoException pcve) { - firePropertyChange(ProjectionVetoedProperty, proj, pcve); - pcve.updateWithParameters(this); - return; - } - - // Mark the layers as dirty, as a group, before notifying them of a - // projection change. They will mark themselves clean when they call - // repaint. - for (Component c : getComponents()) { - Layer l = (Layer) c; - if (l != null) { - // Weird, I know, but I've seen c be null and throw an - // exception here. - l.setReadyToPaint(false); - } - } - - projectionSupport.fireProjectionChanged(proj); - purgeAndNotifyRemovedLayers(); - } - - /** - * Clear the vector containing all of the removed layers, and let those - * layers know they have been removed from the map. - */ - public void purgeAndNotifyRemovedLayers() { - // Tell any layers that have been removed that they have - // been removed - - ArrayList rLayers = new ArrayList(removedLayers); - removedLayers.clear(); - - if (rLayers.isEmpty()) { - return; - } - for (Layer layer : rLayers) { - layer.removed(this); - } - - // Shouldn't call this, but it's the only thing - // that seems to make it work... - // Seems to help gc'ing layers in a timely manner. - if (Debug.debugging("helpgc")) { - System.gc(); - } - } - - /*---------------------------------------------------------------------- + /** + * Add a ProjectionListener to the MapBean. You do not need to call this + * method to add layers as ProjectionListeners. This method is called for + * the layer when it is added to the MapBean. Use this method for other + * objects that you want to know about the MapBean's projection. + * + * @param l ProjectionListener + */ + public synchronized void addProjectionListener(ProjectionListener l) { + projectionSupport.add(l); + + // Assume the listener wants the current projection + try { + l.projectionChanged(new ProjectionEvent(this, getRotatedProjection())); + } catch (Exception e) { + if (logger.isLoggable(Level.FINER)) { + logger.fine("ProjectionListener not handling projection well: " + l.getClass().getName() + " : " + + e.getClass().getName() + " : " + e.getMessage()); + e.printStackTrace(); + } + } + } + + /** + * Remove a ProjectionListener from the MapBean. You do not need to call + * this method to remove layers that are ProjectionListeners. This method is + * called for the layer when it is removed from the MapBean. Use this method + * for other objects that you want to remove from receiving projection + * events. + * + * @param l ProjectionListener + */ + public synchronized void removeProjectionListener(ProjectionListener l) { + projectionSupport.remove(l); + } + + /** + * Called from within the MapBean when its projection listeners need to know + * about a projection change. + */ + protected void fireProjectionChanged() { + + // This handles setting up the RotationHelper if it's needed. + Projection proj = getRotatedProjection(); + + // Fire the property change, so the messages get cleared out. + // Then, if any of the layers have a problem with their new + // projection, their messages will be displayed. + if (logger.isLoggable(Level.FINE)) { + logger.fine("MapBean firing projection property change, vetoable: " + proj); + } + try { + firePropertyChange(ProjectionProperty, null, proj); + } catch (ProjectionChangeVetoException pcve) { + firePropertyChange(ProjectionVetoedProperty, proj, pcve); + pcve.updateWithParameters(this); + return; + } + + // Mark the layers as dirty, as a group, before notifying them of a + // projection change. They will mark themselves clean when they call + // repaint. + for (Component c : getComponents()) { + Layer l = (Layer) c; + if (l != null) { + // Weird, I know, but I've seen c be null and throw an + // exception here. + l.setReadyToPaint(false); + } + } + + projectionSupport.fireProjectionChanged(proj); + purgeAndNotifyRemovedLayers(); + } + + /** + * Clear the vector containing all of the removed layers, and let those + * layers know they have been removed from the map. + */ + public void purgeAndNotifyRemovedLayers() { + // Tell any layers that have been removed that they have + // been removed + + ArrayList rLayers = new ArrayList(removedLayers); + removedLayers.clear(); + + if (rLayers.isEmpty()) { + return; + } + for (Layer layer : rLayers) { + layer.removed(this); + } + + // Shouldn't call this, but it's the only thing + // that seems to make it work... + // Seems to help gc'ing layers in a timely manner. + if (Debug.debugging("helpgc")) { + System.gc(); + } + } + + /*---------------------------------------------------------------------- * Properties *----------------------------------------------------------------------*/ - - /** - * Gets the scale of the map. - * - * @return float the current scale of the map - * @see Projection#getScale - */ - public float getScale() { - return projection.getScale(); - } - - /** - * Sets the scale of the map. The Projection may silently disregard this - * setting, setting it to a maxscale or minscale - * value. - * - * @param newScale the new scale - * @see Proj#setScale - */ - public void setScale(float newScale) { - projection.setScale(newScale); - fireProjectionChanged(); - } - - /** - * Gets the center of the map in the form of a LatLonPoint. - * - * @return the center point of the map - * @see Projection#getCenter - */ - public Point2D getCenter() { - return projection.getCenter(); - } - - /** - * Sets the center of the map. - * - * @param newCenter the center point of the map - * @see Proj#setCenter(Point2D) - */ - public void setCenter(Point2D newCenter) { - projection.setCenter(newCenter); - fireProjectionChanged(); - } - - /** - * Sets the center of the map. - * - * @param lat the latitude of center point of the map in decimal degrees - * @param lon the longitude of center point of the map in decimal degrees - * @see Proj#setCenter(double, double) - */ - public void setCenter(double lat, double lon) { - projection.setCenter(new Point2D.Double(lon, lat)); - fireProjectionChanged(); - } - - /** - * Sets the center of the map. - * - * @param lat the latitude of center point of the map in decimal degrees - * @param lon the longitude of center point of the map in decimal degrees - * @see Proj#setCenter(double, double) - */ - public void setCenter(float lat, float lon) { - setCenter((double) lat, (double) lon); - } - - /** - * Set the background color of the map. If the background for this MapBean - * is not null, the background of the projection will be used. - * - * @param color java.awt.Color. - */ - public void setBackgroundColor(Color color) { - setBackground(color); - } - - public void setBackground(Color color) { - super.setBackground(color); - setBckgrnd((Paint) color); - } - - /** - * We override this to set the paint mode on the Graphics before the border - * is painted, otherwise we get an XOR effect in the border. - */ - public void paintBorder(Graphics g) { - g.setPaintMode(); - super.paintBorder(g); - } - - /** - * Set the background of the map. If the background for this MapBean is not - * null, the background of the projection will be used. - * - * @param paint java.awt.Paint. - */ - public void setBckgrnd(Paint paint) { - setBufferDirty(true); - - // Instead, do this. - Paint oldBackground = background; - background = paint; - firePropertyChange(BackgroundProperty, oldBackground, background); - - repaint(); - } - - /** - * Get the background color of the map. If the background color for this - * MapBean has been explicitly set, that value will be returned. Otherwise, - * the background color of the projection will be returned. If the - * background is not a color (as opposed to Paint) this method will return - * null. - * - * @return color java.awt.Color. - */ - public Color getBackground() { - Paint ret = getBckgrnd(); - if (ret instanceof Color) { - return (Color) ret; - } - - return super.getBackground(); - } - - /** - * Get the background of the map. If the background for this MapBean has - * been explicitly set, that value will be returned. Otherwise, the - * background of the projection will be returned. - * - * @return color java.awt.Color. - */ - public Paint getBckgrnd() { - Paint ret = background; - - MapBeanBackgroundPolicy mbbp = backgroundPolicy; - if (mbbp != null) { - ret = mbbp.getBckgrnd(); - } - - if (ret == null) { - ret = super.getBackground(); - } - - return ret; - } - - /** - * Get the projection property, reflects the projection with no rotation. - * - * @return current Projection of map. - */ - public Projection getProjection() { - return projection; - } - - /** - * @return the expanded rotated projection if map rotated, normal projection - * if not rotated. The rotated projection is larger than the MapBean - * and has extra offsets. - */ - public Projection getRotatedProjection() { - RotationHelper rotation = getUpdatedRotHelper(); - Projection proj = rotation != null ? rotation.getProjection() : projection; - // Double check - ((Proj) proj).setRotationAngle(getRotationAngle()); - return proj; - } - - /** - * Set the projection. Shouldn't be null, and won't do anything if it is. - * - * @param aProjection Projection - */ - public void setProjection(Projection aProjection) { - if (aProjection != null && !aProjection.getProjectionID().contains("NaN")) { - setBufferDirty(true); - projection = (Proj) aProjection; - setPreferredSize(new Dimension(projection.getWidth(), projection.getHeight())); - fireProjectionChanged(); - } - } - - // ------------------------------------------------------------ - // CenterListener interface - // ------------------------------------------------------------ - - /** - * Handles incoming CenterEvents. - * - * @param evt the incoming center event - */ - public void center(CenterEvent evt) { - setCenter(evt.getLatitude(), evt.getLongitude()); - } - - // ------------------------------------------------------------ - // PanListener interface - // ------------------------------------------------------------ - - /** - * Handles incoming PanEvents. - * - * @param evt the incoming pan event - */ - public void pan(PanEvent evt) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("PanEvent: " + evt); - } - float az = evt.getAzimuth() - (float) Math.toDegrees(rotationAngle); - float c = evt.getArcDistance(); - if (Float.isNaN(c)) { - projection.pan(az); - } else { - projection.pan(az, c); - } - - fireProjectionChanged(); - } - - // ------------------------------------------------------------ - // ZoomListener interface - // ------------------------------------------------------------ - - /** - * Zoom the Map. Part of the ZoomListener interface. Sets the scale of the - * MapBean projection, based on a relative or absolute amount. - * - * @param evt the ZoomEvent describing the new scale. - */ - public void zoom(ZoomEvent evt) { - float newScale; - if (evt.isAbsolute()) { - newScale = evt.getAmount(); - } else if (evt.isRelative()) { - newScale = getScale() * evt.getAmount(); - } else { - return; - } - setScale(newScale); - } - - // ------------------------------------------------------------ - // ContainerListener interface - // ------------------------------------------------------------ - - protected transient Layer[] currentLayers = new Layer[0]; - - protected transient boolean doContainerChange = true; - - /** - * ContainerListener Interface method. Should not be called directly. Part - * of the ContainerListener interface, and it's here to make the MapBean a - * good Container citizen. - * - * @param value boolean - */ - public void setDoContainerChange(boolean value) { - // if changing from false to true, call changeLayers() - if (!doContainerChange && value) { - doContainerChange = value; - changeLayers(null); - } else { - doContainerChange = value; - } - } - - /** - * ContainerListener Interface method. Should not be called directly. Part - * of the ContainerListener interface, and it's here to make the MapBean a - * good Container citizen. - * - * @return boolean - */ - public boolean getDoContainerChange() { - return doContainerChange; - } - - /** - * ContainerListener Interface method. Should not be called directly. Part - * of the ContainerListener interface, and it's here to make the MapBean a - * good Container citizen. - * - * @param e ContainerEvent - */ - public void componentAdded(ContainerEvent e) { - // Blindly cast. addImpl has already checked to be - // sure the child is a Layer. - Layer childLayer = (Layer) e.getChild(); - addProjectionListener(childLayer); - - // If the new layer is in the queue to have removed() called - // on it take it off the queue, and don't add it to the - // added() queue (it doesn't know that it was removed, yet). - // Otherwise, add it to the queue to have added() called on - // it. - if (!removedLayers.removeElement(childLayer)) { - addedLayers.addElement(childLayer); - } - changeLayers(e); - } - - /** - * ContainerListener Interface method. Should not be called directly. Part - * of the ContainerListener interface, and it's here to make the MapBean a - * good Container citizen. Layers that are removed are added to a list, - * which is cleared when the projection changes. If they are added to the - * MapBean again before the projection changes, they are taken off the list, - * added back to the MapBean, and are simply repainted. This prevents layers - * from doing unnecessary work if they are toggled on and off without - * projection changes. - * - * @param e ContainerEvent - * @see com.bbn.openmap.MapBean#purgeAndNotifyRemovedLayers - */ - public void componentRemoved(ContainerEvent e) { - // Blindly cast. addImpl has already checked to be - // sure the child is a Layer. - Layer childLayer = (Layer) e.getChild(); - removeProjectionListener(childLayer); - removedLayers.addElement(childLayer); - changeLayers(e); - } - - /** - * ContainerListener Interface method. Should not be called directly. Part - * of the ContainerListener interface, and it's here to make the MapBean a - * good Container citizen. - * - * @param e ContainerEvent - */ - protected void changeLayers(ContainerEvent e) { - // Container Changes can be disabled to speed adding/removing - // multiple layers - if (!doContainerChange) { - return; - } - Component[] comps = this.getComponents(); - int ncomponents = comps.length; - Layer[] newLayers = new Layer[ncomponents]; - System.arraycopy(comps, 0, newLayers, 0, ncomponents); - if (logger.isLoggable(Level.FINE)) { - debugmsg("changeLayers() - firing change"); - } - firePropertyChange(LayersProperty, currentLayers, newLayers); - - // Tell the new layers that they have been added - for (Layer layer : addedLayers) { - layer.added(this); - } - addedLayers.removeAllElements(); - - currentLayers = newLayers; - - } - - // ------------------------------------------------------------ - // ProjectionListener interface - // ------------------------------------------------------------ - - /** - * ProjectionListener interface method. Should not be called directly. - * - * @param e ProjectionEvent - */ - public void projectionChanged(ProjectionEvent e) { - Projection newProj = e.getProjection(); - if (!projection.equals(newProj)) { - setProjection(newProj); - } - } - - /** - * Set the Mouse cursor over the MapBean component. - * - * @param newCursor Cursor - */ - public void setCursor(Cursor newCursor) { - firePropertyChange(CursorProperty, this.getCursor(), newCursor); - super.setCursor(newCursor); - } - - /** - * In addition to adding the PropertyChangeListener as the JComponent method - * does, this method also provides the listener with the initial version of - * the Layer and Cursor properties. - */ - public void addPropertyChangeListener(PropertyChangeListener pcl) { - super.addPropertyChangeListener(pcl); - pcl.propertyChange(new PropertyChangeEvent(this, LayersProperty, currentLayers, currentLayers)); - pcl.propertyChange(new PropertyChangeEvent(this, CursorProperty, this.getCursor(), this.getCursor())); - pcl.propertyChange(new PropertyChangeEvent(this, BackgroundProperty, this.getBckgrnd(), this.getBckgrnd())); - } - - protected final void debugmsg(String msg) { - logger.fine(this.toString() + (DEBUG_TIMESTAMP ? (" [" + System.currentTimeMillis() + "]") : "") - + (DEBUG_THREAD ? (" [" + Thread.currentThread() + "]") : "") + ": " + msg); - } - - /** - * Same as JComponent.paint(), except if there are no children (Layers), the - * projection still paints the background and the border is painted. - */ - public void paint(Graphics g) { - if (projection != null) { - drawProjectionBackground(g); - } - - if (this.getComponentCount() > 0) { - paintChildren(g, null); - } - - paintPainters(g); - - // Border gets painted over by printChildren with special layer - // handling. - paintBorder(g); - } - - /** - * Convenience method to test if Graphics is Graphics2D object, and to try - * to do the right thing. - */ - protected void drawProjectionBackground(Graphics g) { - if (g instanceof Graphics2D) { - projection.drawBackground((Graphics2D) g, getBckgrnd()); - } else { - g.setColor(getBackground()); - projection.drawBackground(g); - } - } - - /** - * Same as JComponent.paintChildren() except any PaintListeners are notified - * and the border is painted over the children. - */ - public void paintChildren(Graphics g) { - paintChildren(g, null); - paintPainters(g); - } - - public void paintPainters(Graphics g) { - // Just want a quick, non-changing handle on the helper. Don't need to - // configure it. - RotationHelper rotationHelper = getRotHelper(); - - if (rotationHelper != null) { - rotationHelper.paintPainters(g); - } else { - painters.paint(g); - } - } - - /** - * Same as paintChildren, but allows you to set a clipping area to paint. Be - * careful with this, because if the clipping area is set while some layer - * decides to paint itself, that layer may not have all it's objects - * painted. - */ - public void paintChildren(Graphics g, Rectangle clip) { - - g = getMapBeanRepaintPolicy().modifyGraphicsForPainting(g); - - RotationHelper rotationHelper = getRotHelper(); - if (rotationHelper != null) { - rotationHelper.paintChildren(g, clip); - } else { - // Normal painting - super.paintChildren(g); - } - } - - /** - * A method that grabs the component list of the MapBean, and renders just - * the layers from back to front. No clipping is set, other than what is set - * on the Graphics object. - * - * @param g Graphics - */ - protected void paintLayers(Graphics g) { - synchronized (getTreeLock()) { - int i = getComponentCount() - 1; - if (i < 0) { - return; - } - - for (; i >= 0; i--) { - Component comp = getComponent(i); - - final boolean isLayer = comp instanceof Layer; - - if (isLayer && comp.isVisible()) { - comp.paint(g); - } - } - } - } - - public Graphics getGraphics(boolean rotateIfSet) { - RotationHelper rotationHelper = getRotHelper(); - if (rotateIfSet && rotationHelper != null) { - return rotationHelper.getGraphics(); - } - - return super.getGraphics(); - } - - /** - * Method that provides an option of whether or not to draw the border when - * painting. Usually called from another object trying to control the Map - * appearance when events are flying around. - */ - public void paintChildrenWithBorder(Graphics g, boolean drawBorder) { - paintChildren(g); - if (drawBorder) { - paintBorder(g); - } - } - - /** - * Add a PaintListener. - * - * @param l PaintListener - */ - public synchronized void addPaintListener(PaintListener l) { - painters.add(l); - } - - /** - * Remove a PaintListener. - * - * @param l PaintListener - */ - public synchronized void removePaintListener(PaintListener l) { - painters.remove(l); - } - - // ------------------------------------------------------------ - // LayerListener interface - // ------------------------------------------------------------ - - /** - * LayerListener interface method. A list of layers will be added, removed, - * or replaced based on on the type of LayerEvent. - * - * @param evt a LayerEvent - */ - public void setLayers(LayerEvent evt) { - setBufferDirty(true); - Layer[] layers = evt.getLayers(); - int type = evt.getType(); - - if (type == LayerEvent.ALL) { - // Don't care about these at all... - return; - } - - // @HACK is this cool?: - if (layers == null) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("MapBean.setLayers(): layers is null!"); - } - return; - } - - boolean oldChange = getDoContainerChange(); - setDoContainerChange(false); - - // use LayerEvent.REPLACE when you want to remove all current - // layers add a new set - if (type == LayerEvent.REPLACE) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("Replacing all layers"); - } - removeAll(); - - for (Layer layer : layers) { - - if (layer == null) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("MapBean.setLayers(): skipping null layer from being added to MapBean"); - } - continue; - } - - if (logger.isLoggable(Level.FINE)) { - debugmsg("Adding layer[" + layer.getName() + "]"); - } - add(layer); - layer.setVisible(true); - } - - } - - // use LayerEvent.ADD when adding and/or reshuffling layers - else if (type == LayerEvent.ADD) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("Adding new layers"); - } - for (Layer layer : layers) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("Adding layer[" + layer.getName() + "]"); - } - add(layer); - layer.setVisible(true); - } - } - - // use LayerEvent.REMOVE when you want to delete layers from - // the map - else if (type == LayerEvent.REMOVE) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("Removing layers"); - } - for (Layer layer : layers) { - if (logger.isLoggable(Level.FINE)) { - debugmsg("Removing layer[" + layer.getName() + "]"); - } - remove(layer); - } - } - - if (!layerRemovalDelayed) { - purgeAndNotifyRemovedLayers(); - } - - setDoContainerChange(oldChange); - revalidate(); - repaint(); - } - - /** - * A call to try and get the MapBean to reduce flashing by controlling when - * repaints happen, waiting for lower layers to call for a repaint(), too. - * Calls shouldForwardRepaint(Layer), which acts as a policy for whether to - * forward the repaint up the Swing tree. - */ - public void repaint(Layer layer) { - setBufferDirty(true); - if (logger.isLoggable(Level.FINER)) { - String name = layer.getName(); - logger.finer((name == null ? layer.getClass().getName() : name) + " - wants a repaint()"); - } - getMapBeanRepaintPolicy().repaint(layer); - } - - /** - * Set the MapBeanRepaintPolicy used by the MapBean. This policy can be used - * to pace/filter layer repaint() requests. - */ - public void setMapBeanRepaintPolicy(MapBeanRepaintPolicy mbrp) { - repaintPolicy = mbrp; - } - - /** - * Get the MapBeanRepaintPolicy used by the MapBean. This policy can be used - * to pace/filter layer repaint() requests. If no policy has been set, a - * StandardMapBeanRepaintPolicy will be created, which simply forwards all - * requests. - */ - public MapBeanRepaintPolicy getMapBeanRepaintPolicy() { - if (repaintPolicy == null) { - repaintPolicy = new StandardMapBeanRepaintPolicy(this); - } - return repaintPolicy; - } - - /** - * Get the MapBeanBackgroundPolicy set on this MapBean. - * - * @return the backgroundPolicy - */ - public MapBeanBackgroundPolicy getBackgroundPolicy() { - return backgroundPolicy; - } - - /** - * @param backgroundPolicy the backgroundPolicy to set - */ - public void setBackgroundPolicy(MapBeanBackgroundPolicy backgroundPolicy) { - this.backgroundPolicy = backgroundPolicy; - } - - /** - * Convenience function to get the LatLonPoint representing a screen - * location from a MouseEvent. Returns null if the event is null, or if the - * projection is not set in the MapBean. Allocates new LatLonPoint with - * coordinates. Takes rotation set on MapBean into account. - */ - public Point2D getCoordinates(MouseEvent event) { - return getCoordinates(event, null); - } - - /** - * Convenience function to get the LatLonPoint representing a screen - * location from a MouseEvent. Returns null if the event is null, or if the - * projection is not set in the MapBean. Save on memory allocation by - * sending in the LatLonPoint to fill. Takes rotation set on MapBean into - * account. - */ - public T getCoordinates(MouseEvent event, T llp) { - Projection proj = getProjection(); - if (proj == null || event == null) { - return null; - } - - return inverse(event.getX(), event.getY(), llp); - } - - /** - * Convenience function to get the pixel Point2D representing a screen - * location from a MouseEvent in the projection space (as if there is no - * rotation set). Returns null if the event is null. This is used to talk to - * the OMGraphics, since they don't know about the map rotation. - */ - public Point2D getNonRotatedLocation(MouseEvent event) { - return getNonRotatedLocation(event, null); - } - - /** - * Convenience function to get the pixel Point2D representing a screen - * location from a MouseEvent in the projection space (as if there is no - * rotation set). Returns null if the event is null. This is used to talk to - * the OMGraphics, since they don't know about the map rotation. - */ - public Point2D getNonRotatedLocation(MouseEvent event, Point2D pnt) { - if (event == null) { - return null; - } - - if (pnt == null) { - pnt = new Point2D.Double(event.getX(), event.getY()); - } else { - pnt.setLocation(event.getX(), event.getY()); - } - - RotationHelper rotationHelper = getRotHelper(); - if (rotationHelper != null) { - pnt = rotationHelper.inverseTransform(pnt, pnt); - } - - return pnt; - } - - /** - * If the map has been rotated, get a shape that has been transformed into - * the pixel space of the unrotated maps (the space the projected OMGraphics - * know about). - * - * @param shape input shape - * @return GeneralPath for transform shape if map is rotated, the input - * shape if the map is not rotated. - */ - public Shape getNonRotatedShape(Shape shape) { - RotationHelper rotationHelper = getRotHelper(); - if (rotationHelper != null) { - return rotationHelper.inverseTransform(shape); - } - return shape; - } - - /** - * Checks the rotation set on the MapBean and accounts for it before calling - * inverse on the projection. - * - * @param x horizontal window pixel from left side - * @param y vertical window pixel from top - * @param ret Point2D object returned with coordinates suitable for - * projection where mouse event is. - * @return the provided T ret object, or new Point2D object from projection - * if ret is null. - */ - public T inverse(double x, double y, T ret) { - RotationHelper rotationHelper = getRotHelper(); - return (rotationHelper == null) ? getProjection().inverse(x, y, ret) : rotationHelper.inverse(x, y, ret); - } - - /** - * Interface-like method to query if the MapBean is buffered, so you can - * control behavior better. Allows the removal of specific instance-like - * queries for, say, BufferedMapBean, when all you really want to know is if - * you have the data is buffered, and if so, should be buffer be cleared. - * For the MapBean, always false. - */ - public boolean isBuffered() { - return false; - } - - /** - * Interface-like method to set a buffer dirty, if there is one. In MapBean, - * there isn't. - * - * @param value boolean - */ - public void setBufferDirty(boolean value) { - } - - /** - * Checks whether the image buffer should be repainted. - * - * @return boolean whether the layer buffer is dirty. Always true for - * MapBean, because a paint is always gonna need to happen. - */ - public boolean isBufferDirty() { - return true; - } - - /** - * If true (default) layers are held when they are removed, and then - * released and notified of removal when the projection changes. This saves - * the layers from releasing resources if the layer is simply being toggled - * on/off for different map views. - * - * @param set the setting - */ - public void setLayerRemovalDelayed(boolean set) { - layerRemovalDelayed = set; - } - - /** - * @return the flag for delayed layer removal. - */ - public boolean isLayerRemovalDelayed() { - return layerRemovalDelayed; - } - - /** - * Go through the layers, and for all of them that have the autoPalette - * variable turned on, show their palettes. - */ - public void showLayerPalettes() { - for (Component comp : getComponents()) { - // they have to be layers - Layer l = (Layer) comp; - if (l.autoPalette) { - l.showPalette(); - } - } - } - - /** - * Turn off all layer palettes. - */ - public void hideLayerPalettes() { - for (Component comp : getComponents()) { - // they have to be layers - ((Layer) comp).hidePalette(); - } - } - - protected ProjectionFactory projectionFactory; - - public ProjectionFactory getProjectionFactory() { - if (projectionFactory == null) { - projectionFactory = ProjectionFactory.loadDefaultProjections(); - } - - return projectionFactory; - } - - public void setProjectionFactory(ProjectionFactory projFactory) { - projectionFactory = projFactory; - } - - protected RotationHelper rotHelper; - - /** - * Handles all of the updating of the RotationHelper if needed, based on the - * current rotation settings on the MapBean. - * - * @return the locRotHelper, null if not needed. - */ - protected RotationHelper getUpdatedRotHelper() { - double rotAngle = getRotationAngle(); - Projection proj = getProjection(); - RotationHelper rotationHelper = getRotHelper(); - - if (rotAngle != 0.0) { - if (rotationHelper == null) { - rotationHelper = new RotationHelper(rotAngle, proj); - setRotHelper(rotationHelper); - } else { - rotationHelper.updateForBufferDimensions(proj); - rotationHelper.updateAngle(rotAngle); - } - } else if (rotationHelper != null) { - /* + /** + * Gets the scale of the map. + * + * @return float the current scale of the map + * @see Projection#getScale + */ + public float getScale() { + return projection.getScale(); + } + + /** + * Sets the scale of the map. The Projection may silently disregard this + * setting, setting it to a maxscale or minscale + * value. + * + * @param newScale the new scale + * @see Proj#setScale + */ + public void setScale(float newScale) { + projection.setScale(newScale); + fireProjectionChanged(); + } + + /** + * Gets the center of the map in the form of a LatLonPoint. + * + * @return the center point of the map + * @see Projection#getCenter + */ + public Point2D getCenter() { + return projection.getCenter(); + } + + /** + * Sets the center of the map. + * + * @param newCenter the center point of the map + * @see Proj#setCenter(Point2D) + */ + public void setCenter(Point2D newCenter) { + projection.setCenter(newCenter); + fireProjectionChanged(); + } + + /** + * Sets the center of the map. + * + * @param lat the latitude of center point of the map in decimal degrees + * @param lon the longitude of center point of the map in decimal degrees + * @see Proj#setCenter(double, double) + */ + public void setCenter(double lat, double lon) { + projection.setCenter(new Point2D.Double(lon, lat)); + fireProjectionChanged(); + } + + /** + * Sets the center of the map. + * + * @param lat the latitude of center point of the map in decimal degrees + * @param lon the longitude of center point of the map in decimal degrees + * @see Proj#setCenter(double, double) + */ + public void setCenter(float lat, float lon) { + setCenter((double) lat, (double) lon); + } + + /** + * Set the background color of the map. If the background for this MapBean + * is not null, the background of the projection will be used. + * + * @param color java.awt.Color. + */ + public void setBackgroundColor(Color color) { + setBackground(color); + } + + public void setBackground(Color color) { + super.setBackground(color); + setBckgrnd((Paint) color); + } + + /** + * We override this to set the paint mode on the Graphics before the border + * is painted, otherwise we get an XOR effect in the border. + */ + public void paintBorder(Graphics g) { + g.setPaintMode(); + super.paintBorder(g); + } + + /** + * Set the background of the map. If the background for this MapBean is not + * null, the background of the projection will be used. + * + * @param paint java.awt.Paint. + */ + public void setBckgrnd(Paint paint) { + setBufferDirty(true); + + // Instead, do this. + Paint oldBackground = background; + background = paint; + firePropertyChange(BackgroundProperty, oldBackground, background); + + repaint(); + } + + /** + * Get the background color of the map. If the background color for this + * MapBean has been explicitly set, that value will be returned. Otherwise, + * the background color of the projection will be returned. If the + * background is not a color (as opposed to Paint) this method will return + * null. + * + * @return color java.awt.Color. + */ + public Color getBackground() { + Paint ret = getBckgrnd(); + if (ret instanceof Color) { + return (Color) ret; + } + + return super.getBackground(); + } + + /** + * Get the background of the map. If the background for this MapBean has + * been explicitly set, that value will be returned. Otherwise, the + * background of the projection will be returned. + * + * @return color java.awt.Color. + */ + public Paint getBckgrnd() { + Paint ret = background; + + MapBeanBackgroundPolicy mbbp = backgroundPolicy; + if (mbbp != null) { + ret = mbbp.getBckgrnd(); + } + + if (ret == null) { + ret = super.getBackground(); + } + + return ret; + } + + /** + * Get the projection property, reflects the projection with no rotation. + * + * @return current Projection of map. + */ + public Projection getProjection() { + return projection; + } + + /** + * @return the expanded rotated projection if map rotated, normal projection + * if not rotated. The rotated projection is larger than the MapBean and has + * extra offsets. + */ + public Projection getRotatedProjection() { + RotationHelper rotation = getUpdatedRotHelper(); + Projection proj = rotation != null ? rotation.getProjection() : projection; + // Double check + ((Proj) proj).setRotationAngle(getRotationAngle()); + return proj; + } + + /** + * Set the projection. Shouldn't be null, and won't do anything if it is. + * + * @param aProjection Projection + */ + public void setProjection(Projection aProjection) { + if (aProjection != null && !aProjection.getProjectionID().contains("NaN")) { + setBufferDirty(true); + projection = (Proj) aProjection; + setPreferredSize(new Dimension(projection.getWidth(), projection.getHeight())); + fireProjectionChanged(); + } + } + + // ------------------------------------------------------------ + // CenterListener interface + // ------------------------------------------------------------ + /** + * Handles incoming CenterEvents. + * + * @param evt the incoming center event + */ + @Override + public void center(CenterEvent evt) { + setCenter(evt.getLatitude(), evt.getLongitude()); + } + + // ------------------------------------------------------------ + // PanListener interface + // ------------------------------------------------------------ + /** + * Handles incoming PanEvents. + * + * @param evt the incoming pan event + */ + @Override + public void pan(PanEvent evt) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("PanEvent: " + evt); + } + float az = evt.getAzimuth() - (float) Math.toDegrees(rotationAngle); + float c = evt.getArcDistance(); + if (Float.isNaN(c)) { + projection.pan(az); + } else { + projection.pan(az, c); + } + + fireProjectionChanged(); + } + + // ------------------------------------------------------------ + // ZoomListener interface + // ------------------------------------------------------------ + /** + * Zoom the Map. Part of the ZoomListener interface. Sets the scale of the + * MapBean projection, based on a relative or absolute amount. If the + * ZoomEvent has a screen point defined, the MapBean will keep that point + * locked down during the zoom. + * + * @param evt the ZoomEvent describing the new scale. + */ + @Override + public void zoom(ZoomEvent evt) { + float newScale; + if (evt.isAbsolute()) { + newScale = evt.getAmount(); + } else if (evt.isRelative()) { + newScale = getScale() * evt.getAmount(); + } else { + return; + } + + Point triggerMousePoint = evt.getScreenPoint(); + if (triggerMousePoint == null) { + setScale(newScale); + return; + } + + Proj proj = (Proj) getProjection().makeClone(); + + Point2D triggerMousePointLL = proj.inverse(triggerMousePoint); + Point2D origCenterLL = proj.getCenter(); + Point2D origCenterPoint = proj.forward(origCenterLL); + + proj.setScale(newScale); + Point2D preAdjNewTargetPoint = proj.forward(triggerMousePointLL); + double xDiff = preAdjNewTargetPoint.getX() - triggerMousePoint.x; + double yDiff = triggerMousePoint.y - preAdjNewTargetPoint.getY(); + + Point2D newCenterProjPoint = new Point2D.Double( + origCenterPoint.getX() + xDiff, + origCenterPoint.getY() - yDiff); + + Point2D newCenterProjLL = proj.inverse(newCenterProjPoint); + proj.setCenter(newCenterProjLL); + setProjection(proj); + } + + // ------------------------------------------------------------ + // ContainerListener interface + // ------------------------------------------------------------ + protected transient Layer[] currentLayers = new Layer[0]; + + protected transient boolean doContainerChange = true; + + /** + * ContainerListener Interface method. Should not be called directly. Part + * of the ContainerListener interface, and it's here to make the MapBean a + * good Container citizen. + * + * @param value boolean + */ + public void setDoContainerChange(boolean value) { + // if changing from false to true, call changeLayers() + if (!doContainerChange && value) { + doContainerChange = value; + changeLayers(null); + } else { + doContainerChange = value; + } + } + + /** + * ContainerListener Interface method. Should not be called directly. Part + * of the ContainerListener interface, and it's here to make the MapBean a + * good Container citizen. + * + * @return boolean + */ + public boolean getDoContainerChange() { + return doContainerChange; + } + + /** + * ContainerListener Interface method. Should not be called directly. Part + * of the ContainerListener interface, and it's here to make the MapBean a + * good Container citizen. + * + * @param e ContainerEvent + */ + public void componentAdded(ContainerEvent e) { + // Blindly cast. addImpl has already checked to be + // sure the child is a Layer. + Layer childLayer = (Layer) e.getChild(); + addProjectionListener(childLayer); + + // If the new layer is in the queue to have removed() called + // on it take it off the queue, and don't add it to the + // added() queue (it doesn't know that it was removed, yet). + // Otherwise, add it to the queue to have added() called on + // it. + if (!removedLayers.removeElement(childLayer)) { + addedLayers.addElement(childLayer); + } + changeLayers(e); + } + + /** + * ContainerListener Interface method. Should not be called directly. Part + * of the ContainerListener interface, and it's here to make the MapBean a + * good Container citizen. Layers that are removed are added to a list, + * which is cleared when the projection changes. If they are added to the + * MapBean again before the projection changes, they are taken off the list, + * added back to the MapBean, and are simply repainted. This prevents layers + * from doing unnecessary work if they are toggled on and off without + * projection changes. + * + * @param e ContainerEvent + * @see com.bbn.openmap.MapBean#purgeAndNotifyRemovedLayers + */ + public void componentRemoved(ContainerEvent e) { + // Blindly cast. addImpl has already checked to be + // sure the child is a Layer. + Layer childLayer = (Layer) e.getChild(); + removeProjectionListener(childLayer); + removedLayers.addElement(childLayer); + changeLayers(e); + } + + /** + * ContainerListener Interface method. Should not be called directly. Part + * of the ContainerListener interface, and it's here to make the MapBean a + * good Container citizen. + * + * @param e ContainerEvent + */ + protected void changeLayers(ContainerEvent e) { + // Container Changes can be disabled to speed adding/removing + // multiple layers + if (!doContainerChange) { + return; + } + Component[] comps = this.getComponents(); + int ncomponents = comps.length; + Layer[] newLayers = new Layer[ncomponents]; + System.arraycopy(comps, 0, newLayers, 0, ncomponents); + if (logger.isLoggable(Level.FINE)) { + debugmsg("changeLayers() - firing change"); + } + firePropertyChange(LayersProperty, currentLayers, newLayers); + + // Tell the new layers that they have been added + for (Layer layer : addedLayers) { + layer.added(this); + } + addedLayers.removeAllElements(); + + currentLayers = newLayers; + + } + + // ------------------------------------------------------------ + // ProjectionListener interface + // ------------------------------------------------------------ + /** + * ProjectionListener interface method. Should not be called directly. + * + * @param e ProjectionEvent + */ + public void projectionChanged(ProjectionEvent e) { + Projection newProj = e.getProjection(); + if (!projection.equals(newProj)) { + setProjection(newProj); + } + } + + /** + * Set the Mouse cursor over the MapBean component. + * + * @param newCursor Cursor + */ + public void setCursor(Cursor newCursor) { + firePropertyChange(CursorProperty, this.getCursor(), newCursor); + super.setCursor(newCursor); + } + + /** + * In addition to adding the PropertyChangeListener as the JComponent method + * does, this method also provides the listener with the initial version of + * the Layer and Cursor properties. + */ + public void addPropertyChangeListener(PropertyChangeListener pcl) { + super.addPropertyChangeListener(pcl); + pcl.propertyChange(new PropertyChangeEvent(this, LayersProperty, currentLayers, currentLayers)); + pcl.propertyChange(new PropertyChangeEvent(this, CursorProperty, this.getCursor(), this.getCursor())); + pcl.propertyChange(new PropertyChangeEvent(this, BackgroundProperty, this.getBckgrnd(), this.getBckgrnd())); + } + + protected final void debugmsg(String msg) { + logger.fine(this.toString() + (DEBUG_TIMESTAMP ? (" [" + System.currentTimeMillis() + "]") : "") + + (DEBUG_THREAD ? (" [" + Thread.currentThread() + "]") : "") + ": " + msg); + } + + /** + * Same as JComponent.paint(), except if there are no children (Layers), the + * projection still paints the background and the border is painted. + */ + public void paint(Graphics g) { + if (projection != null) { + drawProjectionBackground(g); + } + + if (this.getComponentCount() > 0) { + paintChildren(g, null); + } + + paintPainters(g); + + // Border gets painted over by printChildren with special layer + // handling. + paintBorder(g); + } + + /** + * Convenience method to test if Graphics is Graphics2D object, and to try + * to do the right thing. + */ + protected void drawProjectionBackground(Graphics g) { + if (g instanceof Graphics2D) { + projection.drawBackground((Graphics2D) g, getBckgrnd()); + } else { + g.setColor(getBackground()); + projection.drawBackground(g); + } + } + + /** + * Same as JComponent.paintChildren() except any PaintListeners are notified + * and the border is painted over the children. + */ + public void paintChildren(Graphics g) { + paintChildren(g, null); + paintPainters(g); + } + + public void paintPainters(Graphics g) { + // Just want a quick, non-changing handle on the helper. Don't need to + // configure it. + RotationHelper rotationHelper = getRotHelper(); + + if (rotationHelper != null) { + rotationHelper.paintPainters(g); + } else { + painters.paint(g); + } + } + + /** + * Same as paintChildren, but allows you to set a clipping area to paint. Be + * careful with this, because if the clipping area is set while some layer + * decides to paint itself, that layer may not have all it's objects + * painted. + */ + public void paintChildren(Graphics g, Rectangle clip) { + + g = getMapBeanRepaintPolicy().modifyGraphicsForPainting(g); + + RotationHelper rotationHelper = getRotHelper(); + if (rotationHelper != null) { + rotationHelper.paintChildren(g, clip); + } else { + // Normal painting + super.paintChildren(g); + } + } + + /** + * A method that grabs the component list of the MapBean, and renders just + * the layers from back to front. No clipping is set, other than what is set + * on the Graphics object. + * + * @param g Graphics + */ + protected void paintLayers(Graphics g) { + synchronized (getTreeLock()) { + int i = getComponentCount() - 1; + if (i < 0) { + return; + } + + for (; i >= 0; i--) { + Component comp = getComponent(i); + + final boolean isLayer = comp instanceof Layer; + + if (isLayer && comp.isVisible()) { + comp.paint(g); + } + } + } + } + + public Graphics getGraphics(boolean rotateIfSet) { + RotationHelper rotationHelper = getRotHelper(); + if (rotateIfSet && rotationHelper != null) { + return rotationHelper.getGraphics(); + } + + return super.getGraphics(); + } + + /** + * Method that provides an option of whether or not to draw the border when + * painting. Usually called from another object trying to control the Map + * appearance when events are flying around. + */ + public void paintChildrenWithBorder(Graphics g, boolean drawBorder) { + paintChildren(g); + if (drawBorder) { + paintBorder(g); + } + } + + /** + * Add a PaintListener. + * + * @param l PaintListener + */ + public synchronized void addPaintListener(PaintListener l) { + painters.add(l); + } + + /** + * Remove a PaintListener. + * + * @param l PaintListener + */ + public synchronized void removePaintListener(PaintListener l) { + painters.remove(l); + } + + // ------------------------------------------------------------ + // LayerListener interface + // ------------------------------------------------------------ + /** + * LayerListener interface method. A list of layers will be added, removed, + * or replaced based on on the type of LayerEvent. + * + * @param evt a LayerEvent + */ + public void setLayers(LayerEvent evt) { + setBufferDirty(true); + Layer[] layers = evt.getLayers(); + int type = evt.getType(); + + if (type == LayerEvent.ALL) { + // Don't care about these at all... + return; + } + + // @HACK is this cool?: + if (layers == null) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("MapBean.setLayers(): layers is null!"); + } + return; + } + + boolean oldChange = getDoContainerChange(); + setDoContainerChange(false); + + // use LayerEvent.REPLACE when you want to remove all current + // layers add a new set + if (type == LayerEvent.REPLACE) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("Replacing all layers"); + } + removeAll(); + + for (Layer layer : layers) { + + if (layer == null) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("MapBean.setLayers(): skipping null layer from being added to MapBean"); + } + continue; + } + + if (logger.isLoggable(Level.FINE)) { + debugmsg("Adding layer[" + layer.getName() + "]"); + } + add(layer); + layer.setVisible(true); + } + + } // use LayerEvent.ADD when adding and/or reshuffling layers + else if (type == LayerEvent.ADD) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("Adding new layers"); + } + for (Layer layer : layers) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("Adding layer[" + layer.getName() + "]"); + } + add(layer); + layer.setVisible(true); + } + } // use LayerEvent.REMOVE when you want to delete layers from + // the map + else if (type == LayerEvent.REMOVE) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("Removing layers"); + } + for (Layer layer : layers) { + if (logger.isLoggable(Level.FINE)) { + debugmsg("Removing layer[" + layer.getName() + "]"); + } + remove(layer); + } + } + + if (!layerRemovalDelayed) { + purgeAndNotifyRemovedLayers(); + } + + setDoContainerChange(oldChange); + revalidate(); + repaint(); + } + + /** + * A call to try and get the MapBean to reduce flashing by controlling when + * repaints happen, waiting for lower layers to call for a repaint(), too. + * Calls shouldForwardRepaint(Layer), which acts as a policy for whether to + * forward the repaint up the Swing tree. + */ + public void repaint(Layer layer) { + setBufferDirty(true); + if (logger.isLoggable(Level.FINER)) { + String name = layer.getName(); + logger.finer((name == null ? layer.getClass().getName() : name) + " - wants a repaint()"); + } + getMapBeanRepaintPolicy().repaint(layer); + } + + /** + * Set the MapBeanRepaintPolicy used by the MapBean. This policy can be used + * to pace/filter layer repaint() requests. + */ + public void setMapBeanRepaintPolicy(MapBeanRepaintPolicy mbrp) { + repaintPolicy = mbrp; + } + + /** + * Get the MapBeanRepaintPolicy used by the MapBean. This policy can be used + * to pace/filter layer repaint() requests. If no policy has been set, a + * StandardMapBeanRepaintPolicy will be created, which simply forwards all + * requests. + */ + public MapBeanRepaintPolicy getMapBeanRepaintPolicy() { + if (repaintPolicy == null) { + repaintPolicy = new StandardMapBeanRepaintPolicy(this); + } + return repaintPolicy; + } + + /** + * Get the MapBeanBackgroundPolicy set on this MapBean. + * + * @return the backgroundPolicy + */ + public MapBeanBackgroundPolicy getBackgroundPolicy() { + return backgroundPolicy; + } + + /** + * @param backgroundPolicy the backgroundPolicy to set + */ + public void setBackgroundPolicy(MapBeanBackgroundPolicy backgroundPolicy) { + this.backgroundPolicy = backgroundPolicy; + } + + /** + * Convenience function to get the LatLonPoint representing a screen + * location from a MouseEvent. Returns null if the event is null, or if the + * projection is not set in the MapBean. Allocates new LatLonPoint with + * coordinates. Takes rotation set on MapBean into account. + */ + public Point2D getCoordinates(MouseEvent event) { + return getCoordinates(event, null); + } + + /** + * Convenience function to get the LatLonPoint representing a screen + * location from a MouseEvent. Returns null if the event is null, or if the + * projection is not set in the MapBean. Save on memory allocation by + * sending in the LatLonPoint to fill. Takes rotation set on MapBean into + * account. + */ + public T getCoordinates(MouseEvent event, T llp) { + Projection proj = getProjection(); + if (proj == null || event == null) { + return null; + } + + return inverse(event.getX(), event.getY(), llp); + } + + /** + * Convenience function to get the pixel Point2D representing a screen + * location from a MouseEvent in the projection space (as if there is no + * rotation set). Returns null if the event is null. This is used to talk to + * the OMGraphics, since they don't know about the map rotation. + */ + public Point2D getNonRotatedLocation(MouseEvent event) { + return getNonRotatedLocation(event, null); + } + + /** + * Convenience function to get the pixel Point2D representing a screen + * location from a MouseEvent in the projection space (as if there is no + * rotation set). Returns null if the event is null. This is used to talk to + * the OMGraphics, since they don't know about the map rotation. + */ + public Point2D getNonRotatedLocation(MouseEvent event, Point2D pnt) { + if (event == null) { + return null; + } + + if (pnt == null) { + pnt = new Point2D.Double(event.getX(), event.getY()); + } else { + pnt.setLocation(event.getX(), event.getY()); + } + + RotationHelper rotationHelper = getRotHelper(); + if (rotationHelper != null) { + pnt = rotationHelper.inverseTransform(pnt, pnt); + } + + return pnt; + } + + /** + * If the map has been rotated, get a shape that has been transformed into + * the pixel space of the unrotated maps (the space the projected OMGraphics + * know about). + * + * @param shape input shape + * @return GeneralPath for transform shape if map is rotated, the input + * shape if the map is not rotated. + */ + public Shape getNonRotatedShape(Shape shape) { + RotationHelper rotationHelper = getRotHelper(); + if (rotationHelper != null) { + return rotationHelper.inverseTransform(shape); + } + return shape; + } + + /** + * Checks the rotation set on the MapBean and accounts for it before calling + * inverse on the projection. + * + * @param x horizontal window pixel from left side + * @param y vertical window pixel from top + * @param ret Point2D object returned with coordinates suitable for + * projection where mouse event is. + * @return the provided T ret object, or new Point2D object from projection + * if ret is null. + */ + public T inverse(double x, double y, T ret) { + RotationHelper rotationHelper = getRotHelper(); + return (rotationHelper == null) ? getProjection().inverse(x, y, ret) : rotationHelper.inverse(x, y, ret); + } + + /** + * Interface-like method to query if the MapBean is buffered, so you can + * control behavior better. Allows the removal of specific instance-like + * queries for, say, BufferedMapBean, when all you really want to know is if + * you have the data is buffered, and if so, should be buffer be cleared. + * For the MapBean, always false. + */ + public boolean isBuffered() { + return false; + } + + /** + * Interface-like method to set a buffer dirty, if there is one. In MapBean, + * there isn't. + * + * @param value boolean + */ + public void setBufferDirty(boolean value) { + } + + /** + * Checks whether the image buffer should be repainted. + * + * @return boolean whether the layer buffer is dirty. Always true for + * MapBean, because a paint is always gonna need to happen. + */ + public boolean isBufferDirty() { + return true; + } + + /** + * If true (default) layers are held when they are removed, and then + * released and notified of removal when the projection changes. This saves + * the layers from releasing resources if the layer is simply being toggled + * on/off for different map views. + * + * @param set the setting + */ + public void setLayerRemovalDelayed(boolean set) { + layerRemovalDelayed = set; + } + + /** + * @return the flag for delayed layer removal. + */ + public boolean isLayerRemovalDelayed() { + return layerRemovalDelayed; + } + + /** + * Go through the layers, and for all of them that have the autoPalette + * variable turned on, show their palettes. + */ + public void showLayerPalettes() { + for (Component comp : getComponents()) { + // they have to be layers + Layer l = (Layer) comp; + if (l.autoPalette) { + l.showPalette(); + } + } + } + + /** + * Turn off all layer palettes. + */ + public void hideLayerPalettes() { + for (Component comp : getComponents()) { + // they have to be layers + ((Layer) comp).hidePalette(); + } + } + + protected ProjectionFactory projectionFactory; + + public ProjectionFactory getProjectionFactory() { + if (projectionFactory == null) { + projectionFactory = ProjectionFactory.loadDefaultProjections(); + } + + return projectionFactory; + } + + public void setProjectionFactory(ProjectionFactory projFactory) { + projectionFactory = projFactory; + } + + protected RotationHelper rotHelper; + + /** + * Handles all of the updating of the RotationHelper if needed, based on the + * current rotation settings on the MapBean. + * + * @return the locRotHelper, null if not needed. + */ + protected RotationHelper getUpdatedRotHelper() { + double rotAngle = getRotationAngle(); + Projection proj = getProjection(); + RotationHelper rotationHelper = getRotHelper(); + + if (rotAngle != 0.0) { + if (rotationHelper == null) { + rotationHelper = new RotationHelper(rotAngle, proj); + setRotHelper(rotationHelper); + } else { + rotationHelper.updateForBufferDimensions(proj); + rotationHelper.updateAngle(rotAngle); + } + } else if (rotationHelper != null) { + /* * Just because the angle is zero, let's check with the * rotationHelper. If the map is just passing through zero rotation, * keep it around. If we get a couple of projection changes with the * az set to zero, then get rid of the rotation helper. - */ - if (rotationHelper.isStillNeeded(rotAngle)) { - rotationHelper.updateForBufferDimensions(proj); - rotationHelper.updateAngle(rotAngle); - } else { - setRotHelper(null); - rotationHelper = null; - } - } // else return null rotationHelper - - return rotationHelper; - } - - /** - * Get the RotationHelper that assists with rotated maps. - * - * @return RotationHelper, may be null if map isn't rotated. - */ - protected RotationHelper getRotHelper() { - return rotHelper; - } - - /** - * @param nRotHelper the locRotHelper to set as the current one. Disposes of - * the old one. - */ - protected void setRotHelper(RotationHelper nRotHelper) { - RotationHelper rotationHelper = this.rotHelper; - if (rotationHelper != null) { - rotationHelper.dispose(); - } - - this.rotHelper = nRotHelper; - } - - /** - * Set the rotation of the map in RADIANS. - * - * @param angle radians of rotation, increasing clockwise. - */ - public void setRotationAngle(double angle) { - setRotationAngle(angle, false); - } - - /** - * Set the rotation of the map in RADIANS. - * - * @param angle radians of rotation, increasing clockwise. - * @param fastRotation if true, fireProjectionChange will not be called, and - * the RotationHelper will be used to spin image buffer. - */ - public void setRotationAngle(double angle, boolean fastRotation) { - if (this.rotationAngle != angle) { - this.rotationAngle = angle; - - /* + */ + if (rotationHelper.isStillNeeded(rotAngle)) { + rotationHelper.updateForBufferDimensions(proj); + rotationHelper.updateAngle(rotAngle); + } else { + setRotHelper(null); + rotationHelper = null; + } + } // else return null rotationHelper + + return rotationHelper; + } + + /** + * Get the RotationHelper that assists with rotated maps. + * + * @return RotationHelper, may be null if map isn't rotated. + */ + protected RotationHelper getRotHelper() { + return rotHelper; + } + + /** + * @param nRotHelper the locRotHelper to set as the current one. Disposes of + * the old one. + */ + protected void setRotHelper(RotationHelper nRotHelper) { + RotationHelper rotationHelper = this.rotHelper; + if (rotationHelper != null) { + rotationHelper.dispose(); + } + + this.rotHelper = nRotHelper; + } + + /** + * Set the rotation of the map in RADIANS. + * + * @param angle radians of rotation, increasing clockwise. + */ + public void setRotationAngle(double angle) { + setRotationAngle(angle, false); + } + + /** + * Set the rotation of the map in RADIANS. + * + * @param angle radians of rotation, increasing clockwise. + * @param fastRotation if true, fireProjectionChange will not be called, and + * the RotationHelper will be used to spin image buffer. + */ + public void setRotationAngle(double angle, boolean fastRotation) { + if (this.rotationAngle != angle) { + this.rotationAngle = angle; + + /* * moving into this block makes rotation work faster, and smooth. * However, it doesn't give the non-rotating OMGraphics a chance to * counteract the rotation. - */ - if (fastRotation && angle != 0) { - /* + */ + if (fastRotation && angle != 0) { + /* * If only the angle changes, we can just update the * locRotHelper angle, and reuse all of the other settings. If * the angle changes and zero is involved,either way, get the * rotation helper set up in fireProjectionChanged. The * RotationHelper needs to be redefined for any other projection * changes anyway. - */ - RotationHelper locRotHelper = getRotHelper(); - if (locRotHelper != null) { - locRotHelper.updateAngle(angle); - repaint(); - return; - } - } - - fireProjectionChanged(); - } - } - - /** - * Get the rotation of the map in RADIANS. - * - * @return the angle the map has been rotated, in RADIANS, clockwise is - * positive. - */ - public double getRotationAngle() { - return rotationAngle; - } - - protected class RotationHelper { - - Image rotImage; - - double angle; - Point2D rotCenter; - int rotBufferHeight; - int rotBufferWidth; - int rotXOffset; - int rotYOffset; - Projection rotProjection; - AffineTransform rotTransform; - - private RotationHelper(double angle, Projection currentProjection) { - updateForBufferDimensions(currentProjection); - updateAngle(angle); - } - - /** - * We're going to try to do buffering with a image that will cover all - * of the corners when the map is rotated. We'll measure the ground - * distance from the center of the projection/map to each corner, and - * take the longest to create a bounding circle. The NSEW of that - * bounding circle (as a bounding box) Makes up the buffered image pixel - * bounds, and the inverse projected coordinates of that box should be - * returned as upper left and lower right coordinates when those methods - * are called. The projection of that box should be the same as the - * current projection, except for the new width and height. - * - * Because the height and width are different for the buffered image, - * we're going to have to translate it before it is rotated. We can - * probably just tack on an additional translate to the rot. That - * difference will be 1/2 the difference of the height and width between - * the rot image and the original projection (mapbean dimensions). - * - * @param proj the projection to use to create the current image buffer - * @return boolean true if the rotBufferHeight and/or rotBufferWidth - * have changed, indicating that the image buffer was recreated - * for new dimensions. - */ - protected boolean updateForBufferDimensions(Projection proj) { - - int currentRotBufferWidth = rotBufferWidth; - int currentRotBufferHeight = rotBufferHeight; - - Point2D center = proj.getCenter(); - Point2D ul = proj.getUpperLeft(); - Point2D lr = proj.getLowerRight(); - - /* + */ + RotationHelper locRotHelper = getRotHelper(); + if (locRotHelper != null) { + locRotHelper.updateAngle(angle); + repaint(); + return; + } + } + + fireProjectionChanged(); + } + } + + /** + * Get the rotation of the map in RADIANS. + * + * @return the angle the map has been rotated, in RADIANS, clockwise is + * positive. + */ + public double getRotationAngle() { + return rotationAngle; + } + + protected class RotationHelper { + + Image rotImage; + + double angle; + Point2D rotCenter; + int rotBufferHeight; + int rotBufferWidth; + int rotXOffset; + int rotYOffset; + Projection rotProjection; + AffineTransform rotTransform; + + private RotationHelper(double angle, Projection currentProjection) { + updateForBufferDimensions(currentProjection); + updateAngle(angle); + } + + /** + * We're going to try to do buffering with a image that will cover all + * of the corners when the map is rotated. We'll measure the ground + * distance from the center of the projection/map to each corner, and + * take the longest to create a bounding circle. The NSEW of that + * bounding circle (as a bounding box) Makes up the buffered image pixel + * bounds, and the inverse projected coordinates of that box should be + * returned as upper left and lower right coordinates when those methods + * are called. The projection of that box should be the same as the + * current projection, except for the new width and height. + * + * Because the height and width are different for the buffered image, + * we're going to have to translate it before it is rotated. We can + * probably just tack on an additional translate to the rot. That + * difference will be 1/2 the difference of the height and width between + * the rot image and the original projection (mapbean dimensions). + * + * @param proj the projection to use to create the current image buffer + * @return boolean true if the rotBufferHeight and/or rotBufferWidth + * have changed, indicating that the image buffer was recreated for new + * dimensions. + */ + protected boolean updateForBufferDimensions(Projection proj) { + + int currentRotBufferWidth = rotBufferWidth; + int currentRotBufferHeight = rotBufferHeight; + + Point2D center = proj.getCenter(); + Point2D ul = proj.getUpperLeft(); + Point2D lr = proj.getLowerRight(); + + /* * Woooooow, we're really going to have to work it, aren't we? We * need to handle GeoProj differently than Cartesian coords. That * seems to lend itself to moving this kind of calculations to the * super classes of the projection classes. *sigh* For now, let's * try assuming that GeoProj - */ - Geo centerGeo = new Geo(center.getY(), center.getX()); - Geo ulGeo = new Geo(ul.getY(), ul.getX()); - Geo lrGeo = new Geo(lr.getY(), lr.getX()); - - // Comparing the UL and LR corners for distance, get the greatest. - double dist = Math.max(centerGeo.distance(ulGeo), centerGeo.distance(lrGeo)); - - // Now calculate the bounds of that distance in 4 directions - Geo N = Geo.offset(centerGeo, dist, 0); - Geo S = Geo.offset(centerGeo, dist, Math.PI); - Geo E = Geo.offset(centerGeo, dist, Math.PI / 2.0); - Geo W = Geo.offset(centerGeo, dist, -Math.PI / 2); - - // Calculate the coordinates of new bounds for that distance from - // center. - Point2D newUL = new Point2D.Double(W.getLongitude(), N.getLatitude()); - Point2D newLR = new Point2D.Double(E.getLongitude(), S.getLatitude()); - - // Calculate the pixel bounds of the new bounding box to get new - // projection h, w - Point2D newULPix = proj.forward(newUL); - Point2D newLRPix = proj.forward(newLR); - - int reqRotBufferHeight = (int) Math.abs(newLRPix.getY() - newULPix.getY()); - int reqRotBufferWidth = (int) Math.abs(newLRPix.getX() - newULPix.getX()); - - // If the image is a little bigger than we need, we can reuse. Only - // replace it if it is significantly bigger, or at all smaller. - boolean needNewHeightImage = reqRotBufferHeight > currentRotBufferHeight - || reqRotBufferHeight < .9 * currentRotBufferHeight; - boolean needNewWidthImage = reqRotBufferWidth > currentRotBufferWidth - || currentRotBufferWidth < .9 * currentRotBufferWidth; - - boolean bufferImageResized = false; - - if (needNewHeightImage || needNewWidthImage) { - this.rotImage = new BufferedImage(reqRotBufferWidth, reqRotBufferHeight, BufferedImage.TYPE_INT_ARGB); - rotBufferWidth = reqRotBufferWidth; - rotBufferHeight = reqRotBufferHeight; - bufferImageResized = true; - } - - rotProjection = projectionFactory.makeProjection(proj.getClass(), center, proj.getScale(), rotBufferWidth, - rotBufferHeight); - this.rotCenter = rotProjection.forward(center); - - /* + */ + Geo centerGeo = new Geo(center.getY(), center.getX()); + Geo ulGeo = new Geo(ul.getY(), ul.getX()); + Geo lrGeo = new Geo(lr.getY(), lr.getX()); + + // Comparing the UL and LR corners for distance, get the greatest. + double dist = Math.max(centerGeo.distance(ulGeo), centerGeo.distance(lrGeo)); + + // Now calculate the bounds of that distance in 4 directions + Geo N = Geo.offset(centerGeo, dist, 0); + Geo S = Geo.offset(centerGeo, dist, Math.PI); + Geo E = Geo.offset(centerGeo, dist, Math.PI / 2.0); + Geo W = Geo.offset(centerGeo, dist, -Math.PI / 2); + + // Calculate the coordinates of new bounds for that distance from + // center. + Point2D newUL = new Point2D.Double(W.getLongitude(), N.getLatitude()); + Point2D newLR = new Point2D.Double(E.getLongitude(), S.getLatitude()); + + // Calculate the pixel bounds of the new bounding box to get new + // projection h, w + Point2D newULPix = proj.forward(newUL); + Point2D newLRPix = proj.forward(newLR); + + int reqRotBufferHeight = (int) Math.abs(newLRPix.getY() - newULPix.getY()); + int reqRotBufferWidth = (int) Math.abs(newLRPix.getX() - newULPix.getX()); + + // If the image is a little bigger than we need, we can reuse. Only + // replace it if it is significantly bigger, or at all smaller. + boolean needNewHeightImage = reqRotBufferHeight > currentRotBufferHeight + || reqRotBufferHeight < .9 * currentRotBufferHeight; + boolean needNewWidthImage = reqRotBufferWidth > currentRotBufferWidth + || currentRotBufferWidth < .9 * currentRotBufferWidth; + + boolean bufferImageResized = false; + + if (needNewHeightImage || needNewWidthImage) { + this.rotImage = new BufferedImage(reqRotBufferWidth, reqRotBufferHeight, BufferedImage.TYPE_INT_ARGB); + rotBufferWidth = reqRotBufferWidth; + rotBufferHeight = reqRotBufferHeight; + bufferImageResized = true; + } + + rotProjection = projectionFactory.makeProjection(proj.getClass(), center, proj.getScale(), rotBufferWidth, + rotBufferHeight); + this.rotCenter = rotProjection.forward(center); + + /* * Now calculate the different in size between the current * projection and the buffered image projection, and the offset * needed for translation for proper painting. - */ - this.rotXOffset = (rotProjection.getWidth() - proj.getWidth()) / 2; - this.rotYOffset = (rotProjection.getHeight() - proj.getHeight()) / 2; - - return bufferImageResized; - } - - public void updateAngle(double angle) { - this.angle = angle; - this.rotTransform = AffineTransform.getRotateInstance(angle, rotCenter.getX(), rotCenter.getY()); - } - - /** - * @param az angle to test against - * @return true if current angle or new angle is not zero. Two zero - * angles in a row is an indication that the RotationHelper is - * no longer needed. - */ - public boolean isStillNeeded(double az) { - return !(az == 0.0 && angle == 0.0); - } - - /** - * @return the projection of the image buffer that is big enough for - * rotated areas. - */ - public Projection getProjection() { - return rotProjection; - } - - public void paintChildren(Graphics g, Rectangle clip) { - - if (rotProjection == null) { - // We're not properly prepared for rotation, return; - return; - } - - Graphics2D g2 = (Graphics2D) rotImage.getGraphics(); - ((Proj) rotProjection).drawBackground(g2, getBckgrnd()); - g2.setTransform(rotTransform); - paintLayers(g2); - g.drawImage(rotImage, -rotXOffset, -rotYOffset, null); - g2.dispose(); - } - - public void paintPainters(Graphics g) { - Graphics2D g2 = (Graphics2D) g.create(); - AffineTransform transform = AffineTransform.getTranslateInstance(-rotXOffset + getX(), - -rotYOffset + getY()); - transform.concatenate(rotTransform); - g2.setTransform(transform); - - painters.paint(g2); - g2.dispose(); - } - - /** - * @return a Graphics object from the MapBean with the rotation - * transform applied. - */ - public Graphics getGraphics() { - Graphics2D g = (Graphics2D) MapBean.super.getGraphics().create(); - g.setTransform(rotTransform); - return g; - } - - /** - * Performs a projection.inverse operation that also takes into account - * rotation. - * - * @param x pixel x - * @param y pixel y - * @param ret T in the coordinate space of projection. - * @return T, either ret or a new object. - */ - public T inverse(double x, double y, T ret) { - - Point2D pnt = new Point2D.Double(x + rotXOffset, y + rotYOffset); - - try { - pnt = rotTransform.inverseTransform(pnt, pnt); - return getProjection().inverse(pnt, ret); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, e.getMessage(), e); - } - - return ret; - } - - /** - * Returns dst, the unrotated pixel location of the map. - * - * @param src the pixel point - * @param dst - * @return see above. - */ - public Point2D inverseTransform(Point2D src, Point2D dst) { - try { - src.setLocation(src.getX() + rotXOffset, src.getY() + rotYOffset); - dst = rotTransform.inverseTransform(src, dst); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, e.getMessage(), e); - } - return dst; - } - - /** - * Returns a transformed version of the Shape, unrotated into the - * projected pixel space of the layer OMGraphics. - * - * @param shape to transform - * @return the transformed shape. - */ - public Shape inverseTransform(Shape shape) { - - float[] coords = new float[6]; - GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - - PathIterator pi = shape.getPathIterator(getInverseRotationTransform()); - while (!pi.isDone()) { - int type = pi.currentSegment(coords); - - if (type == PathIterator.SEG_MOVETO) { - path.moveTo(coords[0], coords[1]); - } else if (type == PathIterator.SEG_LINETO) { - path.lineTo(coords[0], coords[1]); - } else if (type == PathIterator.SEG_CLOSE) { - path.closePath(); - } else { - if (type == PathIterator.SEG_QUADTO) { - path.quadTo(coords[0], coords[1], coords[2], coords[3]); - } else if (type == PathIterator.SEG_CUBICTO) { - path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); - } - } - - pi.next(); - } - - return path; - } - - public AffineTransform getInverseRotationTransform() { - try { - AffineTransform translateOffset = AffineTransform.getTranslateInstance(rotXOffset, rotYOffset); - AffineTransform transform = rotTransform.createInverse(); - translateOffset.preConcatenate(transform); - return translateOffset; - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "AffineTransform problem", e); - } - - return new AffineTransform(); - } - - public void dispose() { - if (rotImage != null) { - rotImage.flush(); - } - } - } - -} \ No newline at end of file + */ + this.rotXOffset = (rotProjection.getWidth() - proj.getWidth()) / 2; + this.rotYOffset = (rotProjection.getHeight() - proj.getHeight()) / 2; + + return bufferImageResized; + } + + public void updateAngle(double angle) { + this.angle = angle; + this.rotTransform = AffineTransform.getRotateInstance(angle, rotCenter.getX(), rotCenter.getY()); + } + + /** + * @param az angle to test against + * @return true if current angle or new angle is not zero. Two zero + * angles in a row is an indication that the RotationHelper is no longer + * needed. + */ + public boolean isStillNeeded(double az) { + return !(az == 0.0 && angle == 0.0); + } + + /** + * @return the projection of the image buffer that is big enough for + * rotated areas. + */ + public Projection getProjection() { + return rotProjection; + } + + public void paintChildren(Graphics g, Rectangle clip) { + + if (rotProjection == null) { + // We're not properly prepared for rotation, return; + return; + } + + Graphics2D g2 = (Graphics2D) rotImage.getGraphics(); + ((Proj) rotProjection).drawBackground(g2, getBckgrnd()); + g2.setTransform(rotTransform); + paintLayers(g2); + g.drawImage(rotImage, -rotXOffset, -rotYOffset, null); + g2.dispose(); + } + + public void paintPainters(Graphics g) { + Graphics2D g2 = (Graphics2D) g.create(); + AffineTransform transform = AffineTransform.getTranslateInstance(-rotXOffset + getX(), + -rotYOffset + getY()); + transform.concatenate(rotTransform); + g2.setTransform(transform); + + painters.paint(g2); + g2.dispose(); + } + + /** + * @return a Graphics object from the MapBean with the rotation + * transform applied. + */ + public Graphics getGraphics() { + Graphics2D g = (Graphics2D) MapBean.super.getGraphics().create(); + g.setTransform(rotTransform); + return g; + } + + /** + * Performs a projection.inverse operation that also takes into account + * rotation. + * + * @param x pixel x + * @param y pixel y + * @param ret T in the coordinate space of projection. + * @return T, either ret or a new object. + */ + public T inverse(double x, double y, T ret) { + + Point2D pnt = new Point2D.Double(x + rotXOffset, y + rotYOffset); + + try { + pnt = rotTransform.inverseTransform(pnt, pnt); + return getProjection().inverse(pnt, ret); + } catch (NoninvertibleTransformException e) { + logger.log(Level.FINE, e.getMessage(), e); + } + + return ret; + } + + /** + * Returns dst, the unrotated pixel location of the map. + * + * @param src the pixel point + * @param dst + * @return see above. + */ + public Point2D inverseTransform(Point2D src, Point2D dst) { + try { + src.setLocation(src.getX() + rotXOffset, src.getY() + rotYOffset); + dst = rotTransform.inverseTransform(src, dst); + } catch (NoninvertibleTransformException e) { + logger.log(Level.FINE, e.getMessage(), e); + } + return dst; + } + + /** + * Returns a transformed version of the Shape, unrotated into the + * projected pixel space of the layer OMGraphics. + * + * @param shape to transform + * @return the transformed shape. + */ + public Shape inverseTransform(Shape shape) { + + float[] coords = new float[6]; + GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + + PathIterator pi = shape.getPathIterator(getInverseRotationTransform()); + while (!pi.isDone()) { + int type = pi.currentSegment(coords); + + if (type == PathIterator.SEG_MOVETO) { + path.moveTo(coords[0], coords[1]); + } else if (type == PathIterator.SEG_LINETO) { + path.lineTo(coords[0], coords[1]); + } else if (type == PathIterator.SEG_CLOSE) { + path.closePath(); + } else { + if (type == PathIterator.SEG_QUADTO) { + path.quadTo(coords[0], coords[1], coords[2], coords[3]); + } else if (type == PathIterator.SEG_CUBICTO) { + path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); + } + } + + pi.next(); + } + + return path; + } + + public AffineTransform getInverseRotationTransform() { + try { + AffineTransform translateOffset = AffineTransform.getTranslateInstance(rotXOffset, rotYOffset); + AffineTransform transform = rotTransform.createInverse(); + translateOffset.preConcatenate(transform); + return translateOffset; + } catch (NoninvertibleTransformException e) { + logger.log(Level.FINE, "AffineTransform problem", e); + } + + return new AffineTransform(); + } + + public void dispose() { + if (rotImage != null) { + rotImage.flush(); + } + } + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/DDFSubfieldDefinition.java b/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/DDFSubfieldDefinition.java index 837d3c596..f600fcd57 100644 --- a/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/DDFSubfieldDefinition.java +++ b/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/DDFSubfieldDefinition.java @@ -372,7 +372,7 @@ public int getDataLength(byte[] pachSourceData, int nMaxBytes, * the next ExtractStringData() call on this DDFSubfieldDefn(). It * should not be freed by the application. */ - String extractStringData(byte[] pachSourceData, int nMaxBytes, + public String extractStringData(byte[] pachSourceData, int nMaxBytes, MutableInt pnConsumedBytes) { int oldConsumed = 0; if (pnConsumedBytes != null) { diff --git a/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/View8211.java b/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/View8211.java index 3dfbfffd6..6d1d29078 100644 --- a/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/View8211.java +++ b/src/core/src/main/java/com/bbn/openmap/dataAccess/iso8211/View8211.java @@ -30,11 +30,10 @@ package com.bbn.openmap.dataAccess.iso8211; -import java.io.IOException; -import java.util.Iterator; - import com.bbn.openmap.layer.vpf.MutableInt; import com.bbn.openmap.util.Debug; +import java.io.IOException; +import java.util.Iterator; /** * Class that uses the DDF* classes to read an 8211 file and print out the diff --git a/src/core/src/main/java/com/bbn/openmap/dataAccess/srtm/SRTMFrame.java b/src/core/src/main/java/com/bbn/openmap/dataAccess/srtm/SRTMFrame.java new file mode 100644 index 000000000..6f3e0a404 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/dataAccess/srtm/SRTMFrame.java @@ -0,0 +1,588 @@ +// ********************************************************************** +// +// +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// +// ********************************************************************** +// +// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/dataAccess/dted/SRTMFrame.java,v $ +// $RCSfile: SRTMFrame.java,v $ +// $Revision: 1.7 $ +// $Date: 2008/02/29 00:51:10 $ +// $Author: dietrick $ +// +// ********************************************************************** +package com.bbn.openmap.dataAccess.srtm; + +import com.bbn.openmap.dataAccess.dted.*; +import java.io.FileNotFoundException; +import java.io.IOException; + +import com.bbn.openmap.io.BinaryBufferedFile; +import com.bbn.openmap.io.BinaryFile; +import com.bbn.openmap.io.Closable; +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.omGraphics.OMGraphic; +import com.bbn.openmap.omGraphics.OMGrid; +import com.bbn.openmap.omGraphics.OMRaster; +import com.bbn.openmap.omGraphics.grid.OMGridData; +import com.bbn.openmap.omGraphics.grid.SlopeGenerator; +import com.bbn.openmap.proj.CADRG; +import com.bbn.openmap.proj.Length; +import com.bbn.openmap.proj.Projection; +import com.bbn.openmap.proj.coords.LatLonPoint; +import com.bbn.openmap.util.Debug; + +/** + * The SRTMFrame is the representation of the SRTM (Shuttle Radar Topography + * Mission) data from a single srtm data file. It keeps track of all the + * attribute information of its data. It can return an OMGrid object that can be + * configured to create a visual representation of the data, depending on what + * OMGridGenerators are used on the OMGrid object. + */ +public class SRTMFrame + implements Closable { + + public final static int SRTM1_DIMENSION = 3601; + public final static int SRTM3_DIMENSION = 1201; + + /** + * The binary buffered file to read the data from the file. + */ + protected BinaryFile binFile; + /** + * The path to the frame, including the frame name. + */ + protected String path; + /** + * The number of rows and values in the x, y dimension. + */ + int dimension; + + LatLonPoint frameLoc; + + /** + * The array of elevation posts. Note: the 0 index of the array in both + * directions is in the lower left corner of the matrix. As you increase + * indexes in both dimensions, you go up-right. + */ + protected short[][] elevations; // elevation posts + + /** + * Validity flag for the quality of the data file. + */ + public boolean frame_is_valid = false; + + // //////////////// + // Administrative methods + // //////////////// + /** + * Simplest constructor. + * + * @param filePath complete path to the DTED frame. + */ + public SRTMFrame(String filePath) { + this(filePath, false); + } + + /** + * Constructor with colortable and presentation information. + * + * @param filePath complete path to the DTED frame. + * @param readWholeFile If true, all of the elevation data will be read at + * load time. If false, elevation post data will be read in per longitude + * column depending on the need. False is recommended for SRTM level 1 and + * 2. + */ + public SRTMFrame(String filePath, boolean readWholeFile) { + try { + + frameLoc = parseLocation(filePath); + + binFile = new BinaryBufferedFile(filePath); + dimension = SRTM3_DIMENSION; + + read(binFile, readWholeFile); + if (readWholeFile) { + close(true); + } else { + BinaryFile.addClosable(this); + } + + } catch (FileNotFoundException e) { + Debug.error("SRTMFrame: file " + filePath + " not found"); + } catch (IOException e) { + Debug.error("SRTMFrame: File IO Error!\n" + e.toString()); + } + + path = filePath; + } + + /** + * Reads the DTED frame file. Assumes that the File f is valid/exists. + * + * @param binFile the binary buffered file opened on the DTED frame file + * @param readWholeFile flag controlling whether all the row data is read at + * this time. Otherwise, the rows are read as needed. + */ + private void read(BinaryFile binFile, boolean readWholeFile) { + binFile.byteOrder(true); // boolean msbfirst + // Allocate just the columns now - we'll do the rows as + // needed... + elevations = new short[dimension][]; + if (readWholeFile) { + readDataRecords(); + } + frame_is_valid = true; + } + + private LatLonPoint parseLocation(String filePath) { + int startIndex = filePath.lastIndexOf('/') + 1; + + String name = filePath.substring(startIndex, startIndex + 7).toUpperCase(); + int sign = name.charAt(0) == 'S' ? -1 : 1; + double lat = Double.parseDouble(name.substring(1, 3)) * sign; + sign = name.charAt(3) == 'W' ? -1 : 1; + double lon = Double.parseDouble(name.substring(4)) * sign; + + LatLonPoint loc = new LatLonPoint.Double(lat, lon); + return loc; + } + + public LatLonPoint getLocation() { + return frameLoc; + } + + /** + * This must get called to break a reference cycle that prevents the garbage + * collection of frames. + */ + public void dispose() { + // System.out.println("DTED Frame Disposed " + me); + this.close(true); + BinaryFile.removeClosable(this); + } + + /** + * Part of the Closable interface. Closes the BinaryFile pointer, because + * someone else needs another file open, and the system needs a file + * pointer. Sets the binFile variable to null. + */ + public boolean close(boolean done) { + try { + if (binFile != null) { + binFile.close(); + binFile = null; + } + return true; + } catch (IOException e) { + Debug.error("SRTMFrame close(): File IO Error!\n" + e.toString()); + return false; + } + } + + /** + * If the BinaryBufferedFile was closed, this method attempts to reopen it. + * + * @return true if the opening was successful. + */ + protected boolean reopen() { + try { + binFile = new BinaryBufferedFile(path); + return true; + } catch (FileNotFoundException e) { + Debug.error("SRTMFrame reopen(): file " + path + " not found"); + return false; + } catch (IOException e) { + Debug.error("SRTMFrame close(): File IO Error!\n" + e.toString()); + return false; + } + } + + // //////////////// + // These functions can be called from the outside, + // as queries about the data + // //////////////// + /** + * The elevation at the closest SW post to the given lat/lon. This is just a + * go-to-the-closest-post solution. + * + * @param lat latitude in decimal degrees. + * @param lon longitude in decimal degrees. + * @return elevation at lat/lon in meters. + */ + public int elevationAt(float lat, float lon) { + if (frame_is_valid == true) { + LatLonPoint loc = getLocation(); + double fLatitude = loc.getLatitude(); + double fLongitude = loc.getLongitude(); + if (lat >= fLatitude && lat <= fLatitude + 1.0 && lon >= fLongitude && lon <= fLongitude + 1.0) { + + // lat/lon_post_intervals are *10 too big - + // extra 0 in 36000 to counteract + int lat_index = (int) Math.round((lat - fLatitude) * (dimension - 1)); + int lonIndex = (int) Math.round((lon - fLongitude) * (dimension - 1)); + + if (elevations[lonIndex] == null) { + readDataRecord(lonIndex); + } + + return (int) elevations[lonIndex][lat_index]; + } + } + return -32767; // Considered a null elevation value + } + + /** + * Interpolated elevation at a given lat/lon - should be more precise than + * elevationAt(), but that depends on the resolution of the data. + * + * @param lat latitude in decimal degrees. + * @param lon longitude in decimal degrees. + * @return elevation at lat/lon in meters. + */ + public int interpElevationAt(float lat, float lon) { + if (frame_is_valid == true) { + LatLonPoint loc = getLocation(); + double fLatitude = loc.getLatitude(); + double fLongitude = loc.getLongitude(); + if (lat >= fLatitude && lat <= fLatitude + 1.0 && lon >= fLongitude && lon <= fLongitude + 1.0) { + + // lat/lon_post_intervals are *10 too big - + // extra 0 in 36000 to counteract + int numIndexes = dimension - 1; + double latIndex = (lat - fLatitude) * numIndexes; + double lonIndex = (lon - fLongitude) * numIndexes; + + int lflonIndex = (int) Math.floor(lonIndex); + int lclonIndex = (int) Math.ceil(lonIndex); + /* int lflat_index = (int) Math.floor(lat_index); */ + int lclat_index = (int) Math.ceil(latIndex); + + if (elevations[lflonIndex] == null) { + readDataRecord(lflonIndex); + } + if (elevations[lclonIndex] == null) { + readDataRecord(lclonIndex); + } + + // //////////////////////////////////////////////////// + // Print out grid of 20x20 elevations with + // the "asked for" point being in the middle + // System.out.println("***Elevation Map***"); + // for(int l = lclat_index + 5; l > lflat_index - 5; + // l--) { + // System.out.println(); + // for(int k = lflonIndex - 5; k < lclonIndex + 5; + // k++) { + // if (elevations[k]==null) readDataRecord(k); + // System.out.print(elevations[k][l] + " "); + // } + // } + // System.out.println();System.out.println(); + // //////////////////////////////////////////////////// + int ul = elevations[lflonIndex][lclat_index]; + int ur = elevations[lclonIndex][lclat_index]; + int ll = elevations[lflonIndex][lclat_index]; + int lr = elevations[lclonIndex][lclat_index]; + + double answer = resolveFourPoints(ul, ur, lr, ll, latIndex, lonIndex); + return (int) Math.round(answer); + } + } + return -32767; // Considered a null elevation value + } + + /** + * Return an index of ints representing the starting x, y and ending x, y of + * elevation posts given a lat lon box. It does check to make sure that the + * upper lat is larger than the lower, and left lon is less than the right. + * + * @param ullat upper latitude in decimal degrees. + * @param ullon left longitude in decimal degrees. + * @param lrlat lower latitude in decimal degrees. + * @param lrlon right longitude in decimal degrees. + * @return int[4] array of start x, start y, end x, and end y. + */ + public int[] getIndexesFromLatLons(float ullat, float ullon, float lrlat, float lrlon) { + float upper = ullat; + float lower = lrlat; + float right = lrlon; + float left = ullon; + + // Since matrix indexes depend on these being in the right + // order, we'll double check and flip values, just to make + // sure lower is lower, and higher is higher. + if (ullon > lrlon) { + right = ullon; + left = lrlon; + } + + if (lrlat > ullat) { + upper = lrlat; + lower = ullat; + } + + int[] ret = new int[4]; + double swLat = frameLoc.getLatitude(); + double swLon = frameLoc.getLongitude(); + + double numIndexes = dimension - 1; + double ullat_index = (upper - swLat) * numIndexes; + double ullonIndex = (left - swLon) * numIndexes; + double lrlat_index = (lower - swLat) * numIndexes; + double lrlonIndex = (right - swLon) * numIndexes; + + ret[0] = (int) Math.round(ullonIndex); + ret[1] = (int) Math.round(lrlat_index); + ret[2] = (int) Math.round(lrlonIndex); + ret[3] = (int) Math.round(ullat_index); + + if (ret[0] < 0) { + ret[0] = 0; + } + if (ret[0] > dimension - 2) { + ret[0] = dimension - 2; + } + if (ret[1] < 0) { + ret[1] = 0; + } + if (ret[1] > dimension - 2) { + ret[1] = dimension - 2; + } + if (ret[2] < 0) { + ret[2] = 0; + } + if (ret[2] > dimension - 2) { + ret[2] = dimension - 2; + } + if (ret[3] < 0) { + ret[3] = 0; + } + if (ret[3] > dimension - 2) { + ret[3] = dimension - 2; + } + return ret; + + } + + /** + * Return a two dimensional array of posts between lat lons. + * + * @param ullat upper latitude in decimal degrees. + * @param ullon left longitude in decimal degrees. + * @param lrlat lower latitude in decimal degrees. + * @param lrlon right longitude in decimal degrees. + * @return array of elevations in meters. The spacing of the posts depends + * on the DTED level. + */ + public short[][] getElevations(float ullat, float ullon, float lrlat, float lrlon) { + int[] indexes = getIndexesFromLatLons(ullat, ullon, lrlat, lrlon); + return getElevations(indexes[0], indexes[1], indexes[2], indexes[3]); + } + + /** + * Return a two dimensional array of posts between lat lons. Assumes that + * the indexes are checked to not exceed their bounds as defined in the + * file. getIndexesFromLatLons() checks this. + * + * @param startx starting index (left) of the greater matrix to make the + * left side of the returned matrix. + * @param starty starting index (lower) of the greater matrix to make the + * bottom side of the returned matrix. + * @param endx ending index (right) of the greater matrix to make the left + * side of the returned matrix. + * @param endy ending index (top) of the greater matrix to make the top side + * of the returned matrix. + * @return array of elevations in meters. The spacing of the posts depends + * on the DTED level. + */ + public short[][] getElevations(int startx, int starty, int endx, int endy) { + int upper = endy; + int lower = starty; + int right = endx; + int left = startx; + + // Since matrix indexes depend on these being in the right + // order, we'll double check and flip values, just to make + // sure lower is lower, and higher is higher. + if (startx > endx) { + right = startx; + left = endx; + } + + if (starty > endy) { + upper = starty; + lower = endy; + } + + short[][] matrix = new short[right - left + 1][upper - lower + 1]; + int matrixColumn = 0; + for (int x = left; x <= right; x++) { + if (elevations[x] == null) { + readDataRecord(x); + } + System.arraycopy(elevations[x], lower, matrix[matrixColumn], 0, (upper - lower + 1)); + matrixColumn++; + } + return matrix; + } + + // //////////////// + // Internal methods + // //////////////// + /** + * A try at interpolating the corners of the surrounding posts, given a lat + * lon. Called from a function where the data for the lon has been read in. + */ + private double resolveFourPoints(int ul, int ur, int lr, int ll, double latIndex, double lonIndex) { + double top_avg = ((lonIndex - Math.floor(lonIndex)) * (float) (ur - ul)) + ul; + double bottom_avg = ((lonIndex - Math.floor(lonIndex)) * (float) (lr - ll)) + ll; + double right_avg = ((latIndex - Math.floor(latIndex)) * (float) (ur - lr)) + lr; + double left_avg = ((latIndex - Math.floor(latIndex)) * (float) (ul - ll)) / 100.0F + ll; + + double lonAvg = ((latIndex - Math.floor(latIndex)) * (top_avg - bottom_avg)) + bottom_avg; + double latAvg = ((lonIndex - Math.floor(lonIndex)) * (right_avg - left_avg)) + left_avg; + + double result = (lonAvg + latAvg) / 2.0; + return result; + } + + /** + * Reads one longitude line of posts. Assumes that the binFile is valid. + * + * @param lonIndex the column of data to read + * @return true if the column of data was successfully read + */ + protected boolean readDataRecord(int lonIndex) { + try { + if (binFile == null) { + if (!reopen()) { + return false; + } + } + + binFile.seek((lonIndex * (2 * dimension))); + // Allocate the rows of the row + elevations[lonIndex] = new short[dimension]; + for (int j = 0; j < dimension; j++) { + elevations[lonIndex][j] = binFile.readShortData(); + } + + } catch (IOException e3) { + Debug.error("SRTMFrame.RDR: Error reading file."); + e3.printStackTrace(); + elevations[lonIndex] = null; + return false; + } catch (FormatException f) { + Debug.error("SRTMFrame.RDR: File IO Format error!"); + elevations[lonIndex] = null; + return false; + } + return true; + } + + /** + * Read all the elevation posts, at one time. Assumes that the file is open + * and ready. + * + * @return true if the elevation columns were read. + */ + protected boolean readDataRecords() { + boolean ret = true; + for (int lonIndex = 0; lonIndex < dimension; lonIndex++) { + if (readDataRecord(lonIndex) == false) { + ret = false; + } + } + return ret; + } + + public OMGrid getOMGrid() { + // vResolution decimal degrees per row + double resolution = 1.0 / (dimension - 1); + + if (Debug.debugging("grid")) { + Debug.output("SRTMFrame creating OMGrid with resolution: " + resolution + ", created from:" + frameLoc + ", dimension: " + dimension); + } + + LatLonPoint fLoc = getLocation(); + double lat = fLoc.getLatitude(); + double lon = fLoc.getLongitude(); + + OMDTEDGrid omg + = new OMDTEDGrid(lat, lon, lat + 1.0, lon + 1.0, (float) resolution, (float) resolution, + new OMGridData.Short(elevations)); + omg.setUnits(Length.METER); + return omg; + } + + /** + * If you just want to get an image for the SRTMFrame, then call this. One + * image in an OMGraphic for the entire SRTMFrame will be returned, with the + * default rendering parameters (Colored shading) and the default + * colortable. Use the other getImage method if you want something + * different. This method actually calls that other method, so read the + * documentation for that as well. + * + * @param proj EqualArc projection to use to create image. + * @return raster image OMGraphic to display in OpenMap. + */ + public OMGraphic getImage(Projection proj) { + OMGrid grid = getOMGrid(); + grid.generate(proj); + SlopeGenerator sg = new SlopeGenerator(); + return sg.generateRasterForProjection(grid, proj); + } + + public static void main(String args[]) { + Debug.init(); + if (args.length < 1) { + System.out.println("SRTMFrame: Need a path/filename"); + System.exit(0); + } + + String fileName = args[0]; + System.out.println("SRTMFrame: " + fileName); + SRTMFrame df = new SRTMFrame(fileName, true); + + CADRG crg = new CADRG(df.getLocation(), 1500000, 600, 600); + + final OMGraphic ras = df.getImage(crg); + + java.awt.Frame window = new java.awt.Frame(fileName) { + public void paint(java.awt.Graphics g) { + if (ras instanceof OMRaster) { + OMRaster raster = (OMRaster) ras; + g.translate(-100, 100); + ras.render(g); + } + } + }; + + window.addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent e) { + // need a shutdown event to notify other gui beans and + // then exit. + System.exit(0); + } + }); + + if (ras instanceof OMRaster) { + OMRaster raster = (OMRaster) ras; + System.out.println("Setting window to " + raster.getWidth() + ", " + raster.getHeight()); + window.setSize(raster.getWidth(), raster.getHeight()); + } else { + window.setSize(250, 250); + } + window.setVisible(true); + window.repaint(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/event/AbstractMouseMode.java b/src/core/src/main/java/com/bbn/openmap/event/AbstractMouseMode.java index da3d0a2f7..85294f5e1 100644 --- a/src/core/src/main/java/com/bbn/openmap/event/AbstractMouseMode.java +++ b/src/core/src/main/java/com/bbn/openmap/event/AbstractMouseMode.java @@ -19,13 +19,17 @@ // $Author: dietrick $ // // ********************************************************************** - package com.bbn.openmap.event; +import com.bbn.openmap.Layer; +import com.bbn.openmap.MapBean; +import com.bbn.openmap.MouseDelegator; +import com.bbn.openmap.OMComponent; +import com.bbn.openmap.util.I18n; +import com.bbn.openmap.util.PropUtils; +import com.bbn.openmap.util.propertyEditor.OptionPropertyEditor; import java.awt.Cursor; import java.awt.Graphics; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.beans.PropertyChangeListener; @@ -35,845 +39,890 @@ import java.net.MalformedURLException; import java.util.Properties; import java.util.logging.Logger; - import javax.swing.Icon; import javax.swing.ImageIcon; -import javax.swing.Timer; - -import com.bbn.openmap.Layer; -import com.bbn.openmap.MapBean; -import com.bbn.openmap.MouseDelegator; -import com.bbn.openmap.OMComponent; -import com.bbn.openmap.util.I18n; -import com.bbn.openmap.util.PropUtils; -import com.bbn.openmap.util.propertyEditor.OptionPropertyEditor; /** * Base class of the MouseModes. It takes care of the administrative aspects of * being a mouse mode, but does not respond to MouseEvents. *

* The ID and pretty name can be set in the properties file. - * + * *

- * 
- * 
+ *
+ *
  *    # Name that layers use to get events from this mode
  *    mousemode.id=ID
  *    # Tooltip and Menu name for mode
  *    mousemode.prettyName=Display Name
- * 
- * 
- * 
- * 
+ *
+ *
+ *
+ *
  * 
- * + * * This class delegates much of the work of managing its listeners to a * MapMouseSupport object. - * + * * @see MapMouseSupport */ public class AbstractMouseMode - extends OMComponent - implements MapMouseMode, Serializable { - - private static final long serialVersionUID = 1L; - - protected static Logger logger = Logger.getLogger("com.bbn.openmap.event.MapMouseMode"); - - /** - * The identifier for the mode, which is also the name that will be used in a - * used interface describing the mode to a user. - */ - protected String ID = null; - - /** - * The object used to handle the listeners and to pass out the event to the - * layers interested in it. - */ - protected MapMouseSupport mouseSupport; - - /** - * The cursor that appears on the map when this Mouse Mode is active. - */ - protected Cursor cursor = Cursor.getDefaultCursor(); - - /** - * The Icon that can be used in a GUI. Can be null. The class will look for a - * resource gif file that has the same ID string - Navigation.gif for the - * NavMouseMode, for instance. - */ - protected transient Icon guiIcon = null; - - protected transient boolean visible = true; - - protected boolean mouseWheelListener = true; - - protected boolean noMouseWheelListenerTimer = false; - - protected String prettyName; - - protected String iconName; - - protected boolean zoomWhenMouseWheelUp = ZOOM_IN; - - protected PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - - /** - * Zoom direction in when mouse wheel rotated up. - */ - public static final boolean ZOOM_IN = true; - /** - * Zoom direction out when mouse wheel rotated up. - */ - public static final boolean ZOOM_OUT = false; - - /** - * The MouseModeID to use for a particular instance of a MapMouseMode. If not - * set, the default mouse mode ID of the MapMouseMode will be used. - */ - public static final String IDProperty = "id"; - - /** - * The String to use for a key lookup in a Properties object to find the name - * to use in a GUI relating to this Mouse Mode. - */ - public static final String PrettyNameProperty = "prettyName"; - - /** - * The java.awt.Cursor id that should be used for the mouse mode. - * - * @see java.awt.Cursor - */ - public static final String CursorIDProperty = "cursorID"; - - /** - * A property that lets you specify the resource to use for the icon for the - * MouseMode. - */ - public static final String IconProperty = "icon"; - - /** - * A property that lets you specify if the mode zooms in or out when the - * mouse wheel is rotated up. Appropriate values are ZOOM_IN or ZOOM_OUT. - */ - public static final String MouseWheelZoomProperty = "mouseWheelUp"; - - /** - * A property that lets you turn off the mouse wheel listening functionality. - * If enabled, the mouse wheel changes the scale of the map. - */ - public static final String MouseWheelListenerProperty = "mouseWheelListener"; - - /** - * A property that lets you turn off the mouse wheel timer. - * If disabled, a timer is used for dealing with the mouse wheel changes. - */ - public static final String NoMouseWheelListenerTimerProperty = "noMouseWheelListenerTimer"; - - /** - * A property that lets you set the wait interval before a mouse wheel event - * gets triggered. - */ - public static final String MouseWheelTimerIntervalProperty = "mouseWheelTimerInterval"; - - /** - * Construct an AbstractMouseMode. Default constructor, allocates the mouse - * support object. - */ - public AbstractMouseMode() { - this("Unnamed Mode", true); - } - - /** - * Construct an AbstractMouseMode. - * - * @param name the ID of the mode. - * @param shouldConsumeEvents if true, events are propagated to the first - * MapMouseListener that successfully processes the event, if false, - * events are propagated to all MapMouseListeners - */ - public AbstractMouseMode(String name, boolean shouldConsumeEvents) { - mouseSupport = new MapMouseSupport(this, shouldConsumeEvents); - ID = name; - setIconName(name + ".gif"); - } - - /** - * Internal callback method that lets subclasses override a class to use as a - * resource point for icon image retrieval. - * - * @return Class that has icon image file next to it in classpath. - */ - protected Class getClassToUseForIconRetrieval() { - return getClass(); - } - - /** - * Sets the GUI icon based on the name of the resource provided. The resource - * will be checked against the classpath, and if it isn't found, the mouse - * mode will be asked for the class to use for icon retrieval. - * - * @param iName - */ - public void setIconName(String iName) { - iconName = iName; - java.net.URL url = null; - - try { - url = PropUtils.getResourceOrFileOrURL(iName); - } catch (MalformedURLException murle) { - - } - - if (url == null) { - url = getClassToUseForIconRetrieval().getResource(iconName); - } - - if (url != null) { - guiIcon = new ImageIcon(url); - } - } - - public String getIconName() { - return iconName; - } - - /** - * Returns the id (mode name). - * - * @return String ID - */ - public String getID() { - return ID; - } - - /** - * Set the id (mode name). - * - * @param id string that identifies the delegate. - */ - public void setID(String id) { - ID = id; - } - - public void setPrettyName(String pn) { - prettyName = pn; - } - - /** - * Return a pretty name, suitable for the GUI. If set, is independent of the - * mode ID. If not set, is the same as the mode ID. - */ - public String getPrettyName() { - if (prettyName == null) { - return i18n.get(this.getClass(), PrettyNameProperty, ID); - } else { - return prettyName; - } - } - - /** - * Gets the mouse cursor recommended for use when this mouse mode is active. - * - * @return Cursor the mouse cursor recommended for use when this mouse mode - * is active. - */ - public Cursor getModeCursor() { - return cursor; - } - - /** - * Sets the cursor that is recommended for use on the map when this mouse - * mode is active. - * - * @param curs the cursor that is recommended for use on the map when this - * mouse mode is active. - */ - public void setModeCursor(Cursor curs) { - cursor = curs; - } - - /** - * Sets the cursor that is recommended for use on the map when this mouse - * mode is active. - * - * @param cursorID the cursor ID member variable string, i.e. DEFAULT_CURSOR - * @see java.awt.Cursor - */ - public void setModeCursor(String cursorID) { - if (cursorID != null) { - - try { - int cid = java.awt.Cursor.class.getField(cursorID).getInt(null); - - setModeCursor(Cursor.getPredefinedCursor(cid)); - - } catch (NoSuchFieldException nsfe) { - } catch (IllegalAccessException iae) { - } - } - } - - /** - * Gets the Icon to represent the Mouse Mode in a GUI. May be null. - */ - public Icon getGUIIcon() { - return guiIcon; - } - - /** - * Set the icon that should be used for this Mouse Mode in a GUI. - */ - public void setGUIIcon(Icon icon) { - guiIcon = icon; - } - - /** - * Sets how the delegate passes out events. If the value passed in is true, - * the delegate will only pass the event to the first listener that can - * respond to the event. If false, the delegate will pass the event on to all - * its listeners. - * - * @param value true for limited distribution. - */ - public void setConsumeEvents(boolean value) { - mouseSupport.setConsumeEvents(value); - } - - /** - * Returns how the delegate (and it's mouse support) is set up to distribute - * events. - * - * @return true if only one listener gets to act on an event. - */ - public boolean isConsumeEvents() { - return mouseSupport.isConsumeEvents(); - } - - public boolean isZoomWhenMouseWheelUp() { - return zoomWhenMouseWheelUp; - } - - public void setZoomWhenMouseWheelUp(boolean zoomWhenMouseWheelUp) { - this.zoomWhenMouseWheelUp = zoomWhenMouseWheelUp; - } - - /** - * Add a MapMouseListener to the MouseMode. The listener will then get events - * from the delegator if the delegator is active. - * - * @param l the MapMouseListener to add. - */ - public void addMapMouseListener(MapMouseListener l) { - mouseSupport.add(l); - } - - /** - * Remove a MapMouseListener from the MouseMode. - * - * @param l the MapMouseListener to remove. - */ - public void removeMapMouseListener(MapMouseListener l) { - mouseSupport.remove(l); - } - - /** - * Remove all MapMouseListeners from the mode. - */ - public void removeAllMapMouseListeners() { - mouseSupport.clear(); - } - - /** - * Invoked when the mouse has been clicked on a component. Calls - * fireMapMouseClicked on MouseSupport. - * - * @param e MouseEvent - */ - public void mouseClicked(MouseEvent e) { - mouseSupport.fireMapMouseClicked(e); - } - - /** - * Invoked when a mouse button has been pressed on a component. Calls - * fiewMapMousePressed on the MouseSupport. Also requests focus on the source - * of the MouseEvent, so that key events can be processed. - * - * @param e MouseEvent - */ - public void mousePressed(MouseEvent e) { - e.getComponent().requestFocus(); - mouseSupport.fireMapMousePressed(e); - } - - /** - * Invoked when a mouse button has been released on a component. Calls - * fireMapMouseReleased on the MouseSupport. - * - * @param e MouseEvent - */ - public void mouseReleased(MouseEvent e) { - mouseSupport.fireMapMouseReleased(e); - } - - /** - * Invoked when the mouse enters a component. Calls fireMapMouseEntered on - * the MouseSupport. - * - * @param e MouseEvent - */ - public void mouseEntered(MouseEvent e) { - mouseSupport.fireMapMouseEntered(e); - } - - /** - * Invoked when the mouse exits a component. This does nothing. Extend this - * class to add functionality. - * - * @param e MouseEvent - */ - public void mouseExited(MouseEvent e) { - mouseSupport.fireMapMouseExited(e); - } - - /** - * Invoked when a mouse button is pressed on a component and then dragged. - * Calls fireMapMouseDragged on the MouseSupport. - * - * @param e MouseEvent - */ - public void mouseDragged(MouseEvent e) { - mouseSupport.fireMapMouseDragged(e); - } - - /** - * Invoked when the mouse button has been moved on a component (with no - * buttons no down). Calls fireMapMouseMoved on the MouseSupport. - * - * @param e MouseEvent - */ - public void mouseMoved(MouseEvent e) { - mouseSupport.fireMapMouseMoved(e); - } - - /** - * Invoked from the MouseWheelListener interface. - */ - public void mouseWheelMoved(MouseWheelEvent e) { - if (mouseWheelListener) { - int rot = e.getWheelRotation(); - if (e.getSource() instanceof MapBean) { - MapBean mb = (MapBean) e.getSource(); - boolean direction = isZoomWhenMouseWheelUp(); - - float zoomIn = 1.1f; - float zoomOut = .9f; - - float amount = zoomIn; - - if ((direction && rot < 0) || (!direction && rot > 0)) { - amount = zoomOut; - } + extends OMComponent + implements MapMouseMode, Serializable { + + private static final long serialVersionUID = 1L; + + /** + * + */ + protected final static Logger logger = Logger.getLogger("com.bbn.openmap.event.MapMouseMode"); + + /** + * The identifier for the mode, which is also the name that will be used in + * a used interface describing the mode to a user. + */ + protected String ID = null; + + /** + * The object used to handle the listeners and to pass out the event to the + * layers interested in it. + */ + protected MapMouseSupport mouseSupport; + + /** + * The cursor that appears on the map when this Mouse Mode is active. + */ + protected Cursor cursor = Cursor.getDefaultCursor(); + + /** + * The Icon that can be used in a GUI. Can be null. The class will look for + * a resource gif file that has the same ID string - Navigation.gif for the + * NavMouseMode, for instance. + */ + protected transient Icon guiIcon = null; + + /** + * + */ + protected transient boolean visible = true; + + /** + * + */ + protected boolean mouseWheelListenerActive = true; + + /** + * + */ + protected boolean noMouseWheelListenerTimer = false; + + /** + * + */ + protected String prettyName; + + /** + * + */ + protected String iconName; + + /** + * + */ + protected boolean zoomWhenMouseWheelUp = ZOOM_IN; + + protected long lastMouseWheelEventTime; + /** + * The wait interval before a mouse wheel event a reaction from the last one. + */ + protected int mouseWheelTimerInterval = 60; + /** + * zoom factor + */ + protected transient float zoomFactor = 1.3f; + + /** + * + */ + protected PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); + + /** + * Zoom direction in when mouse wheel rotated up. + */ + public static final boolean ZOOM_IN = true; + /** + * Zoom direction out when mouse wheel rotated up. + */ + public static final boolean ZOOM_OUT = false; + + /** + * The MouseModeID to use for a particular instance of a MapMouseMode. If + * not set, the default mouse mode ID of the MapMouseMode will be used. + */ + public static final String ID_PROPERTY = "id"; + + /** + * The String to use for a key lookup in a Properties object to find the + * name to use in a GUI relating to this Mouse Mode. + */ + public static final String PRETTY_NAME_PROPERTY = "prettyName"; + + /** + * The java.awt.Cursor id that should be used for the mouse mode. + * + * @see java.awt.Cursor + */ + public static final String CURSOR_ID_PROPERTY = "cursorID"; + + /** + * A property that lets you specify the resource to use for the icon for the + * MouseMode. + */ + public static final String ICON_PROPERTY = "icon"; + + /** + * A property that lets you specify if the mode zooms in or out when the + * mouse wheel is rotated up. Appropriate values are ZOOM_IN or ZOOM_OUT. + */ + public static final String MOUSE_WHEEL_ZOOM_PROPERTY = "mouseWheelUp"; + + /** + * A property that lets you turn off the mouse wheel listening + * functionality. If enabled, the mouse wheel changes the scale of the map. + */ + public static final String MOUSE_WHEEL_LISTENER_PROPERTY = "mouseWheelListener"; + + /** + * A property that lets you turn off the mouse wheel timer. If disabled, a + * timer is used for dealing with the mouse wheel changes. + */ + public static final String NO_MOUSE_WHEEL_LISTENER_PROPERTY = "noMouseWheelListenerTimer"; + + /** + * A property that lets you set the wait interval before a mouse wheel event + * gets triggered. + */ + public static final String MOUSE_WHEEL_TIMER_INTERVAL_PROPERTY = "mouseWheelTimerInterval"; + + /** + * Construct an AbstractMouseMode. Default constructor, allocates the mouse + * support object. + */ + public AbstractMouseMode() { + this("Unnamed Mode", true); + } + + /** + * Construct an AbstractMouseMode. + * + * @param name the ID of the mode. + * @param shouldConsumeEvents if true, events are propagated to the first + * MapMouseListener that successfully processes the event, if false, events + * are propagated to all MapMouseListeners + */ + public AbstractMouseMode(String name, boolean shouldConsumeEvents) { + mouseSupport = new MapMouseSupport(this, shouldConsumeEvents); + ID = name; + setIconName(name + ".gif"); + + lastMouseWheelEventTime = System.currentTimeMillis(); + } + + /** + * Internal callback method that lets subclasses override a class to use as + * a resource point for icon image retrieval. + * + * @return Class that has icon image file next to it in classpath. + */ + protected Class getClassToUseForIconRetrieval() { + return getClass(); + } + + /** + * Sets the GUI icon based on the name of the resource provided. The + * resource will be checked against the classpath, and if it isn't found, + * the mouse mode will be asked for the class to use for icon retrieval. + * + * @param iName + */ + public void setIconName(String iName) { + iconName = iName; + java.net.URL url = null; + + try { + url = PropUtils.getResourceOrFileOrURL(iName); + } catch (MalformedURLException murle) { + + } + + if (url == null) { + url = getClassToUseForIconRetrieval().getResource(iconName); + } + + if (url != null) { + guiIcon = new ImageIcon(url); + } + } + + /** + * + * @return string of the icon name for the mouse mode + */ + public String getIconName() { + return iconName; + } + + /** + * Returns the id (mode name). + * + * @return String ID + */ + @Override + public String getID() { + return ID; + } + + /** + * Set the id (mode name). + * + * @param id string that identifies the delegate. + */ + public void setID(String id) { + ID = id; + } + + /** + * + * @param pn + */ + public void setPrettyName(String pn) { + prettyName = pn; + } + + /** + * Return a pretty name, suitable for the GUI. If set, is independent of the + * mode ID. If not set, is the same as the mode ID. + * + * @return pretty name string for name + */ + @Override + public String getPrettyName() { + if (prettyName == null) { + return i18n.get(this.getClass(), PRETTY_NAME_PROPERTY, ID); + } else { + return prettyName; + } + } + + /** + * Gets the mouse cursor recommended for use when this mouse mode is active. + * + * @return Cursor the mouse cursor recommended for use when this mouse mode + * is active. + */ + @Override + public Cursor getModeCursor() { + return cursor; + } + + /** + * Sets the cursor that is recommended for use on the map when this mouse + * mode is active. + * + * @param curs the cursor that is recommended for use on the map when this + * mouse mode is active. + */ + public void setModeCursor(Cursor curs) { + cursor = curs; + } + + /** + * Sets the cursor that is recommended for use on the map when this mouse + * mode is active. + * + * @param cursorID the cursor ID member variable string, i.e. DEFAULT_CURSOR + * @see java.awt.Cursor + */ + public void setModeCursor(String cursorID) { + if (cursorID != null) { + + try { + int cid = java.awt.Cursor.class.getField(cursorID).getInt(null); - if (noMouseWheelListenerTimer) { - updateMouseWheelMoved(mb, mb.getScale() * amount); - } else { - if (mouseTimer == null) { - mouseTimer = new Timer(mouseWheelTimerInterval, mouseWheelTimerListener); - mouseTimer.setRepeats(false); - } + setModeCursor(Cursor.getPredefinedCursor(cid)); - mouseWheelTimerListener.addAmount(mb, amount); - mouseTimer.restart(); + } catch (NoSuchFieldException | IllegalAccessException iae) { } - } - } - } - - /** - * Invoked from the MouseWheelListener interface. - */ - public void updateMouseWheelMoved(MapBean mb, float value) { - if (mb != null) { - mb.zoom(new ZoomEvent(mb, ZoomEvent.ABSOLUTE, value)); - } - } - - /** - * Check setting for whether MouseMode responds to mouse wheel events. - * - * @return true if mouse mode is interested in mouse wheel events. - */ - public boolean isMouseWheelListener() { - return mouseWheelListener; - } - - /** - * Set whether MouseMode responds to mouse wheel events. - * - * @param mouseWheelListener - */ - public void setMouseWheelListener(boolean mouseWheelListener) { - this.mouseWheelListener = mouseWheelListener; - } - - /** - * Part of the MapMouseMode interface. Called when the MouseMode is made - * active or inactive. - * - * @param active true if the mode has been made active, false if it has been - * made inactive. - */ - public void setActive(boolean active) { - } - - /** - * Set a MouseSupport explicitly. - * - * @param support The new MapMouseSupport instance - */ - public void setMouseSupport(MapMouseSupport support) { - mouseSupport = support; - } - - /** - * Get the MouseSupport. - * - * @return the MapMouseSupport used by the MouseMode. - */ - public MapMouseSupport getMouseSupport() { - return mouseSupport; - } - - /** - * Method to let the MouseDelegator know if the MapMouseMode should be - * visible, as opposed to a MapMouseMode that is being provided and - * controlled by another tool. True by default. - */ - public boolean isVisible() { - return visible; - } - - /** - * Method to set if the MapMouseMode should be visible, as opposed to a - * MapMouseMode that is being provided and controlled by another tool. - */ - public void setVisible(boolean value) { - visible = value; - } - - /** - * Request to have the parent MapMouseMode act as a proxy for a MapMouseMode - * that wants to remain hidden. Can be useful for directing events to one - * object. This version sets the proxy distribution mask to zero, which means - * that none of this support objects targets will be notified of events. - * - * @param mmm the hidden MapMouseMode for this MapMouseMode to send events - * to. - * @return true if the proxy setup (essentially a lock) is successful, false - * if the proxy is already set up for another listener. - */ - public boolean actAsProxyFor(MapMouseMode mmm) { - return actAsProxyFor(mmm, 0); - } - - /** - * Request to have the MapMouseMode act as a proxy for a MapMouseMode that - * wants to remain hidden. Can be useful for directing events to one object. - * - * @param mmm the hidden MapMouseMode for this MapMouseMode to send events - * to. - * @param pdm the proxy distribution mask to use, which lets this support - * object notify its targets of events if the parent is acting as a - * proxy. - * @return true if the proxy setup (essentially a lock) is successful, false - * if the proxy is already set up for another listener. - */ - public boolean actAsProxyFor(MapMouseMode mmm, int pdm) { - MapMouseMode omm = mouseSupport.getProxied(); - boolean ret = false; - if (mmm != null && !mmm.equals(omm)) { - ret = mouseSupport.setProxyFor(mmm, pdm); - propertyChangeSupport.firePropertyChange(MouseDelegator.ProxyMouseModeProperty, omm, mmm); - } - - return ret; - } - - /** - * Can check if the MapMouseMode is acting as a proxy for another - * MapMouseMode. - */ - public boolean isProxyFor(MapMouseMode mmm) { - return mouseSupport.isProxyFor(mmm); - } - - /** - * Release the proxy lock on the MapMouseMode. - */ - public void releaseProxy() { - MapMouseMode mmm = mouseSupport.getProxied(); - if (mmm != null) { - mouseSupport.releaseProxy(); - propertyChangeSupport.firePropertyChange(MouseDelegator.ProxyMouseModeProperty, mmm, null); - } - } - - /** - * Set the mask that dictates which events get sent to this support object's - * targets even if the parent mouse mode is acting as a proxy. - */ - public void setProxyDistributionMask(int mask) { - mouseSupport.setProxyDistributionMask(mask); - } - - /** - * Returns the MapMouseMode being held inside this mouse mode. - */ - public MapMouseMode getProxied() { - return mouseSupport.getProxied(); - } - - /** - * Get the mask that dictates which events get sent to this support object's - * targets even if the parent mouse mode is acting as a proxy. - */ - public int getProxyDistributionMask() { - return mouseSupport.getProxyDistributionMask(); - } - - public void setProperties(String prefix, Properties props) { - super.setProperties(prefix, props); - - prefix = PropUtils.getScopedPropertyPrefix(prefix); - - String prettyNameString = props.getProperty(prefix + PrettyNameProperty); - if (prettyNameString != null) { - setPrettyName(prettyNameString); - } - - String idString = props.getProperty(prefix + IDProperty); - if (idString != null) { - setID(idString); - } - - setModeCursor(props.getProperty(prefix + CursorIDProperty)); - - String iconString = props.getProperty(prefix + IconProperty); - if (iconString != null) { - setIconName(iconString); - } - - mouseWheelListener = PropUtils.booleanFromProperties(props, prefix + MouseWheelListenerProperty, mouseWheelListener); - - zoomWhenMouseWheelUp = PropUtils.booleanFromProperties(props, prefix + MouseWheelZoomProperty, zoomWhenMouseWheelUp); - - String zwmwu = props.getProperty(prefix + MouseWheelZoomProperty); - if (zwmwu != null) { - try { - boolean zSetting = getClass().getField(zwmwu).getBoolean(null); - setZoomWhenMouseWheelUp(zSetting); - } catch (NoSuchFieldException nsfe) { - } catch (IllegalAccessException iae) { - } - } - - noMouseWheelListenerTimer = PropUtils.booleanFromProperties(props, prefix + NoMouseWheelListenerTimerProperty, noMouseWheelListenerTimer); - mouseWheelTimerInterval = PropUtils.intFromProperties(props, prefix + MouseWheelTimerIntervalProperty, mouseWheelTimerInterval); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - - String prefix = PropUtils.getScopedPropertyPrefix(this); - if (prettyName != null) { - props.put(prefix + PrettyNameProperty, prettyName); - } - - props.put(prefix + IDProperty, getID()); - - int cursorType = getModeCursor().getType(); - - Field[] cFields = Cursor.class.getFields(); - for (int i = 0; i < cFields.length; i++) { - Field f = cFields[i]; - - String name = f.getName(); - if (name.endsWith("_CURSOR")) { - try { - int testType = f.getInt(null); - if (testType == cursorType) { - props.put(prefix + CursorIDProperty, name); - break; - } - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { + } + } + + /** + * Gets the Icon to represent the Mouse Mode in a GUI. May be null. + * + * @return + */ + @Override + public Icon getGUIIcon() { + return guiIcon; + } + + /** + * Set the icon that should be used for this Mouse Mode in a GUI. + * + * @param icon + */ + public void setGUIIcon(Icon icon) { + guiIcon = icon; + } + + /** + * Sets how the delegate passes out events. If the value passed in is true, + * the delegate will only pass the event to the first listener that can + * respond to the event. If false, the delegate will pass the event on to + * all its listeners. + * + * @param value true for limited distribution. + */ + public void setConsumeEvents(boolean value) { + mouseSupport.setConsumeEvents(value); + } + + /** + * Returns how the delegate (and it's mouse support) is set up to distribute + * events. + * + * @return true if only one listener gets to act on an event. + */ + public boolean isConsumeEvents() { + return mouseSupport.isConsumeEvents(); + } + + /** + * + * @return true if zoom in for moving mouse wheel up + */ + public boolean isZoomWhenMouseWheelUp() { + return zoomWhenMouseWheelUp; + } + + /** + * Set if zooming in when mouse wheel up + * + * @param zoomWhenMouseWheelUp + */ + public void setZoomWhenMouseWheelUp(boolean zoomWhenMouseWheelUp) { + this.zoomWhenMouseWheelUp = zoomWhenMouseWheelUp; + } + + /** + * Add a MapMouseListener to the MouseMode. The listener will then get + * events from the delegator if the delegator is active. + * + * @param l the MapMouseListener to add. + */ + @Override + public void addMapMouseListener(MapMouseListener l) { + mouseSupport.add(l); + } + + /** + * Remove a MapMouseListener from the MouseMode. + * + * @param l the MapMouseListener to remove. + */ + @Override + public void removeMapMouseListener(MapMouseListener l) { + mouseSupport.remove(l); + } + + /** + * Remove all MapMouseListeners from the mode. + */ + @Override + public void removeAllMapMouseListeners() { + mouseSupport.clear(); + } + + /** + * Invoked when the mouse has been clicked on a component. Calls + * fireMapMouseClicked on MouseSupport. + * + * @param e MouseEvent + */ + @Override + public void mouseClicked(MouseEvent e) { + mouseSupport.fireMapMouseClicked(e); + } + + /** + * Invoked when a mouse button has been pressed on a component. Calls + * fiewMapMousePressed on the MouseSupport. Also requests focus on the + * source of the MouseEvent, so that key events can be processed. + * + * @param e MouseEvent + */ + @Override + public void mousePressed(MouseEvent e) { + e.getComponent().requestFocus(); + mouseSupport.fireMapMousePressed(e); + } + + /** + * Invoked when a mouse button has been released on a component. Calls + * fireMapMouseReleased on the MouseSupport. + * + * @param e MouseEvent + */ + @Override + public void mouseReleased(MouseEvent e) { + mouseSupport.fireMapMouseReleased(e); + } + + /** + * Invoked when the mouse enters a component. Calls fireMapMouseEntered on + * the MouseSupport. + * + * @param e MouseEvent + */ + @Override + public void mouseEntered(MouseEvent e) { + mouseSupport.fireMapMouseEntered(e); + } + + /** + * Invoked when the mouse exits a component. This does nothing. Extend this + * class to add functionality. + * + * @param e MouseEvent + */ + @Override + public void mouseExited(MouseEvent e) { + mouseSupport.fireMapMouseExited(e); + } + + /** + * Invoked when a mouse button is pressed on a component and then dragged. + * Calls fireMapMouseDragged on the MouseSupport. + * + * @param e MouseEvent + */ + @Override + public void mouseDragged(MouseEvent e) { + mouseSupport.fireMapMouseDragged(e); + } + + /** + * Invoked when the mouse button has been moved on a component (with no + * buttons no down). Calls fireMapMouseMoved on the MouseSupport. + * + * @param e MouseEvent + */ + @Override + public void mouseMoved(MouseEvent e) { + mouseSupport.fireMapMouseMoved(e); + } + + /** + * Invoked from the MouseWheelListener interface. + */ + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + if (mouseWheelListenerActive) { + long currentTime = System.currentTimeMillis(); + if (currentTime - lastMouseWheelEventTime < 50 && !noMouseWheelListenerTimer) { + return; } - } - } - if (zoomWhenMouseWheelUp) { - props.put(prefix + MouseWheelZoomProperty, "ZOOM_IN"); - } else { - props.put(prefix + MouseWheelZoomProperty, "ZOOM_OUT"); - } - - props.put(prefix + MouseWheelListenerProperty, Boolean.toString(mouseWheelListener)); - - props.put(prefix + IconProperty, PropUtils.unnull(getIconName())); - - props.put(prefix + NoMouseWheelListenerTimerProperty, Boolean.toString(noMouseWheelListenerTimer)); - props.put(prefix + MouseWheelTimerIntervalProperty, Integer.toString(mouseWheelTimerInterval)); - - return props; - } - - public Properties getPropertyInfo(Properties props) { - props = super.getPropertyInfo(props); - - Class thisClass = getClass(); - String internString = i18n.get(thisClass, PrettyNameProperty, I18n.TOOLTIP, "Presentable name for Mouse Mode."); - props.put(Layer.AddToBeanContextProperty, internString); - internString = i18n.get(thisClass, PrettyNameProperty, "Name"); - props.put(PrettyNameProperty + LabelEditorProperty, internString); - - internString = i18n.get(thisClass, IDProperty, I18n.TOOLTIP, "Internal ID for Mouse Mode, used by Layers."); - props.put(Layer.AddToBeanContextProperty, internString); - internString = i18n.get(thisClass, IDProperty, "ID"); - props.put(IDProperty + LabelEditorProperty, internString); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, IconProperty, "Icon", "Icon to use for mouse mode.", null); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MouseWheelZoomProperty, "Mouse Wheel Zoom Direction", - "Action to take when the mouse wheel is rolled up.", - "com.bbn.openmap.util.propertyEditor.ComboBoxPropertyEditor"); - props.put(MouseWheelZoomProperty + OptionPropertyEditor.ScopedOptionsProperty, "zoomin zoomout"); - props.put(MouseWheelZoomProperty + ".zoomin", "ZOOM_IN"); - props.put(MouseWheelZoomProperty + ".zoomout", "ZOOM_OUT"); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MouseWheelListenerProperty, "Mouse Wheel Zoom", - "Setting for whether mouse wheel controls map zoom", - "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor"); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, CursorIDProperty, "Cursor", "Cursor to use for this mouse mode.", - "com.bbn.openmap.util.propertyEditor.ComboBoxPropertyEditor"); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, NoMouseWheelListenerTimerProperty, "No Mouse Wheel Listener Timer", - "Setting for whether a timer is used with the mouse wheel controller", - "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor"); - - PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MouseWheelTimerIntervalProperty, "Mouse Wheel Timer Interval", - "Setting for the wait interval for the mouse wheel timer", - null); - - StringBuffer cOptions = new StringBuffer(); - Field[] cFields = Cursor.class.getFields(); - for (int i = 0; i < cFields.length; i++) { - Field f = cFields[i]; - - String name = f.getName(); - if (name.endsWith("_CURSOR")) { - String cName = f.getName(); - props.put(CursorIDProperty + "." + cName, cName); - cOptions.append(" ").append(cName); - } - } - - props.put(CursorIDProperty + OptionPropertyEditor.ScopedOptionsProperty, cOptions.toString().trim()); - - return props; - } - - public void addPropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.addPropertyChangeListener(listener); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.removePropertyChangeListener(listener); - } - - /** - * PaintListener interface, notifying the MouseMode that the MapBean has - * repainted itself. Useful if the MouseMode is drawing stuff. - */ - public void listenerPaint(Object source, Graphics g) { - } - - - public void setNoMouseWheelListener(boolean val) { - noMouseWheelListenerTimer = val; - } - - /** - * - */ - public boolean getNoMouseWheelListener() { - return noMouseWheelListenerTimer; - } - - /** - * The wait interval before a mouse wheel event gets triggered. - */ - protected int mouseWheelTimerInterval = 60; - - /** - * Set the time interval that the mouse timer waits before calling - * upateMouseMoved. A negative number or zero will disable the timer. - */ - public void setMouseWheelTimerInterval(int interval) { - mouseWheelTimerInterval = interval; - if (mouseTimer != null) { - mouseTimer.setInitialDelay(mouseWheelTimerInterval); - } - } - - public int getMouseWheelTimerInterval() { - return mouseWheelTimerInterval; - } - - /** - * The timer used to track the wait interval. - */ - protected Timer mouseTimer = null; - - /** - * The timer listener that calls updateMouseMoved. - */ - protected MouseWheelTimerListener mouseWheelTimerListener = new MouseWheelTimerListener(); - - /** - * The definition of the listener that calls updateMouseMoved when the timer - * goes off. - */ - protected class MouseWheelTimerListener - implements ActionListener { - - float newScale = 0f; - MapBean mapBean; - - public synchronized void addAmount(MapBean map, float amount) { - mapBean = map; - - if (newScale == 0f) { - newScale = map.getScale() * amount; - } else { - newScale *= amount; - } - } - - public synchronized void actionPerformed(ActionEvent ae) { - if (newScale != 0f) { - updateMouseWheelMoved(mapBean, newScale); - newScale = 0f; - } - } - } - - public boolean isNoMouseWheelListenerTimer() { - return noMouseWheelListenerTimer; - } - - public void setNoMouseWheelListenerTimer(boolean noMouseWheelListenerTimer) { - this.noMouseWheelListenerTimer = noMouseWheelListenerTimer; - } -} \ No newline at end of file + Object obj = e.getSource(); + if (obj instanceof MapBean) { + + MapBean map = (MapBean) obj; + double precise = e.getPreciseWheelRotation(); + float zoom; + if (precise > 0) { + zoom = zoomFactor; + } else { + zoom = 1f / zoomFactor; + } + + map.zoom(new ZoomEvent(map, ZoomEvent.RELATIVE, zoom).withScreenLocation(e.getPoint())); + } + lastMouseWheelEventTime = currentTime; + } + } + + /** + * Invoked from the MouseWheelListener interface. + * + * @param mb + * @param value + */ + public void updateMouseWheelMoved(MapBean mb, float value) { + if (mb != null) { + mb.zoom(new ZoomEvent(mb, ZoomEvent.ABSOLUTE, value)); + } + } + + /** + * Check setting for whether MouseMode responds to mouse wheel events. + * + * @return true if mouse mode is interested in mouse wheel events. + */ + public boolean isMouseWheelListener() { + return mouseWheelListenerActive; + } + + /** + * Set whether MouseMode responds to mouse wheel events. + * + * @param mouseWheelListener + */ + public void setMouseWheelListener(boolean mouseWheelListener) { + this.mouseWheelListenerActive = mouseWheelListener; + } + + /** + * Part of the MapMouseMode interface. Called when the MouseMode is made + * active or inactive. + * + * @param active true if the mode has been made active, false if it has been + * made inactive. + */ + @Override + public void setActive(boolean active) { + } + + /** + * Set a MouseSupport explicitly. + * + * @param support The new MapMouseSupport instance + */ + public void setMouseSupport(MapMouseSupport support) { + mouseSupport = support; + } + + /** + * Get the MouseSupport. + * + * @return the MapMouseSupport used by the MouseMode. + */ + public MapMouseSupport getMouseSupport() { + return mouseSupport; + } + + /** + * Method to let the MouseDelegator know if the MapMouseMode should be + * visible, as opposed to a MapMouseMode that is being provided and + * controlled by another tool. True by default. + * + * @return + */ + @Override + public boolean isVisible() { + return visible; + } + + /** + * Method to set if the MapMouseMode should be visible, as opposed to a + * MapMouseMode that is being provided and controlled by another tool. + * + * @param value + */ + public void setVisible(boolean value) { + visible = value; + } + + /** + * Request to have the parent MapMouseMode act as a proxy for a MapMouseMode + * that wants to remain hidden. Can be useful for directing events to one + * object. This version sets the proxy distribution mask to zero, which + * means that none of this support objects targets will be notified of + * events. + * + * @param mmm the hidden MapMouseMode for this MapMouseMode to send events + * to. + * @return true if the proxy setup (essentially a lock) is successful, false + * if the proxy is already set up for another listener. + */ + @Override + public boolean actAsProxyFor(MapMouseMode mmm) { + return actAsProxyFor(mmm, 0); + } + + /** + * Request to have the MapMouseMode act as a proxy for a MapMouseMode that + * wants to remain hidden. Can be useful for directing events to one object. + * + * @param mmm the hidden MapMouseMode for this MapMouseMode to send events + * to. + * @param pdm the proxy distribution mask to use, which lets this support + * object notify its targets of events if the parent is acting as a proxy. + * @return true if the proxy setup (essentially a lock) is successful, false + * if the proxy is already set up for another listener. + */ + @Override + public boolean actAsProxyFor(MapMouseMode mmm, int pdm) { + MapMouseMode omm = mouseSupport.getProxied(); + boolean ret = false; + if (mmm != null && !mmm.equals(omm)) { + ret = mouseSupport.setProxyFor(mmm, pdm); + propertyChangeSupport.firePropertyChange(MouseDelegator.ProxyMouseModeProperty, omm, mmm); + } + + return ret; + } + + /** + * Can check if the MapMouseMode is acting as a proxy for another + * MapMouseMode. + * + * @param mmm + * @return + */ + @Override + public boolean isProxyFor(MapMouseMode mmm) { + return mouseSupport.isProxyFor(mmm); + } + + /** + * Release the proxy lock on the MapMouseMode. + */ + @Override + public void releaseProxy() { + MapMouseMode mmm = mouseSupport.getProxied(); + if (mmm != null) { + mouseSupport.releaseProxy(); + propertyChangeSupport.firePropertyChange(MouseDelegator.ProxyMouseModeProperty, mmm, null); + } + } + + /** + * Set the mask that dictates which events get sent to this support object's + * targets even if the parent mouse mode is acting as a proxy. + * + * @param mask + */ + @Override + public void setProxyDistributionMask(int mask) { + mouseSupport.setProxyDistributionMask(mask); + } + + /** + * Returns the MapMouseMode being held inside this mouse mode. + */ + @Override + public MapMouseMode getProxied() { + return mouseSupport.getProxied(); + } + + /** + * Get the mask that dictates which events get sent to this support object's + * targets even if the parent mouse mode is acting as a proxy. + * + * @return + */ + @Override + public int getProxyDistributionMask() { + return mouseSupport.getProxyDistributionMask(); + } + + /** + * + * @param prefix + * @param props + */ + @Override + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + + prefix = PropUtils.getScopedPropertyPrefix(prefix); + + String prettyNameString = props.getProperty(prefix + PRETTY_NAME_PROPERTY); + if (prettyNameString != null) { + setPrettyName(prettyNameString); + } + + String idString = props.getProperty(prefix + ID_PROPERTY); + if (idString != null) { + setID(idString); + } + + setModeCursor(props.getProperty(prefix + CURSOR_ID_PROPERTY)); + + String iconString = props.getProperty(prefix + ICON_PROPERTY); + if (iconString != null) { + setIconName(iconString); + } + + mouseWheelListenerActive = PropUtils.booleanFromProperties(props, prefix + MOUSE_WHEEL_LISTENER_PROPERTY, mouseWheelListenerActive); + + zoomWhenMouseWheelUp = PropUtils.booleanFromProperties(props, prefix + MOUSE_WHEEL_ZOOM_PROPERTY, zoomWhenMouseWheelUp); + + String zwmwu = props.getProperty(prefix + MOUSE_WHEEL_ZOOM_PROPERTY); + if (zwmwu != null) { + try { + boolean zSetting = getClass().getField(zwmwu).getBoolean(null); + setZoomWhenMouseWheelUp(zSetting); + } catch (NoSuchFieldException | IllegalAccessException iae) { + } + } + + noMouseWheelListenerTimer = PropUtils.booleanFromProperties(props, prefix + NO_MOUSE_WHEEL_LISTENER_PROPERTY, noMouseWheelListenerTimer); + mouseWheelTimerInterval = PropUtils.intFromProperties(props, prefix + MOUSE_WHEEL_TIMER_INTERVAL_PROPERTY, mouseWheelTimerInterval); + } + + /** + * + * @param props + * @return + */ + @Override + public Properties getProperties(Properties props) { + props = super.getProperties(props); + + String prefix = PropUtils.getScopedPropertyPrefix(this); + if (prettyName != null) { + props.put(prefix + PRETTY_NAME_PROPERTY, prettyName); + } + + props.put(prefix + ID_PROPERTY, getID()); + + int cursorType = getModeCursor().getType(); + + for (Field f : Cursor.class.getFields()) { + String name = f.getName(); + if (name.endsWith("_CURSOR")) { + try { + int testType = f.getInt(null); + if (testType == cursorType) { + props.put(prefix + CURSOR_ID_PROPERTY, name); + break; + } + } catch (IllegalArgumentException | IllegalAccessException e) { + } + } + } + + if (zoomWhenMouseWheelUp) { + props.put(prefix + MOUSE_WHEEL_ZOOM_PROPERTY, "ZOOM_IN"); + } else { + props.put(prefix + MOUSE_WHEEL_ZOOM_PROPERTY, "ZOOM_OUT"); + } + + props.put(prefix + MOUSE_WHEEL_LISTENER_PROPERTY, Boolean.toString(mouseWheelListenerActive)); + + props.put(prefix + ICON_PROPERTY, PropUtils.unnull(getIconName())); + + props.put(prefix + NO_MOUSE_WHEEL_LISTENER_PROPERTY, Boolean.toString(noMouseWheelListenerTimer)); + props.put(prefix + MOUSE_WHEEL_TIMER_INTERVAL_PROPERTY, Integer.toString(mouseWheelTimerInterval)); + + return props; + } + + /** + * + * @param props + * @return + */ + @Override + public Properties getPropertyInfo(Properties props) { + props = super.getPropertyInfo(props); + + Class thisClass = getClass(); + String internString = i18n.get(thisClass, PRETTY_NAME_PROPERTY, I18n.TOOLTIP, "Presentable name for Mouse Mode."); + props.put(Layer.AddToBeanContextProperty, internString); + internString = i18n.get(thisClass, PRETTY_NAME_PROPERTY, "Name"); + props.put(PRETTY_NAME_PROPERTY + LabelEditorProperty, internString); + + internString = i18n.get(thisClass, ID_PROPERTY, I18n.TOOLTIP, "Internal ID for Mouse Mode, used by Layers."); + props.put(Layer.AddToBeanContextProperty, internString); + internString = i18n.get(thisClass, ID_PROPERTY, "ID"); + props.put(ID_PROPERTY + LabelEditorProperty, internString); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, ICON_PROPERTY, "Icon", "Icon to use for mouse mode.", null); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MOUSE_WHEEL_ZOOM_PROPERTY, "Mouse Wheel Zoom Direction", + "Action to take when the mouse wheel is rolled up.", + "com.bbn.openmap.util.propertyEditor.ComboBoxPropertyEditor"); + props.put(MOUSE_WHEEL_ZOOM_PROPERTY + OptionPropertyEditor.ScopedOptionsProperty, "zoomin zoomout"); + props.put(MOUSE_WHEEL_ZOOM_PROPERTY + ".zoomin", "ZOOM_IN"); + props.put(MOUSE_WHEEL_ZOOM_PROPERTY + ".zoomout", "ZOOM_OUT"); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MOUSE_WHEEL_LISTENER_PROPERTY, "Mouse Wheel Zoom", + "Setting for whether mouse wheel controls map zoom", + "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor"); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, CURSOR_ID_PROPERTY, "Cursor", "Cursor to use for this mouse mode.", + "com.bbn.openmap.util.propertyEditor.ComboBoxPropertyEditor"); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, NO_MOUSE_WHEEL_LISTENER_PROPERTY, "No Mouse Wheel Listener Timer", + "Setting for whether a timer is used with the mouse wheel controller", + "com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor"); + + PropUtils.setI18NPropertyInfo(i18n, props, thisClass, MOUSE_WHEEL_TIMER_INTERVAL_PROPERTY, "Mouse Wheel Timer Interval", + "Setting for the wait interval for the mouse wheel timer", + null); + + StringBuilder cOptions = new StringBuilder(); + + for (Field f : Cursor.class.getFields()) { + String name = f.getName(); + if (name.endsWith("_CURSOR")) { + String cName = f.getName(); + props.put(CURSOR_ID_PROPERTY + "." + cName, cName); + cOptions.append(" ").append(cName); + } + } + + props.put(CURSOR_ID_PROPERTY + OptionPropertyEditor.ScopedOptionsProperty, cOptions.toString().trim()); + + return props; + } + + /** + * + * @param listener + */ + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + propertyChangeSupport.addPropertyChangeListener(listener); + } + + /** + * + * @param listener + */ + @Override + public void removePropertyChangeListener(PropertyChangeListener listener) { + propertyChangeSupport.removePropertyChangeListener(listener); + } + + /** + * PaintListener interface, notifying the MouseMode that the MapBean has + * repainted itself. Useful if the MouseMode is drawing stuff. + * + * @param g + */ + @Override + public void listenerPaint(Object source, Graphics g) { + } + + /** + * Set the time interval that the mouse timer waits before calling + * upateMouseMoved. A negative number or zero will disable the timer. + * + * @param interval + */ + public void setMouseWheelTimerInterval(int interval) { + mouseWheelTimerInterval = interval; + } + + /** + * + * @return + */ + public int getMouseWheelTimerInterval() { + return mouseWheelTimerInterval; + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/event/ZoomEvent.java b/src/core/src/main/java/com/bbn/openmap/event/ZoomEvent.java index ad6539e37..acb9786a6 100644 --- a/src/core/src/main/java/com/bbn/openmap/event/ZoomEvent.java +++ b/src/core/src/main/java/com/bbn/openmap/event/ZoomEvent.java @@ -19,15 +19,17 @@ // $Author: dietrick $ // // ********************************************************************** - package com.bbn.openmap.event; +import java.awt.Point; + /** - * An event to request that the map zoom in or out. Event specifies - * the type and amount of zoom of the map. + * An event to request that the map zoom in or out. Event specifies the type and + * amount of zoom of the map. */ public class ZoomEvent extends java.util.EventObject implements java.io.Serializable { + /** * Type that specifies that the amount should be used as a multiplier to the * current scale. @@ -49,30 +51,46 @@ public class ZoomEvent extends java.util.EventObject implements */ protected float amount; + /** + * The map pixel location of the origin of the zoom event. + */ + protected Point screenPoint; + /** * Construct a ZoomEvent. - * + * * @param source the creator of the ZoomEvent. - * @param type the type of the event, referring to how to use the - * amount. + * @param type the type of the event, referring to how to use the amount. * @param amount the value of the ZoomEvent. */ public ZoomEvent(Object source, int type, float amount) { super(source); switch (type) { - case RELATIVE: - case ABSOLUTE: - break; - default: - throw new IllegalArgumentException("Invalid type: " + type); + case RELATIVE: + case ABSOLUTE: + break; + default: + throw new IllegalArgumentException("Invalid type: " + type); } this.type = type; this.amount = amount; } + /** + * Provide the pixel location of the mouse cursor if you want that position + * to remain in the same place in the window. + * + * @param screenPixelLocation from the MouseEvent + * @return this ZoomEvent + */ + public ZoomEvent withScreenLocation(Point screenPixelLocation) { + screenPoint = screenPixelLocation; + return this; + } + /** * Check if the type is RELATIVE. - * + * * @return boolean */ public boolean isRelative() { @@ -81,7 +99,7 @@ public boolean isRelative() { /** * Check if the type is ABSOLUTE. - * + * * @return boolean */ public boolean isAbsolute() { @@ -90,20 +108,29 @@ public boolean isAbsolute() { /** * Get the amount of zoom. - * + * * @return float */ public float getAmount() { return amount; } + /** + * The screen pixel location of the origin of the zoom event. + * @return Point + */ + public Point getScreenPoint() { + return screenPoint; + } + /** * Stringify the object. - * + * * @return String */ + @Override public String toString() { return "#"; + + (isAbsolute() ? "Absolute " : "") + amount + (screenPoint != null?" at " + screenPoint:"") + ">"; } -} \ No newline at end of file +} diff --git a/src/core/src/main/java/com/bbn/openmap/event/ZoomSupport.java b/src/core/src/main/java/com/bbn/openmap/event/ZoomSupport.java index dbb064e4a..1e4937a4c 100644 --- a/src/core/src/main/java/com/bbn/openmap/event/ZoomSupport.java +++ b/src/core/src/main/java/com/bbn/openmap/event/ZoomSupport.java @@ -22,6 +22,8 @@ package com.bbn.openmap.event; +import java.awt.Point; + /** * This is a utility class that can be used by beans that need support @@ -49,16 +51,21 @@ public ZoomSupport(Object sourceBean) { * RELATIVE */ public void fireZoom(int zoomType, float amount) { + fireZoom(zoomType, amount, null); + } + + public void fireZoom(int zoomType, float amount, Point screenLoc) { if (!((zoomType == ZoomEvent.RELATIVE) || (zoomType == ZoomEvent.ABSOLUTE))) { throw new IllegalArgumentException("Bad value, " + zoomType + " for zoomType in " + "ZoomSupport.fireZoom()"); } - if (isEmpty()) + if (isEmpty()) { return; + } - ZoomEvent evt = new ZoomEvent(source, zoomType, amount); + ZoomEvent evt = new ZoomEvent(source, zoomType, amount).withScreenLocation(screenLoc); for (ZoomListener listener : this) { listener.zoom(evt); diff --git a/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedNavPanel.java b/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedNavPanel.java index 512375019..722632229 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedNavPanel.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedNavPanel.java @@ -21,9 +21,31 @@ * $Id: NavigationPanel.java 29356 2009-04-21 02:35:27Z rmacinty $ * * ****************************************************************************/ - package com.bbn.openmap.gui; +import com.bbn.openmap.Environment; +import com.bbn.openmap.MapBean; +import com.bbn.openmap.SoloMapComponent; +import com.bbn.openmap.event.CenterListener; +import com.bbn.openmap.event.CenterSupport; +import com.bbn.openmap.event.PanListener; +import com.bbn.openmap.event.PanSupport; +import com.bbn.openmap.event.ProjectionEvent; +import com.bbn.openmap.event.ProjectionListener; +import com.bbn.openmap.event.ZoomEvent; +import com.bbn.openmap.event.ZoomListener; +import com.bbn.openmap.event.ZoomSupport; +import com.bbn.openmap.omGraphics.DrawingAttributes; +import com.bbn.openmap.omGraphics.OMGraphicConstants; +import com.bbn.openmap.proj.Length; +import com.bbn.openmap.proj.Projection; +import com.bbn.openmap.proj.ProjectionStack; +import com.bbn.openmap.proj.ProjectionStackTrigger; +import com.bbn.openmap.tools.icon.IconPart; +import com.bbn.openmap.tools.icon.IconPartList; +import com.bbn.openmap.tools.icon.OMIconFactory; +import com.bbn.openmap.tools.icon.OpenMapAppPartCollection; +import com.bbn.openmap.util.PropUtils; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; @@ -40,7 +62,6 @@ import java.awt.geom.Point2D; import java.util.Properties; import java.util.logging.Logger; - import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -49,33 +70,8 @@ import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicSliderUI; -import com.bbn.openmap.Environment; -import com.bbn.openmap.MapBean; -import com.bbn.openmap.SoloMapComponent; -import com.bbn.openmap.event.CenterListener; -import com.bbn.openmap.event.CenterSupport; -import com.bbn.openmap.event.PanListener; -import com.bbn.openmap.event.PanSupport; -import com.bbn.openmap.event.ProjectionEvent; -import com.bbn.openmap.event.ProjectionListener; -import com.bbn.openmap.event.ZoomEvent; -import com.bbn.openmap.event.ZoomListener; -import com.bbn.openmap.event.ZoomSupport; -import com.bbn.openmap.omGraphics.DrawingAttributes; -import com.bbn.openmap.omGraphics.OMGraphicConstants; -import com.bbn.openmap.proj.Length; -import com.bbn.openmap.proj.Projection; -import com.bbn.openmap.proj.ProjectionStack; -import com.bbn.openmap.proj.ProjectionStackTrigger; -import com.bbn.openmap.tools.icon.IconPart; -import com.bbn.openmap.tools.icon.IconPartList; -import com.bbn.openmap.tools.icon.OMIconFactory; -import com.bbn.openmap.tools.icon.OpenMapAppPartCollection; -import com.bbn.openmap.util.PropUtils; - /** * A panel with map navigation widgets. *

@@ -85,719 +81,745 @@ *

*/ public class EmbeddedNavPanel extends OMComponentPanel implements - ProjectionListener, ProjectionStackTrigger, SoloMapComponent { - public static Logger logger = Logger - .getLogger("com.bbn.openmap.gui.EmbeddedNavPanel"); - - private static final long serialVersionUID = 1L; - - public static final int SLIDER_MAX = 17; - public final static String FADE_ATTRIBUTES_PROPERTY = "fade"; - public final static String LIVE_ATTRIBUTES_PROPERTY = "live"; - public static final String PanDistanceProperty = "panDistance"; - public static final String ZoomFactorProperty = "zoomFactor"; - - public final static int DEFAULT_BUTTON_SIZE = 15; - - protected final static float defaultPanDistance = Float.NaN; - protected final static float defaultZoomFactor = 2.0f; - - protected static Color CONTROL_BACKGROUND = OMGraphicConstants.clear; - protected DrawingAttributes fadeAttributes; - protected DrawingAttributes liveAttributes; - protected int buttonSize = DEFAULT_BUTTON_SIZE; - protected ImageIcon backIcon; - protected ImageIcon backDimIcon; - protected ImageIcon forwardIcon; - protected ImageIcon forwardDimIcon; - - protected MapBean map; - protected CenterSupport centerDelegate; - protected PanSupport panDelegate; - protected ZoomSupport zoomDelegate; - protected JButton forwardProjectionButton; - protected JButton backProjectionButton; - protected JSlider slider; - - private float panDistance = defaultPanDistance; - private float zoomFactor = defaultZoomFactor; - - protected float MIN_TRANSPARENCY = .25f; - protected float SEMI_TRANSPARENCY = .65f; - protected float MAX_TRANSPARENCY = 1.0f; - protected boolean fade = false; - - protected Point2D recenterPoint; - - protected AlphaComposite ac = AlphaComposite.getInstance( - AlphaComposite.SRC_ATOP, MAX_TRANSPARENCY); - - public EmbeddedNavPanel() { - this(null, null, DEFAULT_BUTTON_SIZE); - } - - /** - * Make one. - * - * @param buttonColors - * The live button colors when active. - * @param fadeColors - * The faded button colors, when inactive. - * @param buttonSize - * The relative pixel button sizes. - */ - public EmbeddedNavPanel(DrawingAttributes buttonColors, - DrawingAttributes fadeColors, int buttonSize) { - super(); - centerDelegate = new CenterSupport(this); - panDelegate = new PanSupport(this); - zoomDelegate = new ZoomSupport(this); - // the two commands required to make this panel transparent - setBackground(OMGraphicConstants.clear); - setOpaque(false); - - initColors(buttonColors, fadeColors, buttonSize); - - // Checks the openmap.Latitude and openmap.Longitude properties, and - // initializes the re-center point to that. - float lat = Environment.getFloat(Environment.Latitude, 0f); - float lon = Environment.getFloat(Environment.Longitude, 0f); - setRecenterPoint(new Point2D.Float(lon, lat)); - - layoutPanel(); - } - - protected void initColors(DrawingAttributes buttonColors, - DrawingAttributes fadeColors, int buttonSize) { - - fadeAttributes = fadeColors; - liveAttributes = buttonColors; - - if (buttonSize >= 10) { - this.buttonSize = buttonSize; - } - - if (fadeAttributes == null) { - fadeAttributes = DrawingAttributes.getDefaultClone(); - Color fadeColor = new Color(0xffaaaaaa); - fadeAttributes.setFillPaint(fadeColor); - fadeAttributes.setLinePaint(fadeColor.darker()); - } - - if (buttonColors == null) { - liveAttributes = DrawingAttributes.getDefaultClone(); - Color liveColor = new Color(0xDDF3F3F3); - liveAttributes.setFillPaint(liveColor); - liveAttributes.setMattingPaint(liveColor); - liveAttributes.setMatted(true); - } - } - - public void setProperties(String prefix, Properties props) { - super.setProperties(prefix, props); - prefix = PropUtils.getScopedPropertyPrefix(prefix); - - fadeAttributes.setProperties(prefix + FADE_ATTRIBUTES_PROPERTY, props); - liveAttributes.setProperties(prefix + LIVE_ATTRIBUTES_PROPERTY, props); - - panDistance = PropUtils.floatFromProperties(props, prefix - + PanDistanceProperty, defaultPanDistance); - - zoomFactor = PropUtils.floatFromProperties(props, prefix - + ZoomFactorProperty, defaultZoomFactor); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - - fadeAttributes.getProperties(props); - liveAttributes.getProperties(props); - - String prefix = PropUtils.getScopedPropertyPrefix(this); - props.put(prefix + PanDistanceProperty, String.valueOf(panDistance)); - props.put(prefix + ZoomFactorProperty, String.valueOf(zoomFactor)); - - return props; - } - - /** - * TODO: This is not complete, the drawing attributes need to be separated - * out and scoped, so they can be set individually. - */ - public Properties getPropertyInfo(Properties props) { - props = super.getPropertyInfo(props); - // fadeAttributes.getPropertyInfo(props); - // liveAttributes.getPropertyInfo(props); - - String interString; - props.put(initPropertiesProperty, - PanDistanceProperty + " " + ZoomFactorProperty); - - interString = i18n.get(EmbeddedNavPanel.class, - PanDistanceProperty, - com.bbn.openmap.util.I18n.TOOLTIP, - "Panning Distance."); - props.put(PanDistanceProperty, interString); - interString = i18n.get(EmbeddedNavPanel.class, - PanDistanceProperty, - "Panning Distance"); - props.put(PanDistanceProperty + LabelEditorProperty, - interString); - props.put(PanDistanceProperty + ScopedEditorProperty, - "com.bbn.openmap.util.propertyEditor.TextPropertyEditor"); - - interString = i18n.get(EmbeddedNavPanel.class, - ZoomFactorProperty, - com.bbn.openmap.util.I18n.TOOLTIP, - "Zoom Factor."); - props.put(ZoomFactorProperty, interString); - interString = i18n.get(EmbeddedNavPanel.class, - ZoomFactorProperty, - "Zoom Factor"); - props.put(ZoomFactorProperty + LabelEditorProperty, - interString); - props.put(ZoomFactorProperty + ScopedEditorProperty, - "com.bbn.openmap.util.propertyEditor.TextPropertyEditor"); - - return props; - } - - protected void layoutPanel() { - - removeAll(); - int projStackButtonSize = (int) (buttonSize * 1.25); - int rosetteButtonSize = buttonSize; - int zoomButtonSize = buttonSize; - setLayout(new GridBagLayout()); - - GridBagConstraints layoutConstraints = new GridBagConstraints(); - int baseY = 0; - - IconPart bigArrow = OpenMapAppPartCollection.BIG_ARROW.getIconPart(); - bigArrow.setRenderingAttributes(fadeAttributes); - backDimIcon = OMIconFactory.getIcon(projStackButtonSize, - projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE - .toRadians(270.0)); - bigArrow.setRenderingAttributes(liveAttributes); - backIcon = OMIconFactory.getIcon(projStackButtonSize, - projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE - .toRadians(270.0)); - backProjectionButton = makeButton(backDimIcon, - "Show Previous Projection"); - backProjectionButton.setActionCommand(ProjectionStack.BackProjCmd); - - bigArrow.setRenderingAttributes(fadeAttributes); - forwardDimIcon = OMIconFactory.getIcon(projStackButtonSize, - projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE - .toRadians(90.0)); - bigArrow.setRenderingAttributes(liveAttributes); - forwardIcon = OMIconFactory.getIcon(projStackButtonSize, - projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE - .toRadians(90.0)); - forwardProjectionButton = makeButton(forwardDimIcon, - "Show Next Projection"); - forwardProjectionButton - .setActionCommand(ProjectionStack.ForwardProjCmd); - - JPanel projStackButtonPanel = new JPanel(); - projStackButtonPanel.setOpaque(false); - projStackButtonPanel.setBackground(CONTROL_BACKGROUND); - projStackButtonPanel.add(backProjectionButton); - projStackButtonPanel.add(forwardProjectionButton); - - layoutConstraints.anchor = GridBagConstraints.CENTER; - layoutConstraints.gridwidth = GridBagConstraints.REMAINDER; - layoutConstraints.gridy = baseY++; - - add(projStackButtonPanel, layoutConstraints); - - JPanel rosette = new JPanel(); - GridBagLayout internalGridbag = new GridBagLayout(); - GridBagConstraints c2 = new GridBagConstraints(); - rosette.setLayout(internalGridbag); - - rosette.setOpaque(false); - rosette.setBackground(CONTROL_BACKGROUND); - - c2.gridx = 0; - c2.gridy = 0; - rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI - .getIconPart(), liveAttributes, rosetteButtonSize, 0.0, - "Pan Northwest", new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(-45f, panDistance); - } - }), c2); - c2.gridx = 1; - rosette.add(makeButton( - OpenMapAppPartCollection.MED_ARROW.getIconPart(), - liveAttributes, rosetteButtonSize, 0.0, "Pan North", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(0f, panDistance); - } - })); - c2.gridx = 2; - rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI - .getIconPart(), liveAttributes, rosetteButtonSize, 90.0, - "Pan Northeast", new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(45f, panDistance); - } - }), c2); - - c2.gridx = 0; - c2.gridy = 1; - rosette.add(makeButton( - OpenMapAppPartCollection.MED_ARROW.getIconPart(), - liveAttributes, rosetteButtonSize, 270.0, "Pan West", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(-90f, panDistance); - } - }), c2); - c2.gridx = 1; - IconPartList ipl = new IconPartList(); - ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); - ipl.add(OpenMapAppPartCollection.DOT.getIconPart()); - rosette.add(makeButton(ipl, liveAttributes, rosetteButtonSize, 0.0, - "Center Map", new ActionListener() { - public void actionPerformed(ActionEvent event) { - Point2D centerPnt = getRecenterPoint(); - if (centerPnt == null) { - centerDelegate.fireCenter(0, 0); - } else { - centerDelegate.fireCenter(centerPnt.getY(), - centerPnt.getX()); - } - } - }), c2); - c2.gridx = 2; - rosette.add(makeButton( - OpenMapAppPartCollection.MED_ARROW.getIconPart(), - liveAttributes, rosetteButtonSize, 90.0, "Pan East", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(90f, panDistance); - } - }), c2); - - c2.gridx = 0; - c2.gridy = 2; - rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI - .getIconPart(), liveAttributes, rosetteButtonSize, 270.0, - "Pan Southwest", new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(-135f, panDistance); - } - }), c2); - c2.gridx = 1; - rosette.add(makeButton( - OpenMapAppPartCollection.MED_ARROW.getIconPart(), - liveAttributes, rosetteButtonSize, 180.0, "Pan South", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(180f, panDistance); - } - }), c2); - c2.gridx = 2; - rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI - .getIconPart(), liveAttributes, rosetteButtonSize, 180.0, - "Pan Southeast", new ActionListener() { - public void actionPerformed(ActionEvent event) { - panDelegate.firePan(135f, panDistance); - } - }), c2); - - layoutConstraints.gridy = baseY++; - add(rosette, layoutConstraints); - - layoutConstraints.gridy = baseY++; - layoutConstraints.insets = new Insets(6, 0, 6, 0); - ipl = new IconPartList(); - // ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); - ipl.add(OpenMapAppPartCollection.PLUS.getIconPart()); - add(makeButton(ipl, liveAttributes, zoomButtonSize, 0.0, "Zoom In", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - zoomDelegate.fireZoom(ZoomEvent.RELATIVE, 1.0f / zoomFactor); - } - }), layoutConstraints); - - layoutConstraints.gridy = baseY++; - layoutConstraints.insets = new Insets(0, 0, 0, 0); - add(makeScaleSlider(liveAttributes), layoutConstraints); - - layoutConstraints.gridy = baseY++; - layoutConstraints.insets = new Insets(6, 0, 6, 0); - ipl = new IconPartList(); - // ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); - ipl.add(OpenMapAppPartCollection.MINUS.getIconPart()); - add(makeButton(ipl, liveAttributes, zoomButtonSize, 0.0, "Zoom Out", - new ActionListener() { - public void actionPerformed(ActionEvent event) { - zoomDelegate.fireZoom(ZoomEvent.RELATIVE, zoomFactor); - } - }), layoutConstraints); - - // We could drop this, but I think it's needed to play well with other - // containers when needed. - layoutConstraints.fill = GridBagConstraints.VERTICAL; - layoutConstraints.gridy = baseY++; - layoutConstraints.weighty = 1; - JPanel filler = new JPanel(); - filler.setOpaque(false); - filler.setBackground(OMGraphicConstants.clear); - add(filler, layoutConstraints); - - setMinimumSize(new Dimension(75, (projStackButtonSize + 3 - * rosetteButtonSize + 2 * zoomButtonSize + 24 + 200))); - } - - public Point2D getRecenterPoint() { - return recenterPoint; - } - - public void setRecenterPoint(Point2D recenterPoint) { - this.recenterPoint = recenterPoint; - } - - public float getPanDistance() { - return panDistance; - } - - public void setPanDistance(float panDistance) { - this.panDistance = panDistance; - } - - public float getZoomFactor() { - return zoomFactor; - } - - public void setZoomFactor(float zoomFactor) { - this.zoomFactor = zoomFactor; - } - - protected JButton makeButton(IconPart iconPart, DrawingAttributes da, - int size, double ddRot, String tooltip, ActionListener ac) { - iconPart.setRenderingAttributes(da); - return makeButton(OMIconFactory.getIcon(size, size, iconPart, null, - Length.DECIMAL_DEGREE.toRadians(ddRot)), tooltip, ac); - } - - protected JButton makeButton(ImageIcon icon, String toolTip, - ActionListener listener) { - JButton button = makeButton(icon, toolTip); - button.addActionListener(listener); - // KNOX -- don't let buttons get focus and add transparency listener - button.setFocusable(false); - button.addMouseListener(new NavPanelMouseListener()); - return button; - } - - protected JButton makeButton(ImageIcon icon, String toolTip) { - JButton button = new JButton(icon); - // MAGIC: required to make background transparent! - button.setBackground(CONTROL_BACKGROUND); - button.setBorder(null); - button.setMargin(new Insets(0, 0, 0, 0)); - // No surprise: also required to make background transparent. - button.setOpaque(false); - button.setBorderPainted(false); - button.setPreferredSize(new Dimension(icon.getIconWidth(), icon - .getIconHeight())); - button.setToolTipText(toolTip); - // KNOX -- don't let buttons get focus and add transparency listener - button.setFocusable(false); - button.addMouseListener(new NavPanelMouseListener()); - return button; - } - - protected JComponent makeScaleSlider(DrawingAttributes da) { - slider = new JSlider(SwingConstants.VERTICAL, 0, SLIDER_MAX, SLIDER_MAX); - slider.setUI(new NavPanelSliderUI(slider, (Color) da.getFillPaint())); - // MAGIC: required to make background transparent! - slider.setBackground((Color) da.getFillPaint()); - slider.setBorder(BorderFactory.createLineBorder((Color) da - .getFillPaint(), 1)); - slider.setForeground((Color) da.getFillPaint()); - slider.setInverted(true); - slider.setMinorTickSpacing(1); - // No surprise: also required to make background transparent. - slider.setOpaque(false); - slider.setPaintTicks(true); - slider.setSnapToTicks(true); - slider.addChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent event) { - // Need the check to avoid resetting the map scale if the window - // is - // resized. Only want this to happen of someone is moving the - // slider - // lever. - if (slider.getValueIsAdjusting()) { - changeMapScale(slider.getValue()); - } - } - }); - // KNOX -- don't let slider get focus and add transparency listener - slider.setFocusable(false); - slider.addMouseListener(new NavPanelMouseListener()); - return slider; - } - - protected void changeMapScale(int sliderValue) { - float newScale = sliderToScale(sliderValue); - - if (map.getScale() != newScale) { - map.setScale(newScale); - } - } - - protected void changeSliderValue(Projection projection) { - int newValue = scaleToSlider(projection.getScale()); - - if (slider.getValue() != newValue) { - slider.setValue(newValue); - } - } - - protected float sliderToScale(int sliderValue) { - return (float) (getMapMaxScale() / Math.pow(2, - (SLIDER_MAX - sliderValue))); - } - - protected int scaleToSlider(float mapScale) { - return (SLIDER_MAX - logBase2(getMapMaxScale() / mapScale)); - } - - /** Returns the largest integer n, such that 2^n <= the specified number. */ - public final static int logBase2(double number) { - int log = 0; - - while (number > 1) { - number = Math.floor(number / 2); - ++log; - } - - return log; - } - - public Color getScaleSliderBackground() { - return slider.getBackground(); - } - - public void setScaleSliderBackground(Color sliderBackground) { - slider.setBackground(sliderBackground); - } - - public Color getScaleSliderForeground() { - return slider.getForeground(); - } - - public void setScaleSliderForeground(Color sliderForeground) { - slider.setForeground(sliderForeground); - } - - private final float getMapMaxScale() { - return map.getProjection().getMaxScale(); - } - - // OMComponentPanel - public void findAndInit(Object someObject) { - if (someObject instanceof MapBean) { - map = (MapBean) someObject; - map.addProjectionListener(this); - } - if (someObject instanceof PanListener) { - addPanListener((PanListener) someObject); - } - if (someObject instanceof CenterListener) { - addCenterListener((CenterListener) someObject); - } - if (someObject instanceof ZoomListener) { - addZoomListener((ZoomListener) someObject); - } - if (someObject instanceof ProjectionStack) { - ((ProjectionStack) someObject).addProjectionStackTrigger(this); - } - } - - // OMComponentPanel - public void findAndUndo(Object someObject) { - if (someObject instanceof MapBean) { - map.removeProjectionListener(this); - } - if (someObject instanceof PanListener) { - removePanListener((PanListener) someObject); - } - if (someObject instanceof CenterListener) { - removeCenterListener((CenterListener) someObject); - } - if (someObject instanceof ZoomListener) { - removeZoomListener((ZoomListener) someObject); - } - if (someObject instanceof ProjectionStack) { - ((ProjectionStack) someObject).removeProjectionStackTrigger(this); - } - } - - public synchronized void addCenterListener(CenterListener listener) { - centerDelegate.add(listener); - } - - public synchronized void removeCenterListener(CenterListener listener) { - centerDelegate.remove(listener); - } - - public synchronized void addPanListener(PanListener listener) { - panDelegate.add(listener); - } - - public synchronized void removePanListener(PanListener listener) { - panDelegate.remove(listener); - } - - public synchronized void addZoomListener(ZoomListener listener) { - zoomDelegate.add(listener); - } - - public synchronized void removeZoomListener(ZoomListener listener) { - zoomDelegate.remove(listener); - } - - // ProjectionListener - public void projectionChanged(ProjectionEvent event) { - changeSliderValue(event.getProjection()); - } - - /** Adds a listener for events that shift the Projection stack. */ - // ProjectionStackTrigger - public void addActionListener(ActionListener listener) { - forwardProjectionButton.addActionListener(listener); - backProjectionButton.addActionListener(listener); - } - - /** Removes the listener for events that shift the Projection stack. */ - // ProjectionStackTrigger - public void removeActionListener(ActionListener listener) { - forwardProjectionButton.addActionListener(listener); - backProjectionButton.addActionListener(listener); - } - - /** - * Respond to changes in the contents of the forward and back projection - * stacks. - * - * @param haveBackProjections - * true if there is at least one back projection available - * @param haveForwardProjections - * true if there is at least one forward projection available - */ - // ProjectionStackTrigger - public void updateProjectionStackStatus(boolean haveBackProjections, - boolean haveForwardProjections) { - forwardProjectionButton.setIcon(haveForwardProjections ? forwardIcon - : forwardDimIcon); - backProjectionButton.setIcon(haveBackProjections ? backIcon - : backDimIcon); - forwardProjectionButton.setEnabled(haveForwardProjections); - backProjectionButton.setEnabled(haveBackProjections); - } - - public void paint(Graphics g) { - if (ac != null) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setComposite(ac); - super.paint(g2); - g2.dispose(); - } else { - super.paint(g); - } - } - - public void setTransparency(float transparency) { - if (ac != null) { - if (transparency > MAX_TRANSPARENCY) { - transparency = MAX_TRANSPARENCY; - } - - ac = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, - transparency); - repaint(); - } - } - - public void setMinimumTransparency(float minTransparency) { - MIN_TRANSPARENCY = minTransparency; - } - - public void setSemiTransparency(float semiTransparency) { - SEMI_TRANSPARENCY = semiTransparency; + ProjectionListener, ProjectionStackTrigger, SoloMapComponent { + + public final static Logger logger = Logger + .getLogger("com.bbn.openmap.gui.EmbeddedNavPanel"); + + private static final long serialVersionUID = 1L; + + public static final int SLIDER_MAX = 17; + public final static String FADE_ATTRIBUTES_PROPERTY = "fade"; + public final static String LIVE_ATTRIBUTES_PROPERTY = "live"; + public static final String PAN_DISTANCE_PROPERTY = "panDistance"; + public static final String ZOOM_FACTOR_PROPERTY = "zoomFactor"; + public static final String SHOW_SCALE_SLIDER_PROPERTY = "showScaleSlider"; + public static final String SHOW_ROSETTE_PROPERTY = "showRosette"; + + public final static int DEFAULT_BUTTON_SIZE = 15; + + protected final static float DEFAULT_PAN_DISTANCE = Float.NaN; + protected final static float DEFAULT_ZOOM_DISTANCE = 2.0f; + + protected static Color CONTROL_BACKGROUND = OMGraphicConstants.clear; + protected DrawingAttributes fadeAttributes; + protected DrawingAttributes liveAttributes; + protected int buttonSize = DEFAULT_BUTTON_SIZE; + protected ImageIcon backIcon; + protected ImageIcon backDimIcon; + protected ImageIcon forwardIcon; + protected ImageIcon forwardDimIcon; + + protected MapBean map; + protected CenterSupport centerDelegate; + protected PanSupport panDelegate; + protected ZoomSupport zoomDelegate; + protected JButton forwardProjectionButton; + protected JButton backProjectionButton; + protected JSlider slider; + protected boolean showScaleSlider = false; + protected boolean showRosette = false; + + private float panDistance = DEFAULT_PAN_DISTANCE; + private float zoomFactor = DEFAULT_ZOOM_DISTANCE; + + protected float MIN_TRANSPARENCY = .25f; + protected float SEMI_TRANSPARENCY = .65f; + protected float MAX_TRANSPARENCY = 1.0f; + protected boolean fade = false; + + protected Point2D recenterPoint; + + protected AlphaComposite ac = AlphaComposite.getInstance( + AlphaComposite.SRC_ATOP, MAX_TRANSPARENCY); + + public EmbeddedNavPanel() { + this(null, null, DEFAULT_BUTTON_SIZE); + } + + /** + * Make one. + * + * @param buttonColors The live button colors when active. + * @param fadeColors The faded button colors, when inactive. + * @param buttonSize The relative pixel button sizes. + */ + public EmbeddedNavPanel(DrawingAttributes buttonColors, + DrawingAttributes fadeColors, int buttonSize) { + super(); + centerDelegate = new CenterSupport(this); + panDelegate = new PanSupport(this); + zoomDelegate = new ZoomSupport(this); + // the two commands required to make this panel transparent + setBackground(OMGraphicConstants.clear); + setOpaque(false); + + initColors(buttonColors, fadeColors, buttonSize); + + // Checks the openmap.Latitude and openmap.Longitude properties, and + // initializes the re-center point to that. + float lat = Environment.getFloat(Environment.Latitude, 0f); + float lon = Environment.getFloat(Environment.Longitude, 0f); + setRecenterPoint(new Point2D.Float(lon, lat)); + + layoutPanel(); + } + + protected void initColors(DrawingAttributes buttonColors, + DrawingAttributes fadeColors, int buttonSize) { + + fadeAttributes = fadeColors; + liveAttributes = buttonColors; + + if (buttonSize >= 10) { + this.buttonSize = buttonSize; + } + + if (fadeAttributes == null) { + fadeAttributes = DrawingAttributes.getDefaultClone(); + Color fadeColor = new Color(0xffaaaaaa); + fadeAttributes.setFillPaint(fadeColor); + fadeAttributes.setLinePaint(fadeColor.darker()); + } + + if (buttonColors == null) { + liveAttributes = DrawingAttributes.getDefaultClone(); + Color liveColor = new Color(0xDDF3F3F3); + liveAttributes.setFillPaint(liveColor); + liveAttributes.setMattingPaint(liveColor); + liveAttributes.setMatted(true); + } + } + + @Override + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + prefix = PropUtils.getScopedPropertyPrefix(prefix); + + fadeAttributes.setProperties(prefix + FADE_ATTRIBUTES_PROPERTY, props); + liveAttributes.setProperties(prefix + LIVE_ATTRIBUTES_PROPERTY, props); + + panDistance = PropUtils.floatFromProperties(props, prefix + + PAN_DISTANCE_PROPERTY, DEFAULT_PAN_DISTANCE); + + zoomFactor = PropUtils.floatFromProperties(props, prefix + + ZOOM_FACTOR_PROPERTY, DEFAULT_ZOOM_DISTANCE); + + showRosette = PropUtils.booleanFromProperties(props, prefix + SHOW_ROSETTE_PROPERTY, showRosette); + showScaleSlider = PropUtils.booleanFromProperties(props, prefix + SHOW_SCALE_SLIDER_PROPERTY, showScaleSlider); + } + + @Override + public Properties getProperties(Properties props) { + props = super.getProperties(props); + + fadeAttributes.getProperties(props); + liveAttributes.getProperties(props); + + String prefix = PropUtils.getScopedPropertyPrefix(this); + props.put(prefix + PAN_DISTANCE_PROPERTY, String.valueOf(panDistance)); + props.put(prefix + ZOOM_FACTOR_PROPERTY, String.valueOf(zoomFactor)); + props.put(prefix + SHOW_ROSETTE_PROPERTY, showRosette); + props.put(prefix + SHOW_SCALE_SLIDER_PROPERTY, showScaleSlider); + + return props; + } + + /** + * TODO: This is not complete, the drawing attributes need to be separated + * out and scoped, so they can be set individually. + * + * @param props to decode + */ + @Override + public Properties getPropertyInfo(Properties props) { + props = super.getPropertyInfo(props); + // fadeAttributes.getPropertyInfo(props); + // liveAttributes.getPropertyInfo(props); + + String interString; + props.put(initPropertiesProperty, + PAN_DISTANCE_PROPERTY + " " + ZOOM_FACTOR_PROPERTY); + + interString = i18n.get(EmbeddedNavPanel.class, + PAN_DISTANCE_PROPERTY, + com.bbn.openmap.util.I18n.TOOLTIP, + "Panning Distance."); + props.put(PAN_DISTANCE_PROPERTY, interString); + interString = i18n.get(EmbeddedNavPanel.class, + PAN_DISTANCE_PROPERTY, + "Panning Distance"); + props.put(PAN_DISTANCE_PROPERTY + LabelEditorProperty, + interString); + props.put(PAN_DISTANCE_PROPERTY + ScopedEditorProperty, + "com.bbn.openmap.util.propertyEditor.TextPropertyEditor"); + + interString = i18n.get(EmbeddedNavPanel.class, + ZOOM_FACTOR_PROPERTY, + com.bbn.openmap.util.I18n.TOOLTIP, + "Zoom Factor."); + props.put(ZOOM_FACTOR_PROPERTY, interString); + interString = i18n.get(EmbeddedNavPanel.class, + ZOOM_FACTOR_PROPERTY, + "Zoom Factor"); + props.put(ZOOM_FACTOR_PROPERTY + LabelEditorProperty, + interString); + props.put(ZOOM_FACTOR_PROPERTY + ScopedEditorProperty, + "com.bbn.openmap.util.propertyEditor.TextPropertyEditor"); + + return props; + } + + protected void layoutPanel() { + IconPartList ipl; // for reuse + removeAll(); + int projStackButtonSize = (int) (buttonSize * 1.25); + int rosetteButtonSize = buttonSize; + int zoomButtonSize = buttonSize; + setLayout(new GridBagLayout()); + + GridBagConstraints layoutConstraints = new GridBagConstraints(); + int baseY = 0; + + IconPart bigArrow = OpenMapAppPartCollection.BIG_ARROW.getIconPart(); + bigArrow.setRenderingAttributes(fadeAttributes); + backDimIcon = OMIconFactory.getIcon(projStackButtonSize, + projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE + .toRadians(270.0)); + bigArrow.setRenderingAttributes(liveAttributes); + backIcon = OMIconFactory.getIcon(projStackButtonSize, + projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE + .toRadians(270.0)); + backProjectionButton = makeButton(backDimIcon, + "Show Previous Projection"); + backProjectionButton.setActionCommand(ProjectionStack.BackProjCmd); + + bigArrow.setRenderingAttributes(fadeAttributes); + forwardDimIcon = OMIconFactory.getIcon(projStackButtonSize, + projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE + .toRadians(90.0)); + bigArrow.setRenderingAttributes(liveAttributes); + forwardIcon = OMIconFactory.getIcon(projStackButtonSize, + projStackButtonSize, bigArrow, null, Length.DECIMAL_DEGREE + .toRadians(90.0)); + forwardProjectionButton = makeButton(forwardDimIcon, + "Show Next Projection"); + forwardProjectionButton + .setActionCommand(ProjectionStack.ForwardProjCmd); + + JPanel projStackButtonPanel = new JPanel(); + projStackButtonPanel.setOpaque(false); + projStackButtonPanel.setBackground(CONTROL_BACKGROUND); + projStackButtonPanel.add(backProjectionButton); + projStackButtonPanel.add(forwardProjectionButton); + + layoutConstraints.anchor = GridBagConstraints.CENTER; + layoutConstraints.gridwidth = GridBagConstraints.REMAINDER; + layoutConstraints.gridy = baseY++; + + add(projStackButtonPanel, layoutConstraints); + + if (showRosette) { + + JPanel rosette = new JPanel(); + GridBagLayout internalGridbag = new GridBagLayout(); + GridBagConstraints c2 = new GridBagConstraints(); + rosette.setLayout(internalGridbag); + + rosette.setOpaque(false); + rosette.setBackground(CONTROL_BACKGROUND); + + c2.gridx = 0; + c2.gridy = 0; + rosette.add(makeButton( + OpenMapAppPartCollection.OPP_CORNER_TRI.getIconPart(), + liveAttributes, rosetteButtonSize, 0.0, + "Pan Northwest", + (ActionEvent event) -> { + panDelegate.firePan(-45f, panDistance); + }), + c2); + c2.gridx = 1; + rosette.add(makeButton(OpenMapAppPartCollection.MED_ARROW.getIconPart(), + liveAttributes, rosetteButtonSize, 0.0, "Pan North", (ActionEvent event) -> { + panDelegate.firePan(0f, panDistance); + })); + c2.gridx = 2; + rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI + .getIconPart(), liveAttributes, rosetteButtonSize, 90.0, + "Pan Northeast", (ActionEvent event) -> { + panDelegate.firePan(45f, panDistance); + }), c2); + + c2.gridx = 0; + c2.gridy = 1; + rosette.add(makeButton(OpenMapAppPartCollection.MED_ARROW.getIconPart(), + liveAttributes, rosetteButtonSize, 270.0, "Pan West", (ActionEvent event) -> { + panDelegate.firePan(-90f, panDistance); + }), c2); + c2.gridx = 1; + ipl = new IconPartList(); + ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); + ipl.add(OpenMapAppPartCollection.DOT.getIconPart()); + rosette.add(makeButton(ipl, liveAttributes, rosetteButtonSize, 0.0, + "Center Map", (ActionEvent event) -> { + Point2D centerPnt = getRecenterPoint(); + if (centerPnt == null) { + centerDelegate.fireCenter(0, 0); + } else { + centerDelegate.fireCenter(centerPnt.getY(), + centerPnt.getX()); + } + }), c2); + c2.gridx = 2; + rosette.add(makeButton(OpenMapAppPartCollection.MED_ARROW.getIconPart(), + liveAttributes, rosetteButtonSize, 90.0, "Pan East", (ActionEvent event) -> { + panDelegate.firePan(90f, panDistance); + }), c2); + + c2.gridx = 0; + c2.gridy = 2; + rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI + .getIconPart(), liveAttributes, rosetteButtonSize, 270.0, + "Pan Southwest", (ActionEvent event) -> { + panDelegate.firePan(-135f, panDistance); + }), c2); + c2.gridx = 1; + rosette.add(makeButton(OpenMapAppPartCollection.MED_ARROW.getIconPart(), + liveAttributes, rosetteButtonSize, 180.0, "Pan South", (ActionEvent event) -> { + panDelegate.firePan(180f, panDistance); + }), c2); + c2.gridx = 2; + rosette.add(makeButton(OpenMapAppPartCollection.OPP_CORNER_TRI + .getIconPart(), liveAttributes, rosetteButtonSize, 180.0, + "Pan Southeast", (ActionEvent event) -> { + panDelegate.firePan(135f, panDistance); + }), c2); + + layoutConstraints.gridy = baseY++; + add(rosette, layoutConstraints); + } + + layoutConstraints.gridy = baseY++; + layoutConstraints.insets = new Insets(3, 0, 3, 0); + ipl = new IconPartList(); + if (!showScaleSlider) { + ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); + } + ipl.add(OpenMapAppPartCollection.PLUS.getIconPart()); + add(makeButton(ipl, liveAttributes, zoomButtonSize, 0.0, "Zoom In", (ActionEvent event) -> { + zoomDelegate.fireZoom(ZoomEvent.RELATIVE, 1.0f / zoomFactor); + }), layoutConstraints); + + if (showScaleSlider) { + layoutConstraints.gridy = baseY++; + layoutConstraints.insets = new Insets(0, 0, 0, 0); + add(makeScaleSlider(liveAttributes), layoutConstraints); + } + + layoutConstraints.gridy = baseY++; + layoutConstraints.insets = new Insets(3, 0, 3, 0); + ipl = new IconPartList(); + if (!showScaleSlider) { + ipl.add(OpenMapAppPartCollection.CIRCLE.getIconPart()); + } + ipl.add(OpenMapAppPartCollection.MINUS.getIconPart()); + add(makeButton(ipl, liveAttributes, zoomButtonSize, 0.0, "Zoom Out", (ActionEvent event) -> { + zoomDelegate.fireZoom(ZoomEvent.RELATIVE, zoomFactor); + }), layoutConstraints); + + // We could drop this, but I think it's needed to play well with other + // containers when needed. + layoutConstraints.fill = GridBagConstraints.VERTICAL; + layoutConstraints.gridy = baseY++; + layoutConstraints.weighty = 1; + JPanel filler = new JPanel(); + filler.setOpaque(false); + filler.setBackground(OMGraphicConstants.clear); + add(filler, layoutConstraints); + + setMinimumSize(new Dimension(75, (projStackButtonSize + 3 + * rosetteButtonSize + 2 * zoomButtonSize + 24 + 200))); + } + + public Point2D getRecenterPoint() { + return recenterPoint; + } + + public void setRecenterPoint(Point2D recenterPoint) { + this.recenterPoint = recenterPoint; + } + + public float getPanDistance() { + return panDistance; + } + + public void setPanDistance(float panDistance) { + this.panDistance = panDistance; + } + + public float getZoomFactor() { + return zoomFactor; + } + + public void setZoomFactor(float zoomFactor) { + this.zoomFactor = zoomFactor; + } + + protected JButton makeButton(IconPart iconPart, DrawingAttributes da, + int size, double ddRot, String tooltip, ActionListener ac) { + iconPart.setRenderingAttributes(da); + return makeButton(OMIconFactory.getIcon(size, size, iconPart, null, + Length.DECIMAL_DEGREE.toRadians(ddRot)), tooltip, ac); + } + + protected JButton makeButton(ImageIcon icon, String toolTip, + ActionListener listener) { + JButton button = makeButton(icon, toolTip); + button.addActionListener(listener); + // KNOX -- don't let buttons get focus and add transparency listener + button.setFocusable(false); + button.addMouseListener(new NavPanelMouseListener()); + return button; + } + + protected JButton makeButton(ImageIcon icon, String toolTip) { + JButton button = new JButton(icon); + // MAGIC: required to make background transparent! + button.setBackground(CONTROL_BACKGROUND); + button.setBorder(null); + button.setMargin(new Insets(0, 0, 0, 0)); + // No surprise: also required to make background transparent. + button.setOpaque(false); + button.setBorderPainted(false); + button.setPreferredSize(new Dimension(icon.getIconWidth(), icon + .getIconHeight())); + button.setToolTipText(toolTip); + // KNOX -- don't let buttons get focus and add transparency listener + button.setFocusable(false); + button.addMouseListener(new NavPanelMouseListener()); + return button; + } + + protected JComponent makeScaleSlider(DrawingAttributes da) { + slider = new JSlider(SwingConstants.VERTICAL, 0, SLIDER_MAX, SLIDER_MAX); + slider.setUI(new NavPanelSliderUI(slider, (Color) da.getFillPaint())); + // MAGIC: required to make background transparent! + slider.setBackground((Color) da.getFillPaint()); + slider.setBorder(BorderFactory.createLineBorder((Color) da + .getFillPaint(), 1)); + slider.setForeground((Color) da.getFillPaint()); + slider.setInverted(true); + slider.setMinorTickSpacing(1); + // No surprise: also required to make background transparent. + slider.setOpaque(false); + slider.setPaintTicks(true); + slider.setSnapToTicks(true); + slider.addChangeListener((ChangeEvent event) -> { + // Need the check to avoid resetting the map scale if the window + // is + // resized. Only want this to happen of someone is moving the + // slider + // lever. + if (slider.getValueIsAdjusting()) { + changeMapScale(slider.getValue()); + } + }); + // KNOX -- don't let slider get focus and add transparency listener + slider.setFocusable(false); + slider.addMouseListener(new NavPanelMouseListener()); + return slider; + } + + protected void changeMapScale(int sliderValue) { + float newScale = sliderToScale(sliderValue); + + if (map.getScale() != newScale) { + map.setScale(newScale); + } + } + + protected void changeSliderValue(Projection projection) { + int newValue = scaleToSlider(projection.getScale()); + + if (slider.getValue() != newValue) { + slider.setValue(newValue); + } + } + + protected float sliderToScale(int sliderValue) { + return (float) (getMapMaxScale() / Math.pow(2, + (SLIDER_MAX - sliderValue))); + } + + protected int scaleToSlider(float mapScale) { + return (SLIDER_MAX - logBase2(getMapMaxScale() / mapScale)); + } + + /** + * Returns the largest integer n, such that 2^n <= the specified number. + * + * @param number to start + * @return int + */ + public final static int logBase2(double number) { + int log = 0; + + while (number > 1) { + number = Math.floor(number / 2); + ++log; + } + + return log; + } + + public Color getScaleSliderBackground() { + return slider.getBackground(); + } + + public void setScaleSliderBackground(Color sliderBackground) { + slider.setBackground(sliderBackground); + } + + public Color getScaleSliderForeground() { + return slider.getForeground(); + } + + public void setScaleSliderForeground(Color sliderForeground) { + slider.setForeground(sliderForeground); + } + + private float getMapMaxScale() { + return map.getProjection().getMaxScale(); + } + + @Override + public void findAndInit(Object someObject) { + if (someObject instanceof MapBean) { + map = (MapBean) someObject; + map.addProjectionListener(this); + } + if (someObject instanceof PanListener) { + addPanListener((PanListener) someObject); + } + if (someObject instanceof CenterListener) { + addCenterListener((CenterListener) someObject); + } + if (someObject instanceof ZoomListener) { + addZoomListener((ZoomListener) someObject); + } + if (someObject instanceof ProjectionStack) { + ((ProjectionStack) someObject).addProjectionStackTrigger(this); + } + } + + @Override + public void findAndUndo(Object someObject) { + if (someObject instanceof MapBean) { + map.removeProjectionListener(this); + } + if (someObject instanceof PanListener) { + removePanListener((PanListener) someObject); + } + if (someObject instanceof CenterListener) { + removeCenterListener((CenterListener) someObject); + } + if (someObject instanceof ZoomListener) { + removeZoomListener((ZoomListener) someObject); + } + if (someObject instanceof ProjectionStack) { + ((ProjectionStack) someObject).removeProjectionStackTrigger(this); + } + } + + public synchronized void addCenterListener(CenterListener listener) { + centerDelegate.add(listener); + } + + public synchronized void removeCenterListener(CenterListener listener) { + centerDelegate.remove(listener); + } + + public synchronized void addPanListener(PanListener listener) { + panDelegate.add(listener); + } + + public synchronized void removePanListener(PanListener listener) { + panDelegate.remove(listener); + } + + public synchronized void addZoomListener(ZoomListener listener) { + zoomDelegate.add(listener); + } + + public synchronized void removeZoomListener(ZoomListener listener) { + zoomDelegate.remove(listener); + } + + // ProjectionListener + @Override + public void projectionChanged(ProjectionEvent event) { + changeSliderValue(event.getProjection()); + } + + /** + * Adds a listener for events that shift the Projection stack. + * + * @param listener listener for projection buttons + */ + // ProjectionStackTrigger + @Override + public void addActionListener(ActionListener listener) { + forwardProjectionButton.addActionListener(listener); + backProjectionButton.addActionListener(listener); + } + + /** + * Removes the listener for events that shift the Projection stack. + * + * @param listener listener for projection buttons + */ + // ProjectionStackTrigger + @Override + public void removeActionListener(ActionListener listener) { + forwardProjectionButton.addActionListener(listener); + backProjectionButton.addActionListener(listener); + } + + /** + * Respond to changes in the contents of the forward and back projection + * stacks. + * + * @param haveBackProjections true if there is at least one back projection + * available + * @param haveForwardProjections true if there is at least one forward + * projection available + */ + // ProjectionStackTrigger + @Override + public void updateProjectionStackStatus(boolean haveBackProjections, + boolean haveForwardProjections) { + forwardProjectionButton.setIcon(haveForwardProjections ? forwardIcon + : forwardDimIcon); + backProjectionButton.setIcon(haveBackProjections ? backIcon + : backDimIcon); + forwardProjectionButton.setEnabled(haveForwardProjections); + backProjectionButton.setEnabled(haveBackProjections); + } + + @Override + public void paint(Graphics g) { + if (ac != null) { + Graphics2D g2 = (Graphics2D) g.create(); + g2.setComposite(ac); + super.paint(g2); + g2.dispose(); + } else { + super.paint(g); } + } - public DrawingAttributes getFadeAttributes() { - return fadeAttributes; - } - - public void setFadeAttributes(DrawingAttributes fadeAttributes) { - this.fadeAttributes = fadeAttributes; - } - - public DrawingAttributes getLiveAttributes() { - return liveAttributes; - } - - public void setLiveAttributes(DrawingAttributes liveAttributes) { - this.liveAttributes = liveAttributes; - } - - public AlphaComposite getAc() { - return ac; - } - - public void setAc(AlphaComposite ac) { - this.ac = ac; - } - - public MapBean getMap() { - return map; - } - - // KNOX -- using this to paint ticks on slider - private class NavPanelSliderUI extends BasicSliderUI { - Color sliderTickColor = Color.white; - - public NavPanelSliderUI(JSlider slider, Color tickColor) { - super(slider); - sliderTickColor = tickColor; - } - - @Override - protected void paintMinorTickForVertSlider(Graphics g, - Rectangle tickBounds, int y) { - g.setColor(sliderTickColor); - super.paintMinorTickForVertSlider(g, tickBounds, y); - } - - } - - // KNOX -- using this to change level of transparency when mousing over - // buttons/slider - private class NavPanelMouseListener extends MouseAdapter { - @Override - public void mouseEntered(MouseEvent e) { - if (ac.getAlpha() < SEMI_TRANSPARENCY) { - setTransparency(SEMI_TRANSPARENCY); - getTopLevelAncestor().repaint(); - } - } - - @Override - public void mouseExited(MouseEvent e) { - if (ac.getAlpha() > MIN_TRANSPARENCY) { - setTransparency(MIN_TRANSPARENCY); - getTopLevelAncestor().repaint(); - } - } - } + public void setTransparency(float transparency) { + if (ac != null) { + if (transparency > MAX_TRANSPARENCY) { + transparency = MAX_TRANSPARENCY; + } + + ac = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, + transparency); + repaint(); + } + } + + public void setMinimumTransparency(float minTransparency) { + MIN_TRANSPARENCY = minTransparency; + } + + public void setSemiTransparency(float semiTransparency) { + SEMI_TRANSPARENCY = semiTransparency; + } + + public DrawingAttributes getFadeAttributes() { + return fadeAttributes; + } + + public void setFadeAttributes(DrawingAttributes fadeAttributes) { + this.fadeAttributes = fadeAttributes; + } + + public DrawingAttributes getLiveAttributes() { + return liveAttributes; + } + + public void setLiveAttributes(DrawingAttributes liveAttributes) { + this.liveAttributes = liveAttributes; + } + + public AlphaComposite getAc() { + return ac; + } + + public void setAc(AlphaComposite ac) { + this.ac = ac; + } + + public boolean isShowScaleSlider() { + return showScaleSlider; + } + + public void setShowScaleSlider(boolean showSlider) { + this.showScaleSlider = showSlider; + } + + public boolean isShowRosette() { + return showRosette; + } + + public void setShowRosette(boolean showRosette) { + this.showRosette = showRosette; + } + + public MapBean getMap() { + return map; + } + + // KNOX -- using this to paint ticks on slider + private class NavPanelSliderUI extends BasicSliderUI { + + Color sliderTickColor = Color.white; + + public NavPanelSliderUI(JSlider slider, Color tickColor) { + super(slider); + sliderTickColor = tickColor; + } + + @Override + protected void paintMinorTickForVertSlider(Graphics g, + Rectangle tickBounds, int y) { + g.setColor(sliderTickColor); + super.paintMinorTickForVertSlider(g, tickBounds, y); + } + + } + + // KNOX -- using this to change level of transparency when mousing over + // buttons/slider + private class NavPanelMouseListener extends MouseAdapter { + + @Override + public void mouseEntered(MouseEvent e) { + if (ac.getAlpha() < SEMI_TRANSPARENCY) { + setTransparency(SEMI_TRANSPARENCY); + getTopLevelAncestor().repaint(); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if (ac.getAlpha() > MIN_TRANSPARENCY) { + setTransparency(MIN_TRANSPARENCY); + getTopLevelAncestor().repaint(); + } + } + } } diff --git a/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedScaleDisplayPanel.java b/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedScaleDisplayPanel.java index 6ccd33818..8df2e38d6 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedScaleDisplayPanel.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/EmbeddedScaleDisplayPanel.java @@ -239,7 +239,6 @@ public void projectionChanged(ProjectionEvent e) { * space to find out how long the line should be. Then, we'll move that * length into component pixel space. */ - lower_y = h / 2; right_x = w / 2; left_x = right_x - width; @@ -254,7 +253,7 @@ public void projectionChanged(ProjectionEvent e) { double new_dist = scopeDistance(dist); if (logger.isLoggable(Level.FINE)) { - logger.fine("modifying " + dist + " to new distance: " + new_dist); + logger.log(Level.FINE, "modifying {0} to new distance: {1}", new Object[]{dist, new_dist}); } left_x = getPtAtDistanceFromLatLon(loc2, new_dist, projection, uom); @@ -263,20 +262,20 @@ public void projectionChanged(ProjectionEvent e) { // If the length of the distance line is longer than the width of the // panel, divide it in half. - int maxWidth = Math.max(getWidth() - Math.abs(locationXoffset) * 2, 50); + int maxWidth = Math.max(getWidth() / 2 - Math.abs(locationXoffset) * 2, 50); while (lineLength > maxWidth) { lineLength /= 3; new_dist /= 3.0; if (logger.isLoggable(Level.FINE)) { - logger.fine("length of line too long, halving to " + lineLength); + logger.log(Level.FINE, "length of line too long, halving to [0]", lineLength); } double testDist = scopeDistance(new_dist); if (!MoreMath.approximately_equal(testDist, new_dist) && !(new_dist <= .01)) { lineLength = right_x - getPtAtDistanceFromLatLon(loc2, testDist, projection, uom); if (logger.isLoggable(Level.FINE)) { - logger.fine("needed to rescope distance to " + testDist + " from " + new_dist); + logger.log(Level.FINE, "needed to rescope distance to {0} from {1}", new Object[]{testDist, new_dist}); } new_dist = testDist; } @@ -296,7 +295,7 @@ public void projectionChanged(ProjectionEvent e) { } if (logger.isLoggable(Level.FINE)) { - logger.fine("modified UOM to " + cur_uom.getAbbr() + ", value: " + new_dist); + logger.log(Level.FINE, "modified UOM to {0}, value: {1}", new Object[]{cur_uom.getAbbr(), new_dist}); } double testDist = scopeDistance(new_dist); @@ -304,7 +303,7 @@ public void projectionChanged(ProjectionEvent e) { lineLength = right_x - getPtAtDistanceFromLatLon(loc2, testDist, projection, cur_uom); if (logger.isLoggable(Level.FINE)) { - logger.fine("needed to rescope distance to " + testDist + " from " + new_dist); + logger.log(Level.FINE, "needed to rescope distance to {0} from {1}", new Object[]{testDist, new_dist}); } new_dist = testDist; } @@ -343,21 +342,12 @@ public void projectionChanged(ProjectionEvent e) { dAttributes.setTo(line); graphics.add(line); - // String outtext; - // if (new_dist < 1.0f) { - // outtext = String.format("%.3f %s", new_dist, cur_uom.getAbbr()); - // } else if (new_dist < 10.0f) { - // outtext = String.format("%.2f %s", new_dist, cur_uom.getAbbr()); - // } else if (new_dist < 100.0f) { - // outtext = String.format("%.1f %s", new_dist, cur_uom.getAbbr()); - // } else { String outtext = String.format("%.0f %s", new_dist, cur_uom.getAbbr()); - // } - OMText text = new OMText(right_x, lower_y - 20, "" + outtext, OMText.JUSTIFY_RIGHT); + OMText text = new OMText((left_x + right_x) / 2, lower_y - 3, "" + outtext, OMText.JUSTIFY_CENTER); Font font = text.getFont(); - text.setFont(font.deriveFont(Font.BOLD, font.getSize() + 4)); + text.setFont(font.deriveFont(font.getStyle(), font.getSize() + 2)); dAttributes.setTo(text); text.setTextMatteColor((Color) dAttributes.getMattingPaint()); @@ -365,7 +355,7 @@ public void projectionChanged(ProjectionEvent e) { text.setMattingPaint(OMColor.clear); graphics.add(text); graphics.generate(projection); - + setLegend(graphics); } diff --git a/src/core/src/main/java/com/bbn/openmap/gui/NavigateMenu.java b/src/core/src/main/java/com/bbn/openmap/gui/NavigateMenu.java index 47ea9f81d..d106cbd7b 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/NavigateMenu.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/NavigateMenu.java @@ -22,36 +22,19 @@ package com.bbn.openmap.gui; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JMenu; -import javax.swing.JMenuItem; - -import com.bbn.openmap.MapBean; -import com.bbn.openmap.event.ZoomEvent; -import com.bbn.openmap.event.ZoomListener; -import com.bbn.openmap.event.ZoomSupport; import com.bbn.openmap.gui.menu.CoordsMenuItem; import com.bbn.openmap.gui.menu.ProjectionMenu; -import com.bbn.openmap.util.Debug; /** * Provides MenuItems that lets users control the projection. This * includes providing a means to call up the Coordinate Window to let * users enter coordinates to center the map, a projection choice - * menu, and zooming choices. + * menu. */ -public class NavigateMenu extends AbstractOpenMapMenu implements ActionListener { +public class NavigateMenu extends AbstractOpenMapMenu { - public static final String defaultText = "Navigate"; - public static final String defaultMnemonic = "N"; - - protected ZoomSupport zoomSupport = new ZoomSupport(this); - public final static transient String zoomIn2Cmd = "zoomIn2Cmd"; - public final static transient String zoomIn4Cmd = "zoomIn4Cmd"; - public final static transient String zoomOut2Cmd = "zoomOut2Cmd"; - public final static transient String zoomOut4Cmd = "zoomOut4Cmd"; + public static final String DEFAULT_TEXT = "Navigate"; + public static final String DEFAULT_MNEMONIC = "N"; /** * This constructor automatically configures the Menu to have @@ -60,100 +43,11 @@ public class NavigateMenu extends AbstractOpenMapMenu implements ActionListener */ public NavigateMenu() { super(); - setText(i18n.get(this, "navigate", defaultText)); -// setMnemonic(i18n.get(this, "navigate", I18n.MNEMONIC, defaultMnemonic) + setText(i18n.get(this, "navigate", DEFAULT_TEXT)); +// setMnemonic(i18n.get(this, "navigate", I18n.MNEMONIC, DEFAULT_MNEMONIC) // .charAt(0)); add(new CoordsMenuItem()); - - JMenuItem mi; - JMenu submenu = (JMenu) add(new JMenu(i18n.get(this, - "zoomIn", - "Zoom In"))); - mi = (JMenuItem) submenu.add(new JMenuItem(i18n.get(this, - "zoomIn2X", - "2X"))); - mi.setActionCommand(zoomIn2Cmd); - mi.addActionListener(this); - mi = (JMenuItem) submenu.add(new JMenuItem(i18n.get(this, - "zoomIn4X", - "4X"))); - mi.setActionCommand(zoomIn4Cmd); - mi.addActionListener(this); - - submenu = (JMenu) add(new JMenu(i18n.get(this, "zoomOut", "Zoom Out"))); - mi = (JMenuItem) submenu.add(new JMenuItem(i18n.get(this, - "zoomOut2X", - "2X"))); - mi.setActionCommand(zoomOut2Cmd); - mi.addActionListener(this); - mi = (JMenuItem) submenu.add(new JMenuItem(i18n.get(this, - "zoomOut4X", - "4X"))); - mi.setActionCommand(zoomOut4Cmd); - mi.addActionListener(this); - add(new ProjectionMenu()); } - /** - * ActionListener interface, lets the Menu act on the actions of - * the MenuItems. - */ - public void actionPerformed(ActionEvent ae) { - String command = ae.getActionCommand(); - - Debug.message("navigatemenu", "NavigateMenu.actionPerformed(): " - + command); - - if (command.equals(zoomIn2Cmd)) { - fireZoom(ZoomEvent.RELATIVE, 0.5f); - } else if (command.equals(zoomIn4Cmd)) { - fireZoom(ZoomEvent.RELATIVE, 0.25f); - } else if (command.equals(zoomOut2Cmd)) { - fireZoom(ZoomEvent.RELATIVE, 2.0f); - } else if (command.equals(zoomOut4Cmd)) { - fireZoom(ZoomEvent.RELATIVE, 4.0f); - } - } - - /*---------------------------------------------------------------------- - * Zoom Support - for broadcasting zoom events - *---------------------------------------------------------------------- - */ - - /** - * - */ - public synchronized void addZoomListener(ZoomListener l) { - zoomSupport.add(l); - } - - /** - * - */ - public synchronized void removeZoomListener(ZoomListener l) { - zoomSupport.remove(l); - } - - /** - * - */ - public void fireZoom(int zoomType, float amount) { - zoomSupport.fireZoom(zoomType, amount); - } - - public void findAndInit(Object someObj) { - super.findAndInit(someObj); - if (someObj instanceof MapBean) { - addZoomListener((MapBean) someObj); - } - } - - public void findAndUndo(Object someObj) { - super.findAndUndo(someObj); - if (someObj instanceof MapBean) { - removeZoomListener((MapBean) someObj); - } - } - } \ No newline at end of file diff --git a/src/core/src/main/java/com/bbn/openmap/gui/NavigatePanel.java b/src/core/src/main/java/com/bbn/openmap/gui/NavigatePanel.java index 0b98277d1..6f2b7f6ba 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/NavigatePanel.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/NavigatePanel.java @@ -19,9 +19,14 @@ // $Author: dietrick $ // // ********************************************************************** - package com.bbn.openmap.gui; +import com.bbn.openmap.Environment; +import com.bbn.openmap.event.CenterListener; +import com.bbn.openmap.event.CenterSupport; +import com.bbn.openmap.event.PanListener; +import com.bbn.openmap.event.PanSupport; +import com.bbn.openmap.util.Debug; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -29,18 +34,10 @@ import java.awt.event.ActionListener; import java.io.Serializable; import java.net.URL; - import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPanel; -import com.bbn.openmap.Environment; -import com.bbn.openmap.event.CenterListener; -import com.bbn.openmap.event.CenterSupport; -import com.bbn.openmap.event.PanListener; -import com.bbn.openmap.event.PanSupport; -import com.bbn.openmap.util.Debug; - /** * A Navigation Rosette Bean. This bean is a source for PanEvents and * CenterEvents. @@ -48,15 +45,15 @@ public class NavigatePanel extends OMToolComponent implements Serializable, ActionListener { - public final static String panNWCmd = "panNW"; - public final static String panNCmd = "panN"; - public final static String panNECmd = "panNE"; - public final static String panECmd = "panE"; - public final static String panSECmd = "panSE"; - public final static String panSCmd = "panS"; - public final static String panSWCmd = "panSW"; - public final static String panWCmd = "panW"; - public final static String centerCmd = "center"; + public final static String PAN_NW_CMD = "panNW"; + public final static String PAN_N_CMD = "panN"; + public final static String PAN_NE_CMD = "panNE"; + public final static String PAN_E_CMD = "panE"; + public final static String PAN_SE_CMD = "panSE"; + public final static String PAN_S_CMD = "panS"; + public final static String PAN_SW_CMD = "panSW"; + public final static String PAN_W_CMD = "panW"; + public final static String CENTER_CMD = "center"; protected transient JButton nwButton = null; protected transient JButton nButton = null; @@ -86,19 +83,18 @@ public class NavigatePanel extends OMToolComponent implements Serializable, // protected int height = 0; // calculated // protected int width = 0; // calculated - protected boolean useDefaultCenter = false; protected float defaultCenterLat = 0; protected float defaultCenterLon = 0; - public final static String defaultKey = "navigatepanel"; + public final static String DEFAULT_KEY = "navigatepanel"; /** * Construct the NavigationPanel. */ public NavigatePanel() { super(); - setKey(defaultKey); + setKey(DEFAULT_KEY); panDelegate = new PanSupport(this); centerDelegate = new CenterSupport(this); @@ -111,21 +107,21 @@ public NavigatePanel() { String info = i18n.get(NavigatePanel.class, "panNW.tooltip", "Pan Northwest"); - nwButton = getButton(nwName, info, panNWCmd); + nwButton = getButton(nwName, info, PAN_NW_CMD); c2.gridx = 0; c2.gridy = 0; internalGridbag.setConstraints(nwButton, c2); panel.add(nwButton); info = i18n.get(NavigatePanel.class, "panN.tooltip", "Pan North"); - nButton = getButton(nName, info, panNCmd); + nButton = getButton(nName, info, PAN_N_CMD); c2.gridx = 1; c2.gridy = 0; internalGridbag.setConstraints(nButton, c2); panel.add(nButton); info = i18n.get(NavigatePanel.class, "panNE.tooltip", "Pan Northeast"); - neButton = getButton(neName, info, panNECmd); + neButton = getButton(neName, info, PAN_NE_CMD); c2.gridx = 2; c2.gridy = 0; internalGridbag.setConstraints(neButton, c2); @@ -133,7 +129,7 @@ public NavigatePanel() { // begin middle row info = i18n.get(NavigatePanel.class, "panW.tooltip", "Pan West"); - wButton = getButton(wName, info, panWCmd); + wButton = getButton(wName, info, PAN_W_CMD); c2.gridx = 0; c2.gridy = 1; internalGridbag.setConstraints(wButton, c2); @@ -142,14 +138,14 @@ public NavigatePanel() { info = i18n.get(NavigatePanel.class, "center.tooltip", "Center Map at Starting Coords"); - cButton = getButton(cName, info, centerCmd); + cButton = getButton(cName, info, CENTER_CMD); c2.gridx = 1; c2.gridy = 1; internalGridbag.setConstraints(cButton, c2); panel.add(cButton); info = i18n.get(NavigatePanel.class, "panE.tooltip", "Pan East"); - eButton = getButton(eName, info, panECmd); + eButton = getButton(eName, info, PAN_E_CMD); c2.gridx = 2; c2.gridy = 1; internalGridbag.setConstraints(eButton, c2); @@ -157,21 +153,21 @@ public NavigatePanel() { // begin bottom row info = i18n.get(NavigatePanel.class, "panSW.tooltip", "Pan Southwest"); - swButton = getButton(swName, info, panSWCmd); + swButton = getButton(swName, info, PAN_SW_CMD); c2.gridx = 0; c2.gridy = 2; internalGridbag.setConstraints(swButton, c2); panel.add(swButton); info = i18n.get(NavigatePanel.class, "panS.tooltip", "Pan South"); - sButton = getButton(sName, info, panSCmd); + sButton = getButton(sName, info, PAN_S_CMD); c2.gridx = 1; c2.gridy = 2; internalGridbag.setConstraints(sButton, c2); panel.add(sButton); info = i18n.get(NavigatePanel.class, "panSE.tooltip", "Pan Southeast"); - seButton = getButton(seName, info, panSECmd); + seButton = getButton(seName, info, PAN_SE_CMD); c2.gridx = 2; c2.gridy = 2; internalGridbag.setConstraints(seButton, c2); @@ -182,11 +178,11 @@ public NavigatePanel() { /** * Add the named button to the panel. - * + * * @param name GIF image name * @param info ToolTip text * @param command String command name - * + * @return JButton */ protected JButton getButton(String name, String info, String command) { URL url = NavigatePanel.class.getResource(name); @@ -204,7 +200,7 @@ protected JButton getButton(String name, String info, String command) { /** * Add a CenterListener. - * + * * @param listener CenterListener */ public synchronized void addCenterListener(CenterListener listener) { @@ -213,7 +209,7 @@ public synchronized void addCenterListener(CenterListener listener) { /** * Remove a CenterListener - * + * * @param listener CenterListener */ public synchronized void removeCenterListener(CenterListener listener) { @@ -222,7 +218,7 @@ public synchronized void removeCenterListener(CenterListener listener) { /** * Add a PanListener. - * + * * @param listener PanListener */ public synchronized void addPanListener(PanListener listener) { @@ -231,7 +227,7 @@ public synchronized void addPanListener(PanListener listener) { /** * Remove a PanListener - * + * * @param listener PanListener */ public synchronized void removePanListener(PanListener listener) { @@ -247,7 +243,7 @@ protected synchronized void fireCenterEvent(float lat, float lon) { /** * Fire a PanEvent. - * + * * @param az azimuth east of north */ protected synchronized void firePanEvent(float az) { @@ -257,9 +253,9 @@ protected synchronized void firePanEvent(float az) { /** * Get the pan factor. *

- * The panFactor is the amount of screen to shift when panning in - * a certain direction: 0=none, 1=half-screen shift. - * + * The panFactor is the amount of screen to shift when panning in a certain + * direction: 0=none, 1=half-screen shift. + * * @return float panFactor (0.0 <= panFactor <= 1.0) */ public float getPanFactor() { @@ -269,10 +265,9 @@ public float getPanFactor() { /** * Set the pan factor. *

- * This defaults to 1.0. The panFactor is the amount of screen to - * shift when panning in a certain direction: 0=none, - * 1=half-screen shift. - * + * This defaults to 1.0. The panFactor is the amount of screen to shift when + * panning in a certain direction: 0=none, 1=half-screen shift. + * * @param panFactor (0.0 <= panFactor <= 1.0) */ public void setPanFactor(float panFactor) { @@ -283,11 +278,11 @@ public void setPanFactor(float panFactor) { } /** - * Use this function to set where you want the map projection to - * pan to when the user clicks on "center" button on the - * navigation panel. The scale does not change. When you call this - * function, the projection does not change. - * + * Use this function to set where you want the map projection to pan to when + * the user clicks on "center" button on the navigation panel. The scale + * does not change. When you call this function, the projection does not + * change. + * * @param passedLat float the center latitude (in degrees) * @param passedLon float the center longitude (in degrees) */ @@ -299,52 +294,64 @@ public void setDefaultCenter(float passedLat, float passedLon) { /** * ActionListener Interface. - * + * * @param e ActionEvent */ + @Override public void actionPerformed(java.awt.event.ActionEvent e) { String command = e.getActionCommand(); Debug.message("navpanel", "NavigatePanel.actionPerformed(): " + command); - if (command.equals(panNWCmd)) { - firePanEvent(-45f); - } else if (command.equals(panNCmd)) { - firePanEvent(0f); - } else if (command.equals(panNECmd)) { - firePanEvent(45f); - } else if (command.equals(panECmd)) { - firePanEvent(90f); - } else if (command.equals(panSECmd)) { - firePanEvent(135f); - } else if (command.equals(panSCmd)) { - firePanEvent(180f); - } else if (command.equals(panSWCmd)) { - firePanEvent(-135f); - } else if (command.equals(panWCmd)) { - firePanEvent(-90f); - } else if (command.equals(centerCmd)) { - // go back to the center point - - float lat; - float lon; - if (useDefaultCenter) { - lat = defaultCenterLat; - lon = defaultCenterLon; - } else { - lat = Environment.getFloat(Environment.Latitude, 0f); - lon = Environment.getFloat(Environment.Longitude, 0f); - } - fireCenterEvent(lat, lon); + switch (command) { + case PAN_NW_CMD: + firePanEvent(-45f); + break; + case PAN_N_CMD: + firePanEvent(0f); + break; + case PAN_NE_CMD: + firePanEvent(45f); + break; + case PAN_E_CMD: + firePanEvent(90f); + break; + case PAN_SE_CMD: + firePanEvent(135f); + break; + case PAN_S_CMD: + firePanEvent(180f); + break; + case PAN_SW_CMD: + firePanEvent(-135f); + break; + case PAN_W_CMD: + firePanEvent(-90f); + break; + case CENTER_CMD: + // go back to the center point + + float lat; + float lon; + if (useDefaultCenter) { + lat = defaultCenterLat; + lon = defaultCenterLon; + } else { + lat = Environment.getFloat(Environment.Latitude, 0f); + lon = Environment.getFloat(Environment.Longitude, 0f); + } + fireCenterEvent(lat, lon); + break; + default: + break; } } // ///////////////////////////////////////////////////////////////////////// - // // OMComponentPanel methods to make the tool work with // // the MapHandler to find objects it needs. // ///////////////////////////////////////////////////////////////////////// - + @Override public void findAndInit(Object obj) { if (obj instanceof PanListener) { addPanListener((PanListener) obj); @@ -354,6 +361,7 @@ public void findAndInit(Object obj) { } } + @Override public void findAndUndo(Object obj) { if (obj instanceof PanListener) { removePanListener((PanListener) obj); diff --git a/src/core/src/main/java/com/bbn/openmap/gui/OverlayMapPanel.java b/src/core/src/main/java/com/bbn/openmap/gui/OverlayMapPanel.java index 8cbee0800..da687d78f 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/OverlayMapPanel.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/OverlayMapPanel.java @@ -11,9 +11,15 @@ // // // ********************************************************************** - package com.bbn.openmap.gui; +import com.bbn.openmap.MapBean; +import com.bbn.openmap.PropertyHandler; +import com.bbn.openmap.layer.shape.ShapeLayer; +import com.bbn.openmap.omGraphics.DrawingAttributes; +import com.bbn.openmap.omGraphics.OMGraphicConstants; +import com.bbn.openmap.proj.ProjectionStack; +import com.bbn.openmap.util.PropUtils; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -22,7 +28,6 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Properties; - import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; @@ -30,14 +35,6 @@ import javax.swing.SwingUtilities; import javax.swing.border.BevelBorder; -import com.bbn.openmap.MapBean; -import com.bbn.openmap.PropertyHandler; -import com.bbn.openmap.layer.shape.ShapeLayer; -import com.bbn.openmap.omGraphics.DrawingAttributes; -import com.bbn.openmap.omGraphics.OMGraphicConstants; -import com.bbn.openmap.proj.ProjectionStack; -import com.bbn.openmap.util.PropUtils; - /** * An extension of the BasicMapPanel that uses an OverlayLayout on the panel in * the BorderLayout.CENTER position. Contains a transparent widgets JPanel for @@ -52,320 +49,386 @@ */ public class OverlayMapPanel extends BasicMapPanel implements PropertyChangeListener { - private static final long serialVersionUID = 1L; - - public final static String ACTIVE_WIDGET_COLOR_PROPERTY = "activeWidgets"; - public final static String INACTIVE_WIDGET_COLOR_PROPERTY = "inactiveWidgets"; - public final static String WIDGET_SIZE_PROPERTY = "widgetSize"; - protected int DEFAULT_WIDGET_BUTTON_SIZE = 15; - - /** - * May be null, in which case the widgets should decide. - */ - protected DrawingAttributes activeWidgetColors; - /** - * May be null, in which case the widgets should decide. - */ - protected DrawingAttributes inactiveWidgetColors; - /** - * Defaults to 15; - */ - protected int widgetButtonSize = DEFAULT_WIDGET_BUTTON_SIZE; - - /** - * A transparent JPanel with a border layout, residing on top of the - * MapBean. - */ - protected JPanel widgets; - - private JPanel centerContainer; - - /** - * Creates an empty OverlayMapPanel that creates its own empty - * PropertyHandler. The MapPanel will contain a MapBean, a MapHandler, - * EmbeddedNavPanel and a PropertyHandler with no properties. The - * constructor to use to create a blank map framework to add components to. - */ - public OverlayMapPanel() { - super(new PropertyHandler(new Properties()), false); - } - - /** - * Create a OverlayMapPanel with the option of delaying the search for - * properties until the create() call is made. - * - * @param delayCreation true to let the MapPanel know that the artful - * programmer will call create() - */ - public OverlayMapPanel(boolean delayCreation) { - super(null, delayCreation); - } - - /** - * Create a OverlayMapPanel that configures itself with the properties - * contained in the PropertyHandler provided. If the PropertyHandler is - * null, a new one will be created. - */ - public OverlayMapPanel(PropertyHandler propertyHandler) { - super(propertyHandler, false); - } - - /** - * Create a OverlayMapPanel that configures itself with properties contained - * in the PropertyHandler provided, and with the option of delaying the - * search for properties until the create() call is made. - * - * @param delayCreation true to let the MapPanel know that the artful - * programmer will call create() - */ - public OverlayMapPanel(PropertyHandler propertyHandler, boolean delayCreation) { - super(propertyHandler, delayCreation); - } - - /** - * Calls layoutPanel(MapBean), which configures the panel. - */ - protected void addMapBeanToPanel(MapBean map) { - layoutPanel(map); - map.addPropertyChangeListener(this); - } - - public DrawingAttributes getActiveWidgetColors() { - return activeWidgetColors; - } - - public void setActiveWidgetColors(DrawingAttributes activeWidgetColors) { - this.activeWidgetColors = activeWidgetColors; - } - - public DrawingAttributes getInactiveWidgetColors() { - return inactiveWidgetColors; - } - - public void setInactiveWidgetColors(DrawingAttributes inactiveWidgetColors) { - this.inactiveWidgetColors = inactiveWidgetColors; - } - - public int getWidgetButtonSize() { - return widgetButtonSize; - } - - public void setWidgetButtonSize(int widgetButtonSize) { - this.widgetButtonSize = widgetButtonSize; - } - - /** - * New method added, called from addMapBeanToPanel(MapBean). - * - * @param map - */ - protected void layoutPanel(MapBean map) { - - JPanel hackPanel = new JPanel(); - hackPanel.setLayout(new BorderLayout()); - hackPanel.setOpaque(false); - hackPanel.add(map, BorderLayout.CENTER); - - centerContainer = new JPanel(); - centerContainer.setLayout(new OverlayLayout(centerContainer)); - - addMapComponent(new ProjectionStack()); - widgets = getComponentsFloatingOnMap(map); - - setBorders(map, widgets); - - centerContainer.add(widgets); - centerContainer.add(hackPanel); - - add(centerContainer, BorderLayout.CENTER); - } - - /** - * Create the panel containing the components that will float over the map. - * Default is a nav panel and scale indicator. - * - * @param map The MapBean - * @return a JPanel with the layout and rendering attributes set for the - * area over the map. - */ - protected JPanel getComponentsFloatingOnMap(MapBean map) { - - JPanel floatingWidgets = new JPanel(); - floatingWidgets.setLayout(new BorderLayout()); - floatingWidgets.setBackground(OMGraphicConstants.clear); - floatingWidgets.setOpaque(false); - floatingWidgets.setBounds(0, 0, map.getWidth(), map.getHeight()); - floatingWidgets.setMinimumSize(new Dimension(MapBean.DEFAULT_WIDTH, MapBean.DEFAULT_HEIGHT)); - - // These may be null, but the EmbeddedNavPanel will choose it's own - // default colors if that is so. - DrawingAttributes activeWidgetColors = getActiveWidgetColors(); - DrawingAttributes inactiveWidgetColors = getInactiveWidgetColors(); - int widgetButtonSize = getWidgetButtonSize(); - - EmbeddedNavPanel navPanel = new EmbeddedNavPanel(activeWidgetColors, inactiveWidgetColors, widgetButtonSize); - navPanel.setBounds(12, 12, navPanel.getMinimumSize().width, navPanel.getMinimumSize().height); - addMapComponent(navPanel); - floatingWidgets.add(navPanel, BorderLayout.WEST); - - EmbeddedScaleDisplayPanel scaleDisplay = new EmbeddedScaleDisplayPanel(); - addMapComponent(scaleDisplay); - floatingWidgets.add(scaleDisplay, BorderLayout.EAST); - - return floatingWidgets; - } - - /** - * If you want different borders or color them differently, override this - * method. - * - * @param map - * @param widgets - */ - protected void setBorders(MapBean map, JPanel widgets) { - - if (map != null) { - map.setBorder(null); - } - - if (widgets != null) { - widgets.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.GRAY, Color.DARK_GRAY)); - } - } - - /** Include exit in the File menu. Call this before create(). */ - public void includeExitMenuItem() { - addProperty("quitMenu.class", "com.bbn.openmap.gui.map.QuitMenuItem"); - appendProperty("fileMenu.items", "quitMenu"); - } - - public void setProperties(String prefix, Properties props) { - super.setProperties(prefix, props); - prefix = PropUtils.getScopedPropertyPrefix(prefix); - - DrawingAttributes awc = getActiveWidgetColors(); - if (awc == null) { - awc = DrawingAttributes.getDefaultClone(); - } - DrawingAttributes iwc = getInactiveWidgetColors(); - if (iwc == null) { - iwc = DrawingAttributes.getDefaultClone(); - } - - // If no properties have been set for them, reset to null so the - // EmbeddedNavPanel default colors are used. - awc.setProperties(prefix + ACTIVE_WIDGET_COLOR_PROPERTY, props); - if (awc.equals(DrawingAttributes.getDefaultClone())) { - awc = null; - } - - iwc.setProperties(prefix + INACTIVE_WIDGET_COLOR_PROPERTY, props); - if (iwc.equals(DrawingAttributes.getDefaultClone())) { - iwc = null; - } - - setActiveWidgetColors(awc); - setInactiveWidgetColors(iwc); - - setWidgetButtonSize(PropUtils.intFromProperties(props, prefix + WIDGET_SIZE_PROPERTY, getWidgetButtonSize())); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - String prefix = PropUtils.getScopedPropertyPrefix(this); - - DrawingAttributes awc = getActiveWidgetColors(); - if (awc != null) { - awc.setPropertyPrefix(PropUtils.getScopedPropertyPrefix(this) + ACTIVE_WIDGET_COLOR_PROPERTY); - awc.getProperties(props); - } - - DrawingAttributes iwc = getInactiveWidgetColors(); - if (iwc != null) { - iwc.setPropertyPrefix(PropUtils.getScopedPropertyPrefix(this) + INACTIVE_WIDGET_COLOR_PROPERTY); - iwc.getProperties(props); - } - - int widgetSize = getWidgetButtonSize(); - if (widgetSize != DEFAULT_WIDGET_BUTTON_SIZE) { - props.put(prefix + WIDGET_SIZE_PROPERTY, Integer.toString(widgetSize)); - } - - return props; - } - - /** - * Add object to MapHandler via addMapComponent(Object), then return this - * MapPanel. - * - * @param obj object to add to MapHandler - * @return this MapPanel - */ - public OverlayMapPanel with(Object obj) { - addMapComponent(obj); - return this; - } - - /** - * Create an OverlayMapPanel with a LayerHandler, MouseDelegator and - * OMMouseMode pre-added(). - * - * @return OverlayMapPanel - */ - public static OverlayMapPanel standardConfig() { - return new OverlayMapPanel().with(new com.bbn.openmap.LayerHandler()).with(new com.bbn.openmap.MouseDelegator()) - .with(new com.bbn.openmap.event.OMMouseMode()); - } - - /** A main() method that just brings up a JFrame containing the MapPanel. */ - public static void main(String argv[]) { - SwingUtilities.invokeLater(new Runnable() { - - public void run() { - - OverlayMapPanel map = OverlayMapPanel.standardConfig() - .with(new ShapeLayer("share/data/shape/cntry02/cntry02.shp")); - map.addMapComponent(new com.bbn.openmap.InformationDelegator()); - map.getMapBean().setBckgrnd(new Color(0x99b3cc)); - map.includeExitMenuItem(); - - JFrame f = new JFrame("Map"); - f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - f.setJMenuBar(map.getMapMenuBar()); - f.getContentPane().add(map); - f.setSize(800, 600); - f.setVisible(true); - } - - }); - - } - - /* + private static final long serialVersionUID = 1L; + + /** + * + */ + public final static String ACTIVE_WIDGET_COLOR_PROPERTY = "activeWidgets"; + + /** + * + */ + public final static String INACTIVE_WIDGET_COLOR_PROPERTY = "inactiveWidgets"; + + /** + * + */ + public final static String WIDGET_SIZE_PROPERTY = "widgetSize"; + + /** + * + */ + protected int DEFAULT_WIDGET_BUTTON_SIZE = 15; + + /** + * May be null, in which case the widgets should decide. + */ + protected DrawingAttributes activeWidgetColors; + /** + * May be null, in which case the widgets should decide. + */ + protected DrawingAttributes inactiveWidgetColors; + /** + * Defaults to 15; + */ + protected int widgetButtonSize = DEFAULT_WIDGET_BUTTON_SIZE; + + /** + * A transparent JPanel with a border layout, residing on top of the + * MapBean. + */ + protected JPanel widgets; + + private JPanel centerContainer; + + /** + * Creates an empty OverlayMapPanel that creates its own empty + * PropertyHandler. The MapPanel will contain a MapBean, a MapHandler, + * EmbeddedNavPanel and a PropertyHandler with no properties. The + * constructor to use to create a blank map framework to add components to. + */ + public OverlayMapPanel() { + super(new PropertyHandler(new Properties()), false); + } + + /** + * Create a OverlayMapPanel with the option of delaying the search for + * properties until the create() call is made. + * + * @param delayCreation true to let the MapPanel know that the artful + * programmer will call create() + */ + public OverlayMapPanel(boolean delayCreation) { + super(null, delayCreation); + } + + /** + * Create a OverlayMapPanel that configures itself with the properties + * contained in the PropertyHandler provided. If the PropertyHandler is + * null, a new one will be created. + * + * @param propertyHandler + */ + public OverlayMapPanel(PropertyHandler propertyHandler) { + super(propertyHandler, false); + } + + /** + * Create a OverlayMapPanel that configures itself with properties contained + * in the PropertyHandler provided, and with the option of delaying the + * search for properties until the create() call is made. + * + * @param propertyHandler + * @param delayCreation true to let the MapPanel know that the artful + * programmer will call create() + */ + public OverlayMapPanel(PropertyHandler propertyHandler, boolean delayCreation) { + super(propertyHandler, delayCreation); + } + + /** + * Calls layoutPanel(MapBean), which configures the panel. + * + * @param map + */ + @Override + protected void addMapBeanToPanel(MapBean map) { + layoutPanel(map); + map.addPropertyChangeListener(this); + } + + /** + * + * @return + */ + public DrawingAttributes getActiveWidgetColors() { + return activeWidgetColors; + } + + /** + * + * @param activeWidgetColors + */ + public void setActiveWidgetColors(DrawingAttributes activeWidgetColors) { + this.activeWidgetColors = activeWidgetColors; + } + + /** + * + * @return + */ + public DrawingAttributes getInactiveWidgetColors() { + return inactiveWidgetColors; + } + + /** + * + * @param inactiveWidgetColors + */ + public void setInactiveWidgetColors(DrawingAttributes inactiveWidgetColors) { + this.inactiveWidgetColors = inactiveWidgetColors; + } + + /** + * + * @return + */ + public int getWidgetButtonSize() { + return widgetButtonSize; + } + + /** + * + * @param widgetButtonSize + */ + public void setWidgetButtonSize(int widgetButtonSize) { + this.widgetButtonSize = widgetButtonSize; + } + + /** + * New method added, called from addMapBeanToPanel(MapBean). + * + * @param map + */ + protected void layoutPanel(MapBean map) { + + JPanel hackPanel = new JPanel(); + hackPanel.setLayout(new BorderLayout()); + hackPanel.setOpaque(false); + hackPanel.add(map, BorderLayout.CENTER); + + centerContainer = new JPanel(); + centerContainer.setLayout(new OverlayLayout(centerContainer)); + + addMapComponent(new ProjectionStack()); + widgets = getComponentsFloatingOnMap(map); + + setBorders(map, widgets); + + centerContainer.add(widgets); + centerContainer.add(hackPanel); + + add(centerContainer, BorderLayout.CENTER); + } + + /** + * Create the panel containing the components that will float over the map. + * Default is a nav panel and scale indicator. + * + * @param map The MapBean + * @return a JPanel with the layout and rendering attributes set for the + * area over the map. + */ + protected JPanel getComponentsFloatingOnMap(MapBean map) { + + JPanel floatingWidgets = new JPanel(); + floatingWidgets.setLayout(new BorderLayout()); + floatingWidgets.setBackground(OMGraphicConstants.clear); + floatingWidgets.setOpaque(false); + floatingWidgets.setBounds(0, 0, map.getWidth(), map.getHeight()); + floatingWidgets.setMinimumSize(new Dimension(MapBean.DEFAULT_WIDTH, MapBean.DEFAULT_HEIGHT)); + + // These may be null, but the EmbeddedNavPanel will choose it's own + // default colors if that is so. + DrawingAttributes activeWidgetDA = getActiveWidgetColors(); + DrawingAttributes inactiveWidgetDA = getInactiveWidgetColors(); + int buttonSize = getWidgetButtonSize(); + + EmbeddedNavPanel navPanel = new EmbeddedNavPanel(activeWidgetDA, inactiveWidgetDA, buttonSize); + navPanel.setBounds(12, 12, navPanel.getMinimumSize().width, navPanel.getMinimumSize().height); + addMapComponent(navPanel); + floatingWidgets.add(navPanel, BorderLayout.WEST); + + EmbeddedScaleDisplayPanel scaleDisplay = new EmbeddedScaleDisplayPanel(); + addMapComponent(scaleDisplay); + floatingWidgets.add(scaleDisplay, BorderLayout.EAST); + + return floatingWidgets; + } + + /** + * If you want different borders or color them differently, override this + * method. + * + * @param map + * @param widgets + */ + protected void setBorders(MapBean map, JPanel widgets) { + + if (map != null) { + map.setBorder(null); + } + + if (widgets != null) { + widgets.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.GRAY, Color.DARK_GRAY)); + } + } + + /** + * Include exit in the File menu. Call this before create(). + */ + public void includeExitMenuItem() { + addProperty("quitMenu.class", "com.bbn.openmap.gui.map.QuitMenuItem"); + appendProperty("fileMenu.items", "quitMenu"); + } + + /** + * + * @param prefix + * @param props + */ + @Override + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + prefix = PropUtils.getScopedPropertyPrefix(prefix); + + DrawingAttributes awc = getActiveWidgetColors(); + if (awc == null) { + awc = DrawingAttributes.getDefaultClone(); + } + DrawingAttributes iwc = getInactiveWidgetColors(); + if (iwc == null) { + iwc = DrawingAttributes.getDefaultClone(); + } + + // If no properties have been set for them, reset to null so the + // EmbeddedNavPanel default colors are used. + awc.setProperties(prefix + ACTIVE_WIDGET_COLOR_PROPERTY, props); + if (awc.equals(DrawingAttributes.getDefaultClone())) { + awc = null; + } + + iwc.setProperties(prefix + INACTIVE_WIDGET_COLOR_PROPERTY, props); + if (iwc.equals(DrawingAttributes.getDefaultClone())) { + iwc = null; + } + + setActiveWidgetColors(awc); + setInactiveWidgetColors(iwc); + + setWidgetButtonSize(PropUtils.intFromProperties(props, prefix + WIDGET_SIZE_PROPERTY, getWidgetButtonSize())); + } + + /** + * + * @param props + * @return + */ + @Override + public Properties getProperties(Properties props) { + props = super.getProperties(props); + String prefix = PropUtils.getScopedPropertyPrefix(this); + + DrawingAttributes awc = getActiveWidgetColors(); + if (awc != null) { + awc.setPropertyPrefix(PropUtils.getScopedPropertyPrefix(this) + ACTIVE_WIDGET_COLOR_PROPERTY); + awc.getProperties(props); + } + + DrawingAttributes iwc = getInactiveWidgetColors(); + if (iwc != null) { + iwc.setPropertyPrefix(PropUtils.getScopedPropertyPrefix(this) + INACTIVE_WIDGET_COLOR_PROPERTY); + iwc.getProperties(props); + } + + int widgetSize = getWidgetButtonSize(); + if (widgetSize != DEFAULT_WIDGET_BUTTON_SIZE) { + props.put(prefix + WIDGET_SIZE_PROPERTY, Integer.toString(widgetSize)); + } + + return props; + } + + /** + * Add object to MapHandler via addMapComponent(Object), then return this + * MapPanel. + * + * @param obj object to add to MapHandler + * @return this MapPanel + */ + @Override + public OverlayMapPanel with(Object obj) { + addMapComponent(obj); + return this; + } + + /** + * Create an OverlayMapPanel with a LayerHandler, MouseDelegator and + * OMMouseMode pre-added(). + * + * @return OverlayMapPanel + */ + public static OverlayMapPanel standardConfig() { + return new OverlayMapPanel().with(new com.bbn.openmap.LayerHandler()).with(new com.bbn.openmap.MouseDelegator()) + .with(new com.bbn.openmap.event.OMMouseMode()); + } + + /** + * A main() method that just brings up a JFrame containing the MapPanel. + * + * @param argv + */ + public static void main(String argv[]) { + SwingUtilities.invokeLater(() -> { + OverlayMapPanel map = OverlayMapPanel.standardConfig() + .with(new ShapeLayer("share/data/shape/cntry02/cntry02.shp")); + map.addMapComponent(new com.bbn.openmap.InformationDelegator()); + map.getMapBean().setBckgrnd(new Color(0x99b3cc)); + map.includeExitMenuItem(); + + JFrame f = new JFrame("Map"); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.setJMenuBar(map.getMapMenuBar()); + f.getContentPane().add(map); + f.setSize(800, 600); + f.setVisible(true); + + }); + + } + + /* * (non-Javadoc) * @see java.beans.PropertyChangeListener#propertyChange(java.beans. * PropertyChangeEvent) - */ - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(MapBean.CursorProperty)) { - centerContainer.setCursor(((Cursor) evt.getNewValue())); - } - } - - /** - * If one of the widgets gets removed from the MapHandler, we'll remove it - * from the interface, too. - */ - public void findAndUndo(Object someObj) { - super.findAndUndo(someObj); - - /* + */ + /** + * + * @param evt + */ + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(MapBean.CursorProperty)) { + centerContainer.setCursor(((Cursor) evt.getNewValue())); + } + } + + /** + * If one of the widgets gets removed from the MapHandler, we'll remove it + * from the interface, too. + * + * @param someObj + */ + public void findAndUndo(Object someObj) { + super.findAndUndo(someObj); + + /* * It's no harm to call this for every Component. Component checks to * see if widgets is the Component's parent first. - */ - if (widgets != null && someObj instanceof Component) { - widgets.remove((Component) someObj); - } - } + */ + if (widgets != null && someObj instanceof Component) { + widgets.remove((Component) someObj); + } + } } diff --git a/src/core/src/main/java/com/bbn/openmap/gui/ZoomPanel.java b/src/core/src/main/java/com/bbn/openmap/gui/ZoomPanel.java index 93dc1aff7..40ec4ab29 100644 --- a/src/core/src/main/java/com/bbn/openmap/gui/ZoomPanel.java +++ b/src/core/src/main/java/com/bbn/openmap/gui/ZoomPanel.java @@ -19,9 +19,13 @@ // $Author: dietrick $ // // ********************************************************************** - package com.bbn.openmap.gui; +import com.bbn.openmap.event.ZoomEvent; +import com.bbn.openmap.event.ZoomListener; +import com.bbn.openmap.event.ZoomSupport; +import com.bbn.openmap.util.Debug; +import com.bbn.openmap.util.I18n; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -29,36 +33,29 @@ import java.awt.event.ActionListener; import java.io.Serializable; import java.net.URL; - import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPanel; -import com.bbn.openmap.event.ZoomEvent; -import com.bbn.openmap.event.ZoomListener; -import com.bbn.openmap.event.ZoomSupport; -import com.bbn.openmap.util.Debug; -import com.bbn.openmap.util.I18n; - /** * Bean to zoom the Map. *

- * This bean is a source for ZoomEvents. It is a simple widget with a - * ZoomIn button and a ZoomOut button. When a button is pressed, the - * appropriate zoom event is fired to all registered listeners. - * + * This bean is a source for ZoomEvents. It is a simple widget with a ZoomIn + * button and a ZoomOut button. When a button is pressed, the appropriate zoom + * event is fired to all registered listeners. + * * @see #addZoomListener */ public class ZoomPanel extends OMToolComponent implements ActionListener, Serializable { - public final static transient String zoomInCmd = "zoomin"; - public final static transient String zoomOutCmd = "zoomout"; + public final static transient String ZOOM_IN_CMD = "zoomin"; + public final static transient String ZOOM_OUT_CMD = "zoomout"; protected transient JButton zoomInButton, zoomOutButton; protected transient ZoomSupport zoomDelegate; - public final static String defaultKey = "zoompanel"; + public final static String DEFAULT_KEY = "zoompanel"; /** * Default Zoom In Factor is 0.5. @@ -75,7 +72,7 @@ public class ZoomPanel extends OMToolComponent implements ActionListener, */ public ZoomPanel() { super(); - setKey(defaultKey); + setKey(DEFAULT_KEY); // setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); // setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.setOpaque(false); @@ -86,13 +83,13 @@ public ZoomPanel() { panel.setLayout(internalGridbag); zoomDelegate = new ZoomSupport(this); - zoomInButton = getButton("zoomIn", "Zoom In", zoomInCmd); + zoomInButton = getButton("zoomIn", "Zoom In", ZOOM_IN_CMD); c2.gridx = 0; c2.gridy = 0; internalGridbag.setConstraints(zoomInButton, c2); panel.add(zoomInButton); - zoomOutButton = getButton("zoomOut", "Zoom Out", zoomOutCmd); + zoomOutButton = getButton("zoomOut", "Zoom Out", ZOOM_OUT_CMD); c2.gridy = 1; internalGridbag.setConstraints(zoomOutButton, c2); panel.add(zoomOutButton); @@ -102,29 +99,28 @@ public ZoomPanel() { /** * Get the Zoom In Factor. - * - * @return float the degree by which map scale will be multiplied - * when zoom in button is pressed + * + * @return float the degree by which map scale will be multiplied when zoom + * in button is pressed */ public float getZoomInFactor() { return zoomInFactor; } /** - * Sets the Zoom In factor. The factor must be < 1.0. - * (otherwise it would make ZoomIn into a ZoomOut). - * - * @param factor the degree by which map scale should be - * multiplied + * Sets the Zoom In factor. The factor must be < 1.0. (otherwise it would + * make ZoomIn into a ZoomOut). + * + * @param factor the degree by which map scale should be multiplied */ public void setZoomInFactor(float factor) { if (factor < 1.0f) { zoomInFactor = factor; zoomInButton.setToolTipText(i18n.get(ZoomPanel.class, - zoomInCmd + "factor", + ZOOM_IN_CMD + "factor", I18n.TOOLTIP, "zoom in X" + zoomInFactor, - new Float(zoomInFactor))); + zoomInFactor)); } else { throw new IllegalArgumentException("Zoom In factor too large (must be < 1.0)"); } @@ -132,20 +128,19 @@ public void setZoomInFactor(float factor) { /** * Get the Zoom Out Factor. - * - * @return float the degree by which map scale will be multiplied - * when zoom out button is pressed + * + * @return float the degree by which map scale will be multiplied when zoom + * out button is pressed */ public float getZoomOutFactor() { return zoomOutFactor; } /** - * Sets the Zoom Out Factor. The factor must be > 1.0 - * (otherwise it would turn ZoomOut into ZoomIn). - * - * @param factor the degree by which map scale should be - * multiplied. + * Sets the Zoom Out Factor. The factor must be > 1.0 (otherwise it would + * turn ZoomOut into ZoomIn). + * + * @param factor the degree by which map scale should be multiplied. */ public void setZoomOutFactor(float factor) { if (factor > 1.0f) { @@ -153,10 +148,10 @@ public void setZoomOutFactor(float factor) { // zoomOutButton.setToolTipText("zoom out X" + // zoomOutFactor); zoomOutButton.setToolTipText(i18n.get(ZoomPanel.class, - zoomOutCmd + "factor", + ZOOM_OUT_CMD + "factor", I18n.TOOLTIP, "zoom out X" + zoomOutFactor, - new Float(zoomOutFactor))); + zoomOutFactor)); } else { throw new IllegalArgumentException("Zoom In factor too small (must be > 1.0)"); @@ -165,11 +160,11 @@ public void setZoomOutFactor(float factor) { /** * Add the named button to the panel. - * + * * @param name GIF image name * @param info ToolTip text * @param command String command name - * + * @return JButton */ protected JButton getButton(String name, String info, String command) { URL url = ZoomPanel.class.getResource(name + ".gif"); @@ -188,7 +183,7 @@ protected JButton getButton(String name, String info, String command) { /** * Add a ZoomListener from the listener list. - * + * * @param listener The ZoomListener to be added */ public synchronized void addZoomListener(ZoomListener listener) { @@ -197,7 +192,7 @@ public synchronized void addZoomListener(ZoomListener listener) { /** * Remove a ZoomListener from the listener list. - * + * * @param listener The ZoomListener to be removed */ public synchronized void removeZoomListener(ZoomListener listener) { @@ -206,19 +201,21 @@ public synchronized void removeZoomListener(ZoomListener listener) { /** * ActionListener interface. - * + * * @param e ActionEvent */ + @Override public void actionPerformed(java.awt.event.ActionEvent e) { String command = e.getActionCommand(); - if (command.equals(zoomInCmd)) { + if (command.equals(ZOOM_IN_CMD)) { zoomDelegate.fireZoom(ZoomEvent.RELATIVE, zoomInFactor); - } else if (command.equals(zoomOutCmd)) { + } else if (command.equals(ZOOM_OUT_CMD)) { zoomDelegate.fireZoom(ZoomEvent.RELATIVE, zoomOutFactor); } } + @Override public void setOpaque(boolean set) { super.setOpaque(set); if (zoomInButton != null) { @@ -233,16 +230,17 @@ public void setOpaque(boolean set) { //// OMComponentPanel methods to make the tool work with //// the MapHandler to find objects it needs. /////////////////////////////////////////////////////////////////////////// - + @Override public void findAndInit(Object obj) { if (obj instanceof ZoomListener) { addZoomListener((ZoomListener) obj); } } + @Override public void findAndUndo(Object obj) { if (obj instanceof ZoomListener) { removeZoomListener((ZoomListener) obj); } } -} \ No newline at end of file +} diff --git a/src/core/src/main/java/com/bbn/openmap/layer/ScaleDisplayLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/ScaleDisplayLayer.java index 82226649b..6c8e7df8f 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/ScaleDisplayLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/ScaleDisplayLayer.java @@ -18,7 +18,6 @@ * * ********************************************************************** */ - package com.bbn.openmap.layer; import java.awt.BasicStroke; @@ -39,19 +38,23 @@ import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.OMLine; import com.bbn.openmap.omGraphics.OMText; +import com.bbn.openmap.proj.GreatCircle; import com.bbn.openmap.proj.Length; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; +import com.bbn.openmap.util.MoreMath; import com.bbn.openmap.util.PropUtils; +import java.awt.geom.Point2D; +import java.util.logging.Level; /** * The ScaleDisplayLayer draws a scale indicator in the corner of the map, * showing a line and displaying its length. You can set the location of the * indicator, the colors, and the units being shown. *

- * + * *

- * 
+ *
  * ### Layer used by the overview handler
  * scaleLayer.class=com.bbn.openmap.layer.ScaleDisplayLayer
  * scaleLayer.prettyName=Scale
@@ -62,7 +65,7 @@
  * scaleLayer.locationYoffset=-20
  * scaleLayer.width=150
  * scaleLayer.height=10
- * 
+ *
  * # unitOfMeasure - any com.bbn.openmap.proj.Length instance returned by Length.get(string).
  * # locationXoffset - offset in pixels from left/right, positive from left edge, negative from right edge
  * # locationYoffset - offset in pixels from top/bottom, positive from top edge, negative from bottom edge
@@ -73,273 +76,379 @@
  */
 public class ScaleDisplayLayer extends OMGraphicHandlerLayer {
 
-	public ScaleDisplayLayer() {
-		super();
-		setProjectionChangePolicy(new com.bbn.openmap.layer.policy.ListResetPCPolicy(this));
-		setUnitOfMeasure(Length.KM.toString());
-	}
-
-	protected Logger logger = Logger.getLogger("com.bbn.openmap.layer.ScaleDisplayLayer");
-
-	// Color variables for different line types
-	protected java.awt.Color lineColor = null;
-	protected java.awt.Color textColor = null;
-
-	// Default colors to use, if not specified in the properties.
-	protected String defaultLineColorString = "FFFFFF";
-	protected String defaultTextColorString = "FFFFFF";
-	protected String defaultUnitOfMeasureString = "km";
-	protected int defaultLocationXoffset = -10;
-	protected int defaultLocationYoffset = -10;
-	protected int defaultWidth = 150;
-	protected int defaultHeight = 10;
-
-	// property text values
-	public static final String UnitOfMeasureProperty = "unitOfMeasure";
-	public static final String LocationXOffsetProperty = "locationXoffset";
-	public static final String LocationYOffsetProperty = "locationYoffset";
-	public static final String WidthProperty = "width";
-	public static final String HeightProperty = "height";
-
-	protected String unitOfMeasure = null;
-	protected Length uom = Length.get(defaultUnitOfMeasureString);
-	protected String uomAbbr = uom.getAbbr();
-	protected int locationXoffset = defaultLocationXoffset;
-	protected int locationYoffset = defaultLocationYoffset;
-	protected int width = defaultWidth;
-	protected int height = defaultHeight;
-
-	protected DrawingAttributes dAttributes = DrawingAttributes.getDefaultClone();
-
-	/**
-	 * Sets the properties for the Layer. This allows
-	 * Layer s to get a richer set of parameters than the
-	 * setArgs method.
-	 * 
-	 * @param prefix the token to prefix the property names
-	 * @param properties the Properties object
-	 */
-	public void setProperties(String prefix, Properties properties) {
-		super.setProperties(prefix, properties);
-		prefix = PropUtils.getScopedPropertyPrefix(prefix);
-
-		dAttributes.setProperties(prefix, properties);
-
-		String unitOfMeasureString = properties.getProperty(prefix + UnitOfMeasureProperty);
-		if (unitOfMeasureString != null) {
-			setUnitOfMeasure(unitOfMeasureString);
-		}
-
-		locationXoffset = PropUtils.intFromProperties(properties, prefix + LocationXOffsetProperty,
-				defaultLocationXoffset);
-
-		locationYoffset = PropUtils.intFromProperties(properties, prefix + LocationYOffsetProperty,
-				defaultLocationYoffset);
-
-		width = PropUtils.intFromProperties(properties, prefix + WidthProperty, defaultWidth);
-
-		height = PropUtils.intFromProperties(properties, prefix + HeightProperty, defaultHeight);
-	}
-
-	public Properties getProperties(Properties props) {
-		props = super.getProperties(props);
-		String prefix = PropUtils.getScopedPropertyPrefix(this);
-
-		dAttributes.setProperties(props);
-
-		props.put(prefix + LocationXOffsetProperty, Integer.toString(locationXoffset));
-		props.put(prefix + LocationYOffsetProperty, Integer.toString(locationYoffset));
-		props.put(prefix + WidthProperty, Integer.toString(width));
-		props.put(prefix + HeightProperty, Integer.toString(height));
-
-		props.put(prefix + UnitOfMeasureProperty, unitOfMeasure);
-
-		return props;
-	}
-
-	public synchronized OMGraphicList prepare() {
-		int w, h, left_x = 0, right_x = 0, lower_y = 0, upper_y = 0;
-		Projection projection = getProjection();
-		OMGraphicList graphics = new OMGraphicList();
-
-		w = projection.getWidth();
-		h = projection.getHeight();
-		if (locationXoffset < 0) {
-			left_x = w + locationXoffset - width;
-			right_x = w + locationXoffset;
-		} else if (locationXoffset >= 0) {
-			left_x = locationXoffset;
-			right_x = locationXoffset + width;
-		}
-		if (locationYoffset < 0) {
-			upper_y = h + locationYoffset - height;
-			lower_y = h + locationYoffset;
-		} else if (locationYoffset >= 0) {
-			upper_y = locationYoffset;
-			lower_y = locationYoffset + height;
-		}
-
-		graphics.clear();
-
-		OMLine line = new OMLine(left_x, lower_y, right_x, lower_y);
-		dAttributes.setTo(line);
-		graphics.add(line);
-
-		line = new OMLine(left_x, lower_y, left_x, upper_y);
-		dAttributes.setTo(line);
-		graphics.add(line);
-
-		line = new OMLine(right_x, lower_y, right_x, upper_y);
-		dAttributes.setTo(line);
-		graphics.add(line);
-
-		/*
-		 * We need to use better coordinates to measure distance, like the same
-		 * pixel distance at the center of the map. There's a problem using the
-		 * lower right location, in that those distances decrease as you zoom
-		 * out.
-		 */
-
-		int y = h / 2;
-		int x = w / 2;
-		int xSide = (right_x - left_x) / 2;
-
-		LatLonPoint loc1 = projection.inverse(x - xSide, y, new LatLonPoint.Double());
-		LatLonPoint loc2 = projection.inverse(x + xSide, y, new LatLonPoint.Double());
-
-		double dist = uom.fromRadians(loc1.distance(loc2));
-
-		String outtext;
-		if (dist < 1.0f) {
-			outtext = String.format("%.3f %s", dist, uomAbbr);
-		} else if (dist < 10.0f) {
-			outtext = String.format("%.2f %s", dist, uomAbbr);
-		} else if (dist < 100.0f) {
-			outtext = String.format("%.1f %s", dist, uomAbbr);
-		} else {
-			outtext = String.format("%.0f %s", dist, uomAbbr);
-		}
-
-		/*
-		 * OMText text = new OMText((left_x + right_x) / 2, lower_y - 3, "" +
-		 * outtext, OMText.JUSTIFY_CENTER); Font font = text.getFont();
-		 * text.setFont(font.deriveFont(font.BOLD, font.getSize() + 4));
-		 * dAttributes.setTo(text); text.setTextMatteColor((Color)
-		 * dAttributes.getMattingPaint()); text.setTextMatteStroke(new
-		 * BasicStroke(5)); text.setMattingPaint(OMColor.clear);
-		 * graphics.add(text); graphics.generate(projection);
-		 */
-
-		OMText text = new OMText(right_x, lower_y - 20, "" + outtext, OMText.JUSTIFY_RIGHT);
-
-		Font font = text.getFont();
-		text.setFont(font.deriveFont(Font.BOLD, font.getSize() + 4));
-
-		dAttributes.setTo(text);
-		text.setTextMatteColor((Color) dAttributes.getMattingPaint());
-		text.setTextMatteStroke(new BasicStroke(5));
-		text.setMattingPaint(OMColor.clear);
-		graphics.add(text);
-		graphics.generate(projection);
-
-		return graphics;
-	}
-
-	/**
-	 * Getter for property unitOfMeasure.
-	 * 
-	 * @return Value of property unitOfMeasure.
-	 */
-	public String getUnitOfMeasure() {
-		return this.unitOfMeasure;
-	}
-
-	/**
-	 * Setter for property unitOfMeasure.
-	 * 
-	 * @param unitOfMeasure New value of property unitOfMeasure.
-	 */
-	public void setUnitOfMeasure(String unitOfMeasure) {
-		if (unitOfMeasure == null)
-			unitOfMeasure = Length.KM.toString();
-		this.unitOfMeasure = unitOfMeasure;
-
-		// There is a bug in the Length.get() method that will not
-		// return
-		// the correct (or any value) for a requested uom.
-		// This does not work:
-		// uom = com.bbn.openmap.proj.Length.get(unitOfMeasure);
-
-		// Therefore, The following code correctly obtains the proper
-		// Length object.
-
-		Length[] choices = Length.values();
-		uom = null;
-		for (int i = 0; i < choices.length; i++) {
-			if (unitOfMeasure.equalsIgnoreCase(choices[i].toString())
-					|| unitOfMeasure.equalsIgnoreCase(choices[i].getAbbr())) {
-				uom = choices[i];
-				break;
-			}
-		}
-
-		// of no uom is found assign Kilometers as the default.
-		if (uom == null)
-			uom = Length.KM;
-
-		uomAbbr = uom.getAbbr();
-
-	}
-
-	JPanel palettePanel;
-	ButtonGroup uomButtonGroup;
-	Vector buttons = new Vector();
-
-	/**
-	 * Creates the interface palette.
-	 */
-	public java.awt.Component getGUI() {
-
-		if (palettePanel == null) {
-
-			logger.fine("creating palette.");
-
-			palettePanel = new JPanel();
-			uomButtonGroup = new ButtonGroup();
-
-			palettePanel.setLayout(new javax.swing.BoxLayout(palettePanel, javax.swing.BoxLayout.Y_AXIS));
-			palettePanel.setBorder(new javax.swing.border.TitledBorder("Unit Of Measure"));
-
-			java.awt.event.ActionListener al = new ActionListener() {
-				// We don't have to check for action commands or anything like
-				// that.
-				// We know this listener is going to be added to JRadioButtons
-				// that are labeled with abbreviations for length.
-				public void actionPerformed(ActionEvent e) {
-					JRadioButton jrb = (JRadioButton) e.getSource();
-					setUnitOfMeasure(jrb.getText());
-				}
-			};
-
-			for (Length lengthType : Length.values()) {
-				JRadioButton jrb = new JRadioButton();
-				jrb.setText(lengthType.getAbbr());
-				jrb.setToolTipText(lengthType.toString());
-				uomButtonGroup.add(jrb);
-				palettePanel.add(jrb);
-
-				jrb.addActionListener(al);
-
-				jrb.setSelected(unitOfMeasure.equalsIgnoreCase(lengthType.getAbbr()));
-				buttons.add(jrb);
-			}
-
-		} else {
-			for (JRadioButton button : buttons) {
-				button.setSelected(uom.getAbbr().equalsIgnoreCase(button.getText()));
-			}
-		}
-
-		return palettePanel;
-	}
+    public ScaleDisplayLayer() {
+        super();
+        setProjectionChangePolicy(new com.bbn.openmap.layer.policy.ListResetPCPolicy(this));
+        setUnitOfMeasure(Length.KM.toString());
+    }
+
+    protected Logger logger = Logger.getLogger("com.bbn.openmap.layer.ScaleDisplayLayer");
+
+    // Color variables for different line types
+    protected java.awt.Color lineColor = null;
+    protected java.awt.Color textColor = null;
+
+    // Default colors to use, if not specified in the properties.
+    protected String defaultLineColorString = "FFFFFF";
+    protected String defaultTextColorString = "FFFFFF";
+    protected String defaultUnitOfMeasureString = "km";
+    protected int defaultLocationXoffset = -10;
+    protected int defaultLocationYoffset = -10;
+    protected int defaultWidth = 150;
+    protected int defaultHeight = 10;
+
+    // property text values
+    public static final String UnitOfMeasureProperty = "unitOfMeasure";
+    public static final String LocationXOffsetProperty = "locationXoffset";
+    public static final String LocationYOffsetProperty = "locationYoffset";
+    public static final String WidthProperty = "width";
+    public static final String HeightProperty = "height";
+
+    protected String unitOfMeasure = null;
+    protected Length uom = Length.get(defaultUnitOfMeasureString);
+    protected String uomAbbr = uom.getAbbr();
+    protected int locationXoffset = defaultLocationXoffset;
+    protected int locationYoffset = defaultLocationYoffset;
+    protected int width = defaultWidth;
+    protected int height = defaultHeight;
+    public static final float RADIANS_270 = Length.DECIMAL_DEGREE.toRadians(270);
+    protected DrawingAttributes dAttributes = DrawingAttributes.getDefaultClone();
+
+    /**
+     * Sets the properties for the Layer. This allows
+     * Layer s to get a richer set of parameters than the
+     * setArgs method.
+     *
+     * @param prefix the token to prefix the property names
+     * @param properties the Properties object
+     */
+    public void setProperties(String prefix, Properties properties) {
+        super.setProperties(prefix, properties);
+        prefix = PropUtils.getScopedPropertyPrefix(prefix);
+
+        dAttributes.setProperties(prefix, properties);
+
+        String unitOfMeasureString = properties.getProperty(prefix + UnitOfMeasureProperty);
+        if (unitOfMeasureString != null) {
+            setUnitOfMeasure(unitOfMeasureString);
+        }
+
+        locationXoffset = PropUtils.intFromProperties(properties, prefix + LocationXOffsetProperty,
+                defaultLocationXoffset);
+
+        locationYoffset = PropUtils.intFromProperties(properties, prefix + LocationYOffsetProperty,
+                defaultLocationYoffset);
+
+        width = PropUtils.intFromProperties(properties, prefix + WidthProperty, defaultWidth);
+
+        height = PropUtils.intFromProperties(properties, prefix + HeightProperty, defaultHeight);
+    }
+
+    public Properties getProperties(Properties props) {
+        props = super.getProperties(props);
+        String prefix = PropUtils.getScopedPropertyPrefix(this);
+
+        dAttributes.setProperties(props);
+
+        props.put(prefix + LocationXOffsetProperty, Integer.toString(locationXoffset));
+        props.put(prefix + LocationYOffsetProperty, Integer.toString(locationYoffset));
+        props.put(prefix + WidthProperty, Integer.toString(width));
+        props.put(prefix + HeightProperty, Integer.toString(height));
+
+        props.put(prefix + UnitOfMeasureProperty, unitOfMeasure);
+
+        return props;
+    }
+
+    /**
+     * prepare the graphics for the layer
+     *
+     * @return
+     */
+    @Override
+    public synchronized OMGraphicList prepare() {
+        int w, h, left_x = 0, right_x = 0, lower_y = 0, upper_y = 0;
+        Projection projection = getProjection();
+        OMGraphicList graphics = new OMGraphicList();
+
+        w = projection.getWidth();
+        h = projection.getHeight();
+        // FIXME: Use the center since it's always real
+
+        /**
+         * Since the pixel space for the component has nothing to do with the
+         * pixel space of the projection, we'll just use the projection pixel
+         * space to find out how long the line should be. Then, we'll move that
+         * length into component pixel space.
+         */
+        lower_y = h / 2;
+        right_x = w / 2;
+        left_x = right_x - width;
+
+        LatLonPoint loc1 = projection.inverse(left_x, lower_y, new LatLonPoint.Double());
+        LatLonPoint loc2 = projection.inverse(right_x, lower_y, new LatLonPoint.Double());
+
+        double dist = GreatCircle.sphericalDistance(loc1.getRadLat(), loc1.getRadLon(), loc2.getRadLat(), loc2.getRadLon());
+
+        // Round the distance to one of the preferred values.
+        dist = uom.fromRadians(dist);
+        double new_dist = scopeDistance(dist);
+
+        if (logger.isLoggable(Level.FINE)) {
+            logger.log(Level.FINE, "modifying {0} to new distance: {1}", new Object[]{dist, new_dist});
+        }
+
+        left_x = getPtAtDistanceFromLatLon(loc2, new_dist, projection, uom);
+
+        int lineLength = right_x - left_x;
+
+        // If the length of the distance line is longer than the width of the
+        // panel, divide it in half.
+        int maxWidth = Math.max(getWidth() / 4 - Math.abs(locationXoffset) * 2, 50);
+        while (lineLength > maxWidth) {
+
+            lineLength /= 3;
+            new_dist /= 3.0;
+
+            if (logger.isLoggable(Level.FINE)) {
+                logger.log(Level.FINE, "length of line too long, halving to [0]", lineLength);
+            }
+            double testDist = scopeDistance(new_dist);
+            if (!MoreMath.approximately_equal(testDist, new_dist) && !(new_dist <= .01)) {
+                lineLength = right_x - getPtAtDistanceFromLatLon(loc2, testDist, projection, uom);
+                if (logger.isLoggable(Level.FINE)) {
+                    logger.log(Level.FINE, "needed to rescope distance to {0} from {1}", new Object[]{testDist, new_dist});
+                }
+                new_dist = testDist;
+            }
+
+        }
+
+        // Now, check the units and try to avoid fractions
+        Length cur_uom = uom;
+
+        if (new_dist < 1) {
+            if (uom.equals(Length.KM)) {
+                new_dist *= 1000;
+                cur_uom = Length.METER;
+            } else if (uom.equals(Length.MILE) || uom.equals(Length.DM) || uom.equals(Length.NM)) {
+                new_dist = Length.FEET.fromRadians(uom.toRadians(new_dist));
+                cur_uom = Length.FEET;
+            }
+
+            if (logger.isLoggable(Level.FINE)) {
+                logger.log(Level.FINE, "modified UOM to {0}, value: {1}", new Object[]{cur_uom.getAbbr(), new_dist});
+            }
+
+            double testDist = scopeDistance(new_dist);
+            if (!MoreMath.approximately_equal(testDist, new_dist)) {
+                lineLength = right_x
+                        - getPtAtDistanceFromLatLon(loc2, testDist, projection, cur_uom);
+                if (logger.isLoggable(Level.FINE)) {
+                    logger.log(Level.FINE, "needed to rescope distance to {0} from {1}", new Object[]{testDist, new_dist});
+                }
+                new_dist = testDist;
+            }
+        }
+
+        /**
+         * Now, figure out where OMGraphics go in the component space.
+         */
+        if (locationXoffset < 0) {
+            int cw = getWidth();
+            left_x = cw + locationXoffset - lineLength;
+            right_x = cw + locationXoffset;
+        } else if (locationXoffset >= 0) {
+            left_x = locationXoffset;
+            right_x = locationXoffset + lineLength;
+        }
+        if (locationYoffset < 0) {
+            int ch = getHeight();
+            upper_y = ch + locationYoffset - height;
+            lower_y = ch + locationYoffset;
+        } else if (locationYoffset >= 0) {
+            upper_y = locationYoffset;
+            lower_y = locationYoffset + height;
+        }
+
+        // Draw the lines and the rounded distance string.
+        OMLine line = new OMLine(left_x, lower_y, right_x, lower_y);
+        dAttributes.setTo(line);
+        graphics.add(line);
+
+        line = new OMLine(left_x, lower_y, left_x, upper_y);
+        dAttributes.setTo(line);
+        graphics.add(line);
+
+        line = new OMLine(right_x, lower_y, right_x, upper_y);
+        dAttributes.setTo(line);
+        graphics.add(line);
+
+        String outtext = String.format("%.0f %s", new_dist, cur_uom.getAbbr());
+
+        OMText text = new OMText((left_x + right_x) / 2, lower_y - 3, "" + outtext, OMText.JUSTIFY_CENTER);
+
+        Font font = text.getFont();
+        text.setFont(font.deriveFont(font.getStyle(), font.getSize() + 2));
+
+        dAttributes.setTo(text);
+        text.setTextMatteColor((Color) dAttributes.getMattingPaint());
+        text.setTextMatteStroke(new BasicStroke(5));
+        text.setMattingPaint(OMColor.clear);
+        graphics.add(text);
+        graphics.generate(projection);
+
+        return graphics;
+    }
+
+    protected int getPtAtDistanceFromLatLon(LatLonPoint loc2, double unitDist,
+            Projection projection, Length uom) {
+        double lineWidthInRadians = uom.toRadians(unitDist);
+        LatLonPoint newX = GreatCircle.sphericalBetween(loc2.getRadLat(), loc2.getRadLon(), lineWidthInRadians, RADIANS_270);
+        Point2D newLoc1 = projection.forward(newX);
+        return (int) Math.round(newLoc1.getX());
+    }
+
+    /**
+     * Take a given distance and round it down to the nearest 1, 2, or 5 (or
+     * tens/hundreds version of those increments) multiple of that number.
+     *
+     * @param dist
+     * @return scoped value of distance, incremented properly
+     */
+    protected double scopeDistance(double dist) {
+        double new_dist;
+        if (dist <= .01) {
+            new_dist = .01;
+        } else if (dist <= .02) {
+            new_dist = .02;
+        } else if (dist <= .05) {
+            new_dist = .05;
+        } else if (dist <= .1) {
+            new_dist = .1;
+        } else if (dist <= .2) {
+            new_dist = .2;
+        } else if (dist <= .5) {
+            new_dist = .5;
+        } else if (dist <= 1) {
+            new_dist = 1;
+        } else if (dist <= 2) {
+            new_dist = 2;
+        } else if (dist <= 5) {
+            new_dist = 5;
+        } else if (dist <= 10) {
+            new_dist = 10;
+        } else if (dist <= 20) {
+            new_dist = 20;
+        } else if (dist <= 50) {
+            new_dist = 50;
+        } else if (dist <= 100) {
+            new_dist = 100;
+        } else if (dist <= 200) {
+            new_dist = 200;
+        } else if (dist <= 500) {
+            new_dist = 500;
+        } else {
+            new_dist = 1000;
+        }
+        return new_dist;
+    }
+
+    /**
+     * Getter for property unitOfMeasure.
+     *
+     * @return Value of property unitOfMeasure.
+     */
+    public String getUnitOfMeasure() {
+        return this.unitOfMeasure;
+    }
+
+    /**
+     * Setter for property unitOfMeasure.
+     *
+     * @param unitOfMeasure New value of property unitOfMeasure.
+     */
+    public void setUnitOfMeasure(String unitOfMeasure) {
+        if (unitOfMeasure == null) {
+            unitOfMeasure = Length.KM.toString();
+        }
+        this.unitOfMeasure = unitOfMeasure;
+
+        // There is a bug in the Length.get() method that will not
+        // return
+        // the correct (or any value) for a requested uom.
+        // This does not work:
+        // uom = com.bbn.openmap.proj.Length.get(unitOfMeasure);
+        // Therefore, The following code correctly obtains the proper
+        // Length object.
+        Length[] choices = Length.values();
+        uom = null;
+        for (int i = 0; i < choices.length; i++) {
+            if (unitOfMeasure.equalsIgnoreCase(choices[i].toString())
+                    || unitOfMeasure.equalsIgnoreCase(choices[i].getAbbr())) {
+                uom = choices[i];
+                break;
+            }
+        }
+
+        // of no uom is found assign Kilometers as the default.
+        if (uom == null) {
+            uom = Length.KM;
+        }
+
+        uomAbbr = uom.getAbbr();
+
+    }
+
+    JPanel palettePanel;
+    ButtonGroup uomButtonGroup;
+    Vector buttons = new Vector();
+
+    /**
+     * Creates the interface palette.
+     */
+    public java.awt.Component getGUI() {
+
+        if (palettePanel == null) {
+
+            logger.fine("creating palette.");
+
+            palettePanel = new JPanel();
+            uomButtonGroup = new ButtonGroup();
+
+            palettePanel.setLayout(new javax.swing.BoxLayout(palettePanel, javax.swing.BoxLayout.Y_AXIS));
+            palettePanel.setBorder(new javax.swing.border.TitledBorder("Unit Of Measure"));
+
+            java.awt.event.ActionListener al = new ActionListener() {
+                // We don't have to check for action commands or anything like
+                // that.
+                // We know this listener is going to be added to JRadioButtons
+                // that are labeled with abbreviations for length.
+                public void actionPerformed(ActionEvent e) {
+                    JRadioButton jrb = (JRadioButton) e.getSource();
+                    setUnitOfMeasure(jrb.getText());
+                }
+            };
+
+            for (Length lengthType : Length.values()) {
+                JRadioButton jrb = new JRadioButton();
+                jrb.setText(lengthType.getAbbr());
+                jrb.setToolTipText(lengthType.toString());
+                uomButtonGroup.add(jrb);
+                palettePanel.add(jrb);
+
+                jrb.addActionListener(al);
+
+                jrb.setSelected(unitOfMeasure.equalsIgnoreCase(lengthType.getAbbr()));
+                buttons.add(jrb);
+            }
+
+        } else {
+            for (JRadioButton button : buttons) {
+                button.setSelected(uom.getAbbr().equalsIgnoreCase(button.getText()));
+            }
+        }
+
+        return palettePanel;
+    }
 }
diff --git a/src/core/src/main/java/com/bbn/openmap/layer/postgis/FeatureQuery.java b/src/core/src/main/java/com/bbn/openmap/layer/postgis/FeatureQuery.java
index 43df058d9..ef301c329 100644
--- a/src/core/src/main/java/com/bbn/openmap/layer/postgis/FeatureQuery.java
+++ b/src/core/src/main/java/com/bbn/openmap/layer/postgis/FeatureQuery.java
@@ -12,11 +12,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
-import org.postgis.PGgeometry;
-
 import com.bbn.openmap.omGraphics.DrawingAttributes;
 import com.bbn.openmap.omGraphics.OMGraphicList;
+import net.postgis.jdbc.PGgeometry;
 
 /**
  * The object that builds a query for a particular feature type, and also
diff --git a/src/core/src/main/java/com/bbn/openmap/layer/postgis/PostGISOMGraphicFactory.java b/src/core/src/main/java/com/bbn/openmap/layer/postgis/PostGISOMGraphicFactory.java
index 6393ce58f..8de0a7133 100644
--- a/src/core/src/main/java/com/bbn/openmap/layer/postgis/PostGISOMGraphicFactory.java
+++ b/src/core/src/main/java/com/bbn/openmap/layer/postgis/PostGISOMGraphicFactory.java
@@ -5,21 +5,20 @@
  */
 package com.bbn.openmap.layer.postgis;
 
-import org.postgis.Geometry;
-import org.postgis.GeometryCollection;
-import org.postgis.LineString;
-import org.postgis.MultiLineString;
-import org.postgis.MultiPoint;
-import org.postgis.MultiPolygon;
-import org.postgis.Point;
-import org.postgis.Polygon;
-
 import com.bbn.openmap.omGraphics.DrawingAttributes;
 import com.bbn.openmap.omGraphics.OMGraphic;
 import com.bbn.openmap.omGraphics.OMGraphicList;
 import com.bbn.openmap.omGraphics.OMPoint;
 import com.bbn.openmap.omGraphics.OMPoly;
 import com.bbn.openmap.proj.Projection;
+import net.postgis.jdbc.geometry.Geometry;
+import net.postgis.jdbc.geometry.GeometryCollection;
+import net.postgis.jdbc.geometry.LineString;
+import net.postgis.jdbc.geometry.MultiLineString;
+import net.postgis.jdbc.geometry.MultiPoint;
+import net.postgis.jdbc.geometry.MultiPolygon;
+import net.postgis.jdbc.geometry.Point;
+import net.postgis.jdbc.geometry.Polygon;
 
 /**
  * Creates OMGraphics from PostGIS/PostGRES geometries. If you pass in a
diff --git a/src/core/src/main/java/com/bbn/openmap/omGraphics/OMGraphicList.java b/src/core/src/main/java/com/bbn/openmap/omGraphics/OMGraphicList.java
index 0c8243fad..d9dfef10c 100644
--- a/src/core/src/main/java/com/bbn/openmap/omGraphics/OMGraphicList.java
+++ b/src/core/src/main/java/com/bbn/openmap/omGraphics/OMGraphicList.java
@@ -78,7 +78,7 @@ public OMGraphicList() {
      * @param initialCapacity the initial capacity of the list
      */
     public OMGraphicList(int initialCapacity) {
-        graphics = Collections.synchronizedList(new ArrayList(initialCapacity));
+        super(initialCapacity);
     }
 
     /**
@@ -293,12 +293,6 @@ public void setGridGenerator(OMGridGenerator generator,
      * @return a reference of the graphics List.
      */
     public List getTargets() {
-        if (graphics == null) {
-            // make sure that the graphics vector is not null,
-            // since all of the internal methods rely on it.
-            graphics = Collections.synchronizedList(new ArrayList(10));
-        }
-
         return graphics;
     }
 
@@ -306,9 +300,14 @@ public List getTargets() {
      * Set the List used to hold the OMGraphics. The OMGraphicList assumes that
      * this list contains OMGraphics. Make *SURE* this is the case. The
      * OMGraphicList will behave badly if there are non-OMGraphics on the list.
+     * 
+     * @param list the list of OMGraphics to replace all current OMGraphics.
      */
     public void setTargets(List list) {
-        graphics = Collections.synchronizedList(new ArrayList(list));
+        graphics.clear();
+        if (list != null) {
+            graphics.addAll(list);
+        }
     }
 
     /**
diff --git a/src/core/src/main/java/com/bbn/openmap/omGraphics/OMList.java b/src/core/src/main/java/com/bbn/openmap/omGraphics/OMList.java
index a7ed5c545..802693e57 100644
--- a/src/core/src/main/java/com/bbn/openmap/omGraphics/OMList.java
+++ b/src/core/src/main/java/com/bbn/openmap/omGraphics/OMList.java
@@ -53,6 +53,8 @@
  * whether the first or last object added to the list (FIRST_ADDED_ON_TOP or
  * LAST_ADDED_ON_TOP) is drawn on top of the list and considered first for
  * searches.
+ * 
+ * @param  extends OMGeometry
  */
 public abstract class OMList extends OMGraphicAdapter implements List,
         OMGraphic {
@@ -109,7 +111,7 @@ public abstract class OMList extends OMGraphicAdapter impl
     /**
      * The List that actually contains the the OMGeometry/OMGraphic objects.
      */
-    protected List graphics;
+    protected final List graphics;
 
     /**
      * Construct an OMGraphicList.
@@ -1298,7 +1300,7 @@ public void doAction(T graphic, OMAction action) {
 
         if (action.isMask(LOWER_TO_BOTTOM_GRAPHIC_MASK)) {
             Debug.message("omgl", "OMGraphicList.doAction: lowering graphic to bottom");
-            moveIndexedOneToBottom(i);
+            moveIndexedToBottom(i); // -> Corrected by Jose M. Torres
         }
 
         if (action.isMask(DESELECTALL_GRAPHIC_MASK)) {
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java
similarity index 99%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java
index 44ac412a7..cc794123c 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java
@@ -1,6 +1,6 @@
 /* 
  */
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import java.awt.image.BufferedImage;
 import java.io.IOException;
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
similarity index 93%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
index 52bb0a8d1..a741befb0 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
@@ -1,4 +1,4 @@
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import java.io.File;
 import java.io.IOException;
@@ -16,12 +16,13 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 
 import com.bbn.openmap.util.ComponentFactory;
 import com.bbn.openmap.util.PropUtils;
@@ -74,6 +75,7 @@ public MapTileServlet() {
 
     /**
      * Called when the servlet is loaded.
+     * 
      */
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
@@ -84,16 +86,16 @@ public void init(ServletConfig config) throws ServletException {
         if (leafletCss != null) {
         	leafletCssLocation = leafletCss;
         }
-        logger.info("leaflet.css located at :" + leafletCssLocation);
+        logger.log(Level.INFO, "leaflet.css located at: {0}", leafletCssLocation);
         
         String leafletJs = context.getInitParameter(LEAFLET_JS_LOCATION_ATTRIBUTE);
         if (leafletJs != null) {
         	leafletJsLocation = leafletJs;
         }
-        logger.info("leaflet.js located at :" + leafletJsLocation);        
+        logger.log(Level.INFO, "leaflet.js located at: {0}", leafletJsLocation);        
         
         String descriptions = context.getInitParameter(TILE_SET_DESCRIPTION_ATTRIBUTE);
-        logger.info("Looking for Tile Set Descriptions at: " + descriptions);
+        logger.log(Level.INFO, "Looking for Tile Set Descriptions at: {0}", descriptions);
         if (descriptions != null) {
 
             // Changing descriptions to a folder containing properties files
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java
similarity index 93%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java
index 4e0a9affa..8457c6cd6 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java
@@ -1,4 +1,4 @@
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import com.bbn.openmap.PropertyConsumer;
 import com.bbn.openmap.io.FormatException;
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java
similarity index 95%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java
index de116bb33..2f5037e0a 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java
@@ -1,4 +1,4 @@
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import com.bbn.openmap.dataAccess.mapTile.ServerMapTileFactory;
 import com.bbn.openmap.io.BinaryBufferedFile;
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java
similarity index 95%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java
index 17f1ceea9..203d10513 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java
@@ -1,4 +1,4 @@
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import com.bbn.openmap.dataAccess.mapTile.StandardMapTileFactory;
 import com.bbn.openmap.image.PNGImageIOFormatter;
diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java
similarity index 98%
rename from src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java
index 944814e48..e2592e9a9 100644
--- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java
@@ -3,7 +3,7 @@
  *  Copyright 2012 BBN Technologies
  * 
  */
-package com.bbn.openmap.maptileservlet;
+package com.bbn.openmap.servlet.mapTile;
 
 import java.awt.geom.Point2D;
 import java.awt.image.BufferedImage;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java
index d0dae1cf7..d0c497f20 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ApplyIterator.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.util.Iterator;
 
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java
similarity index 94%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java
index de4ef1643..21b294699 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/Applyable.java,v $
 // $Revision: 1.2 $ $Date: 2004/10/14 18:06:32 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 /**
  * Applyable interface for use with ApplyIterator.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java
index f518758cc..f2cec06f9 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java
index 9635478a3..b94fcbaa5 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
index 76707b106..9b6745afc 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
@@ -11,9 +11,10 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ContextInfo.java,v $
 // $Revision: 1.8 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import com.bbn.openmap.layer.vpf.LibrarySelectionTable;
+import jakarta.servlet.ServletContext;
 import java.io.File;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -21,7 +22,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import javax.servlet.ServletContext;
+
 
 /**
  * This class holds information retrieved from the ServletContext.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
index cb497d620..ffc1926c3 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/Data.java,v $
 // $Revision: 1.6 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -20,11 +20,6 @@
 import java.util.ListIterator;
 import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.Constants;
 import com.bbn.openmap.layer.vpf.DcwColumnInfo;
@@ -34,6 +29,9 @@
 import com.bbn.openmap.util.html.TableHeaderElement;
 import com.bbn.openmap.util.html.TableRowElement;
 import com.bbn.openmap.util.html.WrapElement;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A servlet class that will output table data.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
index 495b3f137..4fcda142f 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/DescribeDBServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.io.IOException;
@@ -23,11 +23,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.CoverageAttributeTable;
 import com.bbn.openmap.layer.vpf.CoverageTable;
@@ -38,6 +33,9 @@
 import com.bbn.openmap.util.html.ListBodyElement;
 import com.bbn.openmap.util.html.ListElement;
 import com.bbn.openmap.util.html.WrapElement;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This class prints out a description of a VPF database, listing the available
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java
similarity index 99%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java
index 2944a67b5..a7cb9cd75 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/DetailRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
similarity index 94%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
index c719e823d..7d5c12d1f 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/DirectoryServlet.java,v $
 // $Revision: 1.5 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.io.IOException;
@@ -19,13 +19,11 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.util.html.HtmlListElement;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This servlet lists the files in a directory of a configured VPF database.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
similarity index 95%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
index 293e2d8d0..b422ec5cf 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
@@ -11,19 +11,17 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/DispatchServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This class infers the format of a VPF file from the name of the file, and
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
similarity index 93%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
index dca4f3c08..317c52b12 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
@@ -11,19 +11,17 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/DocFileServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This class handles displaying VPF .doc files
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
similarity index 96%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
index fe15bd797..c9c46c109 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
@@ -11,17 +11,15 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/FCSRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.layer.vpf.Constants;
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
 import com.bbn.openmap.util.html.TableRowElement;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A RowMaker class specifically for the markup of VPF feature class schema
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java
similarity index 99%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java
index 98c9af09e..8a4d3c036 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/FITRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
similarity index 83%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
index 1991fa7c5..5bbacf9e0 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
@@ -11,16 +11,15 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/HelloWWW.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 /**
  * Test class, not used
  */
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java
similarity index 98%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java
index f84fba926..9dc6b28cd 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/JoinRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
similarity index 95%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
index 7ceb6f2b5..3d81258ee 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
@@ -11,14 +11,13 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/LibraryBean.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.LibrarySelectionTable;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This class prints out a description of a VPF database, listing the
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java
index 38a90137a..f168fcecd 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/PlainRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.util.Iterator;
 import java.util.List;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
similarity index 91%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
index 2e1703bb6..435ac3215 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
@@ -11,10 +11,10 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A RowMaker class that retains references to the HttpServletRequest
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java
similarity index 96%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java
index b4322b8d0..d24ec7053 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/RowMaker.java,v $
 // $Revision: 1.3 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.util.List;
 
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
similarity index 96%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
index 56065a281..1ce79e3b5 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
@@ -11,15 +11,10 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/Schema.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.IOException;
 import java.io.PrintWriter;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.layer.vpf.DcwColumnInfo;
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
 import com.bbn.openmap.util.html.HtmlListElement;
@@ -27,6 +22,9 @@
 import com.bbn.openmap.util.html.StringElement;
 import com.bbn.openmap.util.html.TableRowElement;
 import com.bbn.openmap.util.html.WrapElement;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A servlet class that will print the schema for a VPF table.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
index f0b402a1b..48e433eb8 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
@@ -11,24 +11,22 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.util.HashMap;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwSpatialIndex;
 import com.bbn.openmap.util.html.HtmlListElement;
 import com.bbn.openmap.util.html.ListElement;
 import com.bbn.openmap.util.html.TableHeaderElement;
 import com.bbn.openmap.util.html.TableRowElement;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This servlet generates HTML for VPF files in spatial index format.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
index ddfc10526..965a77bdd 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
@@ -11,17 +11,12 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwSpatialIndex;
 import com.bbn.openmap.util.html.HtmlListElement;
@@ -29,6 +24,9 @@
 import com.bbn.openmap.util.html.TableHeaderElement;
 import com.bbn.openmap.util.html.TableRowElement;
 import com.bbn.openmap.util.html.WrapElement;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This servlet generates HTML for VPF files in spatial index format.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java
index cfa70688f..848518e0d 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
similarity index 96%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
index e754c2dda..28aaf3299 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
@@ -11,17 +11,11 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwThematicIndex;
 import com.bbn.openmap.util.html.Element;
@@ -30,6 +24,10 @@
 import com.bbn.openmap.util.html.TableHeaderElement;
 import com.bbn.openmap.util.html.TableRowElement;
 import com.bbn.openmap.util.html.WrapElement;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * This servlet generates HTML for VPF files in thematic index format.
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java
similarity index 99%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java
index daf47519d..304de8921 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/TileHolder.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.File;
 import java.util.List;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java
similarity index 99%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java
index 3b1f25a96..27769dbc2 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/URLCheck.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
similarity index 92%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
index 0b68255f8..e18887c73 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
@@ -11,16 +11,14 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/VDTRowMaker.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import java.util.Iterator;
 import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
 import com.bbn.openmap.util.html.TableRowElement;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A RowMaker class for int.vdt and char.vdt tables. It generates a
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
similarity index 96%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
index cdf45d457..6763c08b3 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
@@ -11,16 +11,16 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/VPFHttpServlet.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:15 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import com.bbn.openmap.util.html.TableHeaderElement;
 import java.io.File;
 import java.io.IOException;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 /**
  * A base class useful for servlets that use the VPF tools context object. This class also defines some utility methods
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java
similarity index 97%
rename from src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java
index 9995029c3..5b6155d38 100644
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java
@@ -11,7 +11,7 @@
 // $Source: /cvs/distapps/openmap/src/vpfservlet/WEB-INF/src/com/bbn/openmap/vpfservlet/VPFTable.java,v $
 // $Revision: 1.4 $ $Date: 2005/08/11 20:39:16 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.vpfservlet;
+package com.bbn.openmap.servlet.vpfBrowse;
 
 import com.bbn.openmap.io.FormatException;
 import com.bbn.openmap.layer.vpf.DcwRecordFile;
diff --git a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
similarity index 95%
rename from src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
index 0ba8aa056..85347ead4 100644
--- a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
@@ -19,12 +19,12 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-package com.bbn.openmap.wmsservlet;
+package com.bbn.openmap.servlet.wms;
 
 import java.io.IOException;
 import java.io.OutputStream;
 
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
 
 import com.bbn.openmap.util.http.IHttpResponse;
 
diff --git a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
similarity index 95%
rename from src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java
rename to src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
index 8f4a10a71..74ed55733 100644
--- a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java
+++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
@@ -11,16 +11,16 @@
 // $Source: /cvs/distapps/openmap/src/wmsservlet/WEB-INF/src/com/bbn/openmap/wmsservlet/OgcWmsServlet.java,v $
 // $Revision: 1.5 $ $Date: 2008/09/19 14:20:14 $ $Author: dietrick $
 // **********************************************************************
-package com.bbn.openmap.wmsservlet;
+package com.bbn.openmap.servlet.wms;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.util.Properties;
 
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import com.bbn.openmap.PropertyHandler;
 import com.bbn.openmap.image.wms.WMSException;
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicAppIconPart.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicAppIconPart.java
index ed1d4b554..444b6bbf9 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicAppIconPart.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicAppIconPart.java
@@ -19,42 +19,52 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
- * A BasicAppIconPart is a BasicIconPart that can be interested in a
- * set of DrawingAttributes on the fly. Good for an icon part that may
- * change under certain system conditions, like something reflecting a
- * current color, or an application icon reflecting a color theme in
- * the application. The BasicAppIconPart may have a default
- * DrawingAttributes that describe how it should be drawn if other
- * DrawingAttributes aren't provided at rendertime.
+ * A BasicAppIconPart is a BasicIconPart that can be interested in a set of
+ * DrawingAttributes on the fly. Good for an icon part that may change under
+ * certain system conditions, like something reflecting a current color, or an
+ * application icon reflecting a color theme in the application. The
+ * BasicAppIconPart may have a default DrawingAttributes that describe how it
+ * should be drawn if other DrawingAttributes aren't provided at render time.
+ * Coordinates for IconParts are based on 0-100 height and width, and scaled
+ * during rendering to the pixel sizes.
  */
 public class BasicAppIconPart extends BasicIconPart implements IconPart, Cloneable {
 
+    /**
+     *
+     * @param shape java Shape to use for part, 0-100 range for height and
+     * width.
+     */
     public BasicAppIconPart(Shape shape) {
         super(shape);
     }
 
+    /**
+     *
+     * @param shape java Shape to use for part, 0-100 range for height and
+     * width.
+     * @param transform any modification to part, for rotation or skew
+     */
     public BasicAppIconPart(Shape shape, AffineTransform transform) {
         super(shape, transform);
     }
 
     /**
      * Get the DrawingAttributes that should be used for rendering.
-     * 
-     * @param da DrawingAttributes passed in that may affect rendering
-     *        choices. For the BasicAppIconPart, if this is not null,
-     *        it is returned. Otherwise, the internal version is
-     *        returned.
+     *
+     * @param da DrawingAttributes passed in that may affect rendering choices.
+     * For the BasicAppIconPart, if this is not null, it is returned. Otherwise,
+     * the internal version is returned.
      * @return DrawingAttribute for this part.
      */
+    @Override
     protected DrawingAttributes getAttributesForRendering(DrawingAttributes da) {
         if (da == null) {
             return getRenderingAttributes();
@@ -62,4 +72,4 @@ protected DrawingAttributes getAttributesForRendering(DrawingAttributes da) {
             return da;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicIconPart.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicIconPart.java
index 819a1c633..c7da8a612 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicIconPart.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/BasicIconPart.java
@@ -19,17 +19,15 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
  * The BasicIconPart is an implementation of the IconPart. In addition to the
  * geometry and DrawingAttributes adjustments that can be done on an IconPart,
@@ -39,214 +37,265 @@
  */
 public class BasicIconPart implements IconPart, Cloneable {
 
-	/**
-	 * AffineTransform to adjust geometry if needed.
-	 */
-	protected AffineTransform baseTransform;
-	/**
-	 * Shape geometry for this IconPart.
-	 */
-	protected Shape geometry;
-	/**
-	 * Shape clipping area for this IconPart.
-	 */
-	protected Shape clip;
-	/**
-	 * DrawingAttributes for this IconPart.
-	 */
-	protected DrawingAttributes renderingAttributes = null;
-	/**
-	 * Flag to modifying DrawingAttributes Colors into GradientPaints, for that 3D
-	 * lighting look.
-	 */
-	protected boolean gradient = false;
-
-	/**
-	 * Create a BasicIconPart with a java.awt.Shape object for a geometry.
-	 */
-	public BasicIconPart(Shape shape) {
-		this(shape, null, DrawingAttributes.DEFAULT);
-	}
-
-	/**
-	 * Create a BasicIconPart with a java.awt.Shape object for a geometry, along
-	 * with an AffineTransform that may be applied to the geometry at rendertime.
-	 */
-	public BasicIconPart(Shape shape, AffineTransform transform) {
-		this(shape, transform, DrawingAttributes.DEFAULT);
-	}
-
-	/**
-	 * Create a BasicIconPart with a java.awt.Shape object for a geometry.
-	 */
-	public BasicIconPart(Shape shape, DrawingAttributes da) {
-		this(shape, (AffineTransform) null, da);
-	}
-
-	/**
-	 * Create a BasicIconPart with a java.awt.Shape object for a geometry, along
-	 * with an AffineTransform that may be applied to the geometry at rendertime.
-	 */
-	public BasicIconPart(Shape shape, AffineTransform transform, DrawingAttributes da) {
-		geometry = shape;
-
-		if (transform == null) {
-			transform = new AffineTransform();
-		}
-
-		baseTransform = transform;
-		setRenderingAttributes(da);
-	}
-
-	/**
-	 * Get the DrawingAttributes that should be used for rendering.
-	 * 
-	 * @param da DrawingAttributes passed in that may affect rendering choices. Can
-	 *           be null, and the IconPart may decide to ignore it.
-	 * @return DrawingAttribute for this part.
-	 */
-	protected DrawingAttributes getAttributesForRendering(DrawingAttributes da) {
-		return getRenderingAttributes();
-	}
-
-	/**
-	 * @param g      a java.awt.Graphics object to render into.
-	 * @param width  pixel width of icon, used to scale geometry.
-	 * @param height pixel height of icon, used to scale geometry.
-	 */
-	public void render(Graphics g, int width, int height) {
-		render(g, width, height, null);
-	}
-
-	/**
-	 * @param g      a java.awt.Graphics object to render into.
-	 * @param width  pixel width of icon, used to scale geometry.
-	 * @param height pixel height of icon, used to scale geometry.
-	 * @param appDA  drawing attributes to use under certain conditions. Certain
-	 *               IconParts on this list may use these drawing attributes if they
-	 *               want/should. May be null.
-	 */
-	public void render(Graphics g, int width, int height, DrawingAttributes appDA) {
-
-		AffineTransform transform = AffineTransform.getScaleInstance((double) width / 100.0, (double) height / 100.0);
-		transform.concatenate(baseTransform);
-
-		// Handle clip area in Graphics, first
-		Shape clip = getClip();
-		if (clip != null) {
-			g.setClip(new GeneralPath(clip).createTransformedShape(transform));
-		}
-		
-		if (geometry != null) {
-			Shape shape = new GeneralPath(geometry).createTransformedShape(transform);
-			getAttributesForRendering(appDA).render((Graphics2D) g, shape, gradient);
-		}
-	}
-
-	/**
-	 * Set whether colors should be replaced by GradientPaints.
-	 */
-	public void setGradient(boolean value) {
-		gradient = value;
-	}
-
-	/**
-	 * Get whether colors should be replaced by GradientPaints.
-	 */
-	public boolean isGradient() {
-		return gradient;
-	}
-
-	public void setClip(Shape clipArea) {
-		clip = clipArea;
-	}
-
-	public Shape getClip() {
-		return clip;
-	}
-
-	public void setGeometry(Shape shape) {
-		geometry = shape;
-	}
-
-	public Shape getGeometry() {
-		return geometry;
-	}
-
-	public void setTransform(AffineTransform af) {
-		baseTransform = af;
-	}
-
-	public AffineTransform getTransform() {
-		return baseTransform;
-	}
-
-	public void setRenderingAttributes(DrawingAttributes da) {
-		renderingAttributes = da;
-	}
-
-	public DrawingAttributes getRenderingAttributes() {
-		if (renderingAttributes == null) {
-			return DrawingAttributes.DEFAULT;
-		} else {
-			return renderingAttributes;
-		}
-	}
-
-	private BasicIconPart with(Shape s, AffineTransform af, DrawingAttributes da, Shape clipArea, boolean gradient) {
-		BasicIconPart bip = new BasicIconPart(s, af, da);
-		bip.setGradient(gradient);
-		bip.setClip(clipArea);
-		return bip;
-	}
-
-	/**
-	 * @param da new DrawingAttributes
-	 * @return new BasicIconPart with adjusted setting.
-	 */
-	public BasicIconPart with(DrawingAttributes da) {
-		return with(geometry, baseTransform, da, clip, gradient);
-	}
-
-	/**
-	 * @param new affine transform to be applied to the geometry
-	 * @return new BasicIconPart with adjusted setting.
-	 */
-	public BasicIconPart with(AffineTransform af) {
-		return with(geometry, af, renderingAttributes, clip, gradient);
-	}
-
-	/**
-	 * @param s new geometry
-	 * @return new BasicIconPart with adjusted setting.
-	 */
-	public BasicIconPart with(Shape s) {
-		return with(s, baseTransform, renderingAttributes, clip, gradient);
-	}
-
-	/**
-	 * @param c new clip area
-	 * @return new BasicIconPart with adjusted setting.
-	 */
-	public BasicIconPart withClip(Shape c) {
-		return with(geometry, baseTransform, renderingAttributes, c, gradient);
-	}
-
-	/**
-	 * @param gradient true to use gradient colors
-	 * @return new BasicIconPart with adjusted setting.
-	 */
-	public BasicIconPart with(boolean gradient) {
-		return with(geometry, baseTransform, renderingAttributes, clip, gradient);
-	}
-
-	public Object clone() {
-		BasicIconPart clone = null;
-		try {
-			clone = (BasicIconPart) super.clone();
-		} catch (CloneNotSupportedException e) {
-			e.printStackTrace();
-		}
-		return clone;
-	}
-}
\ No newline at end of file
+    /**
+     * AffineTransform to adjust geometry if needed.
+     */
+    protected AffineTransform baseTransform;
+    /**
+     * Shape geometry for this IconPart.
+     */
+    protected Shape geometry;
+    /**
+     * Shape clipping area for this IconPart.
+     */
+    protected Shape clip;
+    /**
+     * DrawingAttributes for this IconPart.
+     */
+    protected DrawingAttributes renderingAttributes = null;
+    /**
+     * Flag to modifying DrawingAttributes Colors into GradientPaints, for that
+     * 3D lighting look.
+     */
+    protected boolean gradient = false;
+
+    /**
+     * Create a BasicIconPart with a java.awt.Shape object for a geometry.
+     *
+     * @param shape, 0-100 range for height and width.
+     */
+    public BasicIconPart(Shape shape) {
+        this(shape, null, DrawingAttributes.DEFAULT);
+    }
+
+    /**
+     * Create a BasicIconPart with a java.awt.Shape object for a geometry, along
+     * with an AffineTransform that may be applied to the geometry at
+     * rendertime.
+     *
+     * @param shape
+     * @param transform
+     */
+    public BasicIconPart(Shape shape, AffineTransform transform) {
+        this(shape, transform, DrawingAttributes.DEFAULT);
+    }
+
+    /**
+     * Create a BasicIconPart with a java.awt.Shape object for a geometry.
+     *
+     * @param shape, 0-100 range for height and width.
+     * @param da
+     */
+    public BasicIconPart(Shape shape, DrawingAttributes da) {
+        this(shape, (AffineTransform) null, da);
+    }
+
+    /**
+     * Create a BasicIconPart with a java.awt.Shape object for a geometry, along
+     * with an AffineTransform that may be applied to the geometry at
+     * rendertime.
+     *
+     * @param shape, 0-100 range for height and width.
+     * @param transform
+     * @param da
+     */
+    public BasicIconPart(Shape shape, AffineTransform transform, DrawingAttributes da) {
+        geometry = shape;
+
+        if (transform == null) {
+            transform = new AffineTransform();
+        }
+
+        baseTransform = transform;
+        setRenderingAttributes(da);
+    }
+
+    /**
+     * Get the DrawingAttributes that should be used for rendering.
+     *
+     * @param da DrawingAttributes passed in that may affect rendering choices.
+     * Can be null, and the IconPart may decide to ignore it.
+     * @return DrawingAttribute for this part.
+     */
+    protected DrawingAttributes getAttributesForRendering(DrawingAttributes da) {
+        return getRenderingAttributes();
+    }
+
+    /**
+     * @param g a java.awt.Graphics object to render into.
+     * @param width pixel width of icon, used to scale geometry.
+     * @param height pixel height of icon, used to scale geometry.
+     */
+    @Override
+    public void render(Graphics g, int width, int height) {
+        render(g, width, height, null);
+    }
+
+    /**
+     * @param g a java.awt.Graphics object to render into.
+     * @param width pixel width of icon, used to scale geometry.
+     * @param height pixel height of icon, used to scale geometry.
+     * @param appDA drawing attributes to use under certain conditions. Certain
+     * IconParts on this list may use these drawing attributes if they
+     * want/should. May be null.
+     */
+    @Override
+    public void render(Graphics g, int width, int height, DrawingAttributes appDA) {
+
+        AffineTransform transform = AffineTransform.getScaleInstance((double) width / 100.0, (double) height / 100.0);
+        transform.concatenate(baseTransform);
+
+        // Handle clip area in Graphics, first
+        Shape clip = getClip();
+        if (clip != null) {
+            g.setClip(new GeneralPath(clip).createTransformedShape(transform));
+        }
+
+        if (geometry != null) {
+            Shape shape = new GeneralPath(geometry).createTransformedShape(transform);
+            getAttributesForRendering(appDA).render((Graphics2D) g, shape, gradient);
+        }
+    }
+
+    /**
+     * Set whether colors should be replaced by GradientPaints.
+     *
+     * @param value
+     */
+    public void setGradient(boolean value) {
+        gradient = value;
+    }
+
+    /**
+     * Get whether colors should be replaced by GradientPaints.
+     *
+     * @return
+     */
+    public boolean isGradient() {
+        return gradient;
+    }
+
+    /**
+     *
+     * @param clipArea
+     */
+    @Override
+    public void setClip(Shape clipArea) {
+        clip = clipArea;
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public Shape getClip() {
+        return clip;
+    }
+
+    /**
+     *
+     * @param shape
+     */
+    @Override
+    public void setGeometry(Shape shape) {
+        geometry = shape;
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public Shape getGeometry() {
+        return geometry;
+    }
+
+    public void setTransform(AffineTransform af) {
+        baseTransform = af;
+    }
+
+    public AffineTransform getTransform() {
+        return baseTransform;
+    }
+
+    @Override
+    public void setRenderingAttributes(DrawingAttributes da) {
+        renderingAttributes = da;
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public DrawingAttributes getRenderingAttributes() {
+        if (renderingAttributes == null) {
+            return DrawingAttributes.DEFAULT;
+        } else {
+            return renderingAttributes;
+        }
+    }
+
+    private BasicIconPart with(Shape s, AffineTransform af, DrawingAttributes da, Shape clipArea, boolean gradient) {
+        BasicIconPart bip = new BasicIconPart(s, af, da);
+        bip.setGradient(gradient);
+        bip.setClip(clipArea);
+        return bip;
+    }
+
+    /**
+     * @param da new DrawingAttributes
+     * @return new BasicIconPart with adjusted setting.
+     */
+    public BasicIconPart with(DrawingAttributes da) {
+        return with(geometry, baseTransform, da, clip, gradient);
+    }
+
+    /**
+     * @param af
+     * @return new BasicIconPart with adjusted setting.
+     */
+    public BasicIconPart with(AffineTransform af) {
+        return with(geometry, af, renderingAttributes, clip, gradient);
+    }
+
+    /**
+     * @param s new geometry
+     * @return new BasicIconPart with adjusted setting.
+     */
+    public BasicIconPart with(Shape s) {
+        return with(s, baseTransform, renderingAttributes, clip, gradient);
+    }
+
+    /**
+     * @param c new clip area
+     * @return new BasicIconPart with adjusted setting.
+     */
+    public BasicIconPart withClip(Shape c) {
+        return with(geometry, baseTransform, renderingAttributes, c, gradient);
+    }
+
+    /**
+     * @param gradient true to use gradient colors
+     * @return new BasicIconPart with adjusted setting.
+     */
+    public BasicIconPart with(boolean gradient) {
+        return with(geometry, baseTransform, renderingAttributes, clip, gradient);
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public Object clone() {
+        BasicIconPart clone = null;
+        try {
+            clone = (BasicIconPart) super.clone();
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+        }
+        return clone;
+    }
+}
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconFactoryTestingTool.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconFactoryTestingTool.java
index d618bb2aa..d2b50573b 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconFactoryTestingTool.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconFactoryTestingTool.java
@@ -19,9 +19,10 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.gui.Tool;
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Container;
@@ -31,132 +32,134 @@
 import java.awt.event.WindowEvent;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
-
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JToolBar;
 import javax.swing.SwingConstants;
 
-import com.bbn.openmap.gui.Tool;
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
  * An example class and example for how to use the OMIconFactory and IconParts
  * to create Icons. Can be run as a class, or can be used as an OpenMap Tool to
  * show up on the OpenMap ToolPanel.
  */
 public class IconFactoryTestingTool
-      implements Tool {
-
-   public IconFactoryTestingTool() {
-   }
-
-   /**
-    * The retrieval tool's interface. This is added to the tool bar.
-    * 
-    * @return String The key for this tool.
-    */
-   public Container getFace() {
-      JToolBar jtb = new JToolBar();
-      jtb.setFloatable(false);
-
-      DrawingAttributes da = new DrawingAttributes();
-      da.setLinePaint(Color.blue);
-      da.setFillPaint(Color.blue);
-      da.setStroke(new BasicStroke(2));
-      DrawingAttributes da2 = new DrawingAttributes();
-      da2.setFillPaint(Color.lightGray);
-      da2.setLinePaint(Color.lightGray);
-      da2.setStroke(new BasicStroke(2));
-
-      int[] xpoints = new int[] {
-         15,
-         15,
-         50,
-         50,
-         90,
-         50,
-         50,
-         15
-      };
-      int[] ypoints = new int[] {
-         30,
-         70,
-         70,
-         90,
-         50,
-         10,
-         30,
-         30
-      };
-      Shape shape = new Polygon(xpoints, ypoints, xpoints.length);
-
-      BasicIconPart testPart = new BasicIconPart(shape);
-      testPart.setRenderingAttributes(da);
-      testPart.setGradient(true);
-
-      Shape shape2 = new Ellipse2D.Double(5, 5, 90, 90);
-      BasicIconPart testPart2 = new BasicIconPart(shape2);
-      testPart2.setRenderingAttributes(da2);
-      testPart2.setGradient(true);
-
-      IconPartList parts = new IconPartList();
-      parts.add(testPart2);
-      parts.add(testPart);
-
-      BasicIconPart testPart3 = new BasicIconPart(shape, AffineTransform.getRotateInstance(Math.PI / 4, 50, 50));
-      testPart3.setRenderingAttributes(da);
-      testPart3.setGradient(true);
-
-      IconPartList parts2 = new IconPartList();
-      parts2.add(testPart2);
-      parts2.add(testPart3);
-
-      jtb.add(new JButton(OMIconFactory.getIcon(10, 10, parts)));
-      jtb.add(new JButton(OMIconFactory.getIcon(20, 20, parts)));
-      jtb.add(new JButton(OMIconFactory.getIcon(50, 50, parts)));
-      jtb.add(new JButton(OMIconFactory.getIcon(50, 50, parts2)));
-      jtb.add(new JButton(OMIconFactory.getIcon(10, 20, parts2)));
-
-      return jtb;
-   }
-
-   /**
-    * The retrieval key for this tool
-    * 
-    * @return String The key for this tool.
-    */
-   public String getKey() {
-      return "IconFactoryTestingTool";
-   }
-
-   /**
-    * Set the retrieval key for this tool
-    * 
-    * @param aKey The key for this tool.
-    */
-   public void setKey(String aKey) {
-   }
-
-   public static void main(String[] argv) {
-      JFrame frame = new JFrame("IconFactoryTestingTool");
-      frame.getContentPane().add(new IconFactoryTestingTool().getFace());
-      frame.pack();
-      frame.addWindowListener(new WindowAdapter() {
-         public void windowClosing(WindowEvent e) {
-            // need a shutdown event to notify other gui beans and
-            // then exit.
-            System.exit(0);
-         }
-      });
-
-      frame.setVisible(true);
-   }
-
-   public void setOrientation(int orientation) {
-   }
-
-   public int getOrientation() {
-      return SwingConstants.HORIZONTAL;
-   }
-}
\ No newline at end of file
+        implements Tool {
+
+    public IconFactoryTestingTool() {
+    }
+
+    /**
+     * The retrieval tool's interface. This is added to the tool bar.
+     *
+     * @return String The key for this tool.
+     */
+    @Override
+    public Container getFace() {
+        JToolBar jtb = new JToolBar();
+        jtb.setFloatable(false);
+
+        DrawingAttributes da = new DrawingAttributes();
+        da.setLinePaint(Color.blue);
+        da.setFillPaint(Color.blue);
+        da.setStroke(new BasicStroke(2));
+        DrawingAttributes da2 = new DrawingAttributes();
+        da2.setFillPaint(Color.lightGray);
+        da2.setLinePaint(Color.lightGray);
+        da2.setStroke(new BasicStroke(2));
+
+        int[] xpoints = new int[]{
+            15,
+            15,
+            50,
+            50,
+            90,
+            50,
+            50,
+            15
+        };
+        int[] ypoints = new int[]{
+            30,
+            70,
+            70,
+            90,
+            50,
+            10,
+            30,
+            30
+        };
+        Shape shape = new Polygon(xpoints, ypoints, xpoints.length);
+
+        BasicIconPart testPart = new BasicIconPart(shape);
+        testPart.setRenderingAttributes(da);
+        testPart.setGradient(true);
+
+        Shape shape2 = new Ellipse2D.Double(5, 5, 90, 90);
+        BasicIconPart testPart2 = new BasicIconPart(shape2);
+        testPart2.setRenderingAttributes(da2);
+        testPart2.setGradient(true);
+
+        IconPartList parts = new IconPartList();
+        parts.add(testPart2);
+        parts.add(testPart);
+
+        BasicIconPart testPart3 = new BasicIconPart(shape, AffineTransform.getRotateInstance(Math.PI / 4, 50, 50));
+        testPart3.setRenderingAttributes(da);
+        testPart3.setGradient(true);
+
+        IconPartList parts2 = new IconPartList();
+        parts2.add(testPart2);
+        parts2.add(testPart3);
+
+        jtb.add(new JButton(OMIconFactory.getIcon(10, 10, parts)));
+        jtb.add(new JButton(OMIconFactory.getIcon(20, 20, parts)));
+        jtb.add(new JButton(OMIconFactory.getIcon(50, 50, parts)));
+        jtb.add(new JButton(OMIconFactory.getIcon(50, 50, parts2)));
+        jtb.add(new JButton(OMIconFactory.getIcon(10, 20, parts2)));
+
+        return jtb;
+    }
+
+    /**
+     * The retrieval key for this tool
+     *
+     * @return String The key for this tool.
+     */
+    @Override
+    public String getKey() {
+        return "IconFactoryTestingTool";
+    }
+
+    /**
+     * Set the retrieval key for this tool
+     *
+     * @param aKey The key for this tool.
+     */
+    @Override
+    public void setKey(String aKey) {
+    }
+
+    public static void main(String[] argv) {
+        JFrame frame = new JFrame("IconFactoryTestingTool");
+        frame.getContentPane().add(new IconFactoryTestingTool().getFace());
+        frame.pack();
+        frame.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                // need a shutdown event to notify other gui beans and
+                // then exit.
+                System.exit(0);
+            }
+        });
+
+        frame.setVisible(true);
+    }
+
+    @Override
+    public void setOrientation(int orientation) {
+    }
+
+    @Override
+    public int getOrientation() {
+        return SwingConstants.HORIZONTAL;
+    }
+}
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPart.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPart.java
index a23828871..a041d4edf 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPart.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPart.java
@@ -22,11 +22,10 @@
 
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.Graphics;
 import java.awt.Shape;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
  * An IconPart is an object that makes up a piece of what's rendered
  * on an Icon. It has a java.awt.Shape object that specifies what gets
@@ -48,6 +47,10 @@ public interface IconPart {
     /**
      * Have the IconPart render itself into the Graphic object for a
      * given height and width.
+     * 
+     * @param g Graphics to draw into
+     * @param width pixels
+     * @param height pixels
      */
     public void render(Graphics g, int width, int height);
 
@@ -59,6 +62,11 @@ public interface IconPart {
      * decide to ignore this provided DrawingAttributes and just use
      * what it has. appDA may be null, in which case the internal
      * DrawingAttributes will be used.
+     * 
+     * @param g Graphics for image to render into
+     * @param width pixels
+     * @param appDA how to draw icon part
+     * @param height pixels
      */
     public void render(Graphics g, int width, int height,
                        DrawingAttributes appDA);
@@ -66,31 +74,37 @@ public void render(Graphics g, int width, int height,
     /**
      * Set a clip area for the IconPart to draw only certain parts of
      * the geometry.
+     * @param clipArea java Shape
      */
     public void setClip(Shape clipArea);
 
     /**
      * Get a clip area for the IconPart.
+     * @return java Shape
      */
     public Shape getClip();
 
     /**
      * Set the geometry for this IconPart.
+     * @param shape java Shape
      */
     public void setGeometry(Shape shape);
 
     /**
      * Get the geometry for this IconPart.
+     * @return java Shape
      */
     public Shape getGeometry();
 
     /**
      * Set the rendering attributes for this IconPart.
+     * @param da
      */
     public void setRenderingAttributes(DrawingAttributes da);
 
     /**
      * Get the rendering attributes for this IconPart.
+     * @return 
      */
     public DrawingAttributes getRenderingAttributes();
     
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartCollection.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartCollection.java
index d671d52a2..e7b31baeb 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartCollection.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartCollection.java
@@ -22,27 +22,38 @@
 
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
- * A collection of IconParts, available by name.
+ * A collection of IconParts, available by name.  A theme, you could say.
  */
 public class IconPartCollection extends IconPartCollectionEntry {
 
-	protected Map entryMap;
-	protected List collections;
+    /**
+     * The selection of parts, by name
+     */
+    protected Map entryMap;
 
-	protected IconPartCollection() {
+    /**
+     *
+     */
+    protected List collections;
+
+    /**
+     *
+     */
+    protected IconPartCollection() {
 	}
 
 	/**
 	 * Create a collection with a name and description.
+     * @param name
+     * @param description
 	 */
 	public IconPartCollection(String name, String description) {
 		setName(name);
@@ -51,6 +62,7 @@ public IconPartCollection(String name, String description) {
 
 	/**
 	 * Add an entry to the collection.
+     * @param entry
 	 */
 	public void add(IconPartCollectionEntry entry) {
 		if (entry != null) {
@@ -67,6 +79,8 @@ public void add(IconPartCollectionEntry entry) {
 
 	/**
 	 * Remove an entry from the collection.
+     * @param entry
+     * @return 
 	 */
 	public Object remove(IconPartCollectionEntry entry) {
 		return getEntryMap().remove(entry.getName());
@@ -81,6 +95,7 @@ public void clear() {
 
 	/**
 	 * Get the set of names for the entries of this collection.
+     * @return 
 	 */
 	public Set keySet() {
 		return getEntryMap().keySet();
@@ -89,6 +104,10 @@ public Set keySet() {
 	/**
 	 * Get an icon part for the given name set with the given rendering attributes.
 	 * Calls get(name);
+     * 
+     * @param name
+     * @param da
+     * @return 
 	 */
 	public IconPart get(String name, DrawingAttributes da) {
 		IconPart ip = get(name);
@@ -104,26 +123,29 @@ public IconPart get(String name, DrawingAttributes da) {
 	 * name. If the name is a collection name, null will be returned. However,
 	 * before returning null, any IconPartCollection added to this collection will
 	 * be checked, too, and any hits will be returned.
+     * 
+     * @param name
+     * @return 
 	 */
 	public IconPart get(String name) {
 		IconPartCollectionEntry entry = getEntryMap().get(name.intern());
-		IconPart part = null;
+		IconPart iconPart = null;
 
 		if (entry != null) {
-			part = (IconPart) entry.getIconPart().clone();
+			iconPart = (IconPart) entry.getIconPart().clone();
 		}
 
-		if (part == null) {
+		if (iconPart == null) {
 			List cllctns = getCollections();
 			for (IconPartCollection ipc : cllctns) {
-				part = ipc.get(name);
-				if (part != null) {
+				iconPart = ipc.get(name);
+				if (iconPart != null) {
 					break;
 				}
 			}
 		}
 
-		return part;
+		return iconPart;
 	}
 
 	/**
@@ -132,6 +154,8 @@ public IconPart get(String name) {
 	 * If the name is a collection name, the description of the collection will be
 	 * returned. Before returning null, any IconPartCollection added to this
 	 * collection will be checked, too, and any hits will be returned.
+     * @param name of the thing you want in the collection
+     * @return the description of the thing
 	 */
 	public String getDescription(String name) {
 		IconPartCollectionEntry entry = getEntryMap().get(name.intern());
@@ -158,6 +182,7 @@ public String getDescription(String name) {
 	 * 
 	 * @param list a List of Strings, with the strings being names of entries into
 	 *             this collection.
+     * @return an IconPart composed from a list of parts.
 	 */
 	public IconPart compose(List list) {
 		IconPartList ipl = new IconPartList();
@@ -180,7 +205,7 @@ public IconPart compose(List list) {
 	 * @return a List of description Strings for the given list of names.
 	 */
 	public List composeDescription(List list) {
-		LinkedList ll = new LinkedList();
+		LinkedList ll = new LinkedList<>();
 
 		for (String entry : list) {
 			String des = getDescription(entry);
@@ -193,6 +218,7 @@ public List composeDescription(List list) {
 
 	/**
 	 * Set the entry Map.
+     * @param map
 	 */
 	protected void setEntryMap(Map map) {
 		entryMap = map;
@@ -200,10 +226,11 @@ protected void setEntryMap(Map map) {
 
 	/**
 	 * Get the entry Map.
+     * @return 
 	 */
 	protected Map getEntryMap() {
 		if (entryMap == null) {
-			entryMap = new HashMap();
+			entryMap = new HashMap<>();
 		}
 		return entryMap;
 	}
@@ -211,6 +238,7 @@ protected Map getEntryMap() {
 	/**
 	 * Set the List to be used for holding IconPartCollections added to this
 	 * collection.
+     * @param list
 	 */
 	protected void setCollections(List list) {
 		collections = list;
@@ -218,19 +246,22 @@ protected void setCollections(List list) {
 
 	/**
 	 * Get the List of IconPartCollections that have been added.
+     * @return 
 	 */
 	protected List getCollections() {
 		if (collections == null) {
-			collections = new LinkedList();
+			collections = new LinkedList<>();
 		}
 		return collections;
 	}
 
-	public void setIconPart(IconPart part) {
+    @Override
+    public void setIconPart(IconPart part) {
 		this.part = part;
 	}
 
-	public IconPart getIconPart() {
+    @Override
+    public IconPart getIconPart() {
 		return part;
 	}
 }
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartList.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartList.java
index 4115d171e..09ed0957f 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartList.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/IconPartList.java
@@ -19,9 +19,9 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Shape;
@@ -30,14 +30,12 @@
 import java.util.LinkedList;
 import java.util.List;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
- * An IconPartList is a group of IconParts that can be rendered
- * together. If you ask an IconPartList for it's geometry, it will
- * combine all its parts into one geometry, and use its
- * DrawingAttributes to render that combined shape. The IconPartList
- * is itself an IconPart, so the recursive possibilities are endless.
+ * An IconPartList is a group of IconParts that can be rendered together. If you
+ * ask an IconPartList for it's geometry, it will combine all its parts into one
+ * geometry, and use its DrawingAttributes to render that combined shape. The
+ * IconPartList is itself an IconPart, so the recursive possibilities are
+ * endless.
  */
 public class IconPartList implements IconPart, Iterable, Cloneable {
 
@@ -45,21 +43,25 @@ public class IconPartList implements IconPart, Iterable, Cloneable {
     protected DrawingAttributes renderingAttributes = null;
     protected Shape clip = null;
 
-    public IconPartList() {}
+    public IconPartList() {
+    }
 
     protected List getList() {
         if (parts == null) {
-            parts = new LinkedList();
+            parts = new LinkedList<>();
         }
         return parts;
     }
 
+    @Override
     public Iterator iterator() {
         return parts.iterator();
     }
 
     /**
      * First in drawn on bottom. Last in on top.
+     *
+     * @param part
      */
     public void add(IconPart part) {
         getList().add(part);
@@ -73,22 +75,24 @@ public void clear() {
         getList().clear();
     }
 
+    @Override
     public void render(Graphics g, int width, int height) {
         render(g, width, height, null);
     }
 
     /**
-     * @param appDA drawing attributes to use under certain
-     *        conditions. Certain IconParts on this list may use these
-     *        drawing attributes if they want/should. May be null.
+     * @param appDA drawing attributes to use under certain conditions. Certain
+     * IconParts on this list may use these drawing attributes if they
+     * want/should. May be null.
      */
+    @Override
     public void render(Graphics g, int width, int height,
-                       DrawingAttributes appDA) {
+            DrawingAttributes appDA) {
 
-        // Handle clip area in Graphics, first
-        Shape clip = getClip();
-        if (clip != null) {
-            g.setClip(clip);
+        // Handle clipShape area in Graphics, first
+        Shape clipShape = getClip();
+        if (clipShape != null) {
+            g.setClip(clipShape);
         }
 
         DrawingAttributes da = getRenderingAttributes();
@@ -112,14 +116,17 @@ public void render(Graphics g, int width, int height,
         }
     }
 
+    @Override
     public void setClip(Shape clipArea) {
         clip = clipArea;
     }
 
+    @Override
     public Shape getClip() {
         return clip;
     }
 
+    @Override
     public void setGeometry(Shape shape) {
         // dump the list, create a generic IconPart to hold the shape.
         List list = getList();
@@ -128,12 +135,13 @@ public void setGeometry(Shape shape) {
     }
 
     /**
-     * If you ask a IconPartList for its geometry, it will combine all
-     * its parts to make one Shape object. All the rendering
-     * attributes from the individual parts will be ignored. The
-     * contributions will be kept geometrically separate
-     * (disconnected) and their clipping areas will be ignored.
+     * If you ask a IconPartList for its geometry, it will combine all its parts
+     * to make one Shape object. All the rendering attributes from the
+     * individual parts will be ignored. The contributions will be kept
+     * geometrically separate (disconnected) and their clipping areas will be
+     * ignored.
      */
+    @Override
     public Shape getGeometry() {
         GeneralPath geometry = null;
         for (IconPart part : this) {
@@ -153,18 +161,21 @@ public Shape getGeometry() {
         return geometry;
     }
 
+    @Override
     public void setRenderingAttributes(DrawingAttributes da) {
         renderingAttributes = da;
     }
 
+    @Override
     public DrawingAttributes getRenderingAttributes() {
         return renderingAttributes;
     }
 
+    @Override
     public Object clone() {
         IconPartList clone = new IconPartList();
         for (IconPart part : this) {
-            clone.add((IconPart)part.clone());
+            clone.add((IconPart) part.clone());
         }
 
         clone.setRenderingAttributes(getRenderingAttributes());
@@ -172,4 +183,4 @@ public Object clone() {
         return clone;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconFactory.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconFactory.java
index 6ff8a2bf7..1ff74ac53 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconFactory.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconFactory.java
@@ -19,21 +19,19 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.tools.icon;
 
+import com.bbn.openmap.omGraphics.DrawingAttributes;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
-
 import javax.swing.ImageIcon;
 
-import com.bbn.openmap.omGraphics.DrawingAttributes;
-
 /**
  * The OMIconFactory is a factory to build ImageIcons, with content described by
- * IconParts for a certain size.
+ * IconParts for a certain size. This is the main class for this package, where
+ * you get the ImageIcon to use for OMGraphics and buttons.
  */
 public class OMIconFactory {
 
@@ -41,6 +39,10 @@ public class OMIconFactory {
      * Create an ImageIcon that is a certain pixel height and width. This will
      * return an empty ImageIcon, and you'd have to do the rendering into its
      * image.
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @return ImageIcon, blank and transparent
      */
     public static ImageIcon createImageIcon(int width, int height) {
         return createImageIcon(width, height, BufferedImage.TYPE_INT_ARGB);
@@ -50,6 +52,11 @@ public static ImageIcon createImageIcon(int width, int height) {
      * Create an ImageIcon that is a certain pixel height and width, with a
      * specified image type (ARGB, RGB, etc). This will return an empty
      * ImageIcon, and you'd have to do the rendering into its image.
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @param imageType BufferedImage TYPE
+     * @return ImageIcon
      */
     public static ImageIcon createImageIcon(int width, int height, int imageType) {
         return new ImageIcon(new BufferedImage(width, height, imageType));
@@ -59,6 +66,11 @@ public static ImageIcon createImageIcon(int width, int height, int imageType) {
      * Create an ImageIcon that is a certain pixel height and width created with
      * a certain IconPart geometry. The geometry will be drawing with default
      * DrawingAttributes.
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @param geometry IconPart to draw in ImageIcon, DrawingAttributes default
+     * @return ImageIcon
      */
     public static ImageIcon getIcon(int width, int height, IconPart geometry) {
         return getIcon(width, height, geometry, null);
@@ -68,9 +80,15 @@ public static ImageIcon getIcon(int width, int height, IconPart geometry) {
      * Create an ImageIcon that is a certain pixel height and width created with
      * a certain IconPart geometry. Also, the DrawingAttributes can be used to
      * add color/texture to the IconPart geometries.
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @param geometry IconPart to draw
+     * @param appDA how to draw IconPart
+     * @return ImageIcon
      */
     public static ImageIcon getIcon(int width, int height, IconPart geometry,
-                                    DrawingAttributes appDA) {
+            DrawingAttributes appDA) {
         return getIcon(width, height, geometry, appDA, null);
     }
 
@@ -84,14 +102,21 @@ public static ImageIcon getIcon(int width, int height, IconPart geometry,
      * to be painted that might be part of a theme. This appDA argument lets you
      * specify how those accents might be rendered. General DrawingAttributes
      * should be set on the IconPart, however.
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @param geometry IconPart to draw
+     * @param appDA how to draw part
+     * @param af used for rotation or other funky mods
+     * @return ImageIcon
      */
     public static ImageIcon getIcon(int width, int height, IconPart geometry,
-                                    DrawingAttributes appDA, AffineTransform af) {
+            DrawingAttributes appDA, AffineTransform af) {
         ImageIcon icon = createImageIcon(width, height);
         Graphics2D g = (Graphics2D) icon.getImage().getGraphics();
-		if (af != null) {
-			g.setTransform(af);
-		}
+        if (af != null) {
+            g.setTransform(af);
+        }
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                 RenderingHints.VALUE_ANTIALIAS_ON);
 
@@ -105,9 +130,16 @@ public static ImageIcon getIcon(int width, int height, IconPart geometry,
      * add color/texture to the IconPart geometries, and an angle can be
      * provided to rotate the geometry (zero is north up, positive clockwise,
      * angle in RADIANS).
+     * 
+     * @param width pixels
+     * @param height pixels
+     * @param geometry IconPart to draw
+     * @param appDA how to draw IconPart
+     * @param rot angle to rotate in RADIANS
+     * @return ImageIcon
      */
     public static ImageIcon getIcon(int width, int height, IconPart geometry,
-                                    DrawingAttributes appDA, double rot) {
+            DrawingAttributes appDA, double rot) {
         return getIcon(width,
                 height,
                 geometry,
@@ -116,4 +148,4 @@ public static ImageIcon getIcon(int width, int height, IconPart geometry,
                         width / 2.0,
                         height / 2.0));
     }
-}
\ No newline at end of file
+}
diff --git a/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconPart.java b/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconPart.java
index b0b7b1aaf..481b30f20 100644
--- a/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconPart.java
+++ b/src/core/src/main/java/com/bbn/openmap/tools/icon/OMIconPart.java
@@ -103,6 +103,7 @@ public static Shape getCircle(double x, double y, double radius) {
 	 * @param radius radius of circle
 	 * @param start  starting angle of arc in degrees
 	 * @param end    ending angle of arc in degrees
+     * @param type   BufferedImage TYPE
 	 * @return Shape from Arc2D
 	 */
 	public static Shape getArc(double x, double y, double radius, double start, double end, int type) {
diff --git a/src/core/src/main/java/com/bbn/openmap/util/DataBounds.java b/src/core/src/main/java/com/bbn/openmap/util/DataBounds.java
index 404534993..c1f14f421 100644
--- a/src/core/src/main/java/com/bbn/openmap/util/DataBounds.java
+++ b/src/core/src/main/java/com/bbn/openmap/util/DataBounds.java
@@ -19,7 +19,6 @@
 // $Author: dietrick $
 // 
 // **********************************************************************
-
 package com.bbn.openmap.util;
 
 import java.awt.geom.Point2D;
@@ -29,216 +28,221 @@
  */
 public class DataBounds {
 
-	protected Point2D min;
-	protected Point2D max;
-
-	protected DataBounds hardLimits;
-
-	/**
-	 * True if the direction of the y coordinates increase in the up direction.
-	 * Should be set to false if larger y values are actually lower pixel values
-	 * on the map.
-	 */
-	boolean yDirUp = true;
-
-	public DataBounds() {
-	}
-
-	public DataBounds(double minx, double miny, double maxx, double maxy) {
-		add(minx, miny);
-		add(maxx, maxy);
-	}
-
-	public DataBounds(Point2D minP, Point2D maxP) {
-		add(minP);
-		add(maxP);
-	}
-
-	/**
-	 * @return a point set to the average of the min and max values. May return
-	 *         null if no points have been added
-	 */
-	public Point2D getCenter() {
-		if (min != null) {
-			double minx = min.getX();
-			double miny = min.getY();
-			double maxx = max.getX();
-			double maxy = max.getY();
-			return new Point2D.Double((minx + maxx) / 2, (miny + maxy) / 2);
-		} else
-			return null;
-	}
-
-	public String toString() {
-		return "DataBounds| min:" + min + " max:" + max;
-	}
-
-	/**
-	 * @return upper right point
-	 */
-	public Point2D getMax() {
-		return max;
-	}
-
-	/**
-	 * @return lower left point
-	 */
-	public Point2D getMin() {
-		return min;
-	}
-
-	public void add(double x, double y) {
-		if (min == null) {
-			min = new Point2D.Double(x, y);
-			max = new Point2D.Double(x, y);
-		} else {
-			double minx = min.getX();
-			double miny = min.getY();
-			double maxx = max.getX();
-			double maxy = max.getY();
-
-			if (minx > x)
-				minx = x;
-			if (miny > y)
-				miny = y;
-			if (maxx < x)
-				maxx = x;
-			if (maxy < y)
-				maxy = y;
-
-			if (hardLimits != null) {
-				double hlminx = hardLimits.min.getX();
-				double hlminy = hardLimits.min.getY();
-				double hlmaxx = hardLimits.max.getX();
-				double hlmaxy = hardLimits.max.getY();
-
-				minx = setInRange(hlmaxx, hlminx, minx);
-				maxx = setInRange(hlmaxx, hlminx, maxx);
-				miny = setInRange(hlmaxy, hlminy, miny);
-				maxy = setInRange(hlmaxy, hlminy, maxy);
-
-			}
-
-			min.setLocation(minx, miny);
-			max.setLocation(maxx, maxy);
-		}
-	}
-
-	/**
-	 * Add min and max from a TimeBounds object to this one.
-	 * 
-	 * @param dataBounds another TimeBounds object.
-	 */
-	public void add(DataBounds dataBounds) {
-		if (dataBounds != null) {
-			add(dataBounds.getMin());
-			add(dataBounds.getMax());
-		}
-	}
-
-	/**
-	 * Make sure the value is within the range.
-	 * 
-	 * @param hi high range value
-	 * @param lo low range value
-	 * @param val testing value
-	 * @return the value, adjusted if necessary.
-	 */
-	protected double setInRange(double hi, double lo, double val) {
-		if (val > hi) {
-			val = hi;
-		}
-
-		if (val < lo) {
-			val = lo;
-		}
-
-		return val;
-	}
-
-	/**
-	 * Add Point2D values to TimeBounds.
-	 * 
-	 * @param point Point2D
-	 */
-	public void add(Point2D point) {
-		if (point != null) {
-			add(point.getX(), point.getY());
-		}
-	}
-
-	public boolean contains(Point2D query) {
-		double x = query.getX();
-		double y = query.getY();
-		return x >= min.getX() && x <= max.getX() && y >= min.getY() && y <= max.getY();
-	}
-
-	public double getWidth() {
-		return max.getX() - min.getX();
-	}
-
-	public double getHeight() {
-		return max.getY() - min.getY();
-	}
-
-	public DataBounds getHardLimits() {
-		return hardLimits;
-	}
-
-	public void setHardLimits(DataBounds hardLimits) {
-		this.hardLimits = hardLimits;
-	}
-
-	public boolean isyDirUp() {
-		return yDirUp;
-	}
-
-	public void setyDirUp(boolean yDirUp) {
-		this.yDirUp = yDirUp;
-	}
-
-	public boolean equals(Object obj) {
-		if (this == obj) {
-			return true;
-		}
-		if (obj instanceof DataBounds) {
-			DataBounds dobj = (DataBounds) obj;
-			boolean match = (min == null && dobj.getMin() == null && max == null && dobj.getMax() == null);
-			boolean match2 = false;
-			try {
-				match2 = getMin().equals(dobj.getMin()) && getMax().equals(dobj.getMax());
-			} catch (NullPointerException npe) {
-
-			}
-
-			return this.yDirUp == dobj.yDirUp && (match || match2);
-		}
-
-		return false;
-	}
-
-	public int hashCode() {
-		int result = HashCodeUtil.SEED;
-		// collect the contributions of various fields
-		if (max != null) {
-			result = HashCodeUtil.hash(result, max.getY());
-			result = HashCodeUtil.hash(result, max.getX());
-		}
-		if (min != null) {
-			result = HashCodeUtil.hash(result, min.getY());
-			result = HashCodeUtil.hash(result, min.getX());
-		}
-		result = HashCodeUtil.hash(result, yDirUp);
-		return result;
-	}
-
-	public boolean intersects(DataBounds db2) {
-		if (db2 == null) {
-			return false;
-		}
-		Point2D min2 = db2.getMin();
-		Point2D max2 = db2.getMax();
-		return !(min2 == null || (min2.getY() > max.getY() || max2.getY() < min.getY())
-				|| (min2.getX() > max.getX() || max2.getX() < min.getX()));
-	}
-}
\ No newline at end of file
+    protected Point2D min;
+    protected Point2D max;
+
+    protected DataBounds hardLimits;
+
+    /**
+     * True if the direction of the y coordinates increase in the up direction.
+     * Should be set to false if larger y values are actually lower pixel values
+     * on the map.
+     */
+    boolean yDirUp = true;
+
+    public DataBounds() {
+    }
+
+    public DataBounds(double minx, double miny, double maxx, double maxy) {
+        add(minx, miny);
+        add(maxx, maxy);
+    }
+
+    public DataBounds(Point2D minP, Point2D maxP) {
+        add(minP);
+        add(maxP);
+    }
+
+    /**
+     * @return a point set to the average of the min and max values. May return
+     * null if no points have been added
+     */
+    public Point2D getCenter() {
+        if (min != null) {
+            double minx = min.getX();
+            double miny = min.getY();
+            double maxx = max.getX();
+            double maxy = max.getY();
+            return new Point2D.Double((minx + maxx) / 2, (miny + maxy) / 2);
+        } 
+
+        return null;
+    }
+
+    public String toString() {
+        return "DataBounds| min:" + min + " max:" + max;
+    }
+
+    /**
+     * @return upper right point
+     */
+    public Point2D getMax() {
+        return max;
+    }
+
+    /**
+     * @return lower left point
+     */
+    public Point2D getMin() {
+        return min;
+    }
+
+    public void add(double x, double y) {
+        if (min == null) {
+            min = new Point2D.Double(x, y);
+            max = new Point2D.Double(x, y);
+        } else {
+            double minx = min.getX();
+            double miny = min.getY();
+            double maxx = max.getX();
+            double maxy = max.getY();
+
+            if (minx > x) {
+                minx = x;
+            }
+            if (miny > y) {
+                miny = y;
+            }
+            if (maxx < x) {
+                maxx = x;
+            }
+            if (maxy < y) {
+                maxy = y;
+            }
+
+            if (hardLimits != null) {
+                double hlminx = hardLimits.min.getX();
+                double hlminy = hardLimits.min.getY();
+                double hlmaxx = hardLimits.max.getX();
+                double hlmaxy = hardLimits.max.getY();
+
+                minx = setInRange(hlmaxx, hlminx, minx);
+                maxx = setInRange(hlmaxx, hlminx, maxx);
+                miny = setInRange(hlmaxy, hlminy, miny);
+                maxy = setInRange(hlmaxy, hlminy, maxy);
+
+            }
+
+            min.setLocation(minx, miny);
+            max.setLocation(maxx, maxy);
+        }
+    }
+
+    /**
+     * Add min and max from a TimeBounds object to this one.
+     *
+     * @param dataBounds another TimeBounds object.
+     */
+    public void add(DataBounds dataBounds) {
+        if (dataBounds != null) {
+            add(dataBounds.getMin());
+            add(dataBounds.getMax());
+        }
+    }
+
+    /**
+     * Make sure the value is within the range.
+     *
+     * @param hi high range value
+     * @param lo low range value
+     * @param val testing value
+     * @return the value, adjusted if necessary.
+     */
+    protected double setInRange(double hi, double lo, double val) {
+        if (val > hi) {
+            val = hi;
+        }
+
+        if (val < lo) {
+            val = lo;
+        }
+
+        return val;
+    }
+
+    /**
+     * Add Point2D values to TimeBounds.
+     *
+     * @param point Point2D
+     */
+    public void add(Point2D point) {
+        if (point != null) {
+            add(point.getX(), point.getY());
+        }
+    }
+
+    public boolean contains(Point2D query) {
+        double x = query.getX();
+        double y = query.getY();
+        return x >= min.getX() && x <= max.getX() && y >= min.getY() && y <= max.getY();
+    }
+
+    public double getWidth() {
+        return max.getX() - min.getX();
+    }
+
+    public double getHeight() {
+        return max.getY() - min.getY();
+    }
+
+    public DataBounds getHardLimits() {
+        return hardLimits;
+    }
+
+    public void setHardLimits(DataBounds hardLimits) {
+        this.hardLimits = hardLimits;
+    }
+
+    public boolean isyDirUp() {
+        return yDirUp;
+    }
+
+    public void setyDirUp(boolean yDirUp) {
+        this.yDirUp = yDirUp;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DataBounds) {
+            DataBounds dobj = (DataBounds) obj;
+            boolean match = (min == null && dobj.getMin() == null && max == null && dobj.getMax() == null);
+            boolean match2 = false;
+            try {
+                match2 = getMin().equals(dobj.getMin()) && getMax().equals(dobj.getMax());
+            } catch (NullPointerException npe) {
+
+            }
+
+            return this.yDirUp == dobj.yDirUp && (match || match2);
+        }
+
+        return false;
+    }
+
+    public int hashCode() {
+        int result = HashCodeUtil.SEED;
+        // collect the contributions of various fields
+        if (max != null) {
+            result = HashCodeUtil.hash(result, max.getY());
+            result = HashCodeUtil.hash(result, max.getX());
+        }
+        if (min != null) {
+            result = HashCodeUtil.hash(result, min.getY());
+            result = HashCodeUtil.hash(result, min.getX());
+        }
+        result = HashCodeUtil.hash(result, yDirUp);
+        return result;
+    }
+
+    public boolean intersects(DataBounds db2) {
+        if (db2 == null) {
+            return false;
+        }
+        Point2D min2 = db2.getMin();
+        Point2D max2 = db2.getMax();
+        return !(min2 == null || (min2.getY() > max.getY() || max2.getY() < min.getY())
+                || (min2.getX() > max.getX() || max2.getX() < min.getX()));
+    }
+}
diff --git a/src/maptileservlet/pom.xml b/src/maptileservlet/pom.xml
index 0cf7fdbfd..816fae79c 100644
--- a/src/maptileservlet/pom.xml
+++ b/src/maptileservlet/pom.xml
@@ -1,106 +1,61 @@
 
-  4.0.0
-  openmap-maptileservlet
-  org.openmap-java
-  6.0-SNAPSHOT
-  war
-  openmap-maptileservlet
-  OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information.  This project encapsulates map tile servlet components that can be used with Tomcat/Glassfish to create a tile server.
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    4.0.0
+    openmap-maptileservlet
+    org.openmap-java
+    6.0-SNAPSHOT
+    war
+    openmap-maptileservlet
+    OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information.  This project encapsulates map tile servlet components that can be used with Tomcat/Glassfish to create a tile server.
 
-  
-    
-      
-        org.apache.maven.plugins
-        maven-jar-plugin
-        3.2.0
-        
-          
-            package
-            
-              jar
-            
-            
-              ommaptile
-            
-          
-        
-      
-      
-	org.apache.maven.plugins
-	maven-source-plugin
-	3.2.1
-	
-	  
-	    attach-sources
-	    install	    
-	    
-	      jar
-	    
-	  
-	
-      
-      
-	org.apache.maven.plugins
-	maven-javadoc-plugin
-	3.2.0
-	
-	  
-	    attach-javadocs
-	    install
-	    
-	      jar
-	    
-	  
-	
-      
-      
-        org.apache.maven.plugins
-        maven-install-plugin
-        2.5.2
-        
-          
-            package
-            
-              ommaptile
-              org.openmap-java
-              6.0-SNAPSHOT
-              jar
-              ${project.build.directory}/${project.build.finalName}-ommaptile.jar
-            
-            
-              install-file
-            
-          
-        
-      
-    
-  
+    
+        
+            
+                org.apache.maven.plugins
+                maven-war-plugin
+                3.3.1
+                
+                    false
+                
+            
+            
+                org.apache.maven.plugins
+                maven-war-plugin
+                3.2.3
+                
+                    
+                        WEB-INF/lib/javaee*.jar,
+                        WEB-INF/lib/jsr*.jar
+                            
+                
+               
+        
+    
   
-  
-    UTF-8
-    7
-    1.7
-  
-  
-    
-      javax.servlet
-      servlet-api
-      2.5
-    
-    
-      org.xerial
-      sqlite-jdbc
-      3.8.11.2
-    
-    
-      org.openmap-java
-      openmap
-      6.0-SNAPSHOT
-      jar
-    
-  
-  
+    
+        UTF-8
+        7
+        1.7
+    
+    
+        
+            javax.servlet
+            servlet-api
+            2.5
+        
+        
+            org.xerial
+            sqlite-jdbc
+            3.8.11.2
+        
+        
+            org.openmap-java
+            openmap
+            6.0-SNAPSHOT
+            jar
+        
+    
+    
 
diff --git a/src/maptileservlet/src/main/resources/tileSetProperties/tileset2.properties b/src/maptileservlet/src/main/resources/tileSetProperties/tileset2.properties
index 54aef3416..2f130218b 100644
--- a/src/maptileservlet/src/main/resources/tileSetProperties/tileset2.properties
+++ b/src/maptileservlet/src/main/resources/tileSetProperties/tileset2.properties
@@ -5,7 +5,7 @@
 # deployment in the war.  You can add more properties files to the
 # directoryfor different tile sets.
 
-name=Control Room
+name=Control_Room
 
 #The rootDir for a TileMill file, using the sql jar file in the classpath, too.
 rootDir=jdbc:sqlite:/Volumes/data/tiles/control-room.mbtiles
diff --git a/src/maptileservlet/src/main/webapp/WEB-INF/web.xml b/src/maptileservlet/src/main/webapp/WEB-INF/web.xml
index c08e7cf90..3322c8cbf 100644
--- a/src/maptileservlet/src/main/webapp/WEB-INF/web.xml
+++ b/src/maptileservlet/src/main/webapp/WEB-INF/web.xml
@@ -51,7 +51,7 @@
 		
 		  Provide map tiles as asked for, based on z/x/y.png requests.
 		
-		com.bbn.openmap.maptileservlet.MapTileServlet
+		com.bbn.openmap.servlet.mapTile.MapTileServlet
 	
 
     
diff --git a/src/vpfbrowseservlet/pom.xml b/src/vpfbrowseservlet/pom.xml
index adb5b50b7..6f12e52ef 100644
--- a/src/vpfbrowseservlet/pom.xml
+++ b/src/vpfbrowseservlet/pom.xml
@@ -4,7 +4,18 @@
   war
   openmap-vpfbrowseservlet
   OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information.  This project contains components that can create a server to browse the contents of VPF libraries.
-
+  
+   
+        
+            org.apache.maven.plugins
+            maven-war-plugin
+            3.3.1
+            
+                false
+            
+        
+    
+  
   
     
       javax.servlet
diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/package.html b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/package.html
deleted file mode 100644
index c2fdf8983..000000000
--- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/package.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-This package is the Java source code to view VPF data through web
-pages generated by servlets.
-
\ No newline at end of file
diff --git a/src/vpfbrowseservlet/src/main/webapp/PrintTable.jsp b/src/vpfbrowseservlet/src/main/webapp/PrintTable.jsp
index bae778d04..3e9fb59ca 100644
--- a/src/vpfbrowseservlet/src/main/webapp/PrintTable.jsp
+++ b/src/vpfbrowseservlet/src/main/webapp/PrintTable.jsp
@@ -1,8 +1,8 @@
 <%@ page session="false" %>
 
-
-
-
+
+
+
 	
 <% table.setFile(request.getParameter("table")); %>
 
diff --git a/src/vpfbrowseservlet/src/main/webapp/VPFText.jsp b/src/vpfbrowseservlet/src/main/webapp/VPFText.jsp
index c54a77f81..574f57067 100644
--- a/src/vpfbrowseservlet/src/main/webapp/VPFText.jsp
+++ b/src/vpfbrowseservlet/src/main/webapp/VPFText.jsp
@@ -11,7 +11,7 @@ This is help text.
 Here we are.
 
  • Hostname: - + <% lst.setContext(application); %> <% lst.setResponse(response); %> diff --git a/src/wmsservlet/pom.xml b/src/wmsservlet/pom.xml index 3f6898fd1..a8878f25e 100644 --- a/src/wmsservlet/pom.xml +++ b/src/wmsservlet/pom.xml @@ -4,17 +4,29 @@ war openmap-wmsservlet OpenMap is a Java Beans based toolkit for building applications and applets needing geographic information. This project encapsulates the wms servlet components that can be used with Tomcat/Glassfish to create a Web Mapping Service. - + + + + org.apache.maven.plugins + maven-war-plugin + 3.4.0 + + false + + + + - javax.servlet - servlet-api - 2.5 + jakarta.servlet + jakarta.servlet-api + 5.0.0 + provided org.openmap-java openmap - 6.0-SNAPSHOT + ${project.version} diff --git a/src/wmsservlet/src/main/webapp/WEB-INF/web.xml b/src/wmsservlet/src/main/webapp/WEB-INF/web.xml index 5ef2631aa..95503b600 100644 --- a/src/wmsservlet/src/main/webapp/WEB-INF/web.xml +++ b/src/wmsservlet/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,8 @@ - - + + OGC Web Map Server Servlet