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