/*******************************************************************************
* Copyright (c) 2006-2013 The RCP Company 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:
* The RCP Company - initial API and implementation
*******************************************************************************/
package com.rcpcompany.uibindings.internal.utils;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.commands.CommandEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.ICommandListener;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.CommandException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.commands.ICommandImageService;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.services.IServiceLocator;
import com.rcpcompany.uibindings.IDisposable;
import com.rcpcompany.uibindings.IManager;
import com.rcpcompany.uibindings.IViewerBinding;
import com.rcpcompany.uibindings.internal.Activator;
import com.rcpcompany.uibindings.utils.IViewerToolBar;
import com.rcpcompany.utils.logging.LogUtils;
/**
* Implementation of {@link IViewerToolBar}.
*
* @author Tonny Madsen, The RCP Company
*/
public class ViewerToolBar implements IViewerToolBar, IDisposable {
/**
* The viewer of this toolbar.
*/
private final IViewerBinding myViewer;
/**
* The style of this toolbar.
*/
private final int myStyle;
public ViewerToolBar(IViewerBinding viewer, int style) {
myViewer = viewer;
myStyle = style;
final Control control = myViewer.getControl();
final Composite parent = control.getParent();
// TODO: Check style
myViewer.registerService(this);
final IManager manager = IManager.Factory.getManager();
FormToolkit toolkit = myViewer.getContext().getService(FormToolkit.class);
if (toolkit == null) {
toolkit = manager.getFormToolkit(parent);
}
final IServiceLocator serviceLocator = getViewer().getContext().getServiceLocator();
myCommandService = (ICommandService) serviceLocator.getService(ICommandService.class);
myHandlerService = (IHandlerService) serviceLocator.getService(IHandlerService.class);
myCommandImageService = (ICommandImageService) serviceLocator.getService(ICommandImageService.class);
/*
* Find the control of the viewer (a Table or Tree).
*
* Find the parent Composite.
*
* Add a new Composite (with a GridLayout) and reparent the control
*
* Then add the toolbar itself on the correct side of the control
*/
myComposite = toolkit.createComposite(parent);
myComposite.setLayoutData(control.getLayoutData());
final GridLayout compLayout = new GridLayout(1, false);
myComposite.setLayout(compLayout);
control.setParent(myComposite);
control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
myToolBar = new ToolBar(myComposite, SWT.FLAT | (style & (VERTICAL | HORIZONTAL)));
if ((style & VERTICAL) != 0) {
myToolBar.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false));
compLayout.numColumns = 2;
} else {
myToolBar.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false));
}
/*
* Inlined from FormToolkit.adapt(Composite composite). Do not set focus though.
*/
myToolBar.setBackground(myComposite.getBackground());
myToolBar.setMenu(myComposite.getMenu());
myViewer.registerWidget(myToolBar);
/*
* Add standard items
*/
if ((style & ADD) != 0) {
// TODO addItem(ADD, "");
}
if ((style & DELETE) != 0) {
addItem(DELETE, IManager.Factory.getManager().getCommandIDs().get(IWorkbenchCommandConstants.EDIT_DELETE));
}
if ((style & UP) != 0) {
addItem(UP, "com.rcpcompany.uibindings.commands.moveItemUp");
}
if ((style & DOWN) != 0) {
addItem(DOWN, "com.rcpcompany.uibindings.commands.moveItemDown");
}
myComposite.layout(true);
}
@Override
public void dispose() {
myViewer.unregisterService(this);
if (myToolBar != null && !myToolBar.isDisposed()) {
myViewer.unregisterWidget(myToolBar);
myToolBar.dispose();
}
}
public static IViewerToolBar addToolBar(IViewerBinding viewer, int style) {
IViewerToolBar bb = viewer.getService(IViewerToolBar.class);
if (bb != null) return bb;
bb = new ViewerToolBar(viewer, style);
return bb;
}
private static Image getImage(String path) {
final ImageRegistry imageRegistry = Activator.getDefault().getImageRegistry();
if (imageRegistry.getDescriptor(path) == null) {
imageRegistry.put(path, AbstractUIPlugin.imageDescriptorFromPlugin(Activator.ID, path));
}
return imageRegistry.get(path);
}
private final Composite myComposite;
private final ToolBar myToolBar;
@Override
public IViewerBinding getViewer() {
return myViewer;
}
@Override
public int getStyle() {
return myStyle;
}
@Override
public ToolBar getToolBar() {
return myToolBar;
}
private final Map<Integer, ToolItem> myItems = new HashMap<Integer, ToolItem>();
private final ICommandService myCommandService;
private final IHandlerService myHandlerService;
private final ICommandImageService myCommandImageService;
@Override
public void addItem(int id, String command) {
try {
final CommandToolItemAdapter a = new CommandToolItemAdapter(command);
addItem(id, a.getItem());
} catch (final CommandException ex) {
// Ignore
}
}
/**
* Mapping of keys to images... An image can be <code>null</code>.
*/
private static final Map<String, Image> TOOLBAR_IMAGES = new HashMap<String, Image>();
/**
* Returns the mapping of keys to images... An image can be <code>null</code>.
*
* @return the map
*/
private Map<String, Image> getToolBarImages() {
return TOOLBAR_IMAGES;
}
/**
* An adapter for IParameterizedCommand to {@link ToolItem}.
*/
private class CommandToolItemAdapter implements Listener, ICommandListener {
private final String myCommandId;
private final ToolItem myItem;
private ParameterizedCommand myCommand = null;
/**
* The {@link ToolBar} item for this adapter.
*
* @return the item
*/
public ToolItem getItem() {
return myItem;
}
private CommandToolItemAdapter(String commandId) throws CommandException {
myCommandId = commandId;
myItem = new ToolItem(getToolBar(), SWT.PUSH);
myCommand = myCommandService.deserialize(commandId);
myCommand.getCommand().addCommandListener(this);
myItem.setImage(getImage(ICommandImageService.TYPE_DEFAULT));
myItem.setDisabledImage(getImage(ICommandImageService.TYPE_DISABLED));
myItem.setHotImage(getImage(ICommandImageService.TYPE_HOVER));
commandChanged(null);
myItem.addListener(SWT.Dispose, this);
myItem.addListener(SWT.Selection, this);
}
private void dispose() {
myCommand.getCommand().removeCommandListener(this);
}
@Override
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Selection:
try {
myHandlerService.executeCommand(myCommand, event);
} catch (final ExecutionException ex) {
LogUtils.error(this, ex);
} catch (final NotDefinedException ex) {
LogUtils.error(this, ex);
} catch (final NotEnabledException ex) {
LogUtils.error(this, ex);
} catch (final NotHandledException ex) {
LogUtils.error(this, ex);
}
break;
case SWT.Dispose:
dispose();
break;
default:
break;
}
}
/**
* Returns the specified type of image.
* <p>
* All images are registered in the image registry of the {@link Activator}.
*
* @param type either {@link ICommandImageService#TYPE_DEFAULT} or
* {@link ICommandImageService#TYPE_DISABLED}
* @return the image
*/
private Image getImage(int type) {
String key = myCommandId;
switch (type) {
case ICommandImageService.TYPE_DEFAULT:
key += "-default";
break;
case ICommandImageService.TYPE_DISABLED:
key += "-disabled";
break;
case ICommandImageService.TYPE_HOVER:
key += "-hover";
break;
default:
LogUtils.error(this, "Unknown type: " + type);
break;
}
if (getToolBarImages().containsKey(key)) return getToolBarImages().get(key);
final ImageDescriptor id = myCommandImageService.getImageDescriptor(myCommandId, type,
ICommandImageService.IMAGE_STYLE_TOOLBAR);
if (id == null) {
getToolBarImages().put(key, null);
return null;
}
final ImageRegistry imageRegistry = Activator.getDefault().getImageRegistry();
imageRegistry.put(key, id);
final Image image = imageRegistry.get(key);
TOOLBAR_IMAGES.put(key, image);
return image;
}
@Override
public void commandChanged(CommandEvent commandEvent) {
myItem.setEnabled(myCommand.getCommand().isEnabled());
try {
myItem.setToolTipText(myCommand.getCommand().getDescription());
} catch (final NotDefinedException ex) {
LogUtils.error(this, ex);
}
}
}
@Override
public void addItem(int id, ToolItem item) {
if (item.getParent() != myToolBar) {
LogUtils.error(this, "Item does nopt have the correct toolbar as parent. Disposed.");
item.dispose();
return;
}
if (myItems.containsKey(id)) {
LogUtils.error(this, "item ID " + id + " already used. Item Disposed.");
item.dispose();
return;
}
myItems.put(id, item);
}
@Override
public ToolItem getItem(int id) {
return myItems.get(id);
}
}