/*
* Copyright (C) 2012 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.statistics;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNodeEvent;
import org.esa.snap.core.datamodel.ProductNodeListener;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.core.datamodel.VectorDataNode;
import org.esa.snap.core.util.SystemUtils;
import org.esa.snap.ui.UIUtils;
import org.esa.snap.ui.tool.ToolButtonFactory;
import org.openide.windows.TopComponent;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* A general page within the statistics window.
*
* @author Marco Peters
*/
public abstract class PagePanel extends JPanel implements ProductNodeListener {
private final TopComponent parentComponent;
private final String helpId;
private final String title;
private Product product;
private boolean productChanged;
private RasterDataNode raster;
private boolean rasterChanged;
private VectorDataNode vectorData;
private boolean vectorDataChanged;
private PagePanel alternativeView;
protected PagePanel(TopComponent parentComponent, String helpId, String title) {
super(new BorderLayout(4, 4));
this.parentComponent = parentComponent;
this.helpId = helpId;
this.title = title;
setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
setPreferredSize(new Dimension(600, 320));
}
public String getTitle() {
return title;
}
public VectorDataNode getVectorDataNode() {
return vectorData;
}
public TopComponent getParentDialog() {
return parentComponent;
}
/**
* Notified when a node was added.
*
* @param event the product node which the listener to be notified
*/
@Override
public void nodeAdded(ProductNodeEvent event) {
}
/**
* Notified when a node changed.
*
* @param event the product node which the listener to be notified
*/
@Override
public void nodeChanged(ProductNodeEvent event) {
}
/**
* Notified when a node's data changed.
*
* @param event the product node which the listener to be notified
*/
@Override
public void nodeDataChanged(ProductNodeEvent event) {
}
/**
* Notified when a node was removed.
*
* @param event the product node which the listener to be notified
*/
@Override
public void nodeRemoved(ProductNodeEvent event) {
}
protected Product getProduct() {
return product;
}
protected RasterDataNode getRaster() {
return raster;
}
protected boolean isRasterChanged() {
return rasterChanged;
}
protected boolean isProductChanged() {
return productChanged;
}
protected boolean isVectorDataNodeChanged() {
return vectorDataChanged;
}
protected void setRaster(RasterDataNode raster) {
if (this.raster != raster) {
this.raster = raster;
rasterChanged = true;
}
}
protected void setVectorDataNode(VectorDataNode vectorDataNode) {
if (this.vectorData != vectorDataNode) {
this.vectorData = vectorDataNode;
vectorDataChanged = true;
}
}
/**
* @return {@code true} if {@link #handleNodeSelectionChanged} shall be called in a reaction to a node selection change.
*/
protected boolean mustHandleSelectionChange() {
return isRasterChanged() || isProductChanged();
}
/**
* Called in reaction to a node selection change and if {@link #mustHandleSelectionChange()} returns {@code true}.
* The default implementation calls {@link #updateComponents}.
*/
protected void handleNodeSelectionChanged() {
updateComponents();
}
/**
* Called in reaction to a layer content change.
* The default implementation does nothing.
*/
protected void handleLayerContentChanged() {
}
/**
* Initialises the panel's sub-components.
*/
protected abstract void initComponents();
/**
* Updates the panel's sub-components as a reaction to a product node selection change.
*/
protected abstract void updateComponents();
protected abstract String getDataAsText();
protected void handlePopupCreated(JPopupMenu popupMenu) {
}
protected boolean checkDataToClipboardCopy() {
return true;
}
protected AbstractButton getHelpButton() {
if (helpId != null) {
final AbstractButton helpButton = ToolButtonFactory.createButton(UIUtils.loadImageIcon("icons/Help22.png"),
false);
helpButton.setToolTipText("Help.");
helpButton.setName("helpButton");
helpButton.addActionListener(e -> parentComponent.getHelpCtx().display());
// HelpSys.enableHelpKey(getParentDialogContentPane(), helpId);
return helpButton;
}
return null;
}
protected JMenuItem createCopyDataToClipboardMenuItem() {
final JMenuItem menuItem = new JMenuItem("Copy Data to Clipboard"); /*I18N*/
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (checkDataToClipboardCopy()) {
copyTextDataToClipboard();
}
}
});
return menuItem;
}
protected void copyTextDataToClipboard() {
final Cursor oldCursor = getCursor();
try {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
final String dataAsText = getDataAsText();
if (dataAsText != null) {
SystemUtils.copyToClipboard(dataAsText);
}
} finally {
setCursor(oldCursor);
}
}
protected boolean hasAlternativeView(){
return alternativeView != null;
}
protected void showAlternativeView() {
final TopComponent parent = (TopComponent) this.getParent();
parent.remove(this);
this.setVisible(false);
parent.add(alternativeView, BorderLayout.CENTER);
alternativeView.setVisible(true);
parent.revalidate();
}
protected void setAlternativeView(PagePanel alternativeView) {
this.alternativeView = alternativeView;
}
protected PagePanel getAlternativeView() {
return alternativeView;
}
void selectionChanged(Product product, RasterDataNode raster, VectorDataNode vectorDataNode) {
if (raster != getRaster() || product != getProduct() || vectorDataNode != getVectorDataNode()) {
setRaster(raster);
setProduct(product);
setVectorDataNode(vectorDataNode);
if (mustHandleSelectionChange()) {
handleNodeSelectionChanged();
rasterChanged = false;
productChanged = false;
vectorDataChanged = false;
}
}
}
private void maybeOpenPopup(MouseEvent mouseEvent) {
if (mouseEvent.isPopupTrigger()) {
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(createCopyDataToClipboardMenuItem());
handlePopupCreated(popupMenu);
final Point point = SwingUtilities.convertPoint(mouseEvent.getComponent(), mouseEvent.getPoint(), this);
popupMenu.show(this, point.x, point.y);
}
}
private String getProductNodeDisplayName() {
if (raster != null) {
return raster.getDisplayName();
} else {
if (product != null) {
return product.getDisplayName();
} else {
return "";
}
}
}
private void transferProductNodeListener(Product oldProduct, Product newProduct) {
if (oldProduct != newProduct) {
if (oldProduct != null) {
oldProduct.removeProductNodeListener(this);
}
if (newProduct != null) {
newProduct.addProductNodeListener(this);
}
}
}
private void setProduct(Product product) {
if (this.product != product) {
transferProductNodeListener(this.product, product);
this.product = product;
productChanged = true;
}
}
class PopupHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
maybeOpenPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
maybeOpenPopup(e);
}
@Override
public void mouseClicked(MouseEvent e) {
maybeOpenPopup(e);
}
}
}