/**
* OrbisGIS is a java GIS application dedicated to research in GIScience.
* OrbisGIS is developed by the GIS group of the DECIDE team of the
* Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
*
* The GIS group of the DECIDE team is located at :
*
* Laboratoire Lab-STICC – CNRS UMR 6285
* Equipe DECIDE
* UNIVERSITÉ DE BRETAGNE-SUD
* Institut Universitaire de Technologie de Vannes
* 8, Rue Montaigne - BP 561 56017 Vannes Cedex
*
* OrbisGIS is distributed under GPL 3 license.
*
* Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
* Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
*
* This file is part of OrbisGIS.
*
* OrbisGIS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OrbisGIS 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, please consult: <http://www.orbisgis.org/>
* or contact directly:
* info_at_ orbisgis.org
*/
package org.orbisgis.mapeditor.map;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.beans.EventHandler;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import javax.swing.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.cts.crs.CoordinateReferenceSystem;
import org.orbisgis.commons.events.OGVetoableChangeSupport;
import org.orbisgis.mapeditor.map.icons.MapEditorIcons;
import org.orbisgis.sif.components.CustomButton;
import org.orbisgis.sif.components.StatusBar;
import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;
/**
* Area at the bottom of the MapEditor
* This is an area in the bottom of the map that contain :
* - A scale information label
* - A projection information label
* - A projection selection button
*/
public class MapStatusBar extends StatusBar {
private static final I18n I18N = I18nFactory.getI18n(MapStatusBar.class);
private static final Logger LOGGER = LoggerFactory.getLogger(MapStatusBar.class);
public static final String PROP_USER_DEFINED_SCALE_DENOMINATOR = "userDefinedScaleDenominator";
private static final int STATUS_BAR_HEIGHT = 30;
private ActionListener scaleInputActionListener = EventHandler.create(ActionListener.class,this,"validateInputScale");
protected VetoableChangeSupport vetoableChangeSupport = new OGVetoableChangeSupport(this);
//Scale
private JLabel scaleLabel;
private JTextField scaleField;
private double scaleValue=1; //Valid scale defined by the MapEditor
private long userDefinedScaleDenominator=1; //Last User scale set
//CRS
private JLabel projectionLabel;
//Coordinates
private JLabel mouseCoordinatesLabel;
private Point2D mouseCoordinates = new Point2D.Double();
//Layout parameters
private static final int OUTER_BAR_BORDER = 1;
private static final int HORIZONTAL_EMPTY_BORDER = 4;
public MapStatusBar() {
super(OUTER_BAR_BORDER,HORIZONTAL_EMPTY_BORDER);
setPreferredSize(new Dimension(-1,STATUS_BAR_HEIGHT));
setMinimumSize(new Dimension(1,STATUS_BAR_HEIGHT));
////////
//Add bar components
//Coordinates
mouseCoordinatesLabel = new JLabel();
addComponent(mouseCoordinatesLabel, SwingConstants.RIGHT);
// Projection
projectionLabel = new JLabel();
addComponent(projectionLabel, SwingConstants.RIGHT);
JButton changeProjection = new CustomButton(MapEditorIcons.getIcon("world_projection"));
changeProjection.setToolTipText(I18N.tr("Change coordinate reference system"));
//changeProjection.setContentAreaFilled(false);
addComponent(changeProjection,SwingConstants.RIGHT,false);
// Scale
scaleLabel = new JLabel(I18N.tr("Scale :"));
scaleField = new JTextField();
scaleField.addActionListener(scaleInputActionListener);
scaleField.setInputVerifier(new FormattedTextFieldVerifier());
//scaleField.setEditable(false);
//scaleField.setColumns(SCALE_FIELD_COLUMNS);
addComponent(scaleLabel, SwingConstants.RIGHT);
addComponent(scaleField, SwingConstants.RIGHT, false);
//Set initial value
setScaleDenominator(1);
//TODO : manage projection
setProjection(null);
setCursorCoordinates(new Point2D.Double());
}
/**
* Called by the VK_ENTER of the textField
*/
public void validateInputScale() {
scaleField.getInputVerifier().verify(scaleField);
}
/**
* Set the value of userDefinedScaleDenominator
*
* @param userDefinedScaleDenominator new value of
* userDefinedScaleDenominator
* @throws java.beans.PropertyVetoException
*/
public void setUserDefinedScaleDenominator(long userDefinedScaleDenominator) throws PropertyVetoException {
long oldUserDefinedScaleDenominator = this.userDefinedScaleDenominator;
vetoableChangeSupport.fireVetoableChange(PROP_USER_DEFINED_SCALE_DENOMINATOR, oldUserDefinedScaleDenominator, userDefinedScaleDenominator);
fireVetoableChange(PROP_USER_DEFINED_SCALE_DENOMINATOR, oldUserDefinedScaleDenominator, userDefinedScaleDenominator);
this.userDefinedScaleDenominator = userDefinedScaleDenominator;
firePropertyChange(PROP_USER_DEFINED_SCALE_DENOMINATOR, oldUserDefinedScaleDenominator, userDefinedScaleDenominator);
}
/**
* Set the new Projection of the Map
* @param projection
*/
public final void setProjection(CoordinateReferenceSystem projection) {
String projectLabel = "Unknown CRS";//projection.toString();
//projectLabel = "TODO"; //TODO read map context project
projectionLabel.setText(I18N.tr("Projection : {0}",projectLabel));
}
/**
* Add a VetoableChangeListener for a specific property.
* @param listener
*/
public void addVetoableChangeListener(String property, VetoableChangeListener listener )
{
vetoableChangeSupport.addVetoableChangeListener(property, listener );
}
/**
* @param cursorCoordinate Set the mouse coordinate in the Coordinate reference system
*/
public final void setCursorCoordinates(Point2D cursorCoordinate) {
if(!mouseCoordinates.equals(cursorCoordinate)) {
mouseCoordinates=cursorCoordinate;
NumberFormat f = DecimalFormat.getInstance(new Locale("en"));
f.setGroupingUsed(false);
mouseCoordinatesLabel.setText(I18N.tr("X:{0} Y:{1}",f.format(cursorCoordinate.getX()),f.format(cursorCoordinate.getY())));
}
}
/**
* Set the value of scaleDenominator
*
* @param scaleDenominator new value of scaleDenominator
*/
public final void setScaleDenominator(double scaleDenominator) {
scaleValue = scaleDenominator;
scaleField.setText(I18N.tr("1:{0}",Math.round(scaleDenominator)));
validate(); // Resize and layout controls
}
private class FormattedTextFieldVerifier extends InputVerifier {
private void invalidateUserInput() {
setScaleDenominator(scaleValue);
}
@Override
public boolean verify(JComponent input) {
if (input instanceof JTextField) {
LOGGER.debug("Verify scale user input..");
JTextField ftf = (JTextField) input;
String text = ftf.getText();
NumberFormat ft = NumberFormat.getIntegerInstance(); //Use default locale
String[] scaleParts = text.split(":");
if(scaleParts.length!=2) {
//More or Less than a single ':' character
LOGGER.error(I18N.tr("The format of a scale is 1:number"));
invalidateUserInput();
} else {
try {
if(ft.parse(scaleParts[0]).intValue()==1) {
setUserDefinedScaleDenominator(ft.parse(scaleParts[1]).longValue());
LOGGER.debug("User scale input accepted..");
} else {
throw new ParseException(I18N.tr("The only accepted value on nominator is 1"), 0);
}
} catch( ParseException ex) {
//Do not send the exception, the user has not to see the traceback
LOGGER.error(ex.getLocalizedMessage());
invalidateUserInput();
} catch (PropertyVetoException ex) {
//Don't know why but something catch the
//Vetoed by the MapEditor
LOGGER.error(ex.getLocalizedMessage());
invalidateUserInput();
}
}
}
return true;
}
@Override
public boolean shouldYieldFocus(JComponent input) {
return verify(input);
}
}
}