Skip to content
Snippets Groups Projects
Commit 2a9ca324 authored by George Adrian Stoica's avatar George Adrian Stoica
Browse files

added tooltip to marker; this should fix issue #10

parent 57fa16fa
No related branches found
No related tags found
1 merge request!6Issue 11 allow user to enter and update metadata about the latlong points
Pipeline #52466 passed with stage
in 2 minutes and 16 seconds
package simpleex.ui;
import com.fasterxml.jackson.databind.ObjectMapper;
import fxmapcontrol.Location;
import fxmapcontrol.MapBase;
import fxmapcontrol.MapItemsControl;
import fxmapcontrol.MapNode;
import fxmapcontrol.MapProjection;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.util.Callback;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Slider;
import simpleex.core.LatLong;
import simpleex.json.LatLongsModule;
/*
@startuml
class AbstractFxAppController
class LatLongs
class BorderPane
class "ListView<LatLong>" as ListView
class "fxmapcontrol.MapBase" as MapBase
BorderPane *--> ListView: "left"
BorderPane *--> MapBase: "center"
AbstractFxAppController --> MapBase: "mapView"
AbstractFxAppController --> ListView: "locationListView"
@enduml
*/
/**
* The controller for the app.
* @author hal
*
*/
public abstract class AbstractFxAppController {
private LatLongsDataAccess dataAccess;
protected LatLongsDataAccess getDataAccess() {
return dataAccess;
}
protected void setDataAccess(final LatLongsDataAccess dataAccess) {
this.dataAccess = dataAccess;
if (locationListView != null) {
updateLocationViewList(0);
}
}
@FXML
private ListView<LatLong> locationListView;
@FXML
private MapBase mapView;
private MapItemsControl<MapNode> markersParent;
private MapMarker marker = null;
private DraggableNodeController draggableMapController = null;
private DraggableNodeController draggableMarkerController = null;
@FXML
private Slider zoomSlider;
@FXML
private void initialize() {
// map stuff
// mapView.getChildren().add(MapTileLayer.getOpenStreetMapLayer());
zoomSlider.valueProperty()
.addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
zoomSlider.setValue(8);
markersParent = new MapItemsControl<MapNode>();
mapView.getChildren().add(markersParent);
draggableMapController = new DraggableNodeController(this::handleMapDragged);
draggableMapController.setImmediate(true);
draggableMapController.attach(mapView);
draggableMarkerController = new DraggableNodeController(this::handleMarkerDragged);
// the location list
locationListView.getSelectionModel().selectedIndexProperty()
.addListener((prop, oldValue, newValue) -> updateMapMarker(true));
//connect the cell renderer to the list
locationListView.setCellFactory(listView -> new LatLongCell());
}
private void handleMapDragged(final Node node, final double dx, final double dy) {
final MapProjection projection = mapView.getProjection();
final Point2D point = projection.locationToViewportPoint(mapView.getCenter());
final Location newCenter = projection.viewportPointToLocation(point.add(-dx, -dy));
mapView.setCenter(newCenter);
}
private void handleMarkerDragged(final Node node, final double dx, final double dy) {
final MapProjection projection = mapView.getProjection();
final Point2D point = projection.locationToViewportPoint(marker.getLocation());
final Location newLocation = projection.viewportPointToLocation(point.add(dx, dy));
dataAccess.setLatLong(locationListView.getSelectionModel().getSelectedIndex(),
location2LatLong(newLocation));
updateLocationViewListSelection(false);
}
private LatLong location2LatLong(final Location newLocation) {
return new LatLong(newLocation.getLatitude(), newLocation.getLongitude());
}
private void updateMapMarker(final boolean centerOnMarker) {
final int num = locationListView.getSelectionModel().getSelectedIndex();
if (num < 0) {
markersParent.getItems().clear();
if (draggableMarkerController != null) {
draggableMarkerController.detach(marker);
}
marker = null;
} else {
final LatLong latLong = dataAccess.getLatLong(num);
if (marker == null) {
marker = new MapMarker(latLong);
markersParent.getItems().add(marker);
if (draggableMarkerController != null) {
draggableMarkerController.attach(marker);
}
} else {
marker.setLocation(latLong);
}
if (centerOnMarker) {
mapView.setCenter(marker.getLocation());
}
}
}
@FXML
void handleAddLocation() {
final Location center = mapView.getCenter();
final LatLong latLong = location2LatLong(center);
final int pos = dataAccess.addLatLong(latLong);
updateLocationViewList(pos);
}
private void updateLocationViewListSelection(final Boolean updateMapMarker) {
final int selectedIndex = locationListView.getSelectionModel().getSelectedIndex();
locationListView.getItems().set(selectedIndex, dataAccess.getLatLong(selectedIndex));
if (updateMapMarker != null) {
updateMapMarker(updateMapMarker);
}
}
protected void updateLocationViewList(int selectedIndex) {
final LatLong[] latLongs = dataAccess.getAllLatLongs().toArray(new LatLong[0]);
final int oldSelectionIndex = locationListView.getSelectionModel().getSelectedIndex();
locationListView.setItems(FXCollections.observableArrayList(latLongs));
if (selectedIndex < 0 || selectedIndex >= latLongs.length) {
selectedIndex = oldSelectionIndex;
}
if (selectedIndex >= 0 && selectedIndex < latLongs.length) {
locationListView.getSelectionModel().select(selectedIndex);
}
}
private ObjectMapper objectMapper;
/**
* Gets the ObjectMapper used by this controller.
* @return the ObjectMapper used by this controller
*/
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new LatLongsModule());
}
return objectMapper;
}
protected void showExceptionDialog(final String message) {
final Alert alert = new Alert(AlertType.ERROR, message, ButtonType.CLOSE);
alert.showAndWait();
}
protected void showExceptionDialog(final String message, final Exception e) {
showExceptionDialog(message + ": " + e.getLocalizedMessage());
}
}
package simpleex.ui;
import java.util.Iterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import fxmapcontrol.Location;
import fxmapcontrol.MapBase;
import fxmapcontrol.MapItemsControl;
import fxmapcontrol.MapNode;
import fxmapcontrol.MapProjection;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.OverrunStyle;
import javafx.scene.control.Slider;
import javafx.scene.control.Tooltip;
import simpleex.core.LatLong;
import simpleex.core.MetaData;
import simpleex.json.LatLongsModule;
/*
@startuml
class AbstractFxAppController
class LatLongs
class BorderPane
class "ListView<LatLong>" as ListView
class "fxmapcontrol.MapBase" as MapBase
BorderPane *--> ListView: "left"
BorderPane *--> MapBase: "center"
AbstractFxAppController --> MapBase: "mapView"
AbstractFxAppController --> ListView: "locationListView"
@enduml
*/
/**
* The controller for the app.
* @author hal
*
*/
public abstract class AbstractFxAppController {
private LatLongsDataAccess dataAccess;
protected LatLongsDataAccess getDataAccess() {
return dataAccess;
}
protected void setDataAccess(final LatLongsDataAccess dataAccess) {
this.dataAccess = dataAccess;
if (locationListView != null) {
updateLocationViewList(0);
}
}
@FXML
private ListView<LatLong> locationListView;
@FXML
private MapBase mapView;
private MapItemsControl<MapNode> markersParent;
private MapMarker marker = null;
private DraggableNodeController draggableMapController = null;
private DraggableNodeController draggableMarkerController = null;
private Tooltip markerTooltip = null;
@FXML
private Slider zoomSlider;
@FXML
private void initialize() {
// map stuff
// mapView.getChildren().add(MapTileLayer.getOpenStreetMapLayer());
zoomSlider.valueProperty()
.addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
zoomSlider.setValue(8);
markersParent = new MapItemsControl<MapNode>();
mapView.getChildren().add(markersParent);
draggableMapController = new DraggableNodeController(this::handleMapDragged);
draggableMapController.setImmediate(true);
draggableMapController.attach(mapView);
draggableMarkerController = new DraggableNodeController(this::handleMarkerDragged);
// the location list
locationListView.getSelectionModel().selectedIndexProperty()
.addListener((prop, oldValue, newValue) -> updateMapMarker(true));
//connect the cell renderer to the list
locationListView.setCellFactory(listView -> new LatLongCell());
}
private void handleMapDragged(final Node node, final double dx, final double dy) {
final MapProjection projection = mapView.getProjection();
final Point2D point = projection.locationToViewportPoint(mapView.getCenter());
final Location newCenter = projection.viewportPointToLocation(point.add(-dx, -dy));
mapView.setCenter(newCenter);
}
private void handleMarkerDragged(final Node node, final double dx, final double dy) {
final MapProjection projection = mapView.getProjection();
final Point2D point = projection.locationToViewportPoint(marker.getLocation());
final Location newLocation = projection.viewportPointToLocation(point.add(dx, dy));
dataAccess.setLatLong(locationListView.getSelectionModel().getSelectedIndex(),
location2LatLong(newLocation));
updateLocationViewListSelection(false);
}
private LatLong location2LatLong(final Location newLocation) {
return new LatLong(newLocation.getLatitude(), newLocation.getLongitude());
}
private void updateMapMarker(final boolean centerOnMarker) {
final int num = locationListView.getSelectionModel().getSelectedIndex();
if (num < 0) {
markersParent.getItems().clear();
if (draggableMarkerController != null) {
draggableMarkerController.detach(marker);
}
marker = null;
} else {
final LatLong latLong = dataAccess.getLatLong(num);
if (marker == null) {
marker = new MapMarker(latLong);
markersParent.getItems().add(marker);
if (draggableMarkerController != null) {
draggableMarkerController.attach(marker);
}
} else {
marker.setLocation(latLong);
}
if (centerOnMarker) {
mapView.setCenter(marker.getLocation());
}
}
prepareMarkerTooltip();
}
void prepareMarkerTooltip() {
if ((marker != null) && (this.markerTooltip != null)) {
Tooltip.uninstall(marker, markerTooltip);
}
Tooltip tooltip = new Tooltip();
tooltip.setPrefWidth(300.0);
tooltip.setWrapText(true);
tooltip.setTextOverrun(OverrunStyle.ELLIPSIS);
tooltip.setStyle(" -fx-background: rgba(255, 237, 131);\r\n" +
" -fx-text-fill: black;\r\n" +
" -fx-background-color: rgba(255, 237, 131, 0.8);\r\n" +
" -fx-background-radius: 6px;\r\n" +
" -fx-background-insets: 0;\r\n" +
" -fx-padding: 0.667em 0.75em 0.667em 0.75em; /* 10px */\r\n" +
" -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.5) , 10, 0.0 , 0 , 3 );\r\n" +
" -fx-font-size: 0.85em;");
final int num = locationListView.getSelectionModel().getSelectedIndex();
if (num >= 0) {
final LatLong latLong = dataAccess.getLatLong(num);
String tooltipText = "";
if(latLong.hasMetaData()) {
if(latLong.getMetaData().hasProperty(MetaData.NAME_PROPERTY)) {
tooltipText += latLong.getMetaData().getProperty(MetaData.NAME_PROPERTY) +"\n";
}
tooltipText += latLong.toString()+"\n";
if(latLong.getMetaData().hasProperty(MetaData.DESCRIPTION_PROPERTY)) {
tooltipText += latLong.getMetaData().getProperty(MetaData.DESCRIPTION_PROPERTY) +"\n";
}
MetaData metaData = latLong.getMetaData();
final Iterator<String> props = metaData.propertyNames();
if (props.hasNext()) {
String propString = "\n";
while (props.hasNext()) {
String propName = props.next();
if((propName != MetaData.NAME_PROPERTY)
&&(propName != MetaData.DESCRIPTION_PROPERTY)) {
propString += propName + ":" + metaData.getProperty(propName) + "\n";
}
}
if(!propString.isBlank()) tooltipText += propString + "\n";
}
final Iterator<String> tags = metaData.tags();
if (tags.hasNext()) {
String tagString = "\n| ";
while (tags.hasNext()) {
tagString += tags.next() + " | ";
}
tooltipText += tagString + "\n";
}
} else {
tooltipText += latLong.toString();
}
tooltip.setText(tooltipText);
}
this.markerTooltip = tooltip;
Tooltip.install(marker, tooltip);
}
@FXML
void handleAddLocation() {
final Location center = mapView.getCenter();
final LatLong latLong = location2LatLong(center);
final int pos = dataAccess.addLatLong(latLong);
updateLocationViewList(pos);
}
private void updateLocationViewListSelection(final Boolean updateMapMarker) {
final int selectedIndex = locationListView.getSelectionModel().getSelectedIndex();
locationListView.getItems().set(selectedIndex, dataAccess.getLatLong(selectedIndex));
if (updateMapMarker != null) {
updateMapMarker(updateMapMarker);
}
}
protected void updateLocationViewList(int selectedIndex) {
final LatLong[] latLongs = dataAccess.getAllLatLongs().toArray(new LatLong[0]);
final int oldSelectionIndex = locationListView.getSelectionModel().getSelectedIndex();
locationListView.setItems(FXCollections.observableArrayList(latLongs));
if (selectedIndex < 0 || selectedIndex >= latLongs.length) {
selectedIndex = oldSelectionIndex;
}
if (selectedIndex >= 0 && selectedIndex < latLongs.length) {
locationListView.getSelectionModel().select(selectedIndex);
}
}
private ObjectMapper objectMapper;
/**
* Gets the ObjectMapper used by this controller.
* @return the ObjectMapper used by this controller
*/
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new LatLongsModule());
}
return objectMapper;
}
protected void showExceptionDialog(final String message) {
final Alert alert = new Alert(AlertType.ERROR, message, ButtonType.CLOSE);
alert.showAndWait();
}
protected void showExceptionDialog(final String message, final Exception e) {
showExceptionDialog(message + ": " + e.getLocalizedMessage());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment