001/* 002 * (C) Copyright 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 * Thierry Delprat 018 * Quentin Lamerand 019 */ 020 021package org.nuxeo.ecm.webapp.action; 022 023import static org.jboss.seam.ScopeType.CONVERSATION; 024 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031 032import javax.faces.context.FacesContext; 033import javax.servlet.http.HttpServletRequest; 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.remoting.WebRemote; 041import org.jboss.seam.core.Events; 042import org.jboss.seam.web.ServletContexts; 043import org.nuxeo.ecm.core.api.Blob; 044import org.nuxeo.ecm.core.api.CoreSession; 045import org.nuxeo.ecm.core.api.DocumentModel; 046import org.nuxeo.ecm.core.api.DocumentNotFoundException; 047import org.nuxeo.ecm.core.api.DocumentRef; 048import org.nuxeo.ecm.core.api.IdRef; 049import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 050import org.nuxeo.ecm.platform.actions.Action; 051import org.nuxeo.ecm.platform.actions.ActionContext; 052import org.nuxeo.ecm.platform.ui.web.api.WebActions; 053import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions; 054import org.nuxeo.ecm.platform.ui.web.util.BaseURL; 055import org.nuxeo.ecm.webapp.edit.lock.LockActions; 056import org.nuxeo.ecm.webapp.helpers.EventNames; 057 058@Name("popupHelper") 059@Scope(CONVERSATION) 060public class PopupHelper implements Serializable { 061 062 private static final long serialVersionUID = 1L; 063 064 private static final Log log = LogFactory.getLog(PopupHelper.class); 065 066 public static final String POPUP_CATEGORY = "POPUP"; 067 068 @In(required = true, create = true) 069 protected transient ActionContextProvider actionContextProvider; 070 071 @In(create = true) 072 protected transient WebActions webActions; 073 074 @In(create = true) 075 protected transient DeleteActions deleteActions; 076 077 @In(create = true, required = false) 078 protected transient CoreSession documentManager; 079 080 @In(create = true) 081 protected transient LockActions lockActions; 082 083 protected DocumentModel currentContainer; 084 085 protected DocumentModel currentParent; 086 087 protected DocumentModel currentPopupDocument; 088 089 protected List<Action> unfiltredActions; 090 091 protected void computeUnfiltredPopupActions() { 092 unfiltredActions = webActions.getAllActions(POPUP_CATEGORY); 093 // unfiltredActions = 094 // webActions.getActionsList(POPUP_CATEGORY, false); 095 } 096 097 /** 098 * Returns all popup actions: used to construct HTML menu template. 099 */ 100 public List<Action> getUnfiltredPopupActions() { 101 if (unfiltredActions == null) { 102 computeUnfiltredPopupActions(); 103 } 104 105 // post filters links to add docId 106 for (Action act : unfiltredActions) { 107 String lnk = act.getLink(); 108 if (lnk.startsWith("javascript:")) { 109 lnk = lnk.replaceFirst("javascript:", ""); 110 act.setLink(lnk); 111 } 112 } 113 return unfiltredActions; 114 } 115 116 public List<Action> getAvailablePopupActions(String popupDocId) { 117 return webActions.getActionsList(POPUP_CATEGORY, createActionContext(popupDocId)); 118 } 119 120 @WebRemote 121 public List<String> getAvailableActionId(String popupDocId) { 122 List<Action> availableActions = getAvailablePopupActions(popupDocId); 123 List<String> availableActionsIds = new ArrayList<String>(availableActions.size()); 124 for (Action act : availableActions) { 125 availableActionsIds.add(act.getId()); 126 } 127 return availableActionsIds; 128 } 129 130 @WebRemote 131 public List<String> getUnavailableActionId(String popupDocId) { 132 List<String> result = new ArrayList<String>(); 133 134 List<Action> allActions = getUnfiltredPopupActions(); 135 List<String> allActionsIds = new ArrayList<String>(allActions.size()); 136 for (Action act : allActions) { 137 allActionsIds.add(act.getId()); 138 } 139 140 List<Action> availableActions = getAvailablePopupActions(popupDocId); 141 List<String> availableActionsIds = new ArrayList<String>(availableActions.size()); 142 for (Action act : availableActions) { 143 availableActionsIds.add(act.getId()); 144 } 145 146 for (String act : allActionsIds) { 147 if (!availableActionsIds.contains(act)) { 148 result.add(act); 149 } 150 } 151 152 return result; 153 } 154 155 protected ActionContext createActionContext(String popupDocId) { 156 ActionContext ctx = actionContextProvider.createActionContext(); 157 158 DocumentModel currentDocument = ctx.getCurrentDocument(); 159 160 DocumentRef popupDocRef = new IdRef(popupDocId); 161 try { 162 DocumentModel popupDoc = documentManager.getDocument(popupDocRef); 163 ctx.setCurrentDocument(popupDoc); 164 ctx.putLocalVariable("container", currentDocument); 165 currentPopupDocument = popupDoc; 166 currentContainer = currentDocument; 167 } catch (DocumentNotFoundException e) { 168 log.error(e, e); 169 } 170 171 return ctx; 172 } 173 174 @WebRemote 175 public String getNavigationURL(String docId, String tabId) { 176 Map<String, String> params = new HashMap<String, String>(); 177 178 if (tabId != null) { 179 params.put("tabId", tabId); 180 } 181 182 DocumentModel doc = documentManager.getDocument(new IdRef(docId)); 183 184 return DocumentModelFunctions.documentUrl(null, doc, null, params, false, getBaseURL()); 185 } 186 187 @WebRemote 188 public String getNavigationURLOnContainer(String tabId) { 189 Map<String, String> params = new HashMap<String, String>(); 190 if (tabId != null) { 191 params.put("tabId", tabId); 192 } 193 194 return DocumentModelFunctions.documentUrl(null, currentContainer, null, params, false, getBaseURL()); 195 } 196 197 @WebRemote 198 public String getNavigationURLOnPopupdoc(String tabId) { 199 return getNavigationURLOnPopupdoc2(tabId, null); 200 } 201 202 protected String getBaseURL() { 203 return BaseURL.getBaseURL(getRequest()); 204 } 205 206 protected HttpServletRequest getRequest() { 207 HttpServletRequest request = ServletContexts.instance().getRequest(); 208 if (request != null) { 209 return request; 210 } 211 FacesContext context = FacesContext.getCurrentInstance(); 212 if (context != null) { 213 return (HttpServletRequest) context.getExternalContext().getRequest(); 214 } 215 return null; 216 } 217 218 @WebRemote 219 public String getNavigationURLOnPopupdoc2(String tabId, String subTabId) { 220 Map<String, String> params = new HashMap<String, String>(); 221 if (tabId != null) { 222 params.put("tabId", tabId); 223 } 224 if (subTabId != null) { 225 params.put("subTabId", subTabId); 226 } 227 return DocumentModelFunctions.documentUrl(null, currentPopupDocument, null, params, false, getBaseURL()); 228 } 229 230 protected Map<String, String> getCurrentTabParameters() { 231 Map<String, String> params = new HashMap<String, String>(); 232 String tabId = webActions.getCurrentTabId(); 233 if (tabId != null) { 234 params.put("tabId", tabId); 235 } 236 String subTabId = webActions.getCurrentSubTabId(); 237 if (subTabId != null) { 238 params.put("subTabId", subTabId); 239 } 240 return params; 241 } 242 243 @WebRemote 244 public String getCurrentURL() { 245 return DocumentModelFunctions.documentUrl(null, currentContainer, null, getCurrentTabParameters(), false, 246 getBaseURL()); 247 } 248 249 @WebRemote 250 public String getCurrentURLAfterDelete() { 251 // If the deleted document is a child of the current container we can stay on the current container, 252 // else we must navigate to the closest parent of the deleted document 253 if (isPopupDocumentDescendantOfCurrentDocument()) { 254 currentParent = currentContainer; 255 } 256 return DocumentModelFunctions.documentUrl(null, currentParent, null, getCurrentTabParameters(), false, 257 getBaseURL()); 258 } 259 260 @WebRemote 261 public String deleteDocument(String docId) { 262 DocumentModel doc = documentManager.getDocument(new IdRef(docId)); 263 currentParent = getFirstParentAfterDelete(doc); 264 List<DocumentModel> docsToDelete = new ArrayList<DocumentModel>(1); 265 docsToDelete.add(doc); 266 return deleteActions.deleteSelection(docsToDelete); 267 } 268 269 @WebRemote 270 public String editTitle(String docId, String newTitle) { 271 DocumentModel doc = documentManager.getDocument(new IdRef(docId)); 272 doc.setProperty("dublincore", "title", newTitle); 273 documentManager.saveDocument(doc); 274 documentManager.save(); 275 Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED); 276 return "OK"; 277 } 278 279 public boolean getIsCurrentContainerDirectParent() { 280 if (documentManager != null && currentContainer != null && currentPopupDocument != null) { 281 DocumentModel parent = documentManager.getParentDocument(currentPopupDocument.getRef()); 282 return currentContainer.equals(parent); 283 } 284 return false; 285 } 286 287 public boolean isDocumentHasBlobAttached(DocumentModel documentModel) { 288 if (documentModel.hasSchema("file")) { 289 Blob blob = (Blob) documentModel.getProperty("file", "content"); 290 return blob != null; 291 } else { 292 return false; 293 } 294 } 295 296 public boolean isDocumentHasBlobs(DocumentModel documentModel) { 297 BlobHolder bh = documentModel.getAdapter(BlobHolder.class); 298 if (bh != null) { 299 List<Blob> docBlobs = bh.getBlobs(); 300 if (docBlobs != null && !docBlobs.isEmpty()) { 301 return true; 302 } else { 303 return false; 304 } 305 } else { 306 return false; 307 } 308 } 309 310 @WebRemote 311 public String downloadDocument(String docId, String blobPropertyName, String filenamePropertyName) { 312 DocumentModel documentModel = documentManager.getDocument(new IdRef(docId)); 313 String filename = (String) documentModel.getPropertyValue(filenamePropertyName); 314 return DocumentModelFunctions.fileUrl("downloadFile", documentModel, blobPropertyName, filename); 315 } 316 317 @WebRemote 318 public String lockDocument(String docId) { 319 DocumentModel documentModel = documentManager.getDocument(new IdRef(docId)); 320 return lockActions.lockDocument(documentModel); 321 } 322 323 @WebRemote 324 public String unlockDocument(String docId) { 325 DocumentModel documentModel = documentManager.getDocument(new IdRef(docId)); 326 return lockActions.unlockDocument(documentModel); 327 } 328 329 @WebRemote 330 public String sendEmail(String docId) { 331 DocumentModel doc = documentManager.getDocument(new IdRef(docId)); 332 return DocumentModelFunctions.documentUrl(null, doc, "send_notification_email", null, false, getBaseURL()); 333 } 334 335 private DocumentModel getFirstParentAfterDelete(DocumentModel doc) { 336 List<DocumentModel> parents = documentManager.getParentDocuments(doc.getRef()); 337 parents.remove(doc); 338 Collections.reverse(parents); 339 for (DocumentModel currentParent : parents) { 340 try { 341 documentManager.getDocument(currentParent.getRef()); 342 return currentParent; 343 } catch (DocumentNotFoundException e) { 344 continue; 345 } 346 } 347 return null; 348 } 349 350 protected boolean isPopupDocumentDescendantOfCurrentDocument() { 351 return currentPopupDocument != null && currentContainer != null 352 && currentPopupDocument.getPathAsString().startsWith(currentContainer.getPathAsString() + "/"); 353 } 354 355}