// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/vpf/VPFLayer.java,v $ // $RCSfile: VPFLayer.java,v $ // $Revision: 1.21 $ // $Date: 2006/03/06 16:13:59 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.layer.vpf; import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import com.bbn.openmap.event.ProjectionListener; import com.bbn.openmap.io.FormatException; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMGraphicConstants; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.proj.GeoProj; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.PropUtils; /** * The VPFFeaureLayer renders VPF data with features being rendered in the order * and style specified by the GeoSym specification. It uses the * VPFAutoFeatureWarehouse, which knows how to use GeoSym data files to manage * desired features. These data files can be modified to adjust which features * are displayed. * * The properties for this layer are: * * <pre> * vpfPath=path to vpf library directory, parent of DHT/LAT file. Multiple paths can be specified, separated by ; * libraryName=name of library to use, since multiple libraries can be specified in a top level vpf directory. Wildcards accepted. * * # VFPAutoFeatureGraphicWarehouse options: * cgmDirectory=parent directory of cgm files used for symbology * faccLookupFile=path to csv file that ties FACC codes to symbol file names * # The priority file is the file to adjust to customize display... * priorityFile=path to csv file specifying which FACC codes, types should be rendered and in what order. * featureInfoHandler=class of object to handle attributes * </pre> * * @author dietrick */ public class VPFFeatureLayer extends OMGraphicHandlerLayer implements ProjectionListener, ActionListener, Serializable { private static final long serialVersionUID = 1L; public static Logger logger = Logger.getLogger("com.bbn.openmap.layer.vpf.VPFFeatureLayer"); /** property extension used to set the VPF root directory */ public static final String pathProperty = "vpfPath"; /** Property for setting VPF cutoff scale */ public static final String cutoffScaleProperty = "cutoffScale"; /** Property for setting VPF library name to use */ public static final String LibraryNameProperty = "libraryName"; /** the object that knows all the nitty-gritty vpf stuff */ protected transient LibrarySelectionTable lst; /** our own little graphics factory */ protected transient VPFAutoFeatureGraphicWarehouse warehouse; /** * hang onto prefix used to initialize warehouse in setProperties() */ protected String prefix; /** hang onto properties file used to initialize warehouse */ protected Properties props; /** the path to the root VPF directory */ protected String[] dataPaths = null; protected int cutoffScale = LibrarySelectionTable.DEFAULT_BROWSE_CUTOFF; /** the library name to focus on */ protected String libraryName = null; /** * Construct a VPF layer. */ public VPFFeatureLayer() { setProjectionChangePolicy(new com.bbn.openmap.layer.policy.ListResetPCPolicy(this)); setMouseModeIDsForEvents(new String[] { "Gestures" }); warehouse = new VPFAutoFeatureGraphicWarehouse(); } /** * Construct a VPFLayer, and sets its name. * * @param name the name of the layer. */ public VPFFeatureLayer(String name) { this(); setName(name); } /** * Another way to set the parameters of the VPFLayer. */ public void setProperties(String prefix, Properties props) { super.setProperties(prefix, props); setAddToBeanContext(true); String realPrefix = PropUtils.getScopedPropertyPrefix(prefix); cutoffScale = PropUtils.intFromProperties(props, realPrefix + cutoffScaleProperty, cutoffScale); libraryName = props.getProperty(realPrefix + LibraryNameProperty, libraryName); String path[] = PropUtils.initPathsFromProperties(props, realPrefix + pathProperty); if (path != null && path.length != 0) { setPath(path); } // need to save these so we can call setProperties on the // warehouse, // which we probably can't construct yet this.prefix = prefix; this.props = props; if (warehouse != null) { warehouse.setProperties(prefix, props); warehouse.setUseLibraries(PropUtils.parseSpacedMarkers(libraryName)); } } public Properties getProperties(Properties props) { props = super.getProperties(props); String realPrefix = PropUtils.getScopedPropertyPrefix(this); props.put(realPrefix + cutoffScaleProperty, Integer.toString(cutoffScale)); StringBuffer paths = new StringBuffer(); String[] ps = getPath(); for (int i = 0; ps != null && i < ps.length; i++) { paths.append(ps[i]); if (i < ps.length - 1) paths.append(";"); } props.put(realPrefix + pathProperty, paths.toString()); // For the library in a vpf package props.put(realPrefix + LibraryNameProperty, PropUtils.unnull(libraryName)); if (warehouse != null) { warehouse.getProperties(props); } return props; } /** Where we store our default properties once we've loaded them. */ private Properties defaultProps; /** * Return our default properties for vpf land. */ public Properties getDefaultProperties() { if (defaultProps == null) { try { InputStream in = VPFFeatureLayer.class.getResourceAsStream("defaultVPFlayers.properties"); // use a temporary so other threads won't see an // empty properties file Properties tmp = new Properties(); if (in != null) { tmp.load(in); in.close(); } else { logger.warning("can't load default properties file"); // just use an empty properties file } defaultProps = tmp; } catch (IOException io) { logger.warning("can't load default properties: " + io); defaultProps = new Properties(); } } return defaultProps; } /** * Set the data path to a single place. */ public void setPath(String newPath) { logger.fine("setting paths to " + newPath); setPath(new String[] { newPath }); } /** * Set the data path to multiple places. */ public void setPath(String[] newPaths) { dataPaths = newPaths; lst = null; initLST(); } /** * Returns the list of paths we use to look for data. * * @return the list of paths. Don't modify the array! */ public String[] getPath() { return dataPaths; } /** * initialize the library selection table. */ protected void initLST() { logger.fine("initializing Library Selection Table (LST)"); try { if (lst == null) { if (dataPaths == null) { logger.info("VPFLayer|" + getName() + ": path not set"); } else { logger.fine("VPFLayer.initLST(dataPaths)"); lst = new LibrarySelectionTable(dataPaths); lst.setCutoffScale(cutoffScale); } } } catch (com.bbn.openmap.io.FormatException f) { throw new java.lang.IllegalArgumentException(f.getMessage()); // } catch (NullPointerException npe) { // throw new // java.lang.IllegalArgumentException("VPFLayer|" + // getName() + // ": path name not valid"); } } public VPFAutoFeatureGraphicWarehouse getWarehouse() { return warehouse; } /** * If the warehouse gets set as a result of this method being called, the * properties will beed to be reset on it. * * @param sbf Search by features. */ public void checkWarehouse(boolean sbf) { if (warehouse == null) { logger.fine("need to create warehouse"); warehouse = new VPFAutoFeatureGraphicWarehouse(); } } /** * Create the OMGraphicList to use on the map. OMGraphicHandler methods call * this. */ public synchronized OMGraphicList prepare() { if (lst == null) { try { initLST(); } catch (IllegalArgumentException iae) { logger.warning("VPFLayer.prepare: Illegal Argument Exception.\n\nPerhaps a file not found. Check to make sure that the paths to the VPF data directories are the parents of \"lat\" or \"lat.\" files. \n\n" + iae); return null; } if (lst == null) { if (logger.isLoggable(Level.FINE)) { logger.fine("VPFLayer| " + getName() + " prepare(), Library Selection Table not set."); } return null; } } if (warehouse == null) { StringBuffer dpb = new StringBuffer(); if (dataPaths != null) { for (int num = 0; num < dataPaths.length; num++) { if (num > 0) { dpb.append(":"); } dpb.append(dataPaths[num]); } } logger.warning("VPFLayer.getRectangle: Data path probably wasn't set correctly (" + dpb.toString() + "). The warehouse not initialized."); return null; } Projection p = getProjection(); if (p == null || !(p instanceof GeoProj)) { if (logger.isLoggable(Level.FINE)) { logger.fine("VPFLayer.getRectangle() called with a projection (" + p + ") set in the layer, which isn't being handled."); } return new OMGraphicList(); } LatLonPoint ll1 = p.getUpperLeft(); LatLonPoint ll2 = p.getLowerRight(); // Check both dynamic args and palette values when // deciding what to draw. if (logger.isLoggable(Level.FINE)) { logger.fine("calling draw with boundaries: " + ll1 + " " + ll2); } long start = System.currentTimeMillis(); OMGraphicList omgList = new OMGraphicList(); try { omgList = warehouse.getFeatures(lst, ll1, ll2, p, omgList); } catch (FormatException fe) { logger.warning("Caught FormatException reading features: " + fe.getMessage()); } long stop = System.currentTimeMillis(); if (logger.isLoggable(Level.FINE)) { logger.fine("read time: " + ((stop - start) / 1000d) + " seconds"); } return omgList; } public String getToolTipTextFor(OMGraphic omg) { return (String) omg.getAttribute(OMGraphicConstants.TOOLTIP); } public String getInfoText(OMGraphic omg) { return (String) omg.getAttribute(OMGraphicConstants.INFOLINE); } public boolean isHighlightable(OMGraphic omg) { VPFFeatureInfoHandler vfih = warehouse.getFeatInfoHandler(); if (vfih != null) { return vfih.isHighlightable(omg); } return false; } /** * Fleeting change of appearance for mouse movements over an OMGraphic. */ public void highlight(OMGraphic omg) { VPFFeatureInfoHandler vfih = warehouse.getFeatInfoHandler(); if (vfih != null && vfih.shouldPaintHighlight(omg)) { super.highlight(omg); } } /** * Notification to set OMGraphic to normal appearance. */ public void unhighlight(OMGraphic omg) { VPFFeatureInfoHandler vfih = warehouse.getFeatInfoHandler(); if (vfih != null && vfih.shouldPaintHighlight(omg)) { super.unhighlight(omg); } } }