/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014, 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.javafx.render2d; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.NumberFormat; import java.util.Arrays; import java.util.Date; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.event.EventHandler; import javafx.scene.control.ColorPicker; import javafx.scene.control.ComboBox; import javafx.scene.control.ToggleButton; import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; import javafx.scene.paint.Color; import javafx.util.converter.LongStringConverter; import org.apache.sis.geometry.DirectPosition2D; import org.controlsfx.control.StatusBar; import org.geotoolkit.display.canvas.AbstractCanvas2D; import org.geotoolkit.display2d.canvas.painter.SolidColorPainter; import org.geotoolkit.gui.javafx.crs.FXAxisView; import org.geotoolkit.gui.javafx.crs.FXCRSButton; import org.geotoolkit.gui.javafx.util.FXUtilities; import org.geotoolkit.internal.GeotkFX; import org.geotoolkit.internal.Loggers; import org.geotoolkit.temporal.object.TemporalConstants; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; /** * * @author Johann Sorel (Geomatys) */ public class FXCoordinateBar extends GridPane { private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(); private final FXMap map; private final PropertyChangeListener listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { final String propertyName = evt.getPropertyName(); if(AbstractCanvas2D.OBJECTIVE_CRS_KEY.equals(propertyName)){ //update crs button crsButton.crsProperty().set((CoordinateReferenceSystem)evt.getNewValue()); }else if(AbstractCanvas2D.ENVELOPE_KEY.equals(propertyName)){ //range slider final Date[] range = map.getCanvas().getTemporalRange(); if(range==null){ sliderview.rangeMinProperty().set(null); sliderview.rangeMaxProperty().set(null); }else{ final boolean wasNull = sliderview.rangeMinProperty().get() == null; final double min = range[0].getTime(); final double max = range[1]!=null ? range[1].getTime() : min; sliderview.rangeMinProperty().set(min); sliderview.rangeMaxProperty().set(max); if(wasNull){ //zoom on selection sliderview.moveTo((max+min/2.0)); } } } //update scale box Platform.runLater(() -> { scaleCombo.valueProperty().removeListener(action); try { final double scale = map.getCanvas().getGeographicScale(); scaleCombo.setValue((long)scale); scaleCombo.valueProperty().addListener(action); } catch (TransformException ex) { Loggers.JAVAFX.log(Level.WARNING, null, ex); } }); } }; private final ChangeListener action = new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { if (map != null) { try { map.getCanvas().setGeographicScale((Long)newValue); } catch (TransformException ex) { Loggers.JAVAFX.log(Level.WARNING, null, ex); } } } }; private final StatusBar statusBar = new StatusBar(); private final ComboBox scaleCombo = new ComboBox(); private final ColorPicker colorPicker = new ColorPicker(Color.WHITE); private final FXCRSButton crsButton = new FXCRSButton(); private final ToggleButton sliderButton = new ToggleButton(null, new ImageView(GeotkFX.ICON_SLIDERS)); private final FXAxisView sliderview = new FXAxisView(); public FXCoordinateBar(FXMap map) { this.map = map; colorPicker.setStyle("-fx-color-label-visible:false;"); statusBar.setMaxWidth(Double.MAX_VALUE); add(statusBar, 0, 1); final ColumnConstraints col0 = new ColumnConstraints(); col0.setHgrow(Priority.ALWAYS); final RowConstraints row0 = new RowConstraints(); row0.setVgrow(Priority.ALWAYS); final RowConstraints row1 = new RowConstraints(); row1.setVgrow(Priority.NEVER); getColumnConstraints().addAll(col0); getRowConstraints().addAll(row0,row1); sliderview.scaleProperty().set( (1.0/TemporalConstants.DAY_MS)*30 ); sliderview.visibleProperty().bind(sliderButton.selectedProperty()); sliderButton.setOnAction((ActionEvent event) -> { getChildren().remove(sliderview); if(sliderButton.isSelected()){ add(sliderview, 0, 0, 1, 1); } }); final ChangeListener rangeListener = new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { try { if(newValue==null){ map.getCanvas().setTemporalRange(null,null); }else{ Number minValue = sliderview.rangeMinProperty().get(); Number maxValue = sliderview.rangeMaxProperty().get(); if(minValue!=null && maxValue!=null && minValue.doubleValue() > maxValue.doubleValue()){ //avoid an invalid range maxValue = minValue; } map.getCanvas().setTemporalRange( minValue!=null ? new Date(minValue.longValue()) : null, maxValue!=null ? new Date(maxValue.longValue()) : null); } } catch (TransformException ex) { Loggers.JAVAFX.log(Level.INFO, ex.getMessage(), ex); } } }; sliderview.rangeMinProperty().addListener(rangeListener); sliderview.rangeMaxProperty().addListener(rangeListener); statusBar.getLeftItems().add(sliderButton); scaleCombo.getItems().addAll( 1000l, 5000l, 20000l, 50000l, 100000l, 500000l); scaleCombo.setEditable(true); scaleCombo.setConverter(new LongStringConverter()); statusBar.getRightItems().add(scaleCombo); statusBar.getRightItems().add(colorPicker); statusBar.getRightItems().add(crsButton); map.addEventHandler(MouseEvent.ANY, new myListener()); if (this.map != null) { this.map.getCanvas().addPropertyChangeListener(listener); } colorPicker.setOnAction(new EventHandler() { public void handle(Event t) { if (map != null) { map.getCanvas().setBackgroundPainter(new SolidColorPainter(FXUtilities.toSwingColor(colorPicker.getValue()))); map.getCanvas().repaint(); } } }); crsButton.crsProperty().setValue(map.getCanvas().getObjectiveCRS()); crsButton.crsProperty().addListener((ObservableValue<? extends CoordinateReferenceSystem> observable, CoordinateReferenceSystem oldValue, CoordinateReferenceSystem newValue) -> { try { if(newValue!=null){ map.getCanvas().setObjectiveCRS(newValue); } } catch (TransformException ex) { Loggers.JAVAFX.log(Level.INFO, ex.getMessage(), ex); } }); // Set button tooltips sliderButton.setTooltip(new Tooltip(GeotkFX.getString(FXCoordinateBar.class, "temporalTooltip"))); statusBar.setTooltip(new Tooltip(GeotkFX.getString(FXCoordinateBar.class, "coordinateTooltip"))); scaleCombo.setTooltip(new Tooltip(GeotkFX.getString(FXCoordinateBar.class, "scaleTooltip"))); colorPicker.setTooltip(new Tooltip(GeotkFX.getString(FXCoordinateBar.class, "bgColorTooltip"))); crsButton.setTooltip(new Tooltip(GeotkFX.getString(FXCoordinateBar.class, "crsTooltip"))); } public void setCrsButtonVisible(boolean visible){ if(statusBar.getRightItems().contains(crsButton)){ statusBar.getRightItems().remove(crsButton); }else{ statusBar.getRightItems().add(crsButton); } } public boolean isCrsButtonVisible(){ return crsButton.isVisible(); } /** * TODO change this, we should be able to control multiple crs axis at the same time. * * @return temporal axis crs viewer */ public FXAxisView getSliderview() { return sliderview; } /** * Set scale values displayed in the right corner combo box. * * @param scales predefined scale values */ public void setScaleBoxValues(Long[] scales){ scaleCombo.getItems().setAll(Arrays.asList(scales)); } private class myListener implements EventHandler<MouseEvent>{ @Override public void handle(MouseEvent event) { final Point2D pt = new Point2D.Double(event.getX(), event.getY()); Point2D coord = new DirectPosition2D(); try { coord = map.getCanvas().getObjectiveToDisplay().inverseTransform(pt, coord); } catch (NoninvertibleTransformException ex) { statusBar.setText(""); 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())); statusBar.setText(sb.toString()); } } }