// **********************************************************************
//
// <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/gui/GoToMenu.java,v $
// $RCSfile: GoToMenu.java,v $
// $Revision: 1.20 $
// $Date: 2008/01/29 22:04:13 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.gui;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import com.bbn.openmap.MapBean;
import com.bbn.openmap.gui.menu.DataBoundsViewMenuItem;
import com.bbn.openmap.gui.menu.OMBasicMenu;
import com.bbn.openmap.proj.Mercator;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.proj.ProjectionFactory;
import com.bbn.openmap.util.DataBoundsProvider;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
/**
* Menu that keeps track of different saved map views (lat/lon, scale and
* projection type), and provides a way to set the map projection to those
* views. There is a set of optional default views, but new views can be added.
* If these views are added to the properties file, they will be added to the
* menu automatically for later uses. This menu can understand a set of
* properties:
*
* <pre>
*
*
* gotoMenu.class=com.bbn.openmap.gui.GoToMenu
* #Add the default, world view option
* gotoMenu.addDefaults=true
* #Add the menu for DataBoundsProviders
* gotoMenu.addDataViews=true
* #Additional views
* goto.views=Argentina India United_States Caspian_Sea
* Argentina.latitude=-39.760445
* Argentina.longitude=-65.92294
* Argentina.name=Argentina
* Argentina.projection=Mercator
* Argentina.scale=5.0E7
* India.latitude=20.895763
* India.longitude=80.437485
* India.name=India
* India.projection=Mercator
* India.scale=3.86688E7
* United_States.latitude=38.82259
* United_States.longitude=-96.74999
* United_States.name=United States
* United_States.projection=Mercator
* United_States.scale=5.186114E7
* Caspian_Sea.name=Caspian Sea
* Caspian_Sea.latitude=40f
* Caspian_Sea.longitude=47f
* Caspian_Sea.scale=1000000
* Caspian_Sea.projection=CADRG
*
*
* </pre>
*/
public class GoToMenu extends AbstractOpenMapMenu {
private String defaultText = "Views";
private String defaultMnemonic = "V";
protected Hashtable dataBoundsProviders = new Hashtable();
protected OMBasicMenu dataBoundsMenu;
protected MapBean map;
/**
* A space separated list of marker names for the views to be loaded from
* the properties.
*/
public final static String ViewListProperty = "views";
/** The name of the view to use in the GUI. */
public final static String NameProperty = "name";
/** The center latitude of the view projection. */
public final static String LatProperty = "latitude";
/** The center longitude of the view projection. */
public final static String LonProperty = "longitude";
/** The scale of the view projection. */
public final static String ScaleProperty = "scale";
/** The projection type of the view projection. */
public final static String ProjectionTypeProperty = "projection";
/** Flag to use to add default views (World, each continent. */
public final static String AddDefaultListProperty = "addDefaults";
/**
* Flag to use to enable/disable the gathering of DataBoundsProviders.
*/
public final static String AddDataViewsProperty = "addDataViews";
protected boolean addDefaults = true;
protected boolean addDataViews = true;
public GoToMenu() {
super();
setText(i18n.get(this, "goto", defaultText));
// setMnemonic(i18n.get(this, "goto", I18n.MNEMONIC, defaultMnemonic)
// .charAt(0));
// dataBoundsMenu = new OMBasicMenu("Go Over Data");
dataBoundsMenu = new OMBasicMenu(i18n.get(this,
"goOverData",
"Go Over Data"));
// add(new AddNewViewButton("Add Saved View..."));
add(new AddNewViewButton(i18n.get(this,
"addSavedView",
"Add Saved View...")));
add(dataBoundsMenu);
add(new JSeparator());
}
public void findAndUndo(Object someObj) {
super.findAndUndo(someObj);
if (someObj instanceof MapBean) {
// do the initializing that need to be done here
if (getMap() == (MapBean) someObj) {
setMap(null);
}
}
if (someObj instanceof DataBoundsProvider) {
removeDataBoundsProvider((DataBoundsProvider) someObj);
}
}
public void findAndInit(Object someObj) {
super.findAndInit(someObj);
if (someObj instanceof MapBean) {
// do the initializing that need to be done here
setMap((MapBean) someObj);
}
if (someObj instanceof DataBoundsProvider) {
addDataBoundsProvider((DataBoundsProvider) someObj);
}
}
/** Set the map to control. */
public void setMap(MapBean mb) {
map = mb;
}
public MapBean getMap() {
return map;
}
/** PropertyConsumer interface method. */
public void setProperties(String prefix, Properties props) {
super.setProperties(prefix, props);
prefix = PropUtils.getScopedPropertyPrefix(prefix);
addDefaults = PropUtils.booleanFromProperties(props, prefix
+ AddDefaultListProperty, addDefaults);
addDataViews = PropUtils.booleanFromProperties(props, prefix
+ AddDataViewsProperty, addDataViews);
dataBoundsMenu.setVisible(addDataViews);
if (addDefaults) {
addDefaultLocations();
add(new JSeparator());
}
String locationList = props.getProperty(prefix + ViewListProperty);
if (locationList != null) {
Vector views = PropUtils.parseSpacedMarkers(locationList);
for (Iterator it = views.iterator(); it.hasNext();) {
String viewPrefix = (String) it.next();
addLocationItem(viewPrefix, props);
}
}
}
/** PropertyConsumer interface method. */
public Properties getProperties(Properties props) {
props = super.getProperties(props);
String prefix = PropUtils.getScopedPropertyPrefix(this);
props.put(prefix + AddDefaultListProperty,
new Boolean(addDefaults).toString());
props.put(prefix + AddDataViewsProperty,
new Boolean(addDataViews).toString());
StringBuffer viewList = new StringBuffer();
for (Iterator it = ensureCustomViews().iterator(); it.hasNext();) {
GoToButton gtb = (GoToButton) it.next();
String sanitizedName = gtb.getText().replace(' ', '_');
viewList.append(" ").append(sanitizedName);
sanitizedName = PropUtils.getScopedPropertyPrefix(sanitizedName);
props.put(sanitizedName + NameProperty, gtb.getText());
props.put(sanitizedName + LatProperty,
new Float(gtb.latitude).toString());
props.put(sanitizedName + LonProperty,
new Float(gtb.longitude).toString());
props.put(sanitizedName + ScaleProperty,
new Float(gtb.scale).toString());
props.put(sanitizedName + ProjectionTypeProperty, gtb.projectionID);
}
props.put(prefix + ViewListProperty, viewList.toString());
return props;
}
/** PropertyConsumer interface method. */
public Properties getPropertyInfo(Properties props) {
props = super.getPropertyInfo(props);
props.put(ViewListProperty,
"Space-separated marker list of different views");
props.put(AddDefaultListProperty,
"Flag to add default views (true/false).");
props.put(AddDefaultListProperty + ScopedEditorProperty,
"com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");
props.put(AddDataViewsProperty,
"Flag to add views from some data components.");
props.put(AddDataViewsProperty + ScopedEditorProperty,
"com.bbn.openmap.util.propertyEditor.YesNoPropertyEditor");
props.put(NameProperty, "The formal name of the view for the user.");
props.put(LatProperty, "The latitude of the center of the view.");
props.put(LonProperty, "The longitude of the center of the view.");
props.put(ScaleProperty, "The scale of the view.");
props.put(ProjectionTypeProperty, "The projection name of the view");
return props;
}
/** Add the default views to the menu. */
public void addDefaultLocations() {
add(new GoToButton(i18n.get(this, "world", "World"), 0, 0, Float.MAX_VALUE, Mercator.MercatorName));
}
protected List customViews;
/**
* An internal callback method that creates the custom views List object.
* Override to change what kind of object gets created (it's a Vector by
* default).
*
* @return List
*/
protected List createCustomViews() {
return new Vector();
}
public List getCustomViews() {
return customViews;
}
/**
* Should call this when dealing with the custom views list, will always
* return a non-null answer.
*
* @return List
*/
public List ensureCustomViews() {
if (customViews == null) {
customViews = createCustomViews();
}
return customViews;
}
public void setCustomViews(List views) {
customViews = views;
}
/**
* Parse and add the view from properties.
*/
public void addLocationItem(String prefix, Properties props) {
prefix = PropUtils.getScopedPropertyPrefix(prefix);
String locationName = props.getProperty(prefix + NameProperty);
String latString = props.getProperty(prefix + LatProperty);
String lonString = props.getProperty(prefix + LonProperty);
String scaleString = props.getProperty(prefix + ScaleProperty);
String projID = props.getProperty(prefix + ProjectionTypeProperty);
if (Debug.debugging("goto")) {
Debug.output("GoToMenu: adding view - " + locationName + ", "
+ latString + ", " + lonString + ", " + scaleString + ", "
+ projID);
}
try {
float lat = new Float(latString).floatValue();
float lon = new Float(lonString).floatValue();
float scale = new Float(scaleString).floatValue();
GoToButton gtb = new GoToButton(locationName, lat, lon, scale, projID);
ensureCustomViews().add(gtb);
add(gtb);
} catch (NumberFormatException nfe) {
return;
}
}
public void addDataBoundsProvider(DataBoundsProvider provider) {
if (!dataBoundsProviders.containsKey(provider)) {
DataBoundsViewMenuItem dbvmi = new DataBoundsViewMenuItem(provider);
dataBoundsProviders.put(provider, dbvmi);
dbvmi.findAndInit(getBeanContext());
dataBoundsMenu.add(dbvmi);
}
}
public void removeDataBoundsProvider(DataBoundsProvider provider) {
JMenuItem item = (DataBoundsViewMenuItem) dataBoundsProviders.remove(provider);
if (item != null) {
dataBoundsMenu.remove(item);
}
}
/**
* Add a button to the menu that will set the map to a particular view.
*/
public void addView(GoToButton newOne) {
ensureCustomViews().add(newOne);
add(newOne);
revalidate();
}
/**
* This is the button that will bring up the dialog to actually name a new
* view being added. The new view will be the current projection of the map.
*/
public class AddNewViewButton extends JMenuItem implements ActionListener {
public AddNewViewButton(String title) {
super(title);
this.addActionListener(this);
}
public void actionPerformed(ActionEvent ae) {
if (map != null) {
Projection proj = map.getProjection();
Point2D llp = proj.getCenter();
new GoToButton((float) llp.getY(), (float) llp.getX(), proj.getScale(), proj.getName());
}
}
}
/**
* This button contains the trigger for a saved view.
*/
public class GoToButton extends JMenuItem implements ActionListener {
public float latitude;
public float longitude;
public float scale;
public String projectionID;
GoToMenu menu;
public GoToButton(String title, float lat, float lon, float s,
String projID) {
super(title);
init(lat, lon, s, projID);
}
public GoToButton(float lat, float lon, float s, String projID) {
init(lat, lon, s, projID);
NameFetcher nf = new NameFetcher(this);
if (map != null) {
Point p = map.getLocationOnScreen();
int x = (int) p.getX();
int y = (int) p.getY();
int w = map.getWidth();
int h = map.getHeight();
nf.setLocation(x + (w - nf.getWidth()) / 2, y
+ (h - nf.getHeight()) / 2);
}
nf.setVisible(true);
}
public void init(float lat, float lon, float s, String projID) {
latitude = lat;
longitude = lon;
scale = s;
projectionID = projID;
this.addActionListener(this);
}
/**
* Gets called when the NameFetcher successfully retrieves a name for the
* view.
*
* @param name new name for the button.
*/
public void setNameAndAdd(String name) {
this.setText(name);
GoToMenu.this.addView(this);
}
public void actionPerformed(ActionEvent ae) {
if (map != null) {
Projection oldProj = map.getProjection();
ProjectionFactory projFactory = map.getProjectionFactory();
Class<? extends Projection> projClass = projFactory.getProjClassForName(projectionID);
if (projClass == null) {
projClass = com.bbn.openmap.proj.Mercator.class;
}
Projection newProj = projFactory.makeProjection(projClass,
new Point2D.Float(longitude, latitude),
scale,
oldProj.getWidth(),
oldProj.getHeight());
map.setProjection(newProj);
}
}
}
/**
* Brings up a GUI to name a new view.
*/
public class NameFetcher extends JDialog implements ActionListener {
JTextField nameField;
JLabel label;
JButton closebutton, applybutton;
GoToButton notifyThis;
public NameFetcher(GoToButton buttonToName) {
notifyThis = buttonToName;
setTitle(i18n.get(GoToMenu.class, "addViewTitle", "Add View"));
JPanel palette = new JPanel();
palette.setLayout(new BoxLayout(palette, BoxLayout.Y_AXIS));
JPanel namePanel = new JPanel();
namePanel.setLayout(new FlowLayout());
label = new JLabel(i18n.get(GoToMenu.class,
"nameOfView",
"Name of View: "));
nameField = new JTextField("", 20);
namePanel.add(label);
namePanel.add(nameField);
palette.add(namePanel);
JPanel buttonPanel = new JPanel();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
buttonPanel.setLayout(gridbag);
applybutton = new JButton(i18n.get(GoToMenu.class,
"addView",
"Add View"));
applybutton.addActionListener(this);
gridbag.setConstraints(applybutton, c);
closebutton = new JButton(i18n.get(GoToMenu.class, "close", "Close"));
closebutton.addActionListener(this);
c.gridx = GridBagConstraints.RELATIVE;
gridbag.setConstraints(closebutton, c);
buttonPanel.add(applybutton);
buttonPanel.add(closebutton);
palette.add(buttonPanel);
this.getContentPane().add(palette);
this.pack();
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == applybutton) {
String newName = nameField.getText();
if (newName != null && !(newName.length() == 0)) {
notifyThis.setNameAndAdd(newName);
}
}
this.setVisible(false);
}
}
}