All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.ui.contextmenu.CmsContextMenuTreeBuilder Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.ui.contextmenu;

import org.opencms.main.CmsLog;
import org.opencms.ui.I_CmsDialogContext;
import org.opencms.ui.actions.CmsContextMenuActionItem;
import org.opencms.ui.actions.I_CmsDefaultAction;
import org.opencms.util.CmsTreeNode;
import org.opencms.workplace.explorer.menu.CmsMenuItemVisibilityMode;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Helper class for building context menus from the list of available context menu items.

*/ public class CmsContextMenuTreeBuilder { /** The logger instance for this class. */ private static final Log LOG = CmsLog.getLog(CmsContextMenuTreeBuilder.class); /** The dialog context. */ private I_CmsDialogContext m_context; /** The default action item. */ private I_CmsContextMenuItem m_defaultActionItem; /** Cached visibilities for context menu entries. */ private IdentityHashMap m_visiblities = new IdentityHashMap(); /** * Creates a new instance.

* * @param context the dialog context */ public CmsContextMenuTreeBuilder(I_CmsDialogContext context) { m_context = context; } /** * Builds the complete context menu from the given available items.

* * @param availableItems the available items * * @return the complete context menu */ public CmsTreeNode buildAll(List availableItems) { CmsTreeNode result = buildTree(availableItems); removeEmptySubtrees(result); return result; } /** * Builds a tree from a list of available context menu items.

* * The root node of the returned tree has no useful data, its child nodes correspond to the top-level * entries of the ccontext menu. * * @param items the available context menu items * @return the context menu item tree */ public CmsTreeNode buildTree(List items) { items = Lists.newArrayList(items); // First sort by priority and then use a map with the id as the key to store the items, // eliminating items with the same id but a lower priority than another item Collections.sort(items, new Comparator() { public int compare(I_CmsContextMenuItem a, I_CmsContextMenuItem b) { return Integer.compare(a.getPriority(), b.getPriority()); } }); LinkedHashMap itemsById = Maps.newLinkedHashMap(); for (I_CmsContextMenuItem item : items) { String id = item.getId(); I_CmsContextMenuItem prevItem = itemsById.get(id); if (prevItem != null) { LOG.info( "Discarding overridden context menu item " + prevItem + " because of higher priority item " + item); } itemsById.put(id, item); } // Now sort by order. Since all children of a node should be processed in one iteration of the following loop, // this order also applies to the child order of each tree node built in the next step List uniqueItems = Lists.newArrayList(itemsById.values()); uniqueItems = filterVisible(uniqueItems); if (m_context.getResources().size() == 1) { m_defaultActionItem = findDefaultAction(uniqueItems); } Collections.sort(uniqueItems, new Comparator() { public int compare(I_CmsContextMenuItem a, I_CmsContextMenuItem b) { return Float.compare(a.getOrder(), b.getOrder()); } }); Set processedIds = Sets.newHashSet(); boolean changed = true; Map> treesById = Maps.newHashMap(); // Create childless tree node for each item for (I_CmsContextMenuItem item : itemsById.values()) { CmsTreeNode node = new CmsTreeNode(); node.setData(item); treesById.put(item.getId(), node); } CmsTreeNode root = new CmsTreeNode(); // Use null as the root node, which does not have any useful data treesById.put(null, root); // Iterate through list multiple times, each time only processing those items whose parents // we have encountered in a previous iteration (actually, in the last iteration). We do this so that the resulting // tree is actually a tree and contains no cycles, even if there is a reference cycle between the context menu items via their parent ids. // (Items which form such a cycle will never be reached.) while (changed) { changed = false; Iterator iterator = uniqueItems.iterator(); Set currentLevel = Sets.newHashSet(); while (iterator.hasNext()) { I_CmsContextMenuItem currentItem = iterator.next(); String parentId = currentItem.getParentId(); if ((parentId == null) || processedIds.contains(parentId)) { changed = true; iterator.remove(); currentLevel.add(currentItem.getId()); treesById.get(parentId).addChild(treesById.get(currentItem.getId())); } } processedIds.addAll(currentLevel); } return root; } /** * Filters out invisible context menu items from a given list.

* * @param items the items * * @return the list of context menu items */ public List filterVisible(List items) { List result = Lists.newArrayList(); for (I_CmsContextMenuItem item : items) { CmsMenuItemVisibilityMode visibility = getVisibility(item); if (!visibility.isInVisible()) { result.add(item); } } return result; } /** * Returns the default action item if available.

* Only available once {@link #buildTree(List)} or {@link #buildAll(List)} has been executed.

* * @return the default action item */ public I_CmsContextMenuItem getDefaultActionItem() { return m_defaultActionItem; } /** * Gets the visibility for a given item (cached, if possible).

* * @param item the item * @return the visibility of that item */ public CmsMenuItemVisibilityMode getVisibility(I_CmsContextMenuItem item) { CmsMenuItemVisibilityMode result = m_visiblities.get(item); if (result == null) { result = item.getVisibility(m_context); m_visiblities.put(item, result); } return result; } /** * Recursively remove subtrees (destructively!) which do not contain any 'leaf' context menu items.

* * @param root the root of the tree to process */ public void removeEmptySubtrees(CmsTreeNode root) { List> children = root.getChildren(); if ((root.getData() != null) && root.getData().isLeafItem()) { children.clear(); } else { Iterator> iter = children.iterator(); while (iter.hasNext()) { CmsTreeNode node = iter.next(); removeEmptySubtrees(node); if ((node.getData() != null) && !node.getData().isLeafItem() && (node.getChildren().size() == 0)) { iter.remove(); } } } } /** * Evaluates the default action if any for highlighting within the menu.

* * @param items the menu items * * @return the default action if available */ private I_CmsContextMenuItem findDefaultAction(Collection items) { I_CmsContextMenuItem result = null; int resultRank = -1; for (I_CmsContextMenuItem menuItem : items) { if ((menuItem instanceof CmsContextMenuActionItem) && (((CmsContextMenuActionItem)menuItem).getWorkplaceAction() instanceof I_CmsDefaultAction)) { I_CmsDefaultAction action = (I_CmsDefaultAction)((CmsContextMenuActionItem)menuItem).getWorkplaceAction(); if (getVisibility(menuItem).isActive()) { if (result == null) { result = menuItem; resultRank = action.getDefaultActionRank(m_context); } else { int rank = action.getDefaultActionRank(m_context); if (rank > resultRank) { result = menuItem; resultRank = rank; } } } } } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy