/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 3 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.crs; import java.awt.Color; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.embed.swing.SwingFXUtils; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; import javafx.scene.control.ScrollPane; import javafx.scene.control.SelectionMode; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TablePosition; import javafx.scene.control.TableView; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.CornerRadii; import javafx.util.Callback; import org.apache.sis.io.wkt.FormattableObject; import org.apache.sis.metadata.iso.citation.Citations; import org.geotoolkit.font.FontAwesomeIcons; import org.geotoolkit.font.IconBuilder; import org.geotoolkit.internal.GeotkFX; import org.geotoolkit.internal.Loggers; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.operation.ConicProjection; import org.opengis.referencing.operation.CylindricalProjection; import org.opengis.referencing.operation.OperationMethod; import org.opengis.referencing.operation.PlanarProjection; import org.opengis.referencing.operation.Projection; import org.opengis.util.FactoryException; /** * * @author Johann Sorel (Geomatys) */ public class FXCRSTable extends ScrollPane{ private static final Color COLOR = new Color(30, 150, 250); public static final Image ICON_GEO = SwingFXUtils.toFXImage(GeotkFX.getBufferedImage("proj_geo", new Dimension(16, 16)), null); public static final Image ICON_SQUARE = SwingFXUtils.toFXImage(GeotkFX.getBufferedImage("proj_square", new Dimension(16, 16)), null); public static final Image ICON_STEREO = SwingFXUtils.toFXImage(GeotkFX.getBufferedImage("proj_stereo", new Dimension(16, 16)), null); public static final Image ICON_UTM = SwingFXUtils.toFXImage(GeotkFX.getBufferedImage("proj_utm", new Dimension(16, 16)), null); public static final Image ICON_CONIC = SwingFXUtils.toFXImage(GeotkFX.getBufferedImage("proj_conic", new Dimension(16, 16)), null); public static final Image ICON_UNKNOWNED = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_QUESTION,16,COLOR),null); private final ObjectProperty<CoordinateReferenceSystem> crsProperty = new SimpleObjectProperty<>(); private final TableView<Code> uiTable = new TableView<>(); private List<Code> allValues; public FXCRSTable(){ uiTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); setContent(uiTable); setFitToHeight(true); setFitToWidth(true); //add a loader while we load datas final ProgressIndicator loading = new ProgressIndicator(); loading.setMaxWidth(60); loading.setMaxHeight(60); loading.setBackground(new Background(new BackgroundFill(new javafx.scene.paint.Color(0, 0, 0, 0), CornerRadii.EMPTY, Insets.EMPTY))); loading.setProgress(-1); uiTable.setPlaceholder(loading); uiTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); uiTable.setTableMenuButtonVisible(false); uiTable.getSelectionModel().getSelectedCells().addListener(new ListChangeListener<TablePosition>() { @Override public void onChanged(ListChangeListener.Change<? extends TablePosition> c) { final ObservableList<TablePosition> cells = uiTable.getSelectionModel().getSelectedCells(); if(!cells.isEmpty()){ final TablePosition cell = cells.get(0); final Code code = uiTable.getItems().get(cell.getRow()); try { crsProperty.set((CoordinateReferenceSystem)code.createObject()); } catch (FactoryException ex) { Loggers.JAVAFX.log(Level.INFO,ex.getMessage(),ex); } } } }); uiTable.getColumns().add(new TypeColumn()); uiTable.getColumns().add(new CodeColumn()); uiTable.getColumns().add(new DescColumn()); uiTable.getColumns().add(new WKTColumn()); //load list new Thread(){ @Override public void run() { try { allValues = getCodes(); Platform.runLater(() -> { uiTable.setItems(FXCollections.observableArrayList(allValues)); uiTable.setPlaceholder(new Label("")); }); } catch (FactoryException ex) { Loggers.JAVAFX.log(Level.WARNING,ex.getMessage(),ex); } } }.start(); } public ObjectProperty<CoordinateReferenceSystem> crsProperty(){ return crsProperty; } public void searchCRS(final String searchword){ filter(searchword); } /** * Display only the CRS name that contains the specified keywords. The {@code keywords} * argument is a space-separated list, usually provided by the user after he pressed the * "Search" button. * * @param keywords space-separated list of keywords to look for. */ private void filter(String keywords) { List<Code> model = allValues; if (keywords != null) { final Locale locale = Locale.getDefault(); keywords = keywords.toLowerCase(locale).trim(); final String[] tokens = keywords.split("\\s+"); if (tokens.length != 0) { model = new ArrayList<>(); scan: for(Code code : allValues){ final String name = code.toString().toLowerCase(locale); for (int j=0; j<tokens.length; j++) { if (!name.contains(tokens[j])) { continue scan; } } model.add(code); } } } uiTable.getItems().setAll(model); } /** * Returns a collection containing only the factories of the specified authority. */ private static Collection<CRSAuthorityFactory> filter( final Collection<? extends CRSAuthorityFactory> factories, final String authority){ final List<CRSAuthorityFactory> filtered = new ArrayList<>(); for (final CRSAuthorityFactory factory : factories) { if (Citations.identifierMatches(factory.getAuthority(), authority)) { filtered.add(factory); } } return filtered; } private List<Code> getCodes() throws FactoryException{ final CRSAuthorityFactory factory = org.apache.sis.referencing.CRS.getAuthorityFactory(null); final Set<String> strs = factory.getAuthorityCodes(CoordinateReferenceSystem.class); final List<Code> codes = new ArrayList<>(); for(String str : strs){ codes.add(new Code(factory, str)); } return codes; } private static class TypeColumn extends TableColumn<Code, Code>{ public TypeColumn() { setEditable(false); setPrefWidth(30); setMinWidth(30); setMaxWidth(30); setCellValueFactory((CellDataFeatures<Code, Code> param) -> new SimpleObjectProperty<>(param.getValue())); setCellFactory(new Callback<TableColumn<Code, Code>, TableCell<Code, Code>>() { @Override public TableCell<Code, Code> call(TableColumn<Code, Code> param) { return new TableCell<Code,Code>(){ @Override protected void updateItem(Code item, boolean empty) { super.updateItem(item, empty); setGraphic(null); if(item!=null){ Image icon = ICON_UNKNOWNED; try{ final IdentifiedObject obj = item.createObject(); if(obj instanceof GeographicCRS){ icon = ICON_GEO; }else if(obj instanceof ProjectedCRS){ final ProjectedCRS pcrs = (ProjectedCRS) obj; final Projection proj = pcrs.getConversionFromBase(); final OperationMethod method = proj.getMethod(); //TODO need to detect UTM and stereo if(String.valueOf(proj.getName()).toLowerCase().contains("utm")){ icon = ICON_UTM; }else if(proj instanceof ConicProjection){ icon = ICON_CONIC; }else if(proj instanceof CylindricalProjection){ icon = ICON_SQUARE; }else if(proj instanceof PlanarProjection){ icon = ICON_SQUARE; }else{ icon = ICON_SQUARE; } }else{ icon = ICON_SQUARE; } }catch(FactoryException ex){ Loggers.JAVAFX.log(Level.INFO, ex.getMessage(),ex); } setGraphic(new ImageView(icon)); } } }; } }); } } private static class CodeColumn extends TableColumn<Code, String>{ public CodeColumn() { super(GeotkFX.getString(FXCRSChooser.class, "code")); setEditable(false); setPrefWidth(150); setCellValueFactory((TableColumn.CellDataFeatures<Code, String> param) -> new SimpleObjectProperty<>(param.getValue().code)); } } private static class DescColumn extends TableColumn<Code, String>{ public DescColumn() { super(GeotkFX.getString(FXCRSChooser.class, "description")); setEditable(false); setCellValueFactory((TableColumn.CellDataFeatures<Code, String> param) -> new SimpleObjectProperty<>(param.getValue().getDescription())); } } private static class WKTColumn extends TableColumn<Code, Code>{ private static final Image ICON = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_FILE_TEXT,16,COLOR),null); public WKTColumn() { super(""); setEditable(false); setPrefWidth(26); setMinWidth(26); setMaxWidth(26); setCellValueFactory((CellDataFeatures<Code, Code> param) -> new SimpleObjectProperty<>(param.getValue())); setCellFactory(new Callback<TableColumn<Code, Code>, TableCell<Code, Code>>() { @Override public TableCell<Code, Code> call(TableColumn<Code, Code> param) { return new TableCell<Code,Code>(){ { setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { final Code item = getItem(); if(item!=null){ try { final IdentifiedObject obj = getItem().createObject(); if(obj instanceof FormattableObject){ FXFormattableObjectPane.showDialog(this, (FormattableObject) obj); } } catch (FactoryException ex) { Loggers.JAVAFX.log(Level.INFO,ex.getMessage(),ex); } } } }); } @Override protected void updateItem(Code item, boolean empty) { super.updateItem(item, empty); if(item !=null && !empty){ setGraphic(new ImageView(ICON)); }else{ setGraphic(null); } } }; } }); } } }