/******************************************************************************* * 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.SWT; 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.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; } }; } 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.getSINGLETON(); 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; } }