| /****************************************************************************** |
| * Copyright (c) 2005, 2008 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.gmf.runtime.diagram.ui.editpolicies; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.draw2d.MouseEvent; |
| import org.eclipse.draw2d.MouseMotionListener; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.EditPartListener; |
| import org.eclipse.gef.editpolicies.GraphicalEditPolicy; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.progress.UIJob; |
| |
| /** |
| * Encapsulates behavior common to editpolicies that popup diagram assistants. |
| * |
| * @author cmahoney |
| */ |
| public abstract class DiagramAssistantEditPolicy |
| extends GraphicalEditPolicy |
| implements MouseMotionListener { |
| |
| /** |
| * The <code>Job</code> used to show the diagram assistant after a certain |
| * amount of time has passed. |
| */ |
| private class ShowDiagramAssistantJob |
| extends UIJob { |
| |
| /** the mouse location when the job was created */ |
| private Point originalMouseLocation; |
| |
| /** |
| * Creates a new instance. |
| */ |
| protected ShowDiagramAssistantJob() { |
| super("Show Diagram Assistant"); //$NON-NLS-1$ |
| setSystem(true); |
| } |
| |
| /** |
| * Sets mouse location |
| * |
| * @param originalMouseLocation |
| * the current mouse location |
| */ |
| public void setOriginalMouseLocation(Point originalMouseLocation) { |
| this.originalMouseLocation = originalMouseLocation; |
| } |
| |
| /** |
| * The diagram assistant added when this task is run if the mouse is |
| * still at the same spot where it was when the timer was started (i.e. |
| * only add the diagram assistant when the user stops moving the mouse). |
| */ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| if (originalMouseLocation != null |
| && originalMouseLocation.equals(getMouseLocation())) { |
| if (isDiagramAssistantShowing() |
| && !shouldAvoidHidingDiagramAssistant()) { |
| hideDiagramAssistant(); |
| } |
| if (shouldShowDiagramAssistant()) { |
| |
| // Cancel the hide diagram assistant job for this host if it |
| // is waiting to run. |
| hideDiagramAssistantJob.cancel(); |
| |
| // Schedule any hide diagram assistant jobs on other |
| // editparts to run immediately to avoid duplicate diagram |
| // assistants showing. |
| if (getDiagramAssistantID() != null) { |
| Job.getJobManager().wakeUp(getDiagramAssistantID()); |
| } |
| |
| showDiagramAssistant(originalMouseLocation); |
| } |
| } |
| return Status.OK_STATUS; |
| } |
| } |
| |
| /** |
| * The <code>Job</code> used to hide the diagram assistant after a certain |
| * amount of time has passed. |
| */ |
| private class HideDiagramAssistantJob |
| extends UIJob { |
| |
| protected HideDiagramAssistantJob() { |
| super("Hide Diagram Assistant"); //$NON-NLS-1$ |
| setSystem(true); |
| } |
| |
| /** |
| * The diagram assistant is removed when this task is run if the mouse |
| * is still outside the shape. |
| */ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| if (getMouseLocation() == null |
| || !shouldAvoidHidingDiagramAssistant()) { |
| hideDiagramAssistant(); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| public boolean belongsTo(Object family) { |
| return family == getDiagramAssistantID(); |
| } |
| } |
| |
| /** |
| * Listens to the focus events on the owner editpart so that the diagram |
| * assistant can be added when the space bar is pressed. I tried to use |
| * IFigure.addFocusListener(), but the figure isn't getting any focus change |
| * events when the space bar is pressed. |
| */ |
| private class FocusListener |
| extends EditPartListener.Stub { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.gef.EditPartListener#selectedStateChanged(org.eclipse.gef.EditPart) |
| */ |
| public void selectedStateChanged(EditPart part) { |
| if (part.hasFocus() && shouldShowDiagramAssistant()) { |
| showDiagramAssistant(getMouseLocation()); |
| } else { |
| hideDiagramAssistant(); |
| } |
| } |
| } |
| |
| /** |
| * The amount of time to wait before showing the diagram assistant. |
| */ |
| private static final int APPEARANCE_DELAY = 200; |
| |
| /** |
| * The amount of time to wait before hiding the diagram assistant after it |
| * has been made visible. |
| */ |
| private static final int DISAPPEARANCE_DELAY = 2000; |
| |
| /** |
| * The amount of time to wait before hiding the diagram assistant after the |
| * user has moved the mouse outside of the editpart. |
| */ |
| private static final int DISAPPEARANCE_DELAY_UPON_EXIT = 1000; |
| |
| /** |
| * The current mouse location within the host used to determine where the |
| * diagram assistant should be displayed. This will be null if the mouse is |
| * outside the host and diagram assistant figure. |
| */ |
| private Point mouseLocation; |
| |
| /** Listens to focus change events on the host editpart. */ |
| private FocusListener focusListener = new FocusListener(); |
| |
| /** Flag to indicate that the diagram assistant should not be hidden. */ |
| private boolean avoidHidingDiagramAssistant = true; |
| |
| private ShowDiagramAssistantJob showDiagramAssistantJob = new ShowDiagramAssistantJob(); |
| |
| private HideDiagramAssistantJob hideDiagramAssistantJob = new HideDiagramAssistantJob(); |
| |
| /** |
| * Creates a new instance. |
| */ |
| public DiagramAssistantEditPolicy() { |
| super(); |
| } |
| |
| /** |
| * Checks if the object is or is part of the diagram assistant figure. This |
| * is used to determine if the mouse is hovering over the diagram assistant. |
| * |
| * @param object |
| * the object in question |
| * @return True if the object in question is or is part of the diagram |
| * assistant figure; false otherwise. |
| */ |
| protected abstract boolean isDiagramAssistant(Object object); |
| |
| /** |
| * Returns true if the diagram assistant is currently showing; false |
| * otherwise. This is used to determine if the diagram assistant should be |
| * shown or hidden at a given point in time. |
| * |
| * @return true if the diagram assistant is showing; false otherwise |
| */ |
| protected abstract boolean isDiagramAssistantShowing(); |
| |
| /** |
| * Shows the diagram assistant figure(s). |
| * |
| * @param referencePoint |
| * The reference point which may be used to determine where the |
| * diagram assistant should be located. This is most likely the |
| * current mouse location. This could be null, for example, when |
| * the host gains focus via the space bar, in which case the |
| * diagram assistant should be shown in a default location. |
| */ |
| protected abstract void showDiagramAssistant(Point referencePoint); |
| |
| /** |
| * Hides the diagram assistant figure(s). |
| */ |
| protected abstract void hideDiagramAssistant(); |
| |
| /** |
| * Returns true if the diagram assistant should be shown; false otherwise. |
| * This can be overridden to check any other conditions which must be met |
| * prior to showing the diagram assistant. |
| * |
| * @return true if the diagram assistant should be shown; false otherwise. |
| */ |
| protected boolean shouldShowDiagramAssistant() { |
| return getHost().isActive() && isPreferenceOn() && isHostEditable() |
| && isHostResolvable() && isDiagramPartActive(); |
| } |
| |
| /** |
| * Returns true if the preference to show this diagram assistant is on or if |
| * there is no applicable preference; false otherwise. |
| */ |
| protected boolean isPreferenceOn() { |
| String prefName = getPreferenceName(); |
| if (prefName == null) { |
| return true; |
| } |
| IPreferenceStore preferenceStore = (IPreferenceStore) ((IGraphicalEditPart) getHost()) |
| .getDiagramPreferencesHint().getPreferenceStore(); |
| return preferenceStore.getBoolean(prefName); |
| } |
| |
| /** |
| * The preference name indicating if the preference should be on or off. |
| * This preference must be a boolean preference stored in the diagram |
| * preferences. |
| * |
| * @return the preference name if applicable; null otherwise |
| */ |
| String getPreferenceName() { |
| return null; |
| } |
| |
| /** |
| * Checks if the host editpart is editable. |
| * |
| * @return True if the host is editable; false otherwise. |
| */ |
| private boolean isHostEditable() { |
| if (getHost() instanceof GraphicalEditPart) { |
| return ((GraphicalEditPart) getHost()).isEditModeEnabled(); |
| } |
| return true; |
| } |
| |
| /** |
| * Is the host's semantic reference resolvable (if applicable)? |
| * |
| * @return true if the semantic reference is resolvable, true if there is no |
| * semantic reference, and false otherwise |
| */ |
| private boolean isHostResolvable() { |
| final View view = (View) getHost().getModel(); |
| EObject element = view.getElement(); |
| if (element != null) { |
| return !element.eIsProxy(); |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Checks if the diagram part is active. |
| * |
| * @return True if the diagram part is active; false otherwise. |
| */ |
| private boolean isDiagramPartActive() { |
| IWorkbenchWindow window = PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow(); |
| |
| if (window != null) { |
| IWorkbenchPage page = window.getActivePage(); |
| if (page != null) { |
| IWorkbenchPart activePart = page.getActivePart(); |
| if (activePart instanceof IDiagramWorkbenchPart) { |
| return ((IDiagramWorkbenchPart) activePart) |
| .getDiagramEditPart().getRoot().equals( |
| ((IGraphicalEditPart) getHost()).getRoot()); |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Shows the diagram assistant after a certain amount of time has passed. |
| * |
| * @param delay |
| * the delay in milliseconds |
| */ |
| protected void showDiagramAssistantAfterDelay(int delay) { |
| if (delay >= 0) { |
| showDiagramAssistantJob.setOriginalMouseLocation(getMouseLocation()); |
| showDiagramAssistantJob.cancel(); |
| showDiagramAssistantJob.schedule(delay); |
| } |
| } |
| |
| /** |
| * Hides the diagram assistant after a certain amount of time has passed. |
| * |
| * @param delay |
| * the delay in milliseconds |
| */ |
| protected void hideDiagramAssistantAfterDelay(int delay) { |
| if (isDiagramAssistantShowing() && delay >= 0) { |
| hideDiagramAssistantJob.cancel(); |
| hideDiagramAssistantJob.schedule(delay); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.gef.editpolicies.AbstractEditPolicy#activate() |
| */ |
| public void activate() { |
| super.activate(); |
| ((IGraphicalEditPart) getHost()).getFigure().addMouseMotionListener( |
| this); |
| ((IGraphicalEditPart) getHost()).addEditPartListener(focusListener); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.gef.editpolicies.AbstractEditPolicy#deactivate() |
| */ |
| public void deactivate() { |
| ((IGraphicalEditPart) getHost()).getFigure().removeMouseMotionListener( |
| this); |
| ((IGraphicalEditPart) getHost()).removeEditPartListener(focusListener); |
| |
| hideDiagramAssistant(); |
| |
| super.deactivate(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.MouseMotionListener#mouseEntered(org.eclipse.draw2d.MouseEvent) |
| */ |
| public void mouseEntered(MouseEvent me) { |
| setMouseLocation(me.getLocation()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.MouseMotionListener#mouseExited(org.eclipse.draw2d.MouseEvent) |
| */ |
| public void mouseExited(MouseEvent me) { |
| setMouseLocation(null); |
| hideDiagramAssistantAfterDelay(getDisappearanceDelayUponExit()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.MouseMotionListener#mouseMoved(org.eclipse.draw2d.MouseEvent) |
| */ |
| public void mouseMoved(MouseEvent me) { |
| setMouseLocation(me.getLocation()); |
| |
| // do not hide the diagram assistant if the user is hovering over it |
| setAvoidHidingDiagramAssistant(isDiagramAssistant(me.getSource())); |
| |
| showDiagramAssistantAfterDelay(getAppearanceDelay()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.MouseMotionListener#mouseHover(org.eclipse.draw2d.MouseEvent) |
| */ |
| public void mouseHover(MouseEvent me) { |
| // do nothing |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.MouseMotionListener#mouseDragged(org.eclipse.draw2d.MouseEvent) |
| */ |
| public void mouseDragged(MouseEvent me) { |
| // do nothing |
| } |
| |
| /** |
| * Gets the amount of time to wait before showing the diagram assistant. |
| * |
| * @return the time to wait in milliseconds |
| */ |
| protected int getAppearanceDelay() { |
| return APPEARANCE_DELAY; |
| } |
| |
| /** |
| * Gets the amount of time to wait before hiding the diagram assistant after |
| * it has been made visible. |
| * |
| * @return the time to wait in milliseconds |
| */ |
| protected int getDisappearanceDelay() { |
| return DISAPPEARANCE_DELAY; |
| } |
| |
| /** |
| * Gets the amount of time to wait before hiding the diagram assistant after |
| * the user has moved the mouse outside of the editpart. |
| * |
| * @return the time to wait in milliseconds |
| */ |
| protected int getDisappearanceDelayUponExit() { |
| return DISAPPEARANCE_DELAY_UPON_EXIT; |
| } |
| |
| /** |
| * Gets the current mouse location. This will be null if the mouse is |
| * outside the host and diagram assistant figure. |
| * |
| * @return Returns the current mouse location |
| */ |
| protected Point getMouseLocation() { |
| return mouseLocation; |
| } |
| |
| /** |
| * Sets the current mouse location. If set to null, this implies that the |
| * mouse is outside the host and diagram assistant figure. |
| * |
| * @param mouseLocation |
| * the current mouse location |
| */ |
| protected void setMouseLocation(Point mouseLocation) { |
| this.mouseLocation = mouseLocation; |
| } |
| |
| /** |
| * Sets the flag to indicate that the diagram assistant should not be |
| * hidden. |
| * |
| * @param avoidHidingDiagramAssistant |
| * Flag to indicate that the diagram assistant should not be |
| * hidden |
| */ |
| protected void setAvoidHidingDiagramAssistant(boolean avoidHidingDiagramAssistant) { |
| this.avoidHidingDiagramAssistant = avoidHidingDiagramAssistant; |
| } |
| |
| /** |
| * Returns true if the diagram assistant should not be hidden; false |
| * otherwise. |
| * |
| * @return true if the diagram assistant should not be hidden; false |
| * otherwise. |
| */ |
| protected boolean shouldAvoidHidingDiagramAssistant() { |
| return avoidHidingDiagramAssistant; |
| } |
| |
| /** |
| * Gets an ID string used to identify the diagram assistant classification. |
| * This ID should be the same string for all instances of a particular type |
| * of diagram assistant. One use of this ID is to avoid having multiple |
| * diagram assistants of the same type showing at the same time on different |
| * editparts. A good ID string would be the class's name (e.g. |
| * ConnectionHandleEditPolicy.class.getName()). |
| * |
| * @return a unique string for a diagram assistant type or null |
| */ |
| protected String getDiagramAssistantID() { |
| return null; |
| } |
| |
| } |