package net.sourceforge.fenixedu.presentationTier.renderers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.sourceforge.fenixedu.domain.Item;
import net.sourceforge.fenixedu.domain.Site;
import net.sourceforge.fenixedu.domain.contents.Attachment;
import net.sourceforge.fenixedu.domain.contents.Container;
import net.sourceforge.fenixedu.domain.contents.Content;
import net.sourceforge.fenixedu.domain.contents.MenuEntry;
import net.sourceforge.fenixedu.domain.functionalities.FunctionalityContext;
import net.sourceforge.fenixedu.domain.messaging.Forum;
import net.sourceforge.fenixedu.presentationTier.renderers.functionalities.MenuRenderer;
import net.sourceforge.fenixedu.presentationTier.servlets.filters.ChecksumRewriter;
import net.sourceforge.fenixedu.presentationTier.servlets.filters.ContentInjectionRewriter;
import net.sourceforge.fenixedu.presentationTier.servlets.filters.functionalities.FilterFunctionalityContext;
import pt.ist.fenixWebFramework.renderers.OutputRenderer;
import pt.ist.fenixWebFramework.renderers.components.Face;
import pt.ist.fenixWebFramework.renderers.components.HtmlComponent;
import pt.ist.fenixWebFramework.renderers.components.HtmlLink;
import pt.ist.fenixWebFramework.renderers.components.HtmlLinkWithPreprendedComment;
import pt.ist.fenixWebFramework.renderers.components.HtmlList;
import pt.ist.fenixWebFramework.renderers.components.HtmlListItem;
import pt.ist.fenixWebFramework.renderers.components.HtmlText;
import pt.ist.fenixWebFramework.renderers.layouts.Layout;
import pt.utl.ist.fenix.tools.util.i18n.MultiLanguageString;
/**
* This renderer is responsible for presenting a
* {@link net.sourceforge.fenixedu.domain.Site} as a menu. It uses all the
* sections defined in the site and it's template to generate the menu and
* expands some sections if they were selected. The renderer uses parameters to
* interact with the environment, so some parameters like sectionID are
* appended automatically and others, like the one indicated by
* {@link #setContextParam(String)}, are appened to mantain the required context
* for the target site.
*/
public class SiteMenuRenderer extends OutputRenderer {
private boolean contextRelative;
private boolean moduleRelative;
private String sectionUrl;
private String contextParam;
private String empty;
private String depthStyle;
public SiteMenuRenderer() {
super();
setModuleRelative(true);
setContextRelative(true);
}
public String getDepthStyle() {
return depthStyle;
}
public void setDepthStyle(String depthStyle) {
this.depthStyle = depthStyle;
}
public boolean isContextRelative() {
return this.contextRelative;
}
/**
* Indicates that the url for the sections ir not relative to the
* applications context. This can be usefull to redirect to another
* application or the remove dependencies on Struts.
*
* @property
*/
public void setContextRelative(boolean contextRelative) {
this.contextRelative = contextRelative;
}
public boolean isModuleRelative() {
return this.moduleRelative;
}
/**
* Indicates that the link for sections is not relative to the module.
*
* @property
*/
public void setModuleRelative(boolean moduleRelative) {
this.moduleRelative = moduleRelative;
}
public String getSectionUrl() {
return this.sectionUrl;
}
/**
* The url of the action responsible for showing the section content.
*
* @property
*/
public void setSectionUrl(String sectionUrl) {
this.sectionUrl = sectionUrl;
}
public String getContextParam() {
return this.contextParam;
}
/**
* The name of the parameters that provides a context for this site.
*
* @property
*/
public void setContextParam(String contextParam) {
this.contextParam = contextParam;
}
public String getEmpty() {
return empty;
}
/**
* Decides what to show when there are no sections to include in the menu.
*
* @property
*/
public void setEmpty(String empty) {
this.empty = empty;
}
protected boolean accessTemplate() {
return true;
}
@Override
protected Layout getLayout(Object object, Class type) {
return new Layout() {
public HtmlComponent createComponent(Object object, Class type) {
if (object == null) {
return new HtmlText();
}
HtmlList list = new HtmlList();
HttpServletRequest request = getContext().getViewState().getRequest();
FilterFunctionalityContext context = (FilterFunctionalityContext) request
.getAttribute(FunctionalityContext.CONTEXT_KEY);
if (context == null) {
context = new FilterFunctionalityContext(request, "ISO-8859-1");
}
Collection entries = getEntries(object);
if (entries.isEmpty()) {
return generateEmpty();
}
createList(list, context, entries, 0);
return list;
}
public void createList(HtmlList list, FilterFunctionalityContext context, Collection entries, Integer depth) {
for (MenuEntry entry : entries) {
if (!entry.isNodeVisible()) {
continue;
}
Content content = entry.getReferingContent();
if (!(content instanceof Item || content instanceof Forum || content instanceof Attachment)) {
HtmlListItem item = list.createItem();
item.addChild(generateComponent(context, content, true));
if (depth > 0) {
item.setStyle(getDepthStyle());
}
if (allowsSubMenus() && isSelectedContent(content, context) && !entry.getChildren().isEmpty()) {
HtmlList subMenu = new HtmlList();
item.addChild(subMenu);
createList(subMenu, context, entry.getChildren(), depth + 1);
}
}
}
}
private HtmlLink generateLink(final String url, final HtmlComponent body, final boolean isPublic) {
final String preapendedComment = isPublic ? ChecksumRewriter.NO_CHECKSUM_PREFIX_HAS_CONTEXT_PREFIX
: ContentInjectionRewriter.HAS_CONTEXT_PREFIX;
HtmlLink link = new HtmlLinkWithPreprendedComment(preapendedComment);
link.setContextRelative(false);
link.setUrl(url);
link.setBody(body);
String contextParamValue = getContextParamValue();
if (contextParamValue != null) {
link.setParameter(getContextParam(), contextParamValue);
}
return link;
}
public HtmlComponent generateComponent(FilterFunctionalityContext context, Content content, boolean canMakeLink) {
HtmlText text = new HtmlText(content.getName().getContent());
text.setFace(Face.STANDARD);
HtmlComponent component = text;
if (content.isAvailable()) {
component = generateLink(getPath(context, content), component, content.isPublic());
}
MultiLanguageString title = content.getTitle();
if (title != null && !title.isEmpty()) {
component.setTitle(title.getContent());
}
return component;
}
private HtmlComponent generateEmpty() {
return new HtmlText(getEmpty(), false);
}
private boolean isSelectedContent(Content current, FunctionalityContext context) {
FilterFunctionalityContext filterContext = (FilterFunctionalityContext) context;
Container selectedContainer = filterContext.getSelectedContainer();
return !filterContext.getPathBetween(selectedContainer, current).isEmpty();
}
private String getContextParamValue() {
String contextParam = getContextParam();
if (contextParam == null) {
return null;
}
HttpServletRequest request = getContext().getViewState().getRequest();
return request.getParameter(contextParam);
}
};
}
protected Collection getEntries(Object object) {
return getSite(object).getMenu();
}
protected Site getSite(Object object) {
return (Site) object;
}
protected String getPath(FilterFunctionalityContext context, Content content) {
return MenuRenderer.findPathFor(context.getRequest().getContextPath(), content, context, subPath(context
.getSelectedContainer(), content));
}
protected boolean allowsSubMenus() {
return true;
}
private List subPath(Container start, Content end) {
List contents = start.getPathTo(end);
List subPaths = new ArrayList();
if (contents.size() > 2) {
for (Content content : contents.subList(1, contents.size() - 1)) {
subPaths.add(content.getNormalizedName().getContent());
}
}
return subPaths;
}
}