blob: ac4164e3a34693487120b9df6cb33a68c2965905 [file] [log] [blame]
/******************************************************************************
* 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;
}
}