/*
* 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.layermanager.layersrc.shapefile;
import com.bc.ceres.glayer.Layer;
import com.bc.ceres.glayer.swing.LayerCanvas;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.ui.layer.AbstractLayerSourceAssistantPage;
import org.esa.snap.ui.layer.LayerSourcePageContext;
import org.esa.snap.ui.product.ProductSceneView;
import org.geotools.styling.Style;
import org.opengis.util.InternationalString;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.text.MessageFormat;
import java.util.concurrent.ExecutionException;
class ShapefileAssistantPage3 extends AbstractLayerSourceAssistantPage {
private JComboBox styleList;
private JPanel mapPanel;
private SwingWorker<Layer, Object> worker;
private boolean shapeFileLoaded;
private JLabel infoLabel;
private JLabel mapLabel;
private ShapefileAssistantPage3.ResizeAdapter resizeAdapter;
ShapefileAssistantPage3() {
super("Layer Preview");
shapeFileLoaded = false;
}
@Override
public boolean validatePage() {
return shapeFileLoaded;
}
@Override
public Component createPageComponent() {
mapPanel = new JPanel(new BorderLayout());
mapLabel = new JLabel();
mapLabel.setHorizontalAlignment(JLabel.CENTER);
mapPanel.add(mapLabel, BorderLayout.CENTER);
LayerSourcePageContext context = getContext();
String filePath = (String) context.getPropertyValue(ShapefileLayerSource.PROPERTY_NAME_FILE_PATH);
String fileName = new File(filePath).getName();
infoLabel = new JLabel();
styleList = new JComboBox();
styleList.setRenderer(new StyleListCellRenderer());
styleList.addItemListener(new StyleSelectionListener());
styleList.setPreferredSize(new Dimension(100, styleList.getPreferredSize().height));
JPanel panel2 = new JPanel(new BorderLayout(4, 4));
panel2.setBorder(new EmptyBorder(4, 4, 4, 4));
panel2.add(new JLabel("Style:"), BorderLayout.WEST);
panel2.add(styleList, BorderLayout.EAST);
JPanel panel3 = new JPanel(new BorderLayout(4, 4));
panel3.setBorder(new EmptyBorder(4, 4, 4, 4));
panel3.add(new JLabel(String.format("<html><b>%s</b>", fileName)), BorderLayout.CENTER);
panel3.add(panel2, BorderLayout.EAST);
JPanel panel = new JPanel(new BorderLayout(4, 4));
panel.setBorder(new EmptyBorder(4, 4, 4, 4));
panel.add(panel3, BorderLayout.NORTH);
panel.add(mapPanel, BorderLayout.CENTER);
panel.add(infoLabel, BorderLayout.SOUTH);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updateMap();
}
});
return panel;
}
@Override
public boolean performFinish() {
LayerSourcePageContext context = getContext();
new ShapefileLayerLoader(context).execute();
return true;
}
private void updateMap() {
if (worker != null && !worker.isDone()) {
try {
worker.cancel(true);
} catch (Throwable ignore) {
// ok
}
}
mapLabel.setText("<html><i>Loading map...</i></html>");
addToMapPanel(mapLabel);
final LayerSourcePageContext context = getContext();
context.getWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
shapeFileLoaded = false;
context.updateState();
worker = new ShapeFilePreviewLoader(context);
worker.execute();
}
private void addToMapPanel(Component component) {
if (resizeAdapter == null && component instanceof LayerCanvas) {
final LayerCanvas layerCanvas = (LayerCanvas) component;
resizeAdapter = new ResizeAdapter(layerCanvas);
mapPanel.addComponentListener(resizeAdapter);
} else {
mapPanel.removeComponentListener(resizeAdapter);
resizeAdapter = null;
}
mapPanel.removeAll();
mapPanel.add(component, BorderLayout.CENTER);
}
private class StyleSelectionListener implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
LayerSourcePageContext context = getContext();
context.setPropertyValue(ShapefileLayerSource.PROPERTY_NAME_SELECTED_STYLE, styleList.getSelectedItem());
context.updateState();
updateMap();
}
}
private static class StyleListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
String text = null;
if (value != null) {
Style style = (Style) value;
InternationalString title = style.getDescription().getTitle();
if (title != null) {
text = title.toString();
}else {
text = "Default Styler";
}
}
label.setText(text);
return label;
}
}
private class ShapeFilePreviewLoader extends ShapefileLoader {
private ShapeFilePreviewLoader(LayerSourcePageContext context) {
super(context);
}
@Override
protected void done() {
final LayerSourcePageContext context = getContext();
context.getWindow().setCursor(Cursor.getDefaultCursor());
final ProductSceneView sceneView = SnapApp.getDefault().getSelectedProductSceneView();
try {
final Layer layer = get();
final LayerCanvas layerCanvas = new LayerCanvas(layer);
layerCanvas.getViewport().setModelYAxisDown(sceneView.getLayerCanvas().getViewport().isModelYAxisDown());
addToMapPanel(layerCanvas);
final Rectangle2D bounds = layer.getModelBounds();
infoLabel.setText(String.format("Model bounds [%.3f : %.3f, %.3f : %.3f]",
bounds.getMinX(), bounds.getMinY(),
bounds.getMaxX(), bounds.getMaxY()));
Style[] styles = (Style[]) context.getPropertyValue(ShapefileLayerSource.PROPERTY_NAME_STYLES);
Style selectedStyle = (Style) context.getPropertyValue(ShapefileLayerSource.PROPERTY_NAME_SELECTED_STYLE);
styleList.setModel(new DefaultComboBoxModel(styles));
styleList.setSelectedItem(selectedStyle);
shapeFileLoaded = true;
} catch (ExecutionException e) {
final String errorMessage = MessageFormat.format("<html><b>Error:</b> <i>{0}</i></html>",
e.getMessage());
e.printStackTrace();
mapLabel.setText(errorMessage);
addToMapPanel(mapLabel);
} catch (InterruptedException ignore) {
// ok
} finally {
context.updateState();
}
}
}
private static class ResizeAdapter extends ComponentAdapter {
private final LayerCanvas layerCanvas;
private ResizeAdapter(LayerCanvas layerCanvas) {
this.layerCanvas = layerCanvas;
}
@Override
public void componentResized(ComponentEvent e) {
layerCanvas.zoomAll();
}
}
}