package net.sourceforge.fenixedu.presentationTier.renderers.functionalities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;
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.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 generates a menu with a tree of functionalities available to
* the user in the current context.
*
*
* Each functionality that has a path defined will be a link to that path. If' a
* functionality is not visible to the user it will not be shown.
*
* @author cfgi
*/
public class MenuRenderer extends OutputRenderer {
private String selectedClasses;
private String selectedStyle;
private String moduleClasses;
private String moduleStyle;
private Map levelClasses;
private Map levelStyle;
public MenuRenderer() {
super();
this.levelClasses = new Hashtable();
this.levelStyle = new Hashtable();
}
public String getSelectedClasses() {
return this.selectedClasses;
}
/**
* Sets the CSS classes to be used in the entry that corresponds to the
* selected functionality.
*
* @property
*/
public void setSelectedClasses(String selectedClasses) {
this.selectedClasses = selectedClasses;
}
public String getSelectedStyle() {
return this.selectedStyle;
}
/**
* Sets the CSS style to be applied to the menu entry that corresponds to
* the selected funcitonality
*
* @property
*/
public void setSelectedStyle(String selectedStyle) {
this.selectedStyle = selectedStyle;
}
public String getLevelClasses(String index) {
return this.levelClasses.get(Integer.parseInt(index));
}
/**
* Selects the CSS classes to apply to each level of the menu. The first
* level is level 0.
*
* @property
*/
public void setLevelClasses(String index, String value) {
this.levelClasses.put(Integer.parseInt(index), value);
}
public String getLevelStyle(String index) {
return this.levelStyle.get(Integer.parseInt(index));
}
/**
* Selects the CSS style to apply to each level of the menu.
*
* @property
*/
public void getLevelStyle(String index, String value) {
this.levelStyle.put(Integer.parseInt(index), value);
}
public String getModuleClasses() {
return this.moduleClasses;
}
/**
* Chooses the CSS classes to apply to the an entry corresponding to a
* module.
*
* @property
*/
public void setModuleClasses(String moduleClasses) {
this.moduleClasses = moduleClasses;
}
public String getModuleStyle() {
return this.moduleStyle;
}
/**
* Sets the CSS style to apply to an a module entry.
*
* @property
*/
public void setModuleStyle(String moduleStyle) {
this.moduleStyle = moduleStyle;
}
@Override
protected Layout getLayout(Object object, Class type) {
return new Layout() {
@Override
public HtmlComponent createComponent(final Object object, final Class type) {
final FilterFunctionalityContext context = (FilterFunctionalityContext) object;
if (context == null || context.getCurrentContextPath() == null) {
return new HtmlText();
}
final Container container = context.getSelectedContainer();
final HtmlList menu = new HtmlList();
addMenuEntries(context, menu, (Collection) container.getOrderedChildrenNodes(), new ArrayList());
return menu;
}
private void addMenuEntries(final FilterFunctionalityContext context, final HtmlList menu,
final Collection entries, final Collection subPath) {
for (MenuEntry entry : entries) {
if (!entry.isNodeVisible() || !entry.isAvailable(context)) {
continue;
}
HtmlListItem item = menu.createItem();
item.addChild(getFunctionalityNameComponent(context, entry, true, subPath));
if (!entry.getChildren().isEmpty()) {
HtmlComponent child = item.getChildren().get(0);
HtmlText text;
if (child instanceof HtmlText) {
text = (HtmlText) child;
} else {
text = (HtmlText) ((HtmlLink) child).getBody();
}
text.setFace(Face.STRONG);
item.setClasses(getModuleClasses());
item.setStyle(getModuleStyle());
HtmlList subMenu = new HtmlList();
item.addChild(subMenu);
final String name = entry.getReferingContent().getNormalizedName().getContent();
subPath.add(name);
addMenuEntries(context, subMenu, entry.getChildren(), subPath);
subPath.remove(name);
}
boolean selected = false;
if (context.getSelectedContent() != null
&& context.getSelectedContent().getContentId().equals(entry.getEntryId())) {
selected = true;
} else {
String nodeId = context.getRequest().getParameter("nodeID");
if (nodeId != null && nodeId.equals(entry.getEntryId())) {
selected = true;
}
}
if (selected) {
String existingClasses = item.getClasses() == null ? "" : item.getClasses();
String existingStyle = item.getStyle() == null ? "" : item.getStyle();
item.setClasses(existingClasses + getSelectedClasses());
item.setStyle(existingStyle + getSelectedStyle());
}
}
menu.setClasses(getLevelClasses(String.valueOf(subPath.size())));
menu.setStyle(getLevelStyle(String.valueOf(subPath.size())));
}
};
}
/**
* Creates a component that shows the functionality name, possibly in a link
* to the functionality's public path. If the fuctionality is parameterized
* then the required parameters are appended to the link.
*/
public static HtmlComponent getFunctionalityNameComponent(FilterFunctionalityContext context, MenuEntry entry,
boolean canMakeLink, final Collection subPath) {
HtmlText text = new HtmlText(entry.getName().getContent());
text.setFace(Face.STANDARD);
HtmlComponent component = text;
String path = entry.getPath();
if (path != null && canMakeLink && entry.isAvailable()) {
final Content content = entry.getReferingContent();
final String linkPrefix = content.isPublic() ? ChecksumRewriter.NO_CHECKSUM_PREFIX_HAS_CONTEXT_PREFIX
: ContentInjectionRewriter.HAS_CONTEXT_PREFIX;
HtmlLink link = new HtmlLinkWithPreprendedComment(linkPrefix);
link.setContextRelative(false);
link.setUrl(findPathFor(context.getRequest().getContextPath(), content, context, subPath));
link.setBody(component);
component = link;
}
MultiLanguageString title = entry.getTitle();
if (title != null && !title.isEmpty()) {
component.setTitle(title.getContent());
}
return component;
}
public static String findPathFor(final String contextPath, final Content targetContent,
final FilterFunctionalityContext context, final Collection subPath) {
final StringBuilder buffer = new StringBuilder(contextPath);
buffer.append(context.getSelectedContainerPath());
for (final String name : subPath) {
buffer.append('/');
buffer.append(name);
}
buffer.append('/');
buffer.append(targetContent.getNormalizedName().getContent());
return buffer.toString();
}
}