/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.theme;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.model.Layout;
import com.liferay.portal.kernel.model.LayoutType;
import com.liferay.portal.kernel.security.permission.ActionKeys;
import com.liferay.portal.kernel.service.LayoutLocalServiceUtil;
import com.liferay.portal.kernel.service.permission.LayoutPermissionUtil;
import com.liferay.portal.kernel.util.HtmlUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.PredicateFilter;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.kernel.webserver.WebServerServletTokenUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/**
* Represents a portal navigation item, providing access to layouts and metadata
* from templates, which can be found in a theme's
* <code>portal-normal.vm</code>.
*
* @author Brian Wing Shun Chan
* @author Shuyang Zhou
*/
public class NavItem implements Serializable {
/**
* Creates a single level of navigation items from the layouts. Navigation
* items for nested layouts are only created when they are accessed.
*
* <p>
* No permission checks are performed in this method. Permissions of child
* layouts are honored when accessing them via {@link #getChildren()}.
* </p>
*
* @param request the currently served {@link HttpServletRequest}
* @param layouts the layouts from which to create the navigation items
* @return a single level of navigation items from the layouts, or
* <code>null</code> if the collection of layouts was
* <code>null</code>.
* @deprecated As of 7.0.0, replaced by {@link #fromLayouts(
* HttpServletRequest, ThemeDisplay, Map)}
*/
@Deprecated
public static List<NavItem> fromLayouts(
HttpServletRequest request, List<Layout> layouts,
Map<String, Object> contextObjects) {
if ((layouts == null) || layouts.isEmpty()) {
return Collections.emptyList();
}
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
List<NavItem> navItems = new ArrayList<>(layouts.size());
for (Layout layout : layouts) {
navItems.add(
new NavItem(request, themeDisplay, layout, contextObjects));
}
return navItems;
}
public static List<NavItem> fromLayouts(
HttpServletRequest request, ThemeDisplay themeDisplay,
Map<String, Object> contextObjects)
throws PortalException {
List<Layout> parentLayouts = themeDisplay.getLayouts();
if (parentLayouts == null) {
return Collections.emptyList();
}
Map<Long, List<Layout>> layoutChildLayouts =
LayoutLocalServiceUtil.getLayoutChildLayouts(
themeDisplay.getLayoutSet(), parentLayouts);
for (List<Layout> childLayouts : layoutChildLayouts.values()) {
Iterator<Layout> iterator = childLayouts.iterator();
while (iterator.hasNext()) {
Layout childLayout = iterator.next();
if (childLayout.isHidden() ||
!LayoutPermissionUtil.contains(
themeDisplay.getPermissionChecker(), childLayout,
ActionKeys.VIEW)) {
iterator.remove();
}
}
}
List<NavItem> navItems = new ArrayList<>(parentLayouts.size());
for (Layout parentLayout : parentLayouts) {
List<Layout> childLayouts = layoutChildLayouts.get(
parentLayout.getLayoutId());
navItems.add(
new NavItem(
request, themeDisplay, parentLayout, childLayouts,
contextObjects));
}
return navItems;
}
public NavItem(
HttpServletRequest request, Layout layout,
Map<String, Object> contextObjects) {
this(
request, (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY),
layout, contextObjects);
}
public NavItem(
HttpServletRequest request, ThemeDisplay themeDisplay, Layout layout,
Map<String, Object> contextObjects) {
_request = request;
_themeDisplay = themeDisplay;
_layout = layout;
_contextObjects = contextObjects;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof NavItem)) {
return false;
}
NavItem navItem = (NavItem)obj;
if (getLayoutId() == navItem.getLayoutId()) {
return true;
}
return false;
}
/**
* Returns all of the browsable child layouts that the current user has
* permission to access from this navigation item's layout.
*
* @return the list of all browsable child layouts that the current user has
* permission to access from this navigation item's layout
* @throws Exception if an exception occurred
*/
public List<NavItem> getBrowsableChildren() throws Exception {
if (_browsableChildren == null) {
List<NavItem> children = getChildren();
_browsableChildren = ListUtil.filter(
children,
new PredicateFilter<NavItem>() {
@Override
public boolean filter(NavItem navItem) {
return navItem.isBrowsable();
}
});
}
return _browsableChildren;
}
/**
* Returns all of child layouts that the current user has permission to
* access from this navigation item's layout.
*
* @return the list of all child layouts that the current user has
* permission to access from this navigation item's layout
* @throws Exception if an exception occurred
*/
public List<NavItem> getChildren() throws Exception {
if (_children == null) {
List<Layout> layouts = _layout.getChildren(
_themeDisplay.getPermissionChecker());
_children = _fromLayouts(
_request, _themeDisplay, layouts, _contextObjects);
}
return _children;
}
/**
* Returns the navigation item's layout.
*
* @return the navigation item's layout
*/
public Layout getLayout() {
return _layout;
}
/**
* Returns the ID of the navigation item's layout.
*
* @return the ID of the navigation item's layout
*/
public long getLayoutId() {
return _layout.getLayoutId();
}
/**
* Returns the HTML-escaped name of the navigation item's layout.
*
* @return the HTML-escaped name of the navigation item's layout
*/
public String getName() {
return HtmlUtil.escape(getUnescapedName());
}
/**
* Returns the full, absolute URL (including the portal's URL) of the
* navigation item's layout.
*
* @return the full, absolute URL of the navigation item's layout
* @throws Exception if an exception occurred
*/
public String getRegularFullURL() throws Exception {
String portalURL = _themeDisplay.getPortalURL();
String regularURL = getRegularURL();
if (StringUtil.startsWith(regularURL, portalURL) ||
Validator.isUrl(regularURL)) {
return regularURL;
}
else {
return portalURL.concat(regularURL);
}
}
/**
* Returns the regular URL of the navigation item's layout.
*
* @return the regular URL of the navigation item's layout
* @throws Exception if an exception occurred
*/
public String getRegularURL() throws Exception {
return _layout.getRegularURL(_request);
}
public String getResetLayoutURL() throws Exception {
return _layout.getResetLayoutURL(_request);
}
public String getResetMaxStateURL() throws Exception {
return _layout.getResetMaxStateURL(_request);
}
/**
* Returns the target of the navigation item's layout.
*
* @return the target of the navigation item's layout
*/
public String getTarget() {
return _layout.getTarget();
}
/**
* Returns the title of the navigation item's layout in the current
* request's locale.
*
* @return the title of the navigation item's layout in the current
* request's locale
*/
public String getTitle() {
return _layout.getTitle(_themeDisplay.getLanguageId());
}
/**
* Returns the unescaped name of the navigation item's layout in the current
* request's locale.
*
* @return the unescaped name of the navigation item's layout in the current
* request's locale
*/
public String getUnescapedName() {
return _layout.getName(_themeDisplay.getLanguageId());
}
/**
* Returns the URL of the navigation item's layout, in a format that makes
* it safe to use the URL as an HREF attribute value
*
* @return the URL of the navigation item's layout, in a format that makes
* it safe to use the URL as an HREF attribute value
* @throws Exception if an exception occurred
*/
public String getURL() throws Exception {
return HtmlUtil.escapeHREF(getRegularFullURL());
}
/**
* Returns <code>true</code> if the navigation item's layout has browsable
* child layouts.
*
* @return <code>true</code> if the navigation item's layout has browsable
* child layouts; <code>false</code> otherwise
* @throws Exception if an exception occurred
*/
public boolean hasBrowsableChildren() throws Exception {
List<NavItem> browsableChildren = getBrowsableChildren();
if (!browsableChildren.isEmpty()) {
return true;
}
else {
return false;
}
}
/**
* Returns <code>true</code> if the navigation item's layout has child
* layouts.
*
* @return <code>true</code> if the navigation item's layout has child
* layouts; <code>false</code> otherwise
* @throws Exception if an exception occurred
*/
public boolean hasChildren() throws Exception {
List<NavItem> children = getChildren();
if (!children.isEmpty()) {
return true;
}
else {
return false;
}
}
@Override
public int hashCode() {
return _layout.hashCode();
}
public String iconURL() throws Exception {
if ((_layout == null) || !_layout.isIconImage()) {
return StringPool.BLANK;
}
StringBundler sb = new StringBundler(5);
sb.append(_themeDisplay.getPathImage());
sb.append("/layout_icon?img_id");
sb.append(_layout.getIconImageId());
sb.append("&t=");
sb.append(WebServerServletTokenUtil.getToken(_layout.getIconImageId()));
return sb.toString();
}
public boolean isBrowsable() {
LayoutType layoutType = _layout.getLayoutType();
return layoutType.isBrowsable();
}
public boolean isChildSelected() throws PortalException {
return _layout.isChildSelected(
_themeDisplay.isTilesSelectable(), _themeDisplay.getLayout());
}
public boolean isInNavigation(List<NavItem> navItems) {
if (navItems == null) {
return false;
}
return navItems.contains(this);
}
public boolean isSelected() throws Exception {
return _layout.isSelected(
_themeDisplay.isTilesSelectable(), _themeDisplay.getLayout(),
_themeDisplay.getLayout().getAncestorPlid());
}
private static List<NavItem> _fromLayouts(
HttpServletRequest request, ThemeDisplay themeDisplay,
List<Layout> layouts, Map<String, Object> contextObjects) {
if ((layouts == null) || layouts.isEmpty()) {
return Collections.emptyList();
}
List<NavItem> navItems = new ArrayList<>(layouts.size());
for (Layout layout : layouts) {
navItems.add(
new NavItem(request, themeDisplay, layout, contextObjects));
}
return navItems;
}
private NavItem(
HttpServletRequest request, ThemeDisplay themeDisplay, Layout layout,
List<Layout> childLayouts, Map<String, Object> contextObjects) {
_request = request;
_themeDisplay = themeDisplay;
_layout = layout;
_children = _fromLayouts(
request, themeDisplay, childLayouts, contextObjects);
_contextObjects = contextObjects;
}
private List<NavItem> _browsableChildren;
private List<NavItem> _children;
private final Map<String, Object> _contextObjects;
private final Layout _layout;
private final HttpServletRequest _request;
private final ThemeDisplay _themeDisplay;
}