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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new a3b8326446 Move to `MapContextview` the widgets controlling the
coverage appearence. Move to the status bar the label which was showing the CRS
name.
a3b8326446 is described below
commit a3b83264468f82d9cf4a39503336d8492cec14db
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Mar 30 17:56:23 2026 +0200
Move to `MapContextview` the widgets controlling the coverage appearence.
Move to the status bar the label which was showing the CRS name.
---
.../apache/sis/gui/coverage/CoverageControls.java | 98 +++++----------
.../apache/sis/gui/coverage/StyleController.java | 92 +++++++++++++-
.../apache/sis/gui/coverage/ViewAndControls.java | 10 +-
.../org/apache/sis/gui/internal/Resources.java | 5 +
.../apache/sis/gui/internal/Resources.properties | 1 +
.../sis/gui/internal/Resources_fr.properties | 1 +
.../main/org/apache/sis/gui/internal/Styles.java | 6 +
.../main/org/apache/sis/gui/map/MapMenu.java | 25 ++--
.../main/org/apache/sis/gui/map/StatusBar.java | 136 ++++++++++++++++-----
9 files changed, 258 insertions(+), 116 deletions(-)
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
index a3ea19acd9..f53be4ff3a 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
@@ -18,16 +18,10 @@ package org.apache.sis.gui.coverage;
import java.util.Locale;
import javafx.application.Platform;
-import javafx.scene.control.TitledPane;
-import javafx.scene.control.ChoiceBox;
-import javafx.scene.control.Label;
-import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.VBox;
-import javafx.scene.layout.Priority;
+import javafx.scene.control.TitledPane;
+import javafx.beans.value.ObservableObjectValue;
import javafx.collections.ObservableList;
-import org.apache.sis.image.Interpolation;
import org.apache.sis.coverage.Category;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.storage.GridCoverageResource;
@@ -36,8 +30,6 @@ import org.apache.sis.gui.dataset.WindowHandler;
import org.apache.sis.gui.map.MapMenu;
import org.apache.sis.gui.map.style.MapLayer;
import org.apache.sis.gui.map.style.MapContextView;
-import org.apache.sis.gui.internal.GUIUtilities;
-import org.apache.sis.gui.internal.Styles;
import org.apache.sis.gui.internal.Resources;
import org.apache.sis.gui.internal.DataStoreOpener;
import org.apache.sis.gui.internal.BackgroundThreads;
@@ -69,24 +61,9 @@ final class CoverageControls extends ViewAndControls {
private final StyleController style;
/**
- * The control showing categories and their colors for the current
coverage.
- */
- private final TableView<Category> categoryTable;
-
- /**
- * The control used for selecting a color ramp for a given category.
- */
- private final CoverageStyling styling;
-
- /**
- * The control used for selecting a color stretching mode.
- */
- private final ChoiceBox<Stretching> stretching;
-
- /**
- * The control used for selecting the interpolation method.
+ * Tool tip for the reference system shown in the status bar.
*/
- private final ChoiceBox<Interpolation> interpolation;
+ private final Tooltip referenceSystemTooltip;
/**
* Creates a new set of coverage controls.
@@ -105,6 +82,14 @@ final class CoverageControls extends ViewAndControls {
final MapMenu menu = new MapMenu(view);
menu.addReferenceSystems(owner.referenceSystems);
menu.addCopyOptions(status);
+ final ObservableObjectValue<String> selectedReferenceSystem =
menu.selectedReferenceSystem().orElse(null);
+ if (selectedReferenceSystem == null) {
+ referenceSystemTooltip = null;
+ } else {
+ referenceSystemTooltip = new
Tooltip(resources.getString(Resources.Keys.SelectCrsByContextMenu));
+ selectedReferenceSystem.addListener((p,o,n) ->
notifyReferenceSystemChanged(n, status.positionReferenceSystemName().get()));
+ status.positionReferenceSystemName().addListener((p,o,n) ->
notifyReferenceSystemChanged(selectedReferenceSystem.get(), n));
+ }
/*
* "Layers" section with the following controls:
* - Tree of layers associated to the coverage (styling, isolines,
visual indication of loaded tiles).
@@ -112,43 +97,6 @@ final class CoverageControls extends ViewAndControls {
final var layers = new MapContextView(resources);
style = new StyleController(view);
layers.setRootItem(style);
- /*
- * "Display" section with the following controls:
- * - Current CRS
- * - Interpolation
- * - Color stretching
- * - Colors for each category
- */
- final VBox displayPane;
- { // Block for making variables locale to this scope.
- final Label crsControl = new Label();
- crsControl.setPadding(CONTENT_MARGIN);
- crsControl.setTooltip(new
Tooltip(resources.getString(Resources.Keys.SelectCrsByContextMenu)));
- menu.selectedReferenceSystem().ifPresent((text) ->
crsControl.textProperty().bind(text));
- /*
- * Creates a "Values" sub-section with the following controls:
- * - Interpolation
- * - Color stretching
- */
- interpolation = InterpolationConverter.button(view);
- stretching = Stretching.createButton((p,o,n) ->
view.setStretching(n));
- final GridPane valuesControl = Styles.createControlGrid(0,
- label(vocabulary, Vocabulary.Keys.Interpolation,
interpolation),
- label(vocabulary, Vocabulary.Keys.Stretching, stretching));
- /*
- * Creates a "Categories" section with the category table.
- */
- styling = new CoverageStyling(view);
- categoryTable = styling.createCategoryTable(resources, vocabulary);
- VBox.setVgrow(categoryTable, Priority.ALWAYS);
- /*
- * All sections put together.
- */
- displayPane = new VBox(
- labelOfGroup(vocabulary, Vocabulary.Keys.ReferenceSystem,
crsControl, true), crsControl,
- labelOfGroup(vocabulary, Vocabulary.Keys.Values,
valuesControl, false), valuesControl,
- labelOfGroup(vocabulary, Vocabulary.Keys.Categories,
categoryTable, false), categoryTable);
- }
/*
* "Isolines" section with the following controls:
* - Colors for each isoline levels
@@ -170,8 +118,7 @@ final class CoverageControls extends ViewAndControls {
*/
final TitledPane deferred; // Control to be built
only if requested.
controlPanes = new TitledPane[] {
- new TitledPane(vocabulary.getString(Vocabulary.Keys.Layers),
layers.getView()),
- new TitledPane(vocabulary.getString(Vocabulary.Keys.Display),
displayPane),
+ new TitledPane(vocabulary.getString(Vocabulary.Keys.Layers),
layers.getView()),
new TitledPane(resources.getString(Resources.Keys.Windows),
windows.getView()),
deferred = new
TitledPane(vocabulary.getString(Vocabulary.Keys.Properties), null)
};
@@ -186,6 +133,19 @@ final class CoverageControls extends ViewAndControls {
setView(view.getView());
}
+ /**
+ * Invoked in JavaFX thread after the reference system of the coverage or
of the status bar changed.
+ *
+ * @param coverage the name of the reference system of the rendered
coverage.
+ * @param coordinates the name of the reference system of coordinates
shown in the status bar.
+ */
+ private void notifyReferenceSystemChanged(String coverage, String
coordinates) {
+ if (coverage != null && !coverage.equalsIgnoreCase(coordinates)) {
+ coverage =
Resources.forLocale(owner.getLocale()).getString(Resources.Keys.MismatchedRS);
+ }
+ status.setDefaultMessage(coverage, coverage == null ? null :
referenceSystemTooltip);
+ }
+
/**
* Invoked in JavaFX thread after {@link CoverageCanvas} resource or
coverage property value changed.
* This method updates the controls GUI with new information available and
update the corresponding
@@ -215,7 +175,7 @@ final class CoverageControls extends ViewAndControls {
}
});
});
- final ObservableList<Category> items = categoryTable.getItems();
+ final ObservableList<Category> items = style.categoryTable.getItems();
if (coverage == null) {
items.clear();
} else {
@@ -242,8 +202,6 @@ final class CoverageControls extends ViewAndControls {
* This is invoked when the user click on "New window" button.
*/
final void copyStyling(final CoverageControls c) {
- styling.copyStyling(c.styling);
- GUIUtilities.copySelection(c.stretching, stretching);
- GUIUtilities.copySelection(c.interpolation, interpolation);
+ style.copyStyling(c.style);
}
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
index 514f2aa75e..11db66b533 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
@@ -16,14 +16,26 @@
*/
package org.apache.sis.gui.coverage;
+import java.util.Locale;
import javafx.scene.control.TreeItem;
+import javafx.scene.control.ChoiceBox;
import javafx.collections.ObservableList;
-import org.apache.sis.gui.internal.Resources;
+import javafx.scene.control.TableView;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
import org.apache.sis.gui.map.style.MapItem;
import org.apache.sis.gui.map.style.ItemController;
import org.apache.sis.gui.map.style.MapLayer;
+import org.apache.sis.gui.internal.Resources;
+import org.apache.sis.gui.internal.Styles;
+import org.apache.sis.gui.internal.GUIUtilities;
+import org.apache.sis.image.Interpolation;
+import org.apache.sis.coverage.Category;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.tiling.TiledGridCoverageResource;
+import org.apache.sis.util.resources.Vocabulary;
/**
@@ -37,6 +49,32 @@ final class StyleController extends ItemController {
*/
private final CoverageCanvas canvas;
+ /**
+ * The controls for configuring the appearance of the grid coverage.
+ * Created when first needed.
+ */
+ private final Region configurationPanel;
+
+ /**
+ * The control showing categories and their colors for the current
coverage.
+ */
+ final TableView<Category> categoryTable;
+
+ /**
+ * The control used for selecting a color ramp for a given category.
+ */
+ private final CoverageStyling styling;
+
+ /**
+ * The control used for selecting a color stretching mode.
+ */
+ private final ChoiceBox<Stretching> stretching;
+
+ /**
+ * The control used for selecting the interpolation method.
+ */
+ private final ChoiceBox<Interpolation> interpolation;
+
/**
* Whether to show a visual indication of which tiles are read.
* Creates when first needed.
@@ -54,6 +92,58 @@ final class StyleController extends ItemController {
setSelected(true);
setIndependent(true);
selectedProperty().addListener((p,o,n) ->
canvas.setCoverageHidden(!n));
+ /*
+ * "Display" section with the following controls:
+ * - Current CRS
+ * - Interpolation
+ * - Color stretching
+ * - Colors for each category
+ */
+ final Locale locale = canvas.getLocale();
+ final Resources resources = Resources.forLocale(locale);
+ final Vocabulary vocabulary = Vocabulary.forLocale(locale);
+ /*
+ * Creates a "Values" sub-section with the following controls:
+ * - Interpolation
+ * - Color stretching
+ */
+ interpolation = InterpolationConverter.button(canvas);
+ stretching = Stretching.createButton((p,o,n) ->
canvas.setStretching(n));
+ final GridPane valuesControl = Styles.createControlGrid(0,
+ CoverageControls.label(vocabulary,
Vocabulary.Keys.Interpolation, interpolation),
+ CoverageControls.label(vocabulary, Vocabulary.Keys.Stretching,
stretching));
+ /*
+ * Creates a "Categories" section with the category table.
+ */
+ styling = new CoverageStyling(canvas);
+ categoryTable = styling.createCategoryTable(resources, vocabulary);
+ VBox.setVgrow(categoryTable, Priority.ALWAYS);
+ /*
+ * All sections put together.
+ */
+ configurationPanel = new VBox(
+ CoverageControls.labelOfGroup(vocabulary,
Vocabulary.Keys.Values, valuesControl, true), valuesControl,
+ CoverageControls.labelOfGroup(vocabulary,
Vocabulary.Keys.Categories, categoryTable, false), categoryTable);
+ }
+
+ /**
+ * Returns a panel of JavaFX controls for configuring the appearance of
the grid coverage.
+ *
+ * @return the configuration panel for the grid coverage.
+ */
+ @Override
+ protected Region getConfigurationPanel() {
+ return configurationPanel;
+ }
+
+ /**
+ * Copies the styling configuration from the given controls.
+ * This is invoked when the user click on "New window" button.
+ */
+ final void copyStyling(final StyleController c) {
+ styling.copyStyling(c.styling);
+ GUIUtilities.copySelection(c.stretching, stretching);
+ GUIUtilities.copySelection(c.interpolation, interpolation);
}
/**
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ViewAndControls.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ViewAndControls.java
index 5c3d3d6817..090742a76d 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ViewAndControls.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ViewAndControls.java
@@ -17,6 +17,7 @@
package org.apache.sis.gui.coverage;
import javafx.geometry.Insets;
+import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
@@ -31,7 +32,6 @@ import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.collections.ObservableList;
-import org.apache.sis.gui.internal.Styles;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
@@ -63,12 +63,6 @@ abstract class ViewAndControls {
*/
private static final Insets NEXT_CAPTION_MARGIN = new Insets(30, 0, 6, 0);
- /**
- * Same indentation as {@link Styles#FORM_INSETS}, but without the space
on other sides.
- * This is used when the node is outside a group created by {@link
Styles#createControlGrid(int, Label...)}.
- */
- static final Insets CONTENT_MARGIN = new Insets(0, 0, 0,
Styles.FORM_INSETS.getLeft());
-
/**
* Index of {@link #sliceSelector} in the list of children of {@link
#viewAndNavigation}.
*/
@@ -256,6 +250,8 @@ abstract class ViewAndControls {
static Label labelOfGroup(final IndexedResourceBundle vocabulary, final
short key, final Region group, final boolean isFirst) {
final Label label = new Label(vocabulary.getString(key));
label.setPadding(isFirst ? CAPTION_MARGIN : NEXT_CAPTION_MARGIN);
+ label.setMaxWidth(Double.MAX_VALUE);
+ label.setAlignment(Pos.CENTER);
label.setLabelFor(group);
label.setFont(fontOfGroup());
return label;
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.java
index d7a52b71bd..0d2fd76e96 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.java
@@ -301,6 +301,11 @@ public class Resources extends IndexedResourceBundle {
*/
public static final short Mercator = 44;
+ /**
+ * The image and the status bar use different reference systems.
+ */
+ public static final short MismatchedRS = 80;
+
/**
* New window
*/
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.properties
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.properties
index 3238bad540..8ca1f85558 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.properties
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources.properties
@@ -68,6 +68,7 @@ IsolinesInRange = Generate isolines at constant
interval\nstarting from g
LicenseAgreement = Do you accept the license shown below?
Loading = Loading\u2026
Mercator = Mercator
+MismatchedRS = The image and the status bar use different reference
systems.
MainWindow = Main window
NewWindow = New window
NoFeatureTypeInfo = No feature type information.
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources_fr.properties
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources_fr.properties
index b4d044e410..189cb170cd 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources_fr.properties
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Resources_fr.properties
@@ -73,6 +73,7 @@ IsolinesInRange = G\u00e9n\u00e8re des isolignes
\u00e0 intervalle consta
LicenseAgreement = Acceptez-vous la licence ci-dessous?
Loading = Chargement\u2026
Mercator = Mercator
+MismatchedRS = L\u2019image et la barre d\u2019\u00e9tat utilisent
des syst\u00e8mes de r\u00e9f\u00e9rence diff\u00e9rents.
MainWindow = Fen\u00eatre principale
NewWindow = Nouvelle fen\u00eatre
NoFeatureTypeInfo = Pas d\u2019information sur le type d\u2019entit\u00e9.
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
index b2255ec381..1cfe119d32 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
@@ -68,6 +68,12 @@ public final class Styles {
*/
public static final Color SELECTED_TEXT = Color.WHITE;
+ /**
+ * Color of text for information purpose but which are not the main topic.
+ * This is using a lighter color for avoiding to be a source of
distraction.
+ */
+ public static final Color FAINT_TEXT = Color.GRAY;
+
/**
* Color of the text saying that data are in process of being loaded.
*/
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/MapMenu.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/MapMenu.java
index dc9314100e..3c943cdbc7 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/MapMenu.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/MapMenu.java
@@ -54,7 +54,7 @@ import org.apache.sis.referencing.IdentifiedObjects;
* In current implementation, there is no mechanism for removing menu items.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.7
* @since 1.1
*/
public class MapMenu extends ContextMenu {
@@ -65,10 +65,20 @@ public class MapMenu extends ContextMenu {
/**
* A handler for controlling the contextual menu.
- * Created when first needed.
+ * Created when first needed and should be considered final after
initialization.
*/
private MapCanvas.MenuHandler menuHandler;
+ /**
+ * Name of the currently selected reference system.
+ * This reference needs to be cached because JavaFX binds properties using
weak references.
+ * If the users invoke {@link #selectedReferenceSystem()} only for
registering listeners without
+ * storing the returned instance, their listeners will be lost unless we
keep a reference here.
+ *
+ * @see #selectedReferenceSystem()
+ */
+ private ObservableObjectValue<String> selectedReferenceSystem;
+
/**
* Groups of menu items that have been added. Bits in this mask are set
when {@link #addCopyOptions(StatusBar)}
* {@link #addReferenceSystems(RecentReferenceSystems)} or similar methods
are invoked. Each {@code addFoo(…)}
@@ -170,23 +180,22 @@ public class MapMenu extends ContextMenu {
getItems().add(coordinates);
}
-
/**
- * Returns an observable value for showing the currently selected CRS as a
text.
+ * Returns an observable value for showing the name of the currently
selected <abbr>CRS</abbr>.
* The value is absent if {@link
#addReferenceSystems(RecentReferenceSystems)} has never been invoked.
*
- * @return the currently selected CRS as a text.
+ * @return the currently selected <abbr>CRS</abbr> as a text.
*
* @see #addReferenceSystems(RecentReferenceSystems)
*/
public Optional<ObservableObjectValue<String>> selectedReferenceSystem() {
- if (menuHandler != null) {
+ if (selectedReferenceSystem == null && menuHandler != null) {
final ObjectProperty<ReferenceSystem> selectedCrsProperty =
menuHandler.selectedCrsProperty;
if (selectedCrsProperty != null) {
- return Optional.of(new SelectedCRS(selectedCrsProperty,
canvas.getLocale()));
+ selectedReferenceSystem = new SelectedCRS(selectedCrsProperty,
canvas.getLocale());
}
}
- return Optional.empty();
+ return Optional.ofNullable(selectedReferenceSystem);
}
/**
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
index 396b1a2eda..9ef30b67b7 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
@@ -49,6 +49,7 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectPropertyBase;
+import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -78,17 +79,17 @@ import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.portrayal.RenderException;
-import org.apache.sis.util.Classes;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.Exceptions;
+import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.internal.shared.Strings;
import org.apache.sis.measure.Quantities;
import org.apache.sis.measure.Units;
-import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.logging.Logging;
import org.apache.sis.gui.Widget;
import org.apache.sis.gui.referencing.RecentReferenceSystems;
import org.apache.sis.gui.internal.BackgroundThreads;
@@ -125,7 +126,7 @@ import org.opengis.coordinate.MismatchedDimensionException;
* {@link #setLocalCoordinates(double, double)} explicitly instead.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
* @since 1.1
*/
public class StatusBar extends Widget implements EventHandler<MouseEvent> {
@@ -154,18 +155,33 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
/**
* The container of controls making the status bar.
- * Contains {@link #message}, {@link #position} and {@link #sampleValues}.
+ * Contains {@link #message}, {@link #position} and {@link #sampleValues}
in that order.
*
* @see #getView()
*/
private final HBox view;
+ /**
+ * The default message to show when there is no error or operation in
progress.
+ *
+ * @see #setDefaultMessage(String, Tooltip)
+ */
+ private String defaultMessage;
+
+ /**
+ * The tool tip to show on the default message, or {@code null} if none.
+ */
+ private Tooltip defaultMessageTeooltip;
+
/**
* Message to write in the middle of the status bar.
- * This component usually has nothing to show; it is used mostly for error
messages.
+ * This component can be used, for example, for error messages.
* It takes all the space before {@link #position}.
*
* @see #getMessage()
+ * @see #setInfoMessage(String)
+ * @see #setErrorMessage(String, Throwable)
+ * @see #setDefaultMessage(String, Tooltip)
*/
private final Label message;
@@ -270,6 +286,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
* directly instead. We omit the "Property" suffix for making this
operation more natural.
*
* @see #position
+ * @see #positionReferenceSystemName()
*/
public final ReadOnlyObjectProperty<ReferenceSystem>
positionReferenceSystem;
@@ -408,6 +425,15 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
*/
protected final Label position;
+ /**
+ * Tool tip of {@link #position} showing the name of the reference system
of the coordinates.
+ * The text property of this tool tip may be used outside this class.
+ *
+ * @see #positionReferenceSystem
+ * @see #positionReferenceSystemName()
+ */
+ private final Tooltip positionReferenceSystemName;
+
/**
* Maximal length of {@linkplain #position} text found so far. This is
used for detecting when
* to compute a minimal {@linkplain #position} width for making sure that
the coordinates stay
@@ -502,6 +528,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
position = new Label();
position.setAlignment(Pos.CENTER_RIGHT);
position.setTextAlignment(TextAlignment.RIGHT);
+ positionReferenceSystemName = new Tooltip();
view = new HBox(6, message, position);
view.setPadding(PADDING);
@@ -1057,7 +1084,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
targetCoordinates = target; // Assign only after above succeed.
formatAsIdentifiers = null;
format.setGroundAccuracy(Quantities.max(accuracy,
lowestAccuracy.get()));
- setTooltip(crs);
+ setCoordinateTooltip(crs);
/*
* Prepare the text to show when the mouse is outside the canvas area.
* We will write axis abbreviations, for example "(φ, λ)".
@@ -1271,7 +1298,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
fullOperationSearchRequired = null;
outsideText = null;
setErrorMessage(null, null);
- setTooltip(coder.getReferenceSystem());
+ setCoordinateTooltip(coder.getReferenceSystem());
position.setText(identifier);
((PositionSystem) positionReferenceSystem).fireValueChangedEvent();
rewritePosition(current);
@@ -1570,18 +1597,23 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
/**
* Sets the tooltip text to show when the mouse cursor is over the
coordinate values.
*/
- private void setTooltip(final ReferenceSystem crs) {
- String text = IdentifiedObjects.getDisplayName(crs, getLocale());
- Tooltip tp = null;
- if (text != null) {
- tp = position.getTooltip();
- if (tp == null) {
- tp = new Tooltip(text);
- } else {
- tp.setText(text);
- }
- }
- position.setTooltip(tp);
+ private void setCoordinateTooltip(final ReferenceSystem crs) {
+ final String text = IdentifiedObjects.getDisplayName(crs, getLocale());
+ positionReferenceSystemName.setText(text);
+ position.setTooltip(text != null ? positionReferenceSystemName : null);
+ }
+
+ /**
+ * Returns a property for the name of the reference system used by the
coordinates.
+ * This is the localized name of the {@link #positionReferenceSystem}
property.
+ *
+ * @return a property for the name of the reference system used by the
coordinates.
+ *
+ * @see #positionReferenceSystem
+ * @since 1.7
+ */
+ public ReadOnlyStringProperty positionReferenceSystemName() {
+ return positionReferenceSystemName.textProperty();
}
/**
@@ -1589,12 +1621,58 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
*
* @return the current message, or an empty value if none.
*
+ * @see #setInfoMessage(String)
+ * @see #setErrorMessage(String, Throwable)
+ * @see #setDefaultMessage(String, Tooltip)
+ *
* @since 1.3
*/
public Optional<String> getMessage() {
return Optional.ofNullable(message.getText());
}
+ /**
+ * Sets the message, or restore the default message if the given text is
null.
+ *
+ * @param text the text, or {@code null} if none.
+ * @param textFill the color to use for the text.
+ */
+ private void setMessage(String text, Color textFill) {
+ Tooltip tooltip = null;
+ if (text == null) {
+ text = defaultMessage;
+ textFill = Styles.FAINT_TEXT;
+ tooltip = defaultMessageTeooltip;
+ }
+ message.setVisible(text != null);
+ message.setText(text);
+ message.setTextFill(textFill);
+ message.setTooltip(tooltip);
+ }
+
+ /**
+ * Sets the default message to show when there is no error or operation in
progress.
+ * If {@link #setInfoMessage(String)} or {@link #setErrorMessage(String,
Throwable)}
+ * is invoked, the informative or error message has precedence over this
default message.
+ * When the informative or error message is reset to {@code null}, the
default message is restored.
+ *
+ * @param text message to show when there is no other kind of
message, or {@code null} if none.
+ * @param tooltip optional tool tip to show on the default message, or
{@code null} if none.
+ *
+ * @since 1.7
+ */
+ public void setDefaultMessage(String text, final Tooltip tooltip) {
+ text = Strings.trimOrNull(text);
+ defaultMessage = text;
+ defaultMessageTeooltip = tooltip;
+ // Use the text fill as a way to identify that the message is not an
error or information.
+ if (message.getText() == null || message.getTextFill() ==
Styles.FAINT_TEXT) {
+ message.setTextFill(Styles.FAINT_TEXT);
+ message.setText(text);
+ message.setTooltip(tooltip);
+ }
+ }
+
/**
* Shows or hides an informative message on the status bar.
* The message should be temporary, for example for telling that a loading
is in progress.
@@ -1604,11 +1682,8 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
* @since 1.3
*/
public void setInfoMessage(String text) {
- text = Strings.trimOrNull(text);
- message.setVisible(text != null);
+ setMessage(Strings.trimOrNull(text), Styles.LOADING_TEXT);
message.setGraphic(null);
- message.setText(text);
- message.setTextFill(Styles.LOADING_TEXT);
}
/**
@@ -1624,15 +1699,16 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
text = Strings.trimOrNull(text);
Button more = null;
if (details != null) {
- final String alert = (text != null) ? text : cause(details);
+ if (text == null) {
+ text = cause(details);
+ }
+ final String alert = text; // Because lambda functions want final
variable.
more = new Button(Styles.ERROR_DETAILS_ICON);
more.setOnAction((e) -> ExceptionReporter.show(getView(),
Resources.forLocale(getLocale()).getString(Resources.Keys.ErrorDetails), alert,
details));
}
- message.setVisible(text != null);
+ setMessage(text, Styles.ERROR_TEXT);
message.setGraphic(more);
- message.setText(text);
- message.setTextFill(Styles.ERROR_TEXT);
}
/**
@@ -1669,7 +1745,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
/**
* Returns a string representation of the message of the given exception.
* If the exception is a wrapper, the exception cause is taken.
- * If there is no message, the exception class name is returned.
+ * If there is no message, the exception class name is used.
*
* @param e the exception.
* @return the exception message or class name.
@@ -1680,7 +1756,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
}
String text = Exceptions.getLocalizedMessage(e, getLocale());
if (text == null) {
- text = Classes.getShortClassName(e);
+ text =
CharSequences.camelCaseToWords(e.getClass().getSimpleName(), false).toString();
}
return text;
}