/*
* (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* troger
*
* $Id$
*/
package org.nuxeo.ecm.platform.pictures.tiles.gwt.client.view;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingInfo;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModelListener;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel.TilingModelEvent;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Point;
import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Rectangle;
import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
/**
* @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
*/
public class TilingPreviewControllerPanel extends FocusPanel implements TilingModelListener {
private static final String DEFAULT_CLASS_NAME = "tilingPreviewControllerPanel";
private class ControllerMouseListener extends MouseListenerAdapter {
boolean mouseDown = false;
int x, y;
@Override
public void onMouseDown(Widget sender, int x, int y) {
mouseDown = true;
this.x = x;
this.y = y;
centerArea(x, y);
DOM.setStyleAttribute(imagesPanel.getElement(), "cursor", "move");
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseMove(Widget sender, int x, int y) {
if (mouseDown) {
moveArea(x - this.x, y - this.y);
this.x = x;
this.y = y;
}
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseUp(Widget sender, int x, int y) {
if (mouseDown) {
mouseDown = false;
moveArea(x - this.x, y - this.y);
updateModel();
DOM.setStyleAttribute(imagesPanel.getElement(), "cursor", "default");
cancelEvent(Event.getCurrentEvent());
}
}
@Override
public void onMouseLeave(Widget sender) {
onMouseUp(sender, x, y);
cancelEvent(Event.getCurrentEvent());
}
}
private class ControllerBlockAllEventsListener extends MouseListenerAdapter {
@Override
public void onMouseDown(Widget sender, int x, int y) {
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseEnter(Widget sender) {
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseLeave(Widget sender) {
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseMove(Widget sender, int x, int y) {
cancelEvent(Event.getCurrentEvent());
}
@Override
public void onMouseUp(Widget sender, int x, int y) {
cancelEvent(Event.getCurrentEvent());
}
}
private final TilingInfo sourceTilingInfo;
private final TilingModel model;
private int totalWidth;
private int totalHeight;
private AbsolutePanel imagesPanel;
private double factor = 1;
private SelectedArea selectedArea;
private final Anchor anchor = new Anchor();
private final SimplePanel area = new SimplePanel();
private final FocusPanel anchorContainer = new FocusPanel(anchor);
private final ControllerMouseListener controllerMouseListener = new ControllerMouseListener();
private final ControllerBlockAllEventsListener blockAllEventsListener = new ControllerBlockAllEventsListener();
public TilingPreviewControllerPanel(TilingInfo sourceTilingInfo, TilingModel model) {
this.sourceTilingInfo = sourceTilingInfo;
this.model = model;
model.addListener(this);
imagesPanel = new AbsolutePanel();
totalWidth = (int) Math.round(sourceTilingInfo.getOriginalImageWidth() * sourceTilingInfo.getZoom());
totalHeight = (int) Math.round(sourceTilingInfo.getOriginalImageHeight() * sourceTilingInfo.getZoom());
imagesPanel.setPixelSize(totalWidth, totalHeight);
setWidget(imagesPanel);
// load the images corresponding to the first TilingInfo retrieved
loadImages();
createSelectedArea();
addMouseListener(controllerMouseListener);
setStyleName(DEFAULT_CLASS_NAME);
}
private void loadImages() {
int heightInTiles = sourceTilingInfo.getNbYTiles();
int widthInTiles = sourceTilingInfo.getNbXTiles();
for (int y = 0; y < heightInTiles; ++y) {
for (int x = 0; x < widthInTiles; ++x) {
String imageUrl = sourceTilingInfo.getBaseUrl() + "?x=" + x + "&y=" + y;
imageUrl += "&date=" + sourceTilingInfo.getLastModificationDate();
Image image = new Image(imageUrl) {
@Override
public void onBrowserEvent(Event event) {
// cancelEvent(event);
}
};
int imageX = x * sourceTilingInfo.getTileWidth();
int imageY = y * sourceTilingInfo.getTileHeight();
imagesPanel.add(image, imageX, imageY);
}
}
imagesPanel.add(area);
}
private void createSelectedArea() {
selectedArea = new SelectedArea(totalWidth, totalHeight, imagesPanel);
}
private void reloadSelectedArea() {
factor = model.getCurrentZoom() / sourceTilingInfo.getZoom();
int left = (int) Math.round(model.getViewAreaLeft() / factor);
int top = (int) Math.round(model.getViewAreaTop() / factor);
int w = (int) Math.round(model.getViewAreaWidth() / factor);
int h = (int) Math.round(model.getViewAreaHeight() / factor);
int maxW = (int) Math.round(sourceTilingInfo.getOriginalImageWidth() * sourceTilingInfo.getZoom());
int maxH = (int) Math.round(sourceTilingInfo.getOriginalImageHeight() * sourceTilingInfo.getZoom());
Log.debug("w: " + w + " maxW: " + maxW + " h: " + h + " maxH: " + maxH);
if (w > maxW) {
w = maxW;
}
if (h > maxH) {
h = maxH;
}
Point topLeft = new Point(left, top);
Rectangle area = new Rectangle(topLeft, w, h);
if (sourceTilingInfo.getZoom() == model.getCurrentZoom()) {
imagesPanel.remove(anchorContainer);
removeMouseListener(controllerMouseListener);
addMouseListener(blockAllEventsListener);
} else {
imagesPanel.add(anchorContainer);
removeMouseListener(blockAllEventsListener);
addMouseListener(controllerMouseListener);
}
selectedArea.changeArea(area);
}
private void updateModel() {
Point center = selectedArea.getCurrentArea().getCenter();
int x = (int) Math.round(center.getX() * factor);
int y = (int) Math.round(center.getY() * factor);
model.centerOn(x, y);
selectedArea.putArea();
}
private void moveArea(int dx, int dy) {
selectedArea.move(dx, dy);
}
private void centerArea(int x, int y) {
selectedArea.centerOn(x, y);
}
private static void cancelEvent(Event event) {
event.preventDefault();
event.cancelBubble(true);
}
public void onModelChange(TilingModelEvent event, TilingModel model) {
switch (event) {
case TILING_INFO_UPDATED:
reloadSelectedArea();
selectedArea.putArea();
break;
}
}
}