blob: a40f92fd7926fd91bda7993be25ed5180d332bdf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 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.gef.internal.ui.palette.editparts;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IMemento;
import org.eclipse.draw2d.ActionEvent;
import org.eclipse.draw2d.ActionListener;
import org.eclipse.draw2d.Border;
import org.eclipse.draw2d.ButtonBorder;
import org.eclipse.draw2d.ButtonModel;
import org.eclipse.draw2d.Clickable;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.Toggle;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.rap.swt.SWT;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.internal.ui.palette.PaletteColorUtil;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteStack;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.ui.palette.PaletteViewerPreferences;
import org.eclipse.gef.ui.palette.editparts.IPinnableEditPart;
import org.eclipse.gef.ui.palette.editparts.PaletteEditPart;
public class ToolEntryEditPart extends PaletteEditPart {
class MenuTimer implements Runnable {
public static final int MENU_TIMER_DELAY = 400;
private boolean enabled = true;
public void disable() {
enabled = false;
}
public void run() {
if (enabled) {
getButtonModel().setArmed(false);
getButtonModel().setPressed(false);
((IPaletteStackEditPart) getParent()).openMenu();
getViewer().getEditDomain().loadDefaultTool();
}
}
}
abstract class ToggleButtonTracker extends SingleSelectionTracker {
private MenuTimer timer = null;
protected void enableTimer() {
timer = new MenuTimer();
getViewer().getControl().getDisplay()
.timerExec(MenuTimer.MENU_TIMER_DELAY, timer);
}
protected void disableTimer() {
if (timer != null) {
timer.disable();
timer = null;
}
}
protected boolean handleButtonDown(int button) {
if (getParent() instanceof IPaletteStackEditPart)
enableTimer();
if (button == 2 && isInState(STATE_INITIAL))
performConditionalSelection();
super.handleButtonDown(button);
if (button == 1) {
getFigure().internalGetEventDispatcher().requestRemoveFocus(
getFigure());
getButtonModel().setArmed(true);
getButtonModel().setPressed(true);
}
return true;
}
protected boolean handleDrag() {
org.eclipse.draw2d.geometry.Point point = getLocation().getCopy();
getFigure().translateToRelative(point);
if (!getFigure().containsPoint(point)) {
getButtonModel().setArmed(false);
getButtonModel().setMouseOver(false);
disableTimer();
} else {
getButtonModel().setArmed(true);
getButtonModel().setMouseOver(true);
}
return true;
}
protected boolean handleNativeDragFinished(DragSourceEvent event) {
getPaletteViewer().setActiveTool(null);
return true;
}
}
class GTKToggleButtonTracker extends ToggleButtonTracker {
int gtkState = 0;
public void deactivate() {
disableTimer();
super.deactivate();
}
protected boolean handleButtonUp(int button) {
disableTimer();
// Workaround for Bug 96351. It should be removed when Bug 35585 is
// fixed.
if (gtkState == 1) {
handleNativeDragFinished(null);
return true;
}
if (button == 1) {
getButtonModel().setPressed(false);
getButtonModel().setArmed(false);
}
return super.handleButtonUp(button);
}
protected boolean handleNativeDragStarted(DragSourceEvent event) {
disableTimer();
gtkState = 1;
return true;
}
}
class OtherToggleButtonTracker extends ToggleButtonTracker {
private static final int WIN_THRESHOLD = 3;
private Point mouseDownLoc = null;
public void deactivate() {
disableTimer();
getButtonModel().setPressed(false);
getButtonModel().setArmed(false);
super.deactivate();
}
protected boolean handleButtonDown(int button) {
mouseDownLoc = new Point(getLocation().x, getLocation().y);
return super.handleButtonDown(button);
}
protected boolean handleButtonUp(int button) {
disableTimer();
if (button == 1) {
getButtonModel().setPressed(false);
getButtonModel().setArmed(false);
}
return super.handleButtonUp(button);
}
protected boolean handleNativeDragStarted(DragSourceEvent event) {
disableTimer();
// win hack because button down is delayed
if (getParent() instanceof IPaletteStackEditPart
&& SWT.getPlatform().equals("win32")) { //$NON-NLS-1$
Point nds = getPaletteViewer().getControl().toControl(
event.display.getCursorLocation());
if (mouseDownLoc != null
&& (Math.abs(nds.x - mouseDownLoc.x) + Math.abs(nds.y
- mouseDownLoc.y)) < WIN_THRESHOLD) {
getButtonModel().setArmed(false);
getButtonModel().setPressed(false);
((IPaletteStackEditPart) getParent()).openMenu();
getViewer().getEditDomain().loadDefaultTool();
event.doit = false;
return false;
}
}
getButtonModel().setPressed(false);
getButtonModel().setArmed(false);
return true;
}
}
/**
* The figure for for a <code>ToolEntryEditPart</code>.
*/
class ToolEntryToggle extends Toggle {
private boolean showHoverFeedback = false;
ToolEntryToggle(IFigure contents) {
super(contents);
setOpaque(false);
setEnabled(true);
if (isToolbarItem()) {
setStyle(Clickable.STYLE_BUTTON | Clickable.STYLE_TOGGLE);
setBorder(TOOLBAR_ITEM_BORDER);
}
}
public boolean containsPoint(int x, int y) {
Rectangle rect = getBounds().getCopy();
if (customLabel.getBorder() == ICON_BORDER) {
rect.width -= PinnablePaletteStackFigure.ARROW_WIDTH;
} else if (customLabel.getBorder() == LIST_BORDER) {
rect.width -= PinnablePaletteStackFigure.ARROW_WIDTH;
rect.x += PinnablePaletteStackFigure.ARROW_WIDTH;
}
return rect.contains(x, y);
}
public IFigure findMouseEventTargetAt(int x, int y) {
return null;
}
public IFigure getToolTip() {
return createToolTip();
}
public void setEnabled(boolean value) {
super.setEnabled(value);
if (isEnabled()) {
setRolloverEnabled(true);
if (getFlag(STYLE_BUTTON)) {
setBorder(TOOLBAR_ITEM_BORDER);
}
setForegroundColor(null);
} else {
if (getFlag(STYLE_BUTTON)) {
setBorder(null);
}
setRolloverEnabled(false);
setForegroundColor(ColorConstants.gray);
}
}
protected void paintFigure(Graphics graphics) {
super.paintFigure(graphics);
if (!isToolbarItem() && isEnabled() && isRolloverEnabled()) {
ButtonModel model = getModel();
if (model.isSelected()) {
graphics.setBackgroundColor(PaletteColorUtil
.getSelectedColor());
graphics.fillRoundRectangle(
getSelectionRectangle(getLayoutSetting(),
customLabel), 3, 3);
} else if (model.isMouseOver() || showHoverFeedback) {
graphics.setBackgroundColor(PaletteColorUtil
.getHoverColor());
graphics.fillRoundRectangle(
getSelectionRectangle(getLayoutSetting(),
customLabel), 3, 3);
}
}
}
protected void paintBorder(Graphics graphics) {
if (isEnabled()) {
if (getBorder() != null)
getBorder().paint(this, graphics, NO_INSETS);
if (hasFocus()) {
graphics.setForegroundColor(ColorConstants.black);
graphics.setBackgroundColor(ColorConstants.white);
Rectangle area = isToolbarItem() ? getClientArea()
: getSelectionRectangle(getLayoutSetting(),
customLabel);
if (isStyle(STYLE_BUTTON))
graphics.drawFocus(area.x, area.y, area.width,
area.height);
else
graphics.drawFocus(area.x, area.y, area.width - 1,
area.height - 1);
}
} else {
super.paintBorder(graphics);
}
}
/**
* Should hover feedback be shown? Allows other palette entities to
* control when the hover feedback should be shown on this tool entry.
*
* @param showHoverFeedback
* true if the hover feedback is to be shown; false
* otherwise.
*/
public void setShowHoverFeedback(boolean showHoverFeedback) {
this.showHoverFeedback = showHoverFeedback;
repaint();
}
}
private static final String ACTIVE_STATE = "active"; //$NON-NLS-1$
private DetailedLabelFigure customLabel;
public ToolEntryEditPart(PaletteEntry paletteEntry) {
super(paletteEntry);
}
public Object getAdapter(Class key) {
if (key == IPinnableEditPart.class) {
if ((getParent() instanceof PinnablePaletteStackEditPart)
&& ((PinnablePaletteStackEditPart) getParent())
.canBePinned()
&& ((PaletteStack) getParent().getModel()).getActiveEntry()
.equals(getModel())) {
return getParent();
}
}
return super.getAdapter(key);
}
protected AccessibleEditPart createAccessible() {
return new AccessibleGraphicalEditPart() {
public void getDescription(AccessibleEvent e) {
e.result = getPaletteEntry().getDescription();
}
public void getName(AccessibleEvent e) {
e.result = getPaletteEntry().getLabel();
}
public void getRole(AccessibleControlEvent e) {
if (getParent() instanceof IPaletteStackEditPart
&& (ToolEntryEditPart.this == ((IPaletteStackEditPart) getParent())
.getActiveEntry())) {
e.detail = ACC.ROLE_COMBOBOX;
} else {
e.detail = ACC.ROLE_PUSHBUTTON;
}
}
public void getState(AccessibleControlEvent e) {
super.getState(e);
if (getButtonModel().isSelected())
e.detail |= ACC.STATE_CHECKED;
}
};
}
static final Border TOOLBAR_ITEM_BORDER = new ButtonBorder(
ButtonBorder.SCHEMES.TOOLBAR);
// The following are the insets that the bounds of the label figure should
// be
// cropped to paint the blue/orange select and hover feedback rectangles.
static final Insets LIST_HIGHLIGHT_INSETS = new Insets(1, 5, 2, 0);
static final Insets ICON_HIGHLIGHT_INSETS = new Insets(2, 1, 2, 1);
// The following are the borders that go around the entire tool figure to
// provide room to draw the arrow and outline of the palette stack figure if
// this tool happens to appear as the active tool of a stack.
static final Border LIST_BORDER = new MarginBorder(3,
PinnablePaletteStackFigure.ARROW_WIDTH + 7, 4, 0);
static final Border ICON_BORDER = new MarginBorder(4, 4, 3,
PinnablePaletteStackFigure.ARROW_WIDTH + 4);
public IFigure createFigure() {
customLabel = new DetailedLabelFigure();
Clickable button = new ToolEntryToggle(customLabel);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
getPaletteViewer().setActiveTool(getToolEntry());
}
});
return button;
}
/**
* @see org.eclipse.gef.ui.palette.editparts.PaletteEditPart#deactivate()
*/
public void deactivate() {
customLabel.dispose();
super.deactivate();
}
/**
* @see org.eclipse.gef.EditPart#eraseTargetFeedback(Request)
*/
public void eraseTargetFeedback(Request request) {
if (RequestConstants.REQ_SELECTION.equals(request.getType()))
getButtonModel().setMouseOver(false);
super.eraseTargetFeedback(request);
}
private ButtonModel getButtonModel() {
Clickable c = (Clickable) getFigure();
return c.getModel();
}
/**
* @see PaletteEditPart#getDragTracker(Request)
*/
public DragTracker getDragTracker(Request request) {
if (SWT.getPlatform().equals("gtk")) //$NON-NLS-1$
return new GTKToggleButtonTracker();
else
return new OtherToggleButtonTracker();
}
private ToolEntry getToolEntry() {
return (ToolEntry) getPaletteEntry();
}
/**
* @see org.eclipse.gef.ui.palette.editparts.PaletteEditPart#getToolTipText()
*/
protected String getToolTipText() {
String result = null;
if (getLayoutSetting() != PaletteViewerPreferences.LAYOUT_DETAILS) {
result = super.getToolTipText();
}
return result;
}
/**
* If this edit part's name is truncated in its label, the name should be
* prepended to the tooltip.
*
* @return whether the name needs to be included in the tooltip
*/
protected boolean nameNeededInToolTip() {
DetailedLabelFigure label = (DetailedLabelFigure) getFigure()
.getChildren().get(0);
return label.isNameTruncated() || super.nameNeededInToolTip();
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
*/
protected void refreshVisuals() {
PaletteEntry entry = getPaletteEntry();
customLabel.setName(entry.getLabel());
customLabel.setDescription(entry.getDescription());
if (getPreferenceSource().useLargeIcons())
setImageDescriptor(entry.getLargeIcon());
else
setImageDescriptor(entry.getSmallIcon());
int layoutMode = getLayoutSetting();
customLabel.setLayoutMode(layoutMode);
if (layoutMode == PaletteViewerPreferences.LAYOUT_COLUMNS) {
customLabel.setBorder(ICON_BORDER);
} else if (layoutMode == PaletteViewerPreferences.LAYOUT_LIST
|| layoutMode == PaletteViewerPreferences.LAYOUT_DETAILS) {
customLabel.setBorder(LIST_BORDER);
} else if (layoutMode == PaletteViewerPreferences.LAYOUT_ICONS
&& !isToolbarItem()) {
customLabel.setBorder(ICON_BORDER);
} else {
customLabel.setBorder(null);
}
super.refreshVisuals();
}
/**
* @see org.eclipse.gef.EditPart#removeNotify()
*/
public void removeNotify() {
if (getButtonModel().isSelected())
getPaletteViewer().setActiveTool(null);
super.removeNotify();
}
public void setToolSelected(boolean value) {
getButtonModel().setSelected(value);
}
public void restoreState(IMemento memento) {
if (new Boolean(memento.getString(ACTIVE_STATE)).booleanValue())
getPaletteViewer().setActiveTool(getToolEntry());
super.restoreState(memento);
}
public void saveState(IMemento memento) {
memento.putString(ACTIVE_STATE, new Boolean(getPaletteViewer()
.getActiveTool() == getToolEntry()).toString());
super.saveState(memento);
}
/**
* @see PaletteEditPart#setImageInFigure(Image)
*/
protected void setImageInFigure(Image image) {
DetailedLabelFigure fig = (DetailedLabelFigure) (getFigure()
.getChildren().get(0));
fig.setImage(image);
}
/**
* @see org.eclipse.gef.EditPart#setSelected(int)
*/
public void setSelected(int value) {
super.setSelected(value);
if (value == SELECTED_PRIMARY
&& getPaletteViewer().getControl() != null
&& !getPaletteViewer().getControl().isDisposed()
&& getPaletteViewer().getControl().isFocusControl())
getFigure().requestFocus();
}
/**
* @see org.eclipse.gef.EditPart#showTargetFeedback(Request)
*/
public void showTargetFeedback(Request request) {
if (RequestConstants.REQ_SELECTION.equals(request.getType()))
getButtonModel().setMouseOver(true);
super.showTargetFeedback(request);
}
static Rectangle getSelectionRectangle(int layoutMode,
DetailedLabelFigure labelFigure) {
Rectangle rect = Rectangle.SINGLETON;
rect.setBounds(labelFigure.getBounds());
if (layoutMode == PaletteViewerPreferences.LAYOUT_LIST
|| layoutMode == PaletteViewerPreferences.LAYOUT_DETAILS) {
rect.x += PinnablePaletteStackFigure.ARROW_WIDTH;
rect.width -= PinnablePaletteStackFigure.ARROW_WIDTH;
int newWidth = labelFigure.getPreferredSize().width + 17;
if (newWidth < rect.width) {
rect.width = newWidth;
}
rect.crop(LIST_HIGHLIGHT_INSETS);
} else {
rect.width -= PinnablePaletteStackFigure.ARROW_WIDTH;
rect.crop(ICON_HIGHLIGHT_INSETS);
}
return rect;
}
}