// ********************************************************************** // // <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/graphicLoader/scenario/EventLayer.java,v $ // $RCSfile: EventLayer.java,v $ // $Revision: 1.9 $ // $Date: 2006/03/06 16:13:59 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.layer.event; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import com.bbn.openmap.PropertyConsumer; import com.bbn.openmap.event.OMEvent; import com.bbn.openmap.event.OMEventHandler; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.time.TemporalOMGraphicList; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.time.RealTimeHandler; import com.bbn.openmap.time.TimeBounds; import com.bbn.openmap.time.TimeBoundsHandler; import com.bbn.openmap.time.TimeBoundsProvider; import com.bbn.openmap.time.TimeEvent; import com.bbn.openmap.time.TimeEventListener; import com.bbn.openmap.util.ComponentFactory; import com.bbn.openmap.util.DataBounds; import com.bbn.openmap.util.DataBoundsProvider; import com.bbn.openmap.util.PropUtils; /** * The EventLayer contains all the TemporalOMGraphics and manages the time for * the graphics and how they should be displayed. This layer works as a * TimeBoundsProvider (an object that provides an active range of time, a * OMEventHandler (an object that provides OMEvents to the * EventPanel/EventPresenter), and a TimeEventListener (an object that changes * when the cloc changes). * <p> * * Sample properties: * * <pre> * eventLayer.class=com.bbn.openmap.layer.time.EventLayer * eventLayer.importer=com.bbn.openmap.layer.time.CSVEventImporter * eventLayer.prettyName=Test Event * * ... see CSVEventImporter for its properties, other importers can be specified here. * </pre> */ public class EventLayer extends OMGraphicHandlerLayer implements DataBoundsProvider, TimeBoundsProvider, TimeEventListener, OMEventHandler { public static Logger logger = Logger.getLogger("com.bbn.openmap.layer.event.EventLayer"); public final static String ImporterProperty = "importer"; protected EventImporter importer = null; protected DataBounds dataBounds = null; protected TimeBounds timeBounds; protected long time; protected String mode; protected boolean active = false; public EventLayer() { dataBounds = new DataBounds(); } /** * The main method call in the EventLayer that actually modifies the * OMGraphics and updates the map. */ public synchronized OMGraphicList prepare() { Projection p = getProjection(); TemporalOMGraphicList scenarioGraphics = null; OMGraphicList list = getList(); // Need this check in here because the time stuff might cause this to be // called before the layer is actually added to the map. if (p != null) { boolean DEBUG = logger.isLoggable(Level.FINE); if (list == null || !(list instanceof TemporalOMGraphicList)) { scenarioGraphics = createData(); if (scenarioGraphics == null) { // Don't do anything return null; } // The data importer should have set the time bounds, and that // should be calling this then. // callForTimeBoundsReset(); } else { scenarioGraphics = new TemporalOMGraphicList(list); } long currentTime = getTime(); if (DEBUG) { logger.fine("EventLayer (" + getName() + ") snapshot at " + currentTime); } scenarioGraphics.generate(p, currentTime); if (DEBUG) { logger.fine("EventLayer (" + getName() + ") setting list of " + scenarioGraphics.size() + " scenario graphics"); } } return scenarioGraphics; } /** * Read the data files and construct the TemporalOMGraphics. */ public synchronized TemporalOMGraphicList createData() { if (importer != null) { return importer.createData(this); } else { return null; } } /** * The properties and prefix are managed and decoded here, for the standard * uses of the EventLayer. * * @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, Properties properties) { super.setProperties(prefix, properties); prefix = PropUtils.getScopedPropertyPrefix(prefix); String importerClass = properties.getProperty(prefix + ImporterProperty); if (importerClass != null) { importer = (EventImporter) ComponentFactory.create(importerClass, prefix, properties); } } /** * 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. * @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); if (importer != null) { props.put(prefix + ImporterProperty, importer.getClass().getName()); } if (importer instanceof PropertyConsumer) { ((PropertyConsumer) importer).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.). This method takes care of the basic * LocationHandler parameters, so any LocationHandlers that extend the * AbstractLocationHandler should call this method, too, before adding any * specific properties. * * @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); PropUtils.setI18NPropertyInfo(i18n, list, getClass(), ImporterProperty, "Data Importer", "Class name of data importer", null); if (importer instanceof PropertyConsumer) { ((PropertyConsumer) importer).getPropertyInfo(list); } return list; } public String getMode() { return mode; } public void setMode(String mode) { this.mode = mode; } /** * DataBoundsProvider method. */ public DataBounds getDataBounds() { return dataBounds; } public void findAndInit(Object someObj) { super.findAndInit(someObj); if (someObj instanceof TimeBoundsHandler) { addTimeBoundsHandler((TimeBoundsHandler) someObj); } if (someObj instanceof RealTimeHandler) { ((RealTimeHandler) someObj).addTimeEventListener(this); } } // TimeBoundsProvider methods. protected List<TimeBoundsHandler> timeBoundsHandlers = new ArrayList<TimeBoundsHandler>(); public void addTimeBoundsHandler(TimeBoundsHandler tbh) { logger.fine("found TimeBoundsHandler: " + tbh.getClass().getName()); timeBoundsHandlers.add(tbh); } protected void setTimeBounds(TimeBounds tb) { timeBounds = tb; if (active) { callForTimeBoundsReset(); } } public TimeBounds getTimeBounds() { if (active) { return timeBounds; } return null; } public void handleTimeBounds(TimeBounds tb) { // NoOp, we don't really care what the current time bounds are } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; if (timeBounds != null) { callForTimeBoundsReset(); } } public void removeTimeBoundsHandler(TimeBoundsHandler tbh) { timeBoundsHandlers.remove(tbh); } public void updateTime(TimeEvent te) { time = te.getSystemTime(); if (active) { setList(prepare()); repaint(); } } public long getTime() { return time; } protected LinkedList<OMEvent> events = new LinkedList<OMEvent>(); protected LinkedList<OMEvent> filters = new LinkedList<OMEvent>(); public List<OMEvent> getEventList() { return getEventList(null); } public List<OMEvent> getEventList(List filters) { if (active) { return events; } return null; } public Boolean getFilterState(String filterName) { return (isVisible() ? Boolean.TRUE : Boolean.FALSE); } public List getFilters() { return filters; } public List<OMEvent> getMacroFilteredList(Collection eventCollection) { return events; } public void setFilterState(String filterName, Boolean state) {} public void callForTimeBoundsReset() { for (TimeBoundsHandler tbh : timeBoundsHandlers) { tbh.resetTimeBounds(); } } public void setVisible(boolean setting) { super.setVisible(setting); setActive(setting); } }