/*
* Copyright (C) 2014 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.tools;
import com.bc.ceres.core.Assert;
import org.esa.snap.core.datamodel.BasicPixelGeoCoding;
import org.esa.snap.core.datamodel.GeoCoding;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNode;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.rcp.util.Dialogs;
import org.esa.snap.ui.UIUtils;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.awt.UndoRedo;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.SwingWorker;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import java.awt.event.ActionEvent;
@ActionID(
category = "Tools",
id = "DetachPixelGeoCodingAction"
)
@ActionRegistration(
displayName = "#CTL_DetachPixelGeoCodingActionText",
popupText = "#CTL_DetachPixelGeoCodingActionText",
lazy = false
)
@ActionReference(path = "Menu/Tools", position = 220)
@Messages({
"CTL_DetachPixelGeoCodingActionText=Detach Pixel Geo-Coding...",
"CTL_DetachPixelGeoCodingDialogTitle=Detach Pixel Geo-Coding"
})
public class DetachPixelGeoCodingAction extends AbstractAction implements ContextAwareAction, LookupListener {
private final Lookup lookup;
public DetachPixelGeoCodingAction() {
this(Utilities.actionsGlobalContext());
}
public DetachPixelGeoCodingAction(Lookup lkp) {
super(Bundle.CTL_DetachPixelGeoCodingActionText());
this.lookup = lkp;
Lookup.Result<ProductNode> lkpContext = lkp.lookupResult(ProductNode.class);
lkpContext.addLookupListener(WeakListeners.create(LookupListener.class, this, lkpContext));
putValue(Action.SHORT_DESCRIPTION, "Detach a pixel based geo-coding from the selected product");
setEnableState();
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
detachPixelGeoCoding(lookup.lookup(ProductNode.class).getProduct());
}
@Override
public Action createContextAwareInstance(Lookup actionContext) {
return new DetachPixelGeoCodingAction(actionContext);
}
@Override
public void resultChanged(LookupEvent ev) {
setEnableState();
}
private static void detachPixelGeoCoding(final Product product) {
final SwingWorker swingWorker = new SwingWorker<Throwable, Object>() {
@Override
protected Throwable doInBackground() throws Exception {
try {
GeoCoding geoCoding = product.getSceneGeoCoding();
if (geoCoding instanceof BasicPixelGeoCoding) {
final BasicPixelGeoCoding pixelGeoCoding = (BasicPixelGeoCoding) geoCoding;
final GeoCoding delegate = pixelGeoCoding.getPixelPosEstimator();
product.setSceneGeoCoding(delegate);
UndoRedo.Manager undoManager = SnapApp.getDefault().getUndoManager(product);
if (undoManager != null) {
undoManager.addEdit(new UndoableDetachGeoCoding<>(product, pixelGeoCoding));
}
}
} catch (Throwable e) {
return e;
}
return null;
}
@Override
public void done() {
try {
Throwable value;
try {
value = get();
} catch (Exception e) {
value = e;
}
String dialogTitle = Bundle.CTL_DetachPixelGeoCodingDialogTitle();
if (value != null) {
Dialogs.showError(dialogTitle, "An internal error occurred:\n" + value.getMessage());
} else {
Dialogs.showInformation(dialogTitle, "Pixel geo-coding has been detached.", null);
}
} finally {
UIUtils.setRootFrameDefaultCursor(SnapApp.getDefault().getMainFrame());
}
}
};
UIUtils.setRootFrameWaitCursor(SnapApp.getDefault().getMainFrame());
swingWorker.execute();
}
private void setEnableState() {
ProductNode productNode = lookup.lookup(ProductNode.class);
boolean state = false;
if (productNode != null) {
Product product = productNode.getProduct();
if (product != null) {
state = product.getSceneGeoCoding() instanceof BasicPixelGeoCoding;
}
}
setEnabled(state);
}
private static class UndoableDetachGeoCoding<T extends BasicPixelGeoCoding> extends AbstractUndoableEdit {
private Product product;
private T pixelGeoCoding;
public UndoableDetachGeoCoding(Product product, T pixelGeoCoding) {
Assert.notNull(product, "product");
Assert.notNull(pixelGeoCoding, "pixelGeoCoding");
this.product = product;
this.pixelGeoCoding = pixelGeoCoding;
}
@Override
public String getPresentationName() {
return Bundle.CTL_DetachPixelGeoCodingDialogTitle();
}
@Override
public void undo() throws CannotUndoException {
super.undo();
product.setSceneGeoCoding(pixelGeoCoding);
}
@Override
public void redo() throws CannotRedoException {
super.redo();
if (product.getSceneGeoCoding() == pixelGeoCoding) {
product.setSceneGeoCoding(pixelGeoCoding.getPixelPosEstimator());
}
}
@Override
public void die() {
pixelGeoCoding = null;
product = null;
}
}
}