/******************************************************************************* * Copyright (c) 2014, 2015 IBH SYSTEMS GmbH. * 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: * IBH SYSTEMS GmbH - initial API and implementation *******************************************************************************/ package org.eclipse.packagedrone.web.common.menu; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; import javax.servlet.http.HttpServletRequest; import org.eclipse.packagedrone.web.common.InterfaceExtender; import org.osgi.framework.FrameworkUtil; import org.osgi.util.tracker.ServiceTracker; public class MenuManagerImpl { private final ServiceTracker<InterfaceExtender, InterfaceExtender> tracker; public MenuManagerImpl () { this.tracker = new ServiceTracker<InterfaceExtender, InterfaceExtender> ( FrameworkUtil.getBundle ( MenuManagerImpl.class ).getBundleContext (), InterfaceExtender.class, null ); this.tracker.open (); } public void close () { this.tracker.close (); } public Menu getMainMenu ( final HttpServletRequest request ) { return getEntries ( ( i ) -> i.getMainMenuEntries ( request ) ); } public Menu getActions ( final HttpServletRequest request, final Object context ) { return getEntries ( ( i ) -> i.getActions ( request, context ) ); } public Menu getViews ( final HttpServletRequest request, final Object context ) { return getEntries ( ( i ) -> i.getViews ( request, context ) ); } protected Menu getEntries ( final Function<InterfaceExtender, List<MenuEntry>> func ) { final List<MenuEntry> result = new LinkedList<> (); for ( final InterfaceExtender me : this.tracker.getTracked ().values () ) { final List<MenuEntry> actions = func.apply ( me ); if ( actions != null ) { result.addAll ( actions ); } } return convert ( result ); } protected Menu convert ( List<MenuEntry> entries ) { if ( entries == null ) { return null; } entries = condenseCategories ( entries ); Collections.sort ( entries ); final List<Node> nodes = new LinkedList<> (); List<Node> currentNodes = nodes; String currentCategory = null; for ( final MenuEntry entry : entries ) { if ( entry.getCategory () == null ) { // main menu entry currentNodes = nodes; currentCategory = null; } else { // sub menu entry if ( currentCategory == null || !currentCategory.equals ( entry.getCategory () ) ) { // switch category currentNodes = new LinkedList<> (); currentCategory = entry.getCategory (); nodes.add ( new SubMenu ( UUID.randomUUID ().toString (), entry.getCategory (), currentNodes ) ); } else { // same category } } currentNodes.add ( convertEntry ( entry ) ); } return new Menu ( nodes ); } private List<MenuEntry> condenseCategories ( final List<MenuEntry> entries ) { final Map<String, Integer> map = new HashMap<> (); for ( final MenuEntry entry : entries ) { final String cat = entry.getCategory (); if ( cat == null ) { // entry has not category continue; } final Integer prio = map.get ( cat ); if ( prio == null && entry.getCategoryOrder () != Integer.MAX_VALUE ) { // we don't yet have a category and the cat order is not "unspecified" map.put ( cat, entry.getCategoryOrder () ); } else if ( prio != null && entry.getCategoryOrder () < prio ) { // overwrite with higher priority map.put ( cat, entry.getCategoryOrder () ); } } // we should have a map of categories priorities now final List<MenuEntry> result = new ArrayList<> ( entries.size () ); for ( final MenuEntry entry : entries ) { final String cat = entry.getCategory (); if ( cat == null ) { // no category, just copy result.add ( entry ); continue; } final Integer prio = map.get ( cat ); if ( prio == null ) { // no recorded priority, copy result.add ( entry ); // and record priority map.put ( cat, entry.getCategoryOrder () ); } else { // recorded priority, create new entry with recorded priority result.add ( new MenuEntry ( entry.getCategory (), prio, entry.getLabel (), entry.getEntryOrder (), entry.getTarget (), entry.getModifier (), entry.getIcon (), entry.isNewWindow (), entry.getBadge () ) ); } } return result; } private Entry convertEntry ( final MenuEntry entry ) { return new Entry ( UUID.randomUUID ().toString (), entry.getLabel (), entry.getTarget (), entry.getModifier (), entry.getIcon (), entry.isNewWindow (), entry.getBadge (), entry.getModal () ); } }