/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.color;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.ExternalActionManager;
import org.eclipse.jface.action.ExternalActionManager.IBindingManagerCallback;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionManagerOverrides;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.bindings.Trigger;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.IKeyLookup;
import org.eclipse.jface.bindings.keys.KeyLookupFactory;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
/**
* @author Frank Shaka
*/
public class ColorPicker extends ContributionItem implements ISelectionProvider {
private final class ColorChooserPopupDialog extends PopupDialog {
private Rectangle aroundBounds = null;
private PaletteViewer viewer;
private boolean showingNativeColorDialog = false;
public ColorChooserPopupDialog(Shell parent) {
super(parent, SWT.NO_TRIM, true, false, false, false, false, null,
null);
}
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
GridLayoutFactory layout = GridLayoutFactory.fillDefaults()
.spacing(0, 0);
GridDataFactory layoutData = GridDataFactory.fillDefaults().grab(
true, false);
layout.copy().margins(4, 4).applyTo(composite);
if (viewer == null) {
viewer = new PaletteViewer() {
protected RGB openNativeColorDialog(Shell shell,
RGB oldColor) {
showingNativeColorDialog = true;
try {
return super.openNativeColorDialog(shell, oldColor);
} finally {
showingNativeColorDialog = false;
}
}
};
viewer.setShowAutoItem(hasPopupStyle(AUTO));
viewer.setShowNoneItem(hasPopupStyle(NONE));
viewer.setShowCustomItem(hasPopupStyle(CUSTOM));
viewer.addSelectionChangedListener(viewerSelectionChangedListener);
viewer.addOpenListener(viewerOpenListener);
}
viewer.createControl(composite);
layoutData.applyTo(viewer.getControl());
viewer.setAutoColor(autoColor);
viewer.setInput(palette);
selectionChangedDuringUpdate = true;
viewer.setSelection(selection);
selectionChangedDuringUpdate = false;
return composite;
}
public int open(Rectangle aroundBounds) {
this.aroundBounds = aroundBounds;
return super.open();
}
public int open(Point location) {
if (location != null) {
this.aroundBounds = new Rectangle(location.x, location.y, 1, 1);
}
return super.open();
}
private Point calcLocation(Rectangle aroundBounds, Point shellSize) {
Point loc = new Point(aroundBounds.x, aroundBounds.y);
Rectangle area = getShell().getDisplay().getClientArea();
if (aroundBounds.x + shellSize.x > area.x + area.width) {
loc.x = aroundBounds.x + aroundBounds.width - shellSize.x;
}
if (aroundBounds.y + aroundBounds.height + shellSize.y > area.y
+ area.height) {
loc.y = aroundBounds.y - shellSize.y;
} else {
loc.y = aroundBounds.y + aroundBounds.height;
}
return loc;
}
protected Point getInitialLocation(Point initialSize) {
if (aroundBounds != null) {
return calcLocation(aroundBounds, initialSize);
}
return super.getInitialLocation(initialSize);
}
public boolean close() {
Shell parentShell = null;
if (getShell() != null && !getShell().isDisposed()
&& getShell().getParent() instanceof Shell) {
parentShell = (Shell) getShell().getParent();
}
if (showingNativeColorDialog)
return false;
boolean closed = super.close();
this.aroundBounds = null;
if (action != null) {
action.setChecked(false);
}
// if (viewer != null) {
// viewer
// .removeSelectionChangedListener(viewerSelectionChangedListener);
// viewer.removeOpenListener(viewerOpenListener);
// }
if (parentShell != null && !parentShell.isDisposed()) {
Shell activeShell = Display.getCurrent().getActiveShell();
if (parentShell.getData() instanceof PopupDialog
&& parentShell != activeShell) {
((PopupDialog) parentShell.getData()).close();
}
}
return closed;
}
@Override
protected Color getBackground() {
return Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
}
}
private final class DropDownAction extends ColorAction {
private DropDownAction(String text) {
super(null, IAction.AS_CHECK_BOX);
setText(text);
}
public void run() {
super.run();
open();
}
}
/**
* Popup style for normal palette contents.
*/
public static final int NORMAL = 0;
/**
* Popup style for palette contents with 'Automatic' selection.
*/
public static final int AUTO = 1;
/**
* Popup style for palette contents with 'None' selection.
*/
public static final int NONE = 1 << 1;
/**
* Popup style for palette contents with 'Custom' selection.
*/
public static final int CUSTOM = 1 << 2;
/**
* Mode bit: Show text on tool items, even if an image is present. If this
* mode bit is not set, text is only shown on tool items if there is no
* image present.
*
* @since 3.0
*/
public static int MODE_FORCE_TEXT = 1;
private static boolean USE_COLOR_ICONS = true;
/**
* Returns whether color icons should be used in toolbars.
*
* @return <code>true</code> if color icons should be used in toolbars,
* <code>false</code> otherwise
*/
public static boolean getUseColorIconsInToolbars() {
return USE_COLOR_ICONS;
}
/**
* Sets whether color icons should be used in toolbars.
*
* @param useColorIcons
* <code>true</code> if color icons should be used in toolbars,
* <code>false</code> otherwise
*/
public static void setUseColorIconsInToolbars(boolean useColorIcons) {
USE_COLOR_ICONS = useColorIcons;
}
/**
* The presentation mode.
*/
private int mode = 0;
private Widget widget;
private IAction action;
private int popupStyle;
private PaletteContents palette;
private ColorChooserPopupDialog popup;
private IColorSelection selection;
private RGB autoColor;
/**
* Listener for SWT tool item widget events.
*/
private Listener toolItemListener;
/**
* Listener for SWT menu item widget events.
*/
private Listener menuItemListener;
/**
* Remembers all images in use by this contribution item
*/
private LocalResourceManager imageManager;
/**
* Listener for action property change notifications.
*/
private final IPropertyChangeListener propertyListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
actionPropertyChange(event);
}
};
/**
* The listener for changes to the text of the action contributed by an
* external source.
*/
private final IPropertyChangeListener actionTextListener = new IPropertyChangeListener() {
/**
* @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
update(event.getProperty());
}
};
private List<ISelectionChangedListener> selectionChangedListeners = null;
private List<IOpenListener> openListeners = null;
private final ISelectionChangedListener viewerSelectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (selectionChangedDuringUpdate)
return;
if (popup != null)
popup.close();
setSelection(event.getSelection());
}
};
private final IOpenListener viewerOpenListener = new IOpenListener() {
public void open(OpenEvent event) {
if (popup != null)
popup.close();
fireOpenEvent(event);
}
};
private boolean selectionChangedDuringUpdate = false;
public ColorPicker(PaletteContents palette) {
this(NORMAL, palette, null, null, null);
}
public ColorPicker(int popupStyle, PaletteContents palette) {
this(popupStyle, palette, null, null, null);
}
public ColorPicker(int popupStyle, PaletteContents palette, String text) {
this(popupStyle, palette, text, null, null);
}
public ColorPicker(int popupStyle, PaletteContents palette, String text,
ImageDescriptor image) {
this(popupStyle, palette, text, image, null);
}
public ColorPicker(int popupStyle, PaletteContents palette, String text,
ImageDescriptor image, String id) {
super(id);
if (image != null) {
this.action = new Action(text, image) {
public void run() {
super.run();
open();
}
};
} else {
this.action = new DropDownAction(text);
}
this.popupStyle = popupStyle;
this.palette = palette;
}
public ISelection getSelection() {
return selection == null ? ColorSelection.EMPTY : selection;
}
public void setAutoColor(RGB color) {
this.autoColor = color;
}
public void setSelection(ISelection selection) {
if (selection == null || !(selection instanceof IColorSelection))
selection = ColorSelection.EMPTY;
if (selection == this.selection
|| (selection != null && selection.equals(this.selection)))
return;
this.selection = (IColorSelection) selection;
update(null);
fireSelectionChanged(new SelectionChangedEvent(this, getSelection()));
}
public void addSelectionChangedListener(ISelectionChangedListener listener) {
if (selectionChangedListeners == null)
selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
selectionChangedListeners.add(listener);
}
public void removeSelectionChangedListener(
ISelectionChangedListener listener) {
if (selectionChangedListeners == null)
return;
selectionChangedListeners.remove(listener);
}
protected void fireSelectionChanged(final SelectionChangedEvent event) {
if (selectionChangedListeners == null)
return;
for (final Object l : selectionChangedListeners.toArray()) {
SafeRunner.run(new SafeRunnable() {
public void run() throws Exception {
((ISelectionChangedListener) l).selectionChanged(event);
}
});
}
}
public void addOpenListener(IOpenListener listener) {
if (openListeners == null)
openListeners = new ArrayList<IOpenListener>();
openListeners.add(listener);
}
public void removeOpenListener(IOpenListener listener) {
if (openListeners == null)
return;
openListeners.remove(listener);
}
protected void fireOpenEvent(final OpenEvent event) {
if (openListeners == null)
return;
for (final Object l : openListeners.toArray()) {
SafeRunner.run(new SafeRunnable() {
public void run() throws Exception {
((IOpenListener) l).open(event);
}
});
}
}
private boolean hasPopupStyle(int style) {
return (popupStyle & style) != 0;
}
public void open() {
if (widget instanceof ToolItem) {
ToolItem item = (ToolItem) widget;
ColorChooserPopupDialog dialog = getPopupDialog();
if (dialog != null)
dialog.open(getItemBoundsToDisplay(item));
} else {
Point curLoc = Display.getCurrent().getCursorLocation();
if (curLoc != null) {
ColorChooserPopupDialog dialog = getPopupDialog();
if (dialog != null)
dialog.open(curLoc);
}
}
}
protected ColorChooserPopupDialog getPopupDialog() {
if (popup == null) {
Shell shell = getShell();
if (shell != null)
popup = new ColorChooserPopupDialog(shell);
}
return popup;
}
private Shell getShell() {
if (widget instanceof ToolItem) {
return ((ToolItem) widget).getParent().getShell();
} else if (widget instanceof MenuItem) {
return ((MenuItem) widget).getParent().getShell();
} else if (widget instanceof Control) {
return ((Control) widget).getShell();
}
return null;
}
private Rectangle getItemBoundsToDisplay(ToolItem item) {
Rectangle bounds = item.getBounds();
Point loc = item.getParent().toDisplay(bounds.x, bounds.y);
bounds.x = loc.x;
bounds.y = loc.y;
return bounds;
}
// private void close() {
// if (popup != null) {
// popup.close();
// }
// }
/**
* The <code>ActionContributionItem</code> implementation of this ,
* <code>IContributionItem</code> method creates an SWT
* <code>ToolItem</code> for the action using the action's style. If the
* action's checked property has been set, a button is created and primed to
* the value of the checked property. If the action's menu creator property
* has been set, a drop-down tool item is created.
*
* ATTN: Brian Sun has modified this method!
*/
public void fill(ToolBar parent, int index) {
if (widget == null && parent != null) {
int flags = SWT.PUSH | SWT.RIGHT;
if (action != null) {
int style = action.getStyle();
if (style == IAction.AS_CHECK_BOX) {
flags = SWT.CHECK;
} else if (style == IAction.AS_RADIO_BUTTON) {
flags = SWT.RADIO;
} else if (style == IAction.AS_DROP_DOWN_MENU) {
flags = SWT.DROP_DOWN;
}
}
ToolItem ti = null;
if (index >= 0) {
ti = new ToolItem(parent, flags, index);
} else {
ti = new ToolItem(parent, flags);
}
ti.setData(this);
ti.addListener(SWT.Selection, getToolItemListener());
ti.addListener(SWT.Dispose, getToolItemListener());
widget = ti;
update(null);
// Attach some extra listeners.
action.addPropertyChangeListener(propertyListener);
if (action != null) {
String commandId = action.getActionDefinitionId();
ExternalActionManager.ICallback callback = ExternalActionManager
.getInstance().getCallback();
if ((callback != null) && (commandId != null)) {
callback.addPropertyChangeListener(commandId,
actionTextListener);
}
}
}
}
@Override
public void fill(Menu parent, int index) {
if (widget == null && parent != null) {
Menu subMenu = null;
int flags = SWT.PUSH;
if (action != null) {
int style = action.getStyle();
if (style == IAction.AS_CHECK_BOX) {
flags = SWT.CHECK;
} else if (style == IAction.AS_RADIO_BUTTON) {
flags = SWT.RADIO;
} else if (style == IAction.AS_DROP_DOWN_MENU) {
IMenuCreator mc = action.getMenuCreator();
if (mc != null) {
subMenu = mc.getMenu(parent);
flags = SWT.CASCADE;
}
}
}
MenuItem mi = null;
if (index >= 0) {
mi = new MenuItem(parent, flags, index);
} else {
mi = new MenuItem(parent, flags);
}
widget = mi;
mi.setData(this);
mi.addListener(SWT.Dispose, getMenuItemListener());
mi.addListener(SWT.Selection, getMenuItemListener());
if (action.getHelpListener() != null) {
mi.addHelpListener(action.getHelpListener());
}
if (subMenu != null) {
mi.setMenu(subMenu);
}
update(null);
// Attach some extra listeners.
action.addPropertyChangeListener(propertyListener);
if (action != null) {
String commandId = action.getActionDefinitionId();
ExternalActionManager.ICallback callback = ExternalActionManager
.getInstance().getCallback();
if ((callback != null) && (commandId != null)) {
callback.addPropertyChangeListener(commandId,
actionTextListener);
}
}
}
}
/**
* Returns the listener for SWT menu item widget events.
*
* @return a listener for menu item events
*/
private Listener getMenuItemListener() {
if (menuItemListener == null) {
menuItemListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose:
handleWidgetDispose(event);
break;
case SWT.Selection:
Widget ew = event.widget;
if (ew != null) {
handleWidgetSelection(event,
((MenuItem) ew).getSelection());
}
break;
}
}
};
}
return menuItemListener;
}
/**
* Returns the listener for SWT tool item widget events.
*
* @return a listener for tool item events
*/
private Listener getToolItemListener() {
if (toolItemListener == null) {
toolItemListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose:
handleWidgetDispose(event);
break;
case SWT.Selection:
Widget ew = event.widget;
if (ew != null) {
handleWidgetSelection(event,
((ToolItem) ew).getSelection());
}
break;
}
}
};
}
return toolItemListener;
}
/**
* Handles a property change event on the action (forwarded by nested
* listener).
*/
private void actionPropertyChange(final PropertyChangeEvent e) {
// This code should be removed. Avoid using free asyncExec
if (isVisible() && widget != null) {
Display display = widget.getDisplay();
if (display.getThread() == Thread.currentThread()) {
update(e.getProperty());
} else {
display.asyncExec(new Runnable() {
public void run() {
update(e.getProperty());
}
});
}
}
}
/**
* Returns the action associated with this contribution item.
*
* @return the action
*/
public IAction getAction() {
return action;
}
/**
* Returns the presentation mode, which is the bitwise-or of the
* <code>MODE_*</code> constants. The default mode setting is 0, meaning
* that for menu items, both text and image are shown (if present), but for
* tool items, the text is shown only if there is no image.
*
* @return the presentation mode settings
*
* @since 3.0
*/
public int getMode() {
return mode;
}
/*
* (non-Javadoc) Method declared on Object.
*/
public int hashCode() {
return action.hashCode();
}
/**
* Returns whether the given action has any images.
*
* @param actionToCheck
* the action
* @return <code>true</code> if the action has any images,
* <code>false</code> if not
*/
private boolean hasImages(IAction actionToCheck) {
return actionToCheck.getImageDescriptor() != null
|| actionToCheck.getHoverImageDescriptor() != null
|| actionToCheck.getDisabledImageDescriptor() != null;
}
// /**
// * Returns whether the command corresponding to this action
// * is active.
// */
// private boolean isCommandActive() {
// IAction actionToCheck = getAction();
//
// if (actionToCheck != null) {
// String commandId = actionToCheck.getActionDefinitionId();
// ExternalActionManager.ICallback callback = ExternalActionManager
// .getInstance().getCallback();
//
// if (callback != null) {
// return callback.isActive(commandId);
// }
// }
// return true;
// }
/**
* The action item implementation of this <code>IContributionItem</code>
* method returns <code>true</code> for menu items and <code>false</code>
* for everything else.
*/
public boolean isDynamic() {
if (widget instanceof MenuItem) {
//Optimization. Only recreate the item is the check or radio style has changed.
boolean itemIsCheck = (widget.getStyle() & SWT.CHECK) != 0;
boolean actionIsCheck = getAction() != null
&& getAction().getStyle() == IAction.AS_CHECK_BOX;
boolean itemIsRadio = (widget.getStyle() & SWT.RADIO) != 0;
boolean actionIsRadio = getAction() != null
&& getAction().getStyle() == IAction.AS_RADIO_BUTTON;
return (itemIsCheck != actionIsCheck)
|| (itemIsRadio != actionIsRadio);
}
return false;
}
/*
* (non-Javadoc) Method declared on IContributionItem.
*/
public boolean isEnabled() {
return action != null && action.isEnabled();
}
// /**
// * Returns <code>true</code> if this item is allowed to enable,
// * <code>false</code> otherwise.
// *
// * @return if this item is allowed to be enabled
// * @since 2.0
// */
// protected boolean isEnabledAllowed() {
// if (getParent() == null) {
// return true;
// }
// Boolean value = getParent().getOverrides().getEnabled(this);
// return (value == null) ? true : value.booleanValue();
// }
//
// /**
// * The <code>ActionContributionItem</code> implementation of this
// * <code>ContributionItem</code> method extends the super implementation
// * by also checking whether the command corresponding to this action is active.
// */
// public boolean isVisible() {
// return super.isVisible() && isCommandActive();
// }
/**
* Sets the presentation mode, which is the bitwise-or of the
* <code>MODE_*</code> constants.
*
* @param mode
* the presentation mode settings
*
* @since 3.0
*/
public void setMode(int mode) {
this.mode = mode;
update();
}
/**
* Handles a widget dispose event for the widget corresponding to this item.
*/
private void handleWidgetDispose(Event e) {
// Check if our widget is the one being disposed.
if (e.widget == widget) {
// Dispose of the menu creator.
if (action.getStyle() == IAction.AS_DROP_DOWN_MENU) {
IMenuCreator mc = action.getMenuCreator();
if (mc != null) {
mc.dispose();
}
}
// Unhook all of the listeners.
action.removePropertyChangeListener(propertyListener);
if (action != null) {
String commandId = action.getActionDefinitionId();
ExternalActionManager.ICallback callback = ExternalActionManager
.getInstance().getCallback();
if ((callback != null) && (commandId != null)) {
callback.removePropertyChangeListener(commandId,
actionTextListener);
}
}
// Clear the widget field.
widget = null;
disposeOldImages();
}
}
/**
* Handles a widget selection event.
*/
private void handleWidgetSelection(Event e, boolean selection) {
Widget item = e.widget;
if (item != null) {
int style = item.getStyle();
if ((style & (SWT.TOGGLE | SWT.CHECK)) != 0) {
if (action.getStyle() == IAction.AS_CHECK_BOX) {
action.setChecked(selection);
}
} else if ((style & SWT.RADIO) != 0) {
if (action.getStyle() == IAction.AS_RADIO_BUTTON) {
action.setChecked(selection);
}
} else if ((style & SWT.DROP_DOWN) != 0) {
if (e.detail == 4) { // on drop-down button
if (action.getStyle() == IAction.AS_DROP_DOWN_MENU) {
// IMenuCreator mc = action.getMenuCreator();
// ToolItem ti = (ToolItem) item;
// // we create the menu as a sub-menu of "dummy" so that we can use
// // it in a cascading menu too.
// // If created on a SWT control we would get an SWT error...
// //Menu dummy= new Menu(ti.getParent());
// //Menu m= mc.getMenu(dummy);
// //dummy.dispose();
// if (mc != null) {
// Menu m = mc.getMenu(ti.getParent());
// if (m != null) {
// // position the menu below the drop down item
// Rectangle b = ti.getBounds();
// Point p = ti.getParent().toDisplay(
// new Point(b.x, b.y + b.height));
// m.setLocation(p.x, p.y); // waiting for SWT 0.42
// m.setVisible(true);
// return; // we don't fire the action
// }
// }
}
}
}
// Ensure action is enabled first.
// See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be executed while disabled.
if (action.isEnabled()) {
boolean trace = Policy.TRACE_ACTIONS;
long ms = System.currentTimeMillis();
if (trace) {
System.out.println("Running action: " + action.getText()); //$NON-NLS-1$
}
action.runWithEvent(e);
if (trace) {
System.out.println((System.currentTimeMillis() - ms)
+ " ms to run action: " + action.getText()); //$NON-NLS-1$
}
}
}
}
/**
* The action item implementation of this <code>IContributionItem</code>
* method calls <code>update(null)</code>.
*/
public final void update() {
update(null);
}
/**
* Synchronizes the UI with the given property. ATTN: Brian Sun ��������
*
* @param propertyName
* the name of the property, or <code>null</code> meaning all
* applicable properties
*/
public void update(String propertyName) {
if (widget != null) {
// determine what to do
boolean textChanged = propertyName == null
|| propertyName.equals(IAction.TEXT);
boolean imageChanged = propertyName == null
|| propertyName.equals(IAction.IMAGE);
boolean tooltipTextChanged = propertyName == null
|| propertyName.equals(IAction.TOOL_TIP_TEXT);
boolean enableStateChanged = propertyName == null
|| propertyName.equals(IAction.ENABLED)
|| propertyName
.equals(IContributionManagerOverrides.P_ENABLED);
boolean checkChanged = (action.getStyle() == IAction.AS_CHECK_BOX || action
.getStyle() == IAction.AS_RADIO_BUTTON)
&& (propertyName == null || propertyName
.equals(IAction.CHECKED));
boolean colorChanged = propertyName == null
|| propertyName.equals(IColorAction.COLOR);
if (widget instanceof ToolItem) {
//int toolbarStyle = SWT.NONE;
ToolItem ti = (ToolItem) widget;
String text = action.getText();
// the set text is shown only if there is no image or if forced by MODE_FORCE_TEXT
boolean showText = text != null
&& ((getMode() & MODE_FORCE_TEXT) != 0 || !hasImages(action));
// && ((toolbarStyle & BFaceConstants.TOOLBAR_TEXT)!=0 ||
// ((toolbarStyle & BFaceConstants.TOOLBAR_TEXT_RIGHT)!=0 && hasRightText));
// only do the trimming if the text will be used
if (showText && text != null) {
text = Action.removeAcceleratorText(text);
text = Action.removeMnemonics(text);
}
if (textChanged) {
String textToSet = showText ? text : ""; //$NON-NLS-1$
boolean rightStyle = (ti.getParent().getStyle() & SWT.RIGHT) != 0;
if (rightStyle || !ti.getText().equals(textToSet)) {
// In addition to being required to update the text if it
// gets nulled out in the action, this is also a workaround
// for bug 50151: Using SWT.RIGHT on a ToolBar leaves blank space
ti.setText(textToSet);
}
}
if (imageChanged) {
// only substitute a missing image if it has no text
updateImages(!showText);
}
if (tooltipTextChanged || textChanged) {
String toolTip = action.getToolTipText();
if ((toolTip == null) || (toolTip.length() == 0)) {
toolTip = text;
}
// if the text is showing, then only set the tooltip if
// different
if (!showText || toolTip != null) {
// && !toolTip.equals(text)) {
ti.setToolTipText(toolTip);
} else {
ti.setToolTipText(null);
}
}
if (enableStateChanged) {
boolean shouldBeEnabled = action.isEnabled();
// && isEnabledAllowed();
if (ti.getEnabled() != shouldBeEnabled) {
ti.setEnabled(shouldBeEnabled);
}
}
if (checkChanged) {
boolean bv = action.isChecked();
if (ti.getSelection() != bv) {
ti.setSelection(bv);
}
}
if (colorChanged) {
updateColors();
}
return;
}
if (widget instanceof MenuItem) {
MenuItem mi = (MenuItem) widget;
if (textChanged) {
int accelerator = 0;
String acceleratorText = null;
IAction updatedAction = getAction();
String text = null;
accelerator = updatedAction.getAccelerator();
ExternalActionManager.ICallback callback = ExternalActionManager
.getInstance().getCallback();
// Block accelerators that are already in use.
if ((accelerator != 0) && (callback != null)
&& (callback.isAcceleratorInUse(accelerator))) {
accelerator = 0;
}
/*
* Process accelerators on GTK in a special way to avoid Bug
* 42009. We will override the native input method by
* allowing these reserved accelerators to be placed on the
* menu. We will only do this for "Ctrl+Shift+[0-9A-FU]".
*/
final String commandId = updatedAction
.getActionDefinitionId();
if (("gtk".equals(SWT.getPlatform())) && (callback instanceof IBindingManagerCallback) //$NON-NLS-1$
&& (commandId != null)) {
final IBindingManagerCallback bindingManagerCallback = (IBindingManagerCallback) callback;
final IKeyLookup lookup = KeyLookupFactory.getDefault();
final TriggerSequence[] triggerSequences = bindingManagerCallback
.getActiveBindingsFor(commandId);
for (int i = 0; i < triggerSequences.length; i++) {
final TriggerSequence triggerSequence = triggerSequences[i];
final Trigger[] triggers = triggerSequence
.getTriggers();
if (triggers.length == 1) {
final Trigger trigger = triggers[0];
if (trigger instanceof KeyStroke) {
final KeyStroke currentKeyStroke = (KeyStroke) trigger;
final int currentNaturalKey = currentKeyStroke
.getNaturalKey();
if ((currentKeyStroke.getModifierKeys() == (lookup
.getCtrl() | lookup.getShift()))
&& ((currentNaturalKey >= '0' && currentNaturalKey <= '9')
|| (currentNaturalKey >= 'A' && currentNaturalKey <= 'F') || (currentNaturalKey == 'U'))) {
accelerator = currentKeyStroke
.getModifierKeys()
| currentNaturalKey;
acceleratorText = triggerSequence
.format();
break;
}
}
}
}
}
if (accelerator == 0) {
if ((callback != null) && (commandId != null)) {
acceleratorText = callback
.getAcceleratorText(commandId);
}
} else {
acceleratorText = Action
.convertAccelerator(accelerator);
}
IContributionManagerOverrides overrides = null;
if (getParent() != null) {
overrides = getParent().getOverrides();
}
if (overrides != null) {
text = getParent().getOverrides().getText(this);
}
mi.setAccelerator(accelerator);
if (text == null) {
text = updatedAction.getText();
}
if (text == null) {
text = ""; //$NON-NLS-1$
} else {
text = Action.removeAcceleratorText(text);
}
if (acceleratorText == null) {
mi.setText(text);
} else {
mi.setText(text + '\t' + acceleratorText);
}
}
if (imageChanged) {
updateImages(false);
}
if (enableStateChanged) {
boolean shouldBeEnabled = action.isEnabled();
// && isEnabledAllowed();
if (mi.getEnabled() != shouldBeEnabled) {
mi.setEnabled(shouldBeEnabled);
}
}
if (checkChanged) {
boolean bv = action.isChecked();
if (mi.getSelection() != bv) {
mi.setSelection(bv);
}
}
if (colorChanged) {
updateColors();
}
return;
}
if (widget instanceof Button) {
Button button = (Button) widget;
if (imageChanged && updateImages(false)) {
textChanged = false; // don't update text if it has an image
}
if (textChanged) {
String text = action.getText();
if (text == null) {
text = ""; //$NON-NLS-1$
} else {
text = Action.removeAcceleratorText(text);
}
button.setText(text);
}
if (tooltipTextChanged) {
button.setToolTipText(action.getToolTipText());
}
if (enableStateChanged) {
boolean shouldBeEnabled = action.isEnabled();
// && isEnabledAllowed();
if (button.getEnabled() != shouldBeEnabled) {
button.setEnabled(shouldBeEnabled);
}
}
if (checkChanged) {
boolean bv = action.isChecked();
if (button.getSelection() != bv) {
button.setSelection(bv);
}
}
if (colorChanged) {
updateColors();
}
return;
}
}
}
private void updateColors() {
if (selection != null) {
RGB c = selection.getColor();
if (action instanceof IColorAction) {
((IColorAction) action).setColor(c);
}
}
}
/**
* Updates the images for this action.
*
* @param forceImage
* <code>true</code> if some form of image is compulsory, and
* <code>false</code> if it is acceptable for this item to have
* no image
* @return <code>true</code> if there are images for this action,
* <code>false</code> if not
*/
private boolean updateImages(boolean forceImage) {
ResourceManager parentResourceManager = JFaceResources.getResources();
if (widget instanceof ToolItem) {
if (USE_COLOR_ICONS) {
ImageDescriptor image = action.getHoverImageDescriptor();
if (image == null) {
image = action.getImageDescriptor();
}
ImageDescriptor disabledImage = action
.getDisabledImageDescriptor();
// Make sure there is a valid image.
if (image == null && forceImage) {
image = ImageDescriptor.getMissingImageDescriptor();
}
LocalResourceManager localManager = new LocalResourceManager(
parentResourceManager);
// performance: more efficient in SWT to set disabled and hot image before regular image
((ToolItem) widget)
.setDisabledImage(disabledImage == null ? null
: localManager
.createImageWithDefault(disabledImage));
((ToolItem) widget).setImage(image == null ? null
: localManager.createImageWithDefault(image));
disposeOldImages();
imageManager = localManager;
return image != null;
}
ImageDescriptor image = action.getImageDescriptor();
ImageDescriptor hoverImage = action.getHoverImageDescriptor();
ImageDescriptor disabledImage = action.getDisabledImageDescriptor();
// If there is no regular image, but there is a hover image,
// convert the hover image to gray and use it as the regular image.
if (image == null && hoverImage != null) {
image = ImageDescriptor.createWithFlags(
action.getHoverImageDescriptor(), SWT.IMAGE_GRAY);
} else {
// If there is no hover image, use the regular image as the hover image,
// and convert the regular image to gray
if (hoverImage == null && image != null) {
hoverImage = image;
image = ImageDescriptor.createWithFlags(
action.getImageDescriptor(), SWT.IMAGE_GRAY);
}
}
// Make sure there is a valid image.
if (hoverImage == null && image == null && forceImage) {
image = ImageDescriptor.getMissingImageDescriptor();
}
// Create a local resource manager to remember the images we've allocated for this tool item
LocalResourceManager localManager = new LocalResourceManager(
parentResourceManager);
// performance: more efficient in SWT to set disabled and hot image before regular image
((ToolItem) widget).setDisabledImage(disabledImage == null ? null
: localManager.createImageWithDefault(disabledImage));
((ToolItem) widget).setHotImage(hoverImage == null ? null
: localManager.createImageWithDefault(hoverImage));
((ToolItem) widget).setImage(image == null ? null : localManager
.createImageWithDefault(image));
// Now that we're no longer referencing the old images, clear them out.
disposeOldImages();
imageManager = localManager;
return image != null;
} else if (widget instanceof Item || widget instanceof Button) {
// Use hover image if there is one, otherwise use regular image.
ImageDescriptor image = action.getHoverImageDescriptor();
if (image == null) {
image = action.getImageDescriptor();
}
// Make sure there is a valid image.
if (image == null && forceImage) {
image = ImageDescriptor.getMissingImageDescriptor();
}
// Create a local resource manager to remember the images we've allocated for this widget
LocalResourceManager localManager = new LocalResourceManager(
parentResourceManager);
if (widget instanceof Item) {
((Item) widget).setImage(image == null ? null : localManager
.createImageWithDefault(image));
} else if (widget instanceof Button) {
((Button) widget).setImage(image == null ? null : localManager
.createImageWithDefault(image));
}
// Now that we're no longer referencing the old images, clear them out.
disposeOldImages();
imageManager = localManager;
return image != null;
}
return false;
}
/**
* Dispose any images allocated for this contribution item
*/
private void disposeOldImages() {
if (imageManager != null) {
imageManager.dispose();
imageManager = null;
}
}
}