org.eclipse.jface.action.ToolBarManager Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Andrey Loskutov - Bug 457211
* Lars Vogel - Bug 457214
* Rolf Theunissen - Bug 90757
*******************************************************************************/
package org.eclipse.jface.action;
import java.util.ArrayList;
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.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
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.
*
* This class may be instantiated; it may also be subclassed if a more
* sophisticated layout is required.
*
*/
public class ToolBarManager extends ContributionManager implements IToolBarManager {
/**
* The tool bar items style; SWT.NONE
by default.
*/
private int itemStyle = SWT.NONE;
/**
* The tool bar control; null
before creation and after
* disposal.
*/
private ToolBar toolBar;
/**
* The menu manager to the context menu associated with the toolbar.
*
* @since 3.0
*/
private MenuManager contextMenuManager;
/**
* Creates a new tool bar manager with the default SWT button style. Use the
* {@link #createControl(Composite)} 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
* createControl
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. NOTE When creating a ToolBarManager
* from an existing {@link ToolBar} you will not get the accessible listener
* provided by JFace.
*
* @see #ToolBarManager()
* @see #ToolBarManager(int)
*
* @param toolbar
* the tool bar control
*/
public ToolBarManager(ToolBar toolbar) {
this();
this.toolBar = toolbar;
if (toolBarExist()) {
this.itemStyle = toolBar.getStyle();
}
}
/**
* Sets SWT button style for new tool bar controls created
* in the {@code createControl(Composite)} method. It does not
* affect already existing tool bar control.
*
* @param style
* the tool bar item style
* @since 3.10
*/
public void setStyle(int style) {
itemStyle = style;
}
/**
* Creates and returns this manager's tool bar control. Does not create
* a new control if one already exists and is not disposed.
* Also create an {@link AccessibleListener} for the {@link ToolBar}.
*
* @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(true);
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() {
@Override
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 removeAll
for that
* purpose.
*/
public void dispose() {
if (toolBarExist()) {
toolBar.dispose();
}
toolBar = null;
IContributionItem[] items = getItems();
for (IContributionItem item : items) {
item.dispose();
}
if (getContextMenuManager() != null) {
getContextMenuManager().dispose();
setContextMenuManager(null);
}
super.setOverrides(null);
}
/**
* Returns the tool bar control for this manager.
*
* @return the tool bar control, or null
if none (before
* creating or after disposal)
*/
public ToolBar getControl() {
return toolBar;
}
/**
* Re-lays out the tool bar.
*
* The default implementation of this framework method re-lays out the
* parent when the number of items are different and the new count != 0
*
* @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 != newCount && newCount != 0) {
Composite parent = layoutBar.getParent();
try {
parent.setRedraw(false);
Point beforePack = layoutBar.getSize();
layoutBar.pack(true);
Point afterPack = layoutBar.getSize();
// If the TB didn't change size then we're done
if (beforePack.equals(afterPack)) {
return;
}
// OK, we need to re-layout the TB
parent.pack();
parent.requestLayout();
// Now, if we're in a CoolBar then change the CoolItem size as well
if (parent instanceof CoolBar) {
CoolBar cb = (CoolBar) layoutBar.getParent();
CoolItem[] items = cb.getItems();
for (CoolItem item : items) {
if (item.getControl() == layoutBar) {
Point curSize = item.getSize();
item.setSize(curSize.x + (afterPack.x - beforePack.x),
curSize.y + (afterPack.y - beforePack.y));
return;
}
}
}
} finally {
parent.setRedraw(true);
}
}
}
/**
* Returns whether the tool bar control is created and not disposed.
*
* @return true
if the control is created and not disposed,
* false
otherwise
*/
private boolean toolBarExist() {
return toolBar != null && !toolBar.isDisposed();
}
@Override
public void update(boolean force) {
if (!isDirty() && !force) {
return;
}
if (!toolBarExist()) {
return;
}
int oldCount = toolBar.getItemCount();
// clean contains all active items without double separators
IContributionItem[] items = getItems();
ArrayList clean = new ArrayList<>(items.length);
IContributionItem separator = null;
for (IContributionItem ci : items) {
if (!isChildVisible(ci)) {
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) {
clean.add(separator);
}
separator = null;
}
clean.add(ci);
}
}
// determine obsolete items (removed or non active)
ToolItem[] mi = toolBar.getItems();
ArrayList toRemove = new ArrayList<>(mi.length);
for (ToolItem item : mi) {
// there may be null items in a toolbar
if (item == null) {
continue;
}
Object data = item.getData();
if (data == null || !clean.contains(data)
|| (data instanceof IContributionItem && ((IContributionItem) data).isDynamic())) {
toRemove.add(item);
}
}
try {
toolBar.setRedraw(false);
// remove obsolete items
for (int i = toRemove.size(); --i >= 0;) {
ToolItem item = toRemove.get(i);
if (!item.isDisposed()) {
Control ctrl = item.getControl();
if (ctrl != null) {
item.setControl(null);
ctrl.dispose();
}
item.dispose();
}
}
// add new items
IContributionItem dest;
mi = toolBar.getItems();
int srcIx = 0;
int destIx = 0;
for (IContributionItem src : clean) {
// 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++;
if (force) {
dest.update();
}
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 {
toolBar.setRedraw(true);
}
int newCount = toolBar.getItemCount();
// If we're forcing a change then ensure that we re-layout
// everything
if (force) {
oldCount = newCount + 1;
}
relayout(toolBar, oldCount, newCount);
}
/**
* 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 null
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 null
if none
* @since 3.0
*/
public void setContextMenuManager(MenuManager contextMenuManager) {
this.contextMenuManager = contextMenuManager;
if (toolBar != null) {
toolBar.setMenu(getContextMenuControl());
}
}
/**
* Computes real item visibility considering possibly overridden state from
* manager
*/
private boolean isChildVisible(IContributionItem item) {
IContributionManagerOverrides overrides = getOverrides();
if(overrides == null) {
return item.isVisible();
}
Boolean v = overrides.getVisible(item);
return v != null ? v.booleanValue() : item.isVisible();
}
}