/*******************************************************************************
* Copyright (c) 2012-2013 RelationWare, Benno Luthiger
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* RelationWare, Benno Luthiger
******************************************************************************/
package org.ripla.web.internal.menu;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.User;
import org.ripla.interfaces.IRiplaEventDispatcher;
import org.ripla.interfaces.IRiplaEventDispatcher.Event;
import org.ripla.util.ParameterObject;
import org.ripla.web.Constants;
import org.ripla.web.interfaces.IContextMenuItem;
import org.ripla.web.interfaces.IMenuSet;
import org.ripla.web.interfaces.IPluggable;
import org.ripla.web.util.UseCaseHelper;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.BaseTheme;
/**
* Helper class responsible for managing all context menu items.
* <p>
* The context menu is the menu displayed in the sidebar panel, i.e. the left
* part of the main window.
* </p>
*
* @author Luthiger
*/
public final class ContextMenuManager {
private final transient Map<String, ContextMenuSet> contextMenus = Collections
.synchronizedMap(new HashMap<String, ContextMenuManager.ContextMenuSet>());
/**
* Private constructor.
*/
private ContextMenuManager() {
}
/**
* Factory method, creates an initialized instance of
* {@link ContextMenuManager}.
*
* @return {@link ContextMenuManager}
*/
public static ContextMenuManager createInstance() {
final ContextMenuManager out = new ContextMenuManager();
// add empty menu
out.addContextMenuSet(new IMenuSet() {
@Override
public String getSetID() {
return Constants.MENU_SET_ID_EMPTY;
}
@Override
public IContextMenuItem[] getContextMenuItems() {
return new IContextMenuItem[] {};
}
});
return out;
}
/**
* Adds the configuration of a context menu set to the menu manager.
*
* @param inMenuSet
* {@link IMenuSet}
*/
public void addContextMenuSet(final IMenuSet inMenuSet) {
final String lSetID = UseCaseHelper.createFullyQualifiedID(
inMenuSet.getSetID(), inMenuSet.getClass());
final ContextMenuSet lContextMenuSet = new ContextMenuSet();
for (final IContextMenuItem lContextMenuItem : inMenuSet
.getContextMenuItems()) {
lContextMenuSet.addContextMenuItem(new ContextMenuItem( // NOPMD
lContextMenuItem));
}
contextMenus.put(lSetID, lContextMenuSet);
}
/**
* Removes the configuration of a context menu set from the menu manager.
*
* @param inMenuSet
* {@link IMenuSet}
*/
public void removeContextMenuSet(final IMenuSet inMenuSet) {
contextMenus.remove(UseCaseHelper.createFullyQualifiedID(
inMenuSet.getSetID(), inMenuSet.getClass()));
}
/**
* Method to render the context menu.
*
* @param inMenuSetName
* String the fully qualified ID of the context menu
* @param inUser
* {@link User} the user instance, might be evaluated to check
* the conditions
* @param inAuthorization
* {@link Authorization} the authorization instance, will be
* evaluate to check the conditions
* @param inParameters
* {@link ParameterObject} the generic parameter object with
* parameters that could be evaluated to check the conditions
* @param inControllerClass
* Class<? extends IPluggable> the active controller class
* @return {@link Component} the component that displays the rendered
* context menu
*/
public Component renderContextMenu(final String inMenuSetName,
final User inUser, final Authorization inAuthorization,
final ParameterObject inParameters,
final Class<? extends IPluggable> inControllerClass) {
final VerticalLayout outContextMenu = new VerticalLayout();
outContextMenu.setMargin(true);
outContextMenu.setStyleName("ripla-contextmenu"); //$NON-NLS-1$
final ContextMenuSet lContextMenuSet = contextMenus.get(inMenuSetName);
if (lContextMenuSet == null) {
return outContextMenu;
}
for (final ContextMenuItem lItem : lContextMenuSet
.getContextMenuItems()) {
if (lItem.checkConditions(inUser, inAuthorization, inParameters)) {
final Button lContextMenuLink = new Button(lItem.getCaption()); // NOPMD
lContextMenuLink.setStyleName(BaseTheme.BUTTON_LINK);
lContextMenuLink.addStyleName("ripla-contextmenu-item");
lContextMenuLink.setSizeUndefined();
final Class<? extends IPluggable> lControllerClass = lItem
.getControllerClass();
if (lControllerClass.equals(inControllerClass)) {
lContextMenuLink.addStyleName("active");
}
lContextMenuLink.addClickListener(new ContextMenuListener( // NOPMD
lControllerClass));
outContextMenu.addComponent(lContextMenuLink);
}
}
return outContextMenu;
}
// --- private classes ---
@SuppressWarnings("serial")
private static class ContextMenuListener implements ClickListener {
private final Class<? extends IPluggable> controllerClass;
ContextMenuListener(final Class<? extends IPluggable> inControllerClass) {
controllerClass = inControllerClass;
}
@Override
public void buttonClick(final ClickEvent inEvent) {
final Map<String, Object> lProperties = new HashMap<String, Object>();
lProperties
.put(Constants.EVENT_PROPERTY_NEXT_CONTROLLER,
UseCaseHelper
.createFullyQualifiedControllerName(controllerClass));
getDispatcher().dispatch(Event.LOAD_CONTROLLER, lProperties);
}
}
private static IRiplaEventDispatcher getDispatcher() {
try {
VaadinSession.getCurrent().getLockInstance().lock();
return VaadinSession.getCurrent().getAttribute(
IRiplaEventDispatcher.class);
} finally {
VaadinSession.getCurrent().getLockInstance().unlock();
}
}
private static class ContextMenuSet {
private final transient Collection<ContextMenuItem> items = new ArrayList<ContextMenuManager.ContextMenuItem>();
protected void addContextMenuItem(final ContextMenuItem inItem) {
items.add(inItem);
}
protected Collection<ContextMenuItem> getContextMenuItems() {
return items;
}
}
/**
* Wrapper class for context menu items provided by use case bundles.
*/
private static class ContextMenuItem {
private final transient IContextMenuItem contextMenuItem; // NOPMD
protected ContextMenuItem(final IContextMenuItem inContextMenuItem) {
contextMenuItem = inContextMenuItem;
}
protected String getCaption() {
return contextMenuItem.getTitleMsg();
}
public Class<? extends IPluggable> getControllerClass() {
return contextMenuItem.getControllerClass();
}
/**
* Check the conditions to display the context menu item.
*
* @param inUser
* {@link User} the user instance, might be evaluated to
* check the conditions
* @param inAuthorization
* {@link Authorization} the authorization instance, will be
* evaluate to check the conditions
* @param inParameters
* {@link ParameterObject} the generic parameter object with
* parameters that could be evaluated to check the conditions
* @return boolean <code>true</code> if the conditions allow to
* display/enable the context menu item, <code>false</code> if
* not
*/
protected boolean checkConditions(final User inUser,
final Authorization inAuthorization,
final ParameterObject inParameters) {
return contextMenuItem.checkConditions(inUser, inAuthorization,
inParameters);
}
}
}