// **********************************************************************
//
// <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/policy/StandardPCPolicy.java,v $
// $RCSfile: StandardPCPolicy.java,v $
// $Revision: 1.9 $
// $Date: 2006/05/19 16:44:57 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.policy;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.bbn.openmap.event.LayerStatusEvent;
import com.bbn.openmap.event.ProjectionEvent;
import com.bbn.openmap.layer.OMGraphicHandlerLayer;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
/**
* ProjectionChangePolicy that uses a Layer SwingWorker to kick off a thread to
* call layer.prepare() and doesn't delete the OMGraphicList between projection
* changes. The standard behavior for simple layers that maintain a constant
* list of OMGraphics.
*/
public class StandardPCPolicy extends AbstractProjectionChangePolicy {
/**
* The number of OMGraphics that have to be on the layer's OMGraphicList
* before a thread is spawned. The default is 50;
*/
protected int graphicCutoff = 50;
/**
* A flag to tell the policy to always spawn a thread.
*/
protected boolean alwaysSpawnThread = false;
/**
* You must set a layer at some point before using this class.
*/
public StandardPCPolicy() {
}
/**
* Don't pass in a null layer.
*/
public StandardPCPolicy(OMGraphicHandlerLayer layer) {
this(layer, true);
}
/**
* Don't pass in a null layer.
*
* @param layer layer to work for
* @param alwaysSpawnThreadForPrepare should be true if the layer's prepare
* method takes a while. Normally, the policy looks at the number of
* OMGraphics on the list to determine if a thread should be spawned.
* True by default.
*/
public StandardPCPolicy(OMGraphicHandlerLayer layer, boolean alwaysSpawnThreadForPrepare) {
setLayer(layer);
setAlwaysSpawnThread(alwaysSpawnThreadForPrepare);
}
/**
* Tell the policy whether to spawn a thread when projectionChanged() is
* called with a new projection.
*
* @param val setting for always spawning thread for every projection
* change.
*/
public void setAlwaysSpawnThread(boolean val) {
alwaysSpawnThread = val;
}
public boolean getAlwaysSpawnThread() {
return alwaysSpawnThread;
}
/**
* When the projection changes, the StandardPCPolicy sets the current
* projection on the layer, and calls prepare() on the layer. repaint() will
* be automatically called. This method does not generate the OMGraphics in
* the list. The layer is still expected to do that in prepare(), as well as
* return that list from prepare.
* <P>
* If a Layer is using this PC policy, then it's kind of assumed that the
* layer is setting the list and generating the same list over and over
* again with the new projection. So, when we look at the min and max scales
* set on the layer, we don't want to clear out that list if the projection
* scale is outside of the acceptable range of good projection scales.
* Instead, we want to skip the prepare() method call as to not waste CPU
* cycles generating things we won't see, and let the RenderPolicy check to
* see if the list should be painted.
*
* @param pe The ProjectionEvent received from the MapBean.
*/
public void projectionChanged(ProjectionEvent pe) {
Logger logger = getLogger();
if (layer != null) {
Projection proj = layer.setProjection(pe);
// proj will be null if the projection hasn't changed, a
// signal that work does not need to be done.
if (proj != null) {
// Some criteria can decide whether
// starting another thread is worth it...
if (shouldSpawnThreadForPrepare()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(getLayer().getName()
+ ": StandardPCPolicy projectionChanged with NEW projection, spawning thread to handle it.");
}
if (layer.isProjectionOK(proj)) {
layer.doPrepare();
}
return;
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine(getLayer().getName()
+ ": StandardPCPolicy projectionChanged with NEW projection, handling it within current thread.");
}
layer.fireStatusUpdate(LayerStatusEvent.START_WORKING);
if (layer.isProjectionOK(proj)) {
layer.setList(layer.prepare());
}
layer.repaint();
}
} else {
layer.repaint();
}
layer.fireStatusUpdate(LayerStatusEvent.FINISH_WORKING);
} else {
Debug.error("StandardPCPolicy.projectionChanged(): NULL layer, can't do anything.");
}
}
/**
* We're assuming that the list is somewhat constant for the layer. If the
* number of OMGraphics on the layer's list is more than the cutoff number,
* a thread should be launched to generate them with the new projection. You
* can extend this method so that different criteria may be considered.
*
* @return true of thread should always be spawned.
*/
protected boolean shouldSpawnThreadForPrepare() {
if (layer != null && !alwaysSpawnThread) {
OMGraphicList list = layer.getList();
if (list != null) {
return layer.getList().size() > graphicCutoff;
}
}
// If we have to create a list, might as well assume that
// is should be done in a new thread.
return true;
}
/**
* @param number Set the number of OMGraphics that have to be on the list
* before a thread gets spawned to call generate() on them.
*/
public void setGraphicCutoff(int number) {
graphicCutoff = number;
}
public int getGraphicCutoff() {
return graphicCutoff;
}
// <editor-fold defaultstate="collapsed" desc="Logger Code">
/**
* Holder for this class's Logger. This allows for lazy initialization of
* the logger.
*/
private static final class LoggerHolder {
/**
* The logger for this class
*/
private static final Logger LOGGER = Logger.getLogger(StandardPCPolicy.class.getName());
/**
* Prevent instantiation
*/
private LoggerHolder() {
throw new AssertionError("This should never be instantiated");
}
}
/**
* Get the logger for this class.
*
* @return logger for this class
*/
private static Logger getLogger() {
return LoggerHolder.LOGGER;
}
// </editor-fold>
}