001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui.components.fileselect; 029 030import static org.opencms.ui.components.CmsResourceTableProperty.PROPERTY_INSIDE_PROJECT; 031 032import org.opencms.db.CmsResourceState; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsPropertyDefinition; 035import org.opencms.file.CmsResource; 036import org.opencms.file.CmsResourceFilter; 037import org.opencms.file.CmsVfsResourceNotFoundException; 038import org.opencms.jsp.CmsJspNavBuilder; 039import org.opencms.jsp.CmsJspNavElement; 040import org.opencms.main.CmsException; 041import org.opencms.main.CmsLog; 042import org.opencms.main.OpenCms; 043import org.opencms.ui.CmsVaadinUtils; 044import org.opencms.ui.apps.Messages; 045import org.opencms.ui.components.CmsErrorDialog; 046import org.opencms.ui.components.CmsResourceIcon; 047import org.opencms.ui.components.CmsResourceTableProperty; 048import org.opencms.ui.util.I_CmsItemSorter; 049import org.opencms.util.CmsUUID; 050import org.opencms.workplace.explorer.CmsResourceUtil; 051 052import java.util.ArrayList; 053import java.util.Collection; 054import java.util.List; 055 056import org.apache.commons.logging.Log; 057 058import com.google.common.collect.Lists; 059import com.vaadin.v7.data.Container; 060import com.vaadin.v7.data.Item; 061import com.vaadin.v7.data.util.HierarchicalContainer; 062 063/** 064 * The data container for the sitmeap folder selection tree.<p> 065 */ 066public class CmsResourceTreeContainer extends HierarchicalContainer { 067 068 /** Property which is used to store the CmsResource. */ 069 public static final String PROPERTY_RESOURCE = "RESOURCE"; 070 071 /** Property which is used to store the sitemap view caption HTML. */ 072 public static final String PROPERTY_SITEMAP_CAPTION = "SITEMAP_CAPTION"; 073 074 /** The logger instance for this class. */ 075 private static final Log LOG = CmsLog.getLog(CmsResourceTreeContainer.class); 076 077 /** Serial version id. */ 078 private static final long serialVersionUID = 1L; 079 080 /** The resource filter. */ 081 private CmsResourceFilter m_filter; 082 083 /** 084 * Default constructor.<p> 085 * 086 * @param filter the resource filter to use 087 */ 088 public CmsResourceTreeContainer(CmsResourceFilter filter) { 089 090 m_filter = filter; 091 defineProperties(); 092 } 093 094 /** 095 * Adds an item to the folder tree.<p> 096 * 097 * @param cms the CMS context 098 * @param resource the folder resource 099 * @param parentId the parent folder id 100 */ 101 public void addTreeItem(CmsObject cms, CmsResource resource, CmsUUID parentId) { 102 103 List<Container.Filter> filters = Lists.newArrayList(getContainerFilters()); 104 105 // getItem only finds an existing item if it isn't filtered out by the container 106 // filters, so we temporarily remove the filters to access the complete data set 107 removeAllContainerFilters(); 108 try { 109 Item resourceItem = getItem(resource.getStructureId()); 110 if (resourceItem == null) { 111 resourceItem = addItem(resource.getStructureId()); 112 } 113 fillProperties(cms, resourceItem, resource, parentId); 114 if (resource.isFile()) { 115 setChildrenAllowed(resource.getStructureId(), false); 116 } 117 if (parentId != null) { 118 setParent(resource.getStructureId(), parentId); 119 } 120 } finally { 121 for (Container.Filter filter : filters) { 122 addContainerFilter(filter); 123 } 124 } 125 } 126 127 /** 128 * @see com.vaadin.v7.data.util.IndexedContainer#getSortableContainerPropertyIds() 129 */ 130 @Override 131 public Collection<?> getSortableContainerPropertyIds() { 132 133 if (getItemSorter() instanceof I_CmsItemSorter) { 134 return ((I_CmsItemSorter)getItemSorter()).getSortableContainerPropertyIds(this); 135 } else { 136 return super.getSortableContainerPropertyIds(); 137 } 138 } 139 140 /** 141 * Initializes the root level of the tree.<p> 142 * 143 * @param cms the CMS context 144 * @param root the root folder 145 */ 146 public void initRoot(CmsObject cms, CmsResource root) { 147 148 addTreeItem(cms, root, null); 149 readTreeLevel(cms, root.getStructureId()); 150 } 151 152 /** 153 * Reads the given tree level.<p> 154 * @param cms the CMS context 155 * @param parentId the parent id 156 */ 157 public void readTreeLevel(CmsObject cms, CmsUUID parentId) { 158 159 try { 160 CmsResource parent = cms.readResource(parentId, m_filter); 161 List<CmsResource> children = cms.readResources(parent, m_filter, false); 162 163 // sets the parent to leaf mode, in case no child folders are present 164 setChildrenAllowed(parentId, !children.isEmpty()); 165 166 for (CmsResource resource : children) { 167 addTreeItem(cms, resource, parentId); 168 } 169 } catch (CmsException e) { 170 CmsErrorDialog.showErrorDialog( 171 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_READ_RESOURCE_1, parentId), 172 e); 173 LOG.error(e.getLocalizedMessage(), e); 174 } 175 } 176 177 /** 178 * Clears the given tree level.<p> 179 * 180 * @param parentId the parent id 181 */ 182 public void removeChildren(CmsUUID parentId) { 183 184 // create a new list to avoid concurrent modifications 185 Collection<?> children = getChildren(parentId); 186 // may be null when monkey clicking 187 if (children != null) { 188 List<Object> childIds = new ArrayList<Object>(children); 189 for (Object childId : childIds) { 190 removeItemRecursively(childId); 191 } 192 } 193 } 194 195 /** 196 * Updates the item for the given structure id.<p> 197 * 198 * @param cms the CMS context 199 * @param id the structure id 200 * @param filter the resource filter used for reading the resource 201 * 202 * @throws CmsException if something goes wrong 203 */ 204 public void update(CmsObject cms, CmsUUID id, CmsResourceFilter filter) throws CmsException { 205 206 try { 207 CmsResource resource = cms.readResource(id, filter); 208 209 CmsResource parent = cms.readParentFolder(id); 210 CmsUUID parentId = parent.getStructureId(); 211 Item resourceItem = getItem(id); 212 if (resourceItem != null) { 213 fillProperties(cms, resourceItem, resource, parentId); 214 if (parentId != null) { 215 setParent(resource.getStructureId(), parentId); 216 } 217 } else { 218 addTreeItem(cms, resource, parentId); 219 } 220 } catch (CmsVfsResourceNotFoundException e) { 221 removeItemRecursively(id); 222 LOG.debug(e.getLocalizedMessage(), e); 223 } 224 } 225 226 /** 227 * Updates the item order according to the latest sort setting.<p> 228 */ 229 public void updateSort() { 230 231 doSort(); 232 233 // Post sort updates 234 if (isFiltered()) { 235 filterAll(); 236 } else { 237 fireItemSetChange(); 238 } 239 } 240 241 /** 242 * Defines the container properties.<p> 243 */ 244 protected void defineProperties() { 245 246 addContainerProperty(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME, String.class, null); 247 addContainerProperty(CmsResourceTableProperty.PROPERTY_STATE, CmsResourceState.class, null); 248 addContainerProperty(CmsResourceTableProperty.PROPERTY_TREE_CAPTION, String.class, null); 249 addContainerProperty(CmsResourceTableProperty.PROPERTY_INSIDE_PROJECT, Boolean.class, Boolean.TRUE); 250 addContainerProperty(CmsResourceTableProperty.PROPERTY_IS_FOLDER, Boolean.class, Boolean.TRUE); 251 addContainerProperty(PROPERTY_RESOURCE, CmsResource.class, null); 252 253 addContainerProperty(CmsResourceTableProperty.PROPERTY_IN_NAVIGATION, Boolean.class, Boolean.FALSE); 254 addContainerProperty( 255 CmsResourceTableProperty.PROPERTY_NAVIGATION_POSITION, 256 Float.class, 257 Float.valueOf(Float.MAX_VALUE)); 258 addContainerProperty(PROPERTY_SITEMAP_CAPTION, String.class, ""); 259 addContainerProperty( 260 CmsResourceTableProperty.PROPERTY_NAVIGATION_TEXT, 261 CmsResourceTableProperty.PROPERTY_NAVIGATION_TEXT.getColumnType(), 262 ""); 263 } 264 265 /** 266 * Fills the properties of a tree item.<p> 267 * 268 * @param cms the CMS context 269 * @param resourceItem the empty item 270 * @param resource the resource for which the tree item is being created 271 * @param parentId the parent id 272 */ 273 protected void fillProperties(CmsObject cms, Item resourceItem, CmsResource resource, CmsUUID parentId) { 274 275 resourceItem.getItemProperty(PROPERTY_RESOURCE).setValue(resource); 276 // use the root path as name in case of the root item 277 String name = getName(cms, resource, parentId); 278 if (resource.isFolder() && !name.endsWith("/")) { 279 name += "/"; 280 } 281 CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource); 282 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME).setValue(name); 283 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_STATE).setValue(resource.getState()); 284 285 resourceItem.getItemProperty(PROPERTY_INSIDE_PROJECT).setValue(Boolean.valueOf(resUtil.isInsideProject())); 286 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_IS_FOLDER).setValue( 287 Boolean.valueOf(resource.isFolder())); 288 try { 289 CmsObject rootCms = OpenCms.initCmsObject(cms); 290 rootCms.getRequestContext().setSiteRoot(""); 291 CmsJspNavBuilder builder = new CmsJspNavBuilder(rootCms); 292 CmsJspNavElement nav = builder.getNavigationForResource(resource.getRootPath(), m_filter); 293 boolean inNavigation = (nav != null) && nav.isInNavigation(); 294 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_IN_NAVIGATION).setValue( 295 Boolean.valueOf(inNavigation)); 296 String navText = null; 297 if (nav != null) { 298 if (inNavigation) { 299 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_NAVIGATION_POSITION).setValue( 300 Float.valueOf(nav.getNavPosition())); 301 } 302 303 if (nav.getProperties().containsKey(CmsPropertyDefinition.PROPERTY_NAVTEXT)) { 304 navText = nav.getProperties().get(CmsPropertyDefinition.PROPERTY_NAVTEXT); 305 } else if (nav.getProperties().containsKey(CmsPropertyDefinition.PROPERTY_TITLE)) { 306 navText = nav.getProperties().get(CmsPropertyDefinition.PROPERTY_TITLE); 307 } 308 } 309 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_NAVIGATION_TEXT).setValue(navText); 310 String folderCaption; 311 folderCaption = CmsResourceIcon.getTreeCaptionHTML(name, resUtil, null, false); 312 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TREE_CAPTION).setValue(folderCaption); 313 if (inNavigation) { 314 if (navText == null) { 315 navText = name; 316 } 317 String sitemapCaption = CmsResourceIcon.getTreeCaptionHTML(navText, resUtil, null, false); 318 resourceItem.getItemProperty(PROPERTY_SITEMAP_CAPTION).setValue(sitemapCaption); 319 } 320 321 } catch (CmsException e) { 322 LOG.error(e.getLocalizedMessage(), e); 323 } 324 325 } 326 327 /** 328 * Gets the name to display for the given resource.<p> 329 * 330 * @param cms the CMS context 331 * @param resource a resource 332 * @param parentId the id of the parent of the resource 333 * 334 * @return the name for the given resoure 335 */ 336 protected String getName(CmsObject cms, CmsResource resource, CmsUUID parentId) { 337 338 return parentId == null ? resource.getRootPath() : resource.getName(); 339 } 340}