blob: 6d3827fd4c6151d795561e8a9ef4c6a53421fc6e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.action;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.accessibility.AccessibleListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
/**
* A tool bar manager is a contribution manager which realizes itself and its
* items in a tool bar control.
* <p>
* This class may be instantiated; it may also be subclassed if a more
* sophisticated layout is required.
* </p>
*/
public class ToolBarManager extends ContributionManager implements
IToolBarManager {
/**
* The tool bar items style; <code>SWT.NONE</code> by default.
*/
private int itemStyle = SWT.NONE;
/**
* The tool bat control; <code>null</code> before creation and after
* disposal.
*/
private ToolBar toolBar = null;
/**
* The menu manager to the context menu associated with the toolbar.
*
* @since 3.0
*/
private MenuManager contextMenuManager = null;
/**
* Creates a new tool bar manager with the default SWT button style. Use the
* <code>createControl</code> method to create the tool bar control.
*/
public ToolBarManager() {
//Do nothing if there are no parameters
}
/**
* Creates a tool bar manager with the given SWT button style. Use the
* <code>createControl</code> method to create the tool bar control.
*
* @param style
* the tool bar item style
* @see org.eclipse.swt.widgets.ToolBar for valid style bits
*/
public ToolBarManager(int style) {
itemStyle = style;
}
/**
* Creates a tool bar manager for an existing tool bar control. This manager
* becomes responsible for the control, and will dispose of it when the
* manager is disposed.
*
* @param toolbar
* the tool bar control
*/
public ToolBarManager(ToolBar toolbar) {
this();
this.toolBar = toolbar;
}
/**
* Creates and returns this manager's tool bar control. Does not create a
* new control if one already exists.
*
* @param parent
* the parent control
* @return the tool bar control
*/
public ToolBar createControl(Composite parent) {
if (!toolBarExist() && parent != null) {
toolBar = new ToolBar(parent, itemStyle);
toolBar.setMenu(getContextMenuControl());
update(false);
toolBar.getAccessible().addAccessibleListener(getAccessibleListener());
}
return toolBar;
}
/**
* Get the accessible listener for the tool bar.
*
* @return AccessibleListener
*
* @since 3.1
*/
private AccessibleListener getAccessibleListener() {
return new AccessibleAdapter() {
public void getName(AccessibleEvent e) {
if (e.childID != ACC.CHILDID_SELF) {
ToolItem item = toolBar.getItem(e.childID);
if (item != null) {
String toolTip = item.getToolTipText();
if (toolTip != null) {
e.result = toolTip;
}
}
}
}
};
}
/**
* Disposes of this tool bar manager and frees all allocated SWT resources.
* Notifies all contribution items of the dispose. Note that this method
* does not clean up references between this tool bar manager and its
* associated contribution items. Use <code>removeAll</code> for that
* purpose.
*/
public void dispose() {
if (toolBarExist()) {
toolBar.dispose();
}
toolBar = null;
IContributionItem[] items = getItems();
for (int i = 0; i < items.length; i++) {
items[i].dispose();
}
if (getContextMenuManager() != null) {
getContextMenuManager().dispose();
setContextMenuManager(null);
}
}
/**
* Returns the tool bar control for this manager.
*
* @return the tool bar control, or <code>null</code> if none (before
* creating or after disposal)
*/
public ToolBar getControl() {
return toolBar;
}
/**
* Re-lays out the tool bar.
* <p>
* The default implementation of this framework method re-lays out the
* parent when the number of items crosses the zero threshold. Subclasses
* should override this method to implement their own re-layout strategy
*
* @param layoutBar
* the tool bar control
* @param oldCount
* the old number of items
* @param newCount
* the new number of items
*/
protected void relayout(ToolBar layoutBar, int oldCount, int newCount) {
if ((oldCount == 0) != (newCount == 0))
layoutBar.getParent().layout();
}
/**
* Returns whether the tool bar control is created and not disposed.
*
* @return <code>true</code> if the control is created and not disposed,
* <code>false</code> otherwise
*/
private boolean toolBarExist() {
return toolBar != null && !toolBar.isDisposed();
}
/*
* (non-Javadoc) Method declared on IContributionManager.
*/
public void update(boolean force) {
// long startTime= 0;
// if (DEBUG) {
// dumpStatistics();
// startTime= (new Date()).getTime();
// }
if (isDirty() || force) {
if (toolBarExist()) {
int oldCount = toolBar.getItemCount();
// clean contains all active items without double separators
IContributionItem[] items = getItems();
ArrayList clean = new ArrayList(items.length);
IContributionItem separator = null;
// long cleanStartTime= 0;
// if (DEBUG) {
// cleanStartTime= (new Date()).getTime();
// }
for (int i = 0; i < items.length; ++i) {
IContributionItem ci = items[i];
if (!ci.isVisible())
continue;
if (ci.isSeparator()) {
// delay creation until necessary
// (handles both adjacent separators, and separator at
// end)
separator = ci;
} else {
if (separator != null) {
if (clean.size() > 0) // no separator if first item
clean.add(separator);
separator = null;
}
clean.add(ci);
}
}
// if (DEBUG) {
// System.out.println(" Time needed to build clean vector: " +
// ((new Date()).getTime() - cleanStartTime));
// }
// determine obsolete items (removed or non active)
ToolItem[] mi = toolBar.getItems();
ArrayList toRemove = new ArrayList(mi.length);
for (int i = 0; i < mi.length; i++) {
Object data = mi[i].getData();
if (data == null
|| !clean.contains(data)
|| (data instanceof IContributionItem && ((IContributionItem) data)
.isDynamic())) {
toRemove.add(mi[i]);
}
}
// Turn redraw off if the number of items to be added
// is above a certain threshold, to minimize flicker,
// otherwise the toolbar can be seen to redraw after each item.
// Do this before any modifications are made.
// We assume each contribution item will contribute at least one
// toolbar item.
boolean useRedraw = (clean.size() - (mi.length - toRemove
.size())) >= 3;
try {
if (useRedraw) {
toolBar.setRedraw(false);
}
// remove obsolete items
for (int i = toRemove.size(); --i >= 0;) {
ToolItem item = (ToolItem) toRemove.get(i);
if (!item.isDisposed()) {
Control ctrl = item.getControl();
if (ctrl != null) {
item.setControl(null);
ctrl.dispose();
}
item.dispose();
}
}
// add new items
IContributionItem src, dest;
mi = toolBar.getItems();
int srcIx = 0;
int destIx = 0;
for (Iterator e = clean.iterator(); e.hasNext();) {
src = (IContributionItem) e.next();
// get corresponding item in SWT widget
if (srcIx < mi.length)
dest = (IContributionItem) mi[srcIx].getData();
else
dest = null;
if (dest != null && src.equals(dest)) {
srcIx++;
destIx++;
continue;
}
if (dest != null && dest.isSeparator()
&& src.isSeparator()) {
mi[srcIx].setData(src);
srcIx++;
destIx++;
continue;
}
int start = toolBar.getItemCount();
src.fill(toolBar, destIx);
int newItems = toolBar.getItemCount() - start;
for (int i = 0; i < newItems; i++) {
ToolItem item = toolBar.getItem(destIx++);
item.setData(src);
}
}
// remove any old tool items not accounted for
for (int i = mi.length; --i >= srcIx;) {
ToolItem item = mi[i];
if (!item.isDisposed()) {
Control ctrl = item.getControl();
if (ctrl != null) {
item.setControl(null);
ctrl.dispose();
}
item.dispose();
}
}
setDirty(false);
// turn redraw back on if we turned it off above
} finally {
if (useRedraw) {
toolBar.setRedraw(true);
}
}
int newCount = toolBar.getItemCount();
relayout(toolBar, oldCount, newCount);
}
}
// if (DEBUG) {
// System.out.println(" Time needed for update: " + ((new
// Date()).getTime() - startTime));
// System.out.println();
// }
}
/**
* Returns the control of the Menu Manager. If the menu manager does not
* have a control then one is created.
*
* @return menu widget associated with manager
*/
private Menu getContextMenuControl() {
if ((contextMenuManager != null) && (toolBar != null)) {
Menu menuWidget = contextMenuManager.getMenu();
if ((menuWidget == null) || (menuWidget.isDisposed())) {
menuWidget = contextMenuManager.createContextMenu(toolBar);
}
return menuWidget;
}
return null;
}
/**
* Returns the context menu manager for this tool bar manager.
*
* @return the context menu manager, or <code>null</code> if none
* @since 3.0
*/
public MenuManager getContextMenuManager() {
return contextMenuManager;
}
/**
* Sets the context menu manager for this tool bar manager to the given menu
* manager. If the tool bar control exists, it also adds the menu control to
* the tool bar.
*
* @param contextMenuManager
* the context menu manager, or <code>null</code> if none
* @since 3.0
*/
public void setContextMenuManager(MenuManager contextMenuManager) {
this.contextMenuManager = contextMenuManager;
if (toolBar != null) {
toolBar.setMenu(getContextMenuControl());
}
}
}