001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * troger 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import com.allen_sauer.gwt.log.client.Log; 026 027/** 028 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a> 029 */ 030public class TilingModel { 031 032 public enum TilingModelEvent { 033 MOVE_EVENT, TILING_INFO_UPDATED 034 }; 035 036 private TilingInfo tilingInfo; 037 038 private int totalWidth; 039 040 private int totalHeight; 041 042 private int viewAreaTop; 043 044 private int viewAreaLeft; 045 046 private int viewAreaWidth; 047 048 private int viewAreaHeight; 049 050 private int maxLeft; 051 052 private int maxTop; 053 054 // we won't zoom out below this zoom 055 private double defaultZoom; 056 057 // used to recenter the area after zooming in / out 058 private int oldXToCenterOn = 0; 059 060 private int oldYToCenterOn = 0; 061 062 private double oldZoom = 1; 063 064 private List<TilingModelListener> listeners = new ArrayList<TilingModelListener>(); 065 066 private TilingInfoCallback tilingInfoCallback = new TilingInfoCallback() { 067 public void tilingInfoUpdated() { 068 updateModel(); 069 070 // compute new center 071 int x = (int) Math.round(oldXToCenterOn * getCurrentZoom() / oldZoom); 072 int y = (int) Math.round(oldYToCenterOn * getCurrentZoom() / oldZoom); 073 // center 074 Log.debug("center on: x=" + x + ", y=" + y); 075 centerOn(x, y, false); 076 077 // fire the event 078 fireEvent(TilingModelEvent.TILING_INFO_UPDATED); 079 } 080 }; 081 082 public TilingModel(TilingInfo ti, int viewAreaWidth, int viewAreaHeight, double defaultZoom) { 083 tilingInfo = ti; 084 this.defaultZoom = defaultZoom; 085 this.viewAreaWidth = viewAreaWidth; 086 this.viewAreaHeight = viewAreaHeight; 087 viewAreaTop = viewAreaLeft = 0; 088 updateModel(); 089 } 090 091 public void notifyListeners() { 092 fireEvent(TilingModelEvent.TILING_INFO_UPDATED); 093 } 094 095 private void updateModel() { 096 totalWidth = (int) Math.round(tilingInfo.getOriginalImageWidth() * getCurrentZoom()); 097 totalHeight = (int) Math.round(tilingInfo.getOriginalImageHeight() * getCurrentZoom()); 098 099 maxLeft = totalWidth - viewAreaWidth; 100 maxTop = totalHeight - viewAreaHeight; 101 } 102 103 public void move(int x, int y, boolean fireEvent) { 104 viewAreaLeft += x; 105 viewAreaTop += y; 106 ensureCorrectValues(); 107 if (fireEvent) { 108 fireEvent(TilingModelEvent.MOVE_EVENT); 109 } 110 } 111 112 public void move(int x, int y) { 113 move(x, y, true); 114 } 115 116 public void resetView() { 117 viewAreaLeft = viewAreaTop = 0; 118 } 119 120 public void setLocation(int left, int top, boolean fireEvent) { 121 viewAreaLeft = left; 122 viewAreaTop = top; 123 ensureCorrectValues(); 124 if (fireEvent) { 125 fireEvent(TilingModelEvent.MOVE_EVENT); 126 } 127 } 128 129 public void setLocation(int left, int top) { 130 setLocation(left, top, true); 131 } 132 133 public void centerOn(int x, int y, boolean fireEvent) { 134 viewAreaLeft = x - viewAreaWidth / 2; 135 viewAreaTop = y - viewAreaHeight / 2; 136 Log.debug("viewAreaLeft= " + viewAreaLeft + " viewAreaTop= " + viewAreaTop); 137 ensureCorrectValues(); 138 if (fireEvent) { 139 fireEvent(TilingModelEvent.MOVE_EVENT); 140 } 141 } 142 143 public void centerOn(int x, int y) { 144 centerOn(x, y, true); 145 } 146 147 private void ensureCorrectValues() { 148 if (viewAreaLeft > maxLeft) { 149 viewAreaLeft = maxLeft; 150 } 151 if (viewAreaTop > maxTop) { 152 viewAreaTop = maxTop; 153 } 154 if (viewAreaLeft < 0) { 155 viewAreaLeft = 0; 156 } 157 if (viewAreaTop < 0) { 158 viewAreaTop = 0; 159 } 160 } 161 162 public void zoomIn() { 163 tilingInfo.setMaxTiles(tilingInfo.getMaxTiles() * 2); 164 saveOldCoord(); 165 tilingInfo.updateTilingInfo(tilingInfoCallback); 166 } 167 168 public void zoomOut() { 169 if (getCurrentZoom() <= defaultZoom) { 170 return; 171 } 172 tilingInfo.setMaxTiles(tilingInfo.getMaxTiles() / 2); 173 saveOldCoord(); 174 tilingInfo.updateTilingInfo(tilingInfoCallback); 175 } 176 177 private void saveOldCoord() { 178 oldZoom = getCurrentZoom(); 179 oldXToCenterOn = viewAreaLeft + viewAreaWidth / 2; 180 oldYToCenterOn = viewAreaTop + viewAreaHeight / 2; 181 } 182 183 public void addListener(TilingModelListener listener) { 184 listeners.add(listener); 185 } 186 187 public void removeListener(TilingModelListener listener) { 188 listeners.remove(listener); 189 } 190 191 private void fireEvent(TilingModelEvent event) { 192 for (TilingModelListener l : listeners) { 193 l.onModelChange(event, this); 194 } 195 } 196 197 /** 198 * @return the totalWidth. 199 */ 200 public int getTotalWidth() { 201 return totalWidth; 202 } 203 204 /** 205 * @return the totalHeight. 206 */ 207 public int getTotalHeight() { 208 return totalHeight; 209 } 210 211 /** 212 * @return the viewAreaTop. 213 */ 214 public int getViewAreaTop() { 215 return viewAreaTop; 216 } 217 218 /** 219 * @return the viewAreaLeft. 220 */ 221 public int getViewAreaLeft() { 222 return viewAreaLeft; 223 } 224 225 /** 226 * @return the viewAreaWidth. 227 */ 228 public int getViewAreaWidth() { 229 return viewAreaWidth; 230 } 231 232 /** 233 * @return the viewAreaHeight. 234 */ 235 public int getViewAreaHeight() { 236 return viewAreaHeight; 237 } 238 239 public int getTileWidth() { 240 return tilingInfo.getTileWidth(); 241 } 242 243 public int getTileHeight() { 244 return tilingInfo.getTileHeight(); 245 } 246 247 public int getWidthInTiles() { 248 return tilingInfo.getNbXTiles(); 249 } 250 251 public int getHeightInTiles() { 252 return tilingInfo.getNbYTiles(); 253 } 254 255 public String getBaseUrl() { 256 return tilingInfo.getBaseUrl(); 257 } 258 259 public double getCurrentZoom() { 260 return tilingInfo.getZoom(); 261 } 262 263 public long getLastModificationDate() { 264 return tilingInfo.getLastModificationDate(); 265 } 266 267}