/*
* 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.file;
import org.esa.snap.core.dataio.EncodeQualification;
import org.esa.snap.core.dataio.ProductIO;
import org.esa.snap.core.dataio.ProductIOPlugInManager;
import org.esa.snap.core.dataio.ProductWriter;
import org.esa.snap.core.dataio.ProductWriterPlugIn;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNode;
import org.esa.snap.core.util.io.SnapFileFilter;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.rcp.util.Dialogs;
import org.netbeans.api.progress.ProgressUtils;
import org.openide.util.ContextAwareAction;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import java.awt.event.ActionEvent;
import java.io.File;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Map;
import java.util.prefs.Preferences;
/**
* Action for exporting a product.
*
* @author Marco Peters
*/
public class ExportProductAction extends AbstractAction implements HelpCtx.Provider, ContextAwareAction {
private static final String PROPERTY_FORMAT_NAME = "formatName";
private static final String PROPERTY_HELP_CTX = "helpCtx";
private static final String PROPERTY_USE_ALL_FILE_FILTER = "useAllFileFilter";
private WeakReference<Product> productRef;
/**
* Action factory method used in NetBeans {@code layer.xml} file, e.g.
* <p>
* <pre>
* <file name="org-esa-snap-csv-dataio-ExportCSVProduct.instance">
* <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.context"/>
* <attr name="type" stringvalue="ProductNode"/>
* <attr name="delegate" methodvalue="ExportProductAction.create"/>
* <attr name="selectionType" stringvalue="EXACTLY_ONE"/>
* <attr name="displayName" stringvalue="CSV Product"/>
* <attr name="formatName" stringvalue="CSV"/>
* <attr name="useAllFileFilter" boolvalue="true"/>
* <attr name="helpId" stringvalue="exportCsvProduct"/>
* <attr name="ShortDescription" stringvalue="Writes a product in CSV format."/>
* </file>
* </pre>
*
* @param configuration Configuration attributes from layer.xml.
* @return The action.
* @since SNAP 2
*/
public static ExportProductAction create(Map<String, Object> configuration) {
ExportProductAction exportProductAction = new ExportProductAction();
exportProductAction.setFormatName((String) configuration.get(PROPERTY_FORMAT_NAME));
exportProductAction.setHelpCtx((String) configuration.get("helpId"));
exportProductAction.setUseAllFileFilter((Boolean) configuration.get(PROPERTY_USE_ALL_FILE_FILTER));
return exportProductAction;
}
@Override
public Action createContextAwareInstance(Lookup actionContext) {
ProductNode productNode = actionContext.lookup(ProductNode.class);
setProduct(productNode.getProduct());
return this;
}
@Override
public HelpCtx getHelpCtx() {
return (HelpCtx) getValue(PROPERTY_HELP_CTX);
}
public void setHelpCtx(String helpId) {
putValue(PROPERTY_HELP_CTX, helpId != null ? new HelpCtx(helpId) : null);
}
public String getDisplayName() {
return (String) getValue("displayName");
}
public void setFormatName(String formatName) {
putValue(PROPERTY_FORMAT_NAME, formatName);
}
public void setUseAllFileFilter(Boolean useAllFileFilter) {
putValue(PROPERTY_USE_ALL_FILE_FILTER, useAllFileFilter);
}
public void setProduct(Product p) {
productRef = new WeakReference<>(p);
}
@Override
public void actionPerformed(ActionEvent e) {
execute();
}
/**
* @return {@code Boolean.TRUE} on success, {@code Boolean.FALSE} on failure, or {@code null} on cancellation.
*/
public Boolean execute() {
Product product = productRef.get();
if (product != null) {
return exportProduct(product, (String) getValue(PROPERTY_FORMAT_NAME));
} else {
// reference was garbage collected, that's fine, no need to save.
return true;
}
}
private Boolean exportProduct(Product product, String formatName) {
final ProductWriter productWriter = ProductIO.getProductWriter(formatName);
if (productWriter == null) {
Dialogs.showError(getDisplayName(), MessageFormat.format("No writer found for format {0}.", formatName));
return null;
}
final EncodeQualification encodeQualification = productWriter.getWriterPlugIn().getEncodeQualification(product);
if (encodeQualification.getPreservation() == EncodeQualification.Preservation.UNABLE) {
Dialogs.showError(getDisplayName(), MessageFormat.format("Writing this product as {0} is not possible:\n"
+ encodeQualification.getInfoString(),
formatName
));
return null;
}
Preferences preferences = SnapApp.getDefault().getPreferences();
ProductFileChooser fc = new ProductFileChooser(new File(preferences.get(ProductOpener.PREFERENCES_KEY_LAST_PRODUCT_DIR, ".")));
fc.setDialogType(JFileChooser.SAVE_DIALOG);
fc.setSubsetEnabled(true);
fc.addChoosableFileFilter(getFileFilter(formatName));
fc.setProductToExport(product);
int returnVal = fc.showSaveDialog(SnapApp.getDefault().getMainFrame());
if (returnVal != JFileChooser.APPROVE_OPTION) {
// cancelled
return null;
}
File newFile = fc.getSelectedFile();
if (newFile == null) {
// cancelled
return null;
}
if (newFile.isFile() && !newFile.canWrite()) {
Dialogs.showWarning(getDisplayName(),
MessageFormat.format("The product\n" +
"''{0}''\n" +
"exists and cannot be overwritten, because it is read only.\n" +
"Please choose another file or remove the write protection.",
newFile.getPath()),
null);
return false;
}
Product exportProduct = fc.getSubsetProduct() != null ? fc.getSubsetProduct() : product;
SnapApp.getDefault().setStatusBarMessage(MessageFormat.format("Exporting product ''{0}'' to {1}...", exportProduct.getDisplayName(), newFile));
WriteProductOperation operation = new WriteProductOperation(exportProduct, newFile, formatName, false);
ProgressUtils.runOffEventThreadWithProgressDialog(operation,
getDisplayName(),
operation.getProgressHandle(),
true,
50,
1000);
SnapApp.getDefault().setStatusBarMessage("");
return operation.getStatus();
}
private FileFilter getFileFilter(String formatName) {
Iterator<ProductWriterPlugIn> writerPlugIns = ProductIOPlugInManager.getInstance().getWriterPlugIns(formatName);
if (writerPlugIns.hasNext()) {
return writerPlugIns.next().getProductFileFilter();
}
return null;
}
private String getFileExtension(String formatName) {
Iterator<ProductWriterPlugIn> writerPlugIns = ProductIOPlugInManager.getInstance().getWriterPlugIns(formatName);
String fileExtension = null;
if (writerPlugIns.hasNext()) {
SnapFileFilter fileFilter = writerPlugIns.next().getProductFileFilter();
if (fileFilter != null) {
fileExtension = fileFilter.getDefaultExtension();
}
}
return fileExtension;
}
}