/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.navigation.ui.swt.views;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.osgi.service.log.LogService;
import org.eclipse.equinox.log.Logger;
import org.eclipse.jface.action.ContributionManager;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.ICoolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.ISourceProvider;
import org.eclipse.ui.ISourceProviderListener;
import org.eclipse.ui.PlatformUI;
import org.eclipse.riena.core.Log4r;
import org.eclipse.riena.core.util.StringUtils;
import org.eclipse.riena.core.wire.Wire;
import org.eclipse.riena.internal.core.Activator;
import org.eclipse.riena.internal.core.StartupsSafeRunnable;
import org.eclipse.riena.internal.ui.ridgets.swt.AbstractItemRidget;
import org.eclipse.riena.internal.ui.ridgets.swt.IContributionExtension.ICommandExtension;
import org.eclipse.riena.internal.ui.ridgets.swt.ToolItemScalingHelper;
import org.eclipse.riena.internal.ui.swt.facades.WorkbenchFacade;
import org.eclipse.riena.navigation.ui.swt.component.MenuCoolBarComposite;
import org.eclipse.riena.ui.ridgets.IActionRidget;
import org.eclipse.riena.ui.ridgets.IRidget;
import org.eclipse.riena.ui.ridgets.controller.IController;
import org.eclipse.riena.ui.ridgets.swt.uibinding.SwtControlRidgetMapper;
import org.eclipse.riena.ui.ridgets.uibinding.DefaultBindingManager;
import org.eclipse.riena.ui.ridgets.uibinding.IBindingManager;
import org.eclipse.riena.ui.ridgets.uibinding.IBindingPropertyLocator;
import org.eclipse.riena.ui.ridgets.uibinding.IControlRidgetMapper;
import org.eclipse.riena.ui.swt.utils.SWTBindingPropertyLocator;
import org.eclipse.riena.ui.swt.utils.SwtUtilities;
/**
* @since 5.0
*
*/
public class RienaMenuHelper {
private static IBindingManager menuItemBindingManager;
private static int itemId = 0;
private final static Logger LOGGER = Log4r.getLogger(Activator.getDefault(), StartupsSafeRunnable.class);
private final List<Object> uiControls;
/**
* Creates a new instance of this helper class and creates binding manager.
*/
public RienaMenuHelper() {
uiControls = new ArrayList<Object>();
if (menuItemBindingManager == null) {
menuItemBindingManager = createMenuItemBindingManager(SWTBindingPropertyLocator.getInstance(), SwtControlRidgetMapper.getInstance());
}
Wire.instance(this).andStart();
}
private IBindingManager createMenuItemBindingManager(final IBindingPropertyLocator propertyStrategy, final IControlRidgetMapper<Object> mapper) {
return new DefaultBindingManager(propertyStrategy, mapper);
}
/**
* Creates Ridgets for the menu items and the cool bar items and binds the Ridgets of the items with the UI widgets.
*
* @param controller
* the controller for all the ridgets of the menu and the tool bar.
*/
public void bindMenuAndToolItems(final IController controller, final Composite menuParent, final Composite toolbarParent) {
createItemRidgets(controller, menuParent, toolbarParent);
menuItemBindingManager.bind(controller, getUIControls());
}
/**
* Unbinds uiControls from their ridgets.
*
* @param controller
* the controller for all the ridgets of the menu and the tool bar.
*/
public void unbind(final IController controller) {
menuItemBindingManager.unbind(controller, getUIControls());
}
private final List<ICommandExtension> items = new ArrayList<ICommandExtension>();
/**
* Creates for every menu item and tool item a ridget and adds
*
* @param controller
*/
private void createItemRidgets(final IController controller, final Composite menuParent, final Composite toolbarParent) {
final List<IRidget> ridgetsToRemove = new ArrayList<IRidget>();
final Collection<? extends IRidget> ridgets = controller.getRidgets();
for (final IRidget ridget : ridgets) {
if (ridget instanceof AbstractItemRidget) {
ridgetsToRemove.add(ridget);
}
}
ridgets.removeAll(ridgetsToRemove);
// items of Riena "menu bar"
final List<MenuCoolBarComposite> menuCoolBarComposites = getMenuCoolBarComposites(menuParent);
for (final MenuCoolBarComposite menuBarComp : menuCoolBarComposites) {
createRidgetsForItems(menuBarComp.getTopLevelItems(), controller);
}
//update toolbar
if (PlatformUI.isWorkbenchRunning()) {
try {
final ICoolBarManager coolBarManager2 = ((ApplicationWindow) PlatformUI.getWorkbench().getActiveWorkbenchWindow()).getCoolBarManager2();
if (coolBarManager2.getItems().length > 0) {
final ContributionManager toolbarManager2 = (ContributionManager) ((IToolBarContributionItem) coolBarManager2.getItems()[0])
.getToolBarManager();
toolbarManager2.update(true);
}
} catch (final Exception e) {
LOGGER.log(LogService.LOG_WARNING, "the toolbar could not be updated:" + e.getLocalizedMessage() + "\n"); //$NON-NLS-1$
for (final StackTraceElement element : e.getStackTrace()) {
LOGGER.log(LogService.LOG_WARNING, element.toString());
}
}
}
// create Separator for Toolbaritems
final ToolItemScalingHelper toolBarScalingHelper = new ToolItemScalingHelper();
if (toolBarScalingHelper.needScaleBasedSpacing()) {
final List<CoolBar> coolBars = getCoolBars(toolbarParent);
for (final CoolBar coolBar : coolBars) {
final List<ToolBar> toolBars = getToolBars(coolBar);
for (final ToolBar toolBar : toolBars) {
toolBarScalingHelper.createSeparatorContributionsForToolBars(toolBars);
}
}
}
// items of cool bar
final List<ToolItem> toolItems = getAllToolItems(toolbarParent);
for (final ToolItem toolItem : toolItems) {
createRidget(controller, toolItem);
}
}
/**
* Returns the composites that contains the menu bar of the sub-application.
*
* @param composite
* @return composite with menu bar
*/
public List<MenuCoolBarComposite> getMenuCoolBarComposites(final Composite composite) {
final List<MenuCoolBarComposite> composites = new ArrayList<MenuCoolBarComposite>();
if (SwtUtilities.isDisposed(composite)) {
return composites;
}
if (composite instanceof MenuCoolBarComposite) {
composites.add((MenuCoolBarComposite) composite);
}
final Control[] children = composite.getChildren();
for (final Control child : children) {
if (child instanceof Composite) {
composites.addAll(getMenuCoolBarComposites((Composite) child));
}
}
return composites;
}
private void createRidgetsForItems(final List<ToolItem> toolItems, final IController controller) {
for (final ToolItem toolItem : toolItems) {
if (!SWTBindingPropertyLocator.getInstance().hasBindingProperty(toolItem)) {
createRidget(controller, toolItem);
}
if (toolItem.getData() instanceof MenuManager) {
final MenuManager manager = (MenuManager) toolItem.getData();
createRidget(controller, manager.getMenu());
}
}
}
/**
* Creates for the given item a ridget and adds it to the given controller.
*
* @param controller
* @param item
*/
private void createRidget(final IController controller, final Item item) {
if (item.isDisposed()) {
return;
}
if (isSeparator(item)) {
// no ridget for separator
// and
// no ridget for tool items with control
// (both tool items has the style SWT.SEPARATOR)
return;
}
String id;
if (item instanceof MenuItem) {
id = getItemId((MenuItem) item);
} else {
id = getItemId((ToolItem) item);
}
if (StringUtils.isEmpty(id)) {
return;
}
final IRidget ridget = menuItemBindingManager.createRidget(item);
SWTBindingPropertyLocator.getInstance().setBindingProperty(item, id);
getUIControls().add(item);
controller.addRidget(id, ridget);
if (item instanceof MenuItem) {
final MenuItem menuItem = (MenuItem) item;
createRidget(controller, menuItem.getMenu());
}
}
private void createRidget(final IController controller, final Menu menu) {
if (menu == null) {
return;
}
final MenuItem[] items = menu.getItems();
for (final MenuItem item : items) {
createRidget(controller, item);
}
}
private boolean isSeparator(final Item item) {
return (item.getStyle() & SWT.SEPARATOR) == SWT.SEPARATOR;
}
/**
* Returns all items of all cool bars.
*
* @return list of tool items
*/
private List<ToolItem> getAllToolItems(final Composite parentComposite) {
final List<ToolItem> items = new ArrayList<ToolItem>();
final List<CoolBar> coolBars = getCoolBars(parentComposite);
for (final CoolBar coolBar : coolBars) {
final List<ToolBar> toolBars = getToolBars(coolBar);
for (final ToolBar toolBar : toolBars) {
items.addAll(Arrays.asList(toolBar.getItems()));
}
}
final List<ToolBar> toolBars = getToolBars(parentComposite);
for (final ToolBar toolBar : toolBars) {
items.addAll(Arrays.asList(toolBar.getItems()));
}
return items;
}
/**
* Returns all cool bars below the given composite (except cool bar of menu).
*
* @param composite
* @return list of cool bars
*/
private List<CoolBar> getCoolBars(final Composite composite) {
final List<CoolBar> coolBars = new ArrayList<CoolBar>();
if (composite == null) {
return coolBars;
}
final Control[] children = composite.getChildren();
for (final Control child : children) {
if (child instanceof CoolBar) {
if (getParentOfType(child, MenuCoolBarComposite.class) == null) {
coolBars.add((CoolBar) child);
}
continue;
}
if (child instanceof Composite) {
coolBars.addAll(getCoolBars((Composite) child));
}
}
return coolBars;
}
/**
* Returns all tool bars of the given cool bar.
*
* @param parentComposite
* cool bar
* @return list of tool bars
*/
private List<ToolBar> getToolBars(final Composite parentComposite) {
final List<ToolBar> toolBars = new ArrayList<ToolBar>();
if (parentComposite == null) {
return toolBars;
}
final Control[] children = parentComposite.getChildren();
for (final Control child : children) {
if (child instanceof ToolBar) {
if (getParentOfType(child, MenuCoolBarComposite.class) == null) {
toolBars.add((ToolBar) child);
}
}
}
return toolBars;
}
private Composite getParentOfType(final Control control, final Class<? extends Control> clazz) {
final Composite parent = control.getParent();
if (parent == null) {
return null;
}
if (clazz.isAssignableFrom(parent.getClass())) {
return parent;
}
return getParentOfType(parent, clazz);
}
/**
* Returns the identifier of this contribution item.
*
* @param item
* @return identifier, or {@code null} if none
*/
private String getItemId(final Item item, final String prefix) {
String id = null;
if (item.getData() instanceof IContributionItem) {
final IContributionItem contributionItem = (IContributionItem) item.getData();
id = contributionItem.getId();
}
if (StringUtils.isEmpty(id)) {
id = SWTBindingPropertyLocator.getInstance().locateBindingProperty(item);
}
if (StringUtils.isEmpty(id)) {
id = Integer.toString(++itemId);
} else {
if (!id.startsWith(prefix)) {
id = prefix + id;
}
}
return id;
}
/**
* Returns the identifier of the given menu item.
*
* @param item
* menu item
* @return identifier, or {@code null} if none
*/
private String getItemId(final MenuItem item) {
return getItemId(item, IActionRidget.BASE_ID_MENUACTION);
}
/**
* Returns the identifier of the given tool item.
*
* @param item
* tool item
* @return identifier, or {@code null} if none
*/
private String getItemId(final ToolItem item) {
return getItemId(item, IActionRidget.BASE_ID_TOOLBARACTION);
}
private List<Object> getUIControls() {
return uiControls;
}
/**
* Adds the given listener to every service provider.
*
* @param listener
* The listener to add; must not be <code>null</code>.
*/
public void addSourceProviderListener(final ISourceProviderListener listener) {
final ISourceProvider[] sourceProviders = getSourceProviders();
for (final ISourceProvider sourceProvider : sourceProviders) {
sourceProvider.addSourceProviderListener(listener);
}
}
/**
* Removes the given listener from every service provider.
*
* @param listener
* The listener to remove; must not be <code>null</code>.
*/
public void removeSourceProviderListener(final ISourceProviderListener listener) {
final ISourceProvider[] sourceProviders = getSourceProviders();
for (final ISourceProvider sourceProvider : sourceProviders) {
sourceProvider.removeSourceProviderListener(listener);
}
}
public ISourceProvider[] getSourceProviders() {
return WorkbenchFacade.getInstance().getSourceProviders();
}
}