/*
* JXMapKit.java
*
* Created on November 19, 2006, 3:52 AM
*/
package org.jdesktop.swingx.mapviewer;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.geom.Point2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JSlider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.mapviewer.empty.EmptyTileFactory;
import org.jdesktop.swingx.painter.Painter;
/**
* <p>
* The JXMapKit is a pair of JXMapViewers preconfigured to be easy to use with
* common features built in. This includes zoom buttons, a zoom slider, and a
* mini-map in the lower right corner showing an overview of the map. Each
* feature can be turned off using an appropriate <CODE>is<I>X</I>visible</CODE>
* property. For example, to turn off the minimap call
*
* <PRE>
* <CODE>jxMapKit.setMiniMapVisible(false);</CODE>
* </PRE>
* </p>
*
* <p>
* The JXMapViewer is preconfigured to connect to maps.swinglabs.org which
* serves up global satellite imagery from NASA's
* <a href="http://earthobservatory.nasa.gov/Newsroom/BlueMarble/">Blue Marble
* NG</a> image collection.
* </p>
*
* @author joshy
*/
public class JXMapKit extends JXPanel {
private static final long serialVersionUID = -1096864144135804141L;
private boolean miniMapVisible = true;
private boolean zoomSliderVisible = true;
private boolean zoomButtonsVisible = true;
private final boolean sliderReversed = false;
// private boolean addressLocationShown = true;
// private boolean dataProviderCreditShown = true;
private static final Log log = LogFactory.getLog(JXMapKit.class);
/**
* Creates a new JXMapKit
*/
public JXMapKit() {
initComponents();
zoomSlider.setOpaque(false);
try {
Icon minusIcon = new ImageIcon(JXMapKit.class.getResource("resources/minus.png"));
this.zoomOutButton.setIcon(minusIcon);
this.zoomOutButton.setText("");
Icon plusIcon = new ImageIcon(JXMapKit.class.getResource("resources/plus.png"));
this.zoomInButton.setIcon(plusIcon);
this.zoomInButton.setText("");
} catch (Throwable thr) {
System.out.println("error: " + thr.getMessage());
thr.printStackTrace();
}
setTileFactory(new EmptyTileFactory());
mainMap.setCenterPosition(new GeoPosition(0, 0, GeoPosition.WGS_84_EPSG));
miniMap.setCenterPosition(new GeoPosition(0, 0, GeoPosition.WGS_84_EPSG));
mainMap.setRestrictOutsidePanning(true);
miniMap.setRestrictOutsidePanning(true);
// update mini map center
mainMap.addPropertyChangeListener("center", new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Point2D mapCenter = (Point2D) evt.getNewValue();
TileFactory tf = mainMap.getTileFactory();
GeoPosition mapPos = tf.getTileProvider().getConverter().pixelToGeo(mapCenter,
mainMap.getZoom());
miniMap.setCenterPosition(mapPos);
}
});
// XXX centerPosition change means center change
/*
* mainMap.addPropertyChangeListener("centerPosition", new
* PropertyChangeListener() { public void
* propertyChange(PropertyChangeEvent evt) { mapCenterPosition =
* (GeoPosition)evt.getNewValue();
* miniMap.setCenterPosition(mapCenterPosition); try { Point2D pt =
* miniMap.getTileFactory().getTileProvider().getConverter().geoToPixel(
* mapCenterPosition,miniMap.getZoom()); miniMap.setCenter(pt);
* miniMap.repaint(); } catch (IllegalGeoPositionException e) {
* log.warn("Error setting mini map center position", e); } } });
*/
// update mini map zoom
mainMap.addPropertyChangeListener("zoom", new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
zoomSlider.setValue(mainMap.getZoom());
miniMap.setZoom(Math.min(mainMap.getZoom() + 4,
mainMap.getTileFactory().getTileProvider().getMaximumZoom()));
}
});
// an overlay for the mini-map which shows a rectangle representing the
// main map
miniMap.setOverlayPainter(new Painter<JXMapViewer>() {
@Override
public void paint(Graphics2D g, JXMapViewer map, int width, int height) {
// get the viewport rect of the main map
Rectangle mainMapBounds = mainMap.getViewportBounds();
// convert to Point2Ds
Point2D upperLeft2D = mainMapBounds.getLocation();
Point2D lowerRight2D = new Point2D.Double(
upperLeft2D.getX() + mainMapBounds.getWidth(),
upperLeft2D.getY() + mainMapBounds.getHeight());
// convert to GeoPostions
GeoPosition upperLeft = mainMap.getTileFactory().getTileProvider().getConverter()
.pixelToGeo(upperLeft2D, mainMap.getZoom());
GeoPosition lowerRight = mainMap.getTileFactory().getTileProvider().getConverter()
.pixelToGeo(lowerRight2D, mainMap.getZoom());
// convert to Point2Ds on the mini-map
try {
upperLeft2D = map.getTileFactory().getTileProvider().getConverter()
.geoToPixel(upperLeft, map.getZoom());
lowerRight2D = map.getTileFactory().getTileProvider().getConverter()
.geoToPixel(lowerRight, map.getZoom());
g = (Graphics2D) g.create();
Rectangle rect = map.getViewportBounds();
g.translate(-rect.x, -rect.y);
// Point2D centerpos =
// map.getTileFactory().getTileProvider().getConverter().geoToPixel(mapCenterPosition,
// map.getZoom());
g.setPaint(Color.RED);
// g.drawRect((int)centerpos.getX()-30,(int)centerpos.getY()-30,60,60);
g.drawRect((int) upperLeft2D.getX(), (int) upperLeft2D.getY(),
(int) (lowerRight2D.getX() - upperLeft2D.getX()),
(int) (lowerRight2D.getY() - upperLeft2D.getY()));
g.setPaint(new Color(255, 0, 0, 50));
g.fillRect((int) upperLeft2D.getX(), (int) upperLeft2D.getY(),
(int) (lowerRight2D.getX() - upperLeft2D.getX()),
(int) (lowerRight2D.getY() - upperLeft2D.getY()));
// g.drawOval((int)lowerRight2D.getX(),(int)lowerRight2D.getY(),1,1);
g.dispose();
} catch (IllegalGeoPositionException e) {
log.warn("Error painting mini map overlay");
}
}
});
setZoom(3);// joshy: hack, i shouldn't need this here
// this.setCenterPosition(new GeoPosition(0,0));
}
// private GeoPosition mapCenterPosition = new GeoPosition(0, 0,
// GeoPosition.WGS_84_EPSG);
private boolean zoomChanging = false;
/**
* Set the current zoomlevel for the main map. The minimap will be updated
* accordingly
*
* @param zoom the new zoom level
*/
public void setZoom(int zoom) {
zoomChanging = true;
mainMap.setZoom(zoom);
// XXX is done by property change listener -
// miniMap.setZoom(mainMap.getZoom()+4);
if (sliderReversed) {
zoomSlider.setValue(zoomSlider.getMaximum() - zoom);
}
else {
zoomSlider.setValue(zoom);
}
zoomChanging = false;
}
/**
* Returns an action which can be attached to buttons or menu items to make
* the map zoom out
*
* @return a preconfigured Zoom Out action
*/
@SuppressWarnings("serial")
public Action getZoomOutAction() {
Action act = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
setZoom(mainMap.getZoom() - 1);
}
};
act.putValue(Action.NAME, "-");
return act;
}
/**
* Returns an action which can be attached to buttons or menu items to make
* the map zoom in
*
* @return a preconfigured Zoom In action
*/
@SuppressWarnings("serial")
public Action getZoomInAction() {
Action act = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
setZoom(mainMap.getZoom() + 1);
}
};
act.putValue(Action.NAME, "+");
return act;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code
// ">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
mainMap = new org.jdesktop.swingx.mapviewer.JXMapViewer();
miniMap = new org.jdesktop.swingx.mapviewer.JXMapViewer();
jPanel1 = new javax.swing.JPanel();
zoomInButton = new javax.swing.JButton();
zoomOutButton = new javax.swing.JButton();
zoomSlider = new javax.swing.JSlider();
setLayout(new java.awt.GridBagLayout());
mainMap.setLayout(new java.awt.GridBagLayout());
miniMap.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
miniMap.setMinimumSize(new java.awt.Dimension(100, 100));
miniMap.setPreferredSize(new java.awt.Dimension(100, 100));
miniMap.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
mainMap.add(miniMap, gridBagConstraints);
jPanel1.setOpaque(false);
jPanel1.setLayout(new java.awt.GridBagLayout());
zoomInButton.setAction(getZoomOutAction());
zoomInButton.setIcon(
new javax.swing.ImageIcon(JXMapKit.class.getResource("resources/plus.png")));
zoomInButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
zoomInButton.setMaximumSize(new java.awt.Dimension(20, 20));
zoomInButton.setMinimumSize(new java.awt.Dimension(20, 20));
zoomInButton.setOpaque(false);
zoomInButton.setPreferredSize(new java.awt.Dimension(20, 20));
zoomInButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomInButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel1.add(zoomInButton, gridBagConstraints);
zoomOutButton.setAction(getZoomInAction());
zoomOutButton.setIcon(
new javax.swing.ImageIcon(JXMapKit.class.getResource("resources/minus.png")));
zoomOutButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
zoomOutButton.setMaximumSize(new java.awt.Dimension(20, 20));
zoomOutButton.setMinimumSize(new java.awt.Dimension(20, 20));
zoomOutButton.setOpaque(false);
zoomOutButton.setPreferredSize(new java.awt.Dimension(20, 20));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weighty = 1.0;
jPanel1.add(zoomOutButton, gridBagConstraints);
zoomSlider.setMajorTickSpacing(1);
zoomSlider.setMaximum(15);
zoomSlider.setMinimum(10);
zoomSlider.setMinorTickSpacing(1);
zoomSlider.setOrientation(javax.swing.JSlider.VERTICAL);
zoomSlider.setPaintTicks(true);
zoomSlider.setSnapToTicks(true);
zoomSlider.setMinimumSize(new java.awt.Dimension(35, 100));
zoomSlider.setPreferredSize(new java.awt.Dimension(35, 190));
zoomSlider.addChangeListener(new javax.swing.event.ChangeListener() {
@Override
public void stateChanged(javax.swing.event.ChangeEvent evt) {
zoomSliderStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
jPanel1.add(zoomSlider, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
mainMap.add(jPanel1, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(mainMap, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void zoomInButtonActionPerformed(
@SuppressWarnings("unused") java.awt.event.ActionEvent evt) {// GEN-FIRST:event_zoomInButtonActionPerformed
// TODO add your handling code here:
}// GEN-LAST:event_zoomInButtonActionPerformed
private void zoomSliderStateChanged(
@SuppressWarnings("unused") javax.swing.event.ChangeEvent evt) {// GEN-FIRST:event_zoomSliderStateChanged
if (!zoomChanging) {
setZoom(zoomSlider.getValue());
}
// TODO add your handling code here:
}// GEN-LAST:event_zoomSliderStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel jPanel1;
private org.jdesktop.swingx.mapviewer.JXMapViewer mainMap;
private org.jdesktop.swingx.mapviewer.JXMapViewer miniMap;
private javax.swing.JButton zoomInButton;
private javax.swing.JButton zoomOutButton;
private javax.swing.JSlider zoomSlider;
// End of variables declaration//GEN-END:variables
/**
* Indicates if the mini-map is currently visible
*
* @return the current value of the mini-map property
*/
public boolean isMiniMapVisible() {
return miniMapVisible;
}
/**
* Sets if the mini-map should be visible
*
* @param miniMapVisible a new value for the miniMap property
*/
public void setMiniMapVisible(boolean miniMapVisible) {
boolean old = this.isMiniMapVisible();
this.miniMapVisible = miniMapVisible;
miniMap.setVisible(miniMapVisible);
firePropertyChange("miniMapVisible", old, this.isMiniMapVisible());
}
/**
* Indicates if the zoom slider is currently visible
*
* @return the current value of the zoomSliderVisible property
*/
public boolean isZoomSliderVisible() {
return zoomSliderVisible;
}
/**
* Sets if the zoom slider should be visible
*
* @param zoomSliderVisible the new value of the zoomSliderVisible property
*/
public void setZoomSliderVisible(boolean zoomSliderVisible) {
boolean old = this.isZoomSliderVisible();
this.zoomSliderVisible = zoomSliderVisible;
zoomSlider.setVisible(zoomSliderVisible);
firePropertyChange("zoomSliderVisible", old, this.isZoomSliderVisible());
}
/**
* Indicates if the zoom buttons are visible. This is a bound property and
* can be listed for using a PropertyChangeListener
*
* @return current value of the zoomButtonsVisible property
*/
public boolean isZoomButtonsVisible() {
return zoomButtonsVisible;
}
/**
* Sets if the zoom buttons should be visible. This ia bound property.
* Changes can be listened for using a PropertyChaneListener
*
* @param zoomButtonsVisible new value of the zoomButtonsVisible property
*/
public void setZoomButtonsVisible(boolean zoomButtonsVisible) {
boolean old = this.isZoomButtonsVisible();
this.zoomButtonsVisible = zoomButtonsVisible;
zoomInButton.setVisible(zoomButtonsVisible);
zoomOutButton.setVisible(zoomButtonsVisible);
firePropertyChange("zoomButtonsVisible", old, this.isZoomButtonsVisible());
}
/**
* Sets the tile factory for both embedded JXMapViewer components. Calling
* this method will also reset the center and zoom levels of both maps, as
* well as the bounds of the zoom slider.
*
* @param fact the new TileFactory
*/
public void setTileFactory(TileFactory fact) {
zoomChanging = true;
zoomSlider.setMinimum(fact.getTileProvider().getMinimumZoom());
zoomSlider.setMaximum(fact.getTileProvider().getMaximumZoom());
zoomChanging = false;
mainMap.setTileFactory(fact);
// mainMap.setCenterPosition(TileProviderUtils.getMapCenter(fact.getTileProvider()));
mainMap.setZoom(fact.getTileProvider().getDefaultZoom());
miniMap.setTileFactory(fact);
// miniMap.setCenterPosition(TileProviderUtils.getMapCenter(fact.getTileProvider()));
setZoom(fact.getTileProvider().getDefaultZoom());
}
/**
* Set the center position
*
* @param pos the center position to set
*/
public void setCenterPosition(GeoPosition pos) {
mainMap.setCenterPosition(pos);
// XXX is done by property change listener -
// miniMap.setCenterPosition(pos);
}
/**
* Get the center position
*
* @return the center position
*/
public GeoPosition getCenterPosition() {
return mainMap.getCenterPosition();
}
/**
* Returns a reference to the main embedded JXMapViewer component
*
* @return the main map
*/
public JXMapViewer getMainMap() {
return this.mainMap;
}
/**
* Returns a reference to the mini embedded JXMapViewer component
*
* @return the minimap JXMapViewer component
*/
public JXMapViewer getMiniMap() {
return this.miniMap;
}
/**
* returns a reference to the zoom in button
*
* @return a jbutton
*/
public JButton getZoomInButton() {
return this.zoomInButton;
}
/**
* returns a reference to the zoom out button
*
* @return a jbutton
*/
public JButton getZoomOutButton() {
return this.zoomOutButton;
}
/**
* returns a reference to the zoom slider
*
* @return a jslider
*/
public JSlider getZoomSlider() {
return this.zoomSlider;
}
/*
* public static void main(String ... args) { SwingUtilities.invokeLater(new
* Runnable() { public void run() { JXMapKit kit = new JXMapKit();
*
* final int max = 17; TileFactoryInfo info = new
* TileFactoryInfo(1,max-2,max, 256, true, true, // tile size is 256 and x/y
* orientation is normal "http://tile.openstreetmap.org",//5/15/10.png",
* "x","y","z") { public String getTileUrl(int x, int y, int zoom) { zoom =
* max-zoom; String url = this.baseURL +"/"+zoom+"/"+x+"/"+y+".png"; return
* url; }
*
* }; TileFactory tf = new DefaultTileFactory(new
* TileFactoryInfoTileProvider(info, SimpleGeoConverter.INSTANCE));
* kit.setTileFactory(tf); kit.setZoom(14); //kit.setAddressLocation(new
* GeoPosition(51.5,0)); kit.getMainMap().setDrawTileBorders(true);
* kit.getMainMap().setRestrictOutsidePanning(true);
* kit.getMainMap().setHorizontalWrapped(false);
*
* ((DefaultTileFactory)kit.getMainMap().getTileFactory()).setThreadPoolSize
* (8); JFrame frame = new JFrame("JXMapKit test"); frame.add(kit);
* frame.pack(); frame.setSize(500,300); frame.setVisible(true); } }); }
*/
}