/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014-2015, 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.style; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.embed.swing.SwingFXUtils; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.DialogPane; import javafx.scene.control.SpinnerValueFactory; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn.CellDataFeatures; import javafx.scene.control.TableView; import javafx.scene.image.ImageView; import javafx.stage.Modality; import org.geotoolkit.display2d.GO2Utilities; import org.geotoolkit.display2d.service.DefaultGlyphService; import static org.geotoolkit.gui.javafx.style.FXStyleElementController.getStyleFactory; import org.geotoolkit.gui.javafx.util.FXDeleteTableColumn; import org.geotoolkit.gui.javafx.util.FXEditTableColumn; import org.geotoolkit.gui.javafx.util.FXMoveDownTableColumn; import org.geotoolkit.gui.javafx.util.FXMoveUpTableColumn; import org.geotoolkit.gui.javafx.util.FXUtilities; import org.geotoolkit.map.MapLayer; import org.geotoolkit.style.StyleConstants; import org.opengis.metadata.citation.OnlineResource; import org.opengis.style.ExternalGraphic; import org.opengis.style.Graphic; import org.opengis.style.GraphicalSymbol; import org.opengis.style.Mark; import org.opengis.style.PointSymbolizer; /** * * @author Johann Sorel (Geomatys) */ public class FXGraphic extends FXStyleElementController<Graphic>{ @FXML protected FXNumberExpression uiSize; @FXML protected FXNumberExpression uiOpacity; @FXML protected FXNumberExpression uiRotation; @FXML protected FXAnchorPoint uiAnchor; @FXML protected FXDisplacement uiDisplacement; @FXML protected Button uiAddMark; @FXML protected Button uiAddExternal; @FXML protected TableView<GraphicalSymbol> uiTable; @FXML void addMark(ActionEvent event) { final GraphicalSymbol mark = getStyleFactory().mark( getFilterFactory().literal("circle"), StyleConstants.DEFAULT_FILL, StyleConstants.DEFAULT_STROKE); uiTable.getItems().add(mark); } @FXML void addExternal(ActionEvent event) { try { final GraphicalSymbol external = getStyleFactory().externalGraphic(new URL("file:/..."), "image/png"); uiTable.getItems().add(external); } catch (MalformedURLException ex) { //won't happen throw new RuntimeException(ex.getMessage(),ex); } } @Override public Class<Graphic> getEditedClass() { return Graphic.class; } @Override public Graphic newValue() { return getStyleFactory().graphic(); } private void resetValue(){ if(updating) return; value.set(getStyleFactory().graphic( new ArrayList<>(uiTable.getItems()), uiOpacity.valueProperty().get(), uiSize.valueProperty().get(), uiRotation.valueProperty().get(), uiAnchor.valueProperty().get(), uiDisplacement.valueProperty().get())); } @Override public void initialize() { super.initialize(); FXUtilities.hideTableHeader(uiTable); final ChangeListener changeListener = (ObservableValue observable, Object oldValue, Object newValue) -> resetValue(); uiOpacity.getEditor().getSpinner().setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 1, 1, 0.1)); uiSize.getEditor().getSpinner().setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, Double.MAX_VALUE, 16, 1)); uiSize.valueProperty().addListener(changeListener); uiOpacity.valueProperty().addListener(changeListener); uiRotation.valueProperty().addListener(changeListener); uiAnchor.valueProperty().addListener(changeListener); uiDisplacement.valueProperty().addListener(changeListener); uiTable.setItems(FXCollections.observableArrayList()); uiTable.getItems().addListener((ListChangeListener<GraphicalSymbol>) c -> Platform.runLater(this::resetValue)); final TableColumn<GraphicalSymbol, GraphicalSymbol> previewCol = new TableColumn<>(); previewCol.setEditable(true); previewCol.setPrefWidth(60); previewCol.setMinWidth(40); previewCol.setCellValueFactory((CellDataFeatures<GraphicalSymbol, GraphicalSymbol> param) -> new SimpleObjectProperty<>((GraphicalSymbol) param.getValue())); previewCol.setCellFactory((TableColumn<GraphicalSymbol, GraphicalSymbol> p) -> new GlyphButton()); uiTable.getColumns().add(previewCol); uiTable.getColumns().add(new FXEditTableColumn((Object o) -> openGraphicalSymbolEditor((GraphicalSymbol)o))); uiTable.getColumns().add(new FXMoveUpTableColumn()); uiTable.getColumns().add(new FXMoveDownTableColumn()); uiTable.getColumns().add(new FXDeleteTableColumn(false)); uiTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); uiTable.setTableMenuButtonVisible(false); FXStyleElementController.configureAdvancedProperty(uiAnchor); } @Override public void setLayer(MapLayer layer) { super.setLayer(layer); uiSize.setLayer(layer); uiOpacity.setLayer(layer); uiRotation.setLayer(layer); uiAnchor.setLayer(layer); uiDisplacement.setLayer(layer); } @Override protected void updateEditor(Graphic graphic) { uiSize.valueProperty().setValue(graphic.getSize()); uiOpacity.valueProperty().setValue(graphic.getOpacity()); uiRotation.valueProperty().setValue(graphic.getRotation()); uiAnchor.valueProperty().setValue(graphic.getAnchorPoint()); uiDisplacement.valueProperty().setValue(graphic.getDisplacement()); uiTable.getItems().setAll(graphic.graphicalSymbols()); } private void openGraphicalSymbolEditor(final GraphicalSymbol graphicalSymbol){ final FXStyleElementController graphicalSymbolEditor = FXStyleElementEditor.findEditor(graphicalSymbol); graphicalSymbolEditor.valueProperty().setValue(graphicalSymbol); graphicalSymbolEditor.setLayer(layer); uiTable.getSelectionModel().select(graphicalSymbol); graphicalSymbolEditor.valueProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { uiTable.getItems().replaceAll((GraphicalSymbol t) -> { if(t==oldValue) return (GraphicalSymbol) newValue; else return t; }); resetValue(); } }); final DialogPane pane = new DialogPane(); pane.setContent(graphicalSymbolEditor); pane.getButtonTypes().add(ButtonType.CLOSE); final Dialog dialog = new Dialog(); dialog.setDialogPane(pane); dialog.initModality(Modality.APPLICATION_MODAL); dialog.setResizable(true); dialog.show(); } private class GlyphButton extends TableCell<GraphicalSymbol, GraphicalSymbol> { @Override protected void updateItem(GraphicalSymbol item, boolean empty) { super.updateItem(item, empty); updateGlyph(item); setText(""); if (item instanceof Mark) { final Mark m = (Mark) item; setText(m.getWellKnownName().toString()); } else if (item instanceof ExternalGraphic) { final ExternalGraphic m = (ExternalGraphic) item; final OnlineResource res = m.getOnlineResource(); if(res != null && res.getLinkage() != null){ setText(String.valueOf(res.getLinkage().getPath())); } } } private void updateGlyph(final GraphicalSymbol graphicalSymbol){ if(graphicalSymbol==null){ setGraphic(null); return; } final Graphic graphic = GO2Utilities.STYLE_FACTORY.graphic( Collections.singletonList(graphicalSymbol), StyleConstants.DEFAULT_GRAPHIC_OPACITY, GO2Utilities.FILTER_FACTORY.literal(16), StyleConstants.DEFAULT_GRAPHIC_ROTATION, StyleConstants.DEFAULT_ANCHOR_POINT, StyleConstants.DEFAULT_DISPLACEMENT); final PointSymbolizer ps = GO2Utilities.STYLE_FACTORY.pointSymbolizer(graphic, null); final BufferedImage img = DefaultGlyphService.create(ps, new Dimension(18, 18), null); setGraphic(new ImageView(SwingFXUtils.toFXImage(img, null))); } } }