/*
* (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.model;
import java.util.ArrayList;
import java.util.List;
import com.allen_sauer.gwt.log.client.Log;
/**
* @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
*/
public class TilingModel {
public enum TilingModelEvent {
MOVE_EVENT, TILING_INFO_UPDATED
};
private TilingInfo tilingInfo;
private int totalWidth;
private int totalHeight;
private int viewAreaTop;
private int viewAreaLeft;
private int viewAreaWidth;
private int viewAreaHeight;
private int maxLeft;
private int maxTop;
// we won't zoom out below this zoom
private double defaultZoom;
// used to recenter the area after zooming in / out
private int oldXToCenterOn = 0;
private int oldYToCenterOn = 0;
private double oldZoom = 1;
private List<TilingModelListener> listeners = new ArrayList<TilingModelListener>();
private TilingInfoCallback tilingInfoCallback = new TilingInfoCallback() {
public void tilingInfoUpdated() {
updateModel();
// compute new center
int x = (int) Math.round(oldXToCenterOn * getCurrentZoom() / oldZoom);
int y = (int) Math.round(oldYToCenterOn * getCurrentZoom() / oldZoom);
// center
Log.debug("center on: x=" + x + ", y=" + y);
centerOn(x, y, false);
// fire the event
fireEvent(TilingModelEvent.TILING_INFO_UPDATED);
}
};
public TilingModel(TilingInfo ti, int viewAreaWidth, int viewAreaHeight, double defaultZoom) {
tilingInfo = ti;
this.defaultZoom = defaultZoom;
this.viewAreaWidth = viewAreaWidth;
this.viewAreaHeight = viewAreaHeight;
viewAreaTop = viewAreaLeft = 0;
updateModel();
}
public void notifyListeners() {
fireEvent(TilingModelEvent.TILING_INFO_UPDATED);
}
private void updateModel() {
totalWidth = (int) Math.round(tilingInfo.getOriginalImageWidth() * getCurrentZoom());
totalHeight = (int) Math.round(tilingInfo.getOriginalImageHeight() * getCurrentZoom());
maxLeft = totalWidth - viewAreaWidth;
maxTop = totalHeight - viewAreaHeight;
}
public void move(int x, int y, boolean fireEvent) {
viewAreaLeft += x;
viewAreaTop += y;
ensureCorrectValues();
if (fireEvent) {
fireEvent(TilingModelEvent.MOVE_EVENT);
}
}
public void move(int x, int y) {
move(x, y, true);
}
public void resetView() {
viewAreaLeft = viewAreaTop = 0;
}
public void setLocation(int left, int top, boolean fireEvent) {
viewAreaLeft = left;
viewAreaTop = top;
ensureCorrectValues();
if (fireEvent) {
fireEvent(TilingModelEvent.MOVE_EVENT);
}
}
public void setLocation(int left, int top) {
setLocation(left, top, true);
}
public void centerOn(int x, int y, boolean fireEvent) {
viewAreaLeft = x - viewAreaWidth / 2;
viewAreaTop = y - viewAreaHeight / 2;
Log.debug("viewAreaLeft= " + viewAreaLeft + " viewAreaTop= " + viewAreaTop);
ensureCorrectValues();
if (fireEvent) {
fireEvent(TilingModelEvent.MOVE_EVENT);
}
}
public void centerOn(int x, int y) {
centerOn(x, y, true);
}
private void ensureCorrectValues() {
if (viewAreaLeft > maxLeft) {
viewAreaLeft = maxLeft;
}
if (viewAreaTop > maxTop) {
viewAreaTop = maxTop;
}
if (viewAreaLeft < 0) {
viewAreaLeft = 0;
}
if (viewAreaTop < 0) {
viewAreaTop = 0;
}
}
public void zoomIn() {
tilingInfo.setMaxTiles(tilingInfo.getMaxTiles() * 2);
saveOldCoord();
tilingInfo.updateTilingInfo(tilingInfoCallback);
}
public void zoomOut() {
if (getCurrentZoom() <= defaultZoom) {
return;
}
tilingInfo.setMaxTiles(tilingInfo.getMaxTiles() / 2);
saveOldCoord();
tilingInfo.updateTilingInfo(tilingInfoCallback);
}
private void saveOldCoord() {
oldZoom = getCurrentZoom();
oldXToCenterOn = viewAreaLeft + viewAreaWidth / 2;
oldYToCenterOn = viewAreaTop + viewAreaHeight / 2;
}
public void addListener(TilingModelListener listener) {
listeners.add(listener);
}
public void removeListener(TilingModelListener listener) {
listeners.remove(listener);
}
private void fireEvent(TilingModelEvent event) {
for (TilingModelListener l : listeners) {
l.onModelChange(event, this);
}
}
/**
* @return the totalWidth.
*/
public int getTotalWidth() {
return totalWidth;
}
/**
* @return the totalHeight.
*/
public int getTotalHeight() {
return totalHeight;
}
/**
* @return the viewAreaTop.
*/
public int getViewAreaTop() {
return viewAreaTop;
}
/**
* @return the viewAreaLeft.
*/
public int getViewAreaLeft() {
return viewAreaLeft;
}
/**
* @return the viewAreaWidth.
*/
public int getViewAreaWidth() {
return viewAreaWidth;
}
/**
* @return the viewAreaHeight.
*/
public int getViewAreaHeight() {
return viewAreaHeight;
}
public int getTileWidth() {
return tilingInfo.getTileWidth();
}
public int getTileHeight() {
return tilingInfo.getTileHeight();
}
public int getWidthInTiles() {
return tilingInfo.getNbXTiles();
}
public int getHeightInTiles() {
return tilingInfo.getNbYTiles();
}
public String getBaseUrl() {
return tilingInfo.getBaseUrl();
}
public double getCurrentZoom() {
return tilingInfo.getZoom();
}
public long getLastModificationDate() {
return tilingInfo.getLastModificationDate();
}
}