/******************************************************************************* * 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.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.osgi.framework.FrameworkUtil; import org.osgi.service.useradmin.Authorization; import org.ripla.interfaces.IMenuCommand; import org.ripla.interfaces.IMenuExtendible; import org.ripla.interfaces.IMenuItem; import org.ripla.services.IExtendibleMenuContribution; import org.ripla.util.ExtendibleMenuMarker; import org.ripla.util.ExtendibleMenuMarker.Position; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.server.Resource; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; /** * Menu factory for an extendible menu. * * @author Luthiger */ public final class ExtendibleMenuFactory extends MenuFactory { private static final Logger LOG = LoggerFactory .getLogger(ExtendibleMenuFactory.class); private final transient IMenuExtendible menu; private final transient List<IExtMenuItem> contributions = new ArrayList<ExtendibleMenuFactory.IExtMenuItem>(); /** * Constructor * * @param inMenu * {@link IVIFMenuExtendible} the extendible menu to process * @param inContributions * Collection of {@link IExtendibleMenuContribution}s the set of * contributions to the extendible menu */ public ExtendibleMenuFactory(final IMenuExtendible inMenu, final Collection<IExtendibleMenuContribution> inContributions) { super(inMenu); menu = inMenu; initializePositions(inMenu.getMarkers(), getSorted(inContributions)); } private Collection<IExtendibleMenuContribution> getSorted( final Collection<IExtendibleMenuContribution> inContributions) { // distribute all contributions to their positions final Map<ExtendibleMenuMarker.Position, List<IExtendibleMenuContribution>> helper = new HashMap<ExtendibleMenuMarker.Position, List<IExtendibleMenuContribution>>( 7); for (final IExtendibleMenuContribution lContribution : inContributions) { final Position lPosition = lContribution.getPosition(); List<IExtendibleMenuContribution> lPositionList = helper .get(lPosition); if (lPositionList == null) { lPositionList = new ArrayList<IExtendibleMenuContribution>(); // NOPMD helper.put(lPosition, lPositionList); } lPositionList.add(lContribution); } // sort each position's list final List<IExtendibleMenuContribution> out = new ArrayList<IExtendibleMenuContribution>( inContributions.size()); for (final Entry<Position, List<IExtendibleMenuContribution>> lPositionSet : helper .entrySet()) { switch (lPositionSet.getKey().getType()) { // NOPMD case APPEND: out.addAll(getWithSort(lPositionSet.getValue(), true)); break; case INSERT_BEFORE: out.addAll(getWithSort(lPositionSet.getValue(), true)); break; case INSERT_AFTER: out.addAll(getWithSort(lPositionSet.getValue(), false)); break; default: out.addAll(getWithSort(lPositionSet.getValue(), true)); } } return out; } private List<IExtendibleMenuContribution> getWithSort( final List<IExtendibleMenuContribution> inToSort, final boolean inAscending) { Collections.sort(inToSort, new ContributionComparator(inAscending)); return inToSort; } private void initializePositions(final ExtendibleMenuMarker[] inMarkers, final Collection<IExtendibleMenuContribution> inContributions) { for (final ExtendibleMenuMarker lMarker : inMarkers) { contributions.add(new MarkerItem(lMarker.getMarkerID())); // NOPMD } for (final IExtendibleMenuContribution lContribution : inContributions) { final ExtendibleMenuMarker.Position lPosition = lContribution .getPosition(); switch (lPosition.getType()) { // NOPMD case INSERT_BEFORE: insert(lPosition.getMarkerID(), lContribution, 0); break; case INSERT_AFTER: insert(lPosition.getMarkerID(), lContribution, 1); break; case APPEND: default: // append appendTo(lPosition.getMarkerID(), lContribution); } } } private void insert(final String inMarkerID, final IExtendibleMenuContribution inContribution, final int inInsertOffset) { final IExtMenuItem lItem = find(inMarkerID); if (lItem == null) { LOG.error("Can't find ID {}!", inMarkerID); //$NON-NLS-1$ throw new IllegalArgumentException("Can't find ID " + inMarkerID); //$NON-NLS-1$ } final int lIndex = contributions.indexOf(lItem); if (lIndex >= 0) { contributions.add(lIndex + inInsertOffset, new ContributionAdapter( inContribution)); } } private IExtMenuItem find(final String inMarkerID) { for (final IExtMenuItem lItem : contributions) { final String lItemID = lItem.getMarkerID(); if (lItemID.equalsIgnoreCase(inMarkerID)) { return lItem; } } return null; } private void appendTo(final String inMarkerID, final IExtendibleMenuContribution inContribution) { int i; // NOPMD final Iterator<IExtMenuItem> lItems = contributions.iterator(); for (i = 0; lItems.hasNext(); i++) { final IExtMenuItem lItem = lItems.next(); if (lItem.isMarker()) { final String lID = lItem.getMarkerID(); if (lID.equalsIgnoreCase(inMarkerID)) { i++; for (; lItems.hasNext(); i++) { final IExtMenuItem lNextItem = lItems.next(); if (lNextItem.isMarker()) { // NOPMD by Luthiger break; } } contributions.add(i - 1, new ContributionAdapter( // NOPMD inContribution)); return; } } } } @Override public MenuItem createMenu(final MenuBar inMenuBar, final Resource inSubMenuIcon, final Map<Integer, IMenuCommand> inMap, final Command inCommand, final Authorization inAuthorization, final String inMenuTagFilter) { if (!checkPermissions(menu.getPermission(), inAuthorization)) { return null; } if (!MenuFilter.checkTagFilter(inMenuTagFilter, menu.getTag())) { return null; } final MenuItem outItem = inMenuBar.addItem(menu.getLabel(), null, inCommand); outItem.setIcon(inSubMenuIcon); boolean lFirst = true; for (final IExtMenuItem lItem : contributions) { if (lItem.isMarker()) { continue; } final IExtendibleMenuContribution lContribution = lItem .getContribution(); // check the permission the item needs to be displayed if (!checkPermissions(lContribution.getPermission(), inAuthorization)) { continue; } final MenuItem lMenuItem = outItem.addItem( lContribution.getLabel(), null, inCommand); addCommand(inMap, lMenuItem, createMenuCommand(lContribution.getControllerName())); if (lFirst) { // clicking the menu has the same effect as clicking the first // sub menu item addCommand(inMap, outItem, createMenuCommand(lContribution.getControllerName())); lFirst = false; } // process sub menu final List<IMenuItem> lSubMenu = lContribution.getSubMenu(); if (!lSubMenu.isEmpty()) { createSubMenu(lSubMenu, lMenuItem, inMap, inCommand, inAuthorization); } } return outItem; } @Override public String getProviderSymbolicName() { final IExtMenuItem lItem = contributions.get(0); if (lItem == null || lItem.getContribution() == null) { return null; } return FrameworkUtil.getBundle(lItem.getContribution().getClass()) .getSymbolicName(); } // --- inner classes --- private static class ContributionComparator implements Comparator<IExtendibleMenuContribution> { private final transient int ascending; protected ContributionComparator(final boolean inAscending) { ascending = inAscending ? 1 : -1; } @Override public int compare(final IExtendibleMenuContribution inContribution1, final IExtendibleMenuContribution inContribution2) { return ascending * inContribution1.getLabel().compareTo( inContribution2.getLabel()); } } private interface IExtMenuItem { boolean isMarker(); String getMarkerID(); IExtendibleMenuContribution getContribution(); } private static class MarkerItem implements IExtMenuItem { private final transient String markerID; public MarkerItem(final String inMarkerID) { markerID = inMarkerID; } @Override public boolean isMarker() { return true; } @Override public String getMarkerID() { return markerID; } @Override public IExtendibleMenuContribution getContribution() { return null; } } private static class ContributionAdapter implements IExtMenuItem { private final transient IExtendibleMenuContribution contribution; public ContributionAdapter( final IExtendibleMenuContribution inContribution) { contribution = inContribution; } @Override public boolean isMarker() { return false; } @Override public String getMarkerID() { return ""; //$NON-NLS-1$ } @Override public IExtendibleMenuContribution getContribution() { return contribution; } } }