001/* 002 * (C) Copyright 2006-2007 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.webapp.note; 021 022import static org.jboss.seam.ScopeType.CONVERSATION; 023 024import java.io.IOException; 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import javax.servlet.http.Part; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.jboss.seam.annotations.In; 036import org.jboss.seam.annotations.Name; 037import org.jboss.seam.annotations.Scope; 038import org.jboss.seam.annotations.web.RequestParameter; 039import org.nuxeo.ecm.core.api.Blob; 040import org.nuxeo.ecm.core.api.CoreSession; 041import org.nuxeo.ecm.core.api.DocumentModel; 042import org.nuxeo.ecm.core.api.ListDiff; 043import org.nuxeo.ecm.core.api.NuxeoException; 044import org.nuxeo.ecm.platform.query.api.PageProvider; 045import org.nuxeo.ecm.platform.query.api.PageProviderService; 046import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider; 047import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions; 048import org.nuxeo.ecm.platform.ui.web.util.files.FileUtils; 049import org.nuxeo.ecm.webapp.base.InputController; 050import org.nuxeo.runtime.api.Framework; 051 052/** 053 * Seam component implementing actions related to inserting an image in a Note document. 054 * <p> 055 * The uploaded image is stored in the <code>files</code> schema of the document. 056 * <p> 057 * After uploading an image, the REST URL for this image can be retrieve through the appropriate method. 058 * <p> 059 * The search method retrieves only the Picture document of the repository. 060 * 061 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a> 062 */ 063@Name("editorImageActions") 064@Scope(CONVERSATION) 065public class EditorImageActionsBean extends InputController implements EditorImageActions, Serializable { 066 067 private static final String FILES_SCHEMA = "files"; 068 069 private static final List<Map<String, String>> SIZES; 070 071 /** @since 5.9.5 */ 072 private static final String PP_SEARCH_MEDIA_BY_TITLE = "search_media_by_title"; 073 074 /** @since 5.9.5 */ 075 private static final String PP_SEARCH_MEDIA_ALL = "search_media_all"; 076 077 static { 078 SIZES = new ArrayList<Map<String, String>>(); 079 Map<String, String> m = new HashMap<String, String>(); 080 m.put("label", "label.imageUpload.originalSize"); 081 m.put("value", "OriginalJpeg"); 082 SIZES.add(m); 083 m = new HashMap<String, String>(); 084 m.put("label", "label.imageUpload.mediumSize"); 085 m.put("value", "Medium"); 086 SIZES.add(m); 087 m = new HashMap<String, String>(); 088 m.put("label", "label.imageUpload.thumbnailSize"); 089 m.put("value", "Thumbnail"); 090 SIZES.add(m); 091 } 092 093 private static final long serialVersionUID = 8716548847393060676L; 094 095 private static final Log log = LogFactory.getLog(EditorImageActionsBean.class); 096 097 @In(create = true, required = false) 098 private transient CoreSession documentManager; 099 100 @RequestParameter 101 private String selectedTab; 102 103 private String oldSelectedTab; 104 105 private Part uploadedImage; 106 107 /** 108 * @deprecated since 7.1 109 */ 110 @Deprecated 111 private String uploadedImageName; 112 113 private String imageUrl; 114 115 private boolean isImageUploaded = false; 116 117 private List<DocumentModel> resultDocuments; 118 119 private List<DocumentModel> resultVideos; 120 121 private boolean hasSearchResults = false; 122 123 private boolean hasSearchVideosResults = false; 124 125 private String searchKeywords; 126 127 private String selectedSize = "OriginalJpeg"; 128 129 @Override 130 public String getSelectedTab() { 131 if (selectedTab != null) { 132 oldSelectedTab = selectedTab; 133 } else if (oldSelectedTab == null) { 134 oldSelectedTab = "UPLOAD"; 135 } 136 return oldSelectedTab; 137 } 138 139 @Override 140 public String getUrlForImage() { 141 isImageUploaded = false; 142 return imageUrl; 143 } 144 145 @Override 146 public boolean getIsImageUploaded() { 147 return isImageUploaded; 148 } 149 150 @Override 151 public void setUploadedImage(Part uploadedImage) { 152 this.uploadedImage = uploadedImage; 153 } 154 155 @Override 156 public Part getUploadedImage() { 157 return uploadedImage; 158 } 159 160 @Override 161 public String getUploadedImageName() { 162 return uploadedImageName; 163 } 164 165 @Override 166 public void setUploadedImageName(String uploadedImageName) { 167 this.uploadedImageName = uploadedImageName; 168 } 169 170 @Override 171 @SuppressWarnings("unchecked") 172 public String uploadImage() { 173 if (uploadedImage == null) { 174 return null; 175 } 176 DocumentModel doc = navigationContext.getCurrentDocument(); 177 List<Map<String, Object>> filesList = (List<Map<String, Object>>) doc.getProperty("files", "files"); 178 int fileIndex = filesList == null ? 0 : filesList.size(); 179 Map<String, Object> props = new HashMap<String, Object>(); 180 Blob blob; 181 try { 182 blob = FileUtils.createBlob(uploadedImage); 183 } catch (IOException e) { 184 throw new NuxeoException(e); 185 } 186 props.put("filename", blob.getFilename()); 187 props.put("file", blob); 188 ListDiff listDiff = new ListDiff(); 189 listDiff.add(props); 190 doc.setProperty("files", "files", listDiff); 191 documentManager.saveDocument(doc); 192 documentManager.save(); 193 imageUrl = DocumentModelFunctions.complexFileUrl("downloadFile", doc, fileIndex, blob.getFilename()); 194 isImageUploaded = true; 195 return "editor_image_upload"; 196 } 197 198 @Override 199 public boolean getInCreationMode() { 200 DocumentModel doc = navigationContext.getChangeableDocument(); 201 if (doc == null || doc.getRef() != null) { 202 // if changeableDocument is null or has an existing ref, assume we 203 // are not in creation and use the currentDocument instead 204 doc = navigationContext.getCurrentDocument(); 205 } 206 if (doc == null) { 207 return false; 208 } 209 if (doc.getId() == null) { 210 return true; 211 } else { 212 return !doc.hasSchema(FILES_SCHEMA); 213 } 214 } 215 216 @Override 217 public boolean getHasSearchResults() { 218 return hasSearchResults; 219 } 220 221 @Override 222 public boolean getHasSearchVideosResults() { 223 return hasSearchVideosResults; 224 } 225 226 @Override 227 public List<DocumentModel> getSearchImageResults() { 228 return resultDocuments; 229 } 230 231 @Override 232 public List<DocumentModel> getSearchVideosResults() { 233 return resultVideos; 234 } 235 236 @Override 237 public String getSearchKeywords() { 238 return searchKeywords; 239 } 240 241 @Override 242 public String searchImages() { 243 // Init the list of results 244 resultDocuments = null; 245 // Search the images 246 resultDocuments = searchMedia("Picture"); 247 hasSearchResults = !resultDocuments.isEmpty(); 248 log.debug("query result contains: " + resultDocuments.size() + " docs."); 249 return "editor_image_upload"; 250 } 251 252 /** 253 * @since 5.9.5 254 */ 255 @Override 256 public String searchVideos() { 257 // Init the list of results 258 resultVideos = null; 259 // Search the videos 260 resultVideos = searchMedia("Video"); 261 hasSearchVideosResults = !resultVideos.isEmpty(); 262 263 log.debug("query result contains: " + resultVideos.size() + " videos."); 264 return "editor_image_upload"; 265 } 266 267 /** 268 * Generic method to search a media. 269 * 270 * @param typeDocument The type of document to search. 271 * @since 5.9.5 272 */ 273 @SuppressWarnings("unchecked") 274 private List<DocumentModel> searchMedia(String typeDocument) { 275 log.debug("Entering searchDocuments with keywords: " + searchKeywords); 276 277 // use page providers 278 PageProviderService ppService = Framework.getService(PageProviderService.class); 279 Map<String, Serializable> props = new HashMap<String, Serializable>(); 280 props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) documentManager); 281 PageProvider<DocumentModel> pp = null; 282 if (searchKeywords != null) { 283 searchKeywords = searchKeywords.trim(); 284 if (searchKeywords.length() > 0) { 285 if (!searchKeywords.equals("*")) { 286 // full text search 287 pp = (PageProvider<DocumentModel>) ppService.getPageProvider(PP_SEARCH_MEDIA_BY_TITLE, null, null, 288 null, props, new Object[] { typeDocument, searchKeywords }); 289 } 290 } 291 } 292 293 // If the pageprovider is null, we search all medias for the specific type 294 if (pp == null) { 295 pp = (PageProvider<DocumentModel>) ppService.getPageProvider(PP_SEARCH_MEDIA_ALL, null, null, null, props, 296 new Object[] { typeDocument }); 297 } 298 return pp.getCurrentPage(); 299 } 300 301 @Override 302 public void setSearchKeywords(final String searchKeywords) { 303 this.searchKeywords = searchKeywords; 304 } 305 306 @Override 307 public List<Map<String, String>> getSizes() { 308 return SIZES; 309 } 310 311 @Override 312 public String getSelectedSize() { 313 return selectedSize; 314 } 315 316 @Override 317 public void setSelectedSize(final String selectedSize) { 318 this.selectedSize = selectedSize; 319 } 320 321 @Override 322 public String getImageProperty() { 323 return selectedSize + ":content"; 324 } 325 326 @Override 327 public String getURLVideo(DocumentModel video, String type) { 328 329 if (video == null || type == null) { 330 return null; 331 } 332 333 @SuppressWarnings("unchecked") 334 List<Map<String, Serializable>> transcodedVideos = (List<Map<String, Serializable>>) video.getPropertyValue("vid:transcodedVideos"); 335 int position = 0; 336 for (Map<String, Serializable> prop : transcodedVideos) { 337 if (type.equals(prop.get("name"))) { 338 Blob content = (Blob) prop.get("content"); 339 String blobPropertyName = "vid:transcodedVideos/" + position + "/content"; 340 return DocumentModelFunctions.bigFileUrl(video, blobPropertyName, content.getFilename()); 341 } 342 position++; 343 } 344 345 return null; 346 } 347 348}