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.view; 021 022import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingInfo; 023import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel; 024import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModelListener; 025import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel.TilingModelEvent; 026import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Point; 027import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Rectangle; 028 029import com.allen_sauer.gwt.log.client.Log; 030import com.google.gwt.user.client.DOM; 031import com.google.gwt.user.client.Event; 032import com.google.gwt.user.client.ui.AbsolutePanel; 033import com.google.gwt.user.client.ui.Anchor; 034import com.google.gwt.user.client.ui.FocusPanel; 035import com.google.gwt.user.client.ui.Image; 036import com.google.gwt.user.client.ui.MouseListenerAdapter; 037import com.google.gwt.user.client.ui.SimplePanel; 038import com.google.gwt.user.client.ui.Widget; 039 040/** 041 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a> 042 */ 043public class TilingPreviewControllerPanel extends FocusPanel implements TilingModelListener { 044 045 private static final String DEFAULT_CLASS_NAME = "tilingPreviewControllerPanel"; 046 047 private class ControllerMouseListener extends MouseListenerAdapter { 048 049 boolean mouseDown = false; 050 051 int x, y; 052 053 @Override 054 public void onMouseDown(Widget sender, int x, int y) { 055 mouseDown = true; 056 this.x = x; 057 this.y = y; 058 centerArea(x, y); 059 060 DOM.setStyleAttribute(imagesPanel.getElement(), "cursor", "move"); 061 cancelEvent(Event.getCurrentEvent()); 062 } 063 064 @Override 065 public void onMouseMove(Widget sender, int x, int y) { 066 if (mouseDown) { 067 moveArea(x - this.x, y - this.y); 068 this.x = x; 069 this.y = y; 070 } 071 cancelEvent(Event.getCurrentEvent()); 072 } 073 074 @Override 075 public void onMouseUp(Widget sender, int x, int y) { 076 if (mouseDown) { 077 mouseDown = false; 078 moveArea(x - this.x, y - this.y); 079 updateModel(); 080 DOM.setStyleAttribute(imagesPanel.getElement(), "cursor", "default"); 081 cancelEvent(Event.getCurrentEvent()); 082 } 083 } 084 085 @Override 086 public void onMouseLeave(Widget sender) { 087 onMouseUp(sender, x, y); 088 cancelEvent(Event.getCurrentEvent()); 089 } 090 091 } 092 093 private class ControllerBlockAllEventsListener extends MouseListenerAdapter { 094 095 @Override 096 public void onMouseDown(Widget sender, int x, int y) { 097 cancelEvent(Event.getCurrentEvent()); 098 } 099 100 @Override 101 public void onMouseEnter(Widget sender) { 102 cancelEvent(Event.getCurrentEvent()); 103 } 104 105 @Override 106 public void onMouseLeave(Widget sender) { 107 cancelEvent(Event.getCurrentEvent()); 108 } 109 110 @Override 111 public void onMouseMove(Widget sender, int x, int y) { 112 cancelEvent(Event.getCurrentEvent()); 113 } 114 115 @Override 116 public void onMouseUp(Widget sender, int x, int y) { 117 cancelEvent(Event.getCurrentEvent()); 118 } 119 120 } 121 122 private final TilingInfo sourceTilingInfo; 123 124 private final TilingModel model; 125 126 private int totalWidth; 127 128 private int totalHeight; 129 130 private AbsolutePanel imagesPanel; 131 132 private double factor = 1; 133 134 private SelectedArea selectedArea; 135 136 private final Anchor anchor = new Anchor(); 137 138 private final SimplePanel area = new SimplePanel(); 139 140 private final FocusPanel anchorContainer = new FocusPanel(anchor); 141 142 private final ControllerMouseListener controllerMouseListener = new ControllerMouseListener(); 143 144 private final ControllerBlockAllEventsListener blockAllEventsListener = new ControllerBlockAllEventsListener(); 145 146 public TilingPreviewControllerPanel(TilingInfo sourceTilingInfo, TilingModel model) { 147 this.sourceTilingInfo = sourceTilingInfo; 148 this.model = model; 149 model.addListener(this); 150 151 imagesPanel = new AbsolutePanel(); 152 totalWidth = (int) Math.round(sourceTilingInfo.getOriginalImageWidth() * sourceTilingInfo.getZoom()); 153 totalHeight = (int) Math.round(sourceTilingInfo.getOriginalImageHeight() * sourceTilingInfo.getZoom()); 154 imagesPanel.setPixelSize(totalWidth, totalHeight); 155 setWidget(imagesPanel); 156 157 // load the images corresponding to the first TilingInfo retrieved 158 loadImages(); 159 160 createSelectedArea(); 161 162 addMouseListener(controllerMouseListener); 163 164 setStyleName(DEFAULT_CLASS_NAME); 165 } 166 167 private void loadImages() { 168 169 int heightInTiles = sourceTilingInfo.getNbYTiles(); 170 int widthInTiles = sourceTilingInfo.getNbXTiles(); 171 172 for (int y = 0; y < heightInTiles; ++y) { 173 for (int x = 0; x < widthInTiles; ++x) { 174 String imageUrl = sourceTilingInfo.getBaseUrl() + "?x=" + x + "&y=" + y; 175 imageUrl += "&date=" + sourceTilingInfo.getLastModificationDate(); 176 177 Image image = new Image(imageUrl) { 178 @Override 179 public void onBrowserEvent(Event event) { 180 // cancelEvent(event); 181 } 182 }; 183 184 int imageX = x * sourceTilingInfo.getTileWidth(); 185 int imageY = y * sourceTilingInfo.getTileHeight(); 186 imagesPanel.add(image, imageX, imageY); 187 } 188 } 189 imagesPanel.add(area); 190 } 191 192 private void createSelectedArea() { 193 selectedArea = new SelectedArea(totalWidth, totalHeight, imagesPanel); 194 } 195 196 private void reloadSelectedArea() { 197 factor = model.getCurrentZoom() / sourceTilingInfo.getZoom(); 198 199 int left = (int) Math.round(model.getViewAreaLeft() / factor); 200 int top = (int) Math.round(model.getViewAreaTop() / factor); 201 int w = (int) Math.round(model.getViewAreaWidth() / factor); 202 int h = (int) Math.round(model.getViewAreaHeight() / factor); 203 204 int maxW = (int) Math.round(sourceTilingInfo.getOriginalImageWidth() * sourceTilingInfo.getZoom()); 205 int maxH = (int) Math.round(sourceTilingInfo.getOriginalImageHeight() * sourceTilingInfo.getZoom()); 206 Log.debug("w: " + w + " maxW: " + maxW + " h: " + h + " maxH: " + maxH); 207 if (w > maxW) { 208 w = maxW; 209 } 210 if (h > maxH) { 211 h = maxH; 212 } 213 214 Point topLeft = new Point(left, top); 215 Rectangle area = new Rectangle(topLeft, w, h); 216 217 if (sourceTilingInfo.getZoom() == model.getCurrentZoom()) { 218 imagesPanel.remove(anchorContainer); 219 removeMouseListener(controllerMouseListener); 220 addMouseListener(blockAllEventsListener); 221 } else { 222 imagesPanel.add(anchorContainer); 223 removeMouseListener(blockAllEventsListener); 224 addMouseListener(controllerMouseListener); 225 } 226 selectedArea.changeArea(area); 227 } 228 229 private void updateModel() { 230 Point center = selectedArea.getCurrentArea().getCenter(); 231 int x = (int) Math.round(center.getX() * factor); 232 int y = (int) Math.round(center.getY() * factor); 233 model.centerOn(x, y); 234 selectedArea.putArea(); 235 } 236 237 private void moveArea(int dx, int dy) { 238 selectedArea.move(dx, dy); 239 } 240 241 private void centerArea(int x, int y) { 242 selectedArea.centerOn(x, y); 243 } 244 245 private static void cancelEvent(Event event) { 246 event.preventDefault(); 247 event.cancelBubble(true); 248 } 249 250 public void onModelChange(TilingModelEvent event, TilingModel model) { 251 switch (event) { 252 case TILING_INFO_UPDATED: 253 reloadSelectedArea(); 254 selectedArea.putArea(); 255 break; 256 } 257 } 258 259}