001/* 002 * (C) Copyright 2012 Nuxeo SA (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 * Anahide Tchertchian 016 * Antoine Taillefer 017 */ 018package org.nuxeo.ecm.webapp.contentbrowser; 019 020import static org.jboss.seam.ScopeType.CONVERSATION; 021import static org.jboss.seam.ScopeType.EVENT; 022 023import java.io.Serializable; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.List; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.jboss.seam.annotations.Factory; 032import org.jboss.seam.annotations.In; 033import org.jboss.seam.annotations.Name; 034import org.jboss.seam.annotations.Observer; 035import org.jboss.seam.annotations.Scope; 036import org.jboss.seam.annotations.intercept.BypassInterceptors; 037import org.nuxeo.ecm.core.api.CoreSession; 038import org.nuxeo.ecm.core.api.DocumentModel; 039import org.nuxeo.ecm.core.api.DocumentRef; 040import org.nuxeo.ecm.core.api.IdRef; 041import org.nuxeo.ecm.core.api.NuxeoException; 042import org.nuxeo.ecm.core.api.VersionModel; 043import org.nuxeo.ecm.platform.contentview.jsf.ContentView; 044import org.nuxeo.ecm.platform.contentview.seam.ContentViewActions; 045import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes; 046import org.nuxeo.ecm.platform.query.api.PageProvider; 047import org.nuxeo.ecm.platform.query.api.PageSelection; 048import org.nuxeo.ecm.platform.types.adapter.TypeInfo; 049import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 050import org.nuxeo.ecm.platform.ui.web.cache.LRUCachingMap; 051import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 052import org.nuxeo.ecm.webapp.helpers.EventNames; 053 054/** 055 * Manages document listings rendering. 056 * 057 * @author Anahide Tchertchian 058 */ 059@Name("documentListingActions") 060@Scope(CONVERSATION) 061public class DocumentListingActionsBean implements Serializable { 062 063 private static final long serialVersionUID = 1L; 064 065 private static final Log log = LogFactory.getLog(DocumentListingActionsBean.class); 066 067 public static String DEFAULT_LISTING_LAYOUT = "document_listing"; 068 069 @In(create = true) 070 protected transient NavigationContext navigationContext; 071 072 /** @since 5.6 */ 073 @In(create = true, required = false) 074 protected transient CoreSession documentManager; 075 076 @In(create = true) 077 protected transient ContentViewActions contentViewActions; 078 079 @In(required = false, create = true) 080 protected transient DocumentsListsManager documentsListsManager; 081 082 // only store 20 entries that cache chosen layout for a given document 083 protected LRUCachingMap<String, String> docTolistings = new LRUCachingMap<String, String>(20); 084 085 protected String currentListingLayoutName = null; 086 087 protected List<String> currentAvailableListingLayoutNames = null; 088 089 // API for current layout in listing mode 090 091 /** 092 * @deprecated this information is now held by content views 093 */ 094 @Deprecated 095 public String getLayoutForDocument(DocumentModel doc) { 096 if (doc != null) { 097 String id = doc.getId(); 098 if (docTolistings.containsKey(id)) { 099 return docTolistings.get(id); 100 } 101 List<String> availableLayouts = getAvailableLayoutsForDocument(doc); 102 if (availableLayouts != null && !availableLayouts.isEmpty()) { 103 return availableLayouts.get(0); 104 } 105 } 106 return DEFAULT_LISTING_LAYOUT; 107 } 108 109 /** 110 * @deprecated this information is now held by content views 111 */ 112 @Deprecated 113 public void setLayoutForDocument(DocumentModel doc, String layoutName) { 114 if (doc == null) { 115 log.error("Cannot set listing layout for null document"); 116 return; 117 } 118 String id = doc.getId(); 119 docTolistings.put(id, layoutName); 120 } 121 122 /** 123 * @deprecated this information is now held by content views 124 */ 125 @Deprecated 126 @Factory(value = "currentListingLayoutName", scope = EVENT) 127 public String getLayoutForCurrentDocument() { 128 if (currentListingLayoutName == null) { 129 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 130 currentListingLayoutName = getLayoutForDocument(currentDocument); 131 } 132 return currentListingLayoutName; 133 } 134 135 /** 136 * @deprecated this information is now held by content views 137 */ 138 @Deprecated 139 public void setLayoutForCurrentDocument(String layoutName) { 140 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 141 setLayoutForDocument(currentDocument, layoutName); 142 currentListingLayoutName = layoutName; 143 } 144 145 /** 146 * @deprecated this information is now held by content views 147 */ 148 @Deprecated 149 public List<String> getAvailableLayoutsForDocument(DocumentModel doc) { 150 if (doc == null) { 151 return Collections.emptyList(); 152 } 153 TypeInfo typeInfo = doc.getAdapter(TypeInfo.class); 154 String[] layoutNames = typeInfo.getLayouts(BuiltinModes.LISTING, null); 155 List<String> res = new ArrayList<String>(); 156 if (layoutNames != null && layoutNames.length > 0) { 157 res.addAll(Arrays.asList(layoutNames)); 158 } else { 159 res.add(DEFAULT_LISTING_LAYOUT); 160 } 161 return res; 162 } 163 164 /** 165 * @deprecated this information is now held by content views 166 */ 167 @Deprecated 168 @Factory(value = "currentAvailableListingLayoutNames", scope = EVENT) 169 public List<String> getAvailableLayoutsForCurrentDocument() { 170 if (currentAvailableListingLayoutNames == null) { 171 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 172 currentAvailableListingLayoutNames = getAvailableLayoutsForDocument(currentDocument); 173 } 174 return currentAvailableListingLayoutNames; 175 } 176 177 /** 178 * @deprecated this information is now held by content views 179 */ 180 @Observer(value = { EventNames.USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED }, create = false) 181 @BypassInterceptors 182 @Deprecated 183 public void documentChanged() { 184 currentListingLayoutName = null; 185 currentAvailableListingLayoutNames = null; 186 } 187 188 // API for AJAX selection in listings of content views 189 190 @SuppressWarnings("unchecked") 191 protected List<DocumentModel> getCurrentPageDocuments(String contentViewName) { 192 List<DocumentModel> documents = null; 193 ContentView cView = contentViewActions.getContentView(contentViewName); 194 if (cView != null) { 195 PageProvider<?> cProvider = cView.getCurrentPageProvider(); 196 if (cProvider != null) { 197 List<?> items = cProvider.getCurrentPage(); 198 try { 199 documents = (List<DocumentModel>) items; 200 } catch (ClassCastException e) { 201 throw new NuxeoException(e); 202 } 203 } 204 } 205 return documents; 206 } 207 208 public void processSelectPage(String contentViewName, String listName, Boolean selection) { 209 List<DocumentModel> documents = getCurrentPageDocuments(contentViewName); 210 if (documents != null) { 211 String lName = (listName == null) ? DocumentsListsManager.CURRENT_DOCUMENT_SELECTION : listName; 212 if (Boolean.TRUE.equals(selection)) { 213 documentsListsManager.addToWorkingList(lName, documents); 214 } else { 215 documentsListsManager.removeFromWorkingList(lName, documents); 216 } 217 } 218 } 219 220 /** 221 * Handle complete table selection event after having ensured that the navigation context stills points to 222 * currentDocumentRef to protect against browsers' back button errors 223 */ 224 public void checkCurrentDocAndProcessSelectPage(String contentViewName, String listName, Boolean selection, 225 String currentDocRef) { 226 DocumentRef currentDocumentRef = new IdRef(currentDocRef); 227 if (!currentDocumentRef.equals(navigationContext.getCurrentDocument().getRef())) { 228 navigationContext.navigateToRef(currentDocumentRef); 229 } 230 processSelectPage(contentViewName, listName, selection); 231 } 232 233 public void processSelectRow(String docRef, String contentViewName, String listName, Boolean selection) 234 { 235 List<DocumentModel> documents = getCurrentPageDocuments(contentViewName); 236 DocumentModel doc = null; 237 if (documents != null) { 238 for (DocumentModel pagedDoc : documents) { 239 if (pagedDoc.getRef().toString().equals(docRef)) { 240 doc = pagedDoc; 241 break; 242 } 243 } 244 } 245 if (doc == null) { 246 log.error(String.format("could not find doc '%s' in the current page of " 247 + "content view page provider '%s'", docRef, contentViewName)); 248 return; 249 } 250 String lName = (listName == null) ? DocumentsListsManager.CURRENT_DOCUMENT_SELECTION : listName; 251 if (Boolean.TRUE.equals(selection)) { 252 documentsListsManager.addToWorkingList(lName, doc); 253 } else { 254 documentsListsManager.removeFromWorkingList(lName, doc); 255 } 256 } 257 258 /** 259 * Handle row selection event after having ensured that the navigation context stills points to currentDocumentRef 260 * to protect against browsers' back button errors 261 */ 262 public void checkCurrentDocAndProcessSelectRow(String docRef, String providerName, String listName, 263 Boolean selection, String requestedCurrentDocRef) { 264 DocumentRef requestedCurrentDocumentRef = new IdRef(requestedCurrentDocRef); 265 DocumentRef currentDocumentRef = null; 266 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 267 if (currentDocument != null) { 268 currentDocumentRef = currentDocument.getRef(); 269 } 270 if (!requestedCurrentDocumentRef.equals(currentDocumentRef)) { 271 navigationContext.navigateToRef(requestedCurrentDocumentRef); 272 } 273 processSelectRow(docRef, providerName, listName, selection); 274 } 275 276 /** 277 * Handle version row selection event after having ensured that the navigation context stills points to 278 * currentDocumentRef to protect against browsers' back button errors. 279 * 280 * @param versionModelSelection the version model selection 281 * @param requestedCurrentDocRef the requested current doc ref 282 * @since 5.6 283 */ 284 public void checkCurrentDocAndProcessVersionSelectRow(PageSelection<VersionModel> versionModelSelection, 285 String requestedCurrentDocRef) { 286 287 DocumentRef requestedCurrentDocumentRef = new IdRef(requestedCurrentDocRef); 288 DocumentRef currentDocumentRef = null; 289 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 290 if (currentDocument != null) { 291 currentDocumentRef = currentDocument.getRef(); 292 } 293 if (!requestedCurrentDocumentRef.equals(currentDocumentRef)) { 294 navigationContext.navigateToRef(requestedCurrentDocumentRef); 295 } 296 processVersionSelectRow(versionModelSelection); 297 } 298 299 /** 300 * Processes the version selection row. 301 * 302 * @param versionModelSelection the version model selection 303 */ 304 protected final void processVersionSelectRow(PageSelection<VersionModel> versionModelSelection) 305 { 306 307 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 308 if (currentDocument == null) { 309 throw new NuxeoException("Cannot process version select row since current document is null."); 310 } 311 312 DocumentModel version = documentManager.getDocumentWithVersion(currentDocument.getRef(), 313 versionModelSelection.getData()); 314 if (version == null) { 315 throw new NuxeoException("Cannot process version select row since selected version document is null."); 316 } 317 318 if (Boolean.TRUE.equals(versionModelSelection.isSelected())) { 319 documentsListsManager.addToWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION, version); 320 } else { 321 documentsListsManager.removeFromWorkingList(DocumentsListsManager.CURRENT_VERSION_SELECTION, version); 322 } 323 } 324 325}