/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.snap.rcp.actions.vector; import com.bc.ceres.core.ProgressMonitor; import com.bc.ceres.swing.progress.ProgressMonitorSwingWorker; import com.vividsolutions.jts.geom.Polygonal; import org.esa.snap.core.dataio.geometry.VectorDataNodeIO; import org.esa.snap.core.datamodel.GeoCoding; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.datamodel.ProductNodeGroup; import org.esa.snap.core.datamodel.VectorDataNode; import org.esa.snap.core.util.Debug; import org.esa.snap.core.util.SystemUtils; import org.esa.snap.core.util.io.SnapFileFilter; import org.esa.snap.rcp.SnapApp; import org.esa.snap.rcp.util.Dialogs; import org.esa.snap.ui.ModalDialog; import org.esa.snap.ui.SnapFileChooser; import org.esa.snap.ui.product.ProductSceneView; import org.opengis.feature.type.GeometryDescriptor; import org.openide.util.HelpCtx; import javax.swing.JFileChooser; import java.io.File; import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.prefs.Preferences; import static org.esa.snap.rcp.SnapApp.SelectionSourceHint.*; // todo - test with shapefile that has no CRS (nf, 2012-04-05) public class VectorDataNodeImporter implements HelpCtx.Provider { private final String dialogTitle; private final String shapeIoDirPreferencesKey; private String helpId; private SnapFileFilter filter; private final VectorDataNodeReader reader; public VectorDataNodeImporter(String helpId, SnapFileFilter filter, VectorDataNodeReader reader, String dialogTitle, String shapeIoDirPreferencesKey) { this.helpId = helpId; this.filter = filter; this.reader = reader; this.dialogTitle = dialogTitle; this.shapeIoDirPreferencesKey = shapeIoDirPreferencesKey; } public void importGeometry(final SnapApp snapApp) { final Preferences preferences = snapApp.getPreferences(); final SnapFileChooser fileChooser = new SnapFileChooser(); fileChooser.setDialogTitle(dialogTitle); fileChooser.setFileFilter(filter); fileChooser.setAcceptAllFileFilterUsed(false); fileChooser.setMultiSelectionEnabled(true); fileChooser.setCurrentDirectory(getIODir(preferences)); final int result = fileChooser.showOpenDialog(snapApp.getMainFrame()); if (result == JFileChooser.APPROVE_OPTION) { final File[] files = fileChooser.getSelectedFiles(); if (files != null && files.length > 0) { setIODir(preferences, files[0].getAbsoluteFile().getParentFile()); for(File file : files) { importGeometry(snapApp, file); } } } } private void importGeometry(final SnapApp snapApp, final File file) { final Product product = snapApp.getSelectedProduct(AUTO); if (product == null) { return; } final GeoCoding geoCoding = product.getSceneGeoCoding(); if (geoCoding == null || !geoCoding.canGetPixelPos()) { Dialogs.showError(dialogTitle, "Failed to import vector data.\n" + "Current geo-coding cannot convert from geographic to pixel coordinates."); /* I18N */ return; } VectorDataNode vectorDataNode; try { vectorDataNode = readGeometry(snapApp, file, product); if (vectorDataNode == null) { return; } } catch (Exception e) { Dialogs.showError(dialogTitle, "Failed to import vector data.\n" + "An I/O Error occurred:\n" + e.getMessage()); /* I18N */ Debug.trace(e); return; } if (vectorDataNode.getFeatureCollection().isEmpty()) { Dialogs.showError(dialogTitle, "The vector data was loaded successfully,\n" + "but no part is located within the scene boundaries."); /* I18N */ return; } boolean individualShapes = false; String attributeName = null; GeometryDescriptor geometryDescriptor = vectorDataNode.getFeatureType().getGeometryDescriptor(); int featureCount = vectorDataNode.getFeatureCollection().size(); if (featureCount > 1 && geometryDescriptor != null && Polygonal.class.isAssignableFrom(geometryDescriptor.getType().getBinding())) { String text = "<html>" + "The vector data set contains <b>" + featureCount + "</b> polygonal shapes.<br>" + "Shall they be imported separately?<br>" + "<br>" + "If you select <b>Yes</b>, the polygons can be used as individual masks<br>" + "and they will be displayed on individual layers.</i>"; SeparateGeometriesDialog dialog = new SeparateGeometriesDialog(snapApp.getMainFrame(), vectorDataNode, helpId, text); int response = dialog.show(); if (response == ModalDialog.ID_CANCEL) { return; } individualShapes = response == ModalDialog.ID_YES; attributeName = dialog.getSelectedAttributeName(); } VectorDataNode[] vectorDataNodes = VectorDataNodeIO.getVectorDataNodes(vectorDataNode, individualShapes, attributeName); for (VectorDataNode vectorDataNode1 : vectorDataNodes) { product.getVectorDataGroup().add(vectorDataNode1); } setLayersVisible(vectorDataNodes); } private void setLayersVisible(VectorDataNode[] vectorDataNodes) { final ProductSceneView sceneView = SnapApp.getDefault().getSelectedProductSceneView(); if (sceneView != null) { sceneView.setLayersVisible(vectorDataNodes); } } public static String findUniqueVectorDataNodeName(String suggestedName, ProductNodeGroup<VectorDataNode> vectorDataGroup) { String name = suggestedName; int index = 1; while (vectorDataGroup.contains(name)) { name = suggestedName + "_" + index; index++; } return name; } private File getIODir(final Preferences preferences) { final File dir = SystemUtils.getUserHomeDir(); return new File(preferences.get(shapeIoDirPreferencesKey, dir.getPath())); } public String getDialogTitle() { return dialogTitle; } @Override public HelpCtx getHelpCtx() { return new HelpCtx(helpId); } public interface VectorDataNodeReader { VectorDataNode readVectorDataNode(File file, Product product, ProgressMonitor pm) throws IOException; } private VectorDataNode readGeometry(final SnapApp snapApp, final File file, final Product product) throws IOException, ExecutionException, InterruptedException { ProgressMonitorSwingWorker<VectorDataNode, Object> worker = new ProgressMonitorSwingWorker<VectorDataNode, Object>(snapApp.getMainFrame(), "Loading vector data") { @Override protected VectorDataNode doInBackground(ProgressMonitor pm) throws Exception { return reader.readVectorDataNode(file, product, pm); } @Override protected void done() { super.done(); } }; worker.executeWithBlocking(); return worker.get(); } private void setIODir(final Preferences preferences, final File dir) { if (dir != null) { preferences.put(shapeIoDirPreferencesKey, dir.getPath()); } } }