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