/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.uberfire.client.workbench.widgets.menu; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; import org.jboss.errai.ioc.client.container.IOC; import org.jboss.errai.security.shared.api.identity.User; import org.uberfire.client.menu.AuthFilterMenuVisitor; import org.uberfire.client.mvp.Activity; import org.uberfire.client.mvp.ActivityManager; import org.uberfire.client.mvp.PerspectiveActivity; import org.uberfire.client.mvp.PerspectiveManager; import org.uberfire.client.mvp.PlaceManager; import org.uberfire.client.workbench.events.PerspectiveChange; import org.uberfire.client.workbench.events.PlaceMaximizedEvent; import org.uberfire.client.workbench.events.PlaceMinimizedEvent; import org.uberfire.mvp.Command; import org.uberfire.mvp.PlaceRequest; import org.uberfire.security.authz.AuthorizationManager; import org.uberfire.workbench.model.ActivityResourceType; import org.uberfire.workbench.model.menu.EnabledStateChangeListener; import org.uberfire.workbench.model.menu.MenuCustom; import org.uberfire.workbench.model.menu.MenuGroup; import org.uberfire.workbench.model.menu.MenuItem; import org.uberfire.workbench.model.menu.MenuItemCommand; import org.uberfire.workbench.model.menu.MenuItemPerspective; import org.uberfire.workbench.model.menu.MenuItemPlain; import org.uberfire.workbench.model.menu.MenuPosition; import org.uberfire.workbench.model.menu.Menus; import org.uberfire.workbench.model.menu.impl.BaseMenuVisitor; import static org.uberfire.plugin.PluginUtil.ensureIterable; /** * Presenter for WorkbenchMenuBar that mediates changes to the Workbench MenuBar * in response to changes to the selected WorkbenchPart. The menu structure is * cloned and items that lack permission are removed. This implementation is * specific to GWT. An alternative implementation should be considered for use * within Eclipse. */ public class WorkbenchMenuBarPresenter implements WorkbenchMenuBar { protected AuthorizationManager authzManager; protected User identity; private boolean useExpandedMode = true; private boolean expanded = true; private List<Menus> addedMenus; private PerspectiveManager perspectiveManager; private ActivityManager activityManager; private View view; WorkbenchMenuBarPresenter(final AuthorizationManager authzManager, final PerspectiveManager perspectiveManager, final ActivityManager activityManager, final User identity, final View view) { this.authzManager = authzManager; this.perspectiveManager = perspectiveManager; this.activityManager = activityManager; this.identity = identity; this.view = view; setup(); } protected void setup() { view.addExpandHandler(new Command() { @Override public void execute() { expanded = true; } }); view.addCollapseHandler(new Command() { @Override public void execute() { expanded = false; } }); } public IsWidget getView() { return this.view; } @Override public void addMenus(final Menus menus) { if (menus != null && !menus.getItems().isEmpty()) { if (addedMenus == null) { addedMenus = new ArrayList<Menus>(); } addedMenus.add(menus); if (menusMustBeReordered(menus)) { reorderMenus(); view.clear(); for (Menus currentMenus : addedMenus) { visitMenus(currentMenus); } } else { visitMenus(menus); } } } private boolean menusMustBeReordered(final Menus menus) { if (addedMenus.size() < 2) { return false; } final Menus previousMenus = addedMenus.get(addedMenus.size() - 2); return previousMenus.getOrder() > menus.getOrder(); } private void reorderMenus() { Collections.sort(addedMenus, new Comparator<Menus>() { @Override public int compare(final Menus o1, final Menus o2) { return o1.getOrder() - o2.getOrder(); } }); } private void visitMenus(final Menus addedMenu) { addedMenu.accept(new AuthFilterMenuVisitor(authzManager, identity, new BaseMenuVisitor() { private String parentId = null; @Override public boolean visitEnter(final MenuGroup menuGroup) { parentId = getMenuItemId(menuGroup); view.addGroupMenuItem(parentId, menuGroup.getCaption(), menuGroup.getPosition()); return true; } @Override public void visitLeave(MenuGroup menuGroup) { parentId = null; } @Override public void visit(final MenuItemPlain menuItemPlain) { view.addMenuItem(getMenuItemId(menuItemPlain), menuItemPlain.getCaption(), parentId, null, menuItemPlain.getPosition()); setupEnableDisableMenuItem(menuItemPlain); } @Override public void visit(final MenuCustom<?> menuCustom) { final Object build = menuCustom.build(); if (build instanceof IsWidget) { view.addCustomMenuItem(((IsWidget) build).asWidget(), menuCustom.getPosition()); } else { view.addMenuItem(getMenuItemId(menuCustom), menuCustom.getCaption(), parentId, null, menuCustom.getPosition()); } setupEnableDisableMenuItem(menuCustom); } @Override public void visit(final MenuItemCommand menuItemCommand) { view.addMenuItem(getMenuItemId(menuItemCommand), menuItemCommand.getCaption(), parentId, menuItemCommand.getCommand(), menuItemCommand.getPosition()); setupEnableDisableMenuItem(menuItemCommand); } @Override public void visit(final MenuItemPerspective menuItemPerspective) { final String id = menuItemPerspective.getPlaceRequest().getIdentifier(); view.addMenuItem(id, menuItemPerspective.getCaption(), parentId, new Command() { @Override public void execute() { IOC.getBeanManager().lookupBean(PlaceManager.class).getInstance().goTo(menuItemPerspective.getPlaceRequest()); } }, menuItemPerspective.getPosition()); setupEnableDisableMenuItem(menuItemPerspective); final PlaceRequest placeRequest = menuItemPerspective.getPlaceRequest(); if (perspectiveManager.getCurrentPerspective() != null && placeRequest.equals(perspectiveManager.getCurrentPerspective().getPlace())) { view.selectMenuItem(id); } } private void setupEnableDisableMenuItem(final MenuItem menuItem) { menuItem.addEnabledStateChangeListener(new EnabledStateChangeListener() { @Override public void enabledStateChanged(final boolean enabled) { view.enableMenuItem(getMenuItemId(menuItem), enabled); } }); } })); synchronizeUIWithMenus(addedMenu.getItems()); } private String getMenuItemId(final MenuItem menuItem) { return menuItem.getIdentifier() == null ? menuItem.getCaption() : menuItem.getIdentifier(); } protected void addPerspectiveMenus(final PerspectiveActivity perspective) { final String perspectiveId = perspective.getIdentifier(); final Menus menus = perspective.getMenus(); view.clearContextMenu(); if (menus != null) { menus.accept(new AuthFilterMenuVisitor(authzManager, identity, new BaseMenuVisitor() { private String parentId = null; @Override public boolean visitEnter(final MenuGroup menuGroup) { parentId = getMenuItemId(menuGroup); view.addContextGroupMenuItem(perspectiveId, parentId, menuGroup.getCaption(), menuGroup.getPosition()); return true; } @Override public void visitLeave(MenuGroup menuGroup) { parentId = null; } @Override public void visit(final MenuItemPlain menuItemPlain) { view.addContextMenuItem(perspectiveId, getMenuItemId(menuItemPlain), menuItemPlain.getCaption(), parentId, null, menuItemPlain.getPosition()); setupEnableDisableContextMenuItem(menuItemPlain); } @Override public void visit(final MenuCustom<?> menuCustom) { view.addContextMenuItem(perspectiveId, getMenuItemId(menuCustom), menuCustom.getCaption(), parentId, null, menuCustom.getPosition()); setupEnableDisableContextMenuItem(menuCustom); } @Override public void visit(final MenuItemCommand menuItemCommand) { view.addContextMenuItem(perspectiveId, getMenuItemId(menuItemCommand), menuItemCommand.getCaption(), parentId, menuItemCommand.getCommand(), menuItemCommand.getPosition()); setupEnableDisableContextMenuItem(menuItemCommand); } @Override public void visit(final MenuItemPerspective menuItemPerspective) { view.addContextMenuItem(perspectiveId, menuItemPerspective.getPlaceRequest().getIdentifier(), menuItemPerspective.getCaption(), parentId, new Command() { @Override public void execute() { IOC.getBeanManager().lookupBean(PlaceManager.class).getInstance().goTo(menuItemPerspective.getPlaceRequest()); } }, menuItemPerspective.getPosition()); setupEnableDisableContextMenuItem(menuItemPerspective); } private void setupEnableDisableContextMenuItem(final MenuItem menuItem) { menuItem.addEnabledStateChangeListener(new EnabledStateChangeListener() { @Override public void enabledStateChanged(final boolean enabled) { view.enableContextMenuItem(getMenuItemId(menuItem), enabled); } }); } })); synchronizeUIWithMenus(menus.getItems()); } } protected void onPerspectiveChange(final PerspectiveChange perspectiveChange) { final Activity activity = activityManager.getActivity(perspectiveChange.getPlaceRequest()); if (activity != null && activity.isType(ActivityResourceType.PERSPECTIVE.name())) { addPerspectiveMenus((PerspectiveActivity) activity); } view.selectMenuItem(perspectiveChange.getPlaceRequest().getIdentifier()); } protected void onPlaceMinimized(final PlaceMinimizedEvent event) { if (isUseExpandedMode()) { view.expand(); } } protected void onPlaceMaximized(final PlaceMaximizedEvent event) { view.collapse(); } @Override public void clear() { view.clear(); } @Override public void expand() { useExpandedMode = true; view.expand(); } @Override public boolean isUseExpandedMode() { return useExpandedMode; } @Override public boolean isExpanded() { return expanded; } @Override public void collapse() { useExpandedMode = false; view.collapse(); } @Override public void addCollapseHandler(final Command command) { view.addCollapseHandler(command); } @Override public void addExpandHandler(final Command command) { view.addExpandHandler(command); } List<Menus> getAddedMenus() { return this.addedMenus; } //Force UI to update to state of MenuItems. Should be called after MenuItems are configured with EnabledStateChangeListener's. void synchronizeUIWithMenus(final List<MenuItem> menuItems) { for (MenuItem menuItem : ensureIterable(menuItems)) { if (menuItem instanceof MenuGroup) { synchronizeUIWithMenus(((MenuGroup) menuItem).getItems()); } else { menuItem.setEnabled(menuItem.isEnabled()); } } } public interface View extends IsWidget { void clear(); void addMenuItem(String id, String label, String parentId, Command command, MenuPosition position); void addCustomMenuItem(Widget menu, MenuPosition position); void addGroupMenuItem(String id, String label, MenuPosition position); void selectMenuItem(String id); void addContextMenuItem(String menuItemId, String id, String label, String parentId, Command command, MenuPosition position); void addContextGroupMenuItem(String menuItemId, String id, String label, MenuPosition position); void clearContextMenu(); void expand(); void collapse(); void addCollapseHandler(Command command); void addExpandHandler(Command command); void enableMenuItem(String menuItemId, boolean enabled); void enableContextMenuItem(String menuItemId, boolean enabled); } }