/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.web;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.TreeSet;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.wicket.Page;
import org.apache.wicket.model.IModel;
import org.projectforge.web.wicket.WicketUtils;
/**
* Represents a single menu entry (of the user's individual menu).
*/
public class MenuEntry implements Serializable, Comparable<MenuEntry>
{
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(MenuEntry.class);
private static final long serialVersionUID = 7961498640193169174L;
protected Collection<MenuEntry> subMenuEntries;
protected String url;
protected boolean opened = false;
protected IModel<Integer> newCounterModel;
protected TotalNewCounterModel totalNewCounterModel;
protected boolean totalNewCounterModelEvaluated;
protected String newCounterTooltip;
protected MenuEntry parent;
protected Boolean visible;
protected MenuItemDef menuItemDef;
protected String name;
protected Menu menu;
private boolean mobileMenu;
private boolean sorted = true;
/**
* @param sorted if true (default) the entries are sorted, otherwise the order is the order of adding.
* @return this for chaining.
*/
public MenuEntry setSorted(final boolean sorted)
{
this.sorted = sorted;
return this;
}
public IModel<Integer> getNewCounterModel()
{
return getNewCounterModel(0);
}
private IModel<Integer> getNewCounterModel(final int depth)
{
if (hasSubMenuEntries() == false || depth == 10) {
// End less loop detection (depth == 10).
return newCounterModel;
}
if (totalNewCounterModelEvaluated == true) {
return totalNewCounterModel;
}
for (final MenuEntry subEntry : subMenuEntries) {
final IModel<Integer> subSumModel = subEntry.getNewCounterModel(depth + 1);
if (subSumModel == null) {
continue;
}
if (totalNewCounterModel == null) {
totalNewCounterModel = new TotalNewCounterModel();
}
totalNewCounterModel.add(subSumModel);
}
totalNewCounterModelEvaluated = true;
return totalNewCounterModel;
}
public void setNewCounterTooltip(final String newCounterTooltip)
{
this.newCounterTooltip = newCounterTooltip;
}
public String getNewCounterTooltip()
{
return newCounterTooltip;
}
/**
* Needed as marker for modified css.
*/
public boolean isFirst()
{
return menu.isFirst(this);
}
public MenuEntry getParent()
{
return parent;
}
/**
* @param menu Needed because MenuEntry is perhaps under construction and menu member isn't set yet.
* @param id
*/
public void setParent(final Menu menu, final String id)
{
final MenuEntry parentEntry = menu.findById(id);
if (parentEntry == null) {
log.error("Oups, menu entry '" + id + "' not found (ignoring setParent(...) of : " + getId());
} else {
setParent(parentEntry);
}
}
void setParent(final MenuEntry parent)
{
this.parent = parent;
}
public boolean hasParent()
{
return this.parent != null;
}
/**
* Root menu entry.
*/
MenuEntry()
{
}
public MenuEntry(final MenuItemDef menuItem, final MenuBuilderContext context)
{
this.menuItemDef = menuItem;
if (context.isMobileMenu() == true) {
mobileMenu = true;
Validate.notNull(menuItem.getMobilePageClass());
this.url = WicketUtils.getBookmarkablePageUrl(menuItem.getMobilePageClass());
} else if (menuItem.isWicketPage() == true) {
this.url = WicketUtils.getBookmarkablePageUrl(menuItem.getPageClass(), menuItem.getParams());
} else if (menuItem.getUrl() != null) {
this.url = "../secure/" + menuItem.getUrl();
}
}
public void setMenu(final Menu menu)
{
this.menu = menu;
menu.addMenuEntry(this);
}
/**
* @return the name Only given for customized menu entries if the user renamed the menu.
*/
public String getName()
{
return name;
}
/**
* @param name the name to set
* @return this for chaining.
*/
public MenuEntry setName(final String name)
{
this.name = name;
return this;
}
public void addMenuEntry(final MenuEntry subMenuEntry)
{
if (subMenuEntries == null) {
if (sorted == true) {
subMenuEntries = new TreeSet<MenuEntry>();
} else {
subMenuEntries = new ArrayList<MenuEntry>();
}
}
subMenuEntries.add(subMenuEntry);
subMenuEntry.setParent(this);
}
public MenuEntry findById(final String id)
{
if (menuItemDef != null && menuItemDef.getId().equals(id) == true) {
return this;
}
if (this.subMenuEntries == null) {
return null;
}
for (final MenuEntry subMenuEntry : this.subMenuEntries) {
final MenuEntry found = subMenuEntry.findById(id);
if (found != null) {
return found;
}
}
return null;
}
public boolean hasSubMenuEntries()
{
return (this.subMenuEntries != null && subMenuEntries.size() > 0);
}
public boolean isOpened()
{
return this.opened;
}
public MenuItemDef getParentMenuItemDef()
{
if (this.mobileMenu == true) {
return this.menuItemDef.getMobileParentMenu();
} else {
return this.menuItemDef.getParent();
}
}
/**
* Should the link open a separate window (named 'pforge2')?
* @return
*/
public boolean isNewWindow()
{
return menuItemDef != null && menuItemDef.isNewWindow();
}
public boolean isWicketPage()
{
return menuItemDef != null && menuItemDef.isWicketPage();
}
public Class< ? extends Page> getPageClass()
{
return menuItemDef != null ? menuItemDef.getPageClass() : null;
}
public Class< ? extends Page> getMobilePageClass()
{
return menuItemDef != null ? menuItemDef.getMobilePageClass() : null;
}
/**
* @return
*/
public Collection<MenuEntry> getSubMenuEntries()
{
return subMenuEntries;
}
public String getI18nKey()
{
return menuItemDef != null ? menuItemDef.getI18nKey() : null;
}
/**
* @return
*/
public String getUrl()
{
return url;
}
public String[] getParams()
{
return menuItemDef.getParams();
}
public void setNewCounterModel(final IModel<Integer> newCounterModel)
{
this.newCounterModel = newCounterModel;
}
public boolean isLink()
{
return menuItemDef.isWicketPage() == true || menuItemDef.hasUrl() == true;
}
/**
* @return True or false if variable visible is set. True, if no sub menu entries exists in this entry has an link. If sub menu entries
* does exist then it's visible if any of the sub menu entries is visible. The variable visible is set automatically after the
* first call of this method.
*/
public boolean isVisible()
{
if (visible != null) {
return visible;
}
if (subMenuEntries == null || subMenuEntries.size() == 0) {
visible = isLink();
} else {
for (final MenuEntry subMenuEntry : subMenuEntries) {
if (subMenuEntry.isVisible() == true) {
visible = true;
break;
}
}
}
return visible;
}
public void setVisible(final boolean visible)
{
this.visible = visible;
}
public String getId()
{
return menuItemDef != null ? menuItemDef.getId() : null;
}
@Override
public int compareTo(final MenuEntry o)
{
final int orderNumber = menuItemDef != null ? menuItemDef.getOrderNumber() : 10000;
final int otherOrderNumber = o.menuItemDef != null ? o.menuItemDef.getOrderNumber() : 10000;
if (orderNumber < otherOrderNumber) {
return -1;
} else if (orderNumber > otherOrderNumber) {
return 1;
}
final String name = menuItemDef != null ? menuItemDef.getI18nKey() : getName();
final String otherName = o.menuItemDef != null ? o.menuItemDef.getI18nKey() : o.getName();
return name.compareTo(otherName);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
final ToStringBuilder tos = new ToStringBuilder(this);
if (menuItemDef != null)
tos.append("menuItemDef", menuItemDef);
if (name != null)
tos.append("name", name);
return tos.toString();
}
}