/*
* Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca
*
* 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.worldwind;
import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.layers.Earth.MSVirtualEarthLayer;
import gov.nasa.worldwind.layers.Earth.OSMMapnikLayer;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.layers.LayerList;
import gov.nasa.worldwind.layers.placename.PlaceNameLayer;
import gov.nasa.worldwindx.examples.WMSLayersPanel;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNode;
import org.esa.snap.core.util.SystemUtils;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.rcp.util.Dialogs;
import org.esa.snap.rcp.util.SelectionSupport;
import org.esa.snap.worldwind.layers.DefaultProductLayer;
import org.esa.snap.worldwind.layers.WWLayer;
import org.esa.snap.worldwind.layers.WWLayerDescriptor;
import org.esa.snap.worldwind.layers.WWLayerRegistry;
import org.netbeans.api.annotations.common.NullAllowed;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URISyntaxException;
import static org.esa.snap.rcp.SnapApp.SelectionSourceHint.*;
@TopComponent.Description(
preferredID = "WWAnalysisToolView",
iconBase = "org/esa/snap/worldwind/icons/worldwind.png",
persistenceType = TopComponent.PERSISTENCE_NEVER
)
@TopComponent.Registration(
mode = "editor",
openAtStartup = false,
position = 60
)
@ActionID(category = "Window", id = "org.esa.snap.worldwind.WWAnalysisToolView")
@ActionReferences({
@ActionReference(path = "Menu/View/Tool Windows"),
@ActionReference(path = "Toolbars/Tool Windows")
})
@TopComponent.OpenActionRegistration(
displayName = "#CTL_WorldWindAnalysisTopComponentName",
preferredID = "WWAnalysisToolView"
)
@NbBundle.Messages({
"CTL_WorldWindAnalysisTopComponentName=WorldWind Analysis View",
"CTL_WorldWindAnalysisTopComponentDescription=WorldWind Analysis World Map",
})
/**
* The window displaying the full WorldWind 3D for analysis.
*
*/
public class WWAnalysisToolView extends WWBaseToolView implements WWView {
private LayerPanel layerPanel = null;
private ProductPanel productPanel = null;
private final Dimension wmsPanelSize = new Dimension(400, 600);
private final JTabbedPane tabbedPane = new JTabbedPane();
private int previousTabIndex = 0;
private static final boolean includeStatusBar = true;
private static final boolean includeLayerPanel = false;
private static final boolean includeProductPanel = true;
private static final boolean includeWMSPanel = false;
private static final String[] servers = new String[]
{
"http://neowms.sci.gsfc.nasa.gov/wms/wms",
//"http://mapserver.flightgear.org/cgi-bin/landcover",
"http://wms.jpl.nasa.gov/wms.cgi",
"http://worldwind46.arc.nasa.gov:8087/wms"
};
public WWAnalysisToolView() {
setDisplayName("WorldWind Analysis");
setLayout(new BorderLayout(4, 4));
setBorder(new EmptyBorder(4, 4, 4, 4));
add(createControl(), BorderLayout.CENTER);
//SnapApp.getDefault().getSelectionSupport(ProductSceneView.class).addHandler((oldValue, newValue) -> setCurrentView(newValue));
}
public JComponent createControl() {
final Window windowPane = SwingUtilities.getWindowAncestor(this);
if (windowPane != null)
windowPane.setSize(800, 400);
final JPanel mainPane = new JPanel(new BorderLayout(4, 4));
mainPane.setSize(new Dimension(300, 300));
// world wind canvas
initialize(mainPane);
return mainPane;
}
private static void insertTiledLayer(final WorldWindow wwd, final Layer layer) {
int position = 0;
final LayerList layers = wwd.getModel().getLayers();
for (Layer l : layers) {
if (l instanceof PlaceNameLayer) {
position = layers.indexOf(l);
break;
}
}
layers.add(position, layer);
}
private void initialize(final JPanel mainPane) {
SystemUtils.LOG.info("INITIALIZE IN WWAnalysisToolView CALLED" + " includeLayerPanel " + includeLayerPanel +
" includeProductPanel " + includeProductPanel);
final WWView toolView = this;
final SwingWorker worker = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
// Create the WorldWindow.
try {
// share resources from existing WorldWind Canvas
WorldWindowGLCanvas shareWith = findWorldWindView();
createWWPanel(shareWith, includeStatusBar, false, false);
wwjPanel.addLayerPanelLayer();
wwjPanel.addElevation();
final MSVirtualEarthLayer virtualEarthLayerA = new MSVirtualEarthLayer(MSVirtualEarthLayer.LAYER_AERIAL);
virtualEarthLayerA.setName("MS Bing Aerial");
insertTiledLayer(getWwd(), virtualEarthLayerA);
final MSVirtualEarthLayer virtualEarthLayerR = new MSVirtualEarthLayer(MSVirtualEarthLayer.LAYER_ROADS);
virtualEarthLayerR.setName("MS Bing Roads");
virtualEarthLayerR.setEnabled(false);
insertTiledLayer(getWwd(), virtualEarthLayerR);
final MSVirtualEarthLayer virtualEarthLayerH = new MSVirtualEarthLayer(MSVirtualEarthLayer.LAYER_HYBRID);
virtualEarthLayerH.setName("MS Bing Hybrid");
virtualEarthLayerH.setEnabled(false);
insertTiledLayer(getWwd(), virtualEarthLayerH);
final OSMMapnikLayer streetLayer = new OSMMapnikLayer();
streetLayer.setOpacity(0.7);
streetLayer.setEnabled(false);
streetLayer.setName("Open Street Map");
insertTiledLayer(getWwd(), streetLayer);
final WWLayerDescriptor[] wwLayerDescriptors = WWLayerRegistry.getInstance().getWWLayerDescriptors();
for (WWLayerDescriptor layerDescriptor : wwLayerDescriptors) {
if (layerDescriptor.showIn3DToolView()) {
final WWLayer wwLayer = layerDescriptor.createWWLayer();
insertTiledLayer(getWwd(), wwLayer);
wwLayer.setOpacity(0.8);
// CHANGED: otherwise the objects in the product layer won't react to the select listener
// wwLayer.setPickEnabled(false);
if (wwLayer instanceof DefaultProductLayer) {
((DefaultProductLayer) wwLayer).setEnableSurfaceImages(true);
}
}
}
// update world map window with the information of the currently activated product scene view.
final SnapApp snapApp = SnapApp.getDefault();
snapApp.getProductManager().addListener(new WWProductManagerListener(toolView));
snapApp.getSelectionSupport(ProductNode.class).addHandler(new SelectionSupport.Handler<ProductNode>() {
@Override
public void selectionChange(@NullAllowed ProductNode oldValue, @NullAllowed ProductNode newValue) {
if (newValue != null) {
setSelectedProduct(newValue.getProduct());
} else {
setSelectedProduct(null);
}
}
});
setProducts(snapApp.getProductManager().getProducts());
setSelectedProduct(snapApp.getSelectedProduct(VIEW));
// Put the pieces together.
mainPane.add(wwjPanel, BorderLayout.CENTER);
if (includeLayerPanel) {
layerPanel = new LayerPanel(wwjPanel.getWwd(), null);
mainPane.add(layerPanel, BorderLayout.WEST);
layerPanel.add(makeControlPanel(), BorderLayout.SOUTH);
layerPanel.update(getWwd());
}
if (includeProductPanel) {
final LayerList layerList = getWwd().getModel().getLayers();
Layer layer = layerList.getLayerByName("Products");
productPanel = new ProductPanel(wwjPanel.getWwd(), (DefaultProductLayer) layer);
mainPane.add(productPanel, BorderLayout.WEST);
productPanel.add(makeControlPanel(), BorderLayout.SOUTH);
productPanel.update(getWwd());
}
if (includeWMSPanel) {
tabbedPane.add(new JPanel());
tabbedPane.setTitleAt(0, "+");
tabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent changeEvent) {
if (tabbedPane.getSelectedIndex() != 0) {
previousTabIndex = tabbedPane.getSelectedIndex();
return;
}
final String server = JOptionPane.showInputDialog("Enter WMS server URL");
if (server == null || server.length() < 1) {
tabbedPane.setSelectedIndex(previousTabIndex);
return;
}
// Respond by adding a new WMSLayerPanel to the tabbed pane.
if (addTab(tabbedPane.getTabCount(), server.trim()) != null)
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
}
});
// Create a tab for each server and add it to the tabbed panel.
for (int i = 0; i < servers.length; i++) {
addTab(i + 1, servers[i]); // i+1 to place all server tabs to the right of the Add Server tab
}
// Display the first server pane by default.
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() > 0 ? 1 : 0);
previousTabIndex = tabbedPane.getSelectedIndex();
mainPane.add(tabbedPane, BorderLayout.EAST);
}
wwjPanel.getWwd().addSelectListener(new SelectListener() {
public void selected(SelectEvent event) {
/*
System.out.println("event.getTopObject() " + event.getTopObject());
if (event.getTopObject() instanceof AnalyticSurface.AnalyticSurfaceObject) {
System.out.println("pick point: " + event.getPickPoint());
Point pickPoint = event.getPickPoint();
if (pickPoint != null) {
System.out.println("position: " + wwjPanel.getWwd().getView().computePositionFromScreenPoint(pickPoint.getX(), pickPoint.getY()));
}
//AnalyticSurface surface = (AnalyticSurface) event.getTopObject();
//System.out.println("dimensions " + surface.getDimensions());
//System.out.println("getCorners " + surface.getSector().getCorners());
}
*/
final LayerList layerList = getWwd().getModel().getLayers();
for (Layer layer : layerList) {
if (layer instanceof WWLayer) {
final WWLayer wwLayer = (WWLayer) layer;
wwLayer.updateInfoAnnotation(event);
}
}
}
});
} catch (Throwable e) {
SnapApp.getDefault().handleError("Unable to initialize WWAnalysisToolView: " + e.getMessage(), e);
}
return null;
}
};
worker.execute();
}
private JPanel makeControlPanel() {
final JPanel controlPanel = new JPanel(new GridLayout(2, 1, 5, 5));
controlPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
final LayerList layerList = getWwd().getModel().getLayers();
for (Layer layer : layerList) {
if (layer instanceof WWLayer) {
final WWLayer wwLayer = (WWLayer) layer;
final JPanel layerControlPanel = wwLayer.getControlPanel(getWwd());
controlPanel.add(layerControlPanel);
}
}
return controlPanel;
}
@Override
public void setSelectedProduct(final Product product) {
super.setSelectedProduct(product);
if (productPanel != null)
productPanel.update(getWwd());
}
@Override
public void setProducts(final Product[] products) {
super.setProducts(products);
if (productPanel != null)
productPanel.update(getWwd());
}
@Override
public void removeProduct(final Product product) {
super.removeProduct(product);
if (productPanel != null)
productPanel.update(getWwd());
}
private WMSLayersPanel addTab(final int position, final String server) {
// Add a server to the tabbed dialog.
try {
final WMSLayersPanel layersPanel = new WMSLayersPanel(wwjPanel.getWwd(), server, wmsPanelSize);
this.tabbedPane.add(layersPanel, BorderLayout.CENTER);
final String title = layersPanel.getServerDisplayString();
this.tabbedPane.setTitleAt(position, title != null && title.length() > 0 ? title : server);
// Add a listener to notice wms layer selections and tell the layer panel to reflect the new state.
layersPanel.addPropertyChangeListener("LayersPanelUpdated", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
layerPanel.update(wwjPanel.getWwd());
}
});
return layersPanel;
} catch (URISyntaxException e) {
Dialogs.showError("Invalid Server URL", "Server URL is invalid");
tabbedPane.setSelectedIndex(previousTabIndex);
return null;
}
}
}