gt:         Product product = view.getProduct();
context: /*
   * 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.rcp.magicwand;
  
  import com.bc.ceres.glayer.Layer;
  import com.bc.ceres.glayer.LayerType;
  import com.bc.ceres.glayer.support.AbstractLayerListener;
  import com.bc.ceres.swing.figure.ViewportInteractor;
  import com.bc.ceres.swing.undo.UndoContext;
  import org.esa.snap.framework.datamodel.Band;
  import org.esa.snap.framework.datamodel.Mask;
  import org.esa.snap.framework.datamodel.Product;
  import org.esa.snap.framework.datamodel.ProductNodeGroup;
  import org.esa.snap.framework.ui.UIUtils;
  import org.esa.snap.framework.ui.product.ProductSceneView;
  import org.esa.snap.glayer.MaskLayerType;
  import org.esa.snap.jai.ImageManager;
  import org.esa.snap.rcp.SnapApp;
  import org.esa.snap.rcp.SnapDialogs;
  import org.esa.snap.util.io.FileUtils;
  
  import javax.swing.JDialog;
  import javax.swing.undo.AbstractUndoableEdit;
  import javax.swing.undo.CannotRedoException;
  import javax.swing.undo.CannotUndoException;
  import java.awt.Point;
  import java.awt.Window;
  import java.awt.event.MouseEvent;
  import java.awt.geom.AffineTransform;
  import java.awt.geom.NoninvertibleTransformException;
  import java.awt.geom.Point2D;
  import java.io.IOException;
  import java.util.List;
  
  /**
   * An interactor that lets users create masks using a "magic wand".
   * The mask comprises all pixels in the image that are "spectrally" close to the pixel that
   * has been selected using the magic wand.
   *
   * @author Norman Fomferra
   * @since BEAM 4.10
   */
  public class MagicWandInteractor extends ViewportInteractor implements MagicWandModel.Listener {
  
      private static final String DIALOG_TITLE = "Magic Wand Tool";
  
      private JDialog optionsWindow;
      private final MyLayerListener layerListener;
  
      private MagicWandModel model;
      private UndoContext undoContext;
      private MagicWandForm form;
  
      private boolean modelModified;
  
      public MagicWandInteractor() {
          layerListener = new MyLayerListener();
          model = new MagicWandModel();
          model.addListener(this);
      }
  
      public boolean isModelModified() {
          return modelModified;
      }
  
      public void setModelModified(boolean modelModified) {
          this.modelModified = modelModified;
      }
  
      @Override
      public void modelChanged(MagicWandModel model, boolean recomputeMask) {
          setModelModified(true);
  
          if (recomputeMask) {
              updateMask();
          }
          if (form != null) {
              updateForm();
          }
      }
  
      void updateForm() {
          if (form.getSettingsFile() != null) {
              optionsWindow.setTitle(DIALOG_TITLE + " - " + FileUtils.getFilenameWithoutExtension(form.getSettingsFile()));
          } else {
              optionsWindow.setTitle(DIALOG_TITLE);
          }
          form.getBindingContext().adjustComponents();
          form.updateState();
      }
  
      public Window getOptionsWindow() {
          return optionsWindow;
      }
  
      static double[] getSpectrum(List<Band> bands, int pixelX, int pixelY) throws IOException {
          final double[] pixel = new double[1];
          final double[] spectrum = new double[bands.size()];
  
          for (int i = 0; i < bands.size(); i++) {
              final Band band = bands.get(i);
              band.readPixels(pixelX, pixelY, 1, 1, pixel, com.bc.ceres.core.ProgressMonitor.NULL);
              final double value;
              if (band.isPixelValid(pixelX, pixelY)) {
                  value = pixel[0];
              } else {
                  value = Double.NaN;
              }
              spectrum[i] = value;
          }
  
          return spectrum;
      }
  
      @Override
      public boolean activate() {
          if (optionsWindow == null) {
              optionsWindow = createOptionsWindow();
          }
          optionsWindow.setVisible(true);
  
          ProductSceneView view = SnapApp.getDefault().getSelectedProductSceneView();
          if (view != null) {
              view.getRootLayer().addListener(layerListener);
          }
  
          return super.activate();
      }
  
      @Override
      public void deactivate() {
          super.deactivate();
  
          if (optionsWindow != null) {
              optionsWindow.setVisible(false);
          }
  
          ProductSceneView view = SnapApp.getDefault().getSelectedProductSceneView();
          if (view != null) {
              view.getRootLayer().removeListener(layerListener);
          }
      }
  
      @Override
      public void mouseClicked(MouseEvent event) {
  
          final ProductSceneView view = SnapApp.getDefault().getSelectedProductSceneView();
          if (view == null) {
              return;
          }
  
          final Product product = view.getProduct();
          if (!ensureBandNamesSet(view, product)) {
              return;
          }
  
          List<Band> bands = model.getBands(product);
          if (bands == null) {
              if (!handleInvalidBandFilter(view)) {
                  return;
              }
              bands = model.getBands(product);
              if (bands == null) {
                  // Should not come here.
                  return;
              }
          }
  
          Point pixelPos = getPixelPos(product, event);
          if (pixelPos == null) {
              return;
          }
  
          final double[] spectrum;
          try {
              spectrum = getSpectrum(bands, pixelPos.x, pixelPos.y);
          } catch (IOException e1) {
              return;
          }
  
          MagicWandModel oldModel = getModel().clone();
          getModel().addSpectrum(spectrum);
          MagicWandModel newModel = getModel().clone();
  
          ensureMaskVisible(view);
  
          undoContext.postEdit(new MyUndoableEdit(oldModel, newModel));
      }
  
      void clearSpectra() {
          MagicWandModel oldModel = getModel().clone();
          getModel().clearSpectra();
          MagicWandModel newModel = getModel().clone();
          undoContext.postEdit(new MyUndoableEdit(oldModel, newModel));
      }
  
      private void ensureMaskVisible(ProductSceneView view) {
  