// **********************************************************************
//
// <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/BufferedLayerMapBean.java,v $
// $RCSfile: BufferedLayerMapBean.java,v $
// $Revision: 1.6 $
// $Date: 2004/10/14 18:05:39 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap;
import java.awt.Color;
import java.awt.Component;
import java.awt.Paint;
import java.awt.event.ContainerEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.bbn.openmap.event.LayerEvent;
import com.bbn.openmap.layer.BufferedLayer;
/**
* The BufferedLayerMapBean is a BufferedMapBean with an additional image buffer
* that holds Layers designated as background layers. The additional image
* buffer is a BufferedLayer that this MapBean manages, and all background
* layers are added to the BufferedLayer, which is automatically added to the
* bottom of the map. When layers are added to the MapBean via the setLayers()
* method, the Layer.getAddAsBackground() flag is checked, and if that is true
* for a layer, it is added to the BufferedLayer. The background layers do not
* receive mouse events.
* <P>
*
* It should be cautioned that the appearance of the map may not match the layer
* stack as it is delivered to the MapBean because of this flag. If, for
* example, layers 1 and 4 are marked as background layers, while layers 2 and 3
* are not (in a 4 layer stack), then the map will show layers 2, 3, 1, 4, with
* layers 1 and 4 being displayed from the BufferedLayer. Something to think
* about when it comes to designing GUI elements.
*/
public class BufferedLayerMapBean extends BufferedMapBean {
private static Logger logger = Logger.getLogger(BufferedLayerMapBean.class.getName());
protected BufferedLayer bufferedLayer;
protected boolean DEBUG = false;
/**
* Construct a MapBean.
*/
public BufferedLayerMapBean() {
super();
DEBUG = logger.isLoggable(Level.FINE);
}
public BufferedLayerMapBean(boolean useThreadedNotification) {
super(useThreadedNotification);
DEBUG = logger.isLoggable(Level.FINE);
}
/**
* Set the background color of the map. Actually sets the background color
* of the projection, and calls repaint().
*
* @param color java.awt.Color.
*/
public void setBackgroundColor(Color color) {
super.setBackground(color);
getBufferedLayer().setBackground(color);
}
public void setBckgrnd(Paint paint) {
super.setBckgrnd(paint);
getBufferedLayer().setBckgrnd(paint);
}
public synchronized void setBufferedLayer(BufferedLayer bl) {
bufferedLayer = bl;
}
public synchronized BufferedLayer getBufferedLayer() {
if (bufferedLayer == null) {
bufferedLayer = new BufferedLayer();
addPropertyChangeListener(bufferedLayer);
bufferedLayer.setName("Background Layers");
}
return bufferedLayer;
}
/**
* Set the MapBeanRepaintPolicy used by the MapBean. This method is
* overridden in order to pass the policy on to the MapBean stored in the
* internal BufferedLayer.
*/
public void setMapBeanRepaintPolicy(MapBeanRepaintPolicy mbrp) {
super.setMapBeanRepaintPolicy(mbrp);
MapBean mb = getBufferedLayer().getMapBean();
if (mb != null) {
if (mbrp == null) {
mb.setMapBeanRepaintPolicy(mbrp);
} else {
MapBeanRepaintPolicy mbrp2 = (MapBeanRepaintPolicy) mbrp.clone();
mb.setMapBeanRepaintPolicy(mbrp2);
mbrp2.setMap(mb);
}
}
}
/**
* 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) {
logger.warning("layer[] is null!");
return;
}
boolean oldChange = getDoContainerChange();
setDoContainerChange(false);
BufferedLayer bufLayer;
synchronized (this) {
bufLayer = getBufferedLayer();
}
// use LayerEvent.REPLACE when you want to remove all current
// layers add a new set
if (type == LayerEvent.REPLACE) {
if (DEBUG) {
debugmsg("Replacing all layers");
}
removeAll();
bufLayer.clearLayers();
bufLayer.setProjection(getRotatedProjection());
for (Layer layer : layers) {
// @HACK is this cool?:
if (layer == null) {
logger.warning("skipping null layer in layer array passed to MapBean");
continue;
}
if (DEBUG) {
debugmsg("Adding layer[" + layer.getName() + "]");
}
if (layer.getAddAsBackground()) {
if (DEBUG) {
logger.fine("Adding layer[" + layer.getName() + "] to background");
}
bufLayer.addLayer(layer);
} else {
add(layer);
}
layer.setVisible(true);
}
if (bufLayer.hasLayers()) {
add(bufLayer);
}
}
// use LayerEvent.ADD when adding and/or reshuffling layers
else if (type == LayerEvent.ADD) {
remove(bufLayer);
if (DEBUG) {
debugmsg("Adding new layers");
}
for (Layer layer : layers) {
if (DEBUG) {
debugmsg("Adding layer[" + layer.getName() + "]");
}
layer.setVisible(true);
if (layer.getAddAsBackground()) {
if (DEBUG) {
debugmsg("Adding layer[" + layer.getName() + "] to background");
}
bufLayer.addLayer(layer);
} else {
add(layer);
}
}
if (bufLayer.hasLayers()) {
add(bufLayer);
}
}
// use LayerEvent.REMOVE when you want to delete layers from
// the map
else if (type == LayerEvent.REMOVE) {
if (DEBUG) {
debugmsg("Removing layers");
}
for (Layer layer : layers) {
if (DEBUG) {
debugmsg("Removing layer[" + layer.getName() + "]");
}
remove(layer);
bufLayer.removeLayer(layer);
}
}
if (!layerRemovalDelayed) {
purgeAndNotifyRemovedLayers();
}
setDoContainerChange(oldChange);
revalidate();
repaint();
}
/**
* In an effort to limit map flashing, the BufferedLayerMapBean consults the
* BufferedLayer to check that all background layers are ready to be painted
* after a projection change, before forwarding on all repaint requests.
*/
public void repaint(Layer layer) {
if (bufferedLayer == null || bufferedLayer.isReadyToPaint()) {
super.repaint(layer);
}
}
/**
* 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;
int nBufLayerComponents = 0;
BufferedLayer bufLayer;
synchronized (this) {
bufLayer = getBufferedLayer();
}
if (ncomponents == 0 || comps[ncomponents - 1] != bufLayer) {
super.changeLayers(e);
return;
}
Component[] bufLayers = bufLayer.getLayers();
nBufLayerComponents = bufLayers.length;
// Take 1 off for the bufLayer
Layer[] newLayers = new Layer[ncomponents + nBufLayerComponents - 1];
System.arraycopy(comps, 0, newLayers, 0, ncomponents - 1);
System.arraycopy(bufLayers, 0, newLayers, ncomponents - 1, nBufLayerComponents);
if (DEBUG) {
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;
}
/**
* Call when getting rid of the MapBean, it releases pointers to all
* listeners and kills the ProjectionSupport thread.
*/
public void dispose() {
if (bufferedLayer != null) {
bufferedLayer.dispose();
}
super.dispose();
}
}