You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2020/07/02 16:52:21 UTC
[sis] branch geoapi-4.0 updated (ffb556a -> 1792a41)
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a change to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git.
from ffb556a Add GeodeticCalculator.createProjectionAroundStart() method.
new 3de9eb3 Update links to EPSG terms of use.
new e981308 Move the handling of context menu from CoverageCanvas to MapCanvas parent class.
new d139a0b Hide context menu when click happen outside.
new 1792a41 More robust computation of space needed for showing sample values.
The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
NOTICE | 2 +-
.../apache/sis/gui/coverage/CoverageCanvas.java | 188 ------------------
.../apache/sis/gui/coverage/CoverageControls.java | 21 +-
.../java/org/apache/sis/gui/map/MapCanvas.java | 219 ++++++++++++++++++++-
.../main/java/org/apache/sis/gui/map/MapMenu.java | 138 +++++++++++++
.../org/apache/sis/gui/map/ValuesUnderCursor.java | 26 ++-
.../sis-openoffice/src/main/unopkg/license.txt | 2 +-
.../factory/sql/epsg/DataScriptFormatter.java | 2 +-
.../sis/referencing/factory/sql/epsg/package.html | 2 +-
.../apache/sis/setup/InstallationResources.java | 4 +-
10 files changed, 377 insertions(+), 227 deletions(-)
create mode 100644 application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapMenu.java
[sis] 01/04: Update links to EPSG terms of use.
Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit 3de9eb32baf66a02fe39acc1b23136546f250d1a
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Jul 2 10:03:59 2020 +0200
Update links to EPSG terms of use.
---
NOTICE | 2 +-
application/sis-openoffice/src/main/unopkg/license.txt | 2 +-
.../apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java | 2 +-
.../java/org/apache/sis/referencing/factory/sql/epsg/package.html | 2 +-
.../src/main/java/org/apache/sis/setup/InstallationResources.java | 4 ++--
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/NOTICE b/NOTICE
index b6d81b3..3281099 100644
--- a/NOTICE
+++ b/NOTICE
@@ -39,7 +39,7 @@ http://junit.org/junit4/
-------------------------------------------------------------
The optional `non-free` group of modules contain geodetic data
collected by the International Association of Oil and Gas Producers.
-http://www.epsg.org/TermsOfUse.aspx
+https://epsg.org/terms-of-use.html
The optional `sis-javafx` module depends on JavaFX
published under GPL 2 with classpath exception.
diff --git a/application/sis-openoffice/src/main/unopkg/license.txt b/application/sis-openoffice/src/main/unopkg/license.txt
index d53a686..43547b5 100644
--- a/application/sis-openoffice/src/main/unopkg/license.txt
+++ b/application/sis-openoffice/src/main/unopkg/license.txt
@@ -8,6 +8,6 @@ Unless required by applicable law or agreed to in writing, software distributed
This software may contain geodetic dataset distributed under EPSG terms of use. You may not use the EPSG Facilities or any of them in whole or in part unless you agree to these Terms of Use. You may obtain a copy of EPSG terms of use at
- http://www.epsg.org/TermsOfUse.aspx
+ https://epsg.org/terms-of-use.html
Data and information provided in the EPSG facilities are provided "as is" without warranty of any kind, either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java
index f3ba867..d2e3870 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java
@@ -186,7 +186,7 @@ public final class DataScriptFormatter extends ScriptRunner {
try (LineNumberReader in = new LineNumberReader(new InputStreamReader(Files.newInputStream(inputFile), StandardCharsets.UTF_8))) {
out.write("---\n" +
"--- Copyright International Association of Oil and Gas Producers (IOGP)\n" +
- "--- See http://www.epsg.org/TermsOfUse.aspx (a copy is in ./LICENSE.txt).\n" +
+ "--- See https://epsg.org/terms-of-use.html (a copy is in ./LICENSE.txt).\n" +
"---\n" +
"--- This file has been reformatted (without any change in the data) for the needs of Apache SIS project.\n" +
"--- See org.apache.sis.referencing.factory.sql.epsg.DataScriptFormatter.\n" +
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
index cf5a089..356c93c 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
@@ -32,7 +32,7 @@
This dataset provides definitions for thousands of Coordinate Reference Systems (CRS),
together with parameter values for thousands of Coordinate Operations between various pairs of CRS.
EPSG is maintained by the <a href="http://www.iogp.org/">International Association of Oil and Gas Producers</a> (IOGP)
- Surveying & Positioning Committee and is subject to <a href="http://www.epsg.org/TermsOfUse.aspx">EPSG terms of use</a>.
+ Surveying & Positioning Committee and is subject to <a href="https://epsg.org/terms-of-use.html">EPSG terms of use</a>.
Because of incompatibilities between EPSG terms of use and Apache 2 license, the EPSG geodetic dataset is not distributed
by default with Apache SIS. A copy of the dataset is provided in a separated module in a separated source code repository.
The Maven identifier of that module is <code>org.apache.sis.non-free:sis-epsg</code> and the source repository is located at
diff --git a/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java b/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
index d9a37ef..fdf1ed6 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
@@ -33,7 +33,7 @@ import java.io.BufferedReader;
* But the weight of those files (about 2.4 Mb) is unnecessary for users who do not live in North America.</li>
* <li>On the other hand, the <a href="http://www.epsg.org/">EPSG geodetic dataset</a> is important for most users.
* Codes like {@code "EPSG:4326"} became a <i>de-facto</i> standard in various places like <cite>Web Map Services</cite>,
- * images encoded in GeoTIFF format, <i>etc</i>. But the <a href="http://www.epsg.org/TermsOfUse.aspx">EPSG terms of use</a>
+ * images encoded in GeoTIFF format, <i>etc</i>. But the <a href="https://epsg.org/terms-of-use.html">EPSG terms of use</a>
* are more restrictive than the Apache license and require that we inform the users about those conditions.</li>
* </ul></div>
*
@@ -111,7 +111,7 @@ public abstract class InstallationResources {
* <th>License</th>
* </tr><tr>
* <td>{@code "EPSG"}</td>
- * <td>A copy of the <a href="http://www.epsg.org/TermsOfUse.aspx">http://www.epsg.org/TermsOfUse.aspx</a> page.</td>
+ * <td>A copy of the <a href="https://epsg.org/terms-of-use.html">https://epsg.org/terms-of-use.html</a> page.</td>
* </tr><tr>
* <td>{@code "Embedded"}</td>
* <td>Above EPSG license.</td>
[sis] 02/04: Move the handling of context menu from CoverageCanvas
to MapCanvas parent class.
Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit e981308a7b2530a56b15fbd1576a6b6eb8b659b2
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Jul 2 11:45:10 2020 +0200
Move the handling of context menu from CoverageCanvas to MapCanvas parent class.
---
.../apache/sis/gui/coverage/CoverageCanvas.java | 188 -------------------
.../apache/sis/gui/coverage/CoverageControls.java | 21 +--
.../java/org/apache/sis/gui/map/MapCanvas.java | 201 ++++++++++++++++++++-
.../main/java/org/apache/sis/gui/map/MapMenu.java | 138 ++++++++++++++
4 files changed, 341 insertions(+), 207 deletions(-)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
index fd6bfa8..ea13486 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java
@@ -24,33 +24,19 @@ import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
import javafx.scene.paint.Color;
-import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
-import javafx.scene.control.Menu;
-import javafx.scene.control.RadioMenuItem;
-import javafx.scene.control.ContextMenu;
-import javafx.scene.control.ToggleGroup;
-import javafx.scene.input.MouseEvent;
-import javafx.event.EventHandler;
import javafx.beans.DefaultProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
-import javafx.beans.value.ObservableValue;
-import javafx.beans.value.WritableValue;
-import javafx.beans.value.ChangeListener;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javax.measure.Quantity;
import javax.measure.quantity.Length;
import org.opengis.geometry.Envelope;
-import org.opengis.geometry.DirectPosition;
import org.opengis.util.FactoryException;
-import org.opengis.referencing.ReferenceSystem;
import org.opengis.referencing.operation.TransformException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.coverage.grid.GridCoverage;
@@ -60,19 +46,13 @@ import org.apache.sis.coverage.grid.ImageRenderer;
import org.apache.sis.internal.gui.ExceptionReporter;
import org.apache.sis.referencing.operation.matrix.AffineTransforms2D;
import org.apache.sis.referencing.operation.transform.LinearTransform;
-import org.apache.sis.referencing.IdentifiedObjects;
-import org.apache.sis.geometry.AbstractEnvelope;
-import org.apache.sis.geometry.DirectPosition2D;
import org.apache.sis.geometry.Envelope2D;
import org.apache.sis.image.PlanarImage;
import org.apache.sis.image.Interpolation;
import org.apache.sis.gui.map.MapCanvas;
import org.apache.sis.gui.map.MapCanvasAWT;
import org.apache.sis.gui.map.StatusBar;
-import org.apache.sis.gui.referencing.PositionableProjection;
-import org.apache.sis.gui.referencing.RecentReferenceSystems;
import org.apache.sis.internal.gui.GUIUtilities;
-import org.apache.sis.internal.gui.Resources;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.measure.Units;
@@ -181,141 +161,6 @@ public class CoverageCanvas extends MapCanvasAWT {
}
/**
- * Creates and register a contextual menu.
- *
- * @todo Consider moving to {@link org.apache.sis.gui.map.MapCanvas}.
- */
- final ObjectProperty<ReferenceSystem> createContextMenu(final RecentReferenceSystems referenceSystems) {
- final Resources resources = Resources.forLocale(getLocale());
- final MenuHandler handler = new MenuHandler();
- final Menu systemChoices = referenceSystems.createMenuItems(handler);
- final Menu localSystems = new Menu(resources.getString(Resources.Keys.CenteredProjection));
- for (final PositionableProjection projection : PositionableProjection.values()) {
- final RadioMenuItem item = new RadioMenuItem(projection.toString());
- item.setToggleGroup(handler.positionables);
- item.setOnAction((e) -> handler.createProjectedCRS(projection));
- localSystems.getItems().add(item);
- }
- handler.menu.getItems().setAll(systemChoices, localSystems);
- addPropertyChangeListener(OBJECTIVE_CRS_PROPERTY, handler);
- fixedPane.setOnMousePressed(handler);
- return handler.selectedProperty = RecentReferenceSystems.getSelectedProperty(systemChoices);
- }
-
- /**
- * Shows or hides the contextual menu when the right mouse button is clicked. This handler can determine
- * the geographic location where the click occurred. This information is used for changing the projection
- * while preserving approximately the location, scale and rotation of pixels around the mouse cursor.
- */
- @SuppressWarnings("serial") // Not intended to be serialized.
- private final class MenuHandler extends DirectPosition2D
- implements EventHandler<MouseEvent>, ChangeListener<ReferenceSystem>, PropertyChangeListener
- {
- /**
- * The property to update if a change of CRS occurs in the enclosing canvas. This property is provided
- * by {@link RecentReferenceSystems}, which listen to changes. Setting this property to a new value
- * causes the "Referencing systems" radio menus to change the item where the check mark appear.
- *
- * <p>This field is initialized by {@link #createContextMenu(RecentReferenceSystems)} and should be
- * considered final after initialization.</p>
- */
- ObjectProperty<ReferenceSystem> selectedProperty;
-
- /**
- * The group of {@link PositionableProjection} items for projections created on-the-fly at mouse position.
- * Those items are not managed by {@link RecentReferenceSystems} so they need to be handled there.
- */
- final ToggleGroup positionables;
-
- /**
- * The contextual menu to show or hide when mouse button is clicked on the canvas.
- */
- final ContextMenu menu;
-
- /**
- * {@code true} if we are in the process of setting a CRS generated by {@link PositionableProjection}.
- */
- private boolean isPositionableProjection;
-
- /**
- * Creates a new handler for contextual menu in enclosing canvas.
- */
- MenuHandler() {
- super(getDisplayCRS());
- menu = new ContextMenu();
- positionables = new ToggleGroup();
- }
-
- /**
- * Invoked when the user click on the canvas.
- * Shows the menu on right mouse click, hide otherwise.
- */
- @Override
- public void handle(final MouseEvent event) {
- if (event.isSecondaryButtonDown()) {
- x = event.getX();
- y = event.getY();
- menu.show((Pane) event.getSource(), event.getScreenX(), event.getScreenY());
- event.consume();
- } else {
- menu.hide();
- }
- }
-
- /**
- * Invoked when user selected a new coordinate reference system among the choices of predefined CRS.
- * Those CRS are the ones managed by {@link RecentReferenceSystems}, not the ones created on-the-fly.
- */
- @Override
- public void changed(final ObservableValue<? extends ReferenceSystem> property,
- final ReferenceSystem oldValue, final ReferenceSystem newValue)
- {
- if (newValue instanceof CoordinateReferenceSystem) {
- setObjectiveCRS((CoordinateReferenceSystem) newValue, this, property);
- }
- }
-
- /**
- * Invoked when user selected a projection centered on mouse position. Those CRS are generated on-the-fly
- * and are generally not on the list of CRS managed by {@link RecentReferenceSystems}.
- */
- final void createProjectedCRS(final PositionableProjection projection) {
- try {
- DirectPosition2D center = new DirectPosition2D();
- center = (DirectPosition2D) objectiveToDisplay.inverseTransform(this, center);
- center.setCoordinateReferenceSystem(getObjectiveCRS());
- CoordinateReferenceSystem crs = projection.createProjectedCRS(center);
- try {
- isPositionableProjection = true;
- setObjectiveCRS(crs, this, null);
- } finally {
- isPositionableProjection = false;
- }
- } catch (Exception e) {
- errorOccurred(e);
- final Resources i18n = Resources.forLocale(getLocale());
- ExceptionReporter.show(null, i18n.getString(Resources.Keys.CanNotUseRefSys_1, projection), e);
- }
- }
-
- /**
- * Invoked when a canvas property changed, typically after a new coverage has been selected.
- * The property of interest is {@value CoverageCanvas#OBJECTIVE_CRS_PROPERTY}.
- * This method updates the CRS selected in the contextual menu.
- */
- @Override
- public void propertyChange(final PropertyChangeEvent event) {
- final Object value = event.getNewValue();
- if (value instanceof CoordinateReferenceSystem) {
- selectedProperty.set((CoordinateReferenceSystem) value);
- }
- if (!isPositionableProjection) {
- positionables.selectToggle(null);
- }
- }
- }
-
- /**
* Returns the region containing the image view.
* The subclass is implementation dependent and may change in any future version.
*
@@ -690,39 +535,6 @@ public class CoverageCanvas extends MapCanvasAWT {
}
/**
- * Invoked when the user changed the CRS from a JavaFX control. If the CRS can not be set to the specified
- * value, then an error message is shown in the status bar and the property is reset to its previous value.
- *
- * @param crs the new Coordinate Reference System in which to transform all data before displaying.
- * @param anchor the point to keep at fixed display coordinates, or {@code null} for default value.
- * @param property the property to reset if the operation fails.
- */
- private void setObjectiveCRS(final CoordinateReferenceSystem crs, DirectPosition anchor,
- final ObservableValue<? extends ReferenceSystem> property)
- {
- final CoordinateReferenceSystem previous = getObjectiveCRS();
- if (crs != previous) try {
- if (anchor == null) {
- final Envelope2D bounds = getDisplayBounds();
- if (bounds != null) {
- anchor = AbstractEnvelope.castOrCopy(bounds).getMedian();
- }
- }
- setObjectiveCRS(crs, anchor);
- requestRepaint();
- } catch (Exception e) {
- if (property instanceof WritableValue<?>) {
- ((WritableValue<ReferenceSystem>) property).setValue(previous);
- }
- errorOccurred(e);
- final Locale locale = getLocale();
- final Resources i18n = Resources.forLocale(locale);
- ExceptionReporter.show(null, i18n.getString(Resources.Keys.CanNotUseRefSys_1,
- IdentifiedObjects.getDisplayName(crs, locale)), e);
- }
- }
-
- /**
* Invoked when an exception occurred while computing a transform but the painting process can continue.
*/
private static void unexpectedException(final Exception e) {
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
index e98811e..b4a39eb 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java
@@ -29,7 +29,6 @@ import javafx.scene.layout.VBox;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
-import javafx.beans.binding.ObjectBinding;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.ChoiceBox;
@@ -37,10 +36,9 @@ import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.util.StringConverter;
-import org.opengis.referencing.ReferenceSystem;
import org.apache.sis.coverage.grid.GridCoverage;
-import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.gui.referencing.RecentReferenceSystems;
+import org.apache.sis.gui.map.MapMenu;
import org.apache.sis.gui.map.StatusBar;
import org.apache.sis.image.Interpolation;
import org.apache.sis.internal.gui.Styles;
@@ -88,8 +86,8 @@ final class CoverageControls extends Controls {
view.statusBar = statusBar;
imageAndStatus = new BorderPane(view.getView());
imageAndStatus.setBottom(statusBar.getView());
- final ObjectProperty<ReferenceSystem> referenceSystem = view.createContextMenu(referenceSystems);
- final Locale locale = vocabulary.getLocale();
+ final MapMenu menu = new MapMenu(view);
+ menu.addReferenceSystems(referenceSystems);
/*
* "Display" section with the following controls:
* - Current CRS
@@ -106,16 +104,7 @@ final class CoverageControls extends Controls {
crsLabel.setFont(font);
crsLabel.setPadding(Styles.FORM_INSETS);
crsShown.setPadding(INDENT_OUTSIDE);
- crsShown.textProperty().bind(new ObjectBinding<String>() {
- /* Constructor */ {
- bind(referenceSystem);
- }
-
- /** Invoked when the reference system changed. */
- @Override protected String computeValue() {
- return IdentifiedObjects.getDisplayName(referenceSystem.get(), locale);
- }
- });
+ menu.selectedReferenceSystem().ifPresent((text) -> crsShown.textProperty().bind(text));
/*
* The pane containing controls will be divided in sections separated by labels:
* ones for values and one for colors.
@@ -124,7 +113,7 @@ final class CoverageControls extends Controls {
final int colorsHeader = 2;
final GridPane gp;
gp = Styles.createControlGrid(valuesHeader + 1,
- label(vocabulary, Vocabulary.Keys.Interpolation, createInterpolationButton(locale)),
+ label(vocabulary, Vocabulary.Keys.Interpolation, createInterpolationButton(vocabulary.getLocale())),
label(vocabulary, Vocabulary.Keys.Stretching, Stretching.createButton((p,o,n) -> view.setStyling(n))),
label(vocabulary, Vocabulary.Keys.Background, createBackgroundButton(background)));
/*
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
index 9ce058b..753f5a3 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
@@ -20,6 +20,8 @@ import java.util.Locale;
import java.util.Arrays;
import java.util.Objects;
import java.awt.geom.AffineTransform;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.layout.Pane;
@@ -33,14 +35,25 @@ import javafx.scene.input.GestureEvent;
import javafx.scene.Cursor;
import javafx.event.EventType;
import javafx.beans.Observable;
+import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WritableValue;
import javafx.concurrent.Task;
+import javafx.event.EventHandler;
+import javafx.scene.control.Menu;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.RadioMenuItem;
+import javafx.scene.control.ToggleGroup;
import javafx.scene.transform.Affine;
import javafx.scene.transform.NonInvertibleTransformException;
import org.opengis.geometry.Envelope;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.ReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -50,20 +63,27 @@ import org.apache.sis.referencing.operation.matrix.MatrixSIS;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.LinearTransform;
import org.apache.sis.referencing.cs.CoordinateSystems;
+import org.apache.sis.geometry.DirectPosition2D;
import org.apache.sis.geometry.Envelope2D;
+import org.apache.sis.geometry.AbstractEnvelope;
import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.gui.referencing.PositionableProjection;
+import org.apache.sis.gui.referencing.RecentReferenceSystems;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.gui.BackgroundThreads;
+import org.apache.sis.internal.gui.ExceptionReporter;
import org.apache.sis.internal.gui.GUIUtilities;
+import org.apache.sis.internal.gui.Resources;
import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.portrayal.PlanarCanvas;
import org.apache.sis.portrayal.RenderException;
+import org.apache.sis.referencing.IdentifiedObjects;
/**
@@ -494,10 +514,178 @@ public abstract class MapCanvas extends PlanarCanvas {
}
/**
- * Returns {@code true} if content changed since the last {@link #repaint()} execution.
+ * Creates and register a contextual menu.
+ *
+ * @return the property for the selected value, or {@code null} if none.
*/
- final boolean contentsChanged() {
- return contentChangeCount != renderedContentStamp;
+ final ObjectProperty<ReferenceSystem> createContextMenu(final ContextMenu menu,
+ final RecentReferenceSystems referenceSystems)
+ {
+ final Resources resources = Resources.forLocale(getLocale());
+ final MenuHandler handler = new MenuHandler(menu);
+ final Menu systemChoices = referenceSystems.createMenuItems(handler);
+ final Menu localSystems = new Menu(resources.getString(Resources.Keys.CenteredProjection));
+ for (final PositionableProjection projection : PositionableProjection.values()) {
+ final RadioMenuItem item = new RadioMenuItem(projection.toString());
+ item.setToggleGroup(handler.positionables);
+ item.setOnAction((e) -> handler.createProjectedCRS(projection));
+ localSystems.getItems().add(item);
+ }
+ menu.getItems().setAll(systemChoices, localSystems);
+ addPropertyChangeListener(OBJECTIVE_CRS_PROPERTY, handler);
+ fixedPane.setOnMousePressed(handler);
+ return handler.selectedProperty = RecentReferenceSystems.getSelectedProperty(systemChoices);
+ }
+
+ /**
+ * Shows or hides the contextual menu when the right mouse button is clicked. This handler can determine
+ * the geographic location where the click occurred. This information is used for changing the projection
+ * while preserving approximately the location, scale and rotation of pixels around the mouse cursor.
+ */
+ @SuppressWarnings("serial") // Not intended to be serialized.
+ private final class MenuHandler extends DirectPosition2D
+ implements EventHandler<MouseEvent>, ChangeListener<ReferenceSystem>, PropertyChangeListener
+ {
+ /**
+ * The property to update if a change of CRS occurs in the enclosing canvas. This property is provided
+ * by {@link RecentReferenceSystems}, which listen to changes. Setting this property to a new value
+ * causes the "Referencing systems" radio menus to change the item where the check mark appear.
+ *
+ * <p>This field is initialized by {@link #createContextMenu(ContextMenu, RecentReferenceSystems)}
+ * and should be considered final after initialization.</p>
+ */
+ ObjectProperty<ReferenceSystem> selectedProperty;
+
+ /**
+ * The group of {@link PositionableProjection} items for projections created on-the-fly at mouse position.
+ * Those items are not managed by {@link RecentReferenceSystems} so they need to be handled there.
+ */
+ final ToggleGroup positionables;
+
+ /**
+ * The contextual menu to show or hide when mouse button is clicked on the canvas.
+ */
+ private final ContextMenu menu;
+
+ /**
+ * {@code true} if we are in the process of setting a CRS generated by {@link PositionableProjection}.
+ */
+ private boolean isPositionableProjection;
+
+ /**
+ * Creates a new handler for contextual menu in enclosing canvas.
+ */
+ MenuHandler(final ContextMenu menu) {
+ super(getDisplayCRS());
+ this.menu = menu;
+ positionables = new ToggleGroup();
+ }
+
+ /**
+ * Invoked when the user click on the canvas.
+ * Shows the menu on right mouse click, hide otherwise.
+ */
+ @Override
+ public void handle(final MouseEvent event) {
+ if (event.isSecondaryButtonDown()) {
+ x = event.getX();
+ y = event.getY();
+ menu.show((Pane) event.getSource(), event.getScreenX(), event.getScreenY());
+ event.consume();
+ } else {
+ menu.hide();
+ }
+ }
+
+ /**
+ * Invoked when user selected a new coordinate reference system among the choices of predefined CRS.
+ * Those CRS are the ones managed by {@link RecentReferenceSystems}, not the ones created on-the-fly.
+ */
+ @Override
+ public void changed(final ObservableValue<? extends ReferenceSystem> property,
+ final ReferenceSystem oldValue, final ReferenceSystem newValue)
+ {
+ if (newValue instanceof CoordinateReferenceSystem) {
+ setObjectiveCRS((CoordinateReferenceSystem) newValue, this, property);
+ }
+ }
+
+ /**
+ * Invoked when user selected a projection centered on mouse position. Those CRS are generated on-the-fly
+ * and are generally not on the list of CRS managed by {@link RecentReferenceSystems}.
+ */
+ final void createProjectedCRS(final PositionableProjection projection) {
+ try {
+ DirectPosition2D center = new DirectPosition2D();
+ center = (DirectPosition2D) objectiveToDisplay.inverseTransform(this, center);
+ center.setCoordinateReferenceSystem(getObjectiveCRS());
+ CoordinateReferenceSystem crs = projection.createProjectedCRS(center);
+ try {
+ isPositionableProjection = true;
+ setObjectiveCRS(crs, this, null);
+ } finally {
+ isPositionableProjection = false;
+ }
+ } catch (Exception e) {
+ errorOccurred(e);
+ final Resources i18n = Resources.forLocale(getLocale());
+ ExceptionReporter.show(null, i18n.getString(Resources.Keys.CanNotUseRefSys_1, projection), e);
+ }
+ }
+
+ /**
+ * Invoked when a canvas property changed, typically after new data are shown.
+ * The property of interest is {@value MapCanvas#OBJECTIVE_CRS_PROPERTY}.
+ * This method updates the CRS selected in the contextual menu.
+ */
+ @Override
+ public void propertyChange(final PropertyChangeEvent event) {
+ final Object value = event.getNewValue();
+ if (value instanceof CoordinateReferenceSystem) {
+ selectedProperty.set((CoordinateReferenceSystem) value);
+ }
+ if (!isPositionableProjection) {
+ positionables.selectToggle(null);
+ }
+ }
+ }
+
+ /**
+ * Invoked when the user changed the CRS from a JavaFX control. If the CRS can not be set to the specified
+ * value, then an error message is shown in the status bar and the property is reset to its previous value.
+ *
+ * @param crs the new Coordinate Reference System in which to transform all data before displaying.
+ * @param anchor the point to keep at fixed display coordinates, or {@code null} for default value.
+ * @param property the property to reset if the operation fails.
+ */
+ private void setObjectiveCRS(final CoordinateReferenceSystem crs, DirectPosition anchor,
+ final ObservableValue<? extends ReferenceSystem> property)
+ {
+ final CoordinateReferenceSystem previous = getObjectiveCRS();
+ if (crs != previous) try {
+ /*
+ * If no anchor is specified, the first default is the center of the region currently visible
+ * in the canvas. If that center can not be determined neither, null anchor defaults to the
+ * point of interest (POI) managed by the Canvas parent class.
+ */
+ if (anchor == null) {
+ final Envelope2D bounds = getDisplayBounds();
+ if (bounds != null) {
+ anchor = AbstractEnvelope.castOrCopy(bounds).getMedian();
+ }
+ }
+ setObjectiveCRS(crs, anchor);
+ requestRepaint();
+ } catch (Exception e) {
+ if (property instanceof WritableValue<?>) {
+ ((WritableValue<ReferenceSystem>) property).setValue(previous);
+ }
+ errorOccurred(e);
+ final Locale locale = getLocale();
+ final Resources i18n = Resources.forLocale(locale);
+ ExceptionReporter.show(null, i18n.getString(Resources.Keys.CanNotUseRefSys_1,
+ IdentifiedObjects.getDisplayName(crs, locale)), e);
+ }
}
/**
@@ -641,6 +829,13 @@ public abstract class MapCanvas extends PlanarCanvas {
}
/**
+ * Returns {@code true} if content changed since the last {@link #repaint()} execution.
+ */
+ final boolean contentsChanged() {
+ return contentChangeCount != renderedContentStamp;
+ }
+
+ /**
* Requests the map to be rendered again, possibly with new data. Invoking this
* method does not necessarily causes the repaint process to start immediately.
* The request will be queued and executed at an arbitrary time.
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapMenu.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapMenu.java
new file mode 100644
index 0000000..39d7811
--- /dev/null
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapMenu.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.map;
+
+import java.util.Locale;
+import java.util.Optional;
+import javafx.scene.control.ContextMenu;
+import javafx.beans.binding.ObjectBinding;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.value.ObservableObjectValue;
+import org.opengis.referencing.ReferenceSystem;
+import org.apache.sis.gui.referencing.RecentReferenceSystems;
+import org.apache.sis.gui.referencing.PositionableProjection;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * A {@link ContextMenu} that can be shown in a {@link MapCanvas}.
+ * On construction, this menu is initially empty.
+ * Items can be added by the following method calls:
+ *
+ * <ul>
+ * <li>{@link #addReferenceSystems(RecentReferenceSystems)}:<ul>
+ * <li><cite>Reference system</cite> with some items from EPSG database.</li>
+ * <li><cite>Centered projection</cite> with the list of {@link PositionableProjection} items.</li>
+ * </ul></li>
+ * </ul>
+ *
+ * More choices may be added in a future versions.
+ * In current implementation, there is no mechanism for removing menu items.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ * @module
+ */
+public class MapMenu extends ContextMenu {
+ /**
+ * The canvas where this menu can be shown.
+ */
+ private final MapCanvas canvas;
+
+ /**
+ * The property for the selected coordinate reference system, created when first needed.
+ */
+ private ObjectProperty<ReferenceSystem> selectedSystem;
+
+ /**
+ * Whether {@link #addReferenceSystems(RecentReferenceSystems)} has been invoked.
+ */
+ private boolean hasCRS;
+
+ /**
+ * Creates an initially empty menu for the given canvas.
+ *
+ * @param canvas the canvas for which to create menus.
+ */
+ public MapMenu(final MapCanvas canvas) {
+ ArgumentChecks.ensureNonNull("canvas", canvas);
+ this.canvas = canvas;
+ }
+
+ /**
+ * Adds menu items for CRS selection. The menu items are in two groups:
+ *
+ * <ul>
+ * <li><cite>Reference system</cite> with some items from EPSG database.</li>
+ * <li><cite>Centered projection</cite> with the list of {@link PositionableProjection} items.</li>
+ * </ul>
+ *
+ * This method can be invoked at most once.
+ *
+ * @param preferences handler of menu items for selecting a CRS from a list of EPSG codes.
+ * Often {@linkplain RecentReferenceSystems#addUserPreferences() built from user preferences}.
+ * @throws IllegalStateException if this method has already been invoked.
+ */
+ public void addReferenceSystems(final RecentReferenceSystems preferences) {
+ ArgumentChecks.ensureNonNull("preferences", preferences);
+ if (hasCRS) {
+ throw new IllegalStateException();
+ }
+ hasCRS = true;
+ selectedSystem = canvas.createContextMenu(this, preferences);
+ }
+
+ /**
+ * Returns an observable value for showing the currently selected CRS as a text.
+ * The value is absent if {@link #addReferenceSystems(RecentReferenceSystems)} has never been invoked.
+ *
+ * @return the currently selected CRS as a text.
+ */
+ public Optional<ObservableObjectValue<String>> selectedReferenceSystem() {
+ if (selectedSystem != null) {
+ return Optional.of(new SelectedCRS(selectedSystem, canvas.getLocale()));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * Implementation of the value returned by {@link #selectedReferenceSystem()}.
+ * Implemented as a static class for reducing the number of direct references to {@link MapMenu}.
+ */
+ private static final class SelectedCRS extends ObjectBinding<String> {
+ /** The property for the selected coordinate reference system. */
+ private final ObjectProperty<ReferenceSystem> selectedSystem;
+
+ /** The locale to use for fetching CRS name. */
+ private final Locale locale;
+
+ /** Creates a new binding. */
+ SelectedCRS(final ObjectProperty<ReferenceSystem> selectedSystem, final Locale locale) {
+ this.selectedSystem = selectedSystem;
+ this.locale = locale;
+ bind(selectedSystem);
+ }
+
+ /** Invoked when the reference system changed. */
+ @Override protected String computeValue() {
+ return IdentifiedObjects.getDisplayName(selectedSystem.get(), locale);
+ }
+ }
+}
[sis] 03/04: Hide context menu when click happen outside.
Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit d139a0b009ffe279750563b48a073ec2f6c62379
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Jul 2 16:05:28 2020 +0200
Hide context menu when click happen outside.
---
.../main/java/org/apache/sis/gui/map/MapCanvas.java | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
index 753f5a3..d60be6b 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/MapCanvas.java
@@ -275,6 +275,11 @@ public abstract class MapCanvas extends PlanarCanvas {
private final ReadOnlyObjectWrapper<Throwable> error;
/**
+ * If a contextual menu is currently visible, that menu. Otherwise {@code null}.
+ */
+ private ContextMenu menuShown;
+
+ /**
* Creates a new canvas for JavaFX application.
*
* @param locale the locale to use for labels and some messages, or {@code null} for default.
@@ -334,6 +339,7 @@ public abstract class MapCanvas extends PlanarCanvas {
final double y = event.getY();
final EventType<? extends MouseEvent> type = event.getEventType();
if (type == MouseEvent.MOUSE_PRESSED && event.isPrimaryButtonDown()) {
+ hideContextMenu();
floatingPane.setCursor(Cursor.CLOSED_HAND);
floatingPane.requestFocus();
isDragging = true;
@@ -514,6 +520,16 @@ public abstract class MapCanvas extends PlanarCanvas {
}
/**
+ * If a context menu is currently shown, hide that menu. Otherwise does nothing.
+ */
+ private void hideContextMenu() {
+ if (menuShown != null) {
+ menuShown.hide();
+ menuShown = null;
+ }
+ }
+
+ /**
* Creates and register a contextual menu.
*
* @return the property for the selected value, or {@code null} if none.
@@ -587,10 +603,12 @@ public abstract class MapCanvas extends PlanarCanvas {
*/
@Override
public void handle(final MouseEvent event) {
+ hideContextMenu();
if (event.isSecondaryButtonDown()) {
x = event.getX();
y = event.getY();
menu.show((Pane) event.getSource(), event.getScreenX(), event.getScreenY());
+ menuShown = menu;
event.consume();
} else {
menu.hide();
[sis] 04/04: More robust computation of space needed for showing
sample values.
Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit 1792a41078b8df9a7238770f8a96298af77a6b4d
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Jul 2 16:49:50 2020 +0200
More robust computation of space needed for showing sample values.
---
.../org/apache/sis/gui/map/ValuesUnderCursor.java | 26 ++++++++++------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
index f0d2e84..6d3bb4c 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
@@ -264,12 +264,16 @@ public abstract class ValuesUnderCursor {
/**
* The text to show when cursor is outside coverage area. It should contain dimension names,
- * for example "(SST)". A {@code null} value means that {@link #onBandSelectionChanged()}
- * needs to be invoked.
+ * for example "(SST)". May be {@code null} if {@link #onBandSelectionChanged()} needs to be invoked.
*/
private String outsideText;
/**
+ * {@code true} if {@link #onBandSelectionChanged()} needs to be invoked again.
+ */
+ private boolean needsBandRefresh;
+
+ /**
* Creates a new provider of textual values for a {@link GridCoverage}.
*/
public FromCoverage() {
@@ -409,9 +413,7 @@ public abstract class ValuesUnderCursor {
});
}
valueChoices.getItems().setAll(menuItems);
- if (!onBandSelectionChanged()) {
- outsideText = null; // For forcing a new computation after canvas is added to scene graph.
- }
+ onBandSelectionChanged();
}
/**
@@ -466,9 +468,7 @@ public abstract class ValuesUnderCursor {
item.setSelected(selectedBands.get(index));
item.selectedProperty().addListener((p,o,n) -> {
selectedBands.set(index, n);
- if (!onBandSelectionChanged()) {
- outsideText = null; // Will be recomputed on next `evaluate(…)` call.
- }
+ onBandSelectionChanged();
});
return item;
}
@@ -484,7 +484,7 @@ public abstract class ValuesUnderCursor {
*/
@Override
public String evaluate(final DirectPosition point) {
- if (outsideText == null && evaluator != null) {
+ if (needsBandRefresh && evaluator != null) {
onBandSelectionChanged();
}
if (point != null) {
@@ -556,14 +556,12 @@ public abstract class ValuesUnderCursor {
* when the bands selection changed, either because of selection in contextual menu or because
* {@link ValuesUnderCursor} is providing data for a new coverage.
*
- * <p>We use {@link #outsideText} null value as a flag meaning meaning that this method needs
+ * <p>We use {@link #needsBandRefresh} as a flag meaning meaning that this method needs
* to be invoked. This method invocation sometime needs to be delayed because calculation of
* text width may be wrong (produce 0 values) if invoked before {@link StatusBar#sampleValues}
* label is added in the scene graph.</p>
- *
- * @return {@code true} on success, or {@code false} if this method should be invoked again.
*/
- private boolean onBandSelectionChanged() {
+ private void onBandSelectionChanged() {
final ObservableList<MenuItem> menus = valueChoices.getItems();
final List<SampleDimension> bands = evaluator.getCoverage().getSampleDimensions();
final StringBuilder names = new StringBuilder().append('(');
@@ -607,7 +605,7 @@ public abstract class ValuesUnderCursor {
others.add(other.getValue());
}
}
- return prototype(text, others);
+ needsBandRefresh = !prototype(text, others);
}
}