📄 scalefilterlayer.java
字号:
// **********************************************************************// // <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/ScaleFilterLayer.java,v $// $RCSfile: ScaleFilterLayer.java,v $// $Revision: 1.7.2.4 $// $Date: 2005/08/11 21:36:12 $// $Author: dietrick $// // **********************************************************************package com.bbn.openmap.layer;import java.awt.Component;import java.awt.Graphics;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.beans.PropertyVetoException;import java.beans.beancontext.BeanContext;import java.util.HashSet;import java.util.Iterator;import java.util.Properties;import java.util.StringTokenizer;import java.util.Vector;import javax.swing.JButton;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JTabbedPane;import javax.swing.OverlayLayout;import com.bbn.openmap.Layer;import com.bbn.openmap.MouseDelegator;import com.bbn.openmap.event.InfoDisplayEvent;import com.bbn.openmap.event.InfoDisplayListener;import com.bbn.openmap.event.LayerStatusEvent;import com.bbn.openmap.event.LayerStatusListener;import com.bbn.openmap.event.MapMouseListener;import com.bbn.openmap.event.MapMouseMode;import com.bbn.openmap.event.NavMouseMode;import com.bbn.openmap.event.NullMouseMode;import com.bbn.openmap.event.ProjectionEvent;import com.bbn.openmap.event.SelectMouseMode;import com.bbn.openmap.proj.Projection;import com.bbn.openmap.util.Debug;import com.bbn.openmap.util.PropUtils;/** * An OpenMap Layer that encapsulates other layers and acts as a scale * filter. It will delegate responsibility to one of several layers * depending on the scale. * <p> * To use this layer, list it as a layer in the openmap.properties * file in the openmap.layers properties, as you would add any other * layer. Then, add these properties to the openmap.properties file. * The layers added to the ScaleFilterLayer do not get added to the * openmap.layers property, but instead get added to the * scaledFilterLayer.layers property listed here. Then, the properties * for these layers are added to the openmap.properties file like any * other layer. <BR> * The properties for this layer look like this: <BR> * <BR> * <code><pre> * * ####################################### * # Properties for ScaleFilterLayer * ####################################### * scaledFilterLayer.class=com.bbn.openmap.layer.ScaleFilterLayer * scaledFilterLayer.prettyName=&ltPretty name used on menu&ge * # List 2 or more layers, larger scale layers first * scaledFilterLayer.layers=layer_1 layer_2 layer_3 ... * # List the transition scales to switch between layers * scaledFilterLayer.transitionScales= (transition scale from layer 1 to 2) (transition scale from layer 2 to 3) (...) * ####################################### * * </pre></code> */public class ScaleFilterLayer extends Layer implements InfoDisplayListener, LayerStatusListener, PropertyChangeListener, MapMouseListener { /** * The layers property. */ public final static transient String layersProperty = "layers"; /** * The transition scales property. */ public final static transient String transitionScalesProperty = "transitionScales"; /** * The layers. */ protected Vector layers; /** * The transition scales. */ protected float[] transitionScales; /** * The default transition scale. */ protected float defaultTransitionScale = 40000000f; /** * The index of the currently selected layer. */ protected int targetIndex = -1; /** * Initializes an empty layer. */ public ScaleFilterLayer() { setLayout(new OverlayLayout(this)); // To get MouseDelegator, to make decisions on receiving mouse // modes for child layers. setAddToBeanContext(true); } /** * Get the Vector holding the Layers. If it hasn't been asked for * yet, a new, empty Vector will be returned, one that will be * used internally. */ public Vector getLayers() { if (layers == null) { layers = new Vector(); } return layers; } /** * Get the transition scales used to set the active layer. */ public float[] getTransitionScales() { return transitionScales; } /** * Programmatic way to set layers and scales. There should be one * more layer on the list than there is scale in the float array. * Layers that should be displayed for larger scale numbers * (smaller scale) should be at the front of the Vector list, and * larger numbers should be at the front of the scale array. For * scale numbers larger than the first number in the array, the * first layer will be displayed. As the scale number decreases, * other layers will be displayed. * * @param list Vector of layers * @param scales Array of transition scales. */ public void setLayersAndScales(Vector list, float[] scales) { layers = list; transitionScales = scales; } /** * Initializes this layer from the given properties. * * @param props the <code>Properties</code> holding settings for * this layer */ public void setProperties(String prefix, Properties props) { super.setProperties(prefix, props); prefix = PropUtils.getScopedPropertyPrefix(prefix); parseLayers(prefix, props); parseScales(prefix, props); } public Properties getProperties(Properties props) { props = super.getProperties(props); String prefix = PropUtils.getScopedPropertyPrefix(this); float[] ts = getTransitionScales(); StringBuffer tsBuffer = new StringBuffer(); if (ts != null) { for (int i = 0; i < ts.length; i++) { tsBuffer.append(Float.toString(ts[i]) + " "); } } props.put(prefix + transitionScalesProperty, tsBuffer.toString()); StringBuffer layerBuffer = new StringBuffer(); for (Iterator it = getLayers().iterator(); it.hasNext();) { Layer layer = (Layer) it.next(); layerBuffer.append(layer.getPropertyPrefix() + " "); layer.getProperties(props); } props.put(prefix + layersProperty, layerBuffer.toString()); return props; } /** * Get the layer that's appropriate at the current scale. The * targetedIndex needs to be set before this is called. The * targetedIndex is the index to the layers array representing the * current layer. * * @return Layer */ public Layer getAppropriateLayer() { Vector target = getLayers(); if (target == null) { return SinkLayer.getSharedInstance(); } if ((targetIndex < 0) || (targetIndex > target.size())) { return SinkLayer.getSharedInstance(); } Layer l = (Layer) target.elementAt(targetIndex); return l; } /** * Create the Layers from a property value string. * * @param prefix String * @param props Properties */ protected void parseLayers(String prefix, Properties props) { String layersString = props.getProperty(prefix + layersProperty); Vector layers = getLayers(); if (layersString == null || layersString.equals("")) { Debug.error("ScaleFilterLayer(): null layersString!"); return; } StringTokenizer tok = new StringTokenizer(layersString); while (tok.hasMoreTokens()) { Object obj; String layerName = tok.nextToken(); String classProperty = layerName + ".class"; String className = props.getProperty(classProperty); if (className == null) { Debug.error("ScaleFilterLayer.parseLayers(): Failed to locate property \"" + classProperty + "\""); Debug.error("ScaleFilterLayer.parseLayers(): Skipping layer \"" + layerName + "\""); className = SinkLayer.class.getName(); } try { if (className.equals(SinkLayer.class.getName())) { obj = SinkLayer.getSharedInstance(); } else { obj = Class.forName(className).newInstance(); } if (Debug.debugging("ScaleFilterLayer")) { Debug.output("ScaleFilterLayer.parseLayers(): Instantiated " + className); } } catch (Exception e) { Debug.error("ScaleFilterLayer.parseLayers(): Failed to instantiate \"" + className + "\": " + e); obj = SinkLayer.getSharedInstance(); } // create the layer and set its properties if (obj instanceof Layer) { Layer l = (Layer) obj; l.setProperties(layerName, props); l.addLayerStatusListener(this); l.addInfoDisplayListener(this); layers.addElement(l); } } } /** * Create the transition scales from a property value string. If * there are N layers, there should be N-1 transition scales. * * @param prefix String * @param props Properties */ protected void parseScales(String prefix, Properties props) { StringTokenizer tok = null; Vector layers = getLayers(); int size = layers.size(); if (size > 0) { --size; } transitionScales = new float[size]; String scales = props.getProperty(prefix + transitionScalesProperty); if (scales == null) { Debug.error("ScaleFilterLayer.parseScales(): Failed to locate property \"" + transitionScalesProperty + "\""); if (transitionScales.length > 0) { transitionScales[0] = defaultTransitionScale; } for (int i = 1; i < transitionScales.length; i++) { transitionScales[i] = transitionScales[i - 1] / 3; } return; } try { tok = new StringTokenizer(scales); transitionScales[0] = (tok.hasMoreTokens()) ? new Float(tok.nextToken()).floatValue() : defaultTransitionScale; } catch (NumberFormatException e) { Debug.error("ScaleFilterLayer.parseScales()1: " + e); transitionScales[0] = defaultTransitionScale; } for (int i = 1; i < transitionScales.length; i++) { try { transitionScales[i] = (tok.hasMoreTokens()) ? new Float(tok.nextToken()).floatValue() : transitionScales[i - 1] / 3; } catch (NumberFormatException e) { Debug.error("ScaleFilterLayer.parseScales()2: " + e); transitionScales[i] = transitionScales[i - 1] / 3; } } } /** * Implementing the ProjectionPainter interface. */ public synchronized void renderDataForProjection(Projection proj, java.awt.Graphics g) { if (proj == null) { Debug.error("ScaleFilterLayer.renderDataForProjection: null projection!"); return; } else { setTargetIndex(proj.getScale()); Layer layer = getAppropriateLayer(); layer.renderDataForProjection(proj, g); } } /** * Calculate the index of the target layer. If there are N layers, * there are N-1 transitionScales. The ith layer is chosen if the * scale is greater than the ith transitionScale. * * @param scale the current map scale * @return true if the targetIndex has changed as a result of the * new scale. */ public boolean setTargetIndex(float scale) { boolean changed = false; float[] target = transitionScales; int i = 0; if (target != null) { for (i = 0; i < target.length; i++) { if (scale > target[i]) { break; } } } if (targetIndex != i) { changed = true; } targetIndex = i; if (Debug.debugging("scalefilterlayer")) { Debug.output("ScaleFilterLayer(" + getName() + ") targetIndex: " + targetIndex + ", changed: " + changed); } return changed; } /** * Handles projection change notification events. Throws out old * graphics, and requests new graphics from the spatial index * based on the bounding rectangle of the new * <code>Projection</code>. * * @param ev the new projection event */ public void projectionChanged(ProjectionEvent ev) { Projection proj = ev.getProjection(); Layer currentLayer = getAppropriateLayer(); boolean changed = setTargetIndex(proj.getScale()); // get the appropriate layer and invoke projectionChanged Layer layer = getAppropriateLayer(); if (changed) { currentLayer.removeNotify(); setPaletteTab(targetIndex); remove(currentLayer); // This will handle the repaint() requests from the // layer... add(layer); layer.addNotify(); checkMouseMode(); } fireStatusUpdate(LayerStatusEvent.START_WORKING); layer.projectionChanged(ev); } /** * Renders the scale-appropriate layer on the map. * * @param g a graphics context */ public void paint(Graphics g) { getAppropriateLayer().paint(g); fireStatusUpdate(LayerStatusEvent.FINISH_WORKING); } /** * Try to handle receiving LayerStatusEvents from child layers. * May not always work, depending on what thread sends/receives * this event - usually in the Swing thread, and the GUI can't
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -