| /******************************************************************************* |
| * Copyright (c) 2004, 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.ui.palette; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.swt.accessibility.ACC; |
| import org.eclipse.swt.accessibility.AccessibleAdapter; |
| import org.eclipse.swt.accessibility.AccessibleControlAdapter; |
| import org.eclipse.swt.accessibility.AccessibleControlEvent; |
| import org.eclipse.swt.accessibility.AccessibleEvent; |
| import org.eclipse.swt.dnd.DropTargetEvent; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseMoveListener; |
| import org.eclipse.swt.events.MouseTrackListener; |
| import org.eclipse.swt.events.PaintListener; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Canvas; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.ControlPaintHandler; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Tracker; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.core.runtime.Preferences; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.ActionContributionItem; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.TransferDropTargetListener; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IPerspectiveDescriptor; |
| import org.eclipse.ui.IPerspectiveListener; |
| import org.eclipse.ui.IViewReference; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.XMLMemento; |
| import org.eclipse.ui.internal.dnd.IDropTarget; |
| |
| import org.eclipse.draw2d.ActionEvent; |
| import org.eclipse.draw2d.ActionListener; |
| import org.eclipse.draw2d.Border; |
| import org.eclipse.draw2d.Button; |
| import org.eclipse.draw2d.ButtonBorder; |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.FocusEvent; |
| import org.eclipse.draw2d.FocusListener; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.Label; |
| import org.eclipse.draw2d.LightweightSystem; |
| import org.eclipse.draw2d.MarginBorder; |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.Triangle; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.rap.swt.SWT; |
| |
| import org.eclipse.gef.GraphicalViewer; |
| import org.eclipse.gef.SharedCursors; |
| import org.eclipse.gef.dnd.TemplateTransfer; |
| import org.eclipse.gef.internal.GEFMessages; |
| import org.eclipse.gef.internal.InternalImages; |
| import org.eclipse.gef.internal.ui.palette.PaletteColorUtil; |
| import org.eclipse.gef.ui.views.palette.PaletteView; |
| |
| /** |
| * The FlyoutPaletteComposite is used to show a flyout palette alongside another |
| * control. The flyout palette auto-hides (thus maximizing space) when not in |
| * use, but can also be pinned open if so desired. It will only be visible when |
| * the PaletteView is not. |
| * |
| * @author Pratik Shah |
| * @since 3.0 |
| */ |
| public class FlyoutPaletteComposite extends Composite { |
| |
| private static final FontManager FONT_MGR = new FontManager(); |
| |
| private static final String PROPERTY_PALETTE_WIDTH = "org.eclipse.gef.ui.palette.fpa.paletteWidth"; //$NON-NLS-1$ |
| private static final String PROPERTY_STATE = "org.eclipse.gef.ui.palette.fpa.state"; //$NON-NLS-1$ |
| private static final String PROPERTY_DOCK_LOCATION = "org.eclipse.gef.ui.palette.fpa.dock"; //$NON-NLS-1$ |
| |
| private static final int DEFAULT_PALETTE_SIZE = 125; |
| private static final int MIN_PALETTE_SIZE = 20; |
| private static final int MAX_PALETTE_SIZE = 500; |
| |
| private static final int STATE_HIDDEN = 8; |
| private static final int STATE_EXPANDED = 1; |
| |
| private static final Dimension ARROW_SIZE = new Dimension(6, 11); |
| private static final int SASH_BUTTON_WIDTH = 11; |
| |
| /** |
| * One of the two possible initial states of the flyout palette. This is the |
| * default one. When in this state, only the flyout palette's sash is |
| * visible. |
| */ |
| public static final int STATE_COLLAPSED = 2; |
| /** |
| * One of the two possible initial states of the flyout palette. When in |
| * this state, the flyout palette is completely visible and pinned open so |
| * that it doesn't disappear when the user wanders away from the flyout. |
| */ |
| public static final int STATE_PINNED_OPEN = 4; |
| |
| private PropertyChangeSupport listeners = new PropertyChangeSupport(this); |
| private Composite paletteContainer; |
| private PaletteViewer pViewer, externalViewer; |
| private IMemento capturedPaletteState; |
| private Control graphicalControl; |
| private Composite sash; |
| private PaletteViewerProvider provider; |
| private FlyoutPreferences prefs; |
| private Point cachedBounds = new Point(0, 0); |
| /* |
| * Fix for Bug# 71525 transferFocus is used to transfer focus from the |
| * button in the vertical sash title to the button in the horizontal |
| * paletteComposite title. When either button is pressed it is set to true, |
| * and when either the sash or the paletteComposite gets notified of the |
| * change in state, they transfer the focus to their button if this flag is |
| * set to true and if that button is visible. |
| */ |
| private boolean transferFocus = false; |
| private int dock = PositionConstants.EAST; |
| private int paletteState = STATE_HIDDEN; |
| private int paletteWidth = DEFAULT_PALETTE_SIZE; |
| private int minWidth = MIN_PALETTE_SIZE; |
| private int cachedSize = -1, cachedState = -1, cachedLocation = -1; |
| private int cachedTitleHeight = 24; // give it a default value |
| |
| private IPerspectiveListener perspectiveListener = new IPerspectiveListener() { |
| public void perspectiveActivated(IWorkbenchPage page, |
| IPerspectiveDescriptor perspective) { |
| handlePerspectiveActivated(page, perspective); |
| } |
| |
| public void perspectiveChanged(IWorkbenchPage page, |
| IPerspectiveDescriptor perspective, String changeId) { |
| handlePerspectiveChanged(page, perspective, changeId); |
| } |
| }; |
| |
| /** |
| * Constructor |
| * |
| * @param parent |
| * The parent Composite |
| * @param style |
| * The style of the widget to construct; only SWT.BORDER is |
| * allowed |
| * @param page |
| * The current workbench page |
| * @param pvProvider |
| * The provider that is to be used to create the flyout palette |
| * @param preferences |
| * To save/retrieve the preferences for the flyout |
| */ |
| public FlyoutPaletteComposite(Composite parent, int style, |
| IWorkbenchPage page, PaletteViewerProvider pvProvider, |
| FlyoutPreferences preferences) { |
| super(parent, style & SWT.BORDER); |
| provider = pvProvider; |
| prefs = preferences; |
| sash = createSash(); |
| paletteContainer = createPaletteContainer(); |
| hookIntoWorkbench(page.getWorkbenchWindow()); |
| |
| // Initialize the state properly |
| if (prefs.getPaletteWidth() <= 0) |
| prefs.setPaletteWidth(DEFAULT_PALETTE_SIZE); |
| setPaletteWidth(prefs.getPaletteWidth()); |
| setDockLocation(prefs.getDockLocation()); |
| updateState(page); |
| |
| addListener(SWT.Resize, new Listener() { |
| public void handleEvent(Event event) { |
| Rectangle area = getClientArea(); |
| /* |
| * @TODO:Pratik Sometimes, the editor is resized to 1,1 or 0,0 |
| * (depending on the platform) when the editor is closed or |
| * maximized. We have to ignore such resizes. See Bug# 62748 |
| */ |
| if (area.width > minWidth) |
| layout(true); |
| } |
| }); |
| |
| listeners.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| String property = evt.getPropertyName(); |
| if (property.equals(PROPERTY_PALETTE_WIDTH)) |
| prefs.setPaletteWidth(paletteWidth); |
| else if (property.equals(PROPERTY_DOCK_LOCATION)) |
| prefs.setDockLocation(dock); |
| else if (property.equals(PROPERTY_STATE)) |
| if (paletteState == STATE_COLLAPSED |
| || paletteState == STATE_PINNED_OPEN) |
| prefs.setPaletteState(paletteState); |
| } |
| }); |
| } |
| |
| private void addListenerToCtrlHierarchy(Control parent, int eventType, |
| Listener listener) { |
| parent.addListener(eventType, listener); |
| if (!(parent instanceof Composite)) |
| return; |
| Control[] children = ((Composite) parent).getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| addListenerToCtrlHierarchy(children[i], eventType, listener); |
| } |
| } |
| |
| private IMemento capturePaletteState(PaletteViewer viewer) { |
| IMemento memento = XMLMemento.createWriteRoot("paletteState"); //$NON-NLS-1$ |
| try { |
| viewer.saveState(memento); |
| } catch (RuntimeException re) { |
| // Bug 74843 -- See comment #1 |
| // If there's a problem with saving the palette's state, it simply |
| // won't be |
| // transferred to the new palette |
| memento = null; |
| /* |
| * @TODO:Pratik You should log this exception. |
| */ |
| } |
| return memento; |
| } |
| |
| private Control createFlyoutControlButton(Composite parent) { |
| return new ButtonCanvas(parent); |
| } |
| |
| /** |
| * This is a convenient method to get a default FlyoutPreferences object. |
| * The returned FlyoutPreferences does not save any changes made to the |
| * given {@link Preferences Preferences}. It's upto the owner plugin to |
| * {@link Plugin#savePluginPreferences() save} the changes before it |
| * {@link Plugin#stop(org.osgi.framework.BundleContext) stops}. |
| * |
| * @param prefs |
| * {@link Plugin#getPluginPreferences() a plugin's Preferences} |
| * @return a default implementation of FlyoutPreferences that stores the |
| * settings in the given Preferences |
| * @since 3.2 |
| */ |
| public static FlyoutPreferences createFlyoutPreferences(Preferences prefs) { |
| return new DefaultFlyoutPreferences(prefs); |
| } |
| |
| private Composite createPaletteContainer() { |
| return new PaletteComposite(this, SWT.NONE); |
| } |
| |
| private Composite createSash() { |
| return new Sash(this, SWT.NONE); |
| } |
| |
| private Control createTitle(Composite parent, boolean isHorizontal) { |
| return new TitleCanvas(parent, isHorizontal); |
| } |
| |
| private Control getPaletteViewerControl() { |
| Control result = null; |
| if (pViewer != null) |
| result = pViewer.getControl(); |
| // Fix for bug 101703 -- pViewer.getControl().getParent() might be |
| // parented |
| // by paletteContainer |
| if (result != null && !result.isDisposed() |
| && result.getParent() != paletteContainer) |
| result = result.getParent(); |
| return result; |
| } |
| |
| private void handlePerspectiveActivated(IWorkbenchPage page, |
| IPerspectiveDescriptor perspective) { |
| updateState(page); |
| } |
| |
| private void handlePerspectiveChanged(IWorkbenchPage page, |
| IPerspectiveDescriptor perspective, String changeId) { |
| if (changeId.equals(IWorkbenchPage.CHANGE_VIEW_SHOW) |
| || changeId.equals(IWorkbenchPage.CHANGE_VIEW_HIDE)) |
| updateState(page); |
| } |
| |
| // Will return false if the ancestor or descendant is null |
| private boolean isDescendantOf(Control ancestor, Control descendant) { |
| if (ancestor == null || descendant == null) |
| return false; |
| while (descendant != null) { |
| if (ancestor == descendant) |
| return true; |
| descendant = descendant.getParent(); |
| } |
| return false; |
| } |
| |
| private boolean isInState(int state) { |
| return (paletteState & state) != 0; |
| } |
| |
| private boolean isMirrored() { |
| return (getStyle() & SWT.MIRRORED) != 0; |
| } |
| |
| /** |
| * @see Composite#layout(boolean) |
| */ |
| public void layout(boolean changed) { |
| if (graphicalControl == null || graphicalControl.isDisposed()) |
| return; |
| |
| Rectangle area = getClientArea(); |
| if (area.width == 0 || area.height == 0) |
| return; |
| |
| int sashWidth = sash.computeSize(-1, -1).x; |
| int pWidth = paletteWidth; |
| int maxWidth = Math.min(area.width / 2, MAX_PALETTE_SIZE); |
| maxWidth = Math.max(maxWidth, minWidth); |
| pWidth = Math.max(pWidth, minWidth); |
| pWidth = Math.min(pWidth, maxWidth); |
| |
| /* |
| * Fix for Bug# 65892 Laying out only when necessary helps reduce |
| * flicker on GTK in the case where the flyout palette is being resized |
| * past its maximum size. |
| */ |
| if (paletteState == cachedState && pWidth == cachedSize |
| && cachedLocation == dock && cachedBounds == getSize()) |
| return; |
| cachedState = paletteState; |
| cachedSize = pWidth; |
| cachedLocation = dock; |
| cachedBounds = getSize(); |
| |
| setRedraw(false); |
| if (isInState(STATE_HIDDEN)) { |
| sash.setVisible(false); |
| paletteContainer.setVisible(false); |
| graphicalControl.setBounds(area); |
| } else if (dock == PositionConstants.EAST) |
| layoutComponentsEast(area, sashWidth, pWidth); |
| else |
| layoutComponentsWest(area, sashWidth, pWidth); |
| sash.layout(); |
| setRedraw(true); |
| update(); |
| } |
| |
| private void layoutComponentsEast(Rectangle area, int sashWidth, int pWidth) { |
| if (isInState(STATE_COLLAPSED)) { |
| paletteContainer.setVisible(false); |
| sash.setBounds(area.x + area.width - sashWidth, area.y, sashWidth, |
| area.height); |
| graphicalControl.setBounds(area.x, area.y, area.width - sashWidth, |
| area.height); |
| sash.setVisible(true); |
| } else if (isInState(STATE_EXPANDED)) { |
| paletteContainer.moveAbove(graphicalControl); |
| sash.moveAbove(paletteContainer); |
| paletteContainer.setBounds(area.x + area.width - pWidth, area.y, |
| pWidth, area.height); |
| sash.setBounds(area.x + area.width - pWidth - sashWidth, area.y, |
| sashWidth, area.height); |
| graphicalControl.setBounds(area.x, area.y, area.width - sashWidth, |
| area.height); |
| sash.setVisible(true); |
| paletteContainer.setVisible(true); |
| } else if (isInState(STATE_PINNED_OPEN)) { |
| paletteContainer.setBounds(area.x + area.width - pWidth, area.y, |
| pWidth, area.height); |
| sash.setBounds(area.x + area.width - pWidth - sashWidth, area.y, |
| sashWidth, area.height); |
| graphicalControl.setBounds(area.x, area.y, area.width - sashWidth |
| - pWidth, area.height); |
| sash.setVisible(true); |
| paletteContainer.setVisible(true); |
| } |
| } |
| |
| private void layoutComponentsWest(Rectangle area, int sashWidth, int pWidth) { |
| if (isInState(STATE_COLLAPSED)) { |
| sash.setVisible(true); |
| paletteContainer.setVisible(false); |
| sash.setBounds(area.x, area.y, sashWidth, area.height); |
| graphicalControl.setBounds(area.x + sashWidth, area.y, area.width |
| - sashWidth, area.height); |
| } else if (isInState(STATE_EXPANDED)) { |
| sash.setVisible(true); |
| paletteContainer.setVisible(true); |
| paletteContainer.moveAbove(graphicalControl); |
| sash.moveAbove(paletteContainer); |
| paletteContainer.setBounds(area.x, area.y, pWidth, area.height); |
| sash.setBounds(area.x + pWidth, area.y, sashWidth, area.height); |
| graphicalControl.setBounds(area.x + sashWidth, area.y, area.width |
| - sashWidth, area.height); |
| } else if (isInState(STATE_PINNED_OPEN)) { |
| sash.setVisible(true); |
| paletteContainer.setVisible(true); |
| paletteContainer.setBounds(area.x, area.y, pWidth, area.height); |
| sash.setBounds(area.x + pWidth, area.y, sashWidth, area.height); |
| graphicalControl.setBounds(area.x + pWidth + sashWidth, area.y, |
| area.width - sashWidth - pWidth, area.height); |
| } |
| } |
| |
| private void hookIntoWorkbench(final IWorkbenchWindow window) { |
| window.addPerspectiveListener(perspectiveListener); |
| addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| window.removePerspectiveListener(perspectiveListener); |
| perspectiveListener = null; |
| } |
| }); |
| } |
| |
| private boolean restorePaletteState(PaletteViewer newPalette, IMemento state) { |
| if (state != null) { |
| try { |
| return newPalette.restoreState(state); |
| } catch (RuntimeException re) { |
| /* |
| * @TODO:Pratik You should log this exception |
| */ |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * If an external palette viewer is provided, palette state (that is |
| * captured in {@link PaletteViewer#saveState(IMemento)} -- active tool, |
| * drawer expansion state, drawer pin state, etc.) will be maintained when |
| * switching between the two viewers. Providing an external viewer, although |
| * recommended, is optional. |
| * |
| * @param viewer |
| * The palette viewer used in the PaletteView |
| */ |
| public void setExternalViewer(PaletteViewer viewer) { |
| if (viewer == null && externalViewer != null) |
| capturedPaletteState = capturePaletteState(externalViewer); |
| externalViewer = viewer; |
| if (externalViewer != null && pViewer != null) |
| transferState(pViewer, externalViewer); |
| } |
| |
| private void setDockLocation(int position) { |
| if (position != PositionConstants.EAST |
| && position != PositionConstants.WEST) |
| return; |
| if (position != dock) { |
| int oldPosition = dock; |
| dock = position; |
| listeners.firePropertyChange(PROPERTY_DOCK_LOCATION, oldPosition, |
| dock); |
| if (pViewer != null) |
| layout(true); |
| } |
| } |
| |
| private void setPaletteWidth(int newSize) { |
| if (paletteWidth != newSize) { |
| int oldValue = paletteWidth; |
| paletteWidth = newSize; |
| listeners.firePropertyChange(PROPERTY_PALETTE_WIDTH, oldValue, |
| paletteWidth); |
| if (pViewer != null) |
| layout(true); |
| } |
| } |
| |
| /** |
| * Sets the control along the side of which the palette is to be displayed. |
| * The given Control should be a child of this Composite. This method should |
| * only be invoked once. |
| * |
| * @param graphicalViewer |
| * the control of the graphical viewer; cannot be |
| * <code>null</code> |
| */ |
| public void setGraphicalControl(Control graphicalViewer) { |
| Assert.isTrue(graphicalViewer != null); |
| Assert.isTrue(graphicalViewer.getParent() == this); |
| Assert.isTrue(graphicalControl == null); |
| graphicalControl = graphicalViewer; |
| // UNSUPPORTED - api not implemented in RAP |
| // addListenerToCtrlHierarchy(graphicalControl, SWT.MouseEnter, new |
| // Listener() |
| // { |
| // public void handleEvent(Event event) |
| // { |
| // if (!isInState(STATE_EXPANDED)) |
| // return; |
| // Display.getCurrent().timerExec(250, new Runnable() |
| // { |
| // public void run() |
| // { |
| // if (isDescendantOf(graphicalControl, |
| // Display.getCurrent().getCursorControl()) && |
| // isInState(STATE_EXPANDED)) |
| // setState(STATE_COLLAPSED); |
| // } |
| // }); |
| // } |
| // }); |
| } |
| |
| /* |
| * @TODO:Pratik For 4.0, change the parameter of this method to be |
| * EditpartViewer instead of GraphicalViewer. |
| */ |
| /** |
| * This method hooks a DropTargetListener that collapses the flyout patette |
| * when the user drags something from the palette and moves the cursor to |
| * the primary viewer's control. If the auto-hide feature of the palette is |
| * to work properly when dragging, this method should be called before any |
| * other drop target listeners are added to the primary viewer. |
| * |
| * @param viewer |
| * the primary viewer |
| */ |
| public void hookDropTargetListener(GraphicalViewer viewer) { |
| viewer.addDropTargetListener(new TransferDropTargetListener() { |
| public void dragEnter(DropTargetEvent event) { |
| } |
| |
| public void dragLeave(DropTargetEvent event) { |
| } |
| |
| public void dragOperationChanged(DropTargetEvent event) { |
| } |
| |
| public void dragOver(DropTargetEvent event) { |
| } |
| |
| public void drop(DropTargetEvent event) { |
| } |
| |
| public void dropAccept(DropTargetEvent event) { |
| } |
| |
| public Transfer getTransfer() { |
| return TemplateTransfer.getInstance(); |
| } |
| |
| public boolean isEnabled(DropTargetEvent event) { |
| if (isInState(STATE_EXPANDED)) |
| setState(STATE_COLLAPSED); |
| return false; |
| } |
| }); |
| } |
| |
| /* |
| * If the given state is invalid (as could be the case when |
| * FlyoutPreferences.getPaletteState() is invoked for the first time), it |
| * will be defaulted to STATE_COLLAPSED. |
| */ |
| private void setState(int newState) { |
| /* |
| * Fix for Bug# 69617 and Bug# 81248 FlyoutPreferences.getPaletteState() |
| * could return an invalid state if none is stored. In that case, we use |
| * the default state: STATE_COLLAPSED. |
| */ |
| if (newState != STATE_HIDDEN && newState != STATE_PINNED_OPEN |
| && newState != STATE_EXPANDED) |
| newState = STATE_COLLAPSED; |
| if (paletteState == newState) |
| return; |
| int oldState = paletteState; |
| paletteState = newState; |
| switch (paletteState) { |
| case STATE_EXPANDED: |
| case STATE_COLLAPSED: |
| case STATE_PINNED_OPEN: |
| if (pViewer == null) { |
| pViewer = provider.createPaletteViewer(paletteContainer); |
| if (externalViewer != null) |
| transferState(externalViewer, pViewer); |
| else |
| restorePaletteState(pViewer, capturedPaletteState); |
| capturedPaletteState = null; |
| minWidth = Math.max(pViewer.getControl().computeSize(0, 0).x, |
| MIN_PALETTE_SIZE); |
| } |
| break; |
| case STATE_HIDDEN: |
| if (pViewer == null) |
| break; |
| if (externalViewer != null) { |
| provider.getEditDomain().setPaletteViewer(externalViewer); |
| transferState(pViewer, externalViewer); |
| } |
| if (provider.getEditDomain().getPaletteViewer() == pViewer) |
| provider.getEditDomain().setPaletteViewer(null); |
| Control pViewerCtrl = getPaletteViewerControl(); |
| if (pViewerCtrl != null && !pViewerCtrl.isDisposed()) |
| pViewerCtrl.dispose(); |
| pViewer = null; |
| } |
| /* |
| * Fix for Bug# 63901 When the flyout collapses, if the palette has |
| * focus, throw focus to the graphical control. That way, hitting ESC |
| * will still deactivate the current tool and load the default one. Note |
| * that focus is being set on RulerComposite and not GraphicalViewer's |
| * control. But this is okay since RulerComposite passes the focus on to |
| * its first child, which is the graphical viewer's control. |
| */ |
| if (paletteState == STATE_COLLAPSED |
| && pViewer.getControl().isFocusControl()) |
| graphicalControl.setFocus(); |
| layout(true); |
| listeners.firePropertyChange(PROPERTY_STATE, oldState, newState); |
| } |
| |
| private void transferState(PaletteViewer src, PaletteViewer dest) { |
| restorePaletteState(dest, capturePaletteState(src)); |
| } |
| |
| private void updateState(IWorkbenchPage page) { |
| IViewReference view = page.findViewReference(PaletteView.ID); |
| if (view == null && isInState(STATE_HIDDEN)) |
| setState(prefs.getPaletteState()); |
| if (view != null && !isInState(STATE_HIDDEN)) |
| setState(STATE_HIDDEN); |
| } |
| |
| /** |
| * FlyoutPreferences is used to save/load the preferences for the flyout |
| * palette. |
| * |
| * @author Pratik Shah |
| * @since 3.0 |
| */ |
| public interface FlyoutPreferences { |
| /** |
| * Should return {@link PositionConstants#EAST} or |
| * {@link PositionConstants#WEST}. Any other int will be ignored and the |
| * default dock location (EAST) will be used instead. |
| * |
| * @return the saved dock location of the Palette |
| */ |
| int getDockLocation(); |
| |
| /** |
| * When there is no saved state, this method can return any non-positive |
| * int (which will result in the palette using the default state -- |
| * collapsed), or {@link FlyoutPaletteComposite#STATE_COLLAPSED}, or |
| * {@link FlyoutPaletteComposite#STATE_PINNED_OPEN} |
| * |
| * @return the saved state of the palette |
| */ |
| int getPaletteState(); |
| |
| /** |
| * When there is no saved width, this method can return any int |
| * (preferrably a non-positive int). Returning a non-positive int will |
| * cause the palette to be sized to the default size, whereas returning |
| * a postive int will find the closest match in the valid range (>= |
| * minimum and <= maximum) |
| * |
| * @return the saved width of the flyout palette |
| */ |
| int getPaletteWidth(); |
| |
| /** |
| * This method is invoked when the flyout palette's dock location is |
| * changed. The provided dock location should be persisted and returned |
| * in {@link #getDockLocation()}. |
| * |
| * @param location |
| * {@link PositionConstants#EAST} or |
| * {@link PositionConstants#WEST} |
| */ |
| void setDockLocation(int location); |
| |
| /** |
| * This method is invoked when the flyout palette's state is changed |
| * (the new state becomes the default). The provided state should be |
| * persisted and returned in {@link #getPaletteState()}. |
| * |
| * @param state |
| * {@link FlyoutPaletteComposite#STATE_COLLAPSED} or |
| * {@link FlyoutPaletteComposite#STATE_PINNED_OPEN} |
| */ |
| void setPaletteState(int state); |
| |
| /** |
| * This method is invoked when the flyout palette is resized. The |
| * provided width should be persisted and returned in |
| * {@link #getPaletteWidth()}. |
| * |
| * @param width |
| * the new size of the flyout palette |
| */ |
| void setPaletteWidth(int width); |
| } |
| |
| private class Sash extends Composite { |
| private Control button; |
| private ControlPaintHandler helper; |
| |
| public Sash(Composite parent, int style) { |
| super(parent, style); |
| helper = new ControlPaintHandler(this); |
| button = createFlyoutControlButton(this); |
| new SashDragManager(); |
| // UNSUPPORTED - api not implemented in RAP |
| // addMouseTrackListener(new MouseTrackAdapter() |
| // { |
| // public void mouseHover(MouseEvent e) |
| // { |
| // if (isInState(STATE_COLLAPSED)) |
| // setState(STATE_EXPANDED); |
| // } |
| // }); |
| |
| helper.addPaintListener(new PaintListener() { |
| public void paintControl(org.eclipse.swt.events.PaintEvent event) { |
| paintSash(event.gc); |
| }; |
| }); |
| |
| addListener(SWT.Resize, new Listener() { |
| public void handleEvent(Event event) { |
| layout(true); |
| } |
| }); |
| |
| listeners.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| if (evt.getPropertyName().equals(PROPERTY_STATE)) |
| updateState(); |
| } |
| }); |
| } |
| |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| if (isInState(STATE_PINNED_OPEN)) |
| return new Point(3, 3); |
| |
| // button size plus two pixels for the two lines to be drawn |
| return new Point(SASH_BUTTON_WIDTH + 2, cachedTitleHeight); |
| } |
| |
| private void handleSashDragged(int shiftAmount) { |
| int newSize = paletteContainer.getBounds().width |
| + (dock == PositionConstants.EAST ? -shiftAmount |
| : shiftAmount); |
| setPaletteWidth(newSize); |
| } |
| |
| public void layout(boolean changed) { |
| if (button == null) |
| return; |
| |
| if (isInState(STATE_PINNED_OPEN)) { |
| button.setVisible(false); |
| return; |
| } |
| |
| button.setVisible(true); |
| Rectangle area = getClientArea(); |
| button.setBounds(area.x + 1, area.y + 1, SASH_BUTTON_WIDTH, |
| cachedTitleHeight - 1); |
| |
| if (transferFocus) { |
| transferFocus = false; |
| button.setFocus(); |
| } |
| } |
| |
| private void paintSash(GC gc) { |
| Rectangle bounds = getBounds(); |
| if (isInState(STATE_PINNED_OPEN)) { |
| gc.setBackground(PaletteColorUtil.WIDGET_BACKGROUND); |
| gc.fillRectangle(0, 0, bounds.width, bounds.height); |
| |
| gc.setForeground(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| gc.drawLine(0, 0, bounds.width, 0); |
| gc.setForeground(PaletteColorUtil.WIDGET_NORMAL_SHADOW); |
| gc.drawLine(0, bounds.height - 1, bounds.width - 1, |
| bounds.height - 1); |
| gc.setForeground(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| gc.drawLine(0, 0, 0, bounds.height); |
| gc.setForeground(PaletteColorUtil.WIDGET_NORMAL_SHADOW); |
| gc.drawLine(bounds.width - 1, 0, bounds.width - 1, |
| bounds.height - 1); |
| } else { |
| gc.setForeground(PaletteColorUtil.WIDGET_NORMAL_SHADOW); |
| gc.drawLine(0, 0, 0, bounds.height); |
| gc.drawLine(bounds.width - 1, 0, bounds.width - 1, |
| bounds.height); |
| |
| gc.setForeground(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| gc.drawLine(1, 0, 1, bounds.height); |
| |
| gc.setForeground(PaletteColorUtil.WIDGET_BACKGROUND_LIST_BACKGROUND_85); |
| gc.drawLine(2, 0, 2, bounds.height); |
| } |
| } |
| |
| private void updateState() { |
| setCursor(isInState(STATE_EXPANDED | STATE_PINNED_OPEN) ? SharedCursors.SIZEWE |
| : null); |
| } |
| |
| private class SashDragManager extends MouseAdapter implements |
| MouseMoveListener { |
| protected boolean dragging = false; |
| protected boolean correctState = false; |
| protected boolean mouseDown = false; |
| protected int origX; |
| protected Listener keyListener = new Listener() { |
| public void handleEvent(Event event) { |
| if (event.keyCode == SWT.ALT || event.keyCode == SWT.ESC) { |
| dragging = false; |
| Display.getCurrent().removeFilter(SWT.KeyDown, this); |
| } |
| event.doit = false; |
| event.type = SWT.None; |
| } |
| }; |
| |
| public SashDragManager() { |
| // UNSUPPORTED - api not implemented in RAP |
| // Sash.this.addMouseMoveListener(this); |
| Sash.this.addMouseListener(this); |
| } |
| |
| public void mouseDown(MouseEvent me) { |
| if (me.button != 1) |
| return; |
| mouseDown = true; |
| correctState = isInState(STATE_EXPANDED | STATE_PINNED_OPEN); |
| origX = me.x; |
| Display.getCurrent().addFilter(SWT.KeyDown, keyListener); |
| } |
| |
| public void mouseMove(MouseEvent me) { |
| if (mouseDown) |
| dragging = true; |
| if (dragging && correctState) |
| handleSashDragged(me.x - origX); |
| } |
| |
| public void mouseUp(MouseEvent me) { |
| Display.getCurrent().removeFilter(SWT.KeyDown, keyListener); |
| if (!dragging && me.button == 1) { |
| if (isInState(STATE_COLLAPSED)) |
| setState(STATE_EXPANDED); |
| else if (isInState(STATE_EXPANDED)) |
| setState(STATE_COLLAPSED); |
| } |
| dragging = false; |
| correctState = false; |
| mouseDown = false; |
| } |
| } |
| } |
| |
| private class ResizeAction extends Action { |
| public ResizeAction() { |
| super(PaletteMessages.RESIZE_LABEL); |
| } |
| |
| public boolean isEnabled() { |
| return !isInState(STATE_COLLAPSED); |
| } |
| |
| public void run() { |
| final Tracker tracker = new Tracker(FlyoutPaletteComposite.this, |
| SWT.RIGHT | SWT.LEFT); |
| Rectangle[] rects = new Rectangle[1]; |
| rects[0] = sash.getBounds(); |
| tracker.setCursor(SharedCursors.SIZEE); |
| tracker.setRectangles(rects); |
| if (tracker.open()) { |
| int deltaX = sash.getBounds().x - tracker.getRectangles()[0].x; |
| if (dock == PositionConstants.WEST) |
| deltaX = -deltaX; |
| setPaletteWidth(paletteContainer.getBounds().width + deltaX); |
| } |
| tracker.dispose(); |
| } |
| } |
| |
| private class TitleDragManager extends MouseAdapter implements Listener, |
| MouseTrackListener { |
| protected boolean switchDock = false; |
| protected boolean dragging = false; |
| protected int threshold; |
| |
| public TitleDragManager(Control ctrl) { |
| ctrl.addListener(SWT.DragDetect, this); |
| ctrl.addMouseListener(this); |
| // UNSUPPORTED - api not implemented in RAP |
| // ctrl.addMouseTrackListener(this); |
| } |
| |
| public void handleEvent(Event event) { |
| dragging = true; |
| switchDock = false; |
| threshold = dock == PositionConstants.EAST ? Integer.MAX_VALUE / 2 |
| : -1; |
| final Composite flyout = FlyoutPaletteComposite.this; |
| final Rectangle flyoutBounds = flyout.getBounds(); |
| final int switchThreshold = flyoutBounds.x |
| + (flyoutBounds.width / 2); |
| Rectangle bounds = sash.getBounds(); |
| if (paletteContainer.getVisible()) |
| bounds = bounds.union(paletteContainer.getBounds()); |
| final Rectangle origBounds = Display.getCurrent().map(flyout, null, |
| bounds); |
| final Tracker tracker = new Tracker(Display.getDefault(), SWT.NULL); |
| tracker.setRectangles(new Rectangle[] { origBounds }); |
| final Display display = Display.getCurrent(); |
| tracker.setStippled(true); |
| tracker.addListener(SWT.Move, new Listener() { |
| public void handleEvent(final Event evt) { |
| display.syncExec(new Runnable() { |
| public void run() { |
| Control ctrl = display.getCursorControl(); |
| Point location = display.getCursorLocation(); // evt.x, |
| // evt.y |
| Point pt = flyout.toControl(location.x, location.y); |
| switchDock = isDescendantOf(graphicalControl, ctrl) |
| && ((dock == PositionConstants.WEST && pt.x > threshold - 10) || (dock == PositionConstants.EAST && pt.x < threshold + 10)); |
| boolean invalid = false; |
| if (!switchDock) |
| invalid = !isDescendantOf( |
| FlyoutPaletteComposite.this, ctrl); |
| if (switchDock) { |
| if (dock == PositionConstants.WEST) { |
| threshold = Math.max(threshold, pt.x); |
| threshold = Math.min(threshold, |
| switchThreshold); |
| } else { |
| threshold = Math.min(threshold, pt.x); |
| threshold = Math.max(threshold, |
| switchThreshold); |
| } |
| } |
| Rectangle placeHolder = origBounds; |
| if (switchDock) { |
| if (dock == PositionConstants.EAST) |
| placeHolder = new Rectangle(0, 0, |
| origBounds.width, origBounds.height); |
| else |
| placeHolder = new Rectangle( |
| flyoutBounds.width |
| - origBounds.width, 0, |
| origBounds.width, origBounds.height); |
| placeHolder = display.map(flyout, null, |
| placeHolder); |
| } |
| // update the cursor |
| int cursor; |
| if (invalid) |
| cursor = DragCursors.INVALID; |
| else if ((!switchDock && dock == PositionConstants.EAST) |
| || (switchDock && dock == PositionConstants.WEST)) |
| cursor = DragCursors.RIGHT; |
| else |
| cursor = DragCursors.LEFT; |
| if (isMirrored()) { |
| if (cursor == DragCursors.RIGHT) |
| cursor = DragCursors.LEFT; |
| else if (cursor == DragCursors.LEFT) |
| cursor = DragCursors.RIGHT; |
| } |
| tracker.setCursor(DragCursors.getCursor(cursor)); |
| // update the rectangle only if it has changed |
| if (!tracker.getRectangles()[0].equals(placeHolder)) |
| tracker.setRectangles(new Rectangle[] { placeHolder }); |
| } |
| }); |
| } |
| }); |
| |
| // HACK for DND in RAP |
| Job dragJob = new Job("Drag-Job") { |
| protected IStatus run(IProgressMonitor monitor) { |
| |
| if (tracker.open()) { |
| |
| display.asyncExec(new Runnable() { |
| public void run() { |
| IDropTarget dropTarget = null; |
| Point finalLocation = display |
| .getCursorLocation(); |
| Control targetControl = display |
| .getCursorControl(); |
| if (switchDock) { |
| setDockLocation(PositionConstants.EAST_WEST |
| & ~dock); |
| // mouse up is received by the tracker and |
| // by this listener, so |
| // we set dragging |
| // to be false |
| dragging = false; |
| } |
| // Cleanup... |
| tracker.dispose(); |
| } |
| }); |
| } |
| return Status.OK_STATUS; |
| } |
| }; |
| dragJob.schedule(); |
| } |
| |
| public void mouseEnter(MouseEvent e) { |
| } |
| |
| public void mouseExit(MouseEvent e) { |
| } |
| |
| public void mouseHover(MouseEvent e) { |
| /* |
| * @TODO:Pratik Mouse hover events are received if the hover occurs |
| * just before you finish or cancel the drag. Open a bugzilla about |
| * it? |
| */ |
| if (isInState(STATE_COLLAPSED)) |
| setState(STATE_EXPANDED); |
| } |
| |
| public void mouseUp(MouseEvent me) { |
| if (me.button != 1) |
| return; |
| if (isInState(STATE_COLLAPSED)) |
| setState(STATE_EXPANDED); |
| else if (isInState(STATE_EXPANDED)) |
| setState(STATE_COLLAPSED); |
| } |
| } |
| |
| private class PaletteComposite extends Composite { |
| protected Control button, title; |
| |
| public PaletteComposite(Composite parent, int style) { |
| super(parent, style); |
| createComponents(); |
| |
| listeners.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| if (evt.getPropertyName().equals(PROPERTY_STATE)) |
| updateState(); |
| else if (evt.getPropertyName().equals( |
| PROPERTY_DOCK_LOCATION)) |
| if (getVisible()) |
| layout(true); |
| } |
| }); |
| |
| addListener(SWT.Resize, new Listener() { |
| public void handleEvent(Event event) { |
| layout(true); |
| } |
| }); |
| |
| updateState(); |
| } |
| |
| protected void createComponents() { |
| title = createTitle(this, true); |
| button = createFlyoutControlButton(this); |
| } |
| |
| public void layout(boolean changed) { |
| Control pCtrl = getPaletteViewerControl(); |
| if (pCtrl == null || pCtrl.isDisposed()) |
| return; |
| |
| Rectangle area = getClientArea(); |
| boolean buttonVisible = button.getVisible(); |
| Point titleSize = title.computeSize(-1, -1); |
| Point buttonSize = buttonVisible ? button.computeSize(-1, -1) |
| : new Point(0, 0); |
| cachedTitleHeight = Math.max(titleSize.y, buttonSize.y); |
| if (buttonVisible) { |
| buttonSize.x = Math.max(cachedTitleHeight, buttonSize.x); |
| } |
| if (dock == PositionConstants.EAST) { |
| int buttonX = area.width - buttonSize.x; |
| button.setBounds(buttonX, 0, buttonSize.x, cachedTitleHeight); |
| title.setBounds(0, 0, buttonX, cachedTitleHeight); |
| } else { |
| int titleX = buttonSize.x; |
| button.setBounds(0, 0, buttonSize.x, cachedTitleHeight); |
| title.setBounds(titleX, 0, area.width - titleX, |
| cachedTitleHeight); |
| } |
| area.y += cachedTitleHeight; |
| area.height -= cachedTitleHeight; |
| pCtrl.setBounds(area); |
| } |
| |
| protected void updateState() { |
| button.setVisible(isInState(STATE_PINNED_OPEN)); |
| if (transferFocus && button.getVisible()) { |
| transferFocus = false; |
| button.setFocus(); |
| } |
| layout(true); |
| } |
| } |
| |
| private static class TitleLabel extends Label { |
| protected static final Border BORDER = new MarginBorder(4, 3, 4, 3); |
| protected static final Border TOOL_TIP_BORDER = new MarginBorder(0, 2, |
| 0, 2); |
| |
| public TitleLabel(boolean isHorizontal) { |
| super(GEFMessages.Palette_Label, InternalImages |
| .get(InternalImages.IMG_PALETTE)); |
| setLabelAlignment(PositionConstants.LEFT); |
| setBorder(BORDER); |
| Label tooltip = new Label(getText()); |
| tooltip.setBorder(TOOL_TIP_BORDER); |
| setToolTip(tooltip); |
| setForegroundColor(ColorConstants.listForeground); |
| } |
| |
| public IFigure getToolTip() { |
| if (isTextTruncated()) |
| return super.getToolTip(); |
| return null; |
| } |
| |
| protected void paintFigure(Graphics graphics) { |
| |
| // paint the gradient |
| graphics.pushState(); |
| org.eclipse.draw2d.geometry.Rectangle r = org.eclipse.draw2d.geometry.Rectangle.SINGLETON; |
| r.setBounds(getBounds()); |
| graphics.setForegroundColor(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| graphics.setBackgroundColor(PaletteColorUtil.WIDGET_BACKGROUND); |
| graphics.fillGradient(r, true); |
| |
| // draw bottom border |
| graphics.setForegroundColor(PaletteColorUtil.WIDGET_NORMAL_SHADOW); |
| graphics.drawLine(r.getBottomLeft().getTranslated(0, -1), r |
| .getBottomRight().getTranslated(0, -1)); |
| |
| graphics.popState(); |
| |
| // paint the text and icon |
| super.paintFigure(graphics); |
| |
| // paint the focus rectangle around the text |
| if (hasFocus()) { |
| org.eclipse.draw2d.geometry.Rectangle textBounds = getTextBounds(); |
| // We reduce the width by 1 because FigureUtilities grows it by |
| // 1 unnecessarily |
| textBounds.width--; |
| graphics.drawFocus(bounds.getResized(-1, -1).intersect( |
| textBounds.getExpanded(getInsets()))); |
| } |
| } |
| } |
| |
| private class ButtonCanvas extends Canvas { |
| private LightweightSystem lws; |
| |
| public ButtonCanvas(Composite parent) { |
| super(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND); |
| init(); |
| provideAccSupport(); |
| } |
| |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| Dimension size = lws.getRootFigure().getPreferredSize(wHint, hHint); |
| size.union(new Dimension(wHint, hHint)); |
| return new org.eclipse.swt.graphics.Point(size.width, size.height); |
| } |
| |
| private int getArrowDirection() { |
| int direction = PositionConstants.EAST; |
| if (isInState(STATE_EXPANDED | STATE_PINNED_OPEN)) |
| direction = dock == PositionConstants.WEST ? PositionConstants.WEST |
| : PositionConstants.EAST; |
| else |
| direction = dock == PositionConstants.WEST ? PositionConstants.EAST |
| : PositionConstants.WEST; |
| if (isMirrored()) { |
| if (direction == PositionConstants.WEST) |
| direction = PositionConstants.EAST; |
| else |
| direction = PositionConstants.WEST; |
| } |
| return direction; |
| } |
| |
| private String getButtonTooltipText() { |
| if (isInState(STATE_COLLAPSED)) |
| return PaletteMessages.PALETTE_SHOW; |
| return PaletteMessages.PALETTE_HIDE; |
| } |
| |
| private void init() { |
| setCursor(SharedCursors.ARROW); |
| lws = new LightweightSystem(); |
| lws.setControl(this); |
| final ArrowButton b = new ArrowButton(getArrowDirection()); |
| b.setRolloverEnabled(true); |
| b.setBorder(new ButtonBorder(ButtonBorder.SCHEMES.TOOLBAR)); |
| b.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent event) { |
| transferFocus = true; |
| if (isInState(STATE_COLLAPSED)) |
| setState(STATE_PINNED_OPEN); |
| else |
| setState(STATE_COLLAPSED); |
| } |
| }); |
| listeners.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| if (evt.getPropertyName().equals(PROPERTY_STATE)) { |
| b.setDirection(getArrowDirection()); |
| setToolTipText(getButtonTooltipText()); |
| } else if (evt.getPropertyName().equals( |
| PROPERTY_DOCK_LOCATION)) |
| b.setDirection(getArrowDirection()); |
| } |
| }); |
| lws.setContents(b); |
| } |
| |
| private void provideAccSupport() { |
| getAccessible().addAccessibleListener(new AccessibleAdapter() { |
| public void getDescription(AccessibleEvent e) { |
| e.result = PaletteMessages.ACC_DESC_PALETTE_BUTTON; |
| } |
| |
| public void getHelp(AccessibleEvent e) { |
| getDescription(e); |
| } |
| |
| public void getName(AccessibleEvent e) { |
| e.result = getToolTipText(); |
| } |
| }); |
| getAccessible().addAccessibleControlListener( |
| new AccessibleControlAdapter() { |
| public void getRole(AccessibleControlEvent e) { |
| e.detail = ACC.ROLE_PUSHBUTTON; |
| } |
| }); |
| } |
| |
| private class ArrowButton extends Button { |
| |
| private Triangle triangle; |
| |
| /** |
| * Creates a new instance |
| * |
| * @param direction |
| * the direction the arrow should face |
| * (PositionConstants.RIGHT or PositionConstants.LEFT) |
| */ |
| public ArrowButton(int direction) { |
| super(); |
| setDirection(direction); |
| |
| triangle = new Triangle(); |
| triangle.setOutline(true); |
| triangle.setBackgroundColor(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| triangle.setForegroundColor(PaletteColorUtil.WIDGET_DARK_SHADOW); |
| setContents(triangle); |
| } |
| |
| public void setDirection(int direction) { |
| if (triangle != null) { |
| triangle.setDirection(direction); |
| } |
| } |
| |
| protected void layout() { |
| org.eclipse.draw2d.geometry.Rectangle clientArea = getBounds(); |
| |
| triangle.setBounds(new org.eclipse.draw2d.geometry.Rectangle( |
| clientArea.getCenter().getTranslated( |
| -ARROW_SIZE.width / 2, -ARROW_SIZE.height / 2), |
| ARROW_SIZE)); |
| } |
| |
| protected void paintFigure(Graphics graphics) { |
| super.paintFigure(graphics); |
| |
| // paint the gradient |
| graphics.pushState(); |
| org.eclipse.draw2d.geometry.Rectangle r = org.eclipse.draw2d.geometry.Rectangle.SINGLETON; |
| r.setBounds(getBounds()); |
| graphics.setForegroundColor(PaletteColorUtil.WIDGET_LIST_BACKGROUND); |
| graphics.setBackgroundColor(PaletteColorUtil.WIDGET_BACKGROUND); |
| graphics.fillGradient(r, true); |
| graphics.popState(); |
| |
| // draw bottom border |
| graphics.setForegroundColor(PaletteColorUtil.WIDGET_NORMAL_SHADOW); |
| graphics.drawLine(r.getBottomLeft().getTranslated(0, -1), r |
| .getBottomRight().getTranslated(0, -1)); |
| } |
| } |
| } |
| |
| private class TitleCanvas extends Canvas { |
| private LightweightSystem lws; |
| |
| public TitleCanvas(Composite parent, boolean horizontal) { |
| super(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND); |
| init(horizontal); |
| provideAccSupport(); |
| } |
| |
| /** |
| * @see org.eclipse.swt.widgets.Control#computeSize(int, int, boolean) |
| */ |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| Dimension size = lws.getRootFigure().getPreferredSize(wHint, hHint); |
| size.union(new Dimension(wHint, hHint)); |
| return new org.eclipse.swt.graphics.Point(size.width, size.height); |
| } |
| |
| private void init(boolean isHorizontal) { |
| final IFigure contents = new TitleLabel(true); |
| contents.setRequestFocusEnabled(true); |
| contents.setFocusTraversable(true); |
| contents.addFocusListener(new FocusListener() { |
| public void focusGained(FocusEvent fe) { |
| fe.gainer.repaint(); |
| } |
| |
| public void focusLost(FocusEvent fe) { |
| fe.loser.repaint(); |
| } |
| }); |
| |
| lws = new LightweightSystem(); |
| lws.setControl(this); |
| lws.setContents(contents); |
| setCursor(SharedCursors.SIZEALL); |
| FONT_MGR.register(this); |
| new TitleDragManager(this); |
| final MenuManager manager = new MenuManager(); |
| MenuManager mgr = new MenuManager(PaletteMessages.DOCK_LABEL); |
| mgr.add(new ChangeDockAction(PaletteMessages.LEFT_LABEL, |
| PositionConstants.WEST)); |
| mgr.add(new ChangeDockAction(PaletteMessages.RIGHT_LABEL, |
| PositionConstants.EAST)); |
| manager.add(new ResizeAction()); |
| manager.add(mgr); |
| setMenu(manager.createContextMenu(this)); |
| mgr.addMenuListener(new IMenuListener() { |
| public void menuAboutToShow(IMenuManager menuMgr) { |
| IContributionItem[] items = menuMgr.getItems(); |
| for (int i = 0; i < items.length; i++) { |
| ((ActionContributionItem) items[i]).update(); |
| } |
| } |
| }); |
| |
| addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| FONT_MGR.unregister(TitleCanvas.this); |
| manager.dispose(); |
| } |
| }); |
| } |
| |
| private void provideAccSupport() { |
| getAccessible().addAccessibleListener(new AccessibleAdapter() { |
| public void getDescription(AccessibleEvent e) { |
| e.result = PaletteMessages.ACC_DESC_PALETTE_TITLE; |
| } |
| |
| public void getHelp(AccessibleEvent e) { |
| getDescription(e); |
| } |
| |
| public void getName(AccessibleEvent e) { |
| e.result = GEFMessages.Palette_Label; |
| } |
| }); |
| getAccessible().addAccessibleControlListener( |
| new AccessibleControlAdapter() { |
| public void getRole(AccessibleControlEvent e) { |
| e.detail = ACC.ROLE_LABEL; |
| } |
| }); |
| } |
| |
| public void setFont(Font font) { |
| ((IFigure) lws.getRootFigure().getChildren().get(0)).setFont(font); |
| if (isVisible()) { |
| /* |
| * If this canvas is in the sash, we want the |
| * FlyoutPaletteComposite to layout (which will cause the sash |
| * to be resized and laid out). However, if this canvas is in |
| * the paletteContainer, the paletteContainer's bounds won't |
| * change, and hence it won't layout. Thus, we also invoke |
| * getParent().layout(). |
| */ |
| FlyoutPaletteComposite.this.layout(true); |
| getParent().layout(true); |
| } |
| } |
| } |
| |
| private class ChangeDockAction extends Action { |
| private int position; |
| |
| /** |
| * Constructor |
| * |
| * @param text |
| * this action's text |
| * @param position |
| * the dock side that this action represents: |
| * PositionConstants.EAST or PositionConstants.WEST |
| */ |
| public ChangeDockAction(String text, int position) { |
| super(text, IAction.AS_RADIO_BUTTON); |
| this.position = position; |
| } |
| |
| /** |
| * This Action is checked when the palette is docked on the side this |
| * action represents |
| * |
| * @see org.eclipse.jface.action.IAction#isChecked() |
| */ |
| public boolean isChecked() { |
| return dock == position; |
| } |
| |
| /** |
| * Changes the palette's dock location to the side this action |
| * represents |
| * |
| * @see org.eclipse.jface.action.IAction#run() |
| */ |
| public void run() { |
| setDockLocation(position); |
| } |
| } |
| |
| private static class FontManager { |
| private final String fontName = getFontType(); |
| private List registrants = new ArrayList(); |
| private Font titleFont; |
| private final IPropertyChangeListener fontListener = new IPropertyChangeListener() { |
| public void propertyChange( |
| org.eclipse.jface.util.PropertyChangeEvent event) { |
| if (fontName.equals(event.getProperty())) |
| handleFontChanged(); |
| } |
| }; |
| |
| private FontManager() { |
| } |
| |
| protected final Font createTitleFont() { |
| return JFaceResources.getFont(fontName); |
| } |
| |
| protected void dispose() { |
| titleFont = null; |
| JFaceResources.getFontRegistry().removeListener(fontListener); |
| } |
| |
| protected String getFontType() { |
| return JFaceResources.DIALOG_FONT; |
| } |
| |
| protected void handleFontChanged() { |
| if (titleFont == null) |
| return; |
| Font oldFont = titleFont; |
| titleFont = createTitleFont(); |
| for (Iterator iter = registrants.iterator(); iter.hasNext();) |
| ((Control) iter.next()).setFont(titleFont); |
| oldFont.dispose(); |
| } |
| |
| protected void init() { |
| titleFont = createTitleFont(); |
| JFaceResources.getFontRegistry().addListener(fontListener); |
| } |
| |
| public void register(Control ctrl) { |
| if (titleFont == null) |
| init(); |
| ctrl.setFont(titleFont); |
| registrants.add(ctrl); |
| } |
| |
| public void unregister(Control ctrl) { |
| registrants.remove(ctrl); |
| if (registrants.isEmpty()) |
| dispose(); |
| } |
| } |
| |
| /** |
| * Default implementation of FlyoutPreferences that stores the flyout |
| * palette settings in the given Preferences. |
| * |
| * @author Pratik Shah |
| * @since 3.2 |
| */ |
| private static class DefaultFlyoutPreferences implements FlyoutPreferences { |
| /* |
| * There's no need to set the default for these properties since the |
| * default-default of 0 for ints will suffice. |
| */ |
| private static final String PALETTE_DOCK_LOCATION = "org.eclipse.gef.pdock"; //$NON-NLS-1$ |
| private static final String PALETTE_SIZE = "org.eclipse.gef.psize"; //$NON-NLS-1$ |
| private static final String PALETTE_STATE = "org.eclipse.gef.pstate"; //$NON-NLS-1$ |
| |
| private Preferences prefs; |
| |
| private DefaultFlyoutPreferences(Preferences preferences) { |
| prefs = preferences; |
| } |
| |
| public int getDockLocation() { |
| return prefs.getInt(PALETTE_DOCK_LOCATION); |
| } |
| |
| public int getPaletteState() { |
| return prefs.getInt(PALETTE_STATE); |
| } |
| |
| public int getPaletteWidth() { |
| return prefs.getInt(PALETTE_SIZE); |
| } |
| |
| public void setDockLocation(int location) { |
| prefs.setValue(PALETTE_DOCK_LOCATION, location); |
| } |
| |
| public void setPaletteState(int state) { |
| prefs.setValue(PALETTE_STATE, state); |
| } |
| |
| public void setPaletteWidth(int width) { |
| prefs.setValue(PALETTE_SIZE, width); |
| } |
| } |
| |
| private static class DragCursors { |
| public static final int INVALID = 0; |
| |
| public static final int LEFT = 1; |
| |
| public static final int RIGHT = 2; |
| |
| private final static Cursor cursors[] = new Cursor[3]; |
| |
| /** |
| * Return the cursor for a drop scenario, as identified by code. Code |
| * must be one of INVALID, LEFT, RIGHT. If the code is not found default |
| * to INVALID. Note that since these three cursors are static, they will |
| * only be created once for the lifetime of the eclipse session and |
| * shared (i.e this is not an image leak). |
| * |
| * @param code |
| * the code |
| * @return the cursor |
| */ |
| public static Cursor getCursor(int code) { |
| Display display = Display.getCurrent(); |
| // UNSUPPORTED - custom cursors not available in RAP |
| // if (cursors[code] == null) { |
| // ImageDescriptor source = null; |
| // ImageDescriptor mask = null; |
| // switch (code) { |
| // case LEFT: |
| // source = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_LEFT_SOURCE); |
| // mask = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_LEFT_MASK); |
| // cursors[LEFT] = new Cursor(display, source.getImageData(), |
| // mask.getImageData(), 16, 16); |
| // break; |
| // case RIGHT: |
| // source = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_RIGHT_SOURCE); |
| // mask = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_RIGHT_MASK); |
| // cursors[RIGHT] = new Cursor(display, source.getImageData(), |
| // mask.getImageData(), 16, 16); |
| // break; |
| // default: |
| // case INVALID: |
| // source = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_INVALID_SOURCE); |
| // mask = PlatformUI |
| // .getWorkbench() |
| // .getSharedImages() |
| // .getImageDescriptor( |
| // ISharedImages.IMG_OBJS_DND_INVALID_MASK); |
| // cursors[INVALID] = new Cursor(display, |
| // source.getImageData(), mask.getImageData(), 16, 16); |
| // break; |
| // } |
| // } |
| // return cursors[code]; |
| return null; |
| } |
| |
| } |
| } |