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 * Alexandre Russel 018 * 019 * $Id$ 020 */ 021package org.nuxeo.ecm.platform.annotations.gwt.client.controler; 022 023import java.util.ArrayList; 024import java.util.List; 025 026import org.nuxeo.ecm.platform.annotations.gwt.client.AnnotationConstant; 027import org.nuxeo.ecm.platform.annotations.gwt.client.annotea.AnnoteaClient; 028import org.nuxeo.ecm.platform.annotations.gwt.client.configuration.WebConfiguration; 029import org.nuxeo.ecm.platform.annotations.gwt.client.model.Annotation; 030import org.nuxeo.ecm.platform.annotations.gwt.client.model.AnnotationChangeListener; 031import org.nuxeo.ecm.platform.annotations.gwt.client.model.AnnotationModel; 032import org.nuxeo.ecm.platform.annotations.gwt.client.util.Point; 033import org.nuxeo.ecm.platform.annotations.gwt.client.util.StringRangeXPointer; 034import org.nuxeo.ecm.platform.annotations.gwt.client.util.XPointerFactory; 035import org.nuxeo.ecm.platform.annotations.gwt.client.view.AnnotatedDocument; 036import org.nuxeo.ecm.platform.annotations.gwt.client.view.NewAnnotationPopup; 037import org.nuxeo.ecm.platform.annotations.gwt.client.view.listener.AnnotationPopupEventListener; 038 039import com.allen_sauer.gwt.log.client.Log; 040import com.google.gwt.core.client.GWT; 041import com.google.gwt.dom.client.ImageElement; 042import com.google.gwt.user.client.Window; 043 044/** 045 * @author Alexandre Russel 046 */ 047public class AnnotationController { 048 049 private static AnnotationController CURRENT_INSTANCE; 050 051 private static AnnotationModel model = new AnnotationModel(); 052 053 private static NewAnnotationPopup newAnnotationPopup; 054 055 private static AnnotatedDocument annotatedDocument; 056 057 private static final List<AnnotationPopupEventListener> annotationPopupListeners = new ArrayList<AnnotationPopupEventListener>(); 058 059 private String xPointerFilter; 060 061 private String pointerAdapter; 062 063 private boolean annotateImageOnly; 064 065 private boolean multiImage; 066 067 private final AnnoteaClient annoteaClient; 068 069 private final WebConfiguration webConfiguration; 070 071 private int frameScrollFromTop; 072 073 private boolean creationPopupOpened = false; 074 075 private final boolean onFrame; 076 077 public AnnotationController(WebConfiguration webConfiguration, boolean onFrame) { 078 this.onFrame = onFrame; 079 this.webConfiguration = (webConfiguration == null ? WebConfiguration.DEFAULT_WEB_CONFIGURATION 080 : webConfiguration); 081 annoteaClient = new AnnoteaClient(this); 082 083 CURRENT_INSTANCE = this; 084 085 if (onFrame) { 086 annotatedDocument = new AnnotatedDocument(this); 087 model.addChangeListener(annotatedDocument); 088 registerOnFrameMethods(); 089 } else { 090 registerMainModuleMethods(); 091 } 092 093 } 094 095 private native void registerOnFrameMethods() /*-{ 096 top['addNewAnnotation'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::addNewAnnotation(); 097 top['showAnnotations'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::showAnnotations(); 098 top['hideAnnotations'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::hideAnnotations(); 099 top['updateSelectedAnnotation'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::updateSelectedAnnotation(I); 100 top['cancelNewAnnotationPopup'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::cancelNewAnnotationPopup(); 101 top['loadAnnotationsOnFrame'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::loadAnnotations(); 102 top['isAnnotationsVisible'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::isAnnotationsVisible(); 103 top['deleteAnnotation'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::deleteAnnotationOnFrame(I); 104 }-*/; 105 106 private native void registerMainModuleMethods() /*-{ 107 top['loadAnnotationsOnMainModule'] = this.@org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::loadAnnotations(); 108 }-*/; 109 110 public void addNewAnnotation() { 111 NewAnnotationPopup popup = getNewAnnotationPopup(); 112 Annotation annotation = getNewAnnotation(); 113 if (popup != null && annotation != null) { 114 if (annotation.getXpointer() instanceof StringRangeXPointer) { 115 // pre-decorate the selected text 116 annotatedDocument.decorateSelectedText(annotation); 117 } 118 popup.show(); 119 } 120 } 121 122 public WebConfiguration getWebConfiguration() { 123 return webConfiguration; 124 } 125 126 public AnnotatedDocument getAnnotatedDocument() { 127 return annotatedDocument; 128 } 129 130 public void setXPointerFilter(String pointerFilter) { 131 xPointerFilter = pointerFilter; 132 } 133 134 public void setPointerAdapter(String pointerAdapter) { 135 this.pointerAdapter = pointerAdapter; 136 } 137 138 public boolean canAnnotate() { 139 return webConfiguration.canAnnotate(); 140 } 141 142 public void addModelChangeListener(AnnotationChangeListener listener) { 143 model.addChangeListener(listener); 144 } 145 146 public int getFrameScrollFromTop() { 147 return frameScrollFromTop; 148 } 149 150 public void setFrameScrollFromTop(int frameScrollFromTop) { 151 this.frameScrollFromTop = frameScrollFromTop; 152 } 153 154 public boolean canCreateNewCreationPopup() { 155 return !creationPopupOpened; 156 } 157 158 public void openCreationPopup() { 159 creationPopupOpened = true; 160 } 161 162 public void closeCreationPopup() { 163 creationPopupOpened = false; 164 } 165 166 public void newAnnotationCreated(Annotation annotation) { 167 model.setNewAnnotation(annotation); 168 } 169 170 public void submitNewAnnotation() { 171 GWT.log("submiting new annotation", null); 172 Annotation newAnnotation = model.getNewAnnotation(); 173 annoteaClient.submitAnnotation(newAnnotation); 174 model.setNewAnnotation(null); 175 176 // set the selected annotation to the newly created one 177 setSelectedAnnotationIndex(model.getAnnotations().size()); 178 } 179 180 private native void setSelectedAnnotationIndex(int index) /*-{ 181 top['selectedAnnotationIndex'] = index; 182 }-*/; 183 184 public void reloadAnnotations() { 185 if (onFrame) { 186 reloadAnnotationsOnMainModule(); 187 } else { 188 reloadAnnotationsOnFrame(); 189 } 190 } 191 192 private native void reloadAnnotationsOnMainModule() /*-{ 193 top['loadAnnotationsOnMainModule'](); 194 }-*/; 195 196 private native void reloadAnnotationsOnFrame() /*-{ 197 top['loadAnnotationsOnFrame'](); 198 }-*/; 199 200 public void cancelNewAnnotation() { 201 model.setNewAnnotation(null); 202 } 203 204 public void cancelNewAnnotationPopup() { 205 if (newAnnotationPopup != null) { 206 newAnnotationPopup.cancel(); 207 } 208 } 209 210 public void createNewAnnotation(String pointer) { 211 String href = getDocumentUrl(); 212 // Hardcoded url codec.... 213 String xpointerURI = href.substring(0, href.lastIndexOf("@") + 1) + pointer; 214 Annotation newAnnotation = new Annotation(XPointerFactory.getXPointer(xpointerURI)); 215 model.setNewAnnotation(newAnnotation); 216 } 217 218 public void setAnnotationList(List<Annotation> annotations) { 219 model.setAnnotations(annotations); 220 } 221 222 public native String getAnnoteaServerUrl() /*-{ 223 return top['annoteaServerUrl']; 224 }-*/; 225 226 public Annotation getNewAnnotation() { 227 return model.getNewAnnotation(); 228 } 229 230 public void loadAnnotations() { 231 if (onFrame) { 232 if (!isMultiImage()) { 233 annotatedDocument.preDecorateDocument(); 234 } 235 } 236 annoteaClient.getAnnotationList(getDocumentUrl()); 237 } 238 239 public native String getDocumentUrl() /*-{ 240 return top['docUrl']; 241 }-*/; 242 243 public void decorateDocument() { 244 Log.debug("decorate document"); 245 annotatedDocument.preDecorateDocument(); 246 updateAnnotation(true); 247 } 248 249 public void updateSelectedAnnotation(int index) { 250 annotatedDocument.updateSelectedAnnotation(index); 251 } 252 253 public void setFirstAnnotationSelected() { 254 if (!model.getAnnotations().isEmpty()) { 255 annotatedDocument.updateSelectedAnnotation(0); 256 } 257 } 258 259 public void setCancelNewAnnotation() { 260 model.setNewAnnotation(null); 261 } 262 263 public void setImageOnly(boolean b) { 264 this.annotateImageOnly = b; 265 } 266 267 public boolean isImageOnly() { 268 return this.annotateImageOnly; 269 } 270 271 public void setMultiImage(boolean b) { 272 this.multiImage = b; 273 } 274 275 public boolean isMultiImage() { 276 return this.multiImage; 277 } 278 279 public String filterXPointer(ImageElement image, String xpath, int i, int j, int k, int l) { 280 if (xPointerFilter != null) { 281 return filter(xPointerFilter, image, xpath, i, j, k, l); 282 } 283 return "#xpointer(image-range(" + xpath + ",[" + i + "," + j + "],[" + k + "," + l + "]))"; 284 } 285 286 public native String filter(String xPointerFilter, ImageElement image, String xpath, int i, int j, int k, int l) /*-{ 287 if(xPointerFilter && top[xPointerFilter]) { 288 return top[xPointerFilter](image, xpath, i, j, k, l); 289 } 290 }-*/; 291 292 public Point[] filterAnnotation(Point topLeft, Point bottomRight) { 293 if (pointerAdapter == null) { 294 return new Point[] { topLeft, bottomRight }; 295 } 296 String result = filterPoint(pointerAdapter, topLeft.getX(), topLeft.getY(), bottomRight.getX(), 297 bottomRight.getY()); 298 if (result.equals("")) { 299 return null; 300 } 301 String[] points = result.split(":"); 302 return new Point[] { new Point(points[0]), new Point(points[1]) }; 303 } 304 305 private native String filterPoint(String pointerAdapter, int x, int y, int x2, int y2) /*-{ 306 if(pointerAdapter && top[pointerAdapter]) { 307 return top[pointerAdapter](x, y, x2, y2); 308 } 309 }-*/; 310 311 public static void updateAnnotation(boolean forceDecorate) { 312 CURRENT_INSTANCE.updateAnnotations(forceDecorate); 313 } 314 315 public static void updateAnnotation() { 316 updateAnnotation(false); 317 } 318 319 public void updateAnnotations(boolean forceDecorate) { 320 annotatedDocument.update(forceDecorate); 321 } 322 323 public native void setAnnotationDecoratorFunction(String annotationDecoratorFunction) /*-{ 324 top[annotationDecoratorFunction] = @org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController::updateAnnotation(Z); 325 }-*/; 326 327 public void setNewAnnotationPopup(NewAnnotationPopup popup) { 328 newAnnotationPopup = popup; 329 } 330 331 public NewAnnotationPopup getNewAnnotationPopup() { 332 return newAnnotationPopup; 333 } 334 335 public void hideAnnotations() { 336 annotatedDocument.hideAnnotations(); 337 disablePopupListeners(); 338 } 339 340 public void disablePopupListeners() { 341 for (AnnotationPopupEventListener listener : annotationPopupListeners) { 342 listener.disable(); 343 } 344 } 345 346 public void showAnnotations() { 347 annotatedDocument.showAnnotations(); 348 enablePopupListeners(); 349 } 350 351 public void enablePopupListeners() { 352 for (AnnotationPopupEventListener listener : annotationPopupListeners) { 353 listener.enable(); 354 } 355 } 356 357 public void registerAnnotationPopupListener(AnnotationPopupEventListener listener) { 358 annotationPopupListeners.add(listener); 359 } 360 361 public void removeAnnotationPopupListener(AnnotationPopupEventListener listener) { 362 annotationPopupListeners.remove(listener); 363 } 364 365 public String getDecorateClassName() { 366 if (annotatedDocument.isAnnotationsVisible()) { 367 return AnnotationConstant.DECORATE_CLASS_NAME; 368 } else { 369 return AnnotationConstant.DECORATE_NOT_CLASS_NAME; 370 } 371 } 372 373 public native void deleteAnnotation(int index) /*-{ 374 top['deleteAnnotation'](index); 375 }-*/; 376 377 @SuppressWarnings("unused") 378 private void deleteAnnotationOnFrame(int index) { 379 annoteaClient.deleteAnnotation(Window.Location.getHref(), model.getAnnotations().get(index)); 380 } 381 382 public native boolean isAnnotationsVisible() /*-{ 383 if (top && typeof top['annotationsShown'] != "undefined") { 384 return top['annotationsShown']; 385 } else { 386 return true; 387 } 388 }-*/; 389 390 public void removeSelectedTextDecoration() { 391 annotatedDocument.removeSelectedTextDecoration(getNewAnnotation()); 392 } 393 394}