/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008 - 2009, Johann Sorel
* (C) 2009 - 2013, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.gui.swing.render2d.control;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import org.apache.sis.geometry.DirectPosition2D;
import org.geotoolkit.display.canvas.AbstractCanvas;
import org.geotoolkit.display2d.GO2Hints;
import org.geotoolkit.display2d.canvas.J2DCanvas;
import org.geotoolkit.gui.swing.render2d.JMap2D;
import org.geotoolkit.font.FontAwesomeIcons;
import org.geotoolkit.font.IconBuilder;
import org.geotoolkit.gui.swing.resource.MessageBundle;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
*
* @author Johann Sorel (Puzzle-GIS)
* @module
*/
public class JCoordinateBar extends AbstractMapControlBar {
private static final ImageIcon ICON_HINT = IconBuilder.createIcon(FontAwesomeIcons.ICON_LIGHTBULB_O, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICON_DIMENSIONS = IconBuilder.createIcon(FontAwesomeIcons.ICON_TASKS, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICON_FRAME = IconBuilder.createIcon(FontAwesomeIcons.ICON_EXTERNAL_LINK, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance();
private final myListener listener = new myListener();
private String error = MessageBundle.format("map_control_coord_error");
private final JButton guiHint = new JButton(ICON_HINT);
private final JScaleCombo guiCombo = new JScaleCombo();
private final JTextField guiCoord = new JTextField();
private final JCRSButton guiCRS = new JCRSButton();
private final JToggleButton guiDimensions = new JToggleButton(ICON_DIMENSIONS);
private final JSplitPane verticalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
private final JPanel paneTemp = new JPanel(new BorderLayout());
private final JAdditionalAxisNavigator guiAdditional = new JAdditionalAxisNavigator();
private final JToggleButton frameAction = new JToggleButton(new AbstractAction("", ICON_FRAME) {
@Override
public void actionPerformed(ActionEvent e) {
updateDimensionFrame();
}
});
private JDialog dimensionDialog = null;
public JCoordinateBar() {
this(null);
}
public JCoordinateBar(final JMap2D candidate) {
setLayout(new BorderLayout(0,1));
final JToolBar bottom = new JToolBar();
bottom.setFloatable(false);
bottom.setLayout(new GridBagLayout());
add(BorderLayout.SOUTH,bottom);
paneTemp.add(BorderLayout.CENTER,guiAdditional);
paneTemp.setPreferredSize(new Dimension(120, 120));
//the hints menu -------------------------------------------------------
final JCheckBoxMenuItem guiAxis = new JCheckBoxMenuItem(MessageBundle.format("map_xy_ratio")){
@Override
public boolean isSelected() {
if(map == null) return false;
return map.getCanvas().getAxisProportions() == 1;
}
};
guiAxis.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
if(map != null){
double d = map.getCanvas().getAxisProportions();
map.getCanvas().setAxisProportions((d == 1) ? Double.NaN : 1);
}
}
});
final JCheckBoxMenuItem guiStyleOrder = new JCheckBoxMenuItem(MessageBundle.format("map_style_order")){
@Override
public boolean isSelected() {
if(map == null) return false;
return GO2Hints.SYMBOL_RENDERING_PRIME.equals(
map.getCanvas().getRenderingHint(GO2Hints.KEY_SYMBOL_RENDERING_ORDER));
}
};
guiStyleOrder.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
if(map != null){
final Object val = map.getCanvas().getRenderingHint(GO2Hints.KEY_SYMBOL_RENDERING_ORDER);
map.getCanvas().setRenderingHint(
GO2Hints.KEY_SYMBOL_RENDERING_ORDER, (GO2Hints.SYMBOL_RENDERING_PRIME.equals(val))?
GO2Hints.SYMBOL_RENDERING_SECOND : GO2Hints.SYMBOL_RENDERING_PRIME);
}
}
});
final JCheckBoxMenuItem guiAntiAliasing = new JCheckBoxMenuItem(MessageBundle.format("antialiasing")){
@Override
public boolean isSelected() {
if(map == null) return false;
return RenderingHints.VALUE_ANTIALIAS_ON.equals(
map.getCanvas().getRenderingHint(RenderingHints.KEY_ANTIALIASING));
}
};
guiAntiAliasing.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
if(map != null){
final Object val = map.getCanvas().getRenderingHint(RenderingHints.KEY_ANTIALIASING);
map.getCanvas().setRenderingHint(
RenderingHints.KEY_ANTIALIASING, (RenderingHints.VALUE_ANTIALIAS_ON.equals(val))?
RenderingHints.VALUE_ANTIALIAS_OFF : RenderingHints.VALUE_ANTIALIAS_ON);
}
}
});
final ButtonGroup group = new ButtonGroup();
final JRadioButtonMenuItem guiNone = new JRadioButtonMenuItem(MessageBundle.format("interpolation_none")){
@Override
public boolean isSelected() {
if(map == null) return false;
return RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(
map.getCanvas().getRenderingHint(RenderingHints.KEY_INTERPOLATION));
}
};
final JRadioButtonMenuItem guiLinear = new JRadioButtonMenuItem(MessageBundle.format("interpolation_linear")){
@Override
public boolean isSelected() {
if(map == null) return false;
return RenderingHints.VALUE_INTERPOLATION_BILINEAR.equals(
map.getCanvas().getRenderingHint(RenderingHints.KEY_INTERPOLATION));
}
};
final JRadioButtonMenuItem guiBicubic = new JRadioButtonMenuItem(MessageBundle.format("interpolation_bicubic")){
@Override
public boolean isSelected() {
if(map == null) return false;
return RenderingHints.VALUE_INTERPOLATION_BICUBIC.equals(
map.getCanvas().getRenderingHint(RenderingHints.KEY_INTERPOLATION));
}
};
group.add(guiNone);
group.add(guiLinear);
group.add(guiBicubic);
final ActionListener interListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(map != null){
final Object source = e.getSource();
if(source == guiNone){
map.getCanvas().setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}else if(source == guiLinear){
map.getCanvas().setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
}else if(source == guiBicubic){
map.getCanvas().setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
}
}
}
};
guiNone.addActionListener(interListener);
guiLinear.addActionListener(interListener);
guiBicubic.addActionListener(interListener);
final JCheckBoxMenuItem guiMultiThread = new JCheckBoxMenuItem(MessageBundle.format("multithread")){
@Override
public boolean isSelected() {
if(map == null) return false;
return GO2Hints.MULTI_THREAD_ON.equals(map.getCanvas().getRenderingHint(GO2Hints.KEY_MULTI_THREAD));
}
};
guiMultiThread.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
if(map != null){
final Object val = map.getCanvas().getRenderingHint(GO2Hints.KEY_MULTI_THREAD);
map.getCanvas().setRenderingHint(GO2Hints.KEY_MULTI_THREAD, (GO2Hints.MULTI_THREAD_ON.equals(val))?
GO2Hints.MULTI_THREAD_OFF : GO2Hints.MULTI_THREAD_ON);
}
}
});
final JPopupMenu guiHintMenu = new JPopupMenu();
guiHintMenu.add(guiAxis);
guiHintMenu.add(guiMultiThread);
guiHintMenu.add(guiStyleOrder);
guiHintMenu.add(guiAntiAliasing);
guiHintMenu.add(new JSeparator());
guiHintMenu.add(new JMenuItem(MessageBundle.format("interpolation")));
guiHintMenu.add(guiNone);
guiHintMenu.add(guiLinear);
guiHintMenu.add(guiBicubic);
guiHint.setComponentPopupMenu(guiHintMenu);
guiHint.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent event) {
if(event.getButton() == MouseEvent.BUTTON1){
guiHintMenu.setSize(guiHintMenu.getPreferredSize());
final Dimension dim = guiHintMenu.getSize();
guiHintMenu.show(guiHint.getParent(), guiHint.getX(), guiHint.getY()-dim.height);
}
}
@Override
public void mousePressed(MouseEvent arg0) {}
@Override
public void mouseReleased(MouseEvent arg0) {}
@Override
public void mouseEntered(MouseEvent arg0) {}
@Override
public void mouseExited(MouseEvent arg0) {}
});
guiCRS.setEnabled(false);
guiAxis.setOpaque(false);
guiCombo.setOpaque(false);
guiCoord.setOpaque(false);
guiCoord.setBorder(null);
guiCoord.setEditable(false);
guiCoord.setHorizontalAlignment(SwingConstants.CENTER);
final int defaultInsetTop = guiDimensions.getMargin().top;
final int defaultInsetBottom = guiDimensions.getMargin().bottom;
guiHint.setMargin(new Insets(defaultInsetTop, 0, defaultInsetBottom, 0));
guiDimensions.setMargin(new Insets(defaultInsetTop, 0, defaultInsetBottom, 0));
guiDimensions.setToolTipText(MessageBundle.format("map_elevation_slider"));
guiDimensions.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
paneTemp.setVisible(guiDimensions.isSelected());
verticalSplit.setDividerLocation(baseMapContainer.getHeight()-paneTemp.getPreferredSize().height);
}
});
guiAdditional.setPreferredSize(new Dimension(100, 100));
guiAdditional.getToolbar().add(frameAction);
int x = 1;
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.WEST;
constraints.gridwidth = 1;
constraints.gridheight = GridBagConstraints.REMAINDER;
constraints.weightx = 0.0;
constraints.weighty = 1.0;
constraints.gridy = 0;
constraints.gridx = x++;
bottom.add(guiHint,constraints);
constraints.gridx = x++;
bottom.add(guiDimensions,constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1;
constraints.gridx = x++;
bottom.add(guiCoord,constraints);
constraints.weightx = 0;
constraints.gridx = x++;
bottom.add(guiCombo,constraints);
constraints.weightx = 0;
constraints.gridx = x++;
bottom.add(guiCRS,constraints);
paneTemp.setVisible(false);
verticalSplit.setDividerSize(2);
verticalSplit.setTopComponent(new JLabel());
verticalSplit.setBottomComponent(paneTemp);
setMap(candidate);
}
private Container baseMapContainer;
private Component baseMapComponent;
@Override
public void setMap(final JMap2D map) {
super.setMap(map);
guiCombo.setMap(map);
guiAdditional.setMap(map);
if(baseMapContainer != null){
baseMapContainer.remove(verticalSplit);
baseMapContainer.add(BorderLayout.CENTER, baseMapComponent);
baseMapComponent.removeMouseMotionListener(listener);
this.map.getCanvas().removePropertyChangeListener(listener);
}
this.map = map;
guiCRS.setMap(this.map);
if(this.map != null){
baseMapContainer = map.getUIContainer();
baseMapComponent = map.getComponent(0);
baseMapComponent.addMouseMotionListener(listener);
this.map.getCanvas().addPropertyChangeListener(listener);
map.getCanvas().addPropertyChangeListener(listener);
baseMapContainer.remove(baseMapComponent);
verticalSplit.setTopComponent(baseMapComponent);
//multiSplitPane.setDividerSize(2);
baseMapContainer.add(BorderLayout.CENTER, verticalSplit);
baseMapContainer.repaint();
final CoordinateReferenceSystem crs = map.getCanvas().getObjectiveCRS();
guiCRS.setText(crs.getName().toString());
}
guiCRS.setEnabled(this.map != null);
}
public void setScales(final List<Number> scales){
guiCombo.setScales(scales);
}
public List<Number> getScales(){
return guiCombo.getScales();
}
public void setStepSize(final Number step){
guiCombo.setStepSize(step);
}
public Number getStepSize(){
return guiCombo.getStepSize();
}
private void updateDimensionFrame(){
if(dimensionDialog!=null){
dimensionDialog.setContentPane(new JPanel());
dimensionDialog.setVisible(false);
dimensionDialog.dispose();
}
paneTemp.remove(guiAdditional);
if(frameAction.isSelected()){
paneTemp.setVisible(false);
dimensionDialog = new JDialog();
dimensionDialog.setContentPane(guiAdditional);
dimensionDialog.setSize(guiAdditional.getSize().width, guiAdditional.getSize().height);
dimensionDialog.setLocationRelativeTo(null);
dimensionDialog.setVisible(true);
}else{
paneTemp.add(BorderLayout.CENTER,guiAdditional);
paneTemp.setVisible(true);
verticalSplit.setDividerLocation(baseMapContainer.getHeight()-paneTemp.getPreferredSize().height);
}
paneTemp.revalidate();
paneTemp.repaint();
}
private class myListener extends MouseMotionAdapter implements PropertyChangeListener{
@Override
public void mouseMoved(final MouseEvent e) {
update(e);
}
@Override
public void mouseDragged(final MouseEvent e) {
update(e);
}
private void update(final MouseEvent event){
Point2D coord = new DirectPosition2D();
try {
coord = map.getCanvas().getObjectiveToDisplay().inverseTransform(event.getPoint(), coord);
} catch (NoninvertibleTransformException ex) {
guiCoord.setText(error);
return;
}
final CoordinateReferenceSystem crs = map.getCanvas().getObjectiveCRS();
final StringBuilder sb = new StringBuilder(" ");
sb.append(crs.getCoordinateSystem().getAxis(0).getAbbreviation());
sb.append(" : ");
sb.append(NUMBER_FORMAT.format(coord.getX()));
sb.append(" ");
sb.append(crs.getCoordinateSystem().getAxis(1).getAbbreviation());
sb.append(" : ");
sb.append(NUMBER_FORMAT.format(coord.getY()));
guiCoord.setText(sb.toString());
}
@Override
public void propertyChange(final PropertyChangeEvent arg0) {
if(J2DCanvas.OBJECTIVE_CRS_KEY.equals(arg0.getPropertyName())){
CoordinateReferenceSystem crs = map.getCanvas().getObjectiveCRS();
guiCRS.setText(crs.getName().toString());
}else if(AbstractCanvas.RENDERSTATE_KEY.equals(arg0.getPropertyName())){
final Object state = arg0.getNewValue();
if(AbstractCanvas.ON_HOLD.equals(state)){
map.getInformationDecoration().setPaintingIconVisible(false);
}else if(AbstractCanvas.RENDERING.equals(state)){
map.getInformationDecoration().setPaintingIconVisible(true);
}else{
map.getInformationDecoration().setPaintingIconVisible(false);
}
}
}
}
private static ImageIcon addHorizontalMargin(final ImageIcon icon, final int margin){
final Image img = icon.getImage();
BufferedImage buffer = new BufferedImage(img.getWidth(null)+2*margin,img.getHeight(null),BufferedImage.TYPE_INT_ARGB);
buffer.getGraphics().drawImage(img, margin, 0, null);
return new ImageIcon(buffer);
}
}