/* * Copyright (C) 2011 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.core.gpf.ui.mosaic; import com.bc.ceres.binding.PropertySet; import com.bc.ceres.swing.TableLayout; import com.bc.ceres.swing.binding.BindingContext; import com.bc.ceres.swing.selection.AbstractSelectionChangeListener; import com.bc.ceres.swing.selection.SelectionChangeEvent; import org.esa.snap.core.dataio.ProductIO; import org.esa.snap.core.dataio.ProductIOPlugInManager; import org.esa.snap.core.dataio.ProductReader; import org.esa.snap.core.dataio.ProductWriterPlugIn; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.datamodel.ProductFilter; import org.esa.snap.core.gpf.OperatorException; import org.esa.snap.core.gpf.common.MosaicOp; import org.esa.snap.core.gpf.ui.SourceProductSelector; import org.esa.snap.core.gpf.ui.TargetProductSelector; import org.esa.snap.core.gpf.ui.TargetProductSelectorModel; import org.esa.snap.core.util.PropertyMap; import org.esa.snap.core.util.SystemUtils; import org.esa.snap.core.util.io.FileUtils; import org.esa.snap.rcp.actions.file.SaveProductAsAction; import org.esa.snap.ui.AppContext; import org.esa.snap.ui.io.FileArrayEditor; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.SwingWorker; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.FlowLayout; import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.stream.Stream; /** * @author Marco Peters * @since BEAM 4.7 */ class MosaicIOPanel extends JPanel { private static final String INPUT_PRODUCT_DIR_KEY = "gpf.mosaic.input.product.dir"; private final AppContext appContext; private final MosaicFormModel mosaicModel; private final PropertySet propertySet; private final TargetProductSelector targetProductSelector; private final SourceProductSelector updateProductSelector; private FileArrayEditor sourceFileEditor; MosaicIOPanel(AppContext appContext, MosaicFormModel mosaicModel, TargetProductSelector selector) { this.appContext = appContext; this.mosaicModel = mosaicModel; propertySet = mosaicModel.getPropertySet(); final FileArrayEditor.EditorParent context = new FileArrayEditorContext(appContext); sourceFileEditor = new FileArrayEditor(context, "Source products") { @Override protected JFileChooser createFileChooserDialog() { final JFileChooser fileChooser = super.createFileChooserDialog(); fileChooser.setDialogTitle("Mosaic - Open Source Product(s)"); return fileChooser; } }; targetProductSelector = selector; updateProductSelector = new SourceProductSelector(appContext); updateProductSelector.setProductFilter(new UpdateProductFilter()); init(); propertySet.addPropertyChangeListener(MosaicFormModel.PROPERTY_UPDATE_MODE, evt -> { if (Boolean.TRUE.equals(evt.getNewValue())) { propertySet.setValue(MosaicFormModel.PROPERTY_UPDATE_PRODUCT, updateProductSelector.getSelectedProduct()); } else { updateProductSelector.setSelectedProduct(null); } }); propertySet.addPropertyChangeListener(MosaicFormModel.PROPERTY_UPDATE_PRODUCT, new TargetProductSelectorUpdater()); } private void init() { final TableLayout tableLayout = new TableLayout(1); tableLayout.setTableAnchor(TableLayout.Anchor.WEST); tableLayout.setTableFill(TableLayout.Fill.BOTH); tableLayout.setTableWeightX(1.0); tableLayout.setTableWeightY(0.0); tableLayout.setTablePadding(3, 3); setLayout(tableLayout); tableLayout.setRowWeightY(0, 1.0); add(createSourceProductsPanel()); add(createTargetProductPanel()); updateProductSelector.addSelectionChangeListener(new AbstractSelectionChangeListener() { @Override public void selectionChanged(SelectionChangeEvent event) { final Product product = (Product) event.getSelection().getSelectedValue(); try { if (product != null) { final Map<String, Object> map = MosaicOp.getOperatorParameters(product); final Stream<Map.Entry<String, Object>> entrySetStream = map.entrySet().stream(); final Stream<Map.Entry<String, Object>> filteredStream = entrySetStream.filter(entry -> propertySet.getProperty(entry.getKey()) != null); filteredStream.forEach(entry -> propertySet.setValue(entry.getKey(), entry.getValue())); } propertySet.setValue(MosaicFormModel.PROPERTY_UPDATE_PRODUCT, product); } catch (OperatorException e) { appContext.handleError("Selected product cannot be used for update mode.", e); } } }); } private JPanel createSourceProductsPanel() { final FileArrayEditor.FileArrayEditorListener listener = files -> { final SwingWorker worker = new SwingWorker() { @Override protected Object doInBackground() throws Exception { mosaicModel.setSourceProducts(files); return null; } @Override protected void done() { try { get(); } catch (Exception e) { final String msg = String.format("Cannot display source products.\n%s", e.getMessage()); appContext.handleError(msg, e); } } }; worker.execute(); }; sourceFileEditor.setListener(listener); JButton addFileButton = sourceFileEditor.createAddFileButton(); JButton removeFileButton = sourceFileEditor.createRemoveFileButton(); final TableLayout tableLayout = new TableLayout(1); tableLayout.setTablePadding(4, 4); tableLayout.setTableWeightX(1.0); tableLayout.setTableWeightY(0.0); tableLayout.setTableAnchor(TableLayout.Anchor.WEST); tableLayout.setTableFill(TableLayout.Fill.BOTH); final JPanel sourceProductPanel = new JPanel(tableLayout); sourceProductPanel.setBorder(BorderFactory.createTitledBorder("Source Products")); final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); buttonPanel.add(addFileButton); buttonPanel.add(removeFileButton); tableLayout.setRowPadding(0, new Insets(1, 4, 1, 4)); sourceProductPanel.add(buttonPanel); final JComponent fileArrayComponent = sourceFileEditor.createFileArrayComponent(); tableLayout.setRowWeightY(1, 1.0); sourceProductPanel.add(fileArrayComponent); return sourceProductPanel; } private JPanel createTargetProductPanel() { final TableLayout tableLayout = new TableLayout(1); tableLayout.setTableAnchor(TableLayout.Anchor.WEST); tableLayout.setTableFill(TableLayout.Fill.BOTH); tableLayout.setTableWeightX(1.0); tableLayout.setTableWeightY(1.0); tableLayout.setTablePadding(3, 3); final JPanel targetProductPanel = new JPanel(tableLayout); targetProductPanel.setBorder(BorderFactory.createTitledBorder("Target Product")); final JCheckBox updateTargetCheckBox = new JCheckBox("Update target product", false); final BindingContext context = new BindingContext(propertySet); context.bind(MosaicFormModel.PROPERTY_UPDATE_MODE, updateTargetCheckBox); targetProductPanel.add(updateTargetCheckBox); final CardLayout cards = new CardLayout(0, 3); final JPanel subPanel = new JPanel(cards); final JPanel newProductSelectorPanel = createTargetProductSelectorPanel(targetProductSelector); final JPanel updateProductSelectorPanel = createUpdateProductSelectorPanel(updateProductSelector); final String newProductKey = "NEW_PRODUCT"; final String updateProductKey = "UPDATE_PRODUCT"; subPanel.add(newProductSelectorPanel, newProductKey); subPanel.add(updateProductSelectorPanel, updateProductKey); updateTargetCheckBox.addActionListener(e -> { if (updateTargetCheckBox.isSelected()) { prepareHideTargetProductSelector(); prepareShowUpdateProductSelector(); cards.show(subPanel, updateProductKey); } else { prepareShowTargetProductSelector(); prepareHideUpdateProductSelector(); cards.show(subPanel, newProductKey); } }); cards.show(subPanel, newProductKey); targetProductPanel.add(subPanel); targetProductPanel.add(targetProductSelector.getOpenInAppCheckBox()); return targetProductPanel; } private JPanel createUpdateProductSelectorPanel(final SourceProductSelector selector) { final JPanel subPanel = new JPanel(new BorderLayout(3, 3)); subPanel.add(selector.getProductNameComboBox(), BorderLayout.CENTER); subPanel.add(selector.getProductFileChooserButton(), BorderLayout.EAST); final TableLayout tableLayout = new TableLayout(1); tableLayout.setTableAnchor(TableLayout.Anchor.WEST); tableLayout.setTableWeightX(1.0); tableLayout.setRowFill(0, TableLayout.Fill.HORIZONTAL); tableLayout.setRowFill(1, TableLayout.Fill.HORIZONTAL); tableLayout.setTablePadding(3, 3); JPanel panel = new JPanel(tableLayout); panel.add(selector.getProductNameLabel()); panel.add(subPanel); panel.add(tableLayout.createVerticalSpacer()); return panel; } private static JPanel createTargetProductSelectorPanel(final TargetProductSelector selector) { final JPanel subPanel1 = new JPanel(new BorderLayout(3, 3)); subPanel1.add(selector.getProductNameLabel(), BorderLayout.NORTH); subPanel1.add(selector.getProductNameTextField(), BorderLayout.CENTER); final JPanel subPanel2 = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); subPanel2.add(selector.getSaveToFileCheckBox()); subPanel2.add(selector.getFormatNameComboBox()); final JPanel subPanel3 = new JPanel(new BorderLayout(3, 3)); subPanel3.add(selector.getProductDirLabel(), BorderLayout.NORTH); subPanel3.add(selector.getProductDirTextField(), BorderLayout.CENTER); subPanel3.add(selector.getProductDirChooserButton(), BorderLayout.EAST); final TableLayout tableLayout = new TableLayout(1); tableLayout.setTableAnchor(TableLayout.Anchor.WEST); tableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); tableLayout.setTableWeightX(1.0); tableLayout.setCellPadding(0, 0, new Insets(3, 3, 3, 3)); tableLayout.setCellPadding(1, 0, new Insets(3, 0, 3, 3)); tableLayout.setCellPadding(2, 0, new Insets(0, 21, 3, 3)); final JPanel panel = new JPanel(tableLayout); panel.add(subPanel1); panel.add(subPanel2); panel.add(subPanel3); return panel; } void prepareShow() { prepareShowTargetProductSelector(); if (mosaicModel.isUpdateMode()) { prepareShowUpdateProductSelector(); } } private void prepareShowUpdateProductSelector() { updateProductSelector.initProducts(); } private void prepareShowTargetProductSelector() { try { final List<File> files = sourceFileEditor.getFiles(); mosaicModel.setSourceProducts(files.toArray(new File[files.size()])); } catch (IOException ignore) { } } void prepareHide() { prepareHideUpdateProductSelector(); prepareHideTargetProductSelector(); } private void prepareHideUpdateProductSelector() { updateProductSelector.releaseProducts(); } private void prepareHideTargetProductSelector() { try { mosaicModel.setSourceProducts(new File[0]); } catch (IOException ignore) { } } private static class FileArrayEditorContext implements FileArrayEditor.EditorParent { private final AppContext applicationContext; private FileArrayEditorContext(AppContext applicationContext) { this.applicationContext = applicationContext; } @Override public File getUserInputDir() { return getInputProductDir(); } @Override public void setUserInputDir(File newDir) { setInputProductDir(newDir); } private void setInputProductDir(final File currentDirectory) { applicationContext.getPreferences().setPropertyString(INPUT_PRODUCT_DIR_KEY, currentDirectory.getAbsolutePath()); } private File getInputProductDir() { final String path = applicationContext.getPreferences().getPropertyString(INPUT_PRODUCT_DIR_KEY); final File inputProductDir; if (path != null) { inputProductDir = new File(path); } else { inputProductDir = null; } return inputProductDir; } } private class TargetProductSelectorUpdater implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { final Product product = (Product) evt.getNewValue(); final TargetProductSelectorModel selectorModel = targetProductSelector.getModel(); if (product != null) { final String formatName = product.getProductReader().getReaderPlugIn().getFormatNames()[0]; final ProductIOPlugInManager ioPlugInManager = ProductIOPlugInManager.getInstance(); final Iterator<ProductWriterPlugIn> writerIterator = ioPlugInManager.getWriterPlugIns(formatName); if (writerIterator.hasNext()) { selectorModel.setFormatName(formatName); } else { final String errMsg = "Cannot write to update product."; final String iseMsg = String.format("No product writer found for format '%s'", formatName); appContext.handleError(errMsg, new IllegalStateException(iseMsg)); } final File fileLocation = product.getFileLocation(); final String fileName = FileUtils.getFilenameWithoutExtension(fileLocation); final File fileDir = fileLocation.getParentFile(); selectorModel.setProductName(fileName); selectorModel.setProductDir(fileDir); } else { selectorModel.setFormatName(ProductIO.DEFAULT_FORMAT_NAME); selectorModel.setProductName("mosaic"); String homeDirPath = SystemUtils.getUserHomeDir().getPath(); final PropertyMap prefs = appContext.getPreferences(); String saveDir = prefs.getPropertyString(SaveProductAsAction.PREFERENCES_KEY_LAST_PRODUCT_DIR, homeDirPath); selectorModel.setProductDir(new File(saveDir)); } } } public class UpdateProductFilter implements ProductFilter { @Override public boolean accept(Product product) { ProductReader productReader = product.getProductReader(); if (productReader != null) { final String formatName = productReader.getReaderPlugIn().getFormatNames()[0]; final ProductIOPlugInManager ioPlugInManager = ProductIOPlugInManager.getInstance(); final Iterator<ProductWriterPlugIn> writerIterator = ioPlugInManager.getWriterPlugIns(formatName); if (writerIterator.hasNext()) { try { MosaicOp.getOperatorParameters(product); } catch (OperatorException e) { return false; } return true; } } return false; } } }