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