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