/******************************************************************************* * 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.controllers; // NOPMD by Luthiger on 09.09.12 00:48 import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; import org.ripla.exceptions.NoControllerFoundException; import org.ripla.interfaces.IMenuCommand; import org.ripla.util.ParameterObject; import org.ripla.web.Constants; import org.ripla.web.RiplaApplication; import org.ripla.web.interfaces.IBodyComponent; import org.ripla.web.interfaces.IPluggable; import org.ripla.web.interfaces.IToolbarAction; import org.ripla.web.interfaces.IToolbarActionListener; import org.ripla.web.interfaces.IToolbarItemCreator; import org.ripla.web.internal.menu.MenuFactory; import org.ripla.web.internal.services.ToolbarItemRegistry; import org.ripla.web.internal.services.UseCaseRegistry; import org.ripla.web.internal.views.DefaultRiplaView; import org.ripla.web.services.ISkin; import org.ripla.web.services.IToolbarItem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.server.Page; import com.vaadin.server.Resource; import com.vaadin.server.VaadinSession; import com.vaadin.shared.ui.MarginInfo; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.Alignment; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.VerticalLayout; /** * <p> * The application's body component consisting of the toolbar, the menubar, the * sidebar panel and the main content panel. * </p> * <p> * Subclasses may override the following methods: * <ul> * <li><code>RiplaBody.{@link #initializeLayout()}</code></li> * <li><code>RiplaBody.{@link #createToolbar()}</code></li> * <li><code>RiplaBody.{@link #createParametersForContextMenu()}</code></li> * <li><code>RiplaBody.{@link #setContextMenu(String)}</code></li> * <li><code>RiplaBody.{@link #afterMenuClick()}</code></li> * <li><code>RiplaBody.{@link #showDefault()}</code></li> * <li><code>RiplaBody.{@link #getDftMenuBarLayout()}</code></li> * </ul> * </p> * * @author Luthiger */ @SuppressWarnings("serial") public class RiplaBody extends CustomComponent implements IBodyComponent { // NOPMD public static final Logger LOG = LoggerFactory.getLogger(RiplaBody.class); private Map<Integer, IMenuCommand> menuMap; private final VerticalLayout layout; private VerticalLayout sidebar; private VerticalLayout content; private final ISkin skin; private final RiplaApplication application; private final String menuTagFilter; private MenuBar menuBar; /** * Protected constructor. * * @param inSkin * {@link ISkin} * @param inApplication * {@link RiplaApplication} * @param inMenuTagFilter */ protected RiplaBody(final ISkin inSkin, final RiplaApplication inApplication, final String inMenuTagFilter) { super(); skin = inSkin; application = inApplication; menuTagFilter = inMenuTagFilter; setSizeFull(); layout = new VerticalLayout(); setCompositionRoot(layout); layout.setStyleName("ripla-body"); layout.setSizeFull(); layout.removeAllComponents(); } /** * Factory method to create an initialized instance of {@link RiplaBody}. * * @param inSkin * {@link ISkin} * @param inApplication * {@link RiplaApplication} * @param inMenuTagFilter * String a filter expression for the application's menu, e.g. * <code>demo.*</code>. * @return {@link RiplaBody} */ public static RiplaBody createInstance(final ISkin inSkin, final RiplaApplication inApplication, final String inMenuTagFilter) { final RiplaBody outBody = new RiplaBody(inSkin, inApplication, inMenuTagFilter); outBody.initializeLayout(); return outBody; } /** * Arranges the body window's views (i.e. <code>header</code>, * <code>footer</code>, <code>toolbar</code>, <code>menubar</code>, * <code>sidebar</code>, <code>content</code>).<br /> * Subclasses may override for a different arrangement of the views. */ protected void initializeLayout() { Page.getCurrent().setTitle(application.getAppName()); if (skin.hasHeader()) { final Component lHeader = skin.getHeader(application.getAppName()); layout.addComponent(lHeader); layout.setExpandRatio(lHeader, 0); } if (skin.hasToolBar()) { final Component lToolbar = createToolbar(skin.getToolbarSeparator()); layout.addComponent(lToolbar); } if (skin.hasMenuBar()) { final Component lMenubar = createMenubar(skin.getMenuBarMedium(), skin.getMenuBar(), skin.getSubMenuIcon()); layout.addComponent(lMenubar); } final HorizontalSplitPanel lPanel = new HorizontalSplitPanel(); layout.addComponent(lPanel); layout.setExpandRatio(lPanel, 1); lPanel.setSplitPosition(10, Unit.PERCENTAGE); // lPanel.setHeight(SIZE_UNDEFINED, Unit.PIXELS); lPanel.setStyleName("ripla-split"); //$NON-NLS-1$ sidebar = new VerticalLayout(); sidebar.setStyleName("ripla-sidebar"); sidebar.setSizeFull(); lPanel.setFirstComponent(sidebar); content = new VerticalLayout(); content.setStyleName("ripla-content"); lPanel.setSecondComponent(content); content.setMargin(true); lPanel.setSizeFull(); layout.setSizeFull(); } protected final UserAdmin getUserAdmin() { return UseCaseRegistry.INSTANCE.getUserAdmin(); } protected final Layout getSidebar() { return sidebar; } private Component createMenubar(final HorizontalLayout inMenuBarMedium, final HorizontalLayout inMenuBarLayout, final Resource inSubMenuIcon) { final HorizontalLayout outComponent = inMenuBarMedium == null ? getDftMenuBarLayout() : inMenuBarMedium; menuBar = new MenuBar(); menuBar.setAutoOpen(true); menuBar.setStyleName("ripla-menu"); //$NON-NLS-1$ createMenu(menuBar, inSubMenuIcon); if (inMenuBarLayout == null) { outComponent.addComponent(menuBar); } else { inMenuBarLayout.removeAllComponents(); inMenuBarLayout.addComponent(menuBar); } return outComponent; } /** * Returns the default menu bar's layout component.<br /> * Subclasses may override. * * @return {@link HorizontalLayout} the default layout for the menu bar. */ protected HorizontalLayout getDftMenuBarLayout() { final HorizontalLayout outLayout = new HorizontalLayout(); outLayout.setStyleName("ripla-menubar"); //$NON-NLS-1$ outLayout.setMargin(new MarginInfo(false, false, false, true)); outLayout.setWidth("100%"); //$NON-NLS-1$ outLayout.setHeight(32, Unit.PIXELS); return outLayout; } private void createMenu(final MenuBar inMenuBar, final Resource inSubMenuIcon) { final MenuBar.Command lCommand = new MenuBar.Command() { @Override public void menuSelected(final MenuItem inSelected) { final IMenuCommand lAction = getMenuMap().get(inSelected.getId()); afterMenuClick(); if (lAction != null) { try { setContentView(getContentComponent(lAction.getControllerName())); } catch (final NoControllerFoundException exc) { handleNoTaskFound(exc); } } } }; final Authorization lAuthorization = UseCaseRegistry.INSTANCE.getUserAdmin().getAuthorization(getUser()); final Map<String, MenuItem> lMenuMap = new HashMap<String, MenuBar.MenuItem>(); for (final MenuFactory lFactory : UseCaseRegistry.INSTANCE.getMenus()) { final MenuItem lItem = lFactory.createMenu(inMenuBar, inSubMenuIcon, getMenuMap(), lCommand, lAuthorization, menuTagFilter); final String lProviderName = lFactory.getProviderSymbolicName(); if (lProviderName != null) { lMenuMap.put(lFactory.getProviderSymbolicName(), lItem); } } // we set the menu map to the session to access it later to mark the // active menu try { VaadinSession.getCurrent().getLockInstance().lock(); VaadinSession.getCurrent().setAttribute(Constants.SA_MENU_MAP, lMenuMap); } finally { VaadinSession.getCurrent().getLockInstance().unlock(); } LOG.debug("Menu created for Ripla."); //$NON-NLS-1$ } /** * Hook for subclasses to provide functionality to be processed after the * user clicked a menu item. * <p> * Subclasses may override. * </p> */ protected void afterMenuClick() { // do nothing } private void handleNoTaskFound(final NoControllerFoundException inExc) { LOG.error("Configuration error:", inExc); //$NON-NLS-1$ setContentView(new DefaultRiplaView(inExc)); } private Map<Integer, IMenuCommand> getMenuMap() { if (menuMap == null) { menuMap = new HashMap<Integer, IMenuCommand>(); } return menuMap; } protected Component createToolbar(final Label inSeparator) { final HorizontalLayout outToolbar = new HorizontalLayout(); outToolbar.setStyleName("ripla-toolbar"); //$NON-NLS-1$ outToolbar.setWidth("100%"); //$NON-NLS-1$ outToolbar.setSpacing(true); outToolbar.setMargin(new MarginInfo(false, true, false, true)); outToolbar.setHeight(22, Unit.PIXELS); final Label lExpand = new Label(" ", ContentMode.HTML); lExpand.setWidth("100%"); outToolbar.addComponent(lExpand); outToolbar.setExpandRatio(lExpand, 1); final Iterator<IToolbarItem> lItems = ToolbarItemRegistry.INSTANCE.getSortedItems().iterator(); boolean lFirst = true; while (lItems.hasNext()) { final IToolbarItem lItem = lItems.next(); final IToolbarItemCreator lFactory = lItem.getCreator(); final Component lComponent = lFactory == null ? lItem.getComponent() : lFactory.createToolbarItem(application, getUser()); if (lComponent == null) { continue; } if (!lFirst) { final Label lSeparator = getSeparator(inSeparator); outToolbar.addComponent(lSeparator); outToolbar.setComponentAlignment(lSeparator, Alignment.MIDDLE_CENTER); } lFirst = false; outToolbar.addComponent(lComponent); outToolbar.setComponentAlignment(lComponent, Alignment.MIDDLE_CENTER); lItem.registerToolbarActionListener(new IToolbarActionListener() { // NOPMD @Override public void processAction(final IToolbarAction inAction) { inAction.run(); } }); } return outToolbar; } private User getUser() { try { VaadinSession.getCurrent().getLockInstance().lock(); return VaadinSession.getCurrent().getAttribute(User.class); } finally { VaadinSession.getCurrent().getLockInstance().unlock(); } } /** * We have to clone the separator label defined in the skin. * * @param inSeparator * Label * @return {@link Label} the cloned label */ private Label getSeparator(final Label inSeparator) { final Label out = new Label(inSeparator.getValue().toString(), inSeparator.getContentMode()); out.setWidth(inSeparator.getWidth(), inSeparator.getWidthUnits()); out.setStyleName(inSeparator.getStyleName()); return out; } @Override public Component getContentComponent(final String inControllerName) throws NoControllerFoundException { return UseCaseRegistry.INSTANCE.getControllerManager().getContent(inControllerName); } @Override public void setContentView(final Component inComponent) { content.removeAllComponents(); content.addComponent(inComponent); } /** * Loads the context menu with the specified set name into the sidebar (i.e. * conext menu) panel. * <p> * This implementation first removes all displayed menu items from the * sidebar. Then it renders the context menu with the specified set name and * passes a parameter object created by * {@link #createParametersForContextMenu()} and adds the rendered component * to the cleaned sidebar panel. * </p> */ @Override public void setContextMenu(final String inMenuSetName, final Class<? extends IPluggable> inControllerClass) { getSidebar().removeAllComponents(); final User lUser = getUser(); getSidebar().addComponent(UseCaseRegistry.INSTANCE.getContextMenuManager().renderContextMenu(inMenuSetName, lUser, getUserAdmin().getAuthorization(lUser), createParametersForContextMenu(), inControllerClass)); } /** * Returns the parameter object to pass context parameters that can be * evaluated to decide whether a context menu item should be displayed or * hidden.<br /> * By default, an empty parameter object is created.<br /> * Subclasses may override. * * @return {@link ParameterObject} */ protected ParameterObject createParametersForContextMenu() { return new ParameterObject(); } @Override public final void refreshBody() { layout.removeAllComponents(); initializeLayout(); showDefault(); } @Override public void showDefault() { final List<MenuItem> lMenuItems = menuBar.getItems(); if (!lMenuItems.isEmpty()) { final MenuItem lMenuItem = lMenuItems.get(0); lMenuItem.getCommand().menuSelected(lMenuItem); } } @Override public final void close() { application.close(); } }