From 2749125208b780acec159f489610cc79f8138975 Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Mon, 5 Jul 2021 09:58:43 -0400 Subject: [PATCH 01/20] Remove unwanted plugin. --- pom.xml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 154db72e..ad0c4c49 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,8 @@ maven-javadoc-plugin 3.2.0 - false + false + private @@ -107,7 +108,7 @@ copy-dependencies - deploy + package copy-dependencies @@ -115,18 +116,6 @@ - - net.ju-n.maven.plugins - checksum-maven-plugin - 1.2 - - - - artifacts - - - - From 3a1a04a054bb5774604dd495a425eb3ed8b1bab0 Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 19:44:41 +0100 Subject: [PATCH 02/20] Moving the MapTile servlet into the core code base. The maptileservlet code base is for organization and managing the servlet. --- .../servlet/mapTile/MBRasterMapTileSet.java | 134 ++++++ .../servlet/mapTile/MapTileServlet.java | 388 ++++++++++++++++++ .../openmap/servlet/mapTile/MapTileSet.java | 66 +++ .../servlet/mapTile/RelayMapTileSet.java | 119 ++++++ .../servlet/mapTile/StandardMapTileSet.java | 142 +++++++ .../bbn/openmap/servlet/mapTile/TileInfo.java | 96 +++++ 6 files changed, 945 insertions(+) create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java new file mode 100644 index 00000000..cc794123 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MBRasterMapTileSet.java @@ -0,0 +1,134 @@ +/* + */ +package com.bbn.openmap.servlet.mapTile; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Properties; +import java.util.logging.Logger; + +import javax.swing.ImageIcon; + +import com.bbn.openmap.dataAccess.mapTile.mb.RasterMapTileFactory; +import com.bbn.openmap.image.BufferedImageHelper; +import com.bbn.openmap.image.PNGImageIOFormatter; +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.util.PropUtils; + +/** + * MapTileSet that reads MapBox raster mbtiles files. + * + *
+ * name=the-name-of-dataset
+ * class=com.bbn.openmap.maptileservlet.MBRasterMapTileSet
+ * rootDir=the path to the mbtiles file.
+ *  * 
+ * + * As an example, a url for accessing a tile from this server would be: + * + *
+ * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
+ * 
+ * + * where ommaptile is the name of the servlet. You can change that in the + * web.xml and in glassfish/tomcat. + * + * @author dietrick + */ +public class MBRasterMapTileSet extends StandardMapTileSet { + + public MBRasterMapTileSet() { + } + + public MBRasterMapTileSet(Properties props) { + setProperties(props); + } + + public Properties getProperties(Properties props) { + props = super.getProperties(props); + String prefix = PropUtils.getScopedPropertyPrefix(this); + props.put(prefix + CLASS_ATTRIBUTE, this.getClass().getName()); + + return props; + } + + public byte[] getImageData(String pathInfo) throws IOException, FormatException { + + byte[] imageData = null; + + try { + Class.forName(RasterMapTileFactory.DEFAULT_TEST_CLASS); + } catch (Exception e) { + getLogger().warning("can't locate sqlite JDBC components"); + return null; + } + + try { + + TileInfo ti = new TileInfo(pathInfo); + + Connection conn = DriverManager.getConnection(rootDir); + Statement stat = conn.createStatement(); + + // "select zoom_level, tile_column, tile_row, tile_data from map, images where map.tile_id = images.tile_id"; + StringBuilder statement = new StringBuilder("select tile_data from map, images where"); + statement.append(" zoom_level = ").append(ti.zoomLevel); + statement.append(" and tile_column = ").append(ti.x); + statement.append(" and tile_row = ").append((int) (Math.pow(2, ti.zoomLevel)) - ti.y + - 1); + statement.append(" and map.tile_id = images.tile_id;"); + + ResultSet rs = stat.executeQuery(statement.toString()); + while (rs.next()) { + byte[] imageBytes = rs.getBytes("tile_data"); + ImageIcon ii = new ImageIcon(imageBytes); + BufferedImage bi = BufferedImageHelper.getBufferedImage(ii.getImage(), 0, 0, -1, -1); + + // TODO: Still have to incorporate properties or something to + // all + // specification of map image format. + imageData = new PNGImageIOFormatter().formatImage(bi); + } + rs.close(); + conn.close(); + } catch (Exception e) { + getLogger().warning("something went wrong fetching image from database: " + + e.getMessage()); + e.printStackTrace(); + } + + return imageData; + } + + /** + * Holder for this class's Logger. This allows for lazy initialization of + * the logger. + */ + private static final class LoggerHolder { + /** + * The logger for this class + */ + private static final Logger LOGGER = Logger.getLogger(MapTileSet.class.getName()); + + /** + * Prevent instantiation + */ + private LoggerHolder() { + throw new AssertionError("This should never be instantiated"); + } + } + + /** + * Get the logger for this class. + * + * @return logger for this class + */ + private static Logger getLogger() { + return LoggerHolder.LOGGER; + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java new file mode 100644 index 00000000..61188d6b --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java @@ -0,0 +1,388 @@ +package com.bbn.openmap.servlet.mapTile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +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 com.bbn.openmap.util.ComponentFactory; +import com.bbn.openmap.util.PropUtils; +import com.bbn.openmap.util.http.HttpConnection; +import com.bbn.openmap.util.wanderer.Wanderer; +import com.bbn.openmap.util.wanderer.WandererCallback; + +/** + * MapTileServlet is a servlet class that fields requests for map tiles. It can + * handle multiple MapTileSets, each one defined by a properties file. The + * web.xml file for this servlet lets you specify the directory where these + * properties files are, under the TileSetDefinitions attribute. The properties + * files in that directory are automatically read and used to create + * MapTileSets. The default deployed name and location of this directory is the + * WEB-INF/classes/tileSetDefinitions directory, but any location can be + * specified. + * + * Each maptileset properties file should specify a name of the tile set, which + * is used in the path to reach those tiles. The MapTileSet object is used by + * the MapTileServlet to handle the specific configuration of the tile set, and + * the MapTileSet object classname to use can be specified in the maptileset + * properties under the 'class' property. The StandardMapTileSet is used by + * default, it assumes the tile set is stored in a z/x/y file structure. The + * TileMillMapTileSet knows how to use mbtiles files created using TileMill. The + * RelayMapTileSet uses a local z/x/y directory structure as a cache for tiles + * to disperse, but goes to another server location to fetch new tiles it + * doesn't have. Each MapTileSet has configuration information in its javadoc. + * See the web.xml file for more information about configuring this + * MapTileServlet. + * + * @author dietrick + */ +public class MapTileServlet extends HttpServlet { + public final static String TILE_SET_DESCRIPTION_ATTRIBUTE = "TileSetDefinitions"; + public final static String LEAFLET_CSS_LOCATION_ATTRIBUTE = "leaflet_css"; + public final static String LEAFLET_JS_LOCATION_ATTRIBUTE = "leaflet_js"; + protected Map mapTileSets; + + String leafletCssLocation = "http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css"; + String leafletJsLocation = "http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"; + + /** + * A do-nothing constructor - init does all the work. + */ + public MapTileServlet() { + super(); + + mapTileSets = Collections.synchronizedMap(new HashMap()); + } + + /** + * Called when the servlet is loaded. + * + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + ServletContext context = config.getServletContext(); + + Logger logger = getLogger(); + String leafletCss = context.getInitParameter(LEAFLET_CSS_LOCATION_ATTRIBUTE); + if (leafletCss != null) { + leafletCssLocation = leafletCss; + } + logger.log(Level.INFO, "leaflet.css located at: {0}", leafletCssLocation); + + String leafletJs = context.getInitParameter(LEAFLET_JS_LOCATION_ATTRIBUTE); + if (leafletJs != null) { + leafletJsLocation = leafletJs; + } + logger.log(Level.INFO, "leaflet.js located at: {0}", leafletJsLocation); + + String descriptions = context.getInitParameter(TILE_SET_DESCRIPTION_ATTRIBUTE); + logger.log(Level.INFO, "Looking for Tile Set Descriptions at: {0}", descriptions); + if (descriptions != null) { + + // Changing descriptions to a folder containing properties files + // defining tile sets. + try { + + URL descriptionFolder = PropUtils.getResourceOrFileOrURL(descriptions); + new PropertiesWanderer(new File(descriptionFolder.getFile())); + + } catch (MalformedURLException e) { + logger.warning("unable to open for Tile Set properties file given " + descriptions); + } catch (NullPointerException npe) { + logger.warning("Can't find directory holding Tile Set properties files: " + + descriptions); + } + } + + } + + /** + * Given a URL to a properties file describing a MapTileSet, create it and + * add it to the list. + * + * @param tileSetProperties + * @throws IOException + * @throws MalformedURLException + */ + protected void parseAndAddMapTileSet(URL tileSetProperties) + throws IOException, MalformedURLException { + Properties descProps = new Properties(); + Logger logger = getLogger(); + + logger.info("going to read props"); + InputStream descURLStream = tileSetProperties.openStream(); + descProps.load(descURLStream); + + logger.info("loaded " + tileSetProperties.toString() + " " + descProps.toString()); + + MapTileSet mts = createMapTileSetFromProperties(descProps); + + if (mts != null && mts.allGood()) { + String mtsName = mts.getName(); + mapTileSets.put(mts.getName(), mts); + logger.info("Adding " + mtsName + " dataset"); + } + + descURLStream.close(); + } + + protected MapTileSet createMapTileSetFromProperties(Properties props) { + String className = props.getProperty(MapTileSet.CLASS_ATTRIBUTE); + Logger logger = getLogger(); + if (className == null) { + MapTileSet mts = new StandardMapTileSet(); + mts.setProperties(props); + return mts; + } else { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Creating special map tile set: " + className); + } + try { + Object obj = ComponentFactory.create(className, null, props); + + if (obj instanceof MapTileSet) { + return (MapTileSet) obj; + } else { + logger.fine("Had trouble creating " + + (obj == null ? className : obj.getClass().getName()) + + ", not a MapTileSet"); + } + + } catch (Exception e) { + getLogger().severe("Problem creating " + className + ", " + e.getMessage()); + } + } + + return null; + } + + /** + * Handles + */ + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + OutputStream out = resp.getOutputStream(); + + String pathInfo = req.getPathInfo(); + Logger logger = getLogger(); + if (logger.isLoggable(Level.FINE)) { + logger.fine("received: " + pathInfo); + } + + // Empty path request, let's return summary catalog, might be of some + // help. + if (pathInfo.length() <= 1) { + String tilePathHeader = req.getServerName() + ":" + req.getServerPort() + + req.getContextPath(); + StringBuilder builder = new StringBuilder("Map Tile Sets:

"); + for (MapTileSet mts : mapTileSets.values()) { + String description = mts.getDescription(); + builder.append("Tile set name: "); + builder.append(mts.getName()).append(", description: "); + builder.append(description == null ? "n/a" : description).append("
"); + } + builder.append(""); + + resp.setContentType(HttpConnection.CONTENT_HTML); + OutputStreamWriter osw = new OutputStreamWriter(out); + out.write(builder.toString().getBytes()); + osw.flush(); + return; + } + + MapTileSet mts = getMapTileSetForRequest(pathInfo); + + if (mts != null) { + + if (pathInfo.endsWith("map")) { + String tilePathHeader = req.getServerName() + ":" + req.getServerPort() + + req.getContextPath(); + String map = getMap(tilePathHeader, mts); + resp.setContentType(HttpConnection.CONTENT_HTML); + OutputStreamWriter osw = new OutputStreamWriter(out); + out.write(map.getBytes()); + osw.flush(); + return; + } + + try { + resp.setContentType(HttpConnection.CONTENT_PNG); + byte[] imageData = mts.getImageData(pathInfo); + OutputStreamWriter osw = new OutputStreamWriter(out); + out.write(imageData, 0, imageData.length); + osw.flush(); + } catch (Exception e) { + if (logger.isLoggable(Level.FINE)) { + getLogger().fine("Tile not found: " + pathInfo); + } + HttpConnection.writeHttpResponse(out, HttpConnection.CONTENT_PLAIN, "Problem loading " + + pathInfo + " from map tile set:" + mts.getName()); + } + } else { + HttpConnection.writeHttpResponse(out, HttpConnection.CONTENT_PLAIN, "Map Tile Set not found for request: " + + pathInfo); + } + } + + protected MapTileSet getMapTileSetForRequest(String pathInfo) { + if (pathInfo.startsWith("/")) { + pathInfo = pathInfo.substring(1); + } + + String key = pathInfo; + + // That first part of the path is the MapTileSet name. + int slash = pathInfo.indexOf('/'); + if (slash > 0) { + key = pathInfo.substring(0, slash); + } + + return mapTileSets.get(key); + } + + /** + * Given a starting directory, look for properties files that describe + * MapTileSets. + * + * @author dietrick + */ + private class PropertiesWanderer extends Wanderer implements WandererCallback { + + public PropertiesWanderer(File startingDirectory) { + setCallback(this); + handleEntry(startingDirectory); + } + + /* + * (non-Javadoc) + * + * @see + * com.bbn.openmap.util.wanderer.WandererCallback#handleDirectory(java + * .io.File) + */ + public boolean handleDirectory(File directory) { + // Do nothing to directories + return true; + } + + /* + * (non-Javadoc) + * + * @see + * com.bbn.openmap.util.wanderer.WandererCallback#handleFile(java.io + * .File) + */ + public boolean handleFile(File file) { + getLogger().fine("Checking " + file); + try { + String name = file.getName(); + if (name.endsWith("properties")) { + parseAndAddMapTileSet(file.toURI().toURL()); + } + } catch (MalformedURLException murle) { + getLogger().warning("Unable to read/load " + file + ", murle"); + } catch (IOException e) { + getLogger().warning("Unable to read/load " + file + ", ioe"); + } + return true; + } + + } + + /** + * Holder for this class's Logger. This allows for lazy initialization of + * the logger. + */ + private static final class LoggerHolder { + /** + * The logger for this class + */ + private static final Logger LOGGER = Logger.getLogger(MapTileServlet.class.getName()); + + /** + * Prevent instantiation + */ + private LoggerHolder() { + throw new AssertionError("This should never be instantiated"); + } + } + + /** + * Get the logger for this class. + * + * @return logger for this class + */ + private static Logger getLogger() { + return LoggerHolder.LOGGER; + } + + /** + * Creates a HTML string that will display a Leaflet map with the map tiles + * for the MapTileSet. + * + * @param tileReqHeader the server:port/context string of this servlet. + * @param mts the MapTileSet to display. + * @return html text. + */ + protected String getMap(String tileReqHeader, MapTileSet mts) { + String name = mts.getName(); + + List nameList = new ArrayList(); + nameList.add(name); + for (MapTileSet set : mapTileSets.values()) { + if (!name.equals(set.getName())) { + nameList.add(set.getName()); + } + } + + StringBuilder ret = new StringBuilder(); + + ret.append(""); + ret.append(""); + ret.append("

"); + ret.append(""); + + return ret.toString(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java new file mode 100644 index 00000000..8457c6cd --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileSet.java @@ -0,0 +1,66 @@ +package com.bbn.openmap.servlet.mapTile; + +import com.bbn.openmap.PropertyConsumer; +import com.bbn.openmap.io.FormatException; +import java.io.IOException; + +/** + * The MapTileSet contains all the information for handling a specific set of tiles. It contains a description, key to + * use in the request, the location of the data directory, and how to handle empty tiles. + * + * @author dietrick + */ +public interface MapTileSet + extends PropertyConsumer { + + /** + * Property used for MapTileSet class. + */ + public final static String CLASS_ATTRIBUTE = "class"; + + /** + * Check for MapTileServlet to see if the MapTileSet is configured properly. + * + * @return true if configured. + */ + boolean allGood(); + + /** + * byte array image data for path. + * + * @param pathInfo path for file, in z/x/y format. + * @return byte[] for image data, null if not found. + * @throws IOException + * @throws FormatException + */ + byte[] getImageData(String pathInfo) + throws IOException, FormatException; + + /** + * Return name to use in URL to tell MapTileServlet to get frames from this MapTileSet. + * + * @return name of this map tile set. + */ + public String getName(); + + /** + * Set the name of this map tile set. + * + * @param name + */ + public void setName(String name); + + /** + * Get a description of this tile set. + * + * @return string description. + */ + public String getDescription(); + + /** + * Set the description of this tile set. + * + * @param description + */ + public void setDescription(String description); +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java new file mode 100644 index 00000000..2f5037e0 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/RelayMapTileSet.java @@ -0,0 +1,119 @@ +package com.bbn.openmap.servlet.mapTile; + +import com.bbn.openmap.dataAccess.mapTile.ServerMapTileFactory; +import com.bbn.openmap.io.BinaryBufferedFile; +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.util.PropUtils; +import java.io.IOException; +import java.util.Properties; + +/** + * The RelayMapTileSet contains all the information for handling a specific set of tiles. It contains a description, key + * to use in the request, the location of the data directory or jar. This MapTileSet is able to contact a remote server + * for tiles if the tile file isn't found locally. + *

+ * These properties should be in the properties file referenced in the web.xml file for this tile set: + * + *

+ * name=the-name-of-dataset
+ * class=com.bbn.openmap.maptileservlet.RelayMapTileSet
+ * rootDir=the formatted URL for remote tiles, i.e. http://server.com/{z}/{x}/{y}.png
+ * localCacheRootDir=the local path of the cached tiles, i.e. /data/tiles/{z}/{x}/{y}.png
+ * 
+ * + * As an example, a url for accessing a tile from this server would be: + *
+ * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
+ * 
where ommaptile is the name of the servlet. You can change that in the web.xml and in glassfish/tomcat. + * + * @author dietrick + */ +public class RelayMapTileSet + extends ServerMapTileFactory + implements MapTileSet { + + protected String name; + protected String description = null; + + // To allow the component factory to create it. + public RelayMapTileSet() { + } + + public boolean allGood() { + return name != null && rootDir != null; + } + + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + prefix = PropUtils.getScopedPropertyPrefix(prefix); + + name = props.getProperty(prefix + StandardMapTileSet.NAME_ATTRIBUTE, name); + description = props.getProperty(prefix + StandardMapTileSet.DESCRIPTION_ATTRIBUTE, description); + } + + public Properties getProperties(Properties props) { + props = super.getProperties(props); + String prefix = PropUtils.getScopedPropertyPrefix(this); + props.put(prefix + StandardMapTileSet.NAME_ATTRIBUTE, PropUtils.unnull(name)); + props.put(prefix + StandardMapTileSet.DESCRIPTION_ATTRIBUTE, PropUtils.unnull(name)); + return props; + } + + public byte[] getImageData(String pathInfo) + throws IOException, FormatException { + byte[] imageData = null; + + // We're assuming that all queries are coming in with the name in front, + // along with a slash + if (name != null) { + int index = pathInfo.indexOf(name, 1); + pathInfo = pathInfo.substring(index + name.length()); + } + + // We need to build and check for local file. If not found, then call + // getImageBytes to fetch from other server and cache locally + String localFilePath = null; + TileInfo tInfo = new TileInfo(pathInfo); + + if (!tInfo.valid) { + return imageData; + } + + if (localCacheDir != null) { + localFilePath = buildLocalFilePath(tInfo.x, tInfo.y, tInfo.zoomLevel, getFileExt()); + + try { + + BinaryBufferedFile file = new BinaryBufferedFile(localFilePath); + imageData = file.readBytes(100000, true); + file.close(); + return imageData; + + } catch (IOException ioe) { + // Didn't find local version of file, that's OK. Continue on... + } + } + + // The file wasn't found. + String remoteFilePath = buildFilePath(tInfo.x, tInfo.y, tInfo.zoomLevel, getFileExt()); + imageData = getImageBytes(remoteFilePath, localFilePath); + + return imageData; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java new file mode 100644 index 00000000..203d1051 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/StandardMapTileSet.java @@ -0,0 +1,142 @@ +package com.bbn.openmap.servlet.mapTile; + +import com.bbn.openmap.dataAccess.mapTile.StandardMapTileFactory; +import com.bbn.openmap.image.PNGImageIOFormatter; +import com.bbn.openmap.io.BinaryBufferedFile; +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.util.PropUtils; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; + +/** + * The StandardMapTileSet contains all the information for handling a specific set of tiles. It contains a description, + * key to use in the request, the location of the data directory or jar, and how to handle empty tiles. The + * StandardMapTileSet properties file would look like this: + * + *
+ * name=the-name-of-dataset
+ * # default, don't really need to specify the class property
+ * #class=com.bbn.openmap.maptileservlet.StandardMapTileSet
+ * rootDir=the path to the root of the tile directory, the parent of the z-level directory.
+ * 
+ * + * As an example, a url for accessing a tile from this server would be: + * + *
+ * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
+ * 
+ * + * where ommaptile is the name of the servlet. You can change that in the web.xml and in glassfish/tomcat. + * + * @author dietrick + */ +public class StandardMapTileSet + extends StandardMapTileFactory + implements MapTileSet { + + public final static String NAME_ATTRIBUTE = "name"; + public final static String DESCRIPTION_ATTRIBUTE = "description"; + + protected String name; + protected String description = null; + + // To allow the component factory to create it. + public StandardMapTileSet() { + } + + public boolean allGood() { + return name != null && rootDir != null; + } + + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + prefix = PropUtils.getScopedPropertyPrefix(prefix); + + name = props.getProperty(prefix + NAME_ATTRIBUTE, name); + description = props.getProperty(prefix + DESCRIPTION_ATTRIBUTE, description); + } + + public Properties getProperties(Properties props) { + props = super.getProperties(props); + String prefix = PropUtils.getScopedPropertyPrefix(this); + props.put(prefix + NAME_ATTRIBUTE, PropUtils.unnull(name)); + props.put(prefix + DESCRIPTION_ATTRIBUTE, PropUtils.unnull(description)); + return props; + } + + public byte[] getImageData(String pathInfo) + throws IOException, FormatException { + byte[] imageData = null; + + // We're assuming that all queries are coming in with the name in front, + // along with a slash + if (name != null) { + int index = pathInfo.indexOf(name, 1); + pathInfo = pathInfo.substring(index + name.length()); + } + + String filePath = rootDir + pathInfo; + if (logger.isLoggable(Level.FINE)) { + logger.fine("looking for " + filePath); + } + + try { + + BinaryBufferedFile file = new BinaryBufferedFile(filePath); + imageData = file.readBytes(100000, true); + file.close(); + + } catch (IOException ioe) { + logger.fine("Problem fetching the file"); + // The file wasn't found. + if (emptyTileHandler != null) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Creating " + filePath + " since it wasn't found from the server."); + } + + TileInfo ti = new TileInfo(filePath);// FPBT: used to be + // pathInfo + ti.setMtcTransform(getMtcTransform()); + BufferedImage bufferedImage = ti.getBufferedImage(emptyTileHandler); + + if (bufferedImage != null) { + imageData = new PNGImageIOFormatter().formatImage(bufferedImage); + logger.fine("buffered image created, writing file to disk too"); + File newFile = new File(filePath); + newFile.getParentFile().mkdirs(); + // Write the image data to the local cache location + FileOutputStream fos = new FileOutputStream(newFile); + fos.write(imageData); + fos.flush(); + fos.close(); + } else { + logger.fine("null buffered image back from EmptyTileHandler"); + } + } else { + logger.fine("no empty file handler"); + } + } + + return imageData; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java new file mode 100644 index 00000000..e2592e9a --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/TileInfo.java @@ -0,0 +1,96 @@ +/* + * + * Copyright 2012 BBN Technologies + * + */ +package com.bbn.openmap.servlet.mapTile; + +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.util.logging.Logger; + +import com.bbn.openmap.dataAccess.mapTile.EmptyTileHandler; +import com.bbn.openmap.dataAccess.mapTile.MapTileCoordinateTransform; +import com.bbn.openmap.dataAccess.mapTile.OSMMapTileCoordinateTransform; +import com.bbn.openmap.dataAccess.mapTile.SimpleEmptyTileHandler; +import com.bbn.openmap.proj.Mercator; +import com.bbn.openmap.proj.coords.LatLonPoint; + +/** + * TileInfo can look at a path string and figure out zoom level, x, y for tiles. + * + * @author dietrick + */ +public class TileInfo { + int x; + int y; + int zoomLevel; + String format; + String pathInfo; + MapTileCoordinateTransform mtcTransform; + + boolean valid = false; + + Logger logger = Logger.getLogger("com.bbn.openmap.maptileservlet"); + + public TileInfo(String pathInfo) { + this.pathInfo = pathInfo; + + if (pathInfo == null) { + return; + } + + int dotIndex = pathInfo.lastIndexOf('.'); + if (dotIndex > 0) { + format = pathInfo.substring(dotIndex + 1); + + int ySlashIndex = pathInfo.lastIndexOf('/'); + if (ySlashIndex > 0) { + String yString = pathInfo.substring(ySlashIndex + 1, dotIndex); + + int xSlashIndex = pathInfo.lastIndexOf('/', ySlashIndex - 1); + if (xSlashIndex > 0) { + String xString = pathInfo.substring(xSlashIndex + 1, ySlashIndex); + + int zSlashIndex = pathInfo.lastIndexOf('/', xSlashIndex - 1); + if (zSlashIndex >= 0) { + String zString = pathInfo.substring(zSlashIndex + 1, xSlashIndex); + + // OK, we're here! + x = Integer.parseInt(xString); + y = Integer.parseInt(yString); + zoomLevel = Integer.parseInt(zString); + valid = true; + return; + } + } + } + } + + logger.info("can't decode " + pathInfo); + } + + public BufferedImage getBufferedImage(EmptyTileHandler eth) { + if (eth != null) { + + LatLonPoint center = mtcTransform.tileUVToLatLon(new Point2D.Double(x + .5, y + .5), zoomLevel, new LatLonPoint.Double()); + Mercator merc = new Mercator(center, mtcTransform.getScaleForZoom(zoomLevel), SimpleEmptyTileHandler.TILE_SIZE, SimpleEmptyTileHandler.TILE_SIZE); + logger.fine("going to create empty tile: " + pathInfo + " from " + + eth.getClass().getName()); + + return eth.getImageForEmptyTile(pathInfo, x, y, zoomLevel, getMtcTransform(), merc); + } + return null; + } + + public MapTileCoordinateTransform getMtcTransform() { + if (mtcTransform == null) { + mtcTransform = new OSMMapTileCoordinateTransform(); + } + return mtcTransform; + } + + public void setMtcTransform(MapTileCoordinateTransform mtcTransform) { + this.mtcTransform = mtcTransform; + } +} \ No newline at end of file From d07c4856f0c9d7812798bdc5216f4e8ae8f2af8a Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 19:46:20 +0100 Subject: [PATCH 03/20] Moving the VprBrowse servlet into the core code base. The vpfbrowseservlet code base is for organization and managing the servlet. --- .../servlet/vpfBrowse/ApplyIterator.java | 52 +++ .../openmap/servlet/vpfBrowse/Applyable.java | 24 + .../vpfBrowse/ComplexFeatureJoinRowMaker.java | 112 +++++ .../vpfBrowse/ComplexJoinRowMaker.java | 102 +++++ .../servlet/vpfBrowse/ContextInfo.java | 203 +++++++++ .../bbn/openmap/servlet/vpfBrowse/Data.java | 418 ++++++++++++++++++ .../servlet/vpfBrowse/DescribeDBServlet.java | 311 +++++++++++++ .../servlet/vpfBrowse/DetailRowMaker.java | 247 +++++++++++ .../servlet/vpfBrowse/DirectoryServlet.java | 124 ++++++ .../servlet/vpfBrowse/DispatchServlet.java | 120 +++++ .../servlet/vpfBrowse/DocFileServlet.java | 109 +++++ .../servlet/vpfBrowse/FCSRowMaker.java | 97 ++++ .../servlet/vpfBrowse/FITRowMaker.java | 167 +++++++ .../openmap/servlet/vpfBrowse/HelloWWW.java | 36 ++ .../servlet/vpfBrowse/JoinRowMaker.java | 83 ++++ .../servlet/vpfBrowse/LibraryBean.java | 128 ++++++ .../servlet/vpfBrowse/PlainRowMaker.java | 62 +++ .../servlet/vpfBrowse/ReferenceRowMaker.java | 46 ++ .../openmap/servlet/vpfBrowse/RowMaker.java | 39 ++ .../bbn/openmap/servlet/vpfBrowse/Schema.java | 126 ++++++ .../vpfBrowse/SpatialGraphicServlet.java | 177 ++++++++ .../vpfBrowse/SpatialIndexServlet.java | 165 +++++++ .../vpfBrowse/TableSubsetRecordIterator.java | 66 +++ .../vpfBrowse/ThematicIndexServlet.java | 172 +++++++ .../openmap/servlet/vpfBrowse/TileHolder.java | 202 +++++++++ .../openmap/servlet/vpfBrowse/URLCheck.java | 136 ++++++ .../servlet/vpfBrowse/VDTRowMaker.java | 55 +++ .../servlet/vpfBrowse/VPFHttpServlet.java | 210 +++++++++ .../openmap/servlet/vpfBrowse/VPFTable.java | 49 ++ .../maptileservlet/MBRasterMapTileSet.java | 134 ------ .../maptileservlet/MapTileServlet.java | 387 ---------------- .../openmap/maptileservlet/MapTileSet.java | 66 --- .../maptileservlet/RelayMapTileSet.java | 119 ----- .../maptileservlet/StandardMapTileSet.java | 142 ------ .../bbn/openmap/maptileservlet/TileInfo.java | 96 ---- 35 files changed, 3838 insertions(+), 944 deletions(-) create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java delete mode 100644 src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java new file mode 100644 index 00000000..d0c497f2 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ApplyIterator.java @@ -0,0 +1,52 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.util.Iterator; + +/** + * An Iterator subclass that wraps another iterator. Each element + * returned by the iterator is the result of calling Applyable.apply() + * on the current element of the underlying iterator. + */ +public class ApplyIterator implements Iterator { + /** the iterator to be wrapped */ + final private Iterator wrapped; + /** the Applyable object to use before returning each element */ + final private Applyable applier; + + /** + * Constructor + * + * @param iter the iterator to wrap, may not be null + * @param apply the Applyable object to use in next(), may not be + * null + */ + public ApplyIterator(Iterator iter, Applyable apply) { + wrapped = iter; + applier = apply; + } + + public boolean hasNext() { + return wrapped.hasNext(); + } + + public Object next() { + return applier.apply(wrapped.next()); + } + + public void remove() { + wrapped.remove(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java new file mode 100644 index 00000000..21b29469 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Applyable.java @@ -0,0 +1,24 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +/** + * Applyable interface for use with ApplyIterator. + */ +public interface Applyable { + /** + * The apply method + */ + Object apply(Object obj); +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java new file mode 100644 index 00000000..f2cec06f --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexFeatureJoinRowMaker.java @@ -0,0 +1,112 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.VPFUtil; +import com.bbn.openmap.util.html.TableDataElement; +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A RowMaker that performs the join in a feature index table. + */ +public class ComplexFeatureJoinRowMaker extends PlainRowMaker { + /** a list reused to load primitive rows */ + final List primRow = new ArrayList(); + /** a list reused to load feature rows */ + final List featureRow = new ArrayList(); + + /** the array of feature tables, each index is lazy-initialized */ + final DcwRecordFile[] featureTables; + + /** + * Construct a rowmaker for a complex feature join. + * @param drf the table + * @throws FormatException some error was encountered + */ + public ComplexFeatureJoinRowMaker(DcwRecordFile drf) throws FormatException { + featureTables = getTables(drf); + } + + public void addToRow(TableRowElement row, List l) { + try { + boolean color1 = false; + int i = 0; + for (Iterator li = l.iterator(); li.hasNext(); ) { + Object o = li.next(); + DcwRecordFile featureTable = featureTables[i++]; + if ((featureTable != null) && + featureTable.getRow(featureRow, VPFUtil.objectToInt(o))) { + color1 = !color1; + for (Iterator fi = featureRow.iterator(); fi.hasNext(); ) { + row.addElement(new TableDataElement(color1 ? "CLASS=JoinColumn" : "CLASS=Join2Column", + fi.next().toString())); + } + } else { + row.addElement(o.toString()); + } + } + } catch (FormatException fe) { + row.addElement(fe.toString()); + } + } + + public DcwRecordFile[] getTables(DcwRecordFile drf) throws FormatException { + DcwRecordFile[] retval = new DcwRecordFile[drf.getColumnCount()]; + File dirPath = new File(drf.getTableFile()).getParentFile(); + File fcsfile = new File(dirPath, "fcs"); + if (!fcsfile.canRead()) { + fcsfile = new File(dirPath, "fcs."); + } + DcwRecordFile fcs = new DcwRecordFile(fcsfile.toString()); + List l = new ArrayList(fcs.getColumnCount()); + String tableName = drf.getTableName(); + + int table1Column = fcs.whatColumn("table1"); + int table1_keyColumn = fcs.whatColumn("table1_key"); + int table2Column = fcs.whatColumn("table2"); + int table2_keyColumn = fcs.whatColumn("table2_key"); + + while (fcs.parseRow(l)) { + String table1 = (String)l.get(table1Column); + String table1_key = (String)l.get(table1_keyColumn); + String table2 = (String)l.get(table2Column); + String table2_key = (String)l.get(table2_keyColumn); + if (table1.equalsIgnoreCase(tableName) && + table2_key.equalsIgnoreCase("id")) { + int indexCol = drf.whatColumn(table1_key); + retval[indexCol] = new DcwRecordFile(dirPath + File.separator + table2); + } + } + + fcs.close(); + return retval; + } + + public void close() { + for (int i = 0; i < featureTables.length; i++) { + DcwRecordFile drf = featureTables[i]; + if (drf != null) { + drf.close(); + } + } + } +} + diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java new file mode 100644 index 00000000..b94fcbaa --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ComplexJoinRowMaker.java @@ -0,0 +1,102 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.FeatureClassInfo; +import com.bbn.openmap.util.html.TableDataElement; +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A RowMaker subclass that handles joins between tables, where the + * column guiding the join of the second table is not "id", and thus + * not simply the row identifier. + */ +public class ComplexJoinRowMaker extends PlainRowMaker { + /** the column that contains the foreign key to the primitive table */ + final int theColumn; + /** the column that contains the tile identifier */ + final int tileColumn; + /** a list reused to load join rows */ + final List jtrow = new ArrayList(); + + /** a map from the table key to row id */ + final Map keyMap; + /** the table we're joining with */ + final DcwRecordFile joinTable; + + public ComplexJoinRowMaker(DcwRecordFile table, String joinColumnName, + String tableName, String tableKeyColumn, boolean isTiled) + throws FormatException { + theColumn = table.whatColumn(joinColumnName); + tileColumn = table.whatColumn(FeatureClassInfo.TILE_ID_COLUMN_NAME); + if (isTiled) { + throw new FormatException("can't complex join with tiling (yet)"); + } + joinTable = new DcwRecordFile(new File(table.getTableFile()).getParentFile() + + File.separator + tableName); + keyMap = getKeyMap(tableKeyColumn); + } + + HashMap getKeyMap(String keyColumn) throws FormatException { + int jcol = joinTable.whatColumn(keyColumn); + HashMap retmap = new HashMap(); + while (joinTable.parseRow(jtrow)) { + retmap.put(jtrow.get(jcol), jtrow.get(0)); + } + return retmap; + } + + public void addToRow(TableRowElement row, List l) { + int i = 0; + for (Iterator li = l.iterator(); li.hasNext();) { + Object elt = li.next(); + if (i == theColumn) { + Number wrow = (Number) keyMap.get(elt); +// int tileId = (tileColumn == -1) ? -1 +// : VPFUtil.objectToInt(l.get(tileColumn)); + + try { + if (wrow == null) { + row.addElement("[" + elt + "]"); + } else if (joinTable.getRow(jtrow, wrow.intValue())) { + for (Iterator it = jtrow.iterator(); it.hasNext();) { + row.addElement(new TableDataElement("CLASS=JoinColumn", it.next() + .toString())); + } + } else { + row.addElement("Join failed!"); + } + } catch (FormatException fe) { + row.addElement(fe.toString()); + } + } else { + row.addElement(elt.toString()); + } + i++; + } + } + + public void close() { + joinTable.close(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java new file mode 100644 index 00000000..c2f1e2aa --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java @@ -0,0 +1,203 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import com.bbn.openmap.layer.vpf.LibrarySelectionTable; +import java.io.File; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import javax.servlet.ServletContext; + +/** + * This class holds information retrieved from the ServletContext. + */ +public class ContextInfo { + + /** + * the name of the attribute where ContextInfo objects are in the ServletContext + */ + public static final String CONTEXT_INFO = ContextInfo.class.getPackage().getName() + ".contextInfo"; + /** + * the prefix used to configure VPF libraries in web.xml + */ + public static final String LIBRARY_PREFIX = ContextInfo.class.getPackage().getName() + ".vpf_library."; + + /** + * a map from library name to (String) library path + */ + private Map lib_pathmap; + /** + * a map from library name to LibrarySelectionTable + */ + private Map lib_lstmap; + + /** + * A constructor - use getContextInfo to get one. + * + * @param context the ServletContext to use to initialize + * @see #getContextInfo + */ + private ContextInfo(ServletContext context) { + lib_pathmap = createLibrariesMap(context); + lib_lstmap = new HashMap(); + } + + /** + * Returns the ContextInfo object for the ServletContext. + * + * @param context the ServletContext to either get an existing ContextInfo from, or the context to use to initialize + * a new ContextInfo, if one doesn't already exist for the context. + */ + public static synchronized ContextInfo getContextInfo(ServletContext context) { + ContextInfo ci = (ContextInfo) context.getAttribute(CONTEXT_INFO); + if (ci == null) { + ci = new ContextInfo(context); + context.setAttribute(CONTEXT_INFO, ci); + } + return ci; + } + + /** + * Grovels through the ServletContext initialization parameters and creates a map from library name to library path. + * + * @param context the context to grovel through + */ + private Map createLibrariesMap(ServletContext context) { + HashMap library_map = new HashMap(); + for (Enumeration en = context.getInitParameterNames(); en.hasMoreElements();) { + String s = (String) en.nextElement(); + if (s.startsWith(LIBRARY_PREFIX)) { + String libname = s.substring(LIBRARY_PREFIX.length()); + String path = getPath(context, context.getInitParameter(s)); + if (path != null) { + library_map.put(libname, path); + } else { + context.log("Excluding " + libname + + " from database list, can't resolve path"); + } + + } + } + return Collections.unmodifiableMap(library_map); + } + + /** + * Try and find an absolute path from an init parameter + * + * @param context the context to use to resolve paths + * @param path the path to try and resolve + * @return an absolute path to a file (hopefully a directory) on the system, or null indicating the resolve failed + * to find anything useful. + */ + private String getPath(ServletContext context, String path) { + // try to resolve as a relative path in the war file + try { + String p2 = context.getRealPath(path); + if (p2 != null) { + File f = new File(p2); + if (f.exists()) { + return p2; + } + } + } catch (java.security.AccessControlException jsace) { + // ignore, nothing to do but press on + } + // try to resolve as an absolute path on the system + try { + File f = new File(path); + if (f.exists()) { + return path; + } + } catch (java.security.AccessControlException jsace) { + // ignore, nothing to do + } + return null; + } + + /** + * Return a file object that the path resolves to. Performs some minimal checks to try and prevent an attacker from + * feeding in urls that cause the servlets to climb out of their sandbox. A better option is to use a servlet + * container with the ability to restrict servlet file access. For example, Apache Software Foundation's Tomcat 5 + * Servlet/JSP Container running with the -security flag. + * + * @param pathInfo the path to resolve (expected to be of the form "/library_name_in_web_xml/path/to/file") + * @return a File if it could be resolved, null otherwise + */ + public String resolvePath(String pathInfo) { + if ((pathInfo == null) || (pathInfo.indexOf("..") != -1)) { // don't + // climb + // out + // of + // sandbox + return null; + } + int libStart = pathInfo.indexOf('/') + 1; + int libEnd = pathInfo.indexOf('/', libStart); + if (libEnd == -1) { + libEnd = pathInfo.length(); + } + String libname = pathInfo.substring(libStart, libEnd); + String subpath = pathInfo.substring(libEnd); + + String lib_home = getPath(libname); + if (lib_home == null) { + return null; + } + + return lib_home + "/" + subpath; + } + + /** + * Returns a Set whose values are the (String) names of the configured libraries. + * + * @return a set of library names + */ + public Set keySet() { + return new TreeSet(lib_pathmap.keySet()); + } + + /** + * Returns the path (or null) for the library + * + * @param libname the library name + * @return the path or null + */ + public String getPath(String libname) { + return (String) lib_pathmap.get(libname); + } + + /** + * Returns the LibrarySelectionTable (or null) for the library + * + * @param libname the library name + * @return the LST or null + */ + public LibrarySelectionTable getLST(String libname) { + return (LibrarySelectionTable) lib_lstmap.get(libname); + } + + /** + * Adds an LST for a library + * + * @param libname the library name + * @param lst the LibrarySelectionTable for libname + */ + public void putLST(String libname, LibrarySelectionTable lst) { + lib_lstmap.put(libname, lst); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java new file mode 100644 index 00000000..9083a8aa --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java @@ -0,0 +1,418 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +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; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.util.html.ListElement; +import com.bbn.openmap.util.html.StringElement; +import com.bbn.openmap.util.html.TableHeaderElement; +import com.bbn.openmap.util.html.TableRowElement; +import com.bbn.openmap.util.html.WrapElement; + +/** + * A servlet class that will output table data. + */ +public class Data extends VPFHttpServlet { + /** the name of the http parameter with the table name */ + public static final String VDTParam = "vdt"; + /** the possible values of the rowselect parameter */ + public static final String RowSelectParam = "show"; + public static final String RowSelectAll = "all"; + public static final String RowSelectNone = "none"; + public static final String RowSelectTest = "test"; + /** other parameters that the servlet takes */ + public static final String JoinColumnParam = "colname"; + public static final String JoinOtherTableParam = "othertable"; + public static final String JoinOtherTableKeyParam = "othertablekey"; + public static final String IsTiledParam = "isTiled"; + + /** + * A do-nothing constructor - init does all the work. + */ + public Data() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + DcwRecordFile foo = (DcwRecordFile) request.getAttribute(DispatchServlet.RECORD_FILE_OBJ); + if (foo == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + try { + doWork(request, response, foo); + } catch (FormatException fe) { + response.getWriter().println("FormatException dealing with table: " + + fe); + } + } + + /** + * Generates the heading used for each HTML table + */ + protected TableRowElement generateHeader(HttpServletRequest req, + HttpServletResponse resp, + DcwColumnInfo[] dci) { + TableRowElement thr = new TableRowElement(); + for (int i = 0; i < dci.length; i++) { + DcwColumnInfo dc = dci[i]; + String colName = dc.getColumnName(); + if (dc.getValueDescriptionTable() == null) { + thr.addElement(new TableHeaderElement(colName)); + } else { + StringBuffer baseurl = new StringBuffer(); + baseurl.append(req.getContextPath()); + baseurl.append(req.getServletPath()); + baseurl.append(req.getPathInfo()).append("?"); + String show = req.getParameter(RowSelectParam); + String vdtl = req.getParameter(VDTParam); + if (show != null) { + baseurl.append(RowSelectParam).append("="); + baseurl.append(show).append("&"); + } + baseurl.append(VDTParam).append("="); + if (vdtl == null) { + vdtl = ""; + } + boolean appendCol = true; + boolean needSep = false; + StringTokenizer st = new StringTokenizer(vdtl, ","); + while (st.hasMoreTokens()) { + String sname = st.nextToken(); + if (colName.equals(sname)) { + appendCol = false; + } else { + append(baseurl, sname, needSep); + needSep = true; + } + } + if (appendCol) { + append(baseurl, colName, needSep); + } + thr.addElement(THE(colName, baseurl.toString())); + } + } + return thr; + } + + public static StringBuffer append(StringBuffer base, String app, + boolean needSep) { + return (needSep ? base.append(",") : base).append(app); + } + + public static final String ROWLIST_OBJECT = Data.class.getPackage() + .getName() + + ".rowlist"; + + protected void doWork(HttpServletRequest request, + HttpServletResponse response, DcwRecordFile drf) + throws FormatException, IOException { + DcwColumnInfo dci[] = drf.getColumnInfo(); + + int rowlist[] = (int[]) request.getAttribute(ROWLIST_OBJECT); + + ListElement rows = new ListElement(); + WrapElement table = new WrapElement("table", "BORDER=1 ALIGN=CENTER", rows); + TableRowElement thr = generateHeader(request, response, dci); + rows.addElement(thr); + + String row_show = request.getParameter(RowSelectParam); + boolean printall = RowSelectAll.equals(row_show); + boolean parseall = RowSelectTest.equals(row_show); + boolean schemaonly = RowSelectNone.equals(row_show); + + String baseurl = request.getContextPath() + request.getServletPath() + + request.getPathInfo(); + String all = baseurl + "?" + RowSelectParam + "=" + RowSelectAll; + String none = baseurl + "?" + RowSelectParam + "=" + RowSelectNone; + String some = baseurl; + String test = baseurl + "?" + RowSelectParam + "=" + RowSelectTest; + String qstr = request.getQueryString(); + if (rowlist != null) { + qstr = null; + } + if (qstr == null) { + qstr = VDTParam + "=ALL"; + } + if (qstr.indexOf(VDTParam + "=") == -1) { + qstr += "&" + VDTParam + "=ALL"; + } + String vdtlookup = baseurl + "?" + qstr; + + response.getWriter().println("

Table Data

"); + String redisplay = "Redisplay " + buildHREF(response, all, "All") + + "\r\n|" + buildHREF(response, none, "None") + "\r\n|" + + buildHREF(response, some, "Some") + "\r\n|" + + buildHREF(response, test, "Test") + "\r\n|" + + buildHREF(response, vdtlookup, "All VDT Columns") + "\r\n"; + + if (schemaonly) { + response.getWriter().println("Data Omitted: " + redisplay); + return; + } + + RowMaker rm; + String basepath = getRootDir(request); + String joincol = request.getParameter(JoinColumnParam); + String jointable = request.getParameter(JoinOtherTableParam); + String jointablekey = request.getParameter(JoinOtherTableKeyParam); + if ((joincol != null) && (jointable != null)) { + String isTiledJoin = request.getParameter(IsTiledParam); + boolean isTiled = Boolean.valueOf(isTiledJoin).booleanValue(); + if (Constants.ID.equals(jointablekey)) { + rm = new JoinRowMaker(drf, joincol, jointable, isTiled); + } else { + rm = new ComplexJoinRowMaker(drf, joincol, jointable, jointablekey, isTiled); + } + } else if (drf.getTableName().equals(Constants.charVDTTableName) + || drf.getTableName().equals(Constants.intVDTTableName)) { + rm = new VDTRowMaker(request, response, basepath, drf); + } else if (drf.getTableName().equals("fcs")) { + rm = new FCSRowMaker(request, response, basepath, drf); + } else if (request.getParameter(VDTParam) != null) { + String subsetmarkup = request.getParameter(VDTParam); + String[] ss = null; + if (subsetmarkup != null) { + StringTokenizer st = new StringTokenizer(subsetmarkup, ",", false); + ss = new String[st.countTokens()]; + for (int i = 0; i < ss.length; i++) { + ss[i] = st.nextToken(); + if ("ALL".equals(ss[i])) { + ss = null; // null array gets all VDT lookups + break; + } + } + } + rm = new DetailRowMaker(drf, ss); + } else if (drf.getTableName().endsWith(".fit")) { + rm = new FITRowMaker(drf); + } else if (drf.getTableName().endsWith(".cft") + || drf.getTableName().endsWith(".cjt")) { + rm = new ComplexFeatureJoinRowMaker(drf); + } else { + rm = new PlainRowMaker(); + } + + Iterator rowiter; + if (rowlist != null) { + rowiter = new TableSubsetRecordIterator(rowlist, drf); + } else if (printall) { + rowiter = new TableListIterator(drf); + } else if (parseall) { + rowiter = new TableTestParseIterator(drf); + } else { + rowiter = new TableSampleIterator(drf); + } + // response.getWriter().println("
Tn = " + + // drf.getTableName() + + // "
" + rm.getClass().getName() + " " + + // rowiter.getClass().getName() + "
"); + int rowcount = 0; + while (rowiter.hasNext()) { + if (rowcount++ >= 99) { + response.getWriter().println(redisplay); + table.generate(response.getWriter()); + rows = new ListElement(); + table = new WrapElement("table", "BORDER=1 ALIGN=CENTER", rows); + rows.addElement(new WrapElement("CAPTION", new StringElement("table data"))); + rows.addElement(thr); + + rowcount = 0; + } + rows.addElement(rm.generateRow((List) rowiter.next())); + } + rm.close(); + response.getWriter().println(redisplay); + table.generate(response.getWriter()); + } + + public ContextInfo getContextInfo() { + return contextInfo; + } + + public static String joinURL(HttpServletRequest request, + HttpServletResponse response, int tag, + String filename, String colname, + String othertable, String othertablekey, + boolean isTiled) { + String pathInfo = request.getPathInfo(); + int index = pathInfo.lastIndexOf('/'); + String subpath = pathInfo.substring(0, index + 1); + String url = request.getContextPath() + request.getServletPath() + + subpath + filename + "?" + JoinColumnParam + "=" + colname + + "&" + JoinOtherTableParam + "=" + othertable + "&" + + JoinOtherTableKeyParam + "=" + othertablekey + "&" + + IsTiledParam + "=" + isTiled; + String value = "" + tag + + "\r\n"; + return value; + } + + /** + * An iterator that returns a subset of the table rows + */ + private static class TableSampleIterator implements Iterator { + private final int recordCount; + private final int columnCount; + private int curRow = 0; + private final DcwRecordFile drf; + + public TableSampleIterator(DcwRecordFile drf) throws FormatException { + this.drf = drf; + recordCount = drf.getRecordCount(); + columnCount = drf.getColumnCount(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public boolean hasNext() { + return (curRow < recordCount); + } + + public Object next() { + if (curRow < 10) { + curRow++; + } else if (curRow == 10) { + curRow = 100; + } else { + curRow += 100; + } + if (curRow > recordCount) { + curRow = recordCount; + } + ArrayList al = new ArrayList(columnCount); + try { + if (!drf.getRow(al, curRow)) { + throw new NoSuchElementException(); + } + } catch (FormatException fe) { + throw new NoSuchElementException(); + } + return al; + } + } + + /** + * An iterator that returns a subset of the table rows, but parses + * every record in the table. + */ + private static class TableTestParseIterator implements Iterator { + final ListIterator base; + + public TableTestParseIterator(DcwRecordFile drf) throws FormatException { + base = new TableListIterator(drf); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public boolean hasNext() { + return base.hasNext(); + } + + public Object next() { + int index; + Object ret; + do { + index = base.nextIndex(); + ret = base.next(); + } while ((index > 10) && ((index % 100) != 0) && base.hasNext()); + return ret; + } + } + + /** + * An iterator that will return every row in the table. + */ + private static class TableListIterator implements java.util.ListIterator { + private int curRow = 1; + private final DcwRecordFile drf; + private final int columnCount; + private final int recordCount; + + public TableListIterator(DcwRecordFile drf) throws FormatException { + this.drf = drf; + columnCount = drf.getColumnCount(); + recordCount = drf.getRecordCount(); + } + + public void add(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean hasPrevious() { + return (curRow > 1); + } + + public boolean hasNext() { + return (curRow <= recordCount); + } + + private ArrayList getRow(int row) { + ArrayList al = new ArrayList(columnCount); + try { + if (!drf.getRow(al, row)) { + throw new NoSuchElementException(); + } + } catch (FormatException fe) { + throw new NoSuchElementException(); + } + return al; + } + + public Object next() { + return getRow(curRow++); + } + + public Object previous() { + return getRow(--curRow); + } + + public int nextIndex() { + return curRow; + } + + public int previousIndex() { + return (curRow - 1); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public void set(Object o) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java new file mode 100644 index 00000000..776a63fe --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java @@ -0,0 +1,311 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +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; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.FeatureClassInfo; +import com.bbn.openmap.layer.vpf.LibrarySelectionTable; +import com.bbn.openmap.util.html.HtmlListElement; +import com.bbn.openmap.util.html.ListBodyElement; +import com.bbn.openmap.util.html.ListElement; +import com.bbn.openmap.util.html.WrapElement; + +/** + * This class prints out a description of a VPF database, listing the available + * libraries, coverage types and feature types. + */ + +public class DescribeDBServlet + extends VPFHttpServlet { + /** + * Takes path arguments, and prints the DB it finds + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + + out.println(HTML_DOCTYPE); + out.println(getStylesheetHTML(request)); + + String pathInfo = request.getPathInfo(); + if (pathInfo == null) { + selectDB(request, response); + return; + } + int findex = pathInfo.indexOf('/', 1); + if (findex < 0) { + findex = pathInfo.length(); + } + String libname = pathInfo.substring(1, findex); + + try { + LibrarySelectionTable lst = getLST(libname); + if (lst == null) { + out.println("VPF Database not configured: " + libname); + return; + } + String dbname = lst.getDatabaseName(); + out.println("\nDescribe VPF Database " + dbname + "\n\n

VPF Database " + + dbname + "

\n"); + ListElement dble = new ListBodyElement(); + WrapElement dblist = new WrapElement("ul", dble); + dble.addElement("Database Description: " + lst.getDatabaseDescription()); + dble.addElement("Database Description Table: " + buildURL(request, response, libname, "dht")); + List libraries = lst.getLibraryNames(); + StringBuffer libnames = new StringBuffer("Database Libraries: "); + for (String libName : libraries) { + libnames.append("").append(libName); + libnames.append("").append(" "); + } + libnames.append("(from "); + libnames.append(buildURL(request, response, libname, "lat")); + libnames.append(")"); + + dble.addElement(libnames.toString()); + dblist.generate(out); + for (String libName : libraries) { + // String prefix = libraries[i] + ":"; + printLibrary(request, response, libname, lst.getCAT(libName)); + } + out.println(""); + } catch (FormatException fe) { + throw new ServletException("FormatException: ", fe); + } + } + + public void selectDB(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + PrintWriter out = response.getWriter(); + + Set databases = contextInfo.keySet(); + + out.println("\nSelect VPF Database" + "\n\n

Available VPF Databases" + "

\n"); + HtmlListElement dblist = new HtmlListElement(); + for (Iterator dbi = databases.iterator(); dbi.hasNext();) { + String db = (String) dbi.next(); + String url = request.getContextPath() + "/DescribeVPF/" + db; + dblist.addElement("" + db + "\r\n"); + } + dblist.generate(out); + out.println("\r\n"); + } + + public static String buildURL(HttpServletRequest request, HttpServletResponse response, String filepref, String filename, + String tag) { + String url = request.getContextPath() + "/UnknownType/" + filepref + "/" + filename; + return "" + tag + ""; + } + + public static String buildURL(HttpServletRequest request, HttpServletResponse response, String filepref, String filename) { + return buildURL(request, response, filepref, filename, filename); + } + + /** + * Prints a VPF Library. + * + * @param request the HttpServletRequest. + * @param response the HTTPServletResponse. + * @param pathPrefix lines get printed with this prefix + * @param cat the CoverageAttributeTable (Library) to print + */ + public void printLibrary(HttpServletRequest request, HttpServletResponse response, String pathPrefix, CoverageAttributeTable cat) + throws ServletException, IOException { + PrintWriter out = response.getWriter(); + + if (cat == null) { + out.println("

Catalog doesn't exist

"); + return; + } + String libName = cat.getLibraryName(); + String libpath = pathPrefix + "/" + libName; + + out.println("

Library " + buildURL(request, response, pathPrefix, libName, libName) + + "

"); + String[] coverages = cat.getCoverageNames(); + Arrays.sort(coverages); + + HtmlListElement list = new HtmlListElement(); + list.addElement("Library uses " + (cat.isTiledData() ? "tiled" : "untiled") + " data"); + HtmlListElement clist = new HtmlListElement("Coverage names (from " + buildURL(request, response, libpath, "cat") + ")"); + + list.addElement(clist); + for (int i = 0; i < coverages.length; i++) { + clist.addElement("" + coverages[i] + ""); + } + list.addElement("Library Header Table: " + buildURL(request, response, libpath, "lht")); + list.addElement("Geographic Reference Table: " + buildURL(request, response, libpath, "grt")); + list.generate(out); + for (int i = 0; i < coverages.length; i++) { + printCoverage(request, response, libpath + "/" + coverages[i], libName, cat, coverages[i]); + } + } + + /** + * Prints a VPF Coverage + * + * @param pathPrefix lines get printed with this prefix + * @param cat the CoverageAttributeTable to get the Coverage from + * @param covname the name of the coverage to print + */ + public void printCoverage(HttpServletRequest request, HttpServletResponse response, String pathPrefix, String libName, + CoverageAttributeTable cat, String covname) + throws ServletException, IOException { + PrintWriter out = response.getWriter(); + out.println("

Coverage " + + buildURL(request, response, pathPrefix, "", covname) + " for Library " + libName + + "

"); + HtmlListElement list = new HtmlListElement(); + list.addElement("Description: " + cat.getCoverageDescription(covname)); + list.addElement("Topology Level: " + cat.getCoverageTopologyLevel(covname)); + String fcsURL = buildURL(request, response, pathPrefix, "fcs?" + Data.RowSelectParam + "=" + Data.RowSelectAll, "fcs"); + list.addElement("Feature Class Schema: " + fcsURL); + CoverageTable ct = cat.getCoverageTable(covname); + // CoverageTable opens alot of files, go through and close + // them + for (Iterator i = ct.getFeatureClasses().values().iterator(); i.hasNext();) { + FeatureClassInfo fci = (FeatureClassInfo) i.next(); + fci.close(); + } + + Map ftypeinfo = new TreeMap(ct.getFeatureTypeInfo()); + if (ftypeinfo.size() == 0) { + list.addElement("No Feature Types in FCA"); + } else { + HtmlListElement flist = + new HtmlListElement("Feature Types (from " + buildURL(request, response, pathPrefix, "fca") + ")"); + list.addElement(flist); + for (Iterator i = ftypeinfo.values().iterator(); i.hasNext();) { + CoverageTable.FeatureClassRec fcr = (CoverageTable.FeatureClassRec) i.next(); + String name = fcr.feature_class.toLowerCase(); + // char t = fcr.type; + String desc = fcr.description; + String tstring = "[unknown] "; + String suffix = ""; + switch (fcr.type) { + case CoverageTable.TEXT_FEATURETYPE: + tstring = "[text feature] "; + suffix = ".tft"; + break; + case CoverageTable.EDGE_FEATURETYPE: + tstring = "[edge feature] "; + suffix = ".lft"; + break; + case CoverageTable.AREA_FEATURETYPE: + tstring = "[area feature] "; + suffix = ".aft"; + break; + case CoverageTable.UPOINT_FEATURETYPE: + FeatureClassInfo fci = ct.getFeatureClassInfo(name); + char type = (fci != null) ? fci.getFeatureType() : CoverageTable.SKIP_FEATURETYPE; + if (type == CoverageTable.EPOINT_FEATURETYPE) { + tstring = "[entity point feature] "; + } else if (type == CoverageTable.CPOINT_FEATURETYPE) { + tstring = "[connected point feature] "; + } else { + tstring = "[missing point feature] "; + } + suffix = ".pft"; + break; + case CoverageTable.COMPLEX_FEATURETYPE: + tstring = "[complex feature] "; + suffix = ".cft"; + break; + default: + tstring = "[unknown] "; + suffix = ""; + } + String url = buildURL(request, response, pathPrefix, name + suffix, name); + flist.addElement(url + ": " + tstring + desc); + } + } + try { + HtmlListElement flist = new HtmlListElement("Feature Types (from " + fcsURL + ")"); + boolean generateflist = false; + DcwRecordFile fcs = new DcwRecordFile(ct.getDataPath() + File.separator + "fcs" + (ct.appendDot ? "." : "")); + int featureClassColumn = fcs.whatColumn("feature_class"); + int table1Column = fcs.whatColumn("table1"); + // int table1_keyColumn = fcs.whatColumn("table1_key"); + // int table2Column = fcs.whatColumn("table2"); + // int table2_keyColumn = fcs.whatColumn("table2_key"); + + List fcsl = new ArrayList(fcs.getColumnCount()); + while (fcs.parseRow(fcsl)) { + String featureclass = ((String) fcsl.get(featureClassColumn)).toLowerCase(); + String table1 = ((String) fcsl.get(table1Column)).toLowerCase(); + if (!ftypeinfo.containsKey(featureclass)) { + ftypeinfo.put(featureclass, null); + String type = null; + if (table1.endsWith(".cft")) { + type = "complex feature"; + } else if (table1.endsWith(".pft")) { + type = "point feature"; + } else if (table1.endsWith(".lft")) { + type = "line feature"; + } else if (table1.endsWith(".aft")) { + type = "area feature"; + } else if (table1.endsWith(".tft")) { + type = "text feature"; + } + if (type != null) { + generateflist = true; + flist.addElement(type + " " + buildURL(request, response, pathPrefix, table1, featureclass)); + } + } + } + if (generateflist) { + list.addElement(flist); + } + fcs.close(); + } catch (FormatException fe) { + list.addElement("no fcs"); + } + list.generate(out); + } + + public LibrarySelectionTable getLST(String libname) + throws FormatException { + LibrarySelectionTable lst = contextInfo.getLST(libname); + if (lst == null) { + String lib_home = contextInfo.getPath(libname); + if (lib_home == null) { + return null; + } + // File flib_home = new File(lib_home); + + lst = new LibrarySelectionTable(lib_home); + contextInfo.putLST(libname, lst); + } + return lst; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java new file mode 100644 index 00000000..a7cb9cd7 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DetailRowMaker.java @@ -0,0 +1,247 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.Constants; +import com.bbn.openmap.layer.vpf.CoverageTable; +import com.bbn.openmap.layer.vpf.DcwColumnInfo; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A RowMaker class that will perform VDT (value description table) + * lookups on selected columns in the table. + */ +public class DetailRowMaker extends PlainRowMaker { + final HashMap intvdt; + final HashMap charvdt; + final DcwColumnInfo dcia[]; + + /** + * Constructor + * + * @param drf the table being parsed + * @param markupCols the column names of the columns to attempt + * lookups for + */ + public DetailRowMaker(DcwRecordFile drf, String[] markupCols) { + File pfile = new File(drf.getTableFile()).getParentFile(); + String tableName = drf.getTableName(); + intvdt = loadIntVDT(pfile, tableName); + charvdt = loadCharVDT(pfile, tableName); + DcwColumnInfo dc[] = drf.getColumnInfo(); + if (markupCols == null) { + dcia = dc; + } else { + dcia = new DcwColumnInfo[dc.length]; + for (int i = 0; i < markupCols.length; i++) { + int col = drf.whatColumn(markupCols[i]); + if (col != -1) { + dcia[col] = dc[col]; + } + } + } + } + + public void addToRow(TableRowElement row, List l) { + int i = 0; + for (Iterator vals = l.listIterator(); vals.hasNext();) { + Object rval = vals.next(); + String vdt = (dcia[i] != null) ? dcia[i].getVDT() : null; + if (vdt == null) { + row.addElement(rval.toString()); + } else if (Constants.intVDTTableName.equals(vdt) + && (rval instanceof Number)) { + int val = ((Number) rval).intValue(); + CoverageIntVdt civ = new CoverageIntVdt(dcia[i].getColumnName(), val); + String lval = (String) intvdt.get(civ); + row.addElement((lval == null) ? ("[" + val + "]") : lval); + } else if (Constants.charVDTTableName.equals(vdt) + && (rval instanceof String)) { + String val = (String) rval; + CoverageCharVdt civ = new CoverageCharVdt(dcia[i].getColumnName(), val); + String lval = (String) charvdt.get(civ); + row.addElement((lval == null) ? ("[" + val + "]") : lval); + } else { + row.addElement("Table Data Error!"); + } + i++; + } + } + + private HashMap loadIntVDT(File path, String tableName) { + HashMap hm = new HashMap(); + try { + File vdt = new File(path, Constants.intVDTTableName); + if (vdt.canRead()) { + DcwRecordFile intvdt = new DcwRecordFile(vdt.toString()); + int intcols[] = intvdt.lookupSchema(CoverageTable.VDTColumnNames, + true, + CoverageTable.intVDTschematype, + CoverageTable.intVDTschemalength, + false); + + List al = new ArrayList(intvdt.getColumnCount()); + while (intvdt.parseRow(al)) { + String tab = (String) al.get(intcols[0]); + if (!tableName.equalsIgnoreCase(tab)) { + continue; + } + String attr = (String) al.get(intcols[1]); + int val = ((Number) al.get(intcols[2])).intValue(); + String desc = ((String) al.get(intcols[3])).intern(); + hm.put(new CoverageIntVdt(attr, val), desc); + } + intvdt.close(); + } + } catch (FormatException f) { + } + return hm; + } + + private HashMap loadCharVDT(File path, String tableName) { + HashMap hm = new HashMap(); + try { + File vdt = new File(path, Constants.charVDTTableName); + if (vdt.canRead()) { + DcwRecordFile charvdt = new DcwRecordFile(vdt.toString()); + int charcols[] = charvdt.lookupSchema(CoverageTable.VDTColumnNames, + true, + CoverageTable.charVDTschematype, + CoverageTable.charVDTschemalength, + false); + + ArrayList al = new ArrayList(charvdt.getColumnCount()); + while (charvdt.parseRow(al)) { + String tab = (String) al.get(charcols[0]); + if (!tableName.equalsIgnoreCase(tab)) { + continue; + } + String attr = (String) al.get(charcols[1]); + String val = (String) al.get(charcols[2]); + String desc = ((String) al.get(charcols[3])).intern(); + hm.put(new CoverageCharVdt(attr, val), desc); + } + charvdt.close(); + } + } catch (FormatException f) { + } + return hm; + } +} + +/** + * A utility class used to map information from a VPF feature table to + * its associated value in an int.vdt file. + */ +class CoverageIntVdt { + /** + * the name of the attribute we are looking up (attribute is + * interned) + */ + final String attribute; + /** the integer value we are looking up */ + final int value; + + /** + * Construct a new object + * + * @param a the value for the attribute member + * @param v the value for the value member + */ + public CoverageIntVdt(String a, int v) { + attribute = a.toLowerCase().intern(); + value = v; + } + + /** + * Override the equals method. Two CoverageIntVdts are equal if + * and only iff their respective attribute and value members are + * equal. + */ + public boolean equals(Object o) { + if (o instanceof CoverageIntVdt) { + CoverageIntVdt civ = (CoverageIntVdt) o; + // we can use == rather than String.equals(String) since + // attribute is interned. + return ((attribute == civ.attribute) && (value == civ.value)); + } else { + return false; + } + } + + /** + * Override hashcode. Compute a hashcode based on our member + * values, rather than our (base class) object identity. + */ + public int hashCode() { + return (attribute.hashCode() ^ value); + } +} + +/** + * A utility class used to map information from a VPF feature table to + * its associated value in an char.vdt file. + */ +class CoverageCharVdt { + /** + * the name of the attribute we are looking up (attribute is + * interned) + */ + final String attribute; + /** the character value we are looking up (value is interned) */ + final String value; + + /** + * Construct a new object + * + * @param a the value for the attribute member + * @param v the value for the value member + */ + public CoverageCharVdt(String a, String v) { + attribute = a.toLowerCase().intern(); + value = v.intern(); + } + + /** + * Override the equals method. Two CoverageIntVdts are equal if + * and only iff their respective attribute and value members are + * equal. + */ + public boolean equals(Object o) { + if (o instanceof CoverageCharVdt) { + CoverageCharVdt civ = (CoverageCharVdt) o; + // we can use == rather than String.equals(String) since + // attribute, and value are interned. + return ((attribute == civ.attribute) && (value == civ.value)); + } else { + return false; + } + } + + /** + * Override hashcode. Compute a hashcode based on our member + * values, rather than our (base class) object identity. + */ + public int hashCode() { + return (attribute.hashCode() ^ value.hashCode()); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java new file mode 100644 index 00000000..83f3454e --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java @@ -0,0 +1,124 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +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; + +/** + * This servlet lists the files in a directory of a configured VPF database. + * Directory listing can be disabled, see the listDirectories servlet parameter + * in the deployment descriptor. (web.xml) + */ +public class DirectoryServlet + extends VPFHttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public DirectoryServlet() { + super(); + } + + /** + * false if this servlet should generate a "disabled by administrator" + * method rather than a directory list. + */ + private boolean listFiles; + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); + if (filePath == null) { + String path = setPathInfo(request); + filePath = contextInfo.resolvePath(path); + if (!pathOkay(filePath, path, response)) { + return; + } + } + File fp = new File(filePath); + String pathInfo = getPathInfo(request); + + PrintWriter out = response.getWriter(); + + String filename = fp.getName().toLowerCase(); + + // This was never used!!! + String end = ""; + + response.setContentType("text/html"); + out.println(HTML_DOCTYPE + "\n" + filename + "\r\n\r\n

Directory " + filename + + "

\r\n"); + out.println(getStylesheetHTML(request)); + + if (!listFiles) { + out.println("Directory listing disabled by administrator."); + } else if (!fp.isDirectory()) { + out.println("Requested path is not a directory."); + } else { + out.println(""); + File files[] = fp.listFiles(); + ArrayList filenames = new ArrayList(); + ArrayList directories = new ArrayList(); + for (int i = 0; i < files.length; i++) { + String name = files[i].getName(); + if (files[i].isDirectory()) { + directories.add(name); + } else { + filenames.add(name); + } + } + Collections.sort(directories); + Collections.sort(filenames); + + if (!pathInfo.endsWith("/")) { + pathInfo += '/'; + } + + HtmlListElement filelist = new HtmlListElement("Sub-Directories"); + + for (Iterator dir = directories.iterator(); dir.hasNext();) { + String url = fileURL(request, response, pathInfo, (String) dir.next()); + filelist.addElement(url); + } + filelist.generate(out); + + filelist = new HtmlListElement("Files"); + for (Iterator file = filenames.iterator(); file.hasNext();) { + String url = fileURL(request, response, pathInfo, (String) file.next()); + filelist.addElement(url); + } + filelist.generate(out); + } + out.println(end); + } + + public void init(ServletConfig config) + throws ServletException { + super.init(config); + listFiles = Boolean.valueOf(config.getInitParameter("listDirectories")).booleanValue(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java new file mode 100644 index 00000000..f43e6a05 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java @@ -0,0 +1,120 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * This class infers the format of a VPF file from the name of the file, and + * dispatches to the appropriate servlet for that type. + * + * This could probably also be handled by a long set of servlet-mapping tags in + * the deployment descriptor. (web.xml) + */ +public class DispatchServlet + extends VPFHttpServlet { + public static final String RECORD_FILE_OBJ = "com.bbn.openmap.vpf_tools.table_obj"; + public static final String ROOTPATH_FILENAME = "com.bbn.openmap.vpf_tools.url_path"; + + /** + * A do-nothing constructor - init does all the work. + */ + public DispatchServlet() { + super(); + } + + /** + * Just a test main to parse vpf datafiles + * + * param args files to parse, plus other command line flags + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String pathInfo = setPathInfo(request); + String rootpath = contextInfo.resolvePath(pathInfo); + if (!pathOkay(rootpath, pathInfo, response)) { + return; + } + + PrintWriter out = response.getWriter(); + File rp = new File(rootpath); + String filename = rp.getName().toLowerCase(); + + String end = "\r\n"; + + // ByteArrayOutputStream bos = new ByteArrayOutputStream(); + // PrintStream s = new PrintStream(bos); + // System.setOut(s); + + request.setAttribute(ROOTPATH_FILENAME, rootpath); + + try { + if (rp.isDirectory()) { + RequestDispatcher rd = request.getRequestDispatcher("/DirectoryList"); + rd.forward(request, response); + return; + } else if (filename.endsWith("x") || filename.endsWith("x.")) { + response.setContentType("text/html"); + out.println(HTML_DOCTYPE + "" + filename + "\r\n\r\n

Table " + filename + + "

\r\n"); + out.println(getStylesheetHTML(request)); + out.println("Skipping VLI format - this format is simply an index to find rows in a corresponding table file, it isn't very interesting to look at so its getting skipped."); + } else if (filename.endsWith("ti")) { + RequestDispatcher rd = request.getRequestDispatcher("/Thematic"); + rd.forward(request, response); + } else if (filename.endsWith("si") || filename.endsWith("si.")) { + RequestDispatcher rd = request.getRequestDispatcher("/SpatialIndex"); + rd.forward(request, response); + } else if (filename.endsWith(".doc")) { + RequestDispatcher rd = request.getRequestDispatcher("/DocFile"); + rd.forward(request, response); + } else { + response.setContentType("text/html"); + out.println(HTML_DOCTYPE + "\n" + filename + "\r\n\r\n

Table " + + filename + "

\r\n"); + out.println(getStylesheetHTML(request)); + DcwRecordFile foo = new DcwRecordFile(rootpath); + request.setAttribute(RECORD_FILE_OBJ, foo); + RequestDispatcher rd = request.getRequestDispatcher("/Schema"); + rd.include(request, response); + RequestDispatcher rd2 = request.getRequestDispatcher("/Data"); + rd2.include(request, response); + + foo.close(); + } + } catch (FormatException f) { + throw new ServletException("Format Error: ", f); + } + // s.close(); + out.println("
");
+        out.println("Context Path: " + request.getContextPath());
+        out.println("PathInfo: " + request.getPathInfo());
+        out.println("ServletPath: " + request.getServletPath());
+        out.println("Query String: " + request.getQueryString());
+        // out.print(bos.toString());
+        out.println("
" + end); + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java new file mode 100644 index 00000000..ff66e676 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java @@ -0,0 +1,109 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * This class handles displaying VPF .doc files + */ +public class DocFileServlet + extends VPFHttpServlet { + /** the columns we need from a VPF doc file */ + static final String FieldColumns[] = { + "text" + }; + /** the fields in a VPF doc file we need */ + static final char[] FieldTypeSchema = { + 'T' + }; + /** the field lengths in a VPF doc file we need */ + static final int[] FieldLengthSchema = { + -1 + }; + + /** + * A do-nothing constructor - init does all the work. + */ + public DocFileServlet() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); + if (filePath == null) { + String pathInfo = setPathInfo(request); + filePath = contextInfo.resolvePath(pathInfo); + if (!pathOkay(filePath, pathInfo, response)) { + return; + } + } + + DcwRecordFile docfile = null; + try { + docfile = new DcwRecordFile(filePath); + } catch (FormatException fe) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, " docfile not found"); + return; + } + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println(HTML_DOCTYPE); + out.println(getStylesheetHTML(request)); + + String tableName = docfile.getTableName(); + out.println(""); + String title = "VPF Documentation File " + tableName; + out.println("" + title + ""); + out.println("

" + title + "

"); + + try { + docfile.lookupSchema(FieldColumns, true, FieldTypeSchema, FieldLengthSchema, false); + } catch (FormatException fe) { + out.println("The documentation file appears to be invalid."); + RequestDispatcher rd = request.getRequestDispatcher("/Schema"); + rd.include(request, response); + out.println(""); + docfile.close(); + return; + } + + ArrayList al = new ArrayList(FieldTypeSchema.length); + out.println("
");
+        try {
+            while (docfile.parseRow(al)) {
+                out.println("   " + al.get(1).toString());
+            }
+            out.println("
"); + } catch (FormatException fe) { + out.println("/pre>"); + out.println("File Format Exception processing data: " + fe); + } + out.println(""); + docfile.close(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java new file mode 100644 index 00000000..6ee6df81 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java @@ -0,0 +1,97 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * A RowMaker class specifically for the markup of VPF feature class schema + * (fcs) files. + */ +public class FCSRowMaker extends ReferenceRowMaker { + /** the length of a row (number of columns) */ + final int rowLen; + /** the directory of the file being read */ + final File drfp; + final String basepath; + final int idCol; + final int featureClassCol; + final int table1Col; + final int table1keyCol; + final int table2Col; + final int table2keyCol; + + public FCSRowMaker(HttpServletRequest request, + HttpServletResponse response, + String basepath, DcwRecordFile drf) { + super(request, response); + this.rowLen = drf.getColumnCount(); + this.basepath = basepath; + this.drfp = new File(drf.getTableFile()).getParentFile(); + idCol = drf.whatColumn(Constants.ID); + featureClassCol = drf.whatColumn(Constants.FCS_FEATURECLASS); + table1Col = drf.whatColumn(Constants.FCS_TABLE1); + table1keyCol = drf.whatColumn(Constants.FCS_TABLE1KEY); + table2Col = drf.whatColumn(Constants.FCS_TABLE2); + table2keyCol = drf.whatColumn(Constants.FCS_TABLE2KEY); + } + + public void addToRow(TableRowElement row, List l) { + int rv = ((Number)l.get(idCol)).intValue(); + String table1 = ((String)l.get(table1Col)).toLowerCase(); + String table1key = ((String)l.get(table1keyCol)).toLowerCase(); + String table2 = ((String)l.get(table2Col)).toLowerCase(); + String table2key = ((String)l.get(table2keyCol)).toLowerCase(); + File fn = new File(drfp, table1); + File otf = new File(drfp, table2); + boolean tiled = !otf.exists(); + for (int i = 0; i < rowLen; i++) { + if (i == idCol) { + if (fn.exists()) { + row.addElement(Data.joinURL(request, response, + rv, table1, + table1key, table2, + table2key, + tiled)); + } else { + row.addElement(Integer.toString(rv)); + } + } else if ((i==table1Col) || (i==table2Col)) { + String tablename = ((String)l.get(i)).toLowerCase(); + if (new File(drfp, tablename).exists()) { + row.addElement(fileURL(basepath, tablename)); +// } else if (Constants.endTableName.equals(tablename) || +// Constants.cndTableName.equals(tablename) || +// Constants.faceTableName.equals(tablename) || +// "edg".equals(tablename) || +// "txt".equals(tablename)) { +// TileHolder ta = new TileHolder(new File(basepath), tablename, true); +// row.addElement(tablename); + } else { + row.addElement(tablename); + } + } else { + row.addElement(l.get(i).toString().toLowerCase()); + } + } + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java new file mode 100644 index 00000000..8a4d3c03 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FITRowMaker.java @@ -0,0 +1,167 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.VPFUtil; +import com.bbn.openmap.util.html.TableDataElement; +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A RowMaker that performs the join in a feature index table. + */ +public class FITRowMaker extends PlainRowMaker { + /** a list reused to load primitive rows */ + final List primRow = new ArrayList(); + /** a list reused to load feature rows */ + final List featureRow = new ArrayList(); + + /** the array of feature tables, each index is lazy-initialized */ + final DcwRecordFile[] featureTables; + /** the array of feature names for the coverage */ + final String[] featureNames; + + /** the utility class that understands tiled and untiled data */ + final TileHolder tiler; + + /** the column in the FIT that specifies the primitive id */ + final int primIdColumn; + /** the column in the FIT that specifies the tile id (may be -1) */ + final int tileIdColumn; + /** the column in the FIT that specifies the feature class id */ + final int fcIdColumn; + /** the column in the FIT that specifies the feature id */ + final int featureIdColumn; + /** the path for the coverage */ + final File dirPath; + /** the extension (e.g. .lft) used for feature table names */ + final String featureTableExt; + + /** + * Construct a rowmaker for a feature index table. + * + * @param drf the feature index table + * @throws FormatException some error was encountered + */ + public FITRowMaker(DcwRecordFile drf) throws FormatException { + String tableName = drf.getTableName().substring(0, 3); + dirPath = new File(drf.getTableFile()).getParentFile(); + + featureTableExt = getExtensionForTable(tableName); + + primIdColumn = drf.whatColumn("prim_id"); + tileIdColumn = drf.whatColumn("tile_id"); + fcIdColumn = drf.whatColumn("fc_id"); + featureIdColumn = drf.whatColumn("feature_id"); + + tiler = new TileHolder(dirPath, tableName, (tileIdColumn != -1)); + featureNames = getFeatureNames(dirPath); + featureTables = new DcwRecordFile[featureNames.length]; + } + + /** + * Returns the feature table that corresponds to the feature class + * ID. + * + * @param fcId the feature class ID + * @return the feature table + * @throws FormatException the feature table couldn't be created + */ + public DcwRecordFile getFeatureTable(int fcId) throws FormatException { + fcId -= 1; // array is 0-based, table ids are 1-based + DcwRecordFile retval = featureTables[fcId]; + if (retval == null) { + retval = new DcwRecordFile(dirPath + File.separator + + featureNames[fcId].toLowerCase() + featureTableExt); + featureTables[fcId] = retval; + } + return retval; + } + + public void addToRow(TableRowElement row, List l) { + int primId = VPFUtil.objectToInt(l.get(primIdColumn)); + int tileId = (tileIdColumn == -1) ? -1 + : VPFUtil.objectToInt(l.get(tileIdColumn)); + int fcId = VPFUtil.objectToInt(l.get(fcIdColumn)); + int featureId = VPFUtil.objectToInt(l.get(featureIdColumn)); + int id = VPFUtil.objectToInt(l.get(0)); + row.addElement("" + id + " (" + tileId + "," + primId + ") (" + fcId + + ", " + featureId + ")"); + try { + tiler.getRow(tileId, primId, primRow); + DcwRecordFile featureTable = getFeatureTable(fcId); + featureTable.getRow(featureRow, featureId); + for (Iterator i = primRow.iterator(); i.hasNext();) { + row.addElement(new TableDataElement("CLASS=JoinColumn", i.next() + .toString())); + } + for (Iterator i = featureRow.iterator(); i.hasNext();) { + row.addElement(new TableDataElement("CLASS=Join2Column", i.next() + .toString())); + } + } catch (FormatException fe) { + row.addElement(fe.toString()); + } + } + + public String[] getFeatureNames(File dirPath) throws FormatException { + File fcafile = new File(dirPath, "fca"); + if (!fcafile.canRead()) { + fcafile = new File(dirPath, "fca."); + } + DcwRecordFile fca = new DcwRecordFile(fcafile.toString()); + List l = new ArrayList(fca.getColumnCount()); + int fclassColumn = fca.whatColumn("fclass"); + List fclassnames = new ArrayList(); + while (fca.parseRow(l)) { + fclassnames.add(l.get(fclassColumn)); + } + fca.close(); + String retval[] = new String[fclassnames.size()]; + fclassnames.toArray(retval); + return retval; + } + + public static String getExtensionForTable(String tablename) { + + if (tablename.equals("fac")) { + return ".aft"; + } else if (tablename.equals("cnd")) { + return ".pft"; + } else if (tablename.equals("end")) { + return ".pft"; + } else if (tablename.equals("txt")) { + return ".tft"; + } else if (tablename.equals("edg")) { + return ".lft"; + } + return null; + } + + public void close() { + tiler.close(); + for (int i = 0; i < featureTables.length; i++) { + DcwRecordFile drf = featureTables[i]; + if (drf != null) { + drf.close(); + } + } + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java new file mode 100644 index 00000000..2a2c62ba --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java @@ -0,0 +1,36 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +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 + */ +public class HelloWWW extends HttpServlet { + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + String docType = "\n"; + out.println(docType + + "\nHello WWW\n\n

Hello WWW

\n\n"); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java new file mode 100644 index 00000000..9dc6b28c --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/JoinRowMaker.java @@ -0,0 +1,83 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.FeatureClassInfo; +import com.bbn.openmap.layer.vpf.TilingAdapter; +import com.bbn.openmap.util.html.TableDataElement; +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A RowMaker subclass that handles simple joins between tables. + */ +public class JoinRowMaker extends PlainRowMaker { + /** the column that contains the foreign key to the primitive table */ + final int theColumn; + /** the column that contains the tile identifier */ + final int tileColumn; + /** a list reused to load primitive rows */ + final List jtrow = new ArrayList(); + + /** the utility class that understands tiled and untiled data */ + final TileHolder tiler; + final TilingAdapter ta; + + public JoinRowMaker(DcwRecordFile table, String joinColumnName, + String tableName, boolean isTiled) throws FormatException { + theColumn = table.whatColumn(joinColumnName); + tileColumn = isTiled ? table.whatColumn(FeatureClassInfo.TILE_ID_COLUMN_NAME) + : -1; + ta = table.getTilingAdapter(tileColumn, theColumn); + tiler = new TileHolder(new File(table.getTableFile()).getParentFile(), tableName, isTiled); + } + + public void addToRow(TableRowElement row, List l) { + int i = 0; + for (Iterator li = l.iterator(); li.hasNext();) { + Object elt = li.next(); + if (i == theColumn) { + int whatrow = ta.getTilePrimId(l); + int tileId = ta.getTileId(l); + try { + if (tiler.getRow(ta, l, jtrow)) { + for (Iterator it = jtrow.iterator(); it.hasNext();) { + row.addElement(new TableDataElement("CLASS=JoinColumn", it.next() + .toString())); + } + } else { + row.addElement("Join failed! [" + elt + "]" + "(" + + tileId + "," + whatrow + ")"); + } + } catch (FormatException fe) { + row.addElement(fe.toString() + "(" + tileId + "," + whatrow + + ")"); + } + } else { + row.addElement(elt.toString()); + } + i++; + } + } + + public void close() { + tiler.close(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java new file mode 100644 index 00000000..1fa23776 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java @@ -0,0 +1,128 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.LibrarySelectionTable; + +/** + * This class prints out a description of a VPF database, listing the + * available libraries, coverage types and feature types. + */ +public class LibraryBean { + private LibrarySelectionTable lst; + private HttpServletRequest request; + private HttpServletResponse response; + + public void setContext(ServletContext c) { + contextInfo = ContextInfo.getContextInfo(c); + } + + public void setResponse(HttpServletResponse r) { + response = r; + } + + public HttpServletRequest getRequest() { + return request; + } + + public void setRequest(HttpServletRequest request) { + this.request = request; + } + + public HttpServletResponse getResponse() { + return response; + } + + public LibrarySelectionTable getLst() { + return lst; + } + + public String getLibName() { + return (lst == null) ? "unknown" : lst.getDatabaseName(); + } + + public void setPath(String pathInfo) { + if (pathInfo == null) { + return; + } + int findex = pathInfo.indexOf('/', 1); + if (findex < 0) { + findex = pathInfo.length(); + } + String libname = pathInfo.substring(0, findex); + + try { + lst = getLST(libname); + if (lst == null) { + return; + } + // String dbname = lst.getDatabaseName(); + // out.println("\nDescribe VPF Database + // " + + // dbname + "\n\n

VPF Database " + + // dbname + "

\n"); + // ListElement dble = new ListBodyElement(); + // WrapElement dblist = new WrapElement("ul", dble); + // dble.addElement("Database Description: " + + // lst.getDatabaseDescription()); + // dble.addElement("Database Description Table: " + + // buildURL(request, response, libname, "dht")); + // String[] libraries = lst.getLibraryNames(); + // StringBuffer libnames = new StringBuffer("Database + // Libraries: "); + // for (int i = 0; i < libraries.length; i++) { + // libnames.append("").append(libraries[i]); + // libnames.append("").append(" "); + // } + // libnames.append("(from "); + // libnames.append(buildURL(request, response, libname, + // "lat")); + // libnames.append(")"); + + // dble.addElement(libnames.toString()); + // dblist.generate(out); + // for (int i = 0; i < libraries.length; i++) { + // String prefix = libraries[i] + ":"; + // printLibrary(request, response, libname, + // lst.getCAT(libraries[i])); + // } + // out.println(""); + } catch (FormatException fe) { + // throw new ServletException("FormatException: " , fe); + } + } + + /** the context object used for config info */ + protected ContextInfo contextInfo; + + public LibrarySelectionTable getLST(String libname) throws FormatException { + LibrarySelectionTable lst = contextInfo.getLST(libname); + if (lst == null) { + String lib_home = contextInfo.getPath(libname); + if (lib_home == null) { + return null; + } + + lst = new LibrarySelectionTable(lib_home); + contextInfo.putLST(libname, lst); + } + return lst; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java new file mode 100644 index 00000000..f168fcec --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/PlainRowMaker.java @@ -0,0 +1,62 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.util.html.TableRowElement; + +/** + * A basic RowMaker that makes rows. + */ +public class PlainRowMaker implements RowMaker { + + /** + * A basic constructor that doesn't do anything special. + */ + public PlainRowMaker() {} + + /** + * Generates a TableRowElement from a table by creating a new + * TableRow and passing it and the list to addToRow, then + * returning the new row. + * + * @param l the VPF table row + * @return a HTML representation of the VPF row + */ + public TableRowElement generateRow(List l) { + TableRowElement tr = new TableRowElement(); + addToRow(tr, l); + return tr; + } + + /** + * Adds the elements of the list to the table row + * + * @param row the HTML row + * @param l the VPF row + */ + public void addToRow(TableRowElement row, List l) { + for (Iterator li = l.iterator(); li.hasNext();) { + row.addElement(li.next().toString()); + } + } + + /** + * An empty implementation, since this class doesn't hold any + * resources. + */ + public void close() {} +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java new file mode 100644 index 00000000..59bfba15 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java @@ -0,0 +1,46 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * A RowMaker class that retains references to the HttpServletRequest + * and HttpServletResponse instances of the request. + */ +public abstract class ReferenceRowMaker extends PlainRowMaker { + /** the servlet request object */ + final protected HttpServletRequest request; + /** the servlet response object */ + final protected HttpServletResponse response; + + public ReferenceRowMaker(HttpServletRequest request, + HttpServletResponse response) { + this.request = request; + this.response = response; + } + + public String toURL(String servletName, String pathname, String filename) { + return VPFHttpServlet.toURL(request, + response, + servletName, + pathname, + filename); + } + + public String fileURL(String pathname, String filename) { + return VPFHttpServlet.fileURL(request, response, pathname, filename); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java new file mode 100644 index 00000000..d24ec705 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/RowMaker.java @@ -0,0 +1,39 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.util.List; + +import com.bbn.openmap.util.html.TableRowElement; + +/** + * An interface used to generate rows of an (html) table from a (VPF) + * table. + */ +public interface RowMaker { + /** + * Generate an HTML table row from a vpf table row + * + * @param row the VPF table row + * @return the HTML representation + */ + public TableRowElement generateRow(List row); + + /** + * Used to indicate that no more calls to addList will be made. + * (implementation may want to reclaim resources without waiting + * for the finalizer to run.) + */ + public void close(); +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java new file mode 100644 index 00000000..fa286d2a --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java @@ -0,0 +1,126 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; +import com.bbn.openmap.util.html.ListElement; +import com.bbn.openmap.util.html.StringElement; +import com.bbn.openmap.util.html.TableRowElement; +import com.bbn.openmap.util.html.WrapElement; + +/** + * A servlet class that will print the schema for a VPF table. + */ +public class Schema extends VPFHttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public Schema() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + DcwRecordFile foo = (DcwRecordFile) request.getAttribute(DispatchServlet.RECORD_FILE_OBJ); + if (foo == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + String basepath = getRootDir(request); + String url = response.encodeURL(request.getContextPath() + + "/VPFHelp.jsp?topic=table_schema"); + PrintWriter out = response.getWriter(); + out.println("

Table Schema

"); + out.println("

General Table Information

"); + HtmlListElement list = new HtmlListElement(); + list.addElement("Table Name: " + foo.getTableName()); + list.addElement("Table Description: " + foo.getDescription()); + list.addElement("DocFile Name: " + + fileURL(request, + response, + basepath, + foo.getDocumentationFilename())); + int reclen = foo.getRecordLength(); + String reclenstr = (reclen == -1) ? ("variable") + : (Integer.toString(reclen) + " bytes"); + list.addElement("Record Length: " + reclenstr); + try { + list.addElement("Record Count: " + foo.getRecordCount()); + } catch (com.bbn.openmap.io.FormatException fe) { + list.addElement("Record Count Error: " + fe.toString()); + } + list.generate(out); + + // out.println("

Column Schema

"); + ListElement rows = new ListElement(); + WrapElement table = new WrapElement("table", "BORDER=1", rows); + TableRowElement thr = new TableRowElement(); + rows.addElement(new WrapElement("CAPTION", new StringElement("Column Schema"))); + rows.addElement(thr); + thr.addElement(THE("#", url)); + thr.addElement(THE("Name", url)); + thr.addElement(THE("Type", url)); + thr.addElement(THE("Count", url)); + thr.addElement(THE("Key Type", url)); + thr.addElement(THE("Description", url)); + thr.addElement(THE("VDT", url)); + thr.addElement(THE("Thematic Index", url)); + thr.addElement(THE("DocFile", url)); + DcwColumnInfo dci[] = foo.getColumnInfo(); + for (int i = 0; i < dci.length; i++) { + TableRowElement tr = new TableRowElement(); + rows.addElement(tr); + tr.addElement(Integer.toString(i)); + tr.addElement(dci[i].getColumnName()); + tr.addElement(String.valueOf(dci[i].getFieldType())); + int elts = dci[i].getNumberOfElements(); + tr.addElement(elts == -1 ? "*" : Integer.toString(elts)); + tr.addElement(String.valueOf(dci[i].getKeyType())); + tr.addElement(dci[i].getColumnDescription()); + tr.addElement(fileURL(request, response, basepath, dci[i].getVDT())); + tr.addElement(thematicURL(request, + response, + basepath, + dci[i].getThematicIndexName())); + tr.addElement(docURL(request, + response, + basepath, + dci[i].getNarrativeTable())); + } + table.generate(response.getWriter()); + } + + public static String thematicURL(HttpServletRequest request, + HttpServletResponse response, + String pathname, String filename) { + return toURL(request, response, "/Thematic", pathname, filename); + } + + public static String docURL(HttpServletRequest request, + HttpServletResponse response, String pathname, + String filename) { + return toURL(request, response, "/DocFile", pathname, filename); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java new file mode 100644 index 00000000..302b9ef7 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java @@ -0,0 +1,177 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * This servlet generates HTML for VPF files in spatial index format. + */ +public class SpatialGraphicServlet extends VPFHttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public SpatialGraphicServlet() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); + if (filePath == null) { + String pathInfo = setPathInfo(request); + filePath = contextInfo.resolvePath(pathInfo); + if (!pathOkay(filePath, pathInfo, response)) { + return; + } + } + + response.setContentType("image/gif"); + + int width = 200; + int height = 200; + int imageType = BufferedImage.TYPE_INT_ARGB; + BufferedImage bufferedImage = new BufferedImage(width, height, imageType); + Graphics2D g2d = bufferedImage.createGraphics(); + g2d.setClip(0, 0, width, height); + g2d.setColor(Color.red); + g2d.drawLine(10, 10, 95, 95); + g2d.drawLine(105, 105, 190, 190); + g2d.drawRect(1, 1, 198, 198); + g2d.dispose(); + // byte [] imageData = AcmeGifHelper.encodeGif(bufferedImage); + + // ServletOutputStream sos = response.getOutputStream(); + // sos.write(imageData); + + String filename = filePath; + String tableMatch = getIndexedTable(filename); + if (tableMatch == null) { + tableMatch = "non-standard spatial index"; + } else { + tableMatch = fileURL(request, + response, + getRootDir(request), + tableMatch); + } + + try { + DcwSpatialIndex ff = new DcwSpatialIndex(filePath.toString(), false); + printSpatial(request, response, ff); + ff.close(); + } catch (FormatException fe) { + } + } + + public void printSpatial(HttpServletRequest request, + HttpServletResponse response, DcwSpatialIndex si) + throws com.bbn.openmap.io.FormatException, IOException { + int width = 200; + int height = 200; + int imageType = BufferedImage.TYPE_INT_ARGB; + BufferedImage bufferedImage = new BufferedImage(width, height, imageType); + Graphics2D g2d = bufferedImage.createGraphics(); + g2d.setClip(0, 0, width, height); + g2d.setColor(Color.red); + g2d.drawLine(10, 10, 95, 95); + g2d.drawLine(105, 105, 190, 190); + g2d.drawRect(1, 1, 198, 198); + g2d.dispose(); + // byte [] imageData = AcmeGifHelper.encodeGif(bufferedImage); + + // ServletOutputStream sos = response.getOutputStream(); + // sos.write(imageData); + + HtmlListElement list = new HtmlListElement(); + list.addElement("Number Of Primitives: " + si.getNumberOfPrimitives()); + int nodesInTree = si.getNodesInTree(); + list.addElement("Nodes in Tree: " + nodesInTree); + list.addElement("Bounding Rectangle: (" + si.getBoundingX1() + ", " + + si.getBoundingY1() + ") - (" + si.getBoundingX2() + ", " + + si.getBoundingY2() + ")"); + TableRowElement columnNames = new TableRowElement(); + columnNames.addElement(new TableHeaderElement("Primitive ID")); + columnNames.addElement(new TableHeaderElement("x1")); + columnNames.addElement(new TableHeaderElement("x2")); + columnNames.addElement(new TableHeaderElement("y1")); + columnNames.addElement(new TableHeaderElement("y2")); + for (int i = 0; i < nodesInTree; i++) { + int count = si.getPrimitiveCount(i); + //int offset = si.getPrimitiveOffset(i); + DcwSpatialIndex.PrimitiveRecord pr[] = si.getPrimitiveRecords(i); + + if (count == 0) { + } else { + ListElement rows = new ListElement(); + //WrapElement table = new WrapElement("table", "BORDER=1", rows); + rows.addElement(columnNames); + for (int j = 0; j < pr.length; j++) { + DcwSpatialIndex.PrimitiveRecord pr1 = pr[j]; + TableRowElement datarow = new TableRowElement(); + rows.addElement(datarow); + datarow.addElement(Integer.toString(pr1.primId)); + datarow.addElement(Short.toString(pr1.x1)); + datarow.addElement(Short.toString(pr1.x2)); + datarow.addElement(Short.toString(pr1.y1)); + datarow.addElement(Short.toString(pr1.y2)); + } + } + } + } + + /** a map from spatial index name to primitive file indexed */ + private HashMap indexTableMap; + + /** + * Returns the name of the primitive file that the spatial index + * is for. + * + * @param indexName the name of the index + * @return the name of the primitive file + */ + public String getIndexedTable(String indexName) { + if (indexTableMap == null) { + HashMap newMap = new HashMap(); + newMap.put("esi", "edg"); + newMap.put("esi.", "edg."); + newMap.put("fsi", "fac"); + newMap.put("fsi.", "fac."); + newMap.put("csi", "cnd"); + newMap.put("csi.", "cnd."); + newMap.put("nsi", "end"); + newMap.put("nsi.", "end."); + newMap.put("tsi", "txt"); + newMap.put("tsi.", "txt."); + indexTableMap = newMap; + } + return (String) indexTableMap.get(indexName); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java new file mode 100644 index 00000000..7bda130a --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java @@ -0,0 +1,165 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; +import com.bbn.openmap.util.html.ListElement; +import com.bbn.openmap.util.html.TableHeaderElement; +import com.bbn.openmap.util.html.TableRowElement; +import com.bbn.openmap.util.html.WrapElement; + +/** + * This servlet generates HTML for VPF files in spatial index format. + */ +public class SpatialIndexServlet extends VPFHttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public SpatialIndexServlet() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); + if (filePath == null) { + String pathInfo = setPathInfo(request); + filePath = contextInfo.resolvePath(pathInfo); + if (!pathOkay(filePath, pathInfo, response)) { + return; + } + } + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + File fp = new File(filePath); + String filename = fp.getName(); + String tableMatch = getIndexedTable(filename); + if (tableMatch == null) { + tableMatch = "non-standard spatial index"; + } else { + tableMatch = fileURL(request, + response, + getRootDir(request), + tableMatch); + } + + out.println(HTML_DOCTYPE + "VPF Spatial Index " + + filename + "\r\n\r\n

Spatial Index " + + filename + " for Table " + tableMatch + "

\r\n"); + + out.println(getStylesheetHTML(request)); + + try { + DcwSpatialIndex ff = new DcwSpatialIndex(filePath, false); + printSpatial(request, response, ff); + ff.close(); + } catch (FormatException fe) { + out.println("FormatException while reading spatial index: " + + fe.getMessage()); + } + out.println("\r\n"); + } + + public void printSpatial(HttpServletRequest request, + HttpServletResponse response, DcwSpatialIndex si) + throws FormatException, IOException { + PrintWriter out = response.getWriter(); + out.println("

General Spatial Index Information

"); + HtmlListElement list = new HtmlListElement(); + list.addElement("Number Of Primitives: " + si.getNumberOfPrimitives()); + int nodesInTree = si.getNodesInTree(); + list.addElement("Nodes in Tree: " + nodesInTree); + list.addElement("Bounding Rectangle: (" + si.getBoundingX1() + ", " + + si.getBoundingY1() + ") - (" + si.getBoundingX2() + ", " + + si.getBoundingY2() + ")"); + list.generate(out); + out.println("

Spatial Index Data

"); + TableRowElement columnNames = new TableRowElement(); + columnNames.addElement(new TableHeaderElement("Primitive ID")); + columnNames.addElement(new TableHeaderElement("x1")); + columnNames.addElement(new TableHeaderElement("x2")); + columnNames.addElement(new TableHeaderElement("y1")); + columnNames.addElement(new TableHeaderElement("y2")); + for (int i = 0; i < nodesInTree; i++) { + int count = si.getPrimitiveCount(i); + int offset = si.getPrimitiveOffset(i); + DcwSpatialIndex.PrimitiveRecord pr[] = si.getPrimitiveRecords(i); + + out.println("

Node " + i); + if (count == 0) { + out.println("(no primitives)

\r\n"); + } else { + out.println("Primitive Count:" + count + + " Relative Offset:" + offset + "\n"); + + ListElement rows = new ListElement(); + WrapElement table = new WrapElement("table", "BORDER=1", rows); + rows.addElement(columnNames); + for (int j = 0; j < pr.length; j++) { + DcwSpatialIndex.PrimitiveRecord pr1 = pr[j]; + TableRowElement datarow = new TableRowElement(); + rows.addElement(datarow); + datarow.addElement(Integer.toString(pr1.primId)); + datarow.addElement(Short.toString(pr1.x1)); + datarow.addElement(Short.toString(pr1.x2)); + datarow.addElement(Short.toString(pr1.y1)); + datarow.addElement(Short.toString(pr1.y2)); + } + table.generate(out); + } + } + } + + /** a map from spatial index name to primitive file indexed */ + private HashMap indexTableMap; + + /** + * Returns the name of the primitive file that the spatial index + * is for. + * + * @param indexName the name of the index + * @return the name of the primitive file + */ + public String getIndexedTable(String indexName) { + if (indexTableMap == null) { + HashMap newMap = new HashMap(); + newMap.put("esi", "edg"); + newMap.put("esi.", "edg."); + newMap.put("fsi", "fac"); + newMap.put("fsi.", "fac."); + newMap.put("csi", "cnd"); + newMap.put("csi.", "cnd."); + newMap.put("nsi", "end"); + newMap.put("nsi.", "end."); + newMap.put("tsi", "txt"); + newMap.put("tsi.", "txt."); + indexTableMap = newMap; + } + return (String) indexTableMap.get(indexName); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java new file mode 100644 index 00000000..848518e0 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TableSubsetRecordIterator.java @@ -0,0 +1,66 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; + +/** + * An iterator that will return a subset of the rows in a table. + */ +public class TableSubsetRecordIterator implements Iterator { + final private int vals[]; + final DcwRecordFile drf; + final List l; + private int current = 0; + + public TableSubsetRecordIterator(int vals[], DcwRecordFile drf, List l) { + this.vals = vals; + this.drf = drf; + this.l = l; + } + + /** + * Constructor + * + * @param drf the table to parse + * @param vals the row numbers to be returned + */ + public TableSubsetRecordIterator(int vals[], DcwRecordFile drf) { + this(vals, drf, new ArrayList(drf.getColumnCount())); + } + + public boolean hasNext() { + return (current < vals.length); + } + + public Object next() { + boolean gotit; + try { + gotit = drf.getRow(l, vals[current++]); + } catch (FormatException fe) { + System.out.println("fe: " + fe); + gotit = false; + } + return gotit ? l : null; + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java new file mode 100644 index 00000000..a25b67aa --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java @@ -0,0 +1,172 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; +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 com.bbn.openmap.util.html.WrapElement; + +/** + * This servlet generates HTML for VPF files in thematic index format. + */ +public class ThematicIndexServlet + extends VPFHttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public ThematicIndexServlet() { + super(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); + if (filePath == null) { + String pathInfo = setPathInfo(request); + filePath = contextInfo.resolvePath(pathInfo); + if (!pathOkay(filePath, pathInfo, response)) { + return; + } + } + + DcwThematicIndex ti; + try { + ti = new DcwThematicIndex(filePath, false); + } catch (FormatException fe) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, fe.toString()); + return; + } + + String valIndex = request.getParameter("valIndex"); + if (valIndex != null) { + showTableIndexed(request, response, valIndex, ti); + } else { + showTableData(request, response, ti, filePath); + } + try { + ti.close(); + } catch (FormatException fe) { + // ignore + } + } + + protected void showTableData(HttpServletRequest request, HttpServletResponse response, DcwThematicIndex ti, String filePath) + throws ServletException, IOException { + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + + String title = "VPF Thematic Index for " + new File(filePath).getName(); + String basepath = getRootDir(request); + out.println("" + title + ""); + out.println(getStylesheetHTML(request)); + out.println("

" + title + "

"); + + out.println("

General Thematic Index Information

"); + HtmlListElement list = new HtmlListElement(); + list.addElement("Number of Codes: " + ti.getNumberOfCodes()); + list.addElement("Number of Rows: " + ti.getNumberOfRows()); + list.addElement("Type Of Index: " + ti.getTypeOfIndex()); + list.addElement("Field Type of Index: " + ti.getFieldTypeOfIndex()); + list.addElement("Number of Data Elements: " + ti.getNumberOfDataElements()); + list.addElement("Data Type Specifier: " + ti.getDataTypeSpecifier()); + list.addElement("Table Indexed: " + fileURL(request, response, basepath, ti.getTableIndexed())); + list.addElement("Column Indexed: " + ti.getColumnIndexed()); + list.addElement("Fields Sorted: " + ti.getSorted()); + list.generate(out); + + out.println("

Thematic Index Data

"); + Object[] values = ti.getValueIndexes(); + ListElement rows = null; + Element table = null; + TableRowElement th = new TableRowElement(); + th.addElement(new TableHeaderElement("CLASS=NavBarCell2", "Index Value")); + th.addElement(new TableHeaderElement("Count")); + th.addElement(new TableHeaderElement("Rows...")); + String valStr = "" + values[i] + ""); + try { + int[] intvals = ti.get(values[i]); + tr.addElement(Integer.toString(intvals.length)); + StringBuffer sb = new StringBuffer(); + sb.append(intvals[0]); + for (int j = 1; j < intvals.length; j++) { + sb.append(", ").append(intvals[j]); + } + tr.addElement(sb.toString()); + } catch (FormatException fe) { + tr.addElement(fe.toString()); + } + } + if (table != null) { + table.generate(out); + } + } + + protected void showTableIndexed(HttpServletRequest request, HttpServletResponse response, String valIndex, DcwThematicIndex ti) + throws IOException, ServletException { + Object val = null; + switch (ti.getFieldTypeOfIndex()) { + case 'I': + val = Integer.valueOf(valIndex); + break; + case 'S': + val = Short.valueOf(valIndex); + break; + case 'T': + val = valIndex; + break; + } + try { + int[] vals = ti.get(val); + request.setAttribute(Data.ROWLIST_OBJECT, vals); + } catch (FormatException fe) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, fe.toString()); + } + String pi = request.getPathInfo(); + int lin = pi.lastIndexOf('/') + 1; + RequestDispatcher rd = request.getRequestDispatcher("/UnknownType" + pi.substring(0, lin) + ti.getTableIndexed()); + rd.forward(request, response); + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java new file mode 100644 index 00000000..304de892 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/TileHolder.java @@ -0,0 +1,202 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.File; +import java.util.List; +import java.util.Vector; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwCrossTileID; +import com.bbn.openmap.layer.vpf.DcwRecordFile; +import com.bbn.openmap.layer.vpf.TilingAdapter; +import com.bbn.openmap.layer.vpf.VPFUtil; + +/** + * This class provides easy access to tiled data. + */ +public class TileHolder { + /** the name of the primitive file */ + private final String fileName; + /** the current open tile */ + private DcwRecordFile currentTileFile; + /** the index (into tileStuff) of the current open tile */ + private int curTile; + /** an array of tile paths */ + private String tileStuff[]; + /** the directory which has tile subdirectories */ + private final File basepath; + + /** + * Construct a TileHolder. close() should be called when you are + * done with the object. + * + * @param basepath the directory which has tile subdirectories + * @param fileName the name of the primitive file + * @param isTiled if the coverage is tiled or not. If it is, + * tiling information is assumed to be located in + * $basepath/../tileref + * @throws FormatException something went wrong + */ + public TileHolder(File basepath, String fileName, boolean isTiled) + throws FormatException { + this.fileName = fileName; + this.basepath = basepath; + curTile = -1; + if (isTiled) { + tileStuff = doTileRefStuff(basepath); + } else { + currentTileFile = new DcwRecordFile(basepath + File.separator + + fileName); + } + } + + /** + * Gets a row from a primitive file in a coverage. + * + * @param tileColumn the column index used to get the tile id + * @param rowColumn the column index used to get the row id + * @param tileRow the row to retrieve the tile and row IDs from + * @param retrow the row gotten from the file + * @return true if the row was fetched, false otherwise + * @throws FormatException + */ + public boolean getRow(int tileColumn, int rowColumn, List tileRow, + List retrow) throws FormatException { + int tileId = (tileColumn == -1) ? -1 + : VPFUtil.objectToInt(tileRow.get(tileColumn)); + int rowId = VPFUtil.objectToInt(tileRow.get(rowColumn)); + return getRow(tileId, rowId, retrow); + } + + public boolean getRow(TilingAdapter ta, List tileRow, List retrow) + throws FormatException { + return getRow(ta.getTileId(tileRow), ta.getTilePrimId(tileRow), retrow); + } + + public boolean getRow(DcwCrossTileID prim, List retrow) + throws FormatException { + return getRow(prim.nextTileID, prim.nextTileKey, retrow); + } + + /** + * Gets a row from a primitive file in a coverage. + * + * @param tileId the tile identifier + * @param rowId the row identifier + * @param retrow the row gotten from the file + * @return true if the row was fetched, false otherwise + * @throws FormatException + */ + public boolean getRow(int tileId, int rowId, List retrow) + throws FormatException { + if (rowId <= 0) { + return false; + } + if (tileId != curTile) { + File joinfile = new File(basepath + File.separator + + tileStuff[tileId]); + close(); + currentTileFile = new DcwRecordFile(joinfile + File.separator + + fileName); + curTile = tileId; + } + return currentTileFile.getRow(retrow, rowId); + } + + /** + * Closes any related tables. + */ + public void close() { + if (currentTileFile != null) { + currentTileFile.close(); + } + currentTileFile = null; + } + + /** + * Loads tiling information for the coverage. + * + * @param path the path to the coverage. tiling info is in + * ../tileref + * @return an array of tile paths + */ + private static String[] doTileRefStuff(File path) throws FormatException { + File pathname = new File(path.getParentFile(), "tileref"); + String faceIDColumnName = null; + // read fcs to figure out what column in tileref.aft we need + // to use to + // read the fbr (face bounding rectangle) table + File fcsFile = new File(pathname, "fcs"); + if (!fcsFile.canRead()) { + fcsFile = new File(pathname, "fcs."); + } + DcwRecordFile fcs = new DcwRecordFile(fcsFile.toString()); + Vector fcsv = new Vector(fcs.getColumnCount()); + while (fcs.parseRow(fcsv)) { + String fclass = ((String) fcsv.elementAt(1)).toLowerCase(); + String table1 = ((String) fcsv.elementAt(2)).toLowerCase(); + if ((fclass.equals("tileref")) && (table1.equals("tileref.aft"))) { + faceIDColumnName = (String) fcsv.elementAt(3); + break; + } + } + fcs.close(); + + if (faceIDColumnName == null) { + throw new FormatException("no faceIDColumn"); + // won't be able to read the tiling info. abort + } + + // Okay, we've got info on what column we use from tileref.aft + // to index + // into the fbr. + DcwRecordFile aft = new DcwRecordFile(pathname + File.separator + + "tileref.aft"); + int faceIDColumn = aft.whatColumn(faceIDColumnName.toLowerCase()); + int tileNameColumn = aft.whatColumn("tile_name"); + + if ((faceIDColumn == -1) || (tileNameColumn == -1)) { + aft.close(); + throw new FormatException("no faceIDColumn"); + } + + Vector aftv = new Vector(aft.getColumnCount()); + + // set the array size to record count + 1, to be able to + // use the tileID as the index into the array + String containedTiles[] = new String[aft.getRecordCount() + 1]; + + int tileid = 1; + while (aft.parseRow(aftv)) { + //int fac_num = ((Number) aftv.elementAt(faceIDColumn)).intValue(); + String tilename = (String) aftv.elementAt(tileNameColumn); + + char chs[] = tilename.toCharArray(); + boolean goodTile = false; + for (int i = 0; i < chs.length; i++) { + if ((chs[i] != '\\') && (chs[i] != ' ')) { + goodTile = true; + chs[i] = Character.toLowerCase(chs[i]); + } + if (chs[i] == '\\') { + chs[i] = File.separatorChar; + } + } + containedTiles[tileid++] = (goodTile) ? new String(chs) : null; + } + aft.close(); + return containedTiles; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java new file mode 100644 index 00000000..27769dbc --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/URLCheck.java @@ -0,0 +1,136 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +/** + * Command line program to wander the vpfservlet pages, to make sure + * all URLs generated are valid. + */ +public class URLCheck { + public static Set check(String surl, PrintStream out) throws IOException { + Set urls = new TreeSet(); + out.println("URL " + surl); + Reader r; + URL url; + try { + url = new URL(surl); + r = new InputStreamReader(url.openStream()); + } catch (MalformedURLException mue) { + out.println(" bad URL"); + return urls; + } + Set names = new HashSet(); + Set localrefs = new HashSet(); + StringBuffer sb = new StringBuffer(); + char buf[] = new char[8096]; + int len; + while ((len = r.read(buf)) != -1) { + sb.append(buf, 0, len); + String str = sb.toString(); + int fromIx = 0; + int gt; + while ((gt = str.indexOf('>', fromIx)) != -1) { + int lt = str.indexOf('<', fromIx); + fromIx = gt + 1; + char firstChar = str.charAt(lt + 1); + if ((firstChar != 'A') && (firstChar != 'a')) { + continue; + } + String substr = str.substring(lt + 1, gt); + String lsubstr = substr.toLowerCase(); + + int hquote = lsubstr.indexOf(href); + if (hquote != -1) { + hquote += href.length(); + int lquote = substr.indexOf('"', hquote); + String rurl = substr.substring(hquote, lquote); + if (rurl.charAt(0) == '#') { + names.add(rurl.substring(1)); + } else { + try { + urls.add(new URL(url, rurl).toExternalForm()); + } catch (MalformedURLException mue) { + out.println(" MUE: " + mue.getMessage()); + } + } + } else { + int nquote = lsubstr.indexOf(name); + if (nquote != -1) { + nquote += name.length(); + int lquote = substr.indexOf('"', nquote); + String n = substr.substring(nquote, lquote); + localrefs.add(n); + } + } + + } + sb.delete(0, fromIx); + } + for (Iterator i = localrefs.iterator(); i.hasNext();) { + String localref = (String) i.next(); + if (!names.contains(localref)) { + out.println("MISSING REF: " + localref); + } + } + return urls; + } + final static String href = "href=\""; + final static String name = "name=\""; + + public static Set workOn(Set master, Set urls, PrintStream out) { + Set newurls = null; + for (Iterator i = urls.iterator(); i.hasNext();) { + String surl = (String) i.next(); + if (master.add(surl)) { + try { + Set rets = check(surl, out); + if (newurls == null) { + newurls = rets; + } else { + newurls.addAll(rets); + } + } catch (FileNotFoundException fnfe) { + out.println("Bogus URL: " + surl); + } catch (IOException ioe) { + out.println(" " + surl + " " + ioe.getClass() + " " + + ioe.getMessage()); + } + } + } + return newurls; + } + + public static void main(String[] args) { + Set master = new HashSet(); + Set workon = new HashSet(); + workon.addAll(Arrays.asList(args)); + do { + workon = workOn(master, workon, System.out); + } while (workon != null); + System.out.println("Done."); + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java new file mode 100644 index 00000000..93e768d1 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java @@ -0,0 +1,55 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * A RowMaker class for int.vdt and char.vdt tables. It generates a + * URL for columns that reference another table. + */ +public class VDTRowMaker extends ReferenceRowMaker { + + /** the path to the coverage */ + final String basepath; + /** the column with the table name */ + final int tableCol; + + public VDTRowMaker(HttpServletRequest request, + HttpServletResponse response, String basepath, DcwRecordFile drf) { + super(request, response); + this.basepath = basepath; + tableCol = drf.whatColumn("table"); + } + + public void addToRow(TableRowElement row, List l) { + int i = 0; + for (Iterator li = l.iterator(); li.hasNext();) { + Object elt = li.next(); + if (i == tableCol) { + row.addElement(fileURL(basepath, ((String) elt).toLowerCase())); + } else { + row.addElement(elt.toString()); + } + i++; + } + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java new file mode 100644 index 00000000..0a3cbfa1 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java @@ -0,0 +1,210 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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; + +/** + * A base class useful for servlets that use the VPF tools context object. This class also defines some utility methods + * used in the package. + */ +public abstract class VPFHttpServlet extends HttpServlet { + + /** + * html doctype for HTML 4.0 + */ + public static final String HTML_DOCTYPE = ""; + + /** + * the context object used for config info + */ + protected ContextInfo contextInfo; + + /** + * A do-nothing constructor - init does all the work. + */ + public VPFHttpServlet() { + super(); + } + + public void init(ServletConfig config) throws ServletException { + super.init(config); + contextInfo = ContextInfo.getContextInfo(config.getServletContext()); + } + + /** + * Checks if a path refers to a file. If its not, reports an error. + * + * @param rootpath the path to check (can be null) + * @param pathInfo used in the error message if rootpath is null + * @param response used to send the error + * @return true if the file can be read, false otherwise + * @see HttpServletResponse#sendError + */ + public static boolean pathOkay(String rootpath, String pathInfo, + HttpServletResponse response) + throws IOException { + if (rootpath == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, pathInfo + + " (invalid path)"); + return false; + } else if (!new File(rootpath).canRead()) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + rootpath.toString() + " not found"); + return false; + } + return true; + } + + /** + * Returns the HTML to reference the common stylesheet + * + * @return the stylesheet HTML + */ + public String getStylesheetHTML(HttpServletRequest request) { + return (""); + } + + /** + * Returns a TableHeaderElement that contains a URL + * + * @param text the text for the reference + * @param url the URL for the reference + * @return a table cell containing a URL + */ + public TableHeaderElement THE(String text, String url) { + return new TableHeaderElement(buildHREF(url, text)); + } + + /** + * Returns a TableHeaderElement that contains a URL + * + * @param text the text for the reference + * @param url the URL for the reference + * @param response the HttpServletResponse object used to encode the url + * @return a table cell containing a URL + */ + public TableHeaderElement THE(String text, String url, + HttpServletResponse response) { + return new TableHeaderElement(buildHREF(response, url, text)); + } + + /** + * Returns a string usable as an HTML HREF element + * + * @param tag the text for the reference + * @param url the URL for the reference + * @return a string containing an HTML HREF + */ + public static String buildHREF(String url, String tag) { + return "" + tag + ""; + } + + /** + * Returns a string usable as an HTML HREF element + * + * @param tag the text for the reference + * @param url the URL for the reference + * @param response the HttpServletResponse object used to encode the url + * @return a string containing an HTML HREF + */ + public static String buildHREF(HttpServletResponse response, String url, + String tag) { + return buildHREF(response.encodeURL(url), tag); + } + + /** + * Returns an HTML HREF based on the parameters. This method is equivelent to toURL(request, response, + * "/UnknownType", pathname, filename); + * + * @see #toURL + * @param request the request to use for context info + * @param response the response to use to encode the URL + * @param pathname the path of the file + * @param filename the name of the file + * @return a string HREF + */ + public static String fileURL(HttpServletRequest request, + HttpServletResponse response, String pathname, + String filename) { + return toURL(request, response, "/UnknownType", pathname, filename); + } + + /** + * Returns an HTML HREF based on the parameters. + * + * @param request the request to use for context info + * @param response the response to use to encode the URL + * @param pathname the path of the file + * @param filename the name of the file (may be null) + * @param servletName the servlet name to use in the URL + * @return a string HREF + */ + public static String toURL(HttpServletRequest request, + HttpServletResponse response, + String servletName, String pathname, + String filename) { + String value; + if (filename == null) { + value = "---"; + } else { + String url = request.getContextPath() + servletName + pathname + + filename; + value = "" + filename + + "\r\n"; + + } + return value; + } + + public static final String ROOT_PATHDIR = VPFHttpServlet.class.getName() + + ".rootPathDir"; + public static final String ROOT_PATH = VPFHttpServlet.class.getName() + + ".rootPath"; + + public static void setRootDir(HttpServletRequest request, String path) { + request.setAttribute(ROOT_PATHDIR, path); + } + + public static String getRootDir(HttpServletRequest request) { + return (String) request.getAttribute(ROOT_PATHDIR); + } + + public static void setPathInfo(HttpServletRequest request, String path) { + request.setAttribute(ROOT_PATH, path); + } + + public static String getPathInfo(HttpServletRequest request) { + return (String) request.getAttribute(ROOT_PATH); + } + + protected static String setPathInfo(HttpServletRequest request) { + String pathInfo = request.getPathInfo(); + setPathInfo(request, pathInfo); + if (pathInfo != null) { + int index = pathInfo.lastIndexOf('/'); + String subpath = pathInfo.substring(0, index + 1); + setRootDir(request, subpath); + } + return pathInfo; + } +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java new file mode 100644 index 00000000..5b6155d3 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFTable.java @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.servlet.vpfBrowse; + +import com.bbn.openmap.io.FormatException; +import com.bbn.openmap.layer.vpf.DcwRecordFile; + +/** + * Wrapper for DcwRecordFile objects, to give JSPs a way to interact + * with them directly. + */ +public class VPFTable { + + private DcwRecordFile table; + + public VPFTable() {} + + public void setFile(String file) { + try { + if ((file == null) && (table != null)) { + table.close(); + table = null; + } + if (file != null) { + table = new DcwRecordFile(file); + } + } catch (FormatException fe) { + } + } + + public String getTablename() { + return (table == null) ? "default" : table.getTableName(); + } + + public String getDescription() { + return (table == null) ? "default" : table.getDescription(); + } +} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java deleted file mode 100644 index 44ac412a..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MBRasterMapTileSet.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - */ -package com.bbn.openmap.maptileservlet; - -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; -import java.util.Properties; -import java.util.logging.Logger; - -import javax.swing.ImageIcon; - -import com.bbn.openmap.dataAccess.mapTile.mb.RasterMapTileFactory; -import com.bbn.openmap.image.BufferedImageHelper; -import com.bbn.openmap.image.PNGImageIOFormatter; -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.util.PropUtils; - -/** - * MapTileSet that reads MapBox raster mbtiles files. - * - *
- * name=the-name-of-dataset
- * class=com.bbn.openmap.maptileservlet.MBRasterMapTileSet
- * rootDir=the path to the mbtiles file.
- *  * 
- * - * As an example, a url for accessing a tile from this server would be: - * - *
- * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
- * 
- * - * where ommaptile is the name of the servlet. You can change that in the - * web.xml and in glassfish/tomcat. - * - * @author dietrick - */ -public class MBRasterMapTileSet extends StandardMapTileSet { - - public MBRasterMapTileSet() { - } - - public MBRasterMapTileSet(Properties props) { - setProperties(props); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - String prefix = PropUtils.getScopedPropertyPrefix(this); - props.put(prefix + CLASS_ATTRIBUTE, this.getClass().getName()); - - return props; - } - - public byte[] getImageData(String pathInfo) throws IOException, FormatException { - - byte[] imageData = null; - - try { - Class.forName(RasterMapTileFactory.DEFAULT_TEST_CLASS); - } catch (Exception e) { - getLogger().warning("can't locate sqlite JDBC components"); - return null; - } - - try { - - TileInfo ti = new TileInfo(pathInfo); - - Connection conn = DriverManager.getConnection(rootDir); - Statement stat = conn.createStatement(); - - // "select zoom_level, tile_column, tile_row, tile_data from map, images where map.tile_id = images.tile_id"; - StringBuilder statement = new StringBuilder("select tile_data from map, images where"); - statement.append(" zoom_level = ").append(ti.zoomLevel); - statement.append(" and tile_column = ").append(ti.x); - statement.append(" and tile_row = ").append((int) (Math.pow(2, ti.zoomLevel)) - ti.y - - 1); - statement.append(" and map.tile_id = images.tile_id;"); - - ResultSet rs = stat.executeQuery(statement.toString()); - while (rs.next()) { - byte[] imageBytes = rs.getBytes("tile_data"); - ImageIcon ii = new ImageIcon(imageBytes); - BufferedImage bi = BufferedImageHelper.getBufferedImage(ii.getImage(), 0, 0, -1, -1); - - // TODO: Still have to incorporate properties or something to - // all - // specification of map image format. - imageData = new PNGImageIOFormatter().formatImage(bi); - } - rs.close(); - conn.close(); - } catch (Exception e) { - getLogger().warning("something went wrong fetching image from database: " - + e.getMessage()); - e.printStackTrace(); - } - - return imageData; - } - - /** - * Holder for this class's Logger. This allows for lazy initialization of - * the logger. - */ - private static final class LoggerHolder { - /** - * The logger for this class - */ - private static final Logger LOGGER = Logger.getLogger(MapTileSet.class.getName()); - - /** - * Prevent instantiation - */ - private LoggerHolder() { - throw new AssertionError("This should never be instantiated"); - } - } - - /** - * Get the logger for this class. - * - * @return logger for this class - */ - private static Logger getLogger() { - return LoggerHolder.LOGGER; - } - -} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java deleted file mode 100644 index 52bb0a8d..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileServlet.java +++ /dev/null @@ -1,387 +0,0 @@ -package com.bbn.openmap.maptileservlet; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -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 com.bbn.openmap.util.ComponentFactory; -import com.bbn.openmap.util.PropUtils; -import com.bbn.openmap.util.http.HttpConnection; -import com.bbn.openmap.util.wanderer.Wanderer; -import com.bbn.openmap.util.wanderer.WandererCallback; - -/** - * MapTileServlet is a servlet class that fields requests for map tiles. It can - * handle multiple MapTileSets, each one defined by a properties file. The - * web.xml file for this servlet lets you specify the directory where these - * properties files are, under the TileSetDefinitions attribute. The properties - * files in that directory are automatically read and used to create - * MapTileSets. The default deployed name and location of this directory is the - * WEB-INF/classes/tileSetDefinitions directory, but any location can be - * specified. - * - * Each maptileset properties file should specify a name of the tile set, which - * is used in the path to reach those tiles. The MapTileSet object is used by - * the MapTileServlet to handle the specific configuration of the tile set, and - * the MapTileSet object classname to use can be specified in the maptileset - * properties under the 'class' property. The StandardMapTileSet is used by - * default, it assumes the tile set is stored in a z/x/y file structure. The - * TileMillMapTileSet knows how to use mbtiles files created using TileMill. The - * RelayMapTileSet uses a local z/x/y directory structure as a cache for tiles - * to disperse, but goes to another server location to fetch new tiles it - * doesn't have. Each MapTileSet has configuration information in its javadoc. - * See the web.xml file for more information about configuring this - * MapTileServlet. - * - * @author dietrick - */ -public class MapTileServlet extends HttpServlet { - public final static String TILE_SET_DESCRIPTION_ATTRIBUTE = "TileSetDefinitions"; - public final static String LEAFLET_CSS_LOCATION_ATTRIBUTE = "leaflet_css"; - public final static String LEAFLET_JS_LOCATION_ATTRIBUTE = "leaflet_js"; - protected Map mapTileSets; - - String leafletCssLocation = "http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css"; - String leafletJsLocation = "http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"; - - /** - * A do-nothing constructor - init does all the work. - */ - public MapTileServlet() { - super(); - - mapTileSets = Collections.synchronizedMap(new HashMap()); - } - - /** - * Called when the servlet is loaded. - */ - public void init(ServletConfig config) throws ServletException { - super.init(config); - ServletContext context = config.getServletContext(); - - Logger logger = getLogger(); - String leafletCss = context.getInitParameter(LEAFLET_CSS_LOCATION_ATTRIBUTE); - if (leafletCss != null) { - leafletCssLocation = leafletCss; - } - logger.info("leaflet.css located at :" + leafletCssLocation); - - String leafletJs = context.getInitParameter(LEAFLET_JS_LOCATION_ATTRIBUTE); - if (leafletJs != null) { - leafletJsLocation = leafletJs; - } - logger.info("leaflet.js located at :" + leafletJsLocation); - - String descriptions = context.getInitParameter(TILE_SET_DESCRIPTION_ATTRIBUTE); - logger.info("Looking for Tile Set Descriptions at: " + descriptions); - if (descriptions != null) { - - // Changing descriptions to a folder containing properties files - // defining tile sets. - try { - - URL descriptionFolder = PropUtils.getResourceOrFileOrURL(descriptions); - new PropertiesWanderer(new File(descriptionFolder.getFile())); - - } catch (MalformedURLException e) { - logger.warning("unable to open for Tile Set properties file given " + descriptions); - } catch (NullPointerException npe) { - logger.warning("Can't find directory holding Tile Set properties files: " - + descriptions); - } - } - - } - - /** - * Given a URL to a properties file describing a MapTileSet, create it and - * add it to the list. - * - * @param tileSetProperties - * @throws IOException - * @throws MalformedURLException - */ - protected void parseAndAddMapTileSet(URL tileSetProperties) - throws IOException, MalformedURLException { - Properties descProps = new Properties(); - Logger logger = getLogger(); - - logger.info("going to read props"); - InputStream descURLStream = tileSetProperties.openStream(); - descProps.load(descURLStream); - - logger.info("loaded " + tileSetProperties.toString() + " " + descProps.toString()); - - MapTileSet mts = createMapTileSetFromProperties(descProps); - - if (mts != null && mts.allGood()) { - String mtsName = mts.getName(); - mapTileSets.put(mts.getName(), mts); - logger.info("Adding " + mtsName + " dataset"); - } - - descURLStream.close(); - } - - protected MapTileSet createMapTileSetFromProperties(Properties props) { - String className = props.getProperty(MapTileSet.CLASS_ATTRIBUTE); - Logger logger = getLogger(); - if (className == null) { - MapTileSet mts = new StandardMapTileSet(); - mts.setProperties(props); - return mts; - } else { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Creating special map tile set: " + className); - } - try { - Object obj = ComponentFactory.create(className, null, props); - - if (obj instanceof MapTileSet) { - return (MapTileSet) obj; - } else { - logger.fine("Had trouble creating " - + (obj == null ? className : obj.getClass().getName()) - + ", not a MapTileSet"); - } - - } catch (Exception e) { - getLogger().severe("Problem creating " + className + ", " + e.getMessage()); - } - } - - return null; - } - - /** - * Handles - */ - public void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - OutputStream out = resp.getOutputStream(); - - String pathInfo = req.getPathInfo(); - Logger logger = getLogger(); - if (logger.isLoggable(Level.FINE)) { - logger.fine("received: " + pathInfo); - } - - // Empty path request, let's return summary catalog, might be of some - // help. - if (pathInfo.length() <= 1) { - String tilePathHeader = req.getServerName() + ":" + req.getServerPort() - + req.getContextPath(); - StringBuilder builder = new StringBuilder("Map Tile Sets:

"); - for (MapTileSet mts : mapTileSets.values()) { - String description = mts.getDescription(); - builder.append("Tile set name: "); - builder.append(mts.getName()).append(", description: "); - builder.append(description == null ? "n/a" : description).append("
"); - } - builder.append(""); - - resp.setContentType(HttpConnection.CONTENT_HTML); - OutputStreamWriter osw = new OutputStreamWriter(out); - out.write(builder.toString().getBytes()); - osw.flush(); - return; - } - - MapTileSet mts = getMapTileSetForRequest(pathInfo); - - if (mts != null) { - - if (pathInfo.endsWith("map")) { - String tilePathHeader = req.getServerName() + ":" + req.getServerPort() - + req.getContextPath(); - String map = getMap(tilePathHeader, mts); - resp.setContentType(HttpConnection.CONTENT_HTML); - OutputStreamWriter osw = new OutputStreamWriter(out); - out.write(map.getBytes()); - osw.flush(); - return; - } - - try { - resp.setContentType(HttpConnection.CONTENT_PNG); - byte[] imageData = mts.getImageData(pathInfo); - OutputStreamWriter osw = new OutputStreamWriter(out); - out.write(imageData, 0, imageData.length); - osw.flush(); - } catch (Exception e) { - if (logger.isLoggable(Level.FINE)) { - getLogger().fine("Tile not found: " + pathInfo); - } - HttpConnection.writeHttpResponse(out, HttpConnection.CONTENT_PLAIN, "Problem loading " - + pathInfo + " from map tile set:" + mts.getName()); - } - } else { - HttpConnection.writeHttpResponse(out, HttpConnection.CONTENT_PLAIN, "Map Tile Set not found for request: " - + pathInfo); - } - } - - protected MapTileSet getMapTileSetForRequest(String pathInfo) { - if (pathInfo.startsWith("/")) { - pathInfo = pathInfo.substring(1); - } - - String key = pathInfo; - - // That first part of the path is the MapTileSet name. - int slash = pathInfo.indexOf('/'); - if (slash > 0) { - key = pathInfo.substring(0, slash); - } - - return mapTileSets.get(key); - } - - /** - * Given a starting directory, look for properties files that describe - * MapTileSets. - * - * @author dietrick - */ - private class PropertiesWanderer extends Wanderer implements WandererCallback { - - public PropertiesWanderer(File startingDirectory) { - setCallback(this); - handleEntry(startingDirectory); - } - - /* - * (non-Javadoc) - * - * @see - * com.bbn.openmap.util.wanderer.WandererCallback#handleDirectory(java - * .io.File) - */ - public boolean handleDirectory(File directory) { - // Do nothing to directories - return true; - } - - /* - * (non-Javadoc) - * - * @see - * com.bbn.openmap.util.wanderer.WandererCallback#handleFile(java.io - * .File) - */ - public boolean handleFile(File file) { - getLogger().fine("Checking " + file); - try { - String name = file.getName(); - if (name.endsWith("properties")) { - parseAndAddMapTileSet(file.toURI().toURL()); - } - } catch (MalformedURLException murle) { - getLogger().warning("Unable to read/load " + file + ", murle"); - } catch (IOException e) { - getLogger().warning("Unable to read/load " + file + ", ioe"); - } - return true; - } - - } - - /** - * Holder for this class's Logger. This allows for lazy initialization of - * the logger. - */ - private static final class LoggerHolder { - /** - * The logger for this class - */ - private static final Logger LOGGER = Logger.getLogger(MapTileServlet.class.getName()); - - /** - * Prevent instantiation - */ - private LoggerHolder() { - throw new AssertionError("This should never be instantiated"); - } - } - - /** - * Get the logger for this class. - * - * @return logger for this class - */ - private static Logger getLogger() { - return LoggerHolder.LOGGER; - } - - /** - * Creates a HTML string that will display a Leaflet map with the map tiles - * for the MapTileSet. - * - * @param tileReqHeader the server:port/context string of this servlet. - * @param mts the MapTileSet to display. - * @return html text. - */ - protected String getMap(String tileReqHeader, MapTileSet mts) { - String name = mts.getName(); - - List nameList = new ArrayList(); - nameList.add(name); - for (MapTileSet set : mapTileSets.values()) { - if (!name.equals(set.getName())) { - nameList.add(set.getName()); - } - } - - StringBuilder ret = new StringBuilder(); - - ret.append(""); - ret.append(""); - ret.append("

"); - ret.append(""); - - return ret.toString(); - } -} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java deleted file mode 100644 index 4e0a9aff..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/MapTileSet.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.bbn.openmap.maptileservlet; - -import com.bbn.openmap.PropertyConsumer; -import com.bbn.openmap.io.FormatException; -import java.io.IOException; - -/** - * The MapTileSet contains all the information for handling a specific set of tiles. It contains a description, key to - * use in the request, the location of the data directory, and how to handle empty tiles. - * - * @author dietrick - */ -public interface MapTileSet - extends PropertyConsumer { - - /** - * Property used for MapTileSet class. - */ - public final static String CLASS_ATTRIBUTE = "class"; - - /** - * Check for MapTileServlet to see if the MapTileSet is configured properly. - * - * @return true if configured. - */ - boolean allGood(); - - /** - * byte array image data for path. - * - * @param pathInfo path for file, in z/x/y format. - * @return byte[] for image data, null if not found. - * @throws IOException - * @throws FormatException - */ - byte[] getImageData(String pathInfo) - throws IOException, FormatException; - - /** - * Return name to use in URL to tell MapTileServlet to get frames from this MapTileSet. - * - * @return name of this map tile set. - */ - public String getName(); - - /** - * Set the name of this map tile set. - * - * @param name - */ - public void setName(String name); - - /** - * Get a description of this tile set. - * - * @return string description. - */ - public String getDescription(); - - /** - * Set the description of this tile set. - * - * @param description - */ - public void setDescription(String description); -} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java deleted file mode 100644 index de116bb3..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/RelayMapTileSet.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.bbn.openmap.maptileservlet; - -import com.bbn.openmap.dataAccess.mapTile.ServerMapTileFactory; -import com.bbn.openmap.io.BinaryBufferedFile; -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.util.PropUtils; -import java.io.IOException; -import java.util.Properties; - -/** - * The RelayMapTileSet contains all the information for handling a specific set of tiles. It contains a description, key - * to use in the request, the location of the data directory or jar. This MapTileSet is able to contact a remote server - * for tiles if the tile file isn't found locally. - *

- * These properties should be in the properties file referenced in the web.xml file for this tile set: - * - *

- * name=the-name-of-dataset
- * class=com.bbn.openmap.maptileservlet.RelayMapTileSet
- * rootDir=the formatted URL for remote tiles, i.e. http://server.com/{z}/{x}/{y}.png
- * localCacheRootDir=the local path of the cached tiles, i.e. /data/tiles/{z}/{x}/{y}.png
- * 
- * - * As an example, a url for accessing a tile from this server would be: - *
- * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
- * 
where ommaptile is the name of the servlet. You can change that in the web.xml and in glassfish/tomcat. - * - * @author dietrick - */ -public class RelayMapTileSet - extends ServerMapTileFactory - implements MapTileSet { - - protected String name; - protected String description = null; - - // To allow the component factory to create it. - public RelayMapTileSet() { - } - - public boolean allGood() { - return name != null && rootDir != null; - } - - public void setProperties(String prefix, Properties props) { - super.setProperties(prefix, props); - prefix = PropUtils.getScopedPropertyPrefix(prefix); - - name = props.getProperty(prefix + StandardMapTileSet.NAME_ATTRIBUTE, name); - description = props.getProperty(prefix + StandardMapTileSet.DESCRIPTION_ATTRIBUTE, description); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - String prefix = PropUtils.getScopedPropertyPrefix(this); - props.put(prefix + StandardMapTileSet.NAME_ATTRIBUTE, PropUtils.unnull(name)); - props.put(prefix + StandardMapTileSet.DESCRIPTION_ATTRIBUTE, PropUtils.unnull(name)); - return props; - } - - public byte[] getImageData(String pathInfo) - throws IOException, FormatException { - byte[] imageData = null; - - // We're assuming that all queries are coming in with the name in front, - // along with a slash - if (name != null) { - int index = pathInfo.indexOf(name, 1); - pathInfo = pathInfo.substring(index + name.length()); - } - - // We need to build and check for local file. If not found, then call - // getImageBytes to fetch from other server and cache locally - String localFilePath = null; - TileInfo tInfo = new TileInfo(pathInfo); - - if (!tInfo.valid) { - return imageData; - } - - if (localCacheDir != null) { - localFilePath = buildLocalFilePath(tInfo.x, tInfo.y, tInfo.zoomLevel, getFileExt()); - - try { - - BinaryBufferedFile file = new BinaryBufferedFile(localFilePath); - imageData = file.readBytes(100000, true); - file.close(); - return imageData; - - } catch (IOException ioe) { - // Didn't find local version of file, that's OK. Continue on... - } - } - - // The file wasn't found. - String remoteFilePath = buildFilePath(tInfo.x, tInfo.y, tInfo.zoomLevel, getFileExt()); - imageData = getImageBytes(remoteFilePath, localFilePath); - - return imageData; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } -} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java deleted file mode 100644 index 17f1ceea..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/StandardMapTileSet.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.bbn.openmap.maptileservlet; - -import com.bbn.openmap.dataAccess.mapTile.StandardMapTileFactory; -import com.bbn.openmap.image.PNGImageIOFormatter; -import com.bbn.openmap.io.BinaryBufferedFile; -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.util.PropUtils; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Properties; -import java.util.logging.Level; - -/** - * The StandardMapTileSet contains all the information for handling a specific set of tiles. It contains a description, - * key to use in the request, the location of the data directory or jar, and how to handle empty tiles. The - * StandardMapTileSet properties file would look like this: - * - *
- * name=the-name-of-dataset
- * # default, don't really need to specify the class property
- * #class=com.bbn.openmap.maptileservlet.StandardMapTileSet
- * rootDir=the path to the root of the tile directory, the parent of the z-level directory.
- * 
- * - * As an example, a url for accessing a tile from this server would be: - * - *
- * http://your.machine/ommaptile/the-name-of-dataset/z/x/y.png
- * 
- * - * where ommaptile is the name of the servlet. You can change that in the web.xml and in glassfish/tomcat. - * - * @author dietrick - */ -public class StandardMapTileSet - extends StandardMapTileFactory - implements MapTileSet { - - public final static String NAME_ATTRIBUTE = "name"; - public final static String DESCRIPTION_ATTRIBUTE = "description"; - - protected String name; - protected String description = null; - - // To allow the component factory to create it. - public StandardMapTileSet() { - } - - public boolean allGood() { - return name != null && rootDir != null; - } - - public void setProperties(String prefix, Properties props) { - super.setProperties(prefix, props); - prefix = PropUtils.getScopedPropertyPrefix(prefix); - - name = props.getProperty(prefix + NAME_ATTRIBUTE, name); - description = props.getProperty(prefix + DESCRIPTION_ATTRIBUTE, description); - } - - public Properties getProperties(Properties props) { - props = super.getProperties(props); - String prefix = PropUtils.getScopedPropertyPrefix(this); - props.put(prefix + NAME_ATTRIBUTE, PropUtils.unnull(name)); - props.put(prefix + DESCRIPTION_ATTRIBUTE, PropUtils.unnull(description)); - return props; - } - - public byte[] getImageData(String pathInfo) - throws IOException, FormatException { - byte[] imageData = null; - - // We're assuming that all queries are coming in with the name in front, - // along with a slash - if (name != null) { - int index = pathInfo.indexOf(name, 1); - pathInfo = pathInfo.substring(index + name.length()); - } - - String filePath = rootDir + pathInfo; - if (logger.isLoggable(Level.FINE)) { - logger.fine("looking for " + filePath); - } - - try { - - BinaryBufferedFile file = new BinaryBufferedFile(filePath); - imageData = file.readBytes(100000, true); - file.close(); - - } catch (IOException ioe) { - logger.fine("Problem fetching the file"); - // The file wasn't found. - if (emptyTileHandler != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Creating " + filePath + " since it wasn't found from the server."); - } - - TileInfo ti = new TileInfo(filePath);// FPBT: used to be - // pathInfo - ti.setMtcTransform(getMtcTransform()); - BufferedImage bufferedImage = ti.getBufferedImage(emptyTileHandler); - - if (bufferedImage != null) { - imageData = new PNGImageIOFormatter().formatImage(bufferedImage); - logger.fine("buffered image created, writing file to disk too"); - File newFile = new File(filePath); - newFile.getParentFile().mkdirs(); - // Write the image data to the local cache location - FileOutputStream fos = new FileOutputStream(newFile); - fos.write(imageData); - fos.flush(); - fos.close(); - } else { - logger.fine("null buffered image back from EmptyTileHandler"); - } - } else { - logger.fine("no empty file handler"); - } - } - - return imageData; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } -} diff --git a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java b/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java deleted file mode 100644 index 944814e4..00000000 --- a/src/maptileservlet/src/main/java/com/bbn/openmap/maptileservlet/TileInfo.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Copyright 2012 BBN Technologies - * - */ -package com.bbn.openmap.maptileservlet; - -import java.awt.geom.Point2D; -import java.awt.image.BufferedImage; -import java.util.logging.Logger; - -import com.bbn.openmap.dataAccess.mapTile.EmptyTileHandler; -import com.bbn.openmap.dataAccess.mapTile.MapTileCoordinateTransform; -import com.bbn.openmap.dataAccess.mapTile.OSMMapTileCoordinateTransform; -import com.bbn.openmap.dataAccess.mapTile.SimpleEmptyTileHandler; -import com.bbn.openmap.proj.Mercator; -import com.bbn.openmap.proj.coords.LatLonPoint; - -/** - * TileInfo can look at a path string and figure out zoom level, x, y for tiles. - * - * @author dietrick - */ -public class TileInfo { - int x; - int y; - int zoomLevel; - String format; - String pathInfo; - MapTileCoordinateTransform mtcTransform; - - boolean valid = false; - - Logger logger = Logger.getLogger("com.bbn.openmap.maptileservlet"); - - public TileInfo(String pathInfo) { - this.pathInfo = pathInfo; - - if (pathInfo == null) { - return; - } - - int dotIndex = pathInfo.lastIndexOf('.'); - if (dotIndex > 0) { - format = pathInfo.substring(dotIndex + 1); - - int ySlashIndex = pathInfo.lastIndexOf('/'); - if (ySlashIndex > 0) { - String yString = pathInfo.substring(ySlashIndex + 1, dotIndex); - - int xSlashIndex = pathInfo.lastIndexOf('/', ySlashIndex - 1); - if (xSlashIndex > 0) { - String xString = pathInfo.substring(xSlashIndex + 1, ySlashIndex); - - int zSlashIndex = pathInfo.lastIndexOf('/', xSlashIndex - 1); - if (zSlashIndex >= 0) { - String zString = pathInfo.substring(zSlashIndex + 1, xSlashIndex); - - // OK, we're here! - x = Integer.parseInt(xString); - y = Integer.parseInt(yString); - zoomLevel = Integer.parseInt(zString); - valid = true; - return; - } - } - } - } - - logger.info("can't decode " + pathInfo); - } - - public BufferedImage getBufferedImage(EmptyTileHandler eth) { - if (eth != null) { - - LatLonPoint center = mtcTransform.tileUVToLatLon(new Point2D.Double(x + .5, y + .5), zoomLevel, new LatLonPoint.Double()); - Mercator merc = new Mercator(center, mtcTransform.getScaleForZoom(zoomLevel), SimpleEmptyTileHandler.TILE_SIZE, SimpleEmptyTileHandler.TILE_SIZE); - logger.fine("going to create empty tile: " + pathInfo + " from " - + eth.getClass().getName()); - - return eth.getImageForEmptyTile(pathInfo, x, y, zoomLevel, getMtcTransform(), merc); - } - return null; - } - - public MapTileCoordinateTransform getMtcTransform() { - if (mtcTransform == null) { - mtcTransform = new OSMMapTileCoordinateTransform(); - } - return mtcTransform; - } - - public void setMtcTransform(MapTileCoordinateTransform mtcTransform) { - this.mtcTransform = mtcTransform; - } -} \ No newline at end of file From 5746903abe9afa2eaa5cd47cfc99c6d56d57ebc6 Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 19:49:42 +0100 Subject: [PATCH 04/20] Moving the wms servlet into the core code base. The wmsservlet code base is for organization and managing the servlet. --- .../bbn/openmap/servlet/wms/HttpResponse.java | 71 ++++++++ .../openmap/servlet/wms/OgcWmsServlet.java | 154 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java create mode 100644 src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java new file mode 100644 index 00000000..880758ab --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java @@ -0,0 +1,71 @@ +// ********************************************************************** +// +// +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// +// ********************************************************************** +// +// $Source: /cvs/distapps/openmap/src/wmsservlet/WEB-INF/src/com/bbn/openmap/wmsservlet/HttpResponse.java,v $ +// $RCSfile: HttpResponse.java,v $ +// $Revision: 1.3 $ +// $Date: 2008/02/20 01:41:08 $ +// $Author: dietrick $ +// +// ********************************************************************** +package com.bbn.openmap.servlet.wms; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.http.HttpServletResponse; + +import com.bbn.openmap.util.http.IHttpResponse; + +/** + */ +public class HttpResponse implements IHttpResponse { + + protected HttpServletResponse httpResponse; + + /** + * Initialize the input Reader and output Writer + * and start the connection thread. + * + * @param response the response object + */ + public HttpResponse(HttpServletResponse response) { + this.httpResponse = response; + } + + /** + * Write a String response encoded as UTF-8 to the OutputStream. + * + * @param contentType the content type of the response. + * @param response the string containing the response. + */ + public void writeHttpResponse(String contentType, String response) throws IOException { + writeHttpResponse(contentType, response.getBytes("UTF-8")); + } + + /** + * Write a byte[] response to the OutputStream. + * + * @param contentType the content type of the response. + * @param response the byte array containing the response. + */ + public void writeHttpResponse(String contentType, byte[] response) throws IOException { + httpResponse.setContentType(contentType); + httpResponse.setContentLength(response.length); + OutputStream out = httpResponse.getOutputStream(); + out.write(response, 0, response.length); + out.flush(); + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java new file mode 100644 index 00000000..d8a4c7aa --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java @@ -0,0 +1,154 @@ +// ********************************************************************** +// +// BBN Technologies +// 10 Moulton Street +// Cambridge, MA 02138 +// (617) 873-8000 +// +// Copyright (C) BBNT Solutions LLC. All rights reserved. +// +// ********************************************************************** +// $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.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 com.bbn.openmap.PropertyHandler; +import com.bbn.openmap.image.wms.WMSException; +import com.bbn.openmap.image.wms.WmsRequestHandler; +import com.bbn.openmap.util.Debug; + +/** + * + */ +public class OgcWmsServlet extends HttpServlet { + + /** + * A do-nothing constructor - init does all the work. + */ + public OgcWmsServlet() { + super(); + } + + /** + * @param request the request argument + * @return Properties + */ + protected Properties parsePropertiesFromRequest(HttpServletRequest request) { + Properties props = new Properties(); + java.util.Enumeration keys = request.getParameterNames(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + String value = request.getParameter(key); + if (value != null) { + // A wms client can send lowercase request parameters. + key = key.toUpperCase(); + props.put(key, value); + } + } + return props; + } + + /** + * Get a {@link Properties} object with the content of openmap.properties. + * No request specific properties are included. + * + * @return Properties + * @throws MalformedURLException + * @throws IOException + */ + protected Properties getProperties() throws MalformedURLException, + IOException { + + // use context parameter "mapDefinition" for path to openmap.properties. + // default to "openmap.properties". + String mapDefinition = getServletContext().getInitParameter( + "mapDefinition"); + if (mapDefinition == null) { + mapDefinition = "openmap.properties"; + } + Debug.message("wms", "Using map definition:" + mapDefinition); + + PropertyHandler propHandler = new PropertyHandler(mapDefinition); + Properties props = propHandler.getProperties(); + + return props; + } + + protected WmsRequestHandler createRequestHandler(HttpServletRequest request) throws ServletException, + IOException { + Debug.message("wms", "OgcWmsServlet.createRequestHandler : "); + + + String schema = request.getScheme(); + if (schema == null) { + throw new ServletException("schema is not specified"); + } + + String hostName = request.getServerName(); + if (hostName == null) { + throw new ServletException("server name not specified"); + } + + int serverPort = request.getServerPort(); + + String contextPath = request.getContextPath(); + if (contextPath == null) { + throw new ServletException("context path is not specified"); + } + + String servletPath = request.getServletPath(); + if (servletPath == null) { + throw new ServletException("servlet path is not specified"); + } + + // can be used to encode extra things in the path info. only usable by + // subclassing OgcWmsServlet + String servletPathInfo = request.getPathInfo(); + if (servletPathInfo == null) { + servletPathInfo = ""; + } + + try { + WmsRequestHandler wmsRequestHandler = new WmsRequestHandler(schema, hostName, + serverPort, contextPath + servletPath + servletPathInfo, getProperties()); + return wmsRequestHandler; + } catch (java.net.MalformedURLException me) { + Debug.message("wms", "MS: caught MalformedURLException - \n" + me.getMessage()); + throw me; + } catch (java.io.IOException ioe) { + Debug.message("wms", "MS: caught IOException - \n" + ioe.getMessage()); + throw ioe; + } catch (WMSException wmse) { + Debug.message("wms", "MS: caught WMSException - \n" + wmse.getMessage()); + throw new ServletException(wmse); + } + + } + + /** + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + Debug.message("wms", "OgcWmsServlet.doGet"); + WmsRequestHandler wmsRequestHandler = createRequestHandler(request); + + Properties properties = parsePropertiesFromRequest(request); + HttpResponse httpResponse = new HttpResponse(response); + wmsRequestHandler.handleRequest(properties, httpResponse); + } + +} From bf6d994dd50c7e6090bf86d1e7854a16e0de91aa Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 20:05:49 +0100 Subject: [PATCH 05/20] Cleanup after moving servlet classes. --- src/maptileservlet/pom.xml | 159 +++---- .../tileSetProperties/tileset2.properties | 2 +- .../src/main/webapp/WEB-INF/web.xml | 2 +- src/vpfbrowseservlet/pom.xml | 13 +- .../bbn/openmap/vpfservlet/ApplyIterator.java | 52 --- .../com/bbn/openmap/vpfservlet/Applyable.java | 24 - .../ComplexFeatureJoinRowMaker.java | 112 ----- .../vpfservlet/ComplexJoinRowMaker.java | 102 ----- .../bbn/openmap/vpfservlet/ContextInfo.java | 203 --------- .../java/com/bbn/openmap/vpfservlet/Data.java | 418 ------------------ .../openmap/vpfservlet/DescribeDBServlet.java | 311 ------------- .../openmap/vpfservlet/DetailRowMaker.java | 247 ----------- .../openmap/vpfservlet/DirectoryServlet.java | 124 ------ .../openmap/vpfservlet/DispatchServlet.java | 120 ----- .../openmap/vpfservlet/DocFileServlet.java | 109 ----- .../bbn/openmap/vpfservlet/FCSRowMaker.java | 97 ---- .../bbn/openmap/vpfservlet/FITRowMaker.java | 167 ------- .../com/bbn/openmap/vpfservlet/HelloWWW.java | 36 -- .../bbn/openmap/vpfservlet/JoinRowMaker.java | 83 ---- .../bbn/openmap/vpfservlet/LibraryBean.java | 128 ------ .../bbn/openmap/vpfservlet/PlainRowMaker.java | 62 --- .../openmap/vpfservlet/ReferenceRowMaker.java | 46 -- .../com/bbn/openmap/vpfservlet/RowMaker.java | 39 -- .../com/bbn/openmap/vpfservlet/Schema.java | 126 ------ .../vpfservlet/SpatialGraphicServlet.java | 177 -------- .../vpfservlet/SpatialIndexServlet.java | 165 ------- .../vpfservlet/TableSubsetRecordIterator.java | 66 --- .../vpfservlet/ThematicIndexServlet.java | 172 ------- .../bbn/openmap/vpfservlet/TileHolder.java | 202 --------- .../com/bbn/openmap/vpfservlet/URLCheck.java | 136 ------ .../bbn/openmap/vpfservlet/VDTRowMaker.java | 55 --- .../openmap/vpfservlet/VPFHttpServlet.java | 210 --------- .../com/bbn/openmap/vpfservlet/VPFTable.java | 49 -- .../com/bbn/openmap/vpfservlet/package.html | 17 - .../src/main/webapp/PrintTable.jsp | 6 +- .../src/main/webapp/VPFText.jsp | 2 +- src/wmsservlet/pom.xml | 13 +- .../bbn/openmap/wmsservlet/HttpResponse.java | 71 --- .../bbn/openmap/wmsservlet/OgcWmsServlet.java | 154 ------- 39 files changed, 87 insertions(+), 4190 deletions(-) delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java delete mode 100644 src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/package.html delete mode 100644 src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java delete mode 100644 src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java diff --git a/src/maptileservlet/pom.xml b/src/maptileservlet/pom.xml index 0cf7fdbf..816fae79 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 54aef341..2f130218 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 c08e7cf9..3322c8cb 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 adb5b50b..6f12e52e 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/ApplyIterator.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java deleted file mode 100644 index d0dae1cf..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ApplyIterator.java +++ /dev/null @@ -1,52 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.util.Iterator; - -/** - * An Iterator subclass that wraps another iterator. Each element - * returned by the iterator is the result of calling Applyable.apply() - * on the current element of the underlying iterator. - */ -public class ApplyIterator implements Iterator { - /** the iterator to be wrapped */ - final private Iterator wrapped; - /** the Applyable object to use before returning each element */ - final private Applyable applier; - - /** - * Constructor - * - * @param iter the iterator to wrap, may not be null - * @param apply the Applyable object to use in next(), may not be - * null - */ - public ApplyIterator(Iterator iter, Applyable apply) { - wrapped = iter; - applier = apply; - } - - public boolean hasNext() { - return wrapped.hasNext(); - } - - public Object next() { - return applier.apply(wrapped.next()); - } - - public void remove() { - wrapped.remove(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java deleted file mode 100644 index de4ef164..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Applyable.java +++ /dev/null @@ -1,24 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -/** - * Applyable interface for use with ApplyIterator. - */ -public interface Applyable { - /** - * The apply method - */ - Object apply(Object obj); -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java deleted file mode 100644 index f518758c..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexFeatureJoinRowMaker.java +++ /dev/null @@ -1,112 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.VPFUtil; -import com.bbn.openmap.util.html.TableDataElement; -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A RowMaker that performs the join in a feature index table. - */ -public class ComplexFeatureJoinRowMaker extends PlainRowMaker { - /** a list reused to load primitive rows */ - final List primRow = new ArrayList(); - /** a list reused to load feature rows */ - final List featureRow = new ArrayList(); - - /** the array of feature tables, each index is lazy-initialized */ - final DcwRecordFile[] featureTables; - - /** - * Construct a rowmaker for a complex feature join. - * @param drf the table - * @throws FormatException some error was encountered - */ - public ComplexFeatureJoinRowMaker(DcwRecordFile drf) throws FormatException { - featureTables = getTables(drf); - } - - public void addToRow(TableRowElement row, List l) { - try { - boolean color1 = false; - int i = 0; - for (Iterator li = l.iterator(); li.hasNext(); ) { - Object o = li.next(); - DcwRecordFile featureTable = featureTables[i++]; - if ((featureTable != null) && - featureTable.getRow(featureRow, VPFUtil.objectToInt(o))) { - color1 = !color1; - for (Iterator fi = featureRow.iterator(); fi.hasNext(); ) { - row.addElement(new TableDataElement(color1 ? "CLASS=JoinColumn" : "CLASS=Join2Column", - fi.next().toString())); - } - } else { - row.addElement(o.toString()); - } - } - } catch (FormatException fe) { - row.addElement(fe.toString()); - } - } - - public DcwRecordFile[] getTables(DcwRecordFile drf) throws FormatException { - DcwRecordFile[] retval = new DcwRecordFile[drf.getColumnCount()]; - File dirPath = new File(drf.getTableFile()).getParentFile(); - File fcsfile = new File(dirPath, "fcs"); - if (!fcsfile.canRead()) { - fcsfile = new File(dirPath, "fcs."); - } - DcwRecordFile fcs = new DcwRecordFile(fcsfile.toString()); - List l = new ArrayList(fcs.getColumnCount()); - String tableName = drf.getTableName(); - - int table1Column = fcs.whatColumn("table1"); - int table1_keyColumn = fcs.whatColumn("table1_key"); - int table2Column = fcs.whatColumn("table2"); - int table2_keyColumn = fcs.whatColumn("table2_key"); - - while (fcs.parseRow(l)) { - String table1 = (String)l.get(table1Column); - String table1_key = (String)l.get(table1_keyColumn); - String table2 = (String)l.get(table2Column); - String table2_key = (String)l.get(table2_keyColumn); - if (table1.equalsIgnoreCase(tableName) && - table2_key.equalsIgnoreCase("id")) { - int indexCol = drf.whatColumn(table1_key); - retval[indexCol] = new DcwRecordFile(dirPath + File.separator + table2); - } - } - - fcs.close(); - return retval; - } - - public void close() { - for (int i = 0; i < featureTables.length; i++) { - DcwRecordFile drf = featureTables[i]; - if (drf != null) { - drf.close(); - } - } - } -} - diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java deleted file mode 100644 index 9635478a..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ComplexJoinRowMaker.java +++ /dev/null @@ -1,102 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.FeatureClassInfo; -import com.bbn.openmap.util.html.TableDataElement; -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A RowMaker subclass that handles joins between tables, where the - * column guiding the join of the second table is not "id", and thus - * not simply the row identifier. - */ -public class ComplexJoinRowMaker extends PlainRowMaker { - /** the column that contains the foreign key to the primitive table */ - final int theColumn; - /** the column that contains the tile identifier */ - final int tileColumn; - /** a list reused to load join rows */ - final List jtrow = new ArrayList(); - - /** a map from the table key to row id */ - final Map keyMap; - /** the table we're joining with */ - final DcwRecordFile joinTable; - - public ComplexJoinRowMaker(DcwRecordFile table, String joinColumnName, - String tableName, String tableKeyColumn, boolean isTiled) - throws FormatException { - theColumn = table.whatColumn(joinColumnName); - tileColumn = table.whatColumn(FeatureClassInfo.TILE_ID_COLUMN_NAME); - if (isTiled) { - throw new FormatException("can't complex join with tiling (yet)"); - } - joinTable = new DcwRecordFile(new File(table.getTableFile()).getParentFile() - + File.separator + tableName); - keyMap = getKeyMap(tableKeyColumn); - } - - HashMap getKeyMap(String keyColumn) throws FormatException { - int jcol = joinTable.whatColumn(keyColumn); - HashMap retmap = new HashMap(); - while (joinTable.parseRow(jtrow)) { - retmap.put(jtrow.get(jcol), jtrow.get(0)); - } - return retmap; - } - - public void addToRow(TableRowElement row, List l) { - int i = 0; - for (Iterator li = l.iterator(); li.hasNext();) { - Object elt = li.next(); - if (i == theColumn) { - Number wrow = (Number) keyMap.get(elt); -// int tileId = (tileColumn == -1) ? -1 -// : VPFUtil.objectToInt(l.get(tileColumn)); - - try { - if (wrow == null) { - row.addElement("[" + elt + "]"); - } else if (joinTable.getRow(jtrow, wrow.intValue())) { - for (Iterator it = jtrow.iterator(); it.hasNext();) { - row.addElement(new TableDataElement("CLASS=JoinColumn", it.next() - .toString())); - } - } else { - row.addElement("Join failed!"); - } - } catch (FormatException fe) { - row.addElement(fe.toString()); - } - } else { - row.addElement(elt.toString()); - } - i++; - } - } - - public void close() { - joinTable.close(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java deleted file mode 100644 index 76707b10..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ContextInfo.java +++ /dev/null @@ -1,203 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import com.bbn.openmap.layer.vpf.LibrarySelectionTable; -import java.io.File; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import javax.servlet.ServletContext; - -/** - * This class holds information retrieved from the ServletContext. - */ -public class ContextInfo { - - /** - * the name of the attribute where ContextInfo objects are in the ServletContext - */ - public static final String CONTEXT_INFO = ContextInfo.class.getPackage().getName() + ".contextInfo"; - /** - * the prefix used to configure VPF libraries in web.xml - */ - public static final String LIBRARY_PREFIX = ContextInfo.class.getPackage().getName() + ".vpf_library."; - - /** - * a map from library name to (String) library path - */ - private Map lib_pathmap; - /** - * a map from library name to LibrarySelectionTable - */ - private Map lib_lstmap; - - /** - * A constructor - use getContextInfo to get one. - * - * @param context the ServletContext to use to initialize - * @see #getContextInfo - */ - private ContextInfo(ServletContext context) { - lib_pathmap = createLibrariesMap(context); - lib_lstmap = new HashMap(); - } - - /** - * Returns the ContextInfo object for the ServletContext. - * - * @param context the ServletContext to either get an existing ContextInfo from, or the context to use to initialize - * a new ContextInfo, if one doesn't already exist for the context. - */ - public static synchronized ContextInfo getContextInfo(ServletContext context) { - ContextInfo ci = (ContextInfo) context.getAttribute(CONTEXT_INFO); - if (ci == null) { - ci = new ContextInfo(context); - context.setAttribute(CONTEXT_INFO, ci); - } - return ci; - } - - /** - * Grovels through the ServletContext initialization parameters and creates a map from library name to library path. - * - * @param context the context to grovel through - */ - private Map createLibrariesMap(ServletContext context) { - HashMap library_map = new HashMap(); - for (Enumeration en = context.getInitParameterNames(); en.hasMoreElements();) { - String s = (String) en.nextElement(); - if (s.startsWith(LIBRARY_PREFIX)) { - String libname = s.substring(LIBRARY_PREFIX.length()); - String path = getPath(context, context.getInitParameter(s)); - if (path != null) { - library_map.put(libname, path); - } else { - context.log("Excluding " + libname - + " from database list, can't resolve path"); - } - - } - } - return Collections.unmodifiableMap(library_map); - } - - /** - * Try and find an absolute path from an init parameter - * - * @param context the context to use to resolve paths - * @param path the path to try and resolve - * @return an absolute path to a file (hopefully a directory) on the system, or null indicating the resolve failed - * to find anything useful. - */ - private String getPath(ServletContext context, String path) { - // try to resolve as a relative path in the war file - try { - String p2 = context.getRealPath(path); - if (p2 != null) { - File f = new File(p2); - if (f.exists()) { - return p2; - } - } - } catch (java.security.AccessControlException jsace) { - // ignore, nothing to do but press on - } - // try to resolve as an absolute path on the system - try { - File f = new File(path); - if (f.exists()) { - return path; - } - } catch (java.security.AccessControlException jsace) { - // ignore, nothing to do - } - return null; - } - - /** - * Return a file object that the path resolves to. Performs some minimal checks to try and prevent an attacker from - * feeding in urls that cause the servlets to climb out of their sandbox. A better option is to use a servlet - * container with the ability to restrict servlet file access. For example, Apache Software Foundation's Tomcat 5 - * Servlet/JSP Container running with the -security flag. - * - * @param pathInfo the path to resolve (expected to be of the form "/library_name_in_web_xml/path/to/file") - * @return a File if it could be resolved, null otherwise - */ - public String resolvePath(String pathInfo) { - if ((pathInfo == null) || (pathInfo.indexOf("..") != -1)) { // don't - // climb - // out - // of - // sandbox - return null; - } - int libStart = pathInfo.indexOf('/') + 1; - int libEnd = pathInfo.indexOf('/', libStart); - if (libEnd == -1) { - libEnd = pathInfo.length(); - } - String libname = pathInfo.substring(libStart, libEnd); - String subpath = pathInfo.substring(libEnd); - - String lib_home = getPath(libname); - if (lib_home == null) { - return null; - } - - return lib_home + "/" + subpath; - } - - /** - * Returns a Set whose values are the (String) names of the configured libraries. - * - * @return a set of library names - */ - public Set keySet() { - return new TreeSet(lib_pathmap.keySet()); - } - - /** - * Returns the path (or null) for the library - * - * @param libname the library name - * @return the path or null - */ - public String getPath(String libname) { - return (String) lib_pathmap.get(libname); - } - - /** - * Returns the LibrarySelectionTable (or null) for the library - * - * @param libname the library name - * @return the LST or null - */ - public LibrarySelectionTable getLST(String libname) { - return (LibrarySelectionTable) lib_lstmap.get(libname); - } - - /** - * Adds an LST for a library - * - * @param libname the library name - * @param lst the LibrarySelectionTable for libname - */ - public void putLST(String libname, LibrarySelectionTable lst) { - lib_lstmap.put(libname, lst); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java deleted file mode 100644 index cb497d62..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Data.java +++ /dev/null @@ -1,418 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -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; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.util.html.ListElement; -import com.bbn.openmap.util.html.StringElement; -import com.bbn.openmap.util.html.TableHeaderElement; -import com.bbn.openmap.util.html.TableRowElement; -import com.bbn.openmap.util.html.WrapElement; - -/** - * A servlet class that will output table data. - */ -public class Data extends VPFHttpServlet { - /** the name of the http parameter with the table name */ - public static final String VDTParam = "vdt"; - /** the possible values of the rowselect parameter */ - public static final String RowSelectParam = "show"; - public static final String RowSelectAll = "all"; - public static final String RowSelectNone = "none"; - public static final String RowSelectTest = "test"; - /** other parameters that the servlet takes */ - public static final String JoinColumnParam = "colname"; - public static final String JoinOtherTableParam = "othertable"; - public static final String JoinOtherTableKeyParam = "othertablekey"; - public static final String IsTiledParam = "isTiled"; - - /** - * A do-nothing constructor - init does all the work. - */ - public Data() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - DcwRecordFile foo = (DcwRecordFile) request.getAttribute(DispatchServlet.RECORD_FILE_OBJ); - if (foo == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - try { - doWork(request, response, foo); - } catch (FormatException fe) { - response.getWriter().println("FormatException dealing with table: " - + fe); - } - } - - /** - * Generates the heading used for each HTML table - */ - protected TableRowElement generateHeader(HttpServletRequest req, - HttpServletResponse resp, - DcwColumnInfo[] dci) { - TableRowElement thr = new TableRowElement(); - for (int i = 0; i < dci.length; i++) { - DcwColumnInfo dc = dci[i]; - String colName = dc.getColumnName(); - if (dc.getValueDescriptionTable() == null) { - thr.addElement(new TableHeaderElement(colName)); - } else { - StringBuffer baseurl = new StringBuffer(); - baseurl.append(req.getContextPath()); - baseurl.append(req.getServletPath()); - baseurl.append(req.getPathInfo()).append("?"); - String show = req.getParameter(RowSelectParam); - String vdtl = req.getParameter(VDTParam); - if (show != null) { - baseurl.append(RowSelectParam).append("="); - baseurl.append(show).append("&"); - } - baseurl.append(VDTParam).append("="); - if (vdtl == null) { - vdtl = ""; - } - boolean appendCol = true; - boolean needSep = false; - StringTokenizer st = new StringTokenizer(vdtl, ","); - while (st.hasMoreTokens()) { - String sname = st.nextToken(); - if (colName.equals(sname)) { - appendCol = false; - } else { - append(baseurl, sname, needSep); - needSep = true; - } - } - if (appendCol) { - append(baseurl, colName, needSep); - } - thr.addElement(THE(colName, baseurl.toString())); - } - } - return thr; - } - - public static StringBuffer append(StringBuffer base, String app, - boolean needSep) { - return (needSep ? base.append(",") : base).append(app); - } - - public static final String ROWLIST_OBJECT = Data.class.getPackage() - .getName() - + ".rowlist"; - - protected void doWork(HttpServletRequest request, - HttpServletResponse response, DcwRecordFile drf) - throws FormatException, IOException { - DcwColumnInfo dci[] = drf.getColumnInfo(); - - int rowlist[] = (int[]) request.getAttribute(ROWLIST_OBJECT); - - ListElement rows = new ListElement(); - WrapElement table = new WrapElement("table", "BORDER=1 ALIGN=CENTER", rows); - TableRowElement thr = generateHeader(request, response, dci); - rows.addElement(thr); - - String row_show = request.getParameter(RowSelectParam); - boolean printall = RowSelectAll.equals(row_show); - boolean parseall = RowSelectTest.equals(row_show); - boolean schemaonly = RowSelectNone.equals(row_show); - - String baseurl = request.getContextPath() + request.getServletPath() - + request.getPathInfo(); - String all = baseurl + "?" + RowSelectParam + "=" + RowSelectAll; - String none = baseurl + "?" + RowSelectParam + "=" + RowSelectNone; - String some = baseurl; - String test = baseurl + "?" + RowSelectParam + "=" + RowSelectTest; - String qstr = request.getQueryString(); - if (rowlist != null) { - qstr = null; - } - if (qstr == null) { - qstr = VDTParam + "=ALL"; - } - if (qstr.indexOf(VDTParam + "=") == -1) { - qstr += "&" + VDTParam + "=ALL"; - } - String vdtlookup = baseurl + "?" + qstr; - - response.getWriter().println("

Table Data

"); - String redisplay = "Redisplay " + buildHREF(response, all, "All") - + "\r\n|" + buildHREF(response, none, "None") + "\r\n|" - + buildHREF(response, some, "Some") + "\r\n|" - + buildHREF(response, test, "Test") + "\r\n|" - + buildHREF(response, vdtlookup, "All VDT Columns") + "\r\n"; - - if (schemaonly) { - response.getWriter().println("Data Omitted: " + redisplay); - return; - } - - RowMaker rm; - String basepath = getRootDir(request); - String joincol = request.getParameter(JoinColumnParam); - String jointable = request.getParameter(JoinOtherTableParam); - String jointablekey = request.getParameter(JoinOtherTableKeyParam); - if ((joincol != null) && (jointable != null)) { - String isTiledJoin = request.getParameter(IsTiledParam); - boolean isTiled = Boolean.valueOf(isTiledJoin).booleanValue(); - if (Constants.ID.equals(jointablekey)) { - rm = new JoinRowMaker(drf, joincol, jointable, isTiled); - } else { - rm = new ComplexJoinRowMaker(drf, joincol, jointable, jointablekey, isTiled); - } - } else if (drf.getTableName().equals(Constants.charVDTTableName) - || drf.getTableName().equals(Constants.intVDTTableName)) { - rm = new VDTRowMaker(request, response, basepath, drf); - } else if (drf.getTableName().equals("fcs")) { - rm = new FCSRowMaker(request, response, basepath, drf); - } else if (request.getParameter(VDTParam) != null) { - String subsetmarkup = request.getParameter(VDTParam); - String[] ss = null; - if (subsetmarkup != null) { - StringTokenizer st = new StringTokenizer(subsetmarkup, ",", false); - ss = new String[st.countTokens()]; - for (int i = 0; i < ss.length; i++) { - ss[i] = st.nextToken(); - if ("ALL".equals(ss[i])) { - ss = null; // null array gets all VDT lookups - break; - } - } - } - rm = new DetailRowMaker(drf, ss); - } else if (drf.getTableName().endsWith(".fit")) { - rm = new FITRowMaker(drf); - } else if (drf.getTableName().endsWith(".cft") - || drf.getTableName().endsWith(".cjt")) { - rm = new ComplexFeatureJoinRowMaker(drf); - } else { - rm = new PlainRowMaker(); - } - - Iterator rowiter; - if (rowlist != null) { - rowiter = new TableSubsetRecordIterator(rowlist, drf); - } else if (printall) { - rowiter = new TableListIterator(drf); - } else if (parseall) { - rowiter = new TableTestParseIterator(drf); - } else { - rowiter = new TableSampleIterator(drf); - } - // response.getWriter().println("
Tn = " + - // drf.getTableName() + - // "
" + rm.getClass().getName() + " " + - // rowiter.getClass().getName() + "
"); - int rowcount = 0; - while (rowiter.hasNext()) { - if (rowcount++ >= 99) { - response.getWriter().println(redisplay); - table.generate(response.getWriter()); - rows = new ListElement(); - table = new WrapElement("table", "BORDER=1 ALIGN=CENTER", rows); - rows.addElement(new WrapElement("CAPTION", new StringElement("table data"))); - rows.addElement(thr); - - rowcount = 0; - } - rows.addElement(rm.generateRow((List) rowiter.next())); - } - rm.close(); - response.getWriter().println(redisplay); - table.generate(response.getWriter()); - } - - public ContextInfo getContextInfo() { - return contextInfo; - } - - public static String joinURL(HttpServletRequest request, - HttpServletResponse response, int tag, - String filename, String colname, - String othertable, String othertablekey, - boolean isTiled) { - String pathInfo = request.getPathInfo(); - int index = pathInfo.lastIndexOf('/'); - String subpath = pathInfo.substring(0, index + 1); - String url = request.getContextPath() + request.getServletPath() - + subpath + filename + "?" + JoinColumnParam + "=" + colname - + "&" + JoinOtherTableParam + "=" + othertable + "&" - + JoinOtherTableKeyParam + "=" + othertablekey + "&" - + IsTiledParam + "=" + isTiled; - String value = "" + tag - + "\r\n"; - return value; - } - - /** - * An iterator that returns a subset of the table rows - */ - private static class TableSampleIterator implements Iterator { - private final int recordCount; - private final int columnCount; - private int curRow = 0; - private final DcwRecordFile drf; - - public TableSampleIterator(DcwRecordFile drf) throws FormatException { - this.drf = drf; - recordCount = drf.getRecordCount(); - columnCount = drf.getColumnCount(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return (curRow < recordCount); - } - - public Object next() { - if (curRow < 10) { - curRow++; - } else if (curRow == 10) { - curRow = 100; - } else { - curRow += 100; - } - if (curRow > recordCount) { - curRow = recordCount; - } - ArrayList al = new ArrayList(columnCount); - try { - if (!drf.getRow(al, curRow)) { - throw new NoSuchElementException(); - } - } catch (FormatException fe) { - throw new NoSuchElementException(); - } - return al; - } - } - - /** - * An iterator that returns a subset of the table rows, but parses - * every record in the table. - */ - private static class TableTestParseIterator implements Iterator { - final ListIterator base; - - public TableTestParseIterator(DcwRecordFile drf) throws FormatException { - base = new TableListIterator(drf); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return base.hasNext(); - } - - public Object next() { - int index; - Object ret; - do { - index = base.nextIndex(); - ret = base.next(); - } while ((index > 10) && ((index % 100) != 0) && base.hasNext()); - return ret; - } - } - - /** - * An iterator that will return every row in the table. - */ - private static class TableListIterator implements java.util.ListIterator { - private int curRow = 1; - private final DcwRecordFile drf; - private final int columnCount; - private final int recordCount; - - public TableListIterator(DcwRecordFile drf) throws FormatException { - this.drf = drf; - columnCount = drf.getColumnCount(); - recordCount = drf.getRecordCount(); - } - - public void add(Object o) { - throw new UnsupportedOperationException(); - } - - public boolean hasPrevious() { - return (curRow > 1); - } - - public boolean hasNext() { - return (curRow <= recordCount); - } - - private ArrayList getRow(int row) { - ArrayList al = new ArrayList(columnCount); - try { - if (!drf.getRow(al, row)) { - throw new NoSuchElementException(); - } - } catch (FormatException fe) { - throw new NoSuchElementException(); - } - return al; - } - - public Object next() { - return getRow(curRow++); - } - - public Object previous() { - return getRow(--curRow); - } - - public int nextIndex() { - return curRow; - } - - public int previousIndex() { - return (curRow - 1); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - public void set(Object o) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java deleted file mode 100644 index 495b3f13..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DescribeDBServlet.java +++ /dev/null @@ -1,311 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -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; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.FeatureClassInfo; -import com.bbn.openmap.layer.vpf.LibrarySelectionTable; -import com.bbn.openmap.util.html.HtmlListElement; -import com.bbn.openmap.util.html.ListBodyElement; -import com.bbn.openmap.util.html.ListElement; -import com.bbn.openmap.util.html.WrapElement; - -/** - * This class prints out a description of a VPF database, listing the available - * libraries, coverage types and feature types. - */ - -public class DescribeDBServlet - extends VPFHttpServlet { - /** - * Takes path arguments, and prints the DB it finds - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - response.setContentType("text/html"); - PrintWriter out = response.getWriter(); - - out.println(HTML_DOCTYPE); - out.println(getStylesheetHTML(request)); - - String pathInfo = request.getPathInfo(); - if (pathInfo == null) { - selectDB(request, response); - return; - } - int findex = pathInfo.indexOf('/', 1); - if (findex < 0) { - findex = pathInfo.length(); - } - String libname = pathInfo.substring(1, findex); - - try { - LibrarySelectionTable lst = getLST(libname); - if (lst == null) { - out.println("VPF Database not configured: " + libname); - return; - } - String dbname = lst.getDatabaseName(); - out.println("\nDescribe VPF Database " + dbname + "\n\n

VPF Database " - + dbname + "

\n"); - ListElement dble = new ListBodyElement(); - WrapElement dblist = new WrapElement("ul", dble); - dble.addElement("Database Description: " + lst.getDatabaseDescription()); - dble.addElement("Database Description Table: " + buildURL(request, response, libname, "dht")); - List libraries = lst.getLibraryNames(); - StringBuffer libnames = new StringBuffer("Database Libraries: "); - for (String libName : libraries) { - libnames.append("").append(libName); - libnames.append("").append(" "); - } - libnames.append("(from "); - libnames.append(buildURL(request, response, libname, "lat")); - libnames.append(")"); - - dble.addElement(libnames.toString()); - dblist.generate(out); - for (String libName : libraries) { - // String prefix = libraries[i] + ":"; - printLibrary(request, response, libname, lst.getCAT(libName)); - } - out.println(""); - } catch (FormatException fe) { - throw new ServletException("FormatException: ", fe); - } - } - - public void selectDB(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - PrintWriter out = response.getWriter(); - - Set databases = contextInfo.keySet(); - - out.println("\nSelect VPF Database" + "\n\n

Available VPF Databases" + "

\n"); - HtmlListElement dblist = new HtmlListElement(); - for (Iterator dbi = databases.iterator(); dbi.hasNext();) { - String db = (String) dbi.next(); - String url = request.getContextPath() + "/DescribeVPF/" + db; - dblist.addElement("" + db + "\r\n"); - } - dblist.generate(out); - out.println("\r\n"); - } - - public static String buildURL(HttpServletRequest request, HttpServletResponse response, String filepref, String filename, - String tag) { - String url = request.getContextPath() + "/UnknownType/" + filepref + "/" + filename; - return "" + tag + ""; - } - - public static String buildURL(HttpServletRequest request, HttpServletResponse response, String filepref, String filename) { - return buildURL(request, response, filepref, filename, filename); - } - - /** - * Prints a VPF Library. - * - * @param request the HttpServletRequest. - * @param response the HTTPServletResponse. - * @param pathPrefix lines get printed with this prefix - * @param cat the CoverageAttributeTable (Library) to print - */ - public void printLibrary(HttpServletRequest request, HttpServletResponse response, String pathPrefix, CoverageAttributeTable cat) - throws ServletException, IOException { - PrintWriter out = response.getWriter(); - - if (cat == null) { - out.println("

Catalog doesn't exist

"); - return; - } - String libName = cat.getLibraryName(); - String libpath = pathPrefix + "/" + libName; - - out.println("

Library " + buildURL(request, response, pathPrefix, libName, libName) - + "

"); - String[] coverages = cat.getCoverageNames(); - Arrays.sort(coverages); - - HtmlListElement list = new HtmlListElement(); - list.addElement("Library uses " + (cat.isTiledData() ? "tiled" : "untiled") + " data"); - HtmlListElement clist = new HtmlListElement("Coverage names (from " + buildURL(request, response, libpath, "cat") + ")"); - - list.addElement(clist); - for (int i = 0; i < coverages.length; i++) { - clist.addElement("" + coverages[i] + ""); - } - list.addElement("Library Header Table: " + buildURL(request, response, libpath, "lht")); - list.addElement("Geographic Reference Table: " + buildURL(request, response, libpath, "grt")); - list.generate(out); - for (int i = 0; i < coverages.length; i++) { - printCoverage(request, response, libpath + "/" + coverages[i], libName, cat, coverages[i]); - } - } - - /** - * Prints a VPF Coverage - * - * @param pathPrefix lines get printed with this prefix - * @param cat the CoverageAttributeTable to get the Coverage from - * @param covname the name of the coverage to print - */ - public void printCoverage(HttpServletRequest request, HttpServletResponse response, String pathPrefix, String libName, - CoverageAttributeTable cat, String covname) - throws ServletException, IOException { - PrintWriter out = response.getWriter(); - out.println("

Coverage " - + buildURL(request, response, pathPrefix, "", covname) + " for Library " + libName - + "

"); - HtmlListElement list = new HtmlListElement(); - list.addElement("Description: " + cat.getCoverageDescription(covname)); - list.addElement("Topology Level: " + cat.getCoverageTopologyLevel(covname)); - String fcsURL = buildURL(request, response, pathPrefix, "fcs?" + Data.RowSelectParam + "=" + Data.RowSelectAll, "fcs"); - list.addElement("Feature Class Schema: " + fcsURL); - CoverageTable ct = cat.getCoverageTable(covname); - // CoverageTable opens alot of files, go through and close - // them - for (Iterator i = ct.getFeatureClasses().values().iterator(); i.hasNext();) { - FeatureClassInfo fci = (FeatureClassInfo) i.next(); - fci.close(); - } - - Map ftypeinfo = new TreeMap(ct.getFeatureTypeInfo()); - if (ftypeinfo.size() == 0) { - list.addElement("No Feature Types in FCA"); - } else { - HtmlListElement flist = - new HtmlListElement("Feature Types (from " + buildURL(request, response, pathPrefix, "fca") + ")"); - list.addElement(flist); - for (Iterator i = ftypeinfo.values().iterator(); i.hasNext();) { - CoverageTable.FeatureClassRec fcr = (CoverageTable.FeatureClassRec) i.next(); - String name = fcr.feature_class.toLowerCase(); - // char t = fcr.type; - String desc = fcr.description; - String tstring = "[unknown] "; - String suffix = ""; - switch (fcr.type) { - case CoverageTable.TEXT_FEATURETYPE: - tstring = "[text feature] "; - suffix = ".tft"; - break; - case CoverageTable.EDGE_FEATURETYPE: - tstring = "[edge feature] "; - suffix = ".lft"; - break; - case CoverageTable.AREA_FEATURETYPE: - tstring = "[area feature] "; - suffix = ".aft"; - break; - case CoverageTable.UPOINT_FEATURETYPE: - FeatureClassInfo fci = ct.getFeatureClassInfo(name); - char type = (fci != null) ? fci.getFeatureType() : CoverageTable.SKIP_FEATURETYPE; - if (type == CoverageTable.EPOINT_FEATURETYPE) { - tstring = "[entity point feature] "; - } else if (type == CoverageTable.CPOINT_FEATURETYPE) { - tstring = "[connected point feature] "; - } else { - tstring = "[missing point feature] "; - } - suffix = ".pft"; - break; - case CoverageTable.COMPLEX_FEATURETYPE: - tstring = "[complex feature] "; - suffix = ".cft"; - break; - default: - tstring = "[unknown] "; - suffix = ""; - } - String url = buildURL(request, response, pathPrefix, name + suffix, name); - flist.addElement(url + ": " + tstring + desc); - } - } - try { - HtmlListElement flist = new HtmlListElement("Feature Types (from " + fcsURL + ")"); - boolean generateflist = false; - DcwRecordFile fcs = new DcwRecordFile(ct.getDataPath() + File.separator + "fcs" + (ct.appendDot ? "." : "")); - int featureClassColumn = fcs.whatColumn("feature_class"); - int table1Column = fcs.whatColumn("table1"); - // int table1_keyColumn = fcs.whatColumn("table1_key"); - // int table2Column = fcs.whatColumn("table2"); - // int table2_keyColumn = fcs.whatColumn("table2_key"); - - List fcsl = new ArrayList(fcs.getColumnCount()); - while (fcs.parseRow(fcsl)) { - String featureclass = ((String) fcsl.get(featureClassColumn)).toLowerCase(); - String table1 = ((String) fcsl.get(table1Column)).toLowerCase(); - if (!ftypeinfo.containsKey(featureclass)) { - ftypeinfo.put(featureclass, null); - String type = null; - if (table1.endsWith(".cft")) { - type = "complex feature"; - } else if (table1.endsWith(".pft")) { - type = "point feature"; - } else if (table1.endsWith(".lft")) { - type = "line feature"; - } else if (table1.endsWith(".aft")) { - type = "area feature"; - } else if (table1.endsWith(".tft")) { - type = "text feature"; - } - if (type != null) { - generateflist = true; - flist.addElement(type + " " + buildURL(request, response, pathPrefix, table1, featureclass)); - } - } - } - if (generateflist) { - list.addElement(flist); - } - fcs.close(); - } catch (FormatException fe) { - list.addElement("no fcs"); - } - list.generate(out); - } - - public LibrarySelectionTable getLST(String libname) - throws FormatException { - LibrarySelectionTable lst = contextInfo.getLST(libname); - if (lst == null) { - String lib_home = contextInfo.getPath(libname); - if (lib_home == null) { - return null; - } - // File flib_home = new File(lib_home); - - lst = new LibrarySelectionTable(lib_home); - contextInfo.putLST(libname, lst); - } - return lst; - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java deleted file mode 100644 index 2944a67b..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DetailRowMaker.java +++ /dev/null @@ -1,247 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.Constants; -import com.bbn.openmap.layer.vpf.CoverageTable; -import com.bbn.openmap.layer.vpf.DcwColumnInfo; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A RowMaker class that will perform VDT (value description table) - * lookups on selected columns in the table. - */ -public class DetailRowMaker extends PlainRowMaker { - final HashMap intvdt; - final HashMap charvdt; - final DcwColumnInfo dcia[]; - - /** - * Constructor - * - * @param drf the table being parsed - * @param markupCols the column names of the columns to attempt - * lookups for - */ - public DetailRowMaker(DcwRecordFile drf, String[] markupCols) { - File pfile = new File(drf.getTableFile()).getParentFile(); - String tableName = drf.getTableName(); - intvdt = loadIntVDT(pfile, tableName); - charvdt = loadCharVDT(pfile, tableName); - DcwColumnInfo dc[] = drf.getColumnInfo(); - if (markupCols == null) { - dcia = dc; - } else { - dcia = new DcwColumnInfo[dc.length]; - for (int i = 0; i < markupCols.length; i++) { - int col = drf.whatColumn(markupCols[i]); - if (col != -1) { - dcia[col] = dc[col]; - } - } - } - } - - public void addToRow(TableRowElement row, List l) { - int i = 0; - for (Iterator vals = l.listIterator(); vals.hasNext();) { - Object rval = vals.next(); - String vdt = (dcia[i] != null) ? dcia[i].getVDT() : null; - if (vdt == null) { - row.addElement(rval.toString()); - } else if (Constants.intVDTTableName.equals(vdt) - && (rval instanceof Number)) { - int val = ((Number) rval).intValue(); - CoverageIntVdt civ = new CoverageIntVdt(dcia[i].getColumnName(), val); - String lval = (String) intvdt.get(civ); - row.addElement((lval == null) ? ("[" + val + "]") : lval); - } else if (Constants.charVDTTableName.equals(vdt) - && (rval instanceof String)) { - String val = (String) rval; - CoverageCharVdt civ = new CoverageCharVdt(dcia[i].getColumnName(), val); - String lval = (String) charvdt.get(civ); - row.addElement((lval == null) ? ("[" + val + "]") : lval); - } else { - row.addElement("Table Data Error!"); - } - i++; - } - } - - private HashMap loadIntVDT(File path, String tableName) { - HashMap hm = new HashMap(); - try { - File vdt = new File(path, Constants.intVDTTableName); - if (vdt.canRead()) { - DcwRecordFile intvdt = new DcwRecordFile(vdt.toString()); - int intcols[] = intvdt.lookupSchema(CoverageTable.VDTColumnNames, - true, - CoverageTable.intVDTschematype, - CoverageTable.intVDTschemalength, - false); - - List al = new ArrayList(intvdt.getColumnCount()); - while (intvdt.parseRow(al)) { - String tab = (String) al.get(intcols[0]); - if (!tableName.equalsIgnoreCase(tab)) { - continue; - } - String attr = (String) al.get(intcols[1]); - int val = ((Number) al.get(intcols[2])).intValue(); - String desc = ((String) al.get(intcols[3])).intern(); - hm.put(new CoverageIntVdt(attr, val), desc); - } - intvdt.close(); - } - } catch (FormatException f) { - } - return hm; - } - - private HashMap loadCharVDT(File path, String tableName) { - HashMap hm = new HashMap(); - try { - File vdt = new File(path, Constants.charVDTTableName); - if (vdt.canRead()) { - DcwRecordFile charvdt = new DcwRecordFile(vdt.toString()); - int charcols[] = charvdt.lookupSchema(CoverageTable.VDTColumnNames, - true, - CoverageTable.charVDTschematype, - CoverageTable.charVDTschemalength, - false); - - ArrayList al = new ArrayList(charvdt.getColumnCount()); - while (charvdt.parseRow(al)) { - String tab = (String) al.get(charcols[0]); - if (!tableName.equalsIgnoreCase(tab)) { - continue; - } - String attr = (String) al.get(charcols[1]); - String val = (String) al.get(charcols[2]); - String desc = ((String) al.get(charcols[3])).intern(); - hm.put(new CoverageCharVdt(attr, val), desc); - } - charvdt.close(); - } - } catch (FormatException f) { - } - return hm; - } -} - -/** - * A utility class used to map information from a VPF feature table to - * its associated value in an int.vdt file. - */ -class CoverageIntVdt { - /** - * the name of the attribute we are looking up (attribute is - * interned) - */ - final String attribute; - /** the integer value we are looking up */ - final int value; - - /** - * Construct a new object - * - * @param a the value for the attribute member - * @param v the value for the value member - */ - public CoverageIntVdt(String a, int v) { - attribute = a.toLowerCase().intern(); - value = v; - } - - /** - * Override the equals method. Two CoverageIntVdts are equal if - * and only iff their respective attribute and value members are - * equal. - */ - public boolean equals(Object o) { - if (o instanceof CoverageIntVdt) { - CoverageIntVdt civ = (CoverageIntVdt) o; - // we can use == rather than String.equals(String) since - // attribute is interned. - return ((attribute == civ.attribute) && (value == civ.value)); - } else { - return false; - } - } - - /** - * Override hashcode. Compute a hashcode based on our member - * values, rather than our (base class) object identity. - */ - public int hashCode() { - return (attribute.hashCode() ^ value); - } -} - -/** - * A utility class used to map information from a VPF feature table to - * its associated value in an char.vdt file. - */ -class CoverageCharVdt { - /** - * the name of the attribute we are looking up (attribute is - * interned) - */ - final String attribute; - /** the character value we are looking up (value is interned) */ - final String value; - - /** - * Construct a new object - * - * @param a the value for the attribute member - * @param v the value for the value member - */ - public CoverageCharVdt(String a, String v) { - attribute = a.toLowerCase().intern(); - value = v.intern(); - } - - /** - * Override the equals method. Two CoverageIntVdts are equal if - * and only iff their respective attribute and value members are - * equal. - */ - public boolean equals(Object o) { - if (o instanceof CoverageCharVdt) { - CoverageCharVdt civ = (CoverageCharVdt) o; - // we can use == rather than String.equals(String) since - // attribute, and value are interned. - return ((attribute == civ.attribute) && (value == civ.value)); - } else { - return false; - } - } - - /** - * Override hashcode. Compute a hashcode based on our member - * values, rather than our (base class) object identity. - */ - public int hashCode() { - return (attribute.hashCode() ^ value.hashCode()); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java deleted file mode 100644 index c719e823..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DirectoryServlet.java +++ /dev/null @@ -1,124 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -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; - -/** - * This servlet lists the files in a directory of a configured VPF database. - * Directory listing can be disabled, see the listDirectories servlet parameter - * in the deployment descriptor. (web.xml) - */ -public class DirectoryServlet - extends VPFHttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public DirectoryServlet() { - super(); - } - - /** - * false if this servlet should generate a "disabled by administrator" - * method rather than a directory list. - */ - private boolean listFiles; - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); - if (filePath == null) { - String path = setPathInfo(request); - filePath = contextInfo.resolvePath(path); - if (!pathOkay(filePath, path, response)) { - return; - } - } - File fp = new File(filePath); - String pathInfo = getPathInfo(request); - - PrintWriter out = response.getWriter(); - - String filename = fp.getName().toLowerCase(); - - // This was never used!!! - String end = ""; - - response.setContentType("text/html"); - out.println(HTML_DOCTYPE + "\n" + filename + "\r\n\r\n

Directory " + filename - + "

\r\n"); - out.println(getStylesheetHTML(request)); - - if (!listFiles) { - out.println("Directory listing disabled by administrator."); - } else if (!fp.isDirectory()) { - out.println("Requested path is not a directory."); - } else { - out.println(""); - File files[] = fp.listFiles(); - ArrayList filenames = new ArrayList(); - ArrayList directories = new ArrayList(); - for (int i = 0; i < files.length; i++) { - String name = files[i].getName(); - if (files[i].isDirectory()) { - directories.add(name); - } else { - filenames.add(name); - } - } - Collections.sort(directories); - Collections.sort(filenames); - - if (!pathInfo.endsWith("/")) { - pathInfo += '/'; - } - - HtmlListElement filelist = new HtmlListElement("Sub-Directories"); - - for (Iterator dir = directories.iterator(); dir.hasNext();) { - String url = fileURL(request, response, pathInfo, (String) dir.next()); - filelist.addElement(url); - } - filelist.generate(out); - - filelist = new HtmlListElement("Files"); - for (Iterator file = filenames.iterator(); file.hasNext();) { - String url = fileURL(request, response, pathInfo, (String) file.next()); - filelist.addElement(url); - } - filelist.generate(out); - } - out.println(end); - } - - public void init(ServletConfig config) - throws ServletException { - super.init(config); - listFiles = Boolean.valueOf(config.getInitParameter("listDirectories")).booleanValue(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java deleted file mode 100644 index 293e2d8d..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DispatchServlet.java +++ /dev/null @@ -1,120 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * This class infers the format of a VPF file from the name of the file, and - * dispatches to the appropriate servlet for that type. - * - * This could probably also be handled by a long set of servlet-mapping tags in - * the deployment descriptor. (web.xml) - */ -public class DispatchServlet - extends VPFHttpServlet { - public static final String RECORD_FILE_OBJ = "com.bbn.openmap.vpf_tools.table_obj"; - public static final String ROOTPATH_FILENAME = "com.bbn.openmap.vpf_tools.url_path"; - - /** - * A do-nothing constructor - init does all the work. - */ - public DispatchServlet() { - super(); - } - - /** - * Just a test main to parse vpf datafiles - * - * param args files to parse, plus other command line flags - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String pathInfo = setPathInfo(request); - String rootpath = contextInfo.resolvePath(pathInfo); - if (!pathOkay(rootpath, pathInfo, response)) { - return; - } - - PrintWriter out = response.getWriter(); - File rp = new File(rootpath); - String filename = rp.getName().toLowerCase(); - - String end = "\r\n"; - - // ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // PrintStream s = new PrintStream(bos); - // System.setOut(s); - - request.setAttribute(ROOTPATH_FILENAME, rootpath); - - try { - if (rp.isDirectory()) { - RequestDispatcher rd = request.getRequestDispatcher("/DirectoryList"); - rd.forward(request, response); - return; - } else if (filename.endsWith("x") || filename.endsWith("x.")) { - response.setContentType("text/html"); - out.println(HTML_DOCTYPE + "" + filename + "\r\n\r\n

Table " + filename - + "

\r\n"); - out.println(getStylesheetHTML(request)); - out.println("Skipping VLI format - this format is simply an index to find rows in a corresponding table file, it isn't very interesting to look at so its getting skipped."); - } else if (filename.endsWith("ti")) { - RequestDispatcher rd = request.getRequestDispatcher("/Thematic"); - rd.forward(request, response); - } else if (filename.endsWith("si") || filename.endsWith("si.")) { - RequestDispatcher rd = request.getRequestDispatcher("/SpatialIndex"); - rd.forward(request, response); - } else if (filename.endsWith(".doc")) { - RequestDispatcher rd = request.getRequestDispatcher("/DocFile"); - rd.forward(request, response); - } else { - response.setContentType("text/html"); - out.println(HTML_DOCTYPE + "\n" + filename + "\r\n\r\n

Table " - + filename + "

\r\n"); - out.println(getStylesheetHTML(request)); - DcwRecordFile foo = new DcwRecordFile(rootpath); - request.setAttribute(RECORD_FILE_OBJ, foo); - RequestDispatcher rd = request.getRequestDispatcher("/Schema"); - rd.include(request, response); - RequestDispatcher rd2 = request.getRequestDispatcher("/Data"); - rd2.include(request, response); - - foo.close(); - } - } catch (FormatException f) { - throw new ServletException("Format Error: ", f); - } - // s.close(); - out.println("
");
-        out.println("Context Path: " + request.getContextPath());
-        out.println("PathInfo: " + request.getPathInfo());
-        out.println("ServletPath: " + request.getServletPath());
-        out.println("Query String: " + request.getQueryString());
-        // out.print(bos.toString());
-        out.println("
" + end); - } - -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java deleted file mode 100644 index dca4f3c0..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/DocFileServlet.java +++ /dev/null @@ -1,109 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * This class handles displaying VPF .doc files - */ -public class DocFileServlet - extends VPFHttpServlet { - /** the columns we need from a VPF doc file */ - static final String FieldColumns[] = { - "text" - }; - /** the fields in a VPF doc file we need */ - static final char[] FieldTypeSchema = { - 'T' - }; - /** the field lengths in a VPF doc file we need */ - static final int[] FieldLengthSchema = { - -1 - }; - - /** - * A do-nothing constructor - init does all the work. - */ - public DocFileServlet() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); - if (filePath == null) { - String pathInfo = setPathInfo(request); - filePath = contextInfo.resolvePath(pathInfo); - if (!pathOkay(filePath, pathInfo, response)) { - return; - } - } - - DcwRecordFile docfile = null; - try { - docfile = new DcwRecordFile(filePath); - } catch (FormatException fe) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, " docfile not found"); - return; - } - - response.setContentType("text/html"); - PrintWriter out = response.getWriter(); - out.println(HTML_DOCTYPE); - out.println(getStylesheetHTML(request)); - - String tableName = docfile.getTableName(); - out.println(""); - String title = "VPF Documentation File " + tableName; - out.println("" + title + ""); - out.println("

" + title + "

"); - - try { - docfile.lookupSchema(FieldColumns, true, FieldTypeSchema, FieldLengthSchema, false); - } catch (FormatException fe) { - out.println("The documentation file appears to be invalid."); - RequestDispatcher rd = request.getRequestDispatcher("/Schema"); - rd.include(request, response); - out.println(""); - docfile.close(); - return; - } - - ArrayList al = new ArrayList(FieldTypeSchema.length); - out.println("
");
-        try {
-            while (docfile.parseRow(al)) {
-                out.println("   " + al.get(1).toString());
-            }
-            out.println("
"); - } catch (FormatException fe) { - out.println("/pre>"); - out.println("File Format Exception processing data: " + fe); - } - out.println(""); - docfile.close(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java deleted file mode 100644 index fe15bd79..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FCSRowMaker.java +++ /dev/null @@ -1,97 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * A RowMaker class specifically for the markup of VPF feature class schema - * (fcs) files. - */ -public class FCSRowMaker extends ReferenceRowMaker { - /** the length of a row (number of columns) */ - final int rowLen; - /** the directory of the file being read */ - final File drfp; - final String basepath; - final int idCol; - final int featureClassCol; - final int table1Col; - final int table1keyCol; - final int table2Col; - final int table2keyCol; - - public FCSRowMaker(HttpServletRequest request, - HttpServletResponse response, - String basepath, DcwRecordFile drf) { - super(request, response); - this.rowLen = drf.getColumnCount(); - this.basepath = basepath; - this.drfp = new File(drf.getTableFile()).getParentFile(); - idCol = drf.whatColumn(Constants.ID); - featureClassCol = drf.whatColumn(Constants.FCS_FEATURECLASS); - table1Col = drf.whatColumn(Constants.FCS_TABLE1); - table1keyCol = drf.whatColumn(Constants.FCS_TABLE1KEY); - table2Col = drf.whatColumn(Constants.FCS_TABLE2); - table2keyCol = drf.whatColumn(Constants.FCS_TABLE2KEY); - } - - public void addToRow(TableRowElement row, List l) { - int rv = ((Number)l.get(idCol)).intValue(); - String table1 = ((String)l.get(table1Col)).toLowerCase(); - String table1key = ((String)l.get(table1keyCol)).toLowerCase(); - String table2 = ((String)l.get(table2Col)).toLowerCase(); - String table2key = ((String)l.get(table2keyCol)).toLowerCase(); - File fn = new File(drfp, table1); - File otf = new File(drfp, table2); - boolean tiled = !otf.exists(); - for (int i = 0; i < rowLen; i++) { - if (i == idCol) { - if (fn.exists()) { - row.addElement(Data.joinURL(request, response, - rv, table1, - table1key, table2, - table2key, - tiled)); - } else { - row.addElement(Integer.toString(rv)); - } - } else if ((i==table1Col) || (i==table2Col)) { - String tablename = ((String)l.get(i)).toLowerCase(); - if (new File(drfp, tablename).exists()) { - row.addElement(fileURL(basepath, tablename)); -// } else if (Constants.endTableName.equals(tablename) || -// Constants.cndTableName.equals(tablename) || -// Constants.faceTableName.equals(tablename) || -// "edg".equals(tablename) || -// "txt".equals(tablename)) { -// TileHolder ta = new TileHolder(new File(basepath), tablename, true); -// row.addElement(tablename); - } else { - row.addElement(tablename); - } - } else { - row.addElement(l.get(i).toString().toLowerCase()); - } - } - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java deleted file mode 100644 index 98c9af09..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/FITRowMaker.java +++ /dev/null @@ -1,167 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.VPFUtil; -import com.bbn.openmap.util.html.TableDataElement; -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A RowMaker that performs the join in a feature index table. - */ -public class FITRowMaker extends PlainRowMaker { - /** a list reused to load primitive rows */ - final List primRow = new ArrayList(); - /** a list reused to load feature rows */ - final List featureRow = new ArrayList(); - - /** the array of feature tables, each index is lazy-initialized */ - final DcwRecordFile[] featureTables; - /** the array of feature names for the coverage */ - final String[] featureNames; - - /** the utility class that understands tiled and untiled data */ - final TileHolder tiler; - - /** the column in the FIT that specifies the primitive id */ - final int primIdColumn; - /** the column in the FIT that specifies the tile id (may be -1) */ - final int tileIdColumn; - /** the column in the FIT that specifies the feature class id */ - final int fcIdColumn; - /** the column in the FIT that specifies the feature id */ - final int featureIdColumn; - /** the path for the coverage */ - final File dirPath; - /** the extension (e.g. .lft) used for feature table names */ - final String featureTableExt; - - /** - * Construct a rowmaker for a feature index table. - * - * @param drf the feature index table - * @throws FormatException some error was encountered - */ - public FITRowMaker(DcwRecordFile drf) throws FormatException { - String tableName = drf.getTableName().substring(0, 3); - dirPath = new File(drf.getTableFile()).getParentFile(); - - featureTableExt = getExtensionForTable(tableName); - - primIdColumn = drf.whatColumn("prim_id"); - tileIdColumn = drf.whatColumn("tile_id"); - fcIdColumn = drf.whatColumn("fc_id"); - featureIdColumn = drf.whatColumn("feature_id"); - - tiler = new TileHolder(dirPath, tableName, (tileIdColumn != -1)); - featureNames = getFeatureNames(dirPath); - featureTables = new DcwRecordFile[featureNames.length]; - } - - /** - * Returns the feature table that corresponds to the feature class - * ID. - * - * @param fcId the feature class ID - * @return the feature table - * @throws FormatException the feature table couldn't be created - */ - public DcwRecordFile getFeatureTable(int fcId) throws FormatException { - fcId -= 1; // array is 0-based, table ids are 1-based - DcwRecordFile retval = featureTables[fcId]; - if (retval == null) { - retval = new DcwRecordFile(dirPath + File.separator - + featureNames[fcId].toLowerCase() + featureTableExt); - featureTables[fcId] = retval; - } - return retval; - } - - public void addToRow(TableRowElement row, List l) { - int primId = VPFUtil.objectToInt(l.get(primIdColumn)); - int tileId = (tileIdColumn == -1) ? -1 - : VPFUtil.objectToInt(l.get(tileIdColumn)); - int fcId = VPFUtil.objectToInt(l.get(fcIdColumn)); - int featureId = VPFUtil.objectToInt(l.get(featureIdColumn)); - int id = VPFUtil.objectToInt(l.get(0)); - row.addElement("" + id + " (" + tileId + "," + primId + ") (" + fcId - + ", " + featureId + ")"); - try { - tiler.getRow(tileId, primId, primRow); - DcwRecordFile featureTable = getFeatureTable(fcId); - featureTable.getRow(featureRow, featureId); - for (Iterator i = primRow.iterator(); i.hasNext();) { - row.addElement(new TableDataElement("CLASS=JoinColumn", i.next() - .toString())); - } - for (Iterator i = featureRow.iterator(); i.hasNext();) { - row.addElement(new TableDataElement("CLASS=Join2Column", i.next() - .toString())); - } - } catch (FormatException fe) { - row.addElement(fe.toString()); - } - } - - public String[] getFeatureNames(File dirPath) throws FormatException { - File fcafile = new File(dirPath, "fca"); - if (!fcafile.canRead()) { - fcafile = new File(dirPath, "fca."); - } - DcwRecordFile fca = new DcwRecordFile(fcafile.toString()); - List l = new ArrayList(fca.getColumnCount()); - int fclassColumn = fca.whatColumn("fclass"); - List fclassnames = new ArrayList(); - while (fca.parseRow(l)) { - fclassnames.add(l.get(fclassColumn)); - } - fca.close(); - String retval[] = new String[fclassnames.size()]; - fclassnames.toArray(retval); - return retval; - } - - public static String getExtensionForTable(String tablename) { - - if (tablename.equals("fac")) { - return ".aft"; - } else if (tablename.equals("cnd")) { - return ".pft"; - } else if (tablename.equals("end")) { - return ".pft"; - } else if (tablename.equals("txt")) { - return ".tft"; - } else if (tablename.equals("edg")) { - return ".lft"; - } - return null; - } - - public void close() { - tiler.close(); - for (int i = 0; i < featureTables.length; i++) { - DcwRecordFile drf = featureTables[i]; - if (drf != null) { - drf.close(); - } - } - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java deleted file mode 100644 index 1991fa7c..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/HelloWWW.java +++ /dev/null @@ -1,36 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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 - */ -public class HelloWWW extends HttpServlet { - public void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - resp.setContentType("text/html"); - PrintWriter out = resp.getWriter(); - String docType = "\n"; - out.println(docType - + "\nHello WWW\n\n

Hello WWW

\n\n"); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java deleted file mode 100644 index f84fba92..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/JoinRowMaker.java +++ /dev/null @@ -1,83 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.FeatureClassInfo; -import com.bbn.openmap.layer.vpf.TilingAdapter; -import com.bbn.openmap.util.html.TableDataElement; -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A RowMaker subclass that handles simple joins between tables. - */ -public class JoinRowMaker extends PlainRowMaker { - /** the column that contains the foreign key to the primitive table */ - final int theColumn; - /** the column that contains the tile identifier */ - final int tileColumn; - /** a list reused to load primitive rows */ - final List jtrow = new ArrayList(); - - /** the utility class that understands tiled and untiled data */ - final TileHolder tiler; - final TilingAdapter ta; - - public JoinRowMaker(DcwRecordFile table, String joinColumnName, - String tableName, boolean isTiled) throws FormatException { - theColumn = table.whatColumn(joinColumnName); - tileColumn = isTiled ? table.whatColumn(FeatureClassInfo.TILE_ID_COLUMN_NAME) - : -1; - ta = table.getTilingAdapter(tileColumn, theColumn); - tiler = new TileHolder(new File(table.getTableFile()).getParentFile(), tableName, isTiled); - } - - public void addToRow(TableRowElement row, List l) { - int i = 0; - for (Iterator li = l.iterator(); li.hasNext();) { - Object elt = li.next(); - if (i == theColumn) { - int whatrow = ta.getTilePrimId(l); - int tileId = ta.getTileId(l); - try { - if (tiler.getRow(ta, l, jtrow)) { - for (Iterator it = jtrow.iterator(); it.hasNext();) { - row.addElement(new TableDataElement("CLASS=JoinColumn", it.next() - .toString())); - } - } else { - row.addElement("Join failed! [" + elt + "]" + "(" - + tileId + "," + whatrow + ")"); - } - } catch (FormatException fe) { - row.addElement(fe.toString() + "(" + tileId + "," + whatrow - + ")"); - } - } else { - row.addElement(elt.toString()); - } - i++; - } - } - - public void close() { - tiler.close(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java deleted file mode 100644 index 7ceb6f2b..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/LibraryBean.java +++ /dev/null @@ -1,128 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.LibrarySelectionTable; - -/** - * This class prints out a description of a VPF database, listing the - * available libraries, coverage types and feature types. - */ -public class LibraryBean { - private LibrarySelectionTable lst; - private HttpServletRequest request; - private HttpServletResponse response; - - public void setContext(ServletContext c) { - contextInfo = ContextInfo.getContextInfo(c); - } - - public void setResponse(HttpServletResponse r) { - response = r; - } - - public HttpServletRequest getRequest() { - return request; - } - - public void setRequest(HttpServletRequest request) { - this.request = request; - } - - public HttpServletResponse getResponse() { - return response; - } - - public LibrarySelectionTable getLst() { - return lst; - } - - public String getLibName() { - return (lst == null) ? "unknown" : lst.getDatabaseName(); - } - - public void setPath(String pathInfo) { - if (pathInfo == null) { - return; - } - int findex = pathInfo.indexOf('/', 1); - if (findex < 0) { - findex = pathInfo.length(); - } - String libname = pathInfo.substring(0, findex); - - try { - lst = getLST(libname); - if (lst == null) { - return; - } - // String dbname = lst.getDatabaseName(); - // out.println("\nDescribe VPF Database - // " + - // dbname + "\n\n

VPF Database " + - // dbname + "

\n"); - // ListElement dble = new ListBodyElement(); - // WrapElement dblist = new WrapElement("ul", dble); - // dble.addElement("Database Description: " + - // lst.getDatabaseDescription()); - // dble.addElement("Database Description Table: " + - // buildURL(request, response, libname, "dht")); - // String[] libraries = lst.getLibraryNames(); - // StringBuffer libnames = new StringBuffer("Database - // Libraries: "); - // for (int i = 0; i < libraries.length; i++) { - // libnames.append("").append(libraries[i]); - // libnames.append("").append(" "); - // } - // libnames.append("(from "); - // libnames.append(buildURL(request, response, libname, - // "lat")); - // libnames.append(")"); - - // dble.addElement(libnames.toString()); - // dblist.generate(out); - // for (int i = 0; i < libraries.length; i++) { - // String prefix = libraries[i] + ":"; - // printLibrary(request, response, libname, - // lst.getCAT(libraries[i])); - // } - // out.println(""); - } catch (FormatException fe) { - // throw new ServletException("FormatException: " , fe); - } - } - - /** the context object used for config info */ - protected ContextInfo contextInfo; - - public LibrarySelectionTable getLST(String libname) throws FormatException { - LibrarySelectionTable lst = contextInfo.getLST(libname); - if (lst == null) { - String lib_home = contextInfo.getPath(libname); - if (lib_home == null) { - return null; - } - - lst = new LibrarySelectionTable(lib_home); - contextInfo.putLST(libname, lst); - } - return lst; - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java deleted file mode 100644 index 38a90137..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/PlainRowMaker.java +++ /dev/null @@ -1,62 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.util.html.TableRowElement; - -/** - * A basic RowMaker that makes rows. - */ -public class PlainRowMaker implements RowMaker { - - /** - * A basic constructor that doesn't do anything special. - */ - public PlainRowMaker() {} - - /** - * Generates a TableRowElement from a table by creating a new - * TableRow and passing it and the list to addToRow, then - * returning the new row. - * - * @param l the VPF table row - * @return a HTML representation of the VPF row - */ - public TableRowElement generateRow(List l) { - TableRowElement tr = new TableRowElement(); - addToRow(tr, l); - return tr; - } - - /** - * Adds the elements of the list to the table row - * - * @param row the HTML row - * @param l the VPF row - */ - public void addToRow(TableRowElement row, List l) { - for (Iterator li = l.iterator(); li.hasNext();) { - row.addElement(li.next().toString()); - } - } - - /** - * An empty implementation, since this class doesn't hold any - * resources. - */ - public void close() {} -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java deleted file mode 100644 index 2e1703bb..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ReferenceRowMaker.java +++ /dev/null @@ -1,46 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A RowMaker class that retains references to the HttpServletRequest - * and HttpServletResponse instances of the request. - */ -public abstract class ReferenceRowMaker extends PlainRowMaker { - /** the servlet request object */ - final protected HttpServletRequest request; - /** the servlet response object */ - final protected HttpServletResponse response; - - public ReferenceRowMaker(HttpServletRequest request, - HttpServletResponse response) { - this.request = request; - this.response = response; - } - - public String toURL(String servletName, String pathname, String filename) { - return VPFHttpServlet.toURL(request, - response, - servletName, - pathname, - filename); - } - - public String fileURL(String pathname, String filename) { - return VPFHttpServlet.fileURL(request, response, pathname, filename); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java deleted file mode 100644 index b4322b8d..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/RowMaker.java +++ /dev/null @@ -1,39 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.util.List; - -import com.bbn.openmap.util.html.TableRowElement; - -/** - * An interface used to generate rows of an (html) table from a (VPF) - * table. - */ -public interface RowMaker { - /** - * Generate an HTML table row from a vpf table row - * - * @param row the VPF table row - * @return the HTML representation - */ - public TableRowElement generateRow(List row); - - /** - * Used to indicate that no more calls to addList will be made. - * (implementation may want to reclaim resources without waiting - * for the finalizer to run.) - */ - public void close(); -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java deleted file mode 100644 index 56065a28..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/Schema.java +++ /dev/null @@ -1,126 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; -import com.bbn.openmap.util.html.ListElement; -import com.bbn.openmap.util.html.StringElement; -import com.bbn.openmap.util.html.TableRowElement; -import com.bbn.openmap.util.html.WrapElement; - -/** - * A servlet class that will print the schema for a VPF table. - */ -public class Schema extends VPFHttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public Schema() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - DcwRecordFile foo = (DcwRecordFile) request.getAttribute(DispatchServlet.RECORD_FILE_OBJ); - if (foo == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - String basepath = getRootDir(request); - String url = response.encodeURL(request.getContextPath() - + "/VPFHelp.jsp?topic=table_schema"); - PrintWriter out = response.getWriter(); - out.println("

Table Schema

"); - out.println("

General Table Information

"); - HtmlListElement list = new HtmlListElement(); - list.addElement("Table Name: " + foo.getTableName()); - list.addElement("Table Description: " + foo.getDescription()); - list.addElement("DocFile Name: " - + fileURL(request, - response, - basepath, - foo.getDocumentationFilename())); - int reclen = foo.getRecordLength(); - String reclenstr = (reclen == -1) ? ("variable") - : (Integer.toString(reclen) + " bytes"); - list.addElement("Record Length: " + reclenstr); - try { - list.addElement("Record Count: " + foo.getRecordCount()); - } catch (com.bbn.openmap.io.FormatException fe) { - list.addElement("Record Count Error: " + fe.toString()); - } - list.generate(out); - - // out.println("

Column Schema

"); - ListElement rows = new ListElement(); - WrapElement table = new WrapElement("table", "BORDER=1", rows); - TableRowElement thr = new TableRowElement(); - rows.addElement(new WrapElement("CAPTION", new StringElement("Column Schema"))); - rows.addElement(thr); - thr.addElement(THE("#", url)); - thr.addElement(THE("Name", url)); - thr.addElement(THE("Type", url)); - thr.addElement(THE("Count", url)); - thr.addElement(THE("Key Type", url)); - thr.addElement(THE("Description", url)); - thr.addElement(THE("VDT", url)); - thr.addElement(THE("Thematic Index", url)); - thr.addElement(THE("DocFile", url)); - DcwColumnInfo dci[] = foo.getColumnInfo(); - for (int i = 0; i < dci.length; i++) { - TableRowElement tr = new TableRowElement(); - rows.addElement(tr); - tr.addElement(Integer.toString(i)); - tr.addElement(dci[i].getColumnName()); - tr.addElement(String.valueOf(dci[i].getFieldType())); - int elts = dci[i].getNumberOfElements(); - tr.addElement(elts == -1 ? "*" : Integer.toString(elts)); - tr.addElement(String.valueOf(dci[i].getKeyType())); - tr.addElement(dci[i].getColumnDescription()); - tr.addElement(fileURL(request, response, basepath, dci[i].getVDT())); - tr.addElement(thematicURL(request, - response, - basepath, - dci[i].getThematicIndexName())); - tr.addElement(docURL(request, - response, - basepath, - dci[i].getNarrativeTable())); - } - table.generate(response.getWriter()); - } - - public static String thematicURL(HttpServletRequest request, - HttpServletResponse response, - String pathname, String filename) { - return toURL(request, response, "/Thematic", pathname, filename); - } - - public static String docURL(HttpServletRequest request, - HttpServletResponse response, String pathname, - String filename) { - return toURL(request, response, "/DocFile", pathname, filename); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java deleted file mode 100644 index f0b402a1..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialGraphicServlet.java +++ /dev/null @@ -1,177 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * This servlet generates HTML for VPF files in spatial index format. - */ -public class SpatialGraphicServlet extends VPFHttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public SpatialGraphicServlet() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); - if (filePath == null) { - String pathInfo = setPathInfo(request); - filePath = contextInfo.resolvePath(pathInfo); - if (!pathOkay(filePath, pathInfo, response)) { - return; - } - } - - response.setContentType("image/gif"); - - int width = 200; - int height = 200; - int imageType = BufferedImage.TYPE_INT_ARGB; - BufferedImage bufferedImage = new BufferedImage(width, height, imageType); - Graphics2D g2d = bufferedImage.createGraphics(); - g2d.setClip(0, 0, width, height); - g2d.setColor(Color.red); - g2d.drawLine(10, 10, 95, 95); - g2d.drawLine(105, 105, 190, 190); - g2d.drawRect(1, 1, 198, 198); - g2d.dispose(); - // byte [] imageData = AcmeGifHelper.encodeGif(bufferedImage); - - // ServletOutputStream sos = response.getOutputStream(); - // sos.write(imageData); - - String filename = filePath; - String tableMatch = getIndexedTable(filename); - if (tableMatch == null) { - tableMatch = "non-standard spatial index"; - } else { - tableMatch = fileURL(request, - response, - getRootDir(request), - tableMatch); - } - - try { - DcwSpatialIndex ff = new DcwSpatialIndex(filePath.toString(), false); - printSpatial(request, response, ff); - ff.close(); - } catch (FormatException fe) { - } - } - - public void printSpatial(HttpServletRequest request, - HttpServletResponse response, DcwSpatialIndex si) - throws com.bbn.openmap.io.FormatException, IOException { - int width = 200; - int height = 200; - int imageType = BufferedImage.TYPE_INT_ARGB; - BufferedImage bufferedImage = new BufferedImage(width, height, imageType); - Graphics2D g2d = bufferedImage.createGraphics(); - g2d.setClip(0, 0, width, height); - g2d.setColor(Color.red); - g2d.drawLine(10, 10, 95, 95); - g2d.drawLine(105, 105, 190, 190); - g2d.drawRect(1, 1, 198, 198); - g2d.dispose(); - // byte [] imageData = AcmeGifHelper.encodeGif(bufferedImage); - - // ServletOutputStream sos = response.getOutputStream(); - // sos.write(imageData); - - HtmlListElement list = new HtmlListElement(); - list.addElement("Number Of Primitives: " + si.getNumberOfPrimitives()); - int nodesInTree = si.getNodesInTree(); - list.addElement("Nodes in Tree: " + nodesInTree); - list.addElement("Bounding Rectangle: (" + si.getBoundingX1() + ", " - + si.getBoundingY1() + ") - (" + si.getBoundingX2() + ", " - + si.getBoundingY2() + ")"); - TableRowElement columnNames = new TableRowElement(); - columnNames.addElement(new TableHeaderElement("Primitive ID")); - columnNames.addElement(new TableHeaderElement("x1")); - columnNames.addElement(new TableHeaderElement("x2")); - columnNames.addElement(new TableHeaderElement("y1")); - columnNames.addElement(new TableHeaderElement("y2")); - for (int i = 0; i < nodesInTree; i++) { - int count = si.getPrimitiveCount(i); - //int offset = si.getPrimitiveOffset(i); - DcwSpatialIndex.PrimitiveRecord pr[] = si.getPrimitiveRecords(i); - - if (count == 0) { - } else { - ListElement rows = new ListElement(); - //WrapElement table = new WrapElement("table", "BORDER=1", rows); - rows.addElement(columnNames); - for (int j = 0; j < pr.length; j++) { - DcwSpatialIndex.PrimitiveRecord pr1 = pr[j]; - TableRowElement datarow = new TableRowElement(); - rows.addElement(datarow); - datarow.addElement(Integer.toString(pr1.primId)); - datarow.addElement(Short.toString(pr1.x1)); - datarow.addElement(Short.toString(pr1.x2)); - datarow.addElement(Short.toString(pr1.y1)); - datarow.addElement(Short.toString(pr1.y2)); - } - } - } - } - - /** a map from spatial index name to primitive file indexed */ - private HashMap indexTableMap; - - /** - * Returns the name of the primitive file that the spatial index - * is for. - * - * @param indexName the name of the index - * @return the name of the primitive file - */ - public String getIndexedTable(String indexName) { - if (indexTableMap == null) { - HashMap newMap = new HashMap(); - newMap.put("esi", "edg"); - newMap.put("esi.", "edg."); - newMap.put("fsi", "fac"); - newMap.put("fsi.", "fac."); - newMap.put("csi", "cnd"); - newMap.put("csi.", "cnd."); - newMap.put("nsi", "end"); - newMap.put("nsi.", "end."); - newMap.put("tsi", "txt"); - newMap.put("tsi.", "txt."); - indexTableMap = newMap; - } - return (String) indexTableMap.get(indexName); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java deleted file mode 100644 index ddfc1052..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/SpatialIndexServlet.java +++ /dev/null @@ -1,165 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; -import com.bbn.openmap.util.html.ListElement; -import com.bbn.openmap.util.html.TableHeaderElement; -import com.bbn.openmap.util.html.TableRowElement; -import com.bbn.openmap.util.html.WrapElement; - -/** - * This servlet generates HTML for VPF files in spatial index format. - */ -public class SpatialIndexServlet extends VPFHttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public SpatialIndexServlet() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); - if (filePath == null) { - String pathInfo = setPathInfo(request); - filePath = contextInfo.resolvePath(pathInfo); - if (!pathOkay(filePath, pathInfo, response)) { - return; - } - } - - response.setContentType("text/html"); - PrintWriter out = response.getWriter(); - File fp = new File(filePath); - String filename = fp.getName(); - String tableMatch = getIndexedTable(filename); - if (tableMatch == null) { - tableMatch = "non-standard spatial index"; - } else { - tableMatch = fileURL(request, - response, - getRootDir(request), - tableMatch); - } - - out.println(HTML_DOCTYPE + "VPF Spatial Index " - + filename + "\r\n\r\n

Spatial Index " - + filename + " for Table " + tableMatch + "

\r\n"); - - out.println(getStylesheetHTML(request)); - - try { - DcwSpatialIndex ff = new DcwSpatialIndex(filePath, false); - printSpatial(request, response, ff); - ff.close(); - } catch (FormatException fe) { - out.println("FormatException while reading spatial index: " - + fe.getMessage()); - } - out.println("\r\n"); - } - - public void printSpatial(HttpServletRequest request, - HttpServletResponse response, DcwSpatialIndex si) - throws FormatException, IOException { - PrintWriter out = response.getWriter(); - out.println("

General Spatial Index Information

"); - HtmlListElement list = new HtmlListElement(); - list.addElement("Number Of Primitives: " + si.getNumberOfPrimitives()); - int nodesInTree = si.getNodesInTree(); - list.addElement("Nodes in Tree: " + nodesInTree); - list.addElement("Bounding Rectangle: (" + si.getBoundingX1() + ", " - + si.getBoundingY1() + ") - (" + si.getBoundingX2() + ", " - + si.getBoundingY2() + ")"); - list.generate(out); - out.println("

Spatial Index Data

"); - TableRowElement columnNames = new TableRowElement(); - columnNames.addElement(new TableHeaderElement("Primitive ID")); - columnNames.addElement(new TableHeaderElement("x1")); - columnNames.addElement(new TableHeaderElement("x2")); - columnNames.addElement(new TableHeaderElement("y1")); - columnNames.addElement(new TableHeaderElement("y2")); - for (int i = 0; i < nodesInTree; i++) { - int count = si.getPrimitiveCount(i); - int offset = si.getPrimitiveOffset(i); - DcwSpatialIndex.PrimitiveRecord pr[] = si.getPrimitiveRecords(i); - - out.println("

Node " + i); - if (count == 0) { - out.println("(no primitives)

\r\n"); - } else { - out.println("Primitive Count:" + count - + " Relative Offset:" + offset + "\n"); - - ListElement rows = new ListElement(); - WrapElement table = new WrapElement("table", "BORDER=1", rows); - rows.addElement(columnNames); - for (int j = 0; j < pr.length; j++) { - DcwSpatialIndex.PrimitiveRecord pr1 = pr[j]; - TableRowElement datarow = new TableRowElement(); - rows.addElement(datarow); - datarow.addElement(Integer.toString(pr1.primId)); - datarow.addElement(Short.toString(pr1.x1)); - datarow.addElement(Short.toString(pr1.x2)); - datarow.addElement(Short.toString(pr1.y1)); - datarow.addElement(Short.toString(pr1.y2)); - } - table.generate(out); - } - } - } - - /** a map from spatial index name to primitive file indexed */ - private HashMap indexTableMap; - - /** - * Returns the name of the primitive file that the spatial index - * is for. - * - * @param indexName the name of the index - * @return the name of the primitive file - */ - public String getIndexedTable(String indexName) { - if (indexTableMap == null) { - HashMap newMap = new HashMap(); - newMap.put("esi", "edg"); - newMap.put("esi.", "edg."); - newMap.put("fsi", "fac"); - newMap.put("fsi.", "fac."); - newMap.put("csi", "cnd"); - newMap.put("csi.", "cnd."); - newMap.put("nsi", "end"); - newMap.put("nsi.", "end."); - newMap.put("tsi", "txt"); - newMap.put("tsi.", "txt."); - indexTableMap = newMap; - } - return (String) indexTableMap.get(indexName); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java deleted file mode 100644 index cfa70688..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TableSubsetRecordIterator.java +++ /dev/null @@ -1,66 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; - -/** - * An iterator that will return a subset of the rows in a table. - */ -public class TableSubsetRecordIterator implements Iterator { - final private int vals[]; - final DcwRecordFile drf; - final List l; - private int current = 0; - - public TableSubsetRecordIterator(int vals[], DcwRecordFile drf, List l) { - this.vals = vals; - this.drf = drf; - this.l = l; - } - - /** - * Constructor - * - * @param drf the table to parse - * @param vals the row numbers to be returned - */ - public TableSubsetRecordIterator(int vals[], DcwRecordFile drf) { - this(vals, drf, new ArrayList(drf.getColumnCount())); - } - - public boolean hasNext() { - return (current < vals.length); - } - - public Object next() { - boolean gotit; - try { - gotit = drf.getRow(l, vals[current++]); - } catch (FormatException fe) { - System.out.println("fe: " + fe); - gotit = false; - } - return gotit ? l : null; - } - - public void remove() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java deleted file mode 100644 index e754c2dd..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/ThematicIndexServlet.java +++ /dev/null @@ -1,172 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; -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 com.bbn.openmap.util.html.WrapElement; - -/** - * This servlet generates HTML for VPF files in thematic index format. - */ -public class ThematicIndexServlet - extends VPFHttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public ThematicIndexServlet() { - super(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - - String filePath = (String) request.getAttribute(DispatchServlet.ROOTPATH_FILENAME); - if (filePath == null) { - String pathInfo = setPathInfo(request); - filePath = contextInfo.resolvePath(pathInfo); - if (!pathOkay(filePath, pathInfo, response)) { - return; - } - } - - DcwThematicIndex ti; - try { - ti = new DcwThematicIndex(filePath, false); - } catch (FormatException fe) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, fe.toString()); - return; - } - - String valIndex = request.getParameter("valIndex"); - if (valIndex != null) { - showTableIndexed(request, response, valIndex, ti); - } else { - showTableData(request, response, ti, filePath); - } - try { - ti.close(); - } catch (FormatException fe) { - // ignore - } - } - - protected void showTableData(HttpServletRequest request, HttpServletResponse response, DcwThematicIndex ti, String filePath) - throws ServletException, IOException { - - response.setContentType("text/html"); - PrintWriter out = response.getWriter(); - - String title = "VPF Thematic Index for " + new File(filePath).getName(); - String basepath = getRootDir(request); - out.println("" + title + ""); - out.println(getStylesheetHTML(request)); - out.println("

" + title + "

"); - - out.println("

General Thematic Index Information

"); - HtmlListElement list = new HtmlListElement(); - list.addElement("Number of Codes: " + ti.getNumberOfCodes()); - list.addElement("Number of Rows: " + ti.getNumberOfRows()); - list.addElement("Type Of Index: " + ti.getTypeOfIndex()); - list.addElement("Field Type of Index: " + ti.getFieldTypeOfIndex()); - list.addElement("Number of Data Elements: " + ti.getNumberOfDataElements()); - list.addElement("Data Type Specifier: " + ti.getDataTypeSpecifier()); - list.addElement("Table Indexed: " + fileURL(request, response, basepath, ti.getTableIndexed())); - list.addElement("Column Indexed: " + ti.getColumnIndexed()); - list.addElement("Fields Sorted: " + ti.getSorted()); - list.generate(out); - - out.println("

Thematic Index Data

"); - Object[] values = ti.getValueIndexes(); - ListElement rows = null; - Element table = null; - TableRowElement th = new TableRowElement(); - th.addElement(new TableHeaderElement("CLASS=NavBarCell2", "Index Value")); - th.addElement(new TableHeaderElement("Count")); - th.addElement(new TableHeaderElement("Rows...")); - String valStr = "" + values[i] + ""); - try { - int[] intvals = ti.get(values[i]); - tr.addElement(Integer.toString(intvals.length)); - StringBuffer sb = new StringBuffer(); - sb.append(intvals[0]); - for (int j = 1; j < intvals.length; j++) { - sb.append(", ").append(intvals[j]); - } - tr.addElement(sb.toString()); - } catch (FormatException fe) { - tr.addElement(fe.toString()); - } - } - if (table != null) { - table.generate(out); - } - } - - protected void showTableIndexed(HttpServletRequest request, HttpServletResponse response, String valIndex, DcwThematicIndex ti) - throws IOException, ServletException { - Object val = null; - switch (ti.getFieldTypeOfIndex()) { - case 'I': - val = Integer.valueOf(valIndex); - break; - case 'S': - val = Short.valueOf(valIndex); - break; - case 'T': - val = valIndex; - break; - } - try { - int[] vals = ti.get(val); - request.setAttribute(Data.ROWLIST_OBJECT, vals); - } catch (FormatException fe) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, fe.toString()); - } - String pi = request.getPathInfo(); - int lin = pi.lastIndexOf('/') + 1; - RequestDispatcher rd = request.getRequestDispatcher("/UnknownType" + pi.substring(0, lin) + ti.getTableIndexed()); - rd.forward(request, response); - } - -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java deleted file mode 100644 index daf47519..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/TileHolder.java +++ /dev/null @@ -1,202 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.File; -import java.util.List; -import java.util.Vector; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwCrossTileID; -import com.bbn.openmap.layer.vpf.DcwRecordFile; -import com.bbn.openmap.layer.vpf.TilingAdapter; -import com.bbn.openmap.layer.vpf.VPFUtil; - -/** - * This class provides easy access to tiled data. - */ -public class TileHolder { - /** the name of the primitive file */ - private final String fileName; - /** the current open tile */ - private DcwRecordFile currentTileFile; - /** the index (into tileStuff) of the current open tile */ - private int curTile; - /** an array of tile paths */ - private String tileStuff[]; - /** the directory which has tile subdirectories */ - private final File basepath; - - /** - * Construct a TileHolder. close() should be called when you are - * done with the object. - * - * @param basepath the directory which has tile subdirectories - * @param fileName the name of the primitive file - * @param isTiled if the coverage is tiled or not. If it is, - * tiling information is assumed to be located in - * $basepath/../tileref - * @throws FormatException something went wrong - */ - public TileHolder(File basepath, String fileName, boolean isTiled) - throws FormatException { - this.fileName = fileName; - this.basepath = basepath; - curTile = -1; - if (isTiled) { - tileStuff = doTileRefStuff(basepath); - } else { - currentTileFile = new DcwRecordFile(basepath + File.separator - + fileName); - } - } - - /** - * Gets a row from a primitive file in a coverage. - * - * @param tileColumn the column index used to get the tile id - * @param rowColumn the column index used to get the row id - * @param tileRow the row to retrieve the tile and row IDs from - * @param retrow the row gotten from the file - * @return true if the row was fetched, false otherwise - * @throws FormatException - */ - public boolean getRow(int tileColumn, int rowColumn, List tileRow, - List retrow) throws FormatException { - int tileId = (tileColumn == -1) ? -1 - : VPFUtil.objectToInt(tileRow.get(tileColumn)); - int rowId = VPFUtil.objectToInt(tileRow.get(rowColumn)); - return getRow(tileId, rowId, retrow); - } - - public boolean getRow(TilingAdapter ta, List tileRow, List retrow) - throws FormatException { - return getRow(ta.getTileId(tileRow), ta.getTilePrimId(tileRow), retrow); - } - - public boolean getRow(DcwCrossTileID prim, List retrow) - throws FormatException { - return getRow(prim.nextTileID, prim.nextTileKey, retrow); - } - - /** - * Gets a row from a primitive file in a coverage. - * - * @param tileId the tile identifier - * @param rowId the row identifier - * @param retrow the row gotten from the file - * @return true if the row was fetched, false otherwise - * @throws FormatException - */ - public boolean getRow(int tileId, int rowId, List retrow) - throws FormatException { - if (rowId <= 0) { - return false; - } - if (tileId != curTile) { - File joinfile = new File(basepath + File.separator - + tileStuff[tileId]); - close(); - currentTileFile = new DcwRecordFile(joinfile + File.separator - + fileName); - curTile = tileId; - } - return currentTileFile.getRow(retrow, rowId); - } - - /** - * Closes any related tables. - */ - public void close() { - if (currentTileFile != null) { - currentTileFile.close(); - } - currentTileFile = null; - } - - /** - * Loads tiling information for the coverage. - * - * @param path the path to the coverage. tiling info is in - * ../tileref - * @return an array of tile paths - */ - private static String[] doTileRefStuff(File path) throws FormatException { - File pathname = new File(path.getParentFile(), "tileref"); - String faceIDColumnName = null; - // read fcs to figure out what column in tileref.aft we need - // to use to - // read the fbr (face bounding rectangle) table - File fcsFile = new File(pathname, "fcs"); - if (!fcsFile.canRead()) { - fcsFile = new File(pathname, "fcs."); - } - DcwRecordFile fcs = new DcwRecordFile(fcsFile.toString()); - Vector fcsv = new Vector(fcs.getColumnCount()); - while (fcs.parseRow(fcsv)) { - String fclass = ((String) fcsv.elementAt(1)).toLowerCase(); - String table1 = ((String) fcsv.elementAt(2)).toLowerCase(); - if ((fclass.equals("tileref")) && (table1.equals("tileref.aft"))) { - faceIDColumnName = (String) fcsv.elementAt(3); - break; - } - } - fcs.close(); - - if (faceIDColumnName == null) { - throw new FormatException("no faceIDColumn"); - // won't be able to read the tiling info. abort - } - - // Okay, we've got info on what column we use from tileref.aft - // to index - // into the fbr. - DcwRecordFile aft = new DcwRecordFile(pathname + File.separator - + "tileref.aft"); - int faceIDColumn = aft.whatColumn(faceIDColumnName.toLowerCase()); - int tileNameColumn = aft.whatColumn("tile_name"); - - if ((faceIDColumn == -1) || (tileNameColumn == -1)) { - aft.close(); - throw new FormatException("no faceIDColumn"); - } - - Vector aftv = new Vector(aft.getColumnCount()); - - // set the array size to record count + 1, to be able to - // use the tileID as the index into the array - String containedTiles[] = new String[aft.getRecordCount() + 1]; - - int tileid = 1; - while (aft.parseRow(aftv)) { - //int fac_num = ((Number) aftv.elementAt(faceIDColumn)).intValue(); - String tilename = (String) aftv.elementAt(tileNameColumn); - - char chs[] = tilename.toCharArray(); - boolean goodTile = false; - for (int i = 0; i < chs.length; i++) { - if ((chs[i] != '\\') && (chs[i] != ' ')) { - goodTile = true; - chs[i] = Character.toLowerCase(chs[i]); - } - if (chs[i] == '\\') { - chs[i] = File.separatorChar; - } - } - containedTiles[tileid++] = (goodTile) ? new String(chs) : null; - } - aft.close(); - return containedTiles; - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java deleted file mode 100644 index 3b1f25a9..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/URLCheck.java +++ /dev/null @@ -1,136 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.io.Reader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; - -/** - * Command line program to wander the vpfservlet pages, to make sure - * all URLs generated are valid. - */ -public class URLCheck { - public static Set check(String surl, PrintStream out) throws IOException { - Set urls = new TreeSet(); - out.println("URL " + surl); - Reader r; - URL url; - try { - url = new URL(surl); - r = new InputStreamReader(url.openStream()); - } catch (MalformedURLException mue) { - out.println(" bad URL"); - return urls; - } - Set names = new HashSet(); - Set localrefs = new HashSet(); - StringBuffer sb = new StringBuffer(); - char buf[] = new char[8096]; - int len; - while ((len = r.read(buf)) != -1) { - sb.append(buf, 0, len); - String str = sb.toString(); - int fromIx = 0; - int gt; - while ((gt = str.indexOf('>', fromIx)) != -1) { - int lt = str.indexOf('<', fromIx); - fromIx = gt + 1; - char firstChar = str.charAt(lt + 1); - if ((firstChar != 'A') && (firstChar != 'a')) { - continue; - } - String substr = str.substring(lt + 1, gt); - String lsubstr = substr.toLowerCase(); - - int hquote = lsubstr.indexOf(href); - if (hquote != -1) { - hquote += href.length(); - int lquote = substr.indexOf('"', hquote); - String rurl = substr.substring(hquote, lquote); - if (rurl.charAt(0) == '#') { - names.add(rurl.substring(1)); - } else { - try { - urls.add(new URL(url, rurl).toExternalForm()); - } catch (MalformedURLException mue) { - out.println(" MUE: " + mue.getMessage()); - } - } - } else { - int nquote = lsubstr.indexOf(name); - if (nquote != -1) { - nquote += name.length(); - int lquote = substr.indexOf('"', nquote); - String n = substr.substring(nquote, lquote); - localrefs.add(n); - } - } - - } - sb.delete(0, fromIx); - } - for (Iterator i = localrefs.iterator(); i.hasNext();) { - String localref = (String) i.next(); - if (!names.contains(localref)) { - out.println("MISSING REF: " + localref); - } - } - return urls; - } - final static String href = "href=\""; - final static String name = "name=\""; - - public static Set workOn(Set master, Set urls, PrintStream out) { - Set newurls = null; - for (Iterator i = urls.iterator(); i.hasNext();) { - String surl = (String) i.next(); - if (master.add(surl)) { - try { - Set rets = check(surl, out); - if (newurls == null) { - newurls = rets; - } else { - newurls.addAll(rets); - } - } catch (FileNotFoundException fnfe) { - out.println("Bogus URL: " + surl); - } catch (IOException ioe) { - out.println(" " + surl + " " + ioe.getClass() + " " - + ioe.getMessage()); - } - } - } - return newurls; - } - - public static void main(String[] args) { - Set master = new HashSet(); - Set workon = new HashSet(); - workon.addAll(Arrays.asList(args)); - do { - workon = workOn(master, workon, System.out); - } while (workon != null); - System.out.println("Done."); - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java deleted file mode 100644 index 0b68255f..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VDTRowMaker.java +++ /dev/null @@ -1,55 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * A RowMaker class for int.vdt and char.vdt tables. It generates a - * URL for columns that reference another table. - */ -public class VDTRowMaker extends ReferenceRowMaker { - - /** the path to the coverage */ - final String basepath; - /** the column with the table name */ - final int tableCol; - - public VDTRowMaker(HttpServletRequest request, - HttpServletResponse response, String basepath, DcwRecordFile drf) { - super(request, response); - this.basepath = basepath; - tableCol = drf.whatColumn("table"); - } - - public void addToRow(TableRowElement row, List l) { - int i = 0; - for (Iterator li = l.iterator(); li.hasNext();) { - Object elt = li.next(); - if (i == tableCol) { - row.addElement(fileURL(basepath, ((String) elt).toLowerCase())); - } else { - row.addElement(elt.toString()); - } - i++; - } - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java deleted file mode 100644 index cdf45d45..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFHttpServlet.java +++ /dev/null @@ -1,210 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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; - -/** - * A base class useful for servlets that use the VPF tools context object. This class also defines some utility methods - * used in the package. - */ -public abstract class VPFHttpServlet extends HttpServlet { - - /** - * html doctype for HTML 4.0 - */ - public static final String HTML_DOCTYPE = ""; - - /** - * the context object used for config info - */ - protected ContextInfo contextInfo; - - /** - * A do-nothing constructor - init does all the work. - */ - public VPFHttpServlet() { - super(); - } - - public void init(ServletConfig config) throws ServletException { - super.init(config); - contextInfo = ContextInfo.getContextInfo(config.getServletContext()); - } - - /** - * Checks if a path refers to a file. If its not, reports an error. - * - * @param rootpath the path to check (can be null) - * @param pathInfo used in the error message if rootpath is null - * @param response used to send the error - * @return true if the file can be read, false otherwise - * @see HttpServletResponse#sendError - */ - public static boolean pathOkay(String rootpath, String pathInfo, - HttpServletResponse response) - throws IOException { - if (rootpath == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, pathInfo - + " (invalid path)"); - return false; - } else if (!new File(rootpath).canRead()) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - rootpath.toString() + " not found"); - return false; - } - return true; - } - - /** - * Returns the HTML to reference the common stylesheet - * - * @return the stylesheet HTML - */ - public String getStylesheetHTML(HttpServletRequest request) { - return (""); - } - - /** - * Returns a TableHeaderElement that contains a URL - * - * @param text the text for the reference - * @param url the URL for the reference - * @return a table cell containing a URL - */ - public TableHeaderElement THE(String text, String url) { - return new TableHeaderElement(buildHREF(url, text)); - } - - /** - * Returns a TableHeaderElement that contains a URL - * - * @param text the text for the reference - * @param url the URL for the reference - * @param response the HttpServletResponse object used to encode the url - * @return a table cell containing a URL - */ - public TableHeaderElement THE(String text, String url, - HttpServletResponse response) { - return new TableHeaderElement(buildHREF(response, url, text)); - } - - /** - * Returns a string usable as an HTML HREF element - * - * @param tag the text for the reference - * @param url the URL for the reference - * @return a string containing an HTML HREF - */ - public static String buildHREF(String url, String tag) { - return "" + tag + ""; - } - - /** - * Returns a string usable as an HTML HREF element - * - * @param tag the text for the reference - * @param url the URL for the reference - * @param response the HttpServletResponse object used to encode the url - * @return a string containing an HTML HREF - */ - public static String buildHREF(HttpServletResponse response, String url, - String tag) { - return buildHREF(response.encodeURL(url), tag); - } - - /** - * Returns an HTML HREF based on the parameters. This method is equivelent to toURL(request, response, - * "/UnknownType", pathname, filename); - * - * @see #toURL - * @param request the request to use for context info - * @param response the response to use to encode the URL - * @param pathname the path of the file - * @param filename the name of the file - * @return a string HREF - */ - public static String fileURL(HttpServletRequest request, - HttpServletResponse response, String pathname, - String filename) { - return toURL(request, response, "/UnknownType", pathname, filename); - } - - /** - * Returns an HTML HREF based on the parameters. - * - * @param request the request to use for context info - * @param response the response to use to encode the URL - * @param pathname the path of the file - * @param filename the name of the file (may be null) - * @param servletName the servlet name to use in the URL - * @return a string HREF - */ - public static String toURL(HttpServletRequest request, - HttpServletResponse response, - String servletName, String pathname, - String filename) { - String value; - if (filename == null) { - value = "---"; - } else { - String url = request.getContextPath() + servletName + pathname - + filename; - value = "" + filename - + "\r\n"; - - } - return value; - } - - public static final String ROOT_PATHDIR = VPFHttpServlet.class.getName() - + ".rootPathDir"; - public static final String ROOT_PATH = VPFHttpServlet.class.getName() - + ".rootPath"; - - public static void setRootDir(HttpServletRequest request, String path) { - request.setAttribute(ROOT_PATHDIR, path); - } - - public static String getRootDir(HttpServletRequest request) { - return (String) request.getAttribute(ROOT_PATHDIR); - } - - public static void setPathInfo(HttpServletRequest request, String path) { - request.setAttribute(ROOT_PATH, path); - } - - public static String getPathInfo(HttpServletRequest request) { - return (String) request.getAttribute(ROOT_PATH); - } - - protected static String setPathInfo(HttpServletRequest request) { - String pathInfo = request.getPathInfo(); - setPathInfo(request, pathInfo); - if (pathInfo != null) { - int index = pathInfo.lastIndexOf('/'); - String subpath = pathInfo.substring(0, index + 1); - setRootDir(request, subpath); - } - return pathInfo; - } -} diff --git a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java b/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java deleted file mode 100644 index 9995029c..00000000 --- a/src/vpfbrowseservlet/src/main/java/com/bbn/openmap/vpfservlet/VPFTable.java +++ /dev/null @@ -1,49 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -import com.bbn.openmap.io.FormatException; -import com.bbn.openmap.layer.vpf.DcwRecordFile; - -/** - * Wrapper for DcwRecordFile objects, to give JSPs a way to interact - * with them directly. - */ -public class VPFTable { - - private DcwRecordFile table; - - public VPFTable() {} - - public void setFile(String file) { - try { - if ((file == null) && (table != null)) { - table.close(); - table = null; - } - if (file != null) { - table = new DcwRecordFile(file); - } - } catch (FormatException fe) { - } - } - - public String getTablename() { - return (table == null) ? "default" : table.getTableName(); - } - - public String getDescription() { - return (table == null) ? "default" : table.getDescription(); - } -} 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 c2fdf898..00000000 --- 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 bae778d0..3e9fb59c 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 c54a77f8..574f5706 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 3f6898fd..a6f94c90 100644 --- a/src/wmsservlet/pom.xml +++ b/src/wmsservlet/pom.xml @@ -4,7 +4,18 @@ 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.3.1 + + false + + + + javax.servlet diff --git a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java b/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java deleted file mode 100644 index 0ba8aa05..00000000 --- a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/HttpResponse.java +++ /dev/null @@ -1,71 +0,0 @@ -// ********************************************************************** -// -// -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// -// ********************************************************************** -// -// $Source: /cvs/distapps/openmap/src/wmsservlet/WEB-INF/src/com/bbn/openmap/wmsservlet/HttpResponse.java,v $ -// $RCSfile: HttpResponse.java,v $ -// $Revision: 1.3 $ -// $Date: 2008/02/20 01:41:08 $ -// $Author: dietrick $ -// -// ********************************************************************** -package com.bbn.openmap.wmsservlet; - -import java.io.IOException; -import java.io.OutputStream; - -import javax.servlet.http.HttpServletResponse; - -import com.bbn.openmap.util.http.IHttpResponse; - -/** - */ -public class HttpResponse implements IHttpResponse { - - protected HttpServletResponse httpResponse; - - /** - * Initialize the input Reader and output Writer - * and start the connection thread. - * - * @param response the response object - */ - public HttpResponse(HttpServletResponse response) { - this.httpResponse = response; - } - - /** - * Write a String response encoded as UTF-8 to the OutputStream. - * - * @param contentType the content type of the response. - * @param response the string containing the response. - */ - public void writeHttpResponse(String contentType, String response) throws IOException { - writeHttpResponse(contentType, response.getBytes("UTF-8")); - } - - /** - * Write a byte[] response to the OutputStream. - * - * @param contentType the content type of the response. - * @param response the byte array containing the response. - */ - public void writeHttpResponse(String contentType, byte[] response) throws IOException { - httpResponse.setContentType(contentType); - httpResponse.setContentLength(response.length); - OutputStream out = httpResponse.getOutputStream(); - out.write(response, 0, response.length); - out.flush(); - } - -} diff --git a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java b/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java deleted file mode 100644 index 8f4a10a7..00000000 --- a/src/wmsservlet/src/main/java/com/bbn/openmap/wmsservlet/OgcWmsServlet.java +++ /dev/null @@ -1,154 +0,0 @@ -// ********************************************************************** -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// ********************************************************************** -// $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; - -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 com.bbn.openmap.PropertyHandler; -import com.bbn.openmap.image.wms.WMSException; -import com.bbn.openmap.image.wms.WmsRequestHandler; -import com.bbn.openmap.util.Debug; - -/** - * - */ -public class OgcWmsServlet extends HttpServlet { - - /** - * A do-nothing constructor - init does all the work. - */ - public OgcWmsServlet() { - super(); - } - - /** - * @param request the request argument - * @return Properties - */ - protected Properties parsePropertiesFromRequest(HttpServletRequest request) { - Properties props = new Properties(); - java.util.Enumeration keys = request.getParameterNames(); - while (keys.hasMoreElements()) { - String key = (String) keys.nextElement(); - String value = request.getParameter(key); - if (value != null) { - // A wms client can send lowercase request parameters. - key = key.toUpperCase(); - props.put(key, value); - } - } - return props; - } - - /** - * Get a {@link Properties} object with the content of openmap.properties. - * No request specific properties are included. - * - * @return Properties - * @throws MalformedURLException - * @throws IOException - */ - protected Properties getProperties() throws MalformedURLException, - IOException { - - // use context parameter "mapDefinition" for path to openmap.properties. - // default to "openmap.properties". - String mapDefinition = getServletContext().getInitParameter( - "mapDefinition"); - if (mapDefinition == null) { - mapDefinition = "openmap.properties"; - } - Debug.message("wms", "Using map definition:" + mapDefinition); - - PropertyHandler propHandler = new PropertyHandler(mapDefinition); - Properties props = propHandler.getProperties(); - - return props; - } - - protected WmsRequestHandler createRequestHandler(HttpServletRequest request) throws ServletException, - IOException { - Debug.message("wms", "OgcWmsServlet.createRequestHandler : "); - - - String schema = request.getScheme(); - if (schema == null) { - throw new ServletException("schema is not specified"); - } - - String hostName = request.getServerName(); - if (hostName == null) { - throw new ServletException("server name not specified"); - } - - int serverPort = request.getServerPort(); - - String contextPath = request.getContextPath(); - if (contextPath == null) { - throw new ServletException("context path is not specified"); - } - - String servletPath = request.getServletPath(); - if (servletPath == null) { - throw new ServletException("servlet path is not specified"); - } - - // can be used to encode extra things in the path info. only usable by - // subclassing OgcWmsServlet - String servletPathInfo = request.getPathInfo(); - if (servletPathInfo == null) { - servletPathInfo = ""; - } - - try { - WmsRequestHandler wmsRequestHandler = new WmsRequestHandler(schema, hostName, - serverPort, contextPath + servletPath + servletPathInfo, getProperties()); - return wmsRequestHandler; - } catch (java.net.MalformedURLException me) { - Debug.message("wms", "MS: caught MalformedURLException - \n" + me.getMessage()); - throw me; - } catch (java.io.IOException ioe) { - Debug.message("wms", "MS: caught IOException - \n" + ioe.getMessage()); - throw ioe; - } catch (WMSException wmse) { - Debug.message("wms", "MS: caught WMSException - \n" + wmse.getMessage()); - throw new ServletException(wmse); - } - - } - - /** - * @param request - * @param response - * @throws ServletException - * @throws IOException - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - Debug.message("wms", "OgcWmsServlet.doGet"); - WmsRequestHandler wmsRequestHandler = createRequestHandler(request); - - Properties properties = parsePropertiesFromRequest(request); - HttpResponse httpResponse = new HttpResponse(response); - wmsRequestHandler.handleRequest(properties, httpResponse); - } - -} From 234ae8e03b2ca8e2aa8f8aa66224388c88732980 Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 20:24:20 +0100 Subject: [PATCH 06/20] OMList internal graphics object is now final and managed, OMGraphicList behavior adjusted accordingly. --- .../com/bbn/openmap/omGraphics/OMGraphicList.java | 15 +++++++-------- .../java/com/bbn/openmap/omGraphics/OMList.java | 6 ++++-- 2 files changed, 11 insertions(+), 10 deletions(-) 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 0c8243fa..d9dfef10 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 a7ed5c54..802693e5 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)) { From 16b586578b3fba97b6dbc4a0d422ffddc587f72a Mon Sep 17 00:00:00 2001 From: Donald Dietrick Date: Sat, 2 Nov 2024 20:29:31 +0100 Subject: [PATCH 07/20] Updating the ScaleDisplayLayer to work the same way as EmbeddedScaleDIsplayPanel. --- .../gui/EmbeddedScaleDisplayPanel.java | 28 +- .../bbn/openmap/layer/ScaleDisplayLayer.java | 655 ++++++++++-------- 2 files changed, 391 insertions(+), 292 deletions(-) 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 6ccd3381..8df2e38d 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/layer/ScaleDisplayLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/ScaleDisplayLayer.java index 82226649..6c8e7df8 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;
    +    }
     }
    
    From 8656ded2b762af930e201035b0ad11d2d964f3a5 Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Sat, 2 Nov 2024 20:30:06 +0100
    Subject: [PATCH 08/20] adding servlet resource for the newly moved servlet
     classes into core.
    
    ---
     src/core/pom.xml | 5 +++++
     1 file changed, 5 insertions(+)
    
    diff --git a/src/core/pom.xml b/src/core/pom.xml
    index 21c51c1a..c0cac58a 100644
    --- a/src/core/pom.xml
    +++ b/src/core/pom.xml
    @@ -174,6 +174,11 @@
           xml-apis
           1.4.01
         
    +      
    +      javax.servlet
    +      servlet-api
    +      2.5
    +    
       
       
         
    
    From 21d86263f61484d6bdd9bf728e9f63e7f3843c4c Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Sat, 2 Nov 2024 20:33:40 +0100
    Subject: [PATCH 09/20] First pass at a SRM reading/drawing component.  Similar
     to DTED.
    
    ---
     .../openmap/dataAccess/srtm/SRTMFrame.java    | 588 ++++++++++++++++++
     1 file changed, 588 insertions(+)
     create mode 100644 src/core/src/main/java/com/bbn/openmap/dataAccess/srtm/SRTMFrame.java
    
    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 00000000..6f3e0a40
    --- /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();
    +    }
    +}
    
    From 6c613344ec1c44436eaa7c8c110f8a7b3e996dab Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Wed, 31 Dec 2025 21:52:27 -0500
    Subject: [PATCH 10/20] Updating to latest version of jakarta for servlet
     functionality.
    
    ---
     pom.xml                                       | 241 +++++++++++++++++-
     .../servlet/mapTile/MapTileServlet.java       |  13 +-
     .../servlet/vpfBrowse/ContextInfo.java        |   3 +-
     .../bbn/openmap/servlet/vpfBrowse/Data.java   |   8 +-
     .../servlet/vpfBrowse/DescribeDBServlet.java  |   8 +-
     .../servlet/vpfBrowse/DirectoryServlet.java   |  10 +-
     .../servlet/vpfBrowse/DispatchServlet.java    |  10 +-
     .../servlet/vpfBrowse/DocFileServlet.java     |  10 +-
     .../servlet/vpfBrowse/FCSRowMaker.java        |   6 +-
     .../openmap/servlet/vpfBrowse/HelloWWW.java   |   9 +-
     .../servlet/vpfBrowse/LibraryBean.java        |   7 +-
     .../servlet/vpfBrowse/ReferenceRowMaker.java  |   4 +-
     .../bbn/openmap/servlet/vpfBrowse/Schema.java |   8 +-
     .../vpfBrowse/SpatialGraphicServlet.java      |   8 +-
     .../vpfBrowse/SpatialIndexServlet.java        |   8 +-
     .../vpfBrowse/ThematicIndexServlet.java       |  10 +-
     .../servlet/vpfBrowse/VDTRowMaker.java        |   6 +-
     .../servlet/vpfBrowse/VPFHttpServlet.java     |  10 +-
     .../bbn/openmap/servlet/wms/HttpResponse.java |   2 +-
     .../openmap/servlet/wms/OgcWmsServlet.java    |   8 +-
     src/wmsservlet/pom.xml                        |  11 +-
     .../src/main/webapp/WEB-INF/web.xml           |   9 +-
     22 files changed, 309 insertions(+), 100 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index ad0c4c49..3ba816ee 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,7 +281,7 @@
           
     	org.apache.maven.plugins
     	maven-javadoc-plugin
    -	3.2.0
    +	3.6.0
     	
     	  false
     	  private
    @@ -104,7 +299,7 @@
           
     	org.apache.maven.plugins
     	maven-dependency-plugin
    -	3.1.1
    +	3.6.1
     	
     	  
     	    copy-dependencies
    @@ -116,6 +311,40 @@
     	  
     	
           
    +      
    +        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/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
    index 61188d6b..a741befb 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/mapTile/MapTileServlet.java
    @@ -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;
    diff --git a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
    index c2f1e2aa..9b6745af 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ContextInfo.java
    @@ -14,6 +14,7 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
    index 9083a8aa..ffc1926c 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Data.java
    @@ -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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
    index 776a63fe..4fcda142 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DescribeDBServlet.java
    @@ -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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
    index 83f3454e..7d5c12d1 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DirectoryServlet.java
    @@ -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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
    index f43e6a05..b422ec5c 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DispatchServlet.java
    @@ -16,14 +16,12 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
    index ff66e676..317c52b1 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/DocFileServlet.java
    @@ -16,14 +16,12 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
    index 6ee6df81..c9c46c10 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/FCSRowMaker.java
    @@ -15,13 +15,11 @@
     
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
    index 2a2c62ba..5bbacf9e 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/HelloWWW.java
    @@ -13,14 +13,13 @@
     // **********************************************************************
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
    index 1fa23776..3d81258e 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/LibraryBean.java
    @@ -13,12 +13,11 @@
     // **********************************************************************
     package com.bbn.openmap.servlet.vpfBrowse;
     
    -import javax.servlet.ServletContext;
    -import javax.servlet.http.HttpServletRequest;
    -import javax.servlet.http.HttpServletResponse;
    -
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
    index 59bfba15..435ac321 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ReferenceRowMaker.java
    @@ -13,8 +13,8 @@
     // **********************************************************************
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
    index fa286d2a..1ce79e3b 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/Schema.java
    @@ -15,11 +15,6 @@
     
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
    index 302b9ef7..48e433eb 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialGraphicServlet.java
    @@ -18,17 +18,15 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
    index 7bda130a..965a77bd 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/SpatialIndexServlet.java
    @@ -17,11 +17,6 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
    index a25b67aa..28aaf329 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/ThematicIndexServlet.java
    @@ -16,12 +16,6 @@
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
    index 93e768d1..e18887c7 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VDTRowMaker.java
    @@ -15,12 +15,10 @@
     
     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/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
    index 0a3cbfa1..6763c08b 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/vpfBrowse/VPFHttpServlet.java
    @@ -16,11 +16,11 @@
     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/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
    index 880758ab..85347ead 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/HttpResponse.java
    @@ -24,7 +24,7 @@
     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/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
    index d8a4c7aa..74ed5573 100644
    --- a/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
    +++ b/src/core/src/main/java/com/bbn/openmap/servlet/wms/OgcWmsServlet.java
    @@ -17,10 +17,10 @@
     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/wmsservlet/pom.xml b/src/wmsservlet/pom.xml
    index a6f94c90..a8878f25 100644
    --- a/src/wmsservlet/pom.xml
    +++ b/src/wmsservlet/pom.xml
    @@ -9,7 +9,7 @@
             
                 org.apache.maven.plugins
                 maven-war-plugin
    -            3.3.1
    +            3.4.0
                 
                     false
                 
    @@ -18,14 +18,15 @@
       
       
         
    -      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 5ef2631a..95503b60 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
         
    
    From ae8546825f08d33b30398dc840c2085d67f71130 Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Wed, 31 Dec 2025 21:55:32 -0500
    Subject: [PATCH 11/20] Updated PostGIS classes, including pom
    
    ---
     src/core/pom.xml                              | 145 ++++++++++--------
     .../openmap/layer/postgis/FeatureQuery.java   |   4 +-
     .../postgis/PostGISOMGraphicFactory.java      |  17 +-
     3 files changed, 86 insertions(+), 80 deletions(-)
    
    diff --git a/src/core/pom.xml b/src/core/pom.xml
    index c0cac58a..d0293105 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,103 +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
         
    -      
    -      javax.servlet
    -      servlet-api
    -      2.5
    +    
    +      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
         
    + 
       
    -  
       
         
           
    @@ -240,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/layer/postgis/FeatureQuery.java b/src/core/src/main/java/com/bbn/openmap/layer/postgis/FeatureQuery.java
    index 43df058d..ef301c32 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 6393ce58..8de0a713 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
    
    From b4784ffe4c19b252979b40e76165de465b66cc37 Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Wed, 31 Dec 2025 21:56:39 -0500
    Subject: [PATCH 12/20] Formatting
    
    ---
     .../java/com/bbn/openmap/util/DataBounds.java | 432 +++++++++---------
     1 file changed, 218 insertions(+), 214 deletions(-)
    
    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 40453499..c1f14f42 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()));
    +    }
    +}
    
    From 210af64d84e9e792dbac19d2b0d41569545498e2 Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Wed, 31 Dec 2025 21:57:41 -0500
    Subject: [PATCH 13/20] Testing out accessing ENC data.
    
    ---
     .../openmap/dataAccess/iso8211/DDFSubfieldDefinition.java  | 2 +-
     .../java/com/bbn/openmap/dataAccess/iso8211/View8211.java  | 7 +++----
     2 files changed, 4 insertions(+), 5 deletions(-)
    
    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 837d3c59..f600fcd5 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 3dfbfffd..c932e007 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
    @@ -160,7 +159,7 @@ public static void main(String[] argv) {
     
           Debug.init();
     
    -      String pszFilename = null;
    +      String pszFilename = "/Volumes/mushmouth/data/ENC/CATALOG.031";
           boolean bFSPTHack = false;
     
           for (int iArg = 0; iArg < argv.length; iArg++) {
    
    From 548cbce385b2fa369581d2328921040d2e57f7df Mon Sep 17 00:00:00 2001
    From: Donald Dietrick 
    Date: Tue, 28 Apr 2026 09:45:32 -0400
    Subject: [PATCH 14/20] Reversing path change in View8211
    
    ---
     .../main/java/com/bbn/openmap/dataAccess/iso8211/View8211.java  | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    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 c932e007..6d1d2907 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
    @@ -159,7 +159,7 @@ public static void main(String[] argv) {
     
           Debug.init();
     
    -      String pszFilename = "/Volumes/mushmouth/data/ENC/CATALOG.031";
    +      String pszFilename = null;
           boolean bFSPTHack = false;
     
           for (int iArg = 0; iArg < argv.length; iArg++) {
    
    From f856c730025dd0652be858cfbe7dfdab30a7e7d3 Mon Sep 17 00:00:00 2001
    From: Don Dietrick 
    Date: Tue, 28 Apr 2026 12:03:24 -0400
    Subject: [PATCH 15/20] Updating MapBean version to proper beta
    
    ---
     .../main/java/com/bbn/openmap/MapBean.java    | 46 +++++++++----------
     1 file changed, 22 insertions(+), 24 deletions(-)
    
    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 bf7758a0..2b28a8f4 100644
    --- a/src/core/src/main/java/com/bbn/openmap/MapBean.java
    +++ b/src/core/src/main/java/com/bbn/openmap/MapBean.java
    @@ -22,6 +22,27 @@
     
     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;
    @@ -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
    @@ -152,7 +150,7 @@ public class MapBean extends JComponent implements ComponentListener, ContainerL
     	/**
     	 * OpenMap version.
     	 */
    -	public static final String version = "6.0b";
    +	public static final String version = "6.1b";
     
     	/**
     	 * Suppress the copyright message on initialization.
    
    From 52abeb548858e87de460e97382860f7d272850d2 Mon Sep 17 00:00:00 2001
    From: Don Dietrick 
    Date: Wed, 20 May 2026 16:47:43 -0400
    Subject: [PATCH 16/20] Updating javadocs, code cleanup.
    
    ---
     .../openmap/tools/icon/BasicAppIconPart.java  |  42 +-
     .../bbn/openmap/tools/icon/BasicIconPart.java | 477 ++++++++++--------
     .../tools/icon/IconFactoryTestingTool.java    | 241 ++++-----
     .../com/bbn/openmap/tools/icon/IconPart.java  |  18 +-
     .../tools/icon/IconPartCollection.java        |  65 ++-
     .../bbn/openmap/tools/icon/IconPartList.java  |  61 ++-
     .../bbn/openmap/tools/icon/OMIconFactory.java |  56 +-
     .../bbn/openmap/tools/icon/OMIconPart.java    |   1 +
     8 files changed, 556 insertions(+), 405 deletions(-)
    
    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 ed1d4b55..444b6bbf 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 819a1c63..c7da8a61 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 d618bb2a..d2b50573 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 a2382887..a041d4ed 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 d671d52a..e7b31bae 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 4115d171..09ed0957 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 6ff8a2bf..1ff74ac5 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 b0b7b1aa..481b30f2 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) {
    
    From 62ad9eec63d35a8a05f6351e96923d4b36943799 Mon Sep 17 00:00:00 2001
    From: Don Dietrick 
    Date: Wed, 20 May 2026 19:11:09 -0400
    Subject: [PATCH 17/20] Updating ZoomEvents and how zoom is handled by the
     AbstractMouseMode and MapBean.  The lat/lon under the cursor is held in place
     on the map.  Removed zoom options in NavigateMenu, too hard to use.
    
    ---
     .../main/java/com/bbn/openmap/MapBean.java    | 3288 +++++++++--------
     .../bbn/openmap/event/AbstractMouseMode.java  | 1691 +++++----
     .../java/com/bbn/openmap/event/ZoomEvent.java |   61 +-
     .../com/bbn/openmap/event/ZoomSupport.java    |   11 +-
     .../com/bbn/openmap/gui/NavigateMenu.java     |  118 +-
     .../java/com/bbn/openmap/gui/ZoomPanel.java   |   92 +-
     6 files changed, 2625 insertions(+), 2636 deletions(-)
    
    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 2b28a8f4..7f2bcf37 100644
    --- a/src/core/src/main/java/com/bbn/openmap/MapBean.java
    +++ b/src/core/src/main/java/com/bbn/openmap/MapBean.java
    @@ -19,7 +19,6 @@
     // $Author: dietrick $
     //
     // **********************************************************************
    -
     package com.bbn.openmap;
     
     import com.bbn.openmap.event.CenterEvent;
    @@ -53,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;
    @@ -122,1682 +122,1696 @@
      * 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.1b";
    +    /**
    +     * 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. + */ + 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/event/AbstractMouseMode.java b/src/core/src/main/java/com/bbn/openmap/event/AbstractMouseMode.java index da3d0a2f..aa9b5385 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)); + } + 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 ad6539e3..acb9786a 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 dbb064e4..1e4937a4 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/NavigateMenu.java b/src/core/src/main/java/com/bbn/openmap/gui/NavigateMenu.java index 47ea9f81..d106cbd7 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/ZoomPanel.java b/src/core/src/main/java/com/bbn/openmap/gui/ZoomPanel.java index 93dc1aff..40ec4ab2 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 +} From 1819682f9ac562cc220423fb6e4884d3d38a5e06 Mon Sep 17 00:00:00 2001 From: Don Dietrick Date: Wed, 20 May 2026 19:11:56 -0400 Subject: [PATCH 18/20] Made the rosette and scale slider optional, and not on by default. If slider not shown, zoom buttons add circles around them. --- .../com/bbn/openmap/gui/EmbeddedNavPanel.java | 1502 +++++++++-------- 1 file changed, 762 insertions(+), 740 deletions(-) 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 51237501..72263222 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(); + } + } + } } From 0c28d5cc496ddce135708847fd1f73517941d9e9 Mon Sep 17 00:00:00 2001 From: Don Dietrick Date: Wed, 20 May 2026 19:12:49 -0400 Subject: [PATCH 19/20] Modernizing java code and fixing javadocs. --- .../com/bbn/openmap/gui/NavigatePanel.java | 170 +++-- .../com/bbn/openmap/gui/OverlayMapPanel.java | 703 ++++++++++-------- 2 files changed, 472 insertions(+), 401 deletions(-) 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 0b98277d..6f2b7f6b 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 8cbee080..da687d78 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); + } + } } From c4d36d79bd0d98e722b5d083ae40a440e6e5728f Mon Sep 17 00:00:00 2001 From: Don Dietrick Date: Thu, 21 May 2026 09:55:30 -0400 Subject: [PATCH 20/20] Attaching mouse point to zoom events for enhanced zooming --- src/core/src/main/java/com/bbn/openmap/MapBean.java | 1 + .../src/main/java/com/bbn/openmap/event/AbstractMouseMode.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 7f2bcf37..70ca19c6 100644 --- a/src/core/src/main/java/com/bbn/openmap/MapBean.java +++ b/src/core/src/main/java/com/bbn/openmap/MapBean.java @@ -777,6 +777,7 @@ public void pan(PanEvent evt) { * * @param evt the ZoomEvent describing the new scale. */ + @Override public void zoom(ZoomEvent evt) { float newScale; if (evt.isAbsolute()) { 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 aa9b5385..85294f5e 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 @@ -545,7 +545,7 @@ public void mouseWheelMoved(MouseWheelEvent e) { zoom = 1f / zoomFactor; } - map.zoom(new ZoomEvent(map, ZoomEvent.RELATIVE, zoom)); + map.zoom(new ZoomEvent(map, ZoomEvent.RELATIVE, zoom).withScreenLocation(e.getPoint())); } lastMouseWheelEventTime = currentTime; }