// License: GPL. Copyright 2007 by Immanuel Scholz and others
package org.openstreetmap.josm.gui.preferences;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.CoordinateFormat;
import org.openstreetmap.josm.data.projection.Mercator;
import org.openstreetmap.josm.data.projection.Projection;
import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
import org.openstreetmap.josm.tools.GBC;
public class ProjectionPreference implements PreferenceSetting {
public static class Factory implements PreferenceSettingFactory {
public PreferenceSetting createPreferenceSetting() {
return new ProjectionPreference();
}
}
/**
* Combobox with all projections available
*/
private JComboBox projectionCombo = new JComboBox(Projection.allProjections);
/**
* Combobox with all coordinate display possibilities
*/
private JComboBox coordinatesCombo = new JComboBox(CoordinateFormat.values());
/**
* This variable holds the JPanel with the projection's preferences. If the
* selected projection does not implement this, it will be set to an empty
* Panel.
*/
private JPanel projSubPrefPanel;
private JLabel projectionCode = new JLabel();
private JLabel bounds = new JLabel();
/**
* This is the panel holding all projection preferences
*/
private JPanel projPanel = new JPanel();
/**
* The GridBagConstraints for the Panel containing the ProjectionSubPrefs.
* This is required twice in the code, creating it here keeps both occurrences
* in sync
*/
static private GBC projSubPrefPanelGBC = GBC.eol().fill(GBC.BOTH).insets(20,5,5,5);
public void addGui(PreferenceTabbedPane gui) {
setupProjectionCombo();
for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(Main.pref.get("coordinates"))) {
coordinatesCombo.setSelectedIndex(i);
break;
}
}
projPanel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
projPanel.setLayout(new GridBagLayout());
projPanel.add(new JLabel(tr("Display coordinates as")), GBC.std().insets(5,5,0,5));
projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
projPanel.add(coordinatesCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
projPanel.add(new JLabel(tr("Projection method")), GBC.std().insets(5,5,0,5));
projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
projPanel.add(projectionCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
projPanel.add(new JLabel(tr("Projection code")), GBC.std().insets(25,5,0,5));
projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
projPanel.add(projectionCode, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
projPanel.add(new JLabel(tr("Bounds")), GBC.std().insets(25,5,0,5));
projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
projPanel.add(bounds, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
projPanel.add(projSubPrefPanel, projSubPrefPanelGBC);
JScrollPane scrollpane = new JScrollPane(projPanel);
gui.mapcontent.addTab(tr("Map Projection"), scrollpane);
updateMeta(Main.proj);
}
private void updateMeta(Projection proj)
{
projectionCode.setText(proj.toCode());
Bounds b = proj.getWorldBoundsLatLon();
CoordinateFormat cf = CoordinateFormat.getDefaultFormat();
bounds.setText(b.getMin().latToString(cf)+"; "+b.getMin().lonToString(cf)+" : "+b.getMax().latToString(cf)+"; "+b.getMax().lonToString(cf));
}
public boolean ok() {
Projection proj = (Projection) projectionCombo.getSelectedItem();
String projname = proj.getClass().getName();
Collection<String> prefs = null;
if(proj instanceof ProjectionSubPrefs) {
prefs = ((ProjectionSubPrefs) proj).getPreferences(projSubPrefPanel);
}
Main.pref.put("projection", projname);
setProjection(projname, prefs);
if(Main.pref.put("coordinates",
((CoordinateFormat)coordinatesCombo.getSelectedItem()).name())) {
CoordinateFormat.setCoordinateFormat((CoordinateFormat)coordinatesCombo.getSelectedItem());
}
return false;
}
static public void setProjection()
{
setProjection(Main.pref.get("projection", Mercator.class.getName()),
Main.pref.getCollection("projection.sub", null));
}
static public void setProjection(String name, Collection<String> coll)
{
Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
Projection oldProj = Main.proj;
try {
Main.proj = (Projection)Class.forName(name).newInstance();
} catch (final Exception e) {
JOptionPane.showMessageDialog(
Main.parent,
tr("The projection {0} could not be activated. Using Mercator", name),
tr("Error"),
JOptionPane.ERROR_MESSAGE
);
coll = null;
Main.proj = new Mercator();
name = Main.proj.getClass().getName();
}
Main.pref.putCollection("projection.sub", coll);
String sname = name.substring(name.lastIndexOf(".")+1);
Main.pref.putCollection("projection.sub."+sname, coll);
if(Main.proj instanceof ProjectionSubPrefs) {
((ProjectionSubPrefs) Main.proj).setPreferences(coll);
}
if(b != null && (!Main.proj.getClass().getName().equals(oldProj.getClass().getName()) || Main.proj.hashCode() != oldProj.hashCode()))
{
Main.map.mapView.zoomTo(b);
/* TODO - remove layers with fixed projection */
}
}
private class SBPanel extends JPanel
{
private Projection p;
public SBPanel(Projection pr)
{
super();
p = pr;
}
@Override
public void paint(java.awt.Graphics g)
{
super.paint(g);
((ProjectionSubPrefs) p).setPreferences(((ProjectionSubPrefs) p).getPreferences(this));
updateMeta(p);
}
}
/**
* Handles all the work related to update the projection-specific
* preferences
* @param proj
*/
private void selectedProjectionChanged(Projection proj) {
if(!(proj instanceof ProjectionSubPrefs)) {
projSubPrefPanel = new JPanel();
} else {
ProjectionSubPrefs projPref = (ProjectionSubPrefs) proj;
projSubPrefPanel = new SBPanel(proj);
projPref.setupPreferencePanel(projSubPrefPanel);
}
// Don't try to update if we're still starting up
int size = projPanel.getComponentCount();
if(size < 1)
return;
// Replace old panel with new one
projPanel.remove(size - 1);
projPanel.add(projSubPrefPanel, projSubPrefPanelGBC);
projPanel.revalidate();
projSubPrefPanel.repaint();
updateMeta(proj);
}
/**
* Sets up projection combobox with default values and action listener
*/
private void setupProjectionCombo() {
for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
Projection proj = (Projection)projectionCombo.getItemAt(i);
String name = proj.getClass().getName();
String sname = name.substring(name.lastIndexOf(".")+1);
if(proj instanceof ProjectionSubPrefs) {
((ProjectionSubPrefs) proj).setPreferences(Main.pref.getCollection("projection.sub."+sname, null));
}
if (name.equals(Main.pref.get("projection", Mercator.class.getName()))) {
projectionCombo.setSelectedIndex(i);
selectedProjectionChanged(proj);
break;
}
}
projectionCombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox)e.getSource();
Projection proj = (Projection)cb.getSelectedItem();
selectedProjectionChanged(proj);
}
});
}
}