// **********************************************************************
//
// <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/RpfLayer.java,v $
// $RCSfile: RpfLayer.java,v $
// $Revision: 1.23 $
// $Date: 2008/09/17 20:47:51 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.rpf;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
/* Java Core */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import com.bbn.openmap.I18n;
import com.bbn.openmap.event.SelectMouseMode;
import com.bbn.openmap.layer.OMGraphicHandlerLayer;
import com.bbn.openmap.layer.policy.ListResetPCPolicy;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMList;
import com.bbn.openmap.omGraphics.OMRaster;
import com.bbn.openmap.omGraphics.event.MapMouseInterpreter;
import com.bbn.openmap.proj.EqualArc;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.PropUtils;
import com.bbn.openmap.util.cacheHandler.CacheHandler;
/**
* The RpfLayer fills the screen with RPF data. There is also a tool available
* that allows you to see the coverage of the available data. To view theimages,
* the projection of the map has to be set in the ARC projection, which OpenMap
* calls the CADRG projection. The RpfLayer can use several RPF directories at
* the same time, and doesn't require that the data actually be there at
* runtime. That way, you can give a location where the data may be mouted
* during runtime(i.e. CDROM) and the layer will still use the data. The scale
* of the projection does not necessarily have to match the scale of a map
* series for that series to be displayed. There are options, set in the
* RpfViewAttributes, that allow scaling of the RPF images to match the map
* scale.
* <P>
*
* The RpfLayer uses the RpfCacheManager to get the images it needs to display.
* Whenever the projection changes, the cache manager takes the new projection
* and creates a OMGraphicList with the new image frames and attribute text.
* <P>
*
* The RpfLayer gets its initial settings from properties. This should be done
* right after the RpfLayer is created. The properties list contains the
* location of the RPF directories, the opaqueness of the images, the number of
* colors to use, and whether to show the images and/or attributes by default.
* An example of the RpfLayer properties:
* <P>
*
* <pre>
*
*
* #-----------------------------
* # Properties for RpfLayer
* #-----------------------------
* # Mandatory properties
* # This property should reflect the paths to the RPF directories
* rpf.paths=/usr/local/matt/data/RPF;/usr/local/matt/data/CIB/RPF
*
* # Optional Properties - the default will be set if these are not
* # included in the properties file:
* # Number between 0-255: 0 is transparent, 255 is opaque. 255 is default.
* rpf.opaque=128
*
* # Number of colors to use on the maps - 16, 32, 216. 216 is default.
* rpf.numberColors=216
*
* # Display maps on startup. Default is true.
* rpf.showMaps=true
*
* # Display attribute information on startup. Default is false.
* rpf.showInfo=false
*
* # Scale charts to match display scale. Default is true.
* rpf.scaleImages=true
*
* # The scale factor to allow when scaling images (2x, 4x, also mean 1/2, 1/4). Default is 4.
* rpf.imageScaleFactor=4
*
* # Delete the cache if the layer is removed from the map. Default is false.
* rpf.killCache=true
* # Limit the display to the chart code specified. (GN, JN, ON, TP, etc.).
* # Default is ANY
* rpf.chartSeries=ANY
* # Get the subframe attribute data from the Frame provider.
* rpf.autofetchAttributes=false
* # Set to true if you want the coverage tool available.
* rpf.coverage=true
* # Set the subframe cache size. (Number of subframes to hold on to, 256x256 pixels)
* rpf.subframeCacheSize=128
* # Then also include coverage properties, which are available in the RpfConstants.
* #------------------------------------
* # End of properties for RpfLayer
* #------------------------------------
*
*
* </pre>
*
*/
public class RpfLayer extends OMGraphicHandlerLayer implements ActionListener, RpfConstants, Serializable {
protected static Logger logger = Logger.getLogger("com.bbn.openmap.layer.rpf.RpfLayer");
protected static Logger rpfLogger = Logger.getLogger("RPF");
private static final long serialVersionUID = 1L;
/**
* The main source for the images and attribute information. All requests
* for graphic objects should go through this cache, and it will
* automatically handle getting the frame files, decoding them, and
* returning an object list.
*/
protected transient RpfCacheManager cache = null;
/** The paths to the RPF directories, telling where the data is. */
protected String[] paths;
/**
* The display attributes for the maps. This object should not be replaced,
* because the caches all look at it, too. Just adjust the parameters within
* it.
*
* @see RpfViewAttributes
*/
protected RpfViewAttributes viewAttributes;
/** Flag to delete the cache if the layer is removed from the map. */
protected boolean killCache = true;
/** The supplier of frame data. */
protected RpfFrameProvider frameProvider;
/** The coverage tool for the layer. */
protected RpfCoverage coverage;
/** Subframe cache size. Default is 40. */
protected int subframeCacheSize = RpfCacheHandler.SUBFRAME_CACHE_SIZE;
/** Auxiliary subframe cache size. Default is 10. */
protected int auxSubframeCacheSize = RpfCacheManager.SMALL_CACHE_SIZE;
/**
* The default constructor for the Layer. All of the attributes are set to
* their default values. Use this construct if you are going to use a
* standard properties file, which will set the paths.
*/
public RpfLayer() {
setName("RPF");
viewAttributes = new RpfViewAttributes();
setProjectionChangePolicy(new ListResetPCPolicy(this));
// setRenderPolicy(new BufferedImageRenderPolicy(this));
setMouseModeIDsForEvents(new String[] { SelectMouseMode.modeID });
showSubframes(false);
}
/**
* The default constructor for the Layer. All of the attributes are set to
* their default values.
*
* @param pathsToRPFDirs
* paths to the RPF directories that hold A.TOC files.
*/
public RpfLayer(String[] pathsToRPFDirs) {
this();
setPaths(pathsToRPFDirs);
}
/**
* Set the paths to the RPF directories, which are by default the parents of
* the A.TOC table of contents files. Creates the RpfFrameProvider.
*
* @param pathsToRPFDirs
* Array of strings that list the paths to RPF directories.
*/
public void setPaths(String[] pathsToRPFDirs) {
if (paths != null && pathsToRPFDirs != null && paths.length == pathsToRPFDirs.length) {
// If the paths haven't changed, don't do anything.
boolean same = true;
for (int i = 0; i < paths.length; i++) {
same = same && paths[i].equals(pathsToRPFDirs[i]);
}
if (same && frameProvider != null) {
return;
}
}
if (pathsToRPFDirs != null) {
setFrameProvider(new RpfFrameCacheHandler(pathsToRPFDirs));
} else {
logger.warning("Need RPF directory paths.");
frameProvider = null;
}
paths = pathsToRPFDirs;
setCoverage(new RpfCoverage(this, frameProvider));
this.cache = null;
}
/**
* Get the paths to the RPF directories.
*
* @return String[]
*/
public String[] getPaths() {
return paths;
}
/**
* Called when the layer is no longer part of the map. In this case, we
* should disconnect from the server if we have a link.
*/
public void removed(java.awt.Container cont) {
if (killCache) {
rpfLogger.fine("emptying cache!");
clearCache();
}
// need to reset this for when it gets added again, if it was
// removed without the projection actually changing. This
// helps when the cache needs to be rebuilt.
setProjection((Projection) null);
}
protected void setDefaultValues() {
// defaults
paths = null;
}
/**
* Set all the RPF properties from a properties object.
*/
public void setProperties(String prefix, java.util.Properties properties) {
super.setProperties(prefix, properties);
prefix = PropUtils.getScopedPropertyPrefix(prefix);
setPaths(PropUtils.initPathsFromProperties(properties, prefix + RpfPathsProperty, paths));
viewAttributes.setProperties(prefix, properties);
showSubframes(viewAttributes.showInfo);
subframeCacheSize = PropUtils.intFromProperties(properties, prefix + CacheSizeProperty, subframeCacheSize);
auxSubframeCacheSize = PropUtils.intFromProperties(properties, prefix + CacheSizeProperty,
auxSubframeCacheSize);
if (viewAttributes.chartSeries == null)
viewAttributes.chartSeries = RpfViewAttributes.ANY;
killCache = PropUtils.booleanFromProperties(properties, prefix + KillCacheProperty, killCache);
if (coverage != null) {
coverage.setProperties(prefix, properties);
}
resetPalette();
}
/**
* 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) {
props = super.getProperties(props);
String prefix = PropUtils.getScopedPropertyPrefix(this);
// find out paths...
String[] p = getPaths();
StringBuffer pathString = new StringBuffer();
if (p != null) {
for (int i = 0; i < p.length; i++) {
if (p[i] != null) {
pathString.append(p[i]);
if (i < p.length - 1) {
pathString.append(";"); // separate paths with
// ;
}
}
}
props.put(prefix + RpfPathsProperty, pathString.toString());
} else {
props.put(prefix + RpfPathsProperty, "");
}
props.put(prefix + KillCacheProperty, new Boolean(killCache).toString());
props.put(prefix + CacheSizeProperty, Integer.toString(subframeCacheSize));
props.put(prefix + AuxCacheSizeProperty, Integer.toString(auxSubframeCacheSize));
viewAttributes.setPropertyPrefix(prefix);
viewAttributes.getProperties(props);
if (coverage == null) {
RpfCoverage cov = new RpfCoverage(this, frameProvider);
cov.setProperties(prefix, new Properties());
cov.getProperties(props);
} else {
coverage.getProperties(props);
}
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) {
list = super.getPropertyInfo(list);
String interString;
interString = i18n.get(RpfLayer.class, RpfPathsProperty, I18n.TOOLTIP,
"Paths to RPF directories. Semi-colon separated paths.");
list.put(RpfPathsProperty, interString);
list.put(RpfPathsProperty + ScopedEditorProperty,
"com.bbn.openmap.util.propertyEditor.MultiDirectoryPropertyEditor");
interString = i18n.get(RpfLayer.class, RpfPathsProperty, "Data Path");
list.put(RpfPathsProperty + LabelEditorProperty, interString);
interString = i18n.get(RpfLayer.class, KillCacheProperty, I18n.TOOLTIP,
"Flag to trigger the cache to be cleared when layer is removed from the map.");
list.put(KillCacheProperty, interString);
list.put(KillCacheProperty + ScopedEditorProperty, "com.bbn.openmap.util.propertyEditor.OnOffPropertyEditor");
interString = i18n.get(RpfLayer.class, KillCacheProperty, "Clear Cache");
list.put(KillCacheProperty + LabelEditorProperty, interString);
interString = i18n.get(RpfLayer.class, CacheSizeProperty, I18n.TOOLTIP,
"Number of frames to hold in the frame cache.");
list.put(CacheSizeProperty, interString);
interString = i18n.get(RpfLayer.class, CacheSizeProperty, "Frame Cache Size");
list.put(CacheSizeProperty + LabelEditorProperty, interString);
interString = i18n.get(RpfLayer.class, AuxCacheSizeProperty, I18n.TOOLTIP,
"Number of frames to hold in aux. frame caches.");
list.put(AuxCacheSizeProperty, interString);
interString = i18n.get(RpfLayer.class, AuxCacheSizeProperty, "Aux Frame Cache Size");
list.put(AuxCacheSizeProperty + LabelEditorProperty, interString);
viewAttributes.getPropertyInfo(list);
RpfCoverage tmpCov = coverage;
if (tmpCov == null) {
tmpCov = new RpfCoverage(this, frameProvider);
}
tmpCov.getPropertyInfo(list);
list.put(initPropertiesProperty,
RpfPathsProperty + " " + KillCacheProperty + " " + CacheSizeProperty + " " + AuxCacheSizeProperty + " "
+ viewAttributes.getInitPropertiesOrder() + " " + AddToBeanContextProperty + " "
+ AddAsBackgroundProperty + " " + RemovableProperty + " " + CoverageProperty + " "
+ tmpCov.getInitPropertiesOrder());
return list;
}
public void resetPalette() {
box = null;
// if (coverage != null) {
// if (coverage.isInUse()) {
// coverage.resetColors();
// }
// }
super.resetPalette();
}
/**
* Clear the frame cache.
*/
public void clearCache() {
if (frameProvider instanceof CacheHandler) {
((CacheHandler) frameProvider).resetCache();
}
if (this.cache != null) {
this.cache.setViewAttributes(null);
this.cache.setFrameProvider(null);
this.cache.clearCaches();
}
frameProvider = null;
setList(null);
this.cache = null;
}
/**
* Set the view attributes for the layer. The frame provider view attributes
* are updated, and the cache is cleared.
*
* @param rva
* the RpfViewAttributes used for the layer.
*/
public void setViewAttributes(RpfViewAttributes rva) {
viewAttributes = rva;
if (this.cache != null) {
this.cache.setViewAttributes(rva);
}
}
/**
* Get the view attributes or the layer.
*
* @return RpfViewAttributes.
*/
public RpfViewAttributes getViewAttributes() {
return viewAttributes;
}
/**
* Set the RpfCoverage tool used by the layer. If the view attributes chart
* series setting is not equal to RpfViewAttributes.ANY, then the palette of
* the tool is not shown.
*
* @param cov
* the RpfCoverage tool.
*/
public void setCoverage(RpfCoverage cov) {
coverage = cov;
if (coverage != null) {
if (viewAttributes != null && !viewAttributes.chartSeries.equalsIgnoreCase(RpfViewAttributes.ANY)) {
coverage.setShowPalette(false);
}
coverage.coverageManager = null;
}
}
/**
* Return the coverage tool used by the layer.
*
* @return RpfCoverage tool.
*/
public RpfCoverage getCoverage() {
return coverage;
}
/**
* Set the RpfFrameProvider for the layer. Clears out the cache, and the
* frame provider gets the RpfViewAttributes held by the layer.
*
* @param fp
* the frame provider.
*/
public void setFrameProvider(RpfFrameProvider fp) {
frameProvider = fp;
if (this.cache != null) {
this.cache.setFrameProvider(frameProvider);
}
}
/**
* Return RpfFrameProvider used by the layer.
*/
public RpfFrameProvider getFrameProvider() {
return frameProvider;
}
/**
* Returns the Vector containing RpfCoverageBoxes that was returned from the
* RpfFrameProvider as a result of the last setCache call. These provide
* rudimentary knowledge about what is being displayed. This vector is from
* the primary cache handler.
*
* @return Vector of RpfCoverageBoxes.
*/
public List<RpfCoverageBox> getCoverageBoxes() {
return this.cache.getCoverageBoxes();
}
/**
* Prepares the graphics for the layer. This is where the getRectangle()
* method call is made on the rpf.
* <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.
*
* @return graphics list of images and attributes.
*/
public synchronized OMGraphicList prepare() {
Projection projection = getProjection();
OMGraphicList retList = new OMGraphicList();
retList.setTraverseMode(OMList.FIRST_ADDED_ON_TOP);
if (frameProvider == null) {
// Assuming running locally - otherwise the
// frameProvider should be set before we get here,
// like in setProperties or in the constructor.
setPaths(paths);
if (frameProvider == null) {
// Doh! no paths were set!
logger.warning(getName()
+ ": null frame provider - either no RPF paths were set, or no frame provider was assigned. The RpfLayer has no way to get RPF data.");
return retList;
}
}
if (coverage != null && coverage.isInUse()) {
coverage.prepare(projection, viewAttributes.chartSeries);
retList.add(coverage);
}
// Check the current minScale and maxScale set on the layer, ignore if
// projection scale is out of range.
if (!isProjectionOK(projection)) {
return retList;
}
if (this.cache == null) {
rpfLogger.fine(getName() + ": Creating cache!");
this.cache = new RpfCacheManager(frameProvider, viewAttributes, subframeCacheSize, auxSubframeCacheSize);
}
// Check to make sure the projection is CADRG
if (!(projection instanceof EqualArc) && (viewAttributes.showMaps || viewAttributes.showInfo)) {
// fireRequestInfoLine("RpfLayer runs faster with an Equal Arc
// projection (CADRG/LLXY).");
}
rpfLogger.fine(getName() + " 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.
// call getRectangle();
if (rpfLogger.isLoggable(Level.FINE)) {
rpfLogger.fine(getName() + "calling getRectangle " + " with projection: " + projection + " ul = "
+ projection.getUpperLeft() + " lr = " + projection.getLowerRight());
}
if (frameProvider.needViewAttributeUpdates()) {
frameProvider.setViewAttributes(viewAttributes);
}
try {
// OMGraphics are generated by the RpfCacheHandlers when fetched
retList.addAll(this.cache.getRectangle(projection));
if (logger.isLoggable(Level.FINE)) {
logger.fine(getName() + ": finished with " + retList.size() + " graphics");
}
} catch (java.lang.NullPointerException npe) {
logger.warning(getName() + ": Something really bad happened - \n " + npe);
npe.printStackTrace();
retList = new OMGraphicList();
this.cache = null;
}
return retList;
}
public boolean isHighlightable(OMGraphic omg) {
return viewAttributes.showInfo && omg instanceof OMRaster && omg.isSelected();
}
public String getToolTipTextFor(OMGraphic omg) {
return (String) omg.getAttribute(OMGraphic.TOOLTIP);
}
/**
* Overridden to do nothing because we want nothing to happen.
*/
public void highlight(OMGraphic omg) {
}
/**
* Overridden to do nothing because we want nothing to happen.
*/
public void unhighlight(OMGraphic omg) {
}
// ----------------------------------------------------------------------
// GUI
// ----------------------------------------------------------------------
private transient JPanel box = null;
/**
* 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() {
if (box == null) {
JCheckBox showInfoCheck, lockSeriesCheck;
box = new JPanel();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
box.setLayout(gridbag);
c.anchor = GridBagConstraints.NORTHWEST;
c.gridx = GridBagConstraints.REMAINDER;
showInfoCheck = new JCheckBox("Show Attributes", viewAttributes.showInfo);
showInfoCheck.setActionCommand(showInfoCommand);
showInfoCheck.addActionListener(this);
String tmpCS = viewAttributes.chartSeries;
if (tmpCS == null) {
tmpCS = RpfViewAttributes.ANY;
}
boolean locked = !tmpCS.equalsIgnoreCase(RpfViewAttributes.ANY);
String lockedTitle = locked ? (lockedButtonTitle + " - " + tmpCS) : unlockedButtonTitle;
lockSeriesCheck = new JCheckBox(lockedTitle, locked);
lockSeriesCheck.setActionCommand(lockSeriesCommand);
lockSeriesCheck.addActionListener(this);
// box1.add(showMapsCheck);
gridbag.setConstraints(showInfoCheck, c);
box.add(showInfoCheck);
gridbag.setConstraints(lockSeriesCheck, c);
box.add(lockSeriesCheck);
if (coverage != null) {
JCheckBox showCoverageCheck = new JCheckBox("Show Coverage", coverage.isInUse());
showCoverageCheck.setActionCommand(showCoverageCommand);
showCoverageCheck.addActionListener(this);
gridbag.setConstraints(showCoverageCheck, c);
box.add(showCoverageCheck);
}
JPanel layerStuff = getDefaultSettingsPanel(RpfLayer.class, viewAttributes.opaqueness / 255f);
gridbag.setConstraints(layerStuff, c);
box.add(layerStuff);
}
return box;
}
// ----------------------------------------------------------------------
// ActionListener interface implementation
// ----------------------------------------------------------------------
/**
* The Action Listener method, that reacts to the palette widgets actions.
*/
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
String cmd = e.getActionCommand();
if (cmd == showMapsCommand) {
JCheckBox mapCheck = (JCheckBox) e.getSource();
viewAttributes.showMaps = mapCheck.isSelected();
repaint();
} else if (cmd == showInfoCommand) {
JCheckBox infoCheck = (JCheckBox) e.getSource();
boolean showInfo = infoCheck.isSelected();
viewAttributes.showInfo = showInfo;
showSubframes(showInfo);
doPrepare();
} else if (cmd == lockSeriesCommand) {
JCheckBox lockCheck = (JCheckBox) e.getSource();
boolean locked = lockCheck.isSelected();
if (locked) {
List<RpfCoverageBox> coverageBoxes = getCoverageBoxes();
String seriesName;
if (coverageBoxes == null || coverageBoxes.isEmpty()) {
seriesName = RpfViewAttributes.ANY;
} else {
seriesName = coverageBoxes.get(0).chartCode;
}
if (seriesName == null) {
seriesName = RpfViewAttributes.ANY;
fireRequestMessage("The " + getName()
+ " Layer is having trouble determining what kind\nof charts are being displayed. Can't establish lock for charts\ncurrently being viewed.");
}
lockCheck.setText(lockedButtonTitle + " - " + seriesName);
viewAttributes.chartSeries = seriesName;
} else {
lockCheck.setText(unlockedButtonTitle);
viewAttributes.chartSeries = RpfViewAttributes.ANY;
}
} else if (cmd == showCoverageCommand) {
if (coverage != null) {
JCheckBox coverageCheck = (JCheckBox) e.getSource();
coverage.setInUse(coverageCheck.isSelected());
doPrepare();
}
} else {
// logger.warning("RpfLayer: Unknown action command \"" + cmd
// +
// "\" in RpfLayer.actionPerformed().");
// OK, not really sure what happened, just act like a
// reset.
doPrepare();
}
}
protected void showSubframes(boolean show) {
OMGraphicList list = getList();
if (list != null) {
list.setSelected(show);
}
MapMouseInterpreter mmi = getMouseEventInterpreter();
if (mmi != null) {
mmi.setActive(show);
}
}
/** Print out the contents of a properties file. */
public static void main(String[] argv) {
System.out.println("#########################################");
System.out.println("# Properties for the JAVA RpfLayer");
System.out.println("# Mandatory properties:");
System.out.println("layer.class=com.bbn.openmap.layer.rpf.RpfLayer");
System.out.println("layer.prettyName=CADRG");
System.out.println("# This property should reflect the paths to the RPF directories");
System.out.println("layer.paths=<Path to RPF dir>;/cdrom/cdrom0/RPF");
System.out.println(
"# Optional properties - Defaults will be set for properties not included (defaults are listed):");
System.out.println("# Number between 0-255: 0 is transparent, 255 is opaque");
System.out.println("layer.opaque=255");
System.out.println("# Number of colors to use on the maps - 16, 32, 216");
System.out.println("layer.numberColors=216");
System.out.println("# Display maps on startup");
System.out.println("layer.showMaps=true");
System.out.println("# Display attribute information on startup");
System.out.println("layer.showInfo=false");
System.out.println("# Scale images to match map scale");
System.out.println("layer.scaleImages=true");
System.out.println(
"# The scale factor to allow when scaling images (2x, 4x, also mean 1/2, 1/4). Default is 4.");
System.out.println("rpf.imageScaleFactor=4");
System.out.println("# Reset the cache if layer is removed from map");
System.out.println("layer.killCache=false");
System.out.println("# Limit the display to the chart code specified. (GN, JN, ON, TP, etc.)");
System.out.println("layer.chartSeries=ANY");
System.out.println("# Set the subframe cache size. (Number of subframes to hold on to, 256x256 pixels");
System.out.println("layer.subframeCacheSize=128");
System.out.println("# Get the subframe attribute data from the frame provider.");
System.out.println("rpf.autofetchAttributes=false");
System.out.println("#If you want the coverage tool to be available");
System.out.println("layer.coverage=true");
System.out.println("#Then add coverage constants as needed.");
}
}