package org.fenixedu.bennu.portal.domain;
import java.util.ArrayList;
import java.util.List;
import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.core.groups.Group;
import org.fenixedu.bennu.core.security.Authenticate;
import org.fenixedu.commons.i18n.LocalizedString;
import pt.ist.fenixframework.Atomic;
/**
* Base class for items that are presented in an application's menu.
*
* {@code MenuItem}s are either a {@link MenuContainer}, aggregating other items or a {@link MenuFunctionality}, representing a
* concrete entry in the menu.
*
* Note that a {@link MenuItem} is immutable, meaning that once it is installed in the menu, it is not possible to modify any of
* its properties. If you desire to do so, {@code delete} the item and create a new one with the new values.
*
* {@code MenuItem}s are {@link Comparable} according to their order in the menu.
*
* @see MenuContainer
* @see MenuFunctionality
*
*/
public abstract class MenuItem extends MenuItem_Base implements Comparable<MenuItem> {
protected MenuItem() {
super();
setOrd(1);
}
protected final void init(MenuContainer parent, boolean visible, String accessGroup, LocalizedString title,
LocalizedString description, String path) {
setVisible(visible);
setAccessGroup(Group.parse(accessGroup));
setDescription(description);
setTitle(title);
setPath(path);
if (parent != null) {
parent.addChild(this);
}
setFullPath(computeFullPath());
}
protected final void init(MenuContainer parent, MenuItem original) {
setVisible(original.getVisible());
setAccessGroup(original.getAccessGroup());
setDescription(original.getDescription());
setTitle(original.getTitle());
setPath(original.getPath());
setLayout(original.getLayout());
if (parent != null) {
parent.addChild(this);
}
setFullPath(computeFullPath());
}
public Group getAccessGroup() {
return getGroup().toGroup();
}
public void setAccessGroup(Group group) {
setGroup(group.toPersistentGroup());
}
private String computeFullPath() {
StringBuilder builder = new StringBuilder();
builder.append("/");
builder.append(this.getPath());
MenuContainer current = getParent();
while (current != null && current.getConfiguration() == null) {
builder.insert(0, current.getPath());
builder.insert(0, "/");
current = current.getParent();
}
return builder.toString();
}
/**
* Compares this {@link MenuItem} with another, taking into account the order of both items.
*
* Note that it only makes sense to invoke this method for items at the same level, as there are no ordering guarantees across
* multiple levels.
*/
@Override
public int compareTo(MenuItem o) {
int ord = getOrd().compareTo(o.getOrd());
return ord == 0 ? getTitle().compareTo(o.getTitle()) : ord;
}
/**
* Deletes this item, removing it from the menu.
*/
@Atomic
public void delete() {
setParent(null);
setGroup(null);
deleteDomainObject();
}
/**
* Determines whether this {@link MenuItem} and all its parents are available for the given {@link User}.
*
* @param user
* The user to verify
* @return
* Whether the given user can access this item
*/
public boolean isAvailable(User user) {
return getGroup().isMember(user) && getParent().isAvailable(user);
}
/**
* Determines whether this {@link MenuItem} and all its parents are available for the currently logged user.
* This method is a shorthand for <code>isAvailable(Authenticate.getUser())</code>.
*
* @return
* Whether the currently logged user can access this item
*/
public boolean isAvailableForCurrentUser() {
return isAvailable(Authenticate.getUser());
}
/*
* Returns whether this item is available for the current user.
* Implementation Node: This method ONLY checks the current node, not the full chain!
*/
protected boolean isItemAvailableForCurrentUser() {
return getGroup().isMember(Authenticate.getUser());
}
/**
* Returns whether the Item should be visible when rendering a menu.
*
* @return
* {@code true} if this item is visible
*/
public boolean isVisible() {
return getVisible();
}
@Override
public MenuContainer getParent() {
//FIXME: remove when the framework enables read-only slots
return super.getParent();
}
@Override
public String getPath() {
//FIXME: remove when the framework enables read-only slots
return super.getPath();
}
@Override
public String getFullPath() {
//FIXME: remove when the framework enables read-only slots
return super.getFullPath();
}
public boolean isMenuContainer() {
return this instanceof MenuContainer;
}
public boolean isMenuFunctionality() {
return this instanceof MenuFunctionality;
}
public MenuContainer getAsMenuContainer() {
if (isMenuContainer()) {
return (MenuContainer) this;
}
throw new IllegalStateException("Not a MenuContainer");
}
public MenuFunctionality getAsMenuFunctionality() {
if (isMenuFunctionality()) {
return (MenuFunctionality) this;
}
throw new IllegalStateException("Not a MenuFunctionality");
}
public List<MenuItem> getPathFromRoot() {
List<MenuItem> result = new ArrayList<MenuItem>();
MenuItem current = this;
while (current.getParent() != null) {
result.add(0, current);
current = current.getParent();
}
return result;
}
protected abstract MenuItem moveTo(MenuContainer container);
}