// **********************************************************************
//
// <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/rpf/RpfCoverage.java,v $
// $RCSfile: RpfCoverage.java,v $
// $Revision: 1.9 $
// $Date: 2005/12/09 21:09:05 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.rpf;
/* Java Core */
import java.awt.Color;
import java.awt.Component;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import com.bbn.openmap.Environment;
import com.bbn.openmap.I18n;
import com.bbn.openmap.Layer;
import com.bbn.openmap.PropertyConsumer;
import com.bbn.openmap.omGraphics.OMColor;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.proj.CADRG;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.proj.coords.LatLonPoint;
import com.bbn.openmap.util.ColorFactory;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
/**
* This is a tool that provides coverage information on the Rpf data. It is
* supposed to be a simple tool that lets you see the general location of data,
* to guide you to the right place and scale of coverage. The layer really uses
* the properties passed in to it to determine which RPF/A.TOC should be scanned
* for the data. There is a palette for this layer, that lets you turn off the
* coverage for different levels of Rpf. Right now, only City Graphics, TLM,
* JOG, TPC, ONC, JNC, GNC and 5/10 meter CIB scales are are handled. All other
* scales are tossed together under the misc setting. The City Graphics setting
* shows all charts for scales greater than than 1:15k.
* <P>
*
* <pre>
* The properties for this file are:
* # Java Rpf properties
* # Number between 0-255: 0 is transparent, 255 is opaque
* jrpf.coverageOpaque=255
* #Default is true, don't need this entry if you like it...
* jrpf.CG.showcov=true
* #Default colors don't need this entry
* jrpf.CG.color=CE4F3F
* # Other types can be substituted for CG (TLM, JOG, TPC, ONC, JNC, GNC, CIB10, CIB5, MISC)
* # Fill the rectangle, default is true
* jrpf.coverageFill=true
* </pre>
*/
public class RpfCoverage extends OMGraphicList implements RpfConstants, PropertyConsumer {
/** Property to use for filled rectangles (when java supports it). */
public static final String CoverageOpaquenessProperty = "coverageOpaque";
/** Property to use to fill rectangles. */
public static final String FillProperty = "coverageFill";
/**
*
*/
private static final long serialVersionUID = 1L;
protected RpfCoverageManager coverageManager = null;
protected RpfFrameProvider frameProvider = null;
protected Map<RpfProductInfo, RpfCoverageControl> coverages = new TreeMap<RpfProductInfo, RpfCoverageControl>(
new RCCScaleComparator());
protected String propertyPrefix = null;
/**
* A setting for how transparent to make the images. The default is 255,
* which is totally opaque. Not used right now.
*/
protected int opaqueness = RpfColortable.DEFAULT_OPAQUENESS;
/** Flag to fill the coverage rectangles. */
protected boolean fillRects = true;
/** The parent layer. */
protected Layer layer;
/** Flag to track when the RpfCoverage is active. */
protected boolean inUse = false;
/**
* Show the palette when showing coverage. Probably not needed for layers
* limiting chart seriestypes for display.
*/
protected boolean showPalette = true;
protected I18n i18n = Environment.getI18n();
/**
* The default constructor for the Layer. All of the attributes are set to
* their default values.
*/
public RpfCoverage(Layer l, RpfFrameProvider frameProvider) {
this.layer = l;
setFrameProvider(frameProvider);
super.setTraverseMode(LAST_ADDED_ON_TOP);
}
public void setFrameProvider(RpfFrameProvider frameProvider) {
this.frameProvider = frameProvider;
if (frameProvider != null) {
List<RpfCoverageBox> rpfCoverages = frameProvider.getCatalogCoverage(90f, -180f, -90f, 180f,
new CADRG(new LatLonPoint.Double(), 10000000f, 200, 200), null);
for (RpfCoverageBox rcb : rpfCoverages) {
RpfProductInfo rpfPI = RpfProductInfo.get(rcb.chartCode);
if (rpfPI != null) {
RpfCoverageControl control = coverages.get(RpfProductInfo.get(rcb.chartCode));
if (control == null) {
control = new RpfCoverageControl(rpfPI, layer);
coverages.put(rpfPI, control);
control.setFilled(fillRects);
control.setFillPaint(getModifiedColor((Color) control.getFillPaint()));
}
}
}
}
}
/** Method that sets all the variables to the default values. */
protected void setDefaultValues() {
allCoveragesOn();
opaqueness = RpfColortable.DEFAULT_OPAQUENESS / 2;
fillRects = true;
}
public boolean isInUse() {
return inUse;
}
public void setInUse(boolean iu) {
inUse = iu;
this.setVisible(iu); // Show OMGraphics or not
if (showPalette || !inUse) {
// Always want it hidden if not in use.
JFrame covPalette = getPaletteWindow();
covPalette.setLocationRelativeTo(layer.getPalette());
covPalette.setVisible(inUse);
}
}
public boolean isShowPalette() {
return showPalette;
}
public void setShowPalette(boolean sp) {
showPalette = sp;
if (!showPalette) {
allCoveragesOn();
}
}
public void allCoveragesOn() {
for (RpfCoverageControl rcc : coverages.values()) {
rcc.setVisible(true);
}
}
public void setProperties(java.util.Properties props) {
setProperties(null, props);
}
/**
* Set all the Rpf properties from a properties object.
*
* @param prefix
* string prefix used in the properties file for this layer.
* @param properties
* the properties set in the properties file.
*/
public void setProperties(String prefix, java.util.Properties properties) {
setPropertyPrefix(prefix);
setDefaultValues();
prefix = PropUtils.getScopedPropertyPrefix(prefix);
fillRects = PropUtils.booleanFromProperties(properties, prefix + FillProperty, fillRects);
showPalette = PropUtils.booleanFromProperties(properties, prefix + CoverageProperty, showPalette);
opaqueness = PropUtils.intFromProperties(properties, prefix + CoverageOpaquenessProperty, opaqueness);
for (RpfCoverageControl rcc : coverages.values()) {
String abbrdot = PropUtils.getScopedPropertyPrefix(rcc.rpfProduct.abbr.replace(' ', '_'));
rcc.setColorValue(properties.getProperty(prefix + abbrdot + ColorProperty, rcc.getColorValue()));
rcc.setFilled(fillRects);
rcc.setFillPaint(getModifiedColor((Color) rcc.getFillPaint()));
rcc.setVisible(PropUtils.booleanFromProperties(properties, prefix + abbrdot + ShowCoverageProperty,
rcc.isVisible()));
}
}
/**
* PropertyConsumer method, to fill in a Properties object, reflecting the
* current values of the layer. If the layer has a propertyPrefix set, the
* property keys should have that prefix plus a separating '.' prepended to
* each property key it uses for configuration.
*
* @param props
* a Properties object to load the PropertyConsumer properties
* into. If props equals null, then a new Properties object
* should be created.
* @return Properties object containing PropertyConsumer property values. If
* getList was not null, this should equal getList. Otherwise, it
* should be the Properties object created by the PropertyConsumer.
*/
public Properties getProperties(Properties props) {
if (props == null) {
props = new Properties();
}
String prefix = PropUtils.getScopedPropertyPrefix(propertyPrefix);
props.put(prefix + FillProperty, new Boolean(fillRects).toString());
props.put(prefix + CoverageProperty, new Boolean(showPalette).toString());
props.put(prefix + CoverageOpaquenessProperty, Integer.toString(opaqueness));
for (RpfCoverageControl rcc : coverages.values()) {
String abbr = rcc.rpfProduct.abbr.replace(' ', '_');
String abbrdot = PropUtils.getScopedPropertyPrefix(abbr);
props.put(prefix + abbrdot + ColorProperty, Integer.toHexString(((Color) rcc.getLinePaint()).getRGB()));
}
return props;
}
/**
* Method to fill in a Properties object with values reflecting the
* properties able to be set on this PropertyConsumer. The key for each
* property should be the raw property name (without a prefix) with a value
* that is a String that describes what the property key represents, along
* with any other information about the property that would be helpful
* (range, default value, etc.). For Layer, this method should at least
* return the 'prettyName' property.
*
* @param list
* a Properties object to load the PropertyConsumer properties
* into. If getList equals null, then a new Properties object
* should be created.
* @return Properties object containing PropertyConsumer property values. If
* getList was not null, this should equal getList. Otherwise, it
* should be the Properties object created by the PropertyConsumer.
*/
public Properties getPropertyInfo(Properties list) {
if (list == null) {
list = new Properties();
}
PropUtils.setI18NPropertyInfo(i18n, list, RpfLayer.class, FillProperty, "Fill Coverage Rectangles",
"Flag to set if the coverage rectangles should be filled.",
"com.bbn.openmap.util.propertyEditor.OnOffPropertyEditor");
PropUtils.setI18NPropertyInfo(i18n, list, RpfLayer.class, CoverageProperty, "Show Coverage Palette",
"Flag to set the coverage palette should be shown.",
"com.bbn.openmap.util.propertyEditor.OnOffPropertyEditor");
PropUtils.setI18NPropertyInfo(i18n, list, RpfLayer.class, CoverageOpaquenessProperty, "Coverage Opaqueness",
"Integer representing opaqueness level (0-255, 0 is clear) of coverage rectangles.", null);
for (RpfCoverageControl rcc : coverages.values()) {
String abbr = rcc.rpfProduct.abbr.replace(' ', '_');
String abbrdot = PropUtils.getScopedPropertyPrefix(abbr);
PropUtils.setI18NPropertyInfo(i18n, list, RpfLayer.class, abbrdot + ColorProperty,
rcc.rpfProduct.abbr + " Coverage Color", "Color for " + abbr + " chart coverage.",
"com.bbn.openmap.util.propertyEditor.ColorPropertyEditor");
}
return list;
}
/**
* Specify what order properties should be presented in an editor.
*/
public String getInitPropertiesOrder() {
StringBuilder sb = new StringBuilder(" " + FillProperty + " " + CoverageOpaquenessProperty);
for (RpfProductInfo rpi : coverages.keySet()) {
sb.append(" ").append(rpi.abbr.replace(' ', '_')).append(".").append(ColorProperty);
}
return sb.toString();
}
/**
* Set the property key prefix that should be used by the PropertyConsumer.
* The prefix, along with a '.', should be prepended to the property keys
* known by the PropertyConsumer.
*
* @param prefix
* the prefix String.
*/
public void setPropertyPrefix(String prefix) {
propertyPrefix = prefix;
}
/**
* Get the property key prefix that is being used to prepend to the property
* keys for Properties lookups.
*
* @return the property prefix
*/
public String getPropertyPrefix() {
return propertyPrefix;
}
/**
* Prepares the graphics for the layer. This is where the getRectangle()
* method call is made on the rpfcov.
* <p>
* Occasionally it is necessary to abort a prepare call. When this happens,
* the map will set the cancel bit in the LayerThread, (the thread that is
* running the prepare). If this Layer needs to do any cleanups during the
* abort, it should do so, but return out of the prepare asap.
*/
public void prepare(Projection projection, String chartSeries) {
double ullat = 90;
double ullon = -180;
double lrlat = -90;
double lrlon = 180;
if (projection != null) {
ullat = projection.getUpperLeft().getY();
ullon = projection.getUpperLeft().getX();
lrlat = projection.getLowerRight().getY();
lrlon = projection.getLowerRight().getX();
}
Debug.message("basic", "RpfCoverage.prepare(): doing it");
// Setting the OMGraphicsList for this layer. Remember, the
// OMGraphicList is made up of OMGraphics, which are generated
// (projected) when the graphics are added to the list. So,
// after this call, the list is ready for painting.
// IF the data arrays have not been set up yet, do it!
if (coverageManager == null) {
coverageManager = new RpfCoverageManager(frameProvider);
}
clearLayerAndCoverages();
coverageManager.getCatalogCoverage(ullat, ullon, lrlat, lrlon, projection, chartSeries, coverages);
resetCoveragesOnLayer();
}
protected void clearLayerAndCoverages() {
this.clear();
for (RpfCoverageControl rcc : coverages.values()) {
rcc.clear();
}
}
protected void resetCoveragesOnLayer() {
this.clear();
for (RpfCoverageControl rcc : coverages.values()) {
if (rcc.getVisibilityToggle().isSelected()) {
this.addAll(rcc);
}
}
}
/**
* @return Returns the opaqueness.
*/
public int getOpaqueness() {
return opaqueness;
}
/**
* @param opaqueness
* The opaqueness to set.
*/
public void setOpaqueness(int opaqueness) {
this.opaqueness = opaqueness;
for (RpfCoverageControl rcc : coverages.values()) {
rcc.setFilled(fillRects);
rcc.setFillPaint(getModifiedColor((Color) rcc.getFillPaint()));
}
}
/**
* @return the fillRects
*/
public boolean isFillRects() {
return fillRects;
}
/**
* @param fillRects
* the fillRects to set
*/
public void setFillRects(boolean fillRects) {
this.fillRects = fillRects;
if (coverages != null) {
for (RpfCoverageControl rcc : coverages.values()) {
rcc.setFilled(fillRects);
rcc.setFillPaint(getModifiedColor((Color) rcc.getFillPaint()));
}
}
}
protected Color getModifiedColor(Color color) {
if (opaqueness < 255) {
int opa = opaqueness << 24;
return ColorFactory.createColor(((color.getRGB() & 0x00FFFFFF) | opa), true);
} else {
return ColorFactory.createColor(color.getRGB(), true);
}
}
// ----------------------------------------------------------------------
// GUI
// ----------------------------------------------------------------------
/**
* Provides the palette widgets to control the options of showing maps, or
* attribute text.
*
* @return Component object representing the palette widgets.
*/
public java.awt.Component getGUI() {
Box box = Box.createVerticalBox();
box.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Coverage Controls"));
if (coverages != null) {
for (RpfProductInfo rpi : coverages.keySet()) {
box.add(coverages.get(rpi).getVisibilityToggle());
}
}
return box;
}
public static class RpfCoverageControl extends OMGraphicList {
private static final long serialVersionUID = 1L;
RpfProductInfo rpfProduct;
Layer layer;
JCheckBox controlToggle;
String colorValue;
public RpfCoverageControl(RpfProductInfo rpfPro, Layer layer) {
this.rpfProduct = rpfPro;
this.layer = layer;
Color c = DefaultColors.getColor(rpfPro);
setLinePaint(c);
setColorValue(Integer.toHexString(c.getRGB()));
}
public JCheckBox getVisibilityToggle() {
if (controlToggle == null) {
StringBuilder title = new StringBuilder("Show ");
title.append(rpfProduct.abbr).append(" Coverage");
controlToggle = new JCheckBox(title.toString(), true);
controlToggle.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
RpfCoverageControl.this.setVisible(((JCheckBox) ae.getSource()).isSelected());
if (layer != null) {
if (layer instanceof RpfLayer && ((RpfLayer)layer).coverage != null) {
((RpfLayer)layer).coverage.resetCoveragesOnLayer();
}
layer.repaint();
}
}
});
}
return controlToggle;
}
public boolean add(OMGraphic omg) {
omg.setLinePaint(getLinePaint());
omg.setFillPaint(getFillPaint());
return super.add(omg);
}
public void setFilled(boolean filled) {
if (filled) {
setFillPaint(getLinePaint());
} else {
setFillPaint(OMColor.clear);
}
}
public boolean isFilled() {
Paint fPaint = getFillPaint();
return fPaint == null || fPaint == OMColor.clear;
}
public void setVisible(boolean set) {
super.setVisible(set);
if (controlToggle != null) {
controlToggle.setSelected(set);
}
}
/**
* @return the colorValue
*/
public String getColorValue() {
return colorValue;
}
/**
* @param colorValue
* the colorValue to set
*/
public void setColorValue(String colorValue) {
try {
this.colorValue = colorValue;
setLinePaint(PropUtils.parseColor(colorValue));
} catch (NumberFormatException nfe) {
}
}
}
public static class RCCScaleComparator implements Comparator<RpfProductInfo> {
public int compare(RpfProductInfo c1, RpfProductInfo c2) {
double diff = c1.scale - c2.scale;
if (diff == 0) {
return 0;
} else if (diff < 0) {
return 1;
} else {
return -1;
}
}
}
protected JFrame paletteWindow = null;
/**
* Get RpfCoverage's associated palette as a top-level window
*
* @return the frame that the palette is in
*/
public JFrame getPaletteWindow() {
if (paletteWindow == null) {
// create the palette's scroll pane
Component pal = getGUI();
if (pal == null) {
pal = new JLabel("No Coverage Information Available.");
}
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setAlignmentX(Component.LEFT_ALIGNMENT);
p.setAlignmentY(Component.BOTTOM_ALIGNMENT);
p.add(pal);
JScrollPane scrollPane = new JScrollPane(p, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
scrollPane.setAlignmentY(Component.TOP_ALIGNMENT);
// create the palette internal window
paletteWindow = new JFrame("RPF Coverage Palette");
paletteWindow.setContentPane(scrollPane);
paletteWindow.pack();// layout all the components
}
return paletteWindow;
}
protected enum DefaultColors {
CG(RpfProductInfo.CG, 0xAC4853),
TLM(RpfProductInfo.TL, 0xCE4F3F),
JOG(RpfProductInfo.JG, 0xAC7D74),
TPC(RpfProductInfo.TP, 0xACCD10),
ONC(RpfProductInfo.ON, 0xFCCDE5),
JNC(RpfProductInfo.JN, 0x7386E5),
GNC(RpfProductInfo.GN, 0x55866B),
CIB10(RpfProductInfo.I1, 0x07516B),
CIB5(RpfProductInfo.I2, 0x071CE0),
MISC(RpfProductInfo.MM, 0xF2C921);
private RpfProductInfo rpi;
private int defaultColorInt;
DefaultColors(RpfProductInfo rpi, int defaultColorInt) {
this.rpi = rpi;
this.defaultColorInt = defaultColorInt;
}
static int getColorInt(RpfProductInfo rpi) {
for (DefaultColors dc : DefaultColors.values()) {
if (dc.rpi.equals(rpi)) {
return dc.defaultColorInt;
}
}
return MISC.defaultColorInt;
}
static Color getColor(RpfProductInfo rpi) {
return new Color(DefaultColors.getColorInt(rpi));
}
}
}