/* * 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.beam.smos.visat.export; import com.bc.ceres.binding.*; import com.bc.ceres.swing.TableLayout; import com.bc.ceres.swing.binding.Binding; import com.bc.ceres.swing.binding.BindingContext; import com.bc.ceres.swing.selection.SelectionManager; import org.esa.beam.dataio.smos.ProductFile; import org.esa.beam.dataio.smos.SmosFile; import org.esa.beam.dataio.smos.SmosProductReader; import org.esa.beam.framework.dataio.ProductReader; import org.esa.beam.framework.datamodel.Product; import org.esa.beam.framework.datamodel.ProductManager; import org.esa.beam.framework.datamodel.VectorDataNode; import org.esa.beam.framework.gpf.annotations.ParameterDescriptorFactory; import org.esa.beam.framework.ui.AppContext; import org.esa.beam.smos.gui.*; import org.esa.beam.util.io.FileChooserFactory; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; class GridPointExportDialog extends ProductChangeAwareDialog { static final String ALIAS_RECURSIVE = "recursive"; static final String ALIAS_TARGET_FILE = "targetFileOrDir"; static final String ALIAS_EXPORT_FORMAT = "exportFormat"; static final String NAME_CSV = "CSV"; static final String NAME_EEF = "Earth Explorer subsets"; private final AppContext appContext; private final PropertyContainer propertyContainer; private final BindingContext bindingContext; private final ProductSelectionListener productSelectionListener; private GeometryListener geometryListener; private final ExportParameter exportParameter; GridPointExportDialog(final AppContext appContext, String helpId) { super(appContext.getApplicationWindow(), "Export SMOS Grid Points", ID_OK | ID_CLOSE | ID_HELP, helpId); /* I18N */ exportParameter = new ExportParameter(); this.appContext = appContext; propertyContainer = PropertyContainer.createObjectBacked(exportParameter, new ParameterDescriptorFactory()); try { initPropertyContainer(); } catch (ValidationException e) { throw new IllegalStateException(e); // cannot happen } bindingContext = new BindingContext(propertyContainer); bindingContext.bindEnabledState(BindingConstants.REGION, true, BindingConstants.ROI_TYPE, BindingConstants.ROI_TYPE_PRODUCT); GuiHelper.bindLonLatPanelToRoiType(2, bindingContext); createUI(); final ProductManager productManager = appContext.getProductManager(); productManager.addListener(new ProductManagerListener(this)); geometryListener = new GeometryListener(this); final SelectionManager selectionManager = appContext.getApplicationPage().getSelectionManager(); productSelectionListener = new ProductSelectionListener(this, selectionManager); selectionManager.addSelectionChangeListener(productSelectionListener); } @Override protected void onOK() { final File sourceDirectory = propertyContainer.getValue(BindingConstants.SOURCE_DIRECTORY); final File targetFile = propertyContainer.getValue(ALIAS_TARGET_FILE); GuiHelper.setDefaultSourceDirectory(sourceDirectory, appContext); setDefaultTargetFile(targetFile); if (targetFile.exists() && targetFile.isFile()) { final String message = MessageFormat.format( "The selected target file\n''{0}''\nalready exists.\n\nDo you want to overwrite the target file?", targetFile.getPath()); final int answer = JOptionPane.showConfirmDialog(getJDialog(), message, getTitle(), JOptionPane.YES_NO_OPTION); if (answer != JOptionPane.YES_OPTION) { return; } } final GridPointExportSwingWorker swingWorker = new GridPointExportSwingWorker(appContext, exportParameter.getClone()); GuiHelper.setDefaultSourceDirectory(exportParameter.getSourceDirectory(), appContext); final File exportedFile = exportParameter.getTargetFile(); if (exportedFile != null) { GuiHelper.setDefaultTargetDirectory(exportedFile.getParentFile(), appContext); } swingWorker.execute(); } @Override protected boolean verifyUserInput() { final int roiType = propertyContainer.getValue(BindingConstants.ROI_TYPE); if (roiType == 2) { final double north = propertyContainer.getValue(BindingConstants.NORTH); final double south = propertyContainer.getValue(BindingConstants.SOUTH); if (north <= south) { showErrorDialog("The southern latitude must be less than the northern latitude."); return false; } final double east = propertyContainer.getValue(BindingConstants.EAST); final double west = propertyContainer.getValue(BindingConstants.WEST); if (east <= west) { showErrorDialog("The western longitude must be less than the eastern longitude."); return false; } } final File targetFile = propertyContainer.getValue(ALIAS_TARGET_FILE); final String exportFormat = propertyContainer.getValue(ALIAS_EXPORT_FORMAT); if (NAME_CSV.equals(exportFormat)) { if (targetFile.exists() && !targetFile.isFile()) { showErrorDialog("The target file must be a normal file, not a directory."); return false; } } else { if (targetFile.exists() && !targetFile.isDirectory()) { showErrorDialog("The target file must be a directory, not a normal file."); return false; } } return true; } private void initPropertyContainer() throws ValidationException { propertyContainer.setDefaultValues(); final File defaultSourceDirectory = GuiHelper.getDefaultSourceDirectory(appContext); propertyContainer.setValue(BindingConstants.SOURCE_DIRECTORY, defaultSourceDirectory); final File targetFile = getDefaultTargetFile(); propertyContainer.setValue(ALIAS_TARGET_FILE, targetFile); updateSelectedProductAndGeometries(); if (targetFile.isDirectory()) { propertyContainer.setValue(ALIAS_EXPORT_FORMAT, NAME_EEF); } propertyContainer.addPropertyChangeListener(ALIAS_EXPORT_FORMAT, new ExportFormatChangeListener()); } @SuppressWarnings("ConstantConditions") private void updateSelectedProductAndGeometries() throws ValidationException { final Product selectedProduct = getSelectedSmosProduct(); if (selectedProduct != null) { final List<VectorDataNode> geometryNodeList = GuiHelper.getGeometries(selectedProduct); if (!geometryNodeList.isEmpty()) { GuiHelper.bindGeometryVectorDataNodes(geometryNodeList, propertyContainer); } else { removeGeometries(); if (selectedProduct.getPinGroup().getNodeCount() != 0) { propertyContainer.setValue(BindingConstants.ROI_TYPE, BindingConstants.ROI_TYPE_GEOMETRY); } } } // if (bindingContext != null) { // bindingContext.setComponentsEnabled(BindingConstants.SELECTED_PRODUCT, selectedProduct != null); // } propertyContainer.setValue(BindingConstants.SELECTED_PRODUCT, selectedProduct != null); setSelectedProductButtonEnabled(selectedProduct != null); } private void removeProductAndGeometries(Product product) throws ValidationException { final Product selectedSmosProduct = getSelectedSmosProduct(); if (selectedSmosProduct == null) { propertyContainer.setValue(BindingConstants.SELECTED_PRODUCT, false); setSelectedProductButtonEnabled(false); final List<VectorDataNode> geometryNodeList = GuiHelper.getGeometries(product); if (!geometryNodeList.isEmpty()) { removeGeometries(); } } } @SuppressWarnings("ConstantConditions") private void setSelectedProductButtonEnabled(boolean enabled) { if (bindingContext == null) { return; } final Binding binding = bindingContext.getBinding(BindingConstants.SELECTED_PRODUCT); final JComponent[] components = binding.getComponents(); for (final JComponent component : components) { if (component instanceof JRadioButton) { if (((JRadioButton) component).getText().equals(BindingConstants.USE_SELECTED_PRODUCT_BUTTON_NAME)) { component.setEnabled(enabled); break; } } } } private void removeGeometries() throws ValidationException { final Property geometryProperty = propertyContainer.getProperty(BindingConstants.REGION); geometryProperty.getDescriptor().setValueSet(new ValueSet(new VectorDataNode[0])); propertyContainer.setValue(BindingConstants.REGION, null); propertyContainer.setValue(BindingConstants.ROI_TYPE, BindingConstants.ROI_TYPE_AREA); } private void createUI() { final JPanel mainPanel = GuiHelper.createPanelWithBoxLayout(); mainPanel.add(createSourceProductPanel()); mainPanel.add(createRoiPanel()); mainPanel.add(createTargetFilePanel()); setContent(mainPanel); } private JComponent createSourceProductPanel() { final boolean useSelectProductEnabled = getSelectedSmosProduct() != null; final TableLayout layout = GuiHelper.createWeightedTablelayout(1); final JPanel sourceProductPanel = new JPanel(layout); sourceProductPanel.setBorder(BorderFactory.createTitledBorder("Source Products")); GuiHelper.addSourceProductsButtons(sourceProductPanel, useSelectProductEnabled, bindingContext); final JCheckBox checkBox = new JCheckBox("Descend into subdirectories"); bindingContext.bind(ALIAS_RECURSIVE, checkBox); bindingContext.bindEnabledState(ALIAS_RECURSIVE, true, BindingConstants.SELECTED_PRODUCT, false); final PropertyDescriptor sourceDirectoryDescriptor = propertyContainer.getDescriptor(BindingConstants.SOURCE_DIRECTORY); final JComponent fileEditor = GuiHelper.createFileEditorComponent(sourceDirectoryDescriptor, new DefaultChooserFactory(), bindingContext); layout.setCellPadding(2, 0, new Insets(0, 24, 3, 3)); sourceProductPanel.add(fileEditor); layout.setCellPadding(3, 0, new Insets(0, 24, 3, 3)); sourceProductPanel.add(checkBox); return sourceProductPanel; } private Component createRoiPanel() { final JRadioButton useGeometryButton = new JRadioButton("Geometry"); final PropertyDescriptor geometryDescriptor = propertyContainer.getDescriptor(BindingConstants.REGION); if (geometryDescriptor != null && geometryDescriptor.getValueSet() == null) { useGeometryButton.setEnabled(false); } final JRadioButton usePinsButton = new JRadioButton("Pins"); final Product selectedProduct = getSelectedSmosProduct(); if (selectedProduct == null || selectedProduct.getPinGroup().getNodeCount() == 0) { usePinsButton.setEnabled(false); } final JRadioButton useAreaButton = new JRadioButton("Area"); final Map<AbstractButton, Object> buttonGroupValueSet = new HashMap<>(); buttonGroupValueSet.put(useGeometryButton, 0); buttonGroupValueSet.put(usePinsButton, 1); buttonGroupValueSet.put(useAreaButton, 2); final ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(useGeometryButton); buttonGroup.add(usePinsButton); buttonGroup.add(useAreaButton); bindingContext.bind(BindingConstants.ROI_TYPE, buttonGroup, buttonGroupValueSet); final JComboBox geometryComboBox = GuiHelper.createGeometryComboBox(geometryDescriptor, bindingContext); final TableLayout layout = GuiHelper.createWeightedTablelayout(1); final JPanel roiPanel = new JPanel(layout); roiPanel.setBorder(BorderFactory.createTitledBorder("Region of Interest")); roiPanel.add(useGeometryButton); roiPanel.add(geometryComboBox); roiPanel.add(usePinsButton); roiPanel.add(useAreaButton); final Component latLonPanel = GuiHelper.createLatLonPanel(propertyContainer, bindingContext); roiPanel.add(latLonPanel); layout.setCellPadding(1, 0, new Insets(0, 24, 3, 3)); layout.setCellPadding(3, 0, new Insets(0, 24, 3, 3)); return roiPanel; } private JComponent createTargetFilePanel() { final TableLayout layout = GuiHelper.createWeightedTablelayout(1); final JPanel targetFilePanel = new JPanel(layout); targetFilePanel.setBorder(BorderFactory.createTitledBorder("Target File")); final PropertyDescriptor formatDescriptor = propertyContainer.getDescriptor(ALIAS_EXPORT_FORMAT); final JComboBox<Object> formatComboBox = new JComboBox<>(formatDescriptor.getValueSet().getItems()); bindingContext.bind(ALIAS_EXPORT_FORMAT, formatComboBox); final JPanel formatPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); formatPanel.add(new JLabel("Export as:")); formatPanel.add(formatComboBox); final JLabel label = new JLabel(); if (NAME_CSV.equals(propertyContainer.getValue(ALIAS_EXPORT_FORMAT))) { label.setText("Save to file:"); } else { label.setText("Save subset files to directory:"); } final PropertyDescriptor targetFileDescriptor = propertyContainer.getDescriptor(ALIAS_TARGET_FILE); final ChooserFactory chooserFactory = new ChooserFactory() { @Override public JFileChooser createChooser(File file) { final FileChooserFactory chooserFactory = FileChooserFactory.getInstance(); final JFileChooser fileChooser; if (NAME_CSV.equals(bindingContext.getBinding(ALIAS_EXPORT_FORMAT).getPropertyValue())) { fileChooser = chooserFactory.createFileChooser(file); fileChooser.setAcceptAllFileFilterUsed(true); fileChooser.setFileFilter(new FileNameExtensionFilter("CSV", "CSV")); } else { fileChooser = chooserFactory.createDirChooser(file); } return fileChooser; } }; final JComponent fileEditor = GuiHelper.createFileEditorComponent(targetFileDescriptor, chooserFactory, bindingContext); targetFilePanel.add(formatPanel); targetFilePanel.add(label); targetFilePanel.add(fileEditor); bindingContext.addPropertyChangeListener(ALIAS_EXPORT_FORMAT, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (NAME_CSV.equals(evt.getNewValue())) { label.setText("Save to file:"); } else { label.setText("Save subset files to directory:"); } } }); return targetFilePanel; } private File getDefaultTargetFile() { final String def = new File(System.getProperty("user.home", "."), "export.csv").getPath(); return new File(appContext.getPreferences().getPropertyString(GuiHelper.LAST_TARGET_FILE_KEY, def)); } private void setDefaultTargetFile(File targetFile) { appContext.getPreferences().setPropertyString(GuiHelper.LAST_TARGET_FILE_KEY, targetFile.getPath()); } private Product getSelectedSmosProduct() { final Product selectedProduct = appContext.getSelectedProduct(); if (selectedProduct != null) { final ProductReader productReader = selectedProduct.getProductReader(); if (productReader instanceof SmosProductReader) { final SmosProductReader smosProductReader = (SmosProductReader) productReader; final ProductFile productFile = smosProductReader.getProductFile(); if (productFile instanceof SmosFile) { selectedProduct.addProductNodeListener(geometryListener); return selectedProduct; } } } return null; } protected void productAdded() { try { updateSelectedProductAndGeometries(); } catch (ValidationException e) { showErrorDialog("Internal error: " + e.getMessage()); } } protected void productRemoved(Product product) { try { removeProductAndGeometries(product); } catch (ValidationException e) { showErrorDialog("Internal error: " + e.getMessage()); } product.removeProductNodeListener(geometryListener); } @Override protected void geometryAdded() { try { updateSelectedProductAndGeometries(); } catch (ValidationException e) { showErrorDialog("Internal error: " + e.getMessage()); } } @Override protected void geometryRemoved() { try { updateSelectedProductAndGeometries(); } catch (ValidationException e) { showErrorDialog("Internal error: " + e.getMessage()); } } @Override protected void productSelectionChanged() { try { updateSelectedProductAndGeometries(); } catch (ValidationException e) { showErrorDialog("Internal error: " + e.getMessage()); } } @Override protected void onClose() { productSelectionListener.dispose(); super.onClose(); } private class ExportFormatChangeListener implements PropertyChangeListener { File last; @Override public void propertyChange(PropertyChangeEvent evt) { if (NAME_CSV.equals(evt.getNewValue())) { final File dir = propertyContainer.getValue(ALIAS_TARGET_FILE); if (last != null) { propertyContainer.setValue(ALIAS_TARGET_FILE, new File(dir, last.getName())); } } else { last = propertyContainer.getValue(ALIAS_TARGET_FILE); propertyContainer.setValue(ALIAS_TARGET_FILE, last.getParentFile()); } } } }