/*
* 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.nav;
import com.bc.ceres.glayer.CollectionLayer;
import com.bc.ceres.glayer.Layer;
import com.bc.ceres.glayer.LayerFilter;
import com.bc.ceres.glayer.support.ImageLayer;
import com.bc.ceres.glayer.swing.DefaultLayerCanvasModel;
import com.bc.ceres.glayer.swing.LayerCanvas;
import com.bc.ceres.glayer.swing.LayerCanvasModel;
import com.bc.ceres.grender.Rendering;
import com.bc.ceres.grender.Viewport;
import com.bc.ceres.grender.ViewportListener;
import com.bc.ceres.grender.support.DefaultViewport;
import org.esa.snap.rcp.windows.NavigationTopComponent;
import org.esa.snap.ui.product.ProductSceneView;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class NavigationCanvas extends JPanel {
private final NavigationTopComponent navigationWindow;
private LayerCanvas thumbnailCanvas;
private static final DefaultLayerCanvasModel NULL_MODEL = new DefaultLayerCanvasModel(new CollectionLayer(),
new DefaultViewport());
private ObservedViewportHandler observedViewportHandler;
private Rectangle2D moveSliderRect;
private boolean adjustingObservedViewport;
private boolean debug = false;
public NavigationCanvas(NavigationTopComponent navigationWindow) {
super(new BorderLayout());
setOpaque(true);
this.navigationWindow = navigationWindow;
thumbnailCanvas = new LayerCanvas();
thumbnailCanvas.setBackground(ProductSceneView.DEFAULT_IMAGE_BACKGROUND_COLOR);
thumbnailCanvas.setLayerFilter(new LayerFilter() {
@Override
public boolean accept(Layer layer) {
return layer instanceof ImageLayer;
}
});
thumbnailCanvas.addOverlay(new LayerCanvas.Overlay() {
@Override
public void paintOverlay(LayerCanvas canvas, Rendering rendering) {
if (moveSliderRect != null && !moveSliderRect.isEmpty()) {
Graphics2D g = rendering.getGraphics();
g.setColor(new Color(getForeground().getRed(), getForeground().getGreen(),
getForeground().getBlue(), 82));
final Rectangle bounds = moveSliderRect.getBounds();
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
g.setColor(getForeground());
g.draw3DRect(bounds.x - 1, bounds.y - 1, bounds.width + 2, bounds.height + 2, true);
g.draw3DRect(bounds.x, bounds.y, bounds.width, bounds.height, false);
}
}
});
add(thumbnailCanvas, BorderLayout.CENTER);
final MouseHandler mouseHandler = new MouseHandler();
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
observedViewportHandler = new ObservedViewportHandler();
}
@Override
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
thumbnailCanvas.getViewport().setViewBounds(new Rectangle(x, y, width, height));
thumbnailCanvas.zoomAll();
updateMoveSliderRect();
}
/**
* This method ignores the given parameter. It is an empty implementation to
* prevent from setting borders on this canvas.
*
* @param border is ignored
*/
@Override
public void setBorder(Border border) {
}
public void handleViewChanged(ProductSceneView oldView, ProductSceneView newView) {
if (debug) {
System.out.println("NavigationCanvas.handleViewChanged(): " + System.currentTimeMillis());
System.out.println(" oldView = " + (oldView == null ? "null" : oldView.getSceneName()));
System.out.println(" newView = " + (newView == null ? "null" : newView.getSceneName()));
}
if (oldView != null) {
Viewport observedViewport = oldView.getLayerCanvas().getViewport();
observedViewport.removeListener(observedViewportHandler);
}
if (newView != null) {
Viewport observedViewport = newView.getLayerCanvas().getViewport();
observedViewport.addListener(observedViewportHandler);
final Rectangle bounds;
if (getBounds().isEmpty()) {
bounds = new Rectangle(0, 0, 100, 100);
} else {
bounds = getBounds();
}
Viewport thumbnailViewport = new DefaultViewport(bounds, observedViewport.isModelYAxisDown());
thumbnailViewport.setOrientation(observedViewport.getOrientation());
LayerCanvasModel thumbnailCanvasModel = new DefaultLayerCanvasModel(newView.getRootLayer(),
thumbnailViewport);
thumbnailCanvas.setModel(thumbnailCanvasModel);
thumbnailCanvas.zoomAll();
} else {
thumbnailCanvas.setModel(NULL_MODEL);
}
updateMoveSliderRect();
}
private void updateMoveSliderRect() {
ProductSceneView currentView = getNavigationWindow().getCurrentView();
if (currentView != null) {
Viewport viewport = currentView.getLayerCanvas().getViewport();
Rectangle viewBounds = viewport.getViewBounds();
AffineTransform m2vTN = thumbnailCanvas.getViewport().getModelToViewTransform();
AffineTransform v2mVP = viewport.getViewToModelTransform();
moveSliderRect = m2vTN.createTransformedShape(v2mVP.createTransformedShape(viewBounds)).getBounds2D();
} else {
moveSliderRect = new Rectangle2D.Double();
}
if (debug) {
System.out.println("NavigationCanvas.updateMoveSliderRect(): " + System.currentTimeMillis());
if (currentView != null) {
Viewport viewport = currentView.getLayerCanvas().getViewport();
System.out.println(
" currentView = " + currentView.getSceneName() + ", viewBounds = " + viewport.getViewBounds() + ", viewBounds = " + viewport.getViewBounds());
} else {
System.out.println(" currentView = null");
}
System.out.println(" moveSliderRect = " + moveSliderRect);
}
repaint();
}
private void handleMoveSliderRectChanged() {
ProductSceneView view = getNavigationWindow().getCurrentView();
if (view != null) {
adjustingObservedViewport = true;
Point2D location = new Point2D.Double(moveSliderRect.getMinX(), moveSliderRect.getMinY());
thumbnailCanvas.getViewport().getViewToModelTransform().transform(location, location);
getNavigationWindow().setModelOffset(location.getX(), location.getY());
adjustingObservedViewport = false;
}
}
private NavigationTopComponent getNavigationWindow() {
return navigationWindow;
}
private class ObservedViewportHandler implements ViewportListener {
@Override
public void handleViewportChanged(Viewport observedViewport, boolean orientationChanged) {
if (!adjustingObservedViewport) {
if (orientationChanged) {
thumbnailCanvas.getViewport().setOrientation(observedViewport.getOrientation());
thumbnailCanvas.zoomAll();
}
updateMoveSliderRect();
}
}
}
private class MouseHandler extends MouseInputAdapter {
private Point pickPoint;
private Point sliderPoint;
@Override
public void mousePressed(MouseEvent e) {
pickPoint = e.getPoint();
if (!moveSliderRect.contains(pickPoint)) {
final int x1 = pickPoint.x - moveSliderRect.getBounds().width / 2;
final int y1 = pickPoint.y - moveSliderRect.getBounds().height / 2;
moveSliderRect.setRect(x1, y1, moveSliderRect.getWidth(), moveSliderRect.getHeight());
repaint();
}
sliderPoint = moveSliderRect.getBounds().getLocation();
}
@Override
public void mouseReleased(MouseEvent e) {
repaint();
handleMoveSliderRectChanged();
}
@Override
public void mouseDragged(MouseEvent e) {
final int x1 = sliderPoint.x + (e.getX() - pickPoint.x);
final int y1 = sliderPoint.y + (e.getY() - pickPoint.y);
moveSliderRect.setRect(x1, y1, moveSliderRect.getWidth(), moveSliderRect.getHeight());
repaint();
handleMoveSliderRectChanged();
}
}
}