blob: 017cba8effd41c84ceb120d77a88388117dd968f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.gef.ui.parts;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.draw2d.ExclusionSearch;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.rap.swt.SWT;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.ExposeHelper;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.Handle;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.MouseWheelHandler;
import org.eclipse.gef.MouseWheelHelper;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.editparts.LayerManager;
import org.eclipse.gef.editparts.ScalableRootEditPart;
/**
* An EditPartViewer implementation based on {@link org.eclipse.draw2d.IFigure
* Figures}.
*
* @author hudsonr
*/
public class GraphicalViewerImpl extends AbstractEditPartViewer implements
GraphicalViewer {
private final LightweightSystem lws = createLightweightSystem();
IFigure rootFigure;
private DomainEventDispatcher eventDispatcher;
private FocusListener lFocus;
/**
* Constructs a GraphicalViewerImpl with the default root editpart.
*/
public GraphicalViewerImpl() {
createDefaultRoot();
setProperty(MouseWheelHandler.KeyGenerator.getKey(SWT.NONE),
MouseWheelDelegateHandler.SINGLETON);
}
/**
* @see org.eclipse.gef.EditPartViewer#createControl(org.eclipse.swt.widgets.Composite)
*/
public Control createControl(Composite composite) {
setControl(new Canvas(composite, SWT.NO_BACKGROUND));
return getControl();
}
/**
* Creates the default root editpart. Called during construction.
*/
protected void createDefaultRoot() {
setRootEditPart(new ScalableRootEditPart());
}
/**
* Creates the lightweight system used to host figures. Subclasses should
* not need to override this method.
*
* @return the lightweight system
*/
protected LightweightSystem createLightweightSystem() {
return new LightweightSystem();
}
/**
* @see AbstractEditPartViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
*/
protected void handleDispose(DisposeEvent e) {
super.handleDispose(e);
getLightweightSystem().getUpdateManager().dispose();
}
/**
* This method is invoked when this viewer's control gains focus. It gives
* focus to the {@link AbstractEditPartViewer#focusPart focusPart}, if there
* is one.
*
* @param fe
* the focusEvent received by this viewer's control
*/
protected void handleFocusGained(FocusEvent fe) {
if (focusPart != null)
focusPart.setFocus(true);
}
/**
* This method is invoked when this viewer's control loses focus. It removes
* focus from the {@link AbstractEditPartViewer#focusPart focusPart}, if
* there is one.
*
* @param fe
* the focusEvent received by this viewer's control
*/
protected void handleFocusLost(FocusEvent fe) {
if (focusPart != null)
focusPart.setFocus(false);
}
/**
* @see GraphicalViewer#findHandleAt(org.eclipse.draw2d.geometry.Point)
*/
public Handle findHandleAt(Point p) {
LayerManager layermanager = (LayerManager) getEditPartRegistry().get(
LayerManager.ID);
if (layermanager == null)
return null;
List list = new ArrayList(3);
list.add(layermanager.getLayer(LayerConstants.PRIMARY_LAYER));
list.add(layermanager.getLayer(LayerConstants.CONNECTION_LAYER));
list.add(layermanager.getLayer(LayerConstants.FEEDBACK_LAYER));
IFigure handle = getLightweightSystem().getRootFigure()
.findFigureAtExcluding(p.x, p.y, list);
if (handle instanceof Handle)
return (Handle) handle;
return null;
}
/**
* @see EditPartViewer#findObjectAtExcluding(Point, Collection,
* EditPartViewer.Conditional)
*/
public EditPart findObjectAtExcluding(Point pt, Collection exclude,
final Conditional condition) {
class ConditionalTreeSearch extends ExclusionSearch {
ConditionalTreeSearch(Collection coll) {
super(coll);
}
public boolean accept(IFigure figure) {
EditPart editpart = null;
while (editpart == null && figure != null) {
editpart = (EditPart) getVisualPartMap().get(figure);
figure = figure.getParent();
}
return editpart != null
&& (condition == null || condition.evaluate(editpart));
}
}
IFigure figure = getLightweightSystem().getRootFigure().findFigureAt(
pt.x, pt.y, new ConditionalTreeSearch(exclude));
EditPart part = null;
while (part == null && figure != null) {
part = (EditPart) getVisualPartMap().get(figure);
figure = figure.getParent();
}
if (part == null)
return getContents();
return part;
}
/**
* Flushes and pending layouts and paints in the lightweight system.
*
* @see org.eclipse.gef.EditPartViewer#flush()
*/
public void flush() {
getLightweightSystem().getUpdateManager().performUpdate();
}
/**
* Returns the event dispatcher
*
* @deprecated This method should not be called by subclasses
* @return the event dispatcher
*/
protected DomainEventDispatcher getEventDispatcher() {
return eventDispatcher;
}
/**
* Convenience method for finding the layer manager.
*
* @return the LayerManager
*/
protected LayerManager getLayerManager() {
return (LayerManager) getEditPartRegistry().get(LayerManager.ID);
}
/**
* Returns the lightweight system.
*
* @return the system
*/
protected LightweightSystem getLightweightSystem() {
return lws;
}
/**
* Returns the root figure
*
* @deprecated There is no reason to call this method $TODO delete this
* method
* @return the root figure
*/
protected IFigure getRootFigure() {
return rootFigure;
}
/**
* Extended to flush paints during drop callbacks.
*
* @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#hookDropTarget()
*/
protected void hookDropTarget() {
// Allow the real drop targets to make their changes first.
super.hookDropTarget();
// Then force and update since async paints won't occurs during a Drag
// operation
getDropTarget().addDropListener(new DropTargetAdapter() {
public void dragEnter(DropTargetEvent event) {
flush();
}
public void dragLeave(DropTargetEvent event) {
flush();
}
public void dragOver(DropTargetEvent event) {
flush();
}
});
}
/**
* Extended to tell the lightweight system what its control is.
*
* @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#hookControl()
*/
protected void hookControl() {
super.hookControl();
Control control = getControl();
Object innerCanvas = control.getData(Canvas.class.getName());
if (innerCanvas instanceof Canvas) {
control = (Canvas) innerCanvas;
}
getLightweightSystem().setControl((Canvas) control);
control.addFocusListener(lFocus = new FocusListener() {
public void focusGained(FocusEvent e) {
handleFocusGained(e);
}
public void focusLost(FocusEvent e) {
handleFocusLost(e);
}
});
}
/**
* Registers the accessible editpart with the event dispatcher.
*
* @param acc
* the accessible
*/
public void registerAccessibleEditPart(AccessibleEditPart acc) {
Assert.isNotNull(acc);
DomainEventDispatcher domainEventDispatcher = getEventDispatcher();
if (domainEventDispatcher != null) {
domainEventDispatcher.putAccessible(acc);
}
}
/**
* Reveals the specified editpart by using {@link ExposeHelper}s. A
* bottom-up scan through the parent-chain is performed, looking for expose
* helpers along the way, and asking them to expose the given editpart.
*
* @see org.eclipse.gef.EditPartViewer#reveal(EditPart)
*/
public void reveal(EditPart part) {
if (part == null)
return;
EditPart current = part.getParent();
while (current != null) {
ExposeHelper helper = (ExposeHelper) current
.getAdapter(ExposeHelper.class);
if (helper != null)
helper.exposeDescendant(part);
current = current.getParent();
}
AccessibleEditPart acc = (AccessibleEditPart) part
.getAdapter(AccessibleEditPart.class);
if (acc != null)
getControl().getAccessible().setFocus(acc.getAccessibleID());
}
/**
* Extended implementation to flush the viewer as the context menu is shown.
*
* @see EditPartViewer#setContextMenu(org.eclipse.jface.action.MenuManager)
*/
public void setContextMenu(MenuManager contextMenu) {
super.setContextMenu(contextMenu);
if (contextMenu != null)
contextMenu.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
flush();
}
});
}
/**
* @see org.eclipse.gef.EditPartViewer#setCursor(org.eclipse.swt.graphics.Cursor)
*/
public void setCursor(Cursor newCursor) {
if (getEventDispatcher() != null)
getEventDispatcher().setOverrideCursor(newCursor);
}
/**
* Extends the drag source to handle figures which handle MouseDown events,
* thereby aborting any DragDetect callbacks.
*
* @see AbstractEditPartViewer#setDragSource(org.eclipse.swt.dnd.DragSource)
*/
protected void setDragSource(DragSource source) {
super.setDragSource(source);
class TheLastListener extends DragSourceAdapter {
public void dragStart(DragSourceEvent event) {
// If the EventDispatcher has captured the mouse, don't perform
// native drag.
if (getEventDispatcher().isCaptured())
event.doit = false;
if (event.doit) {
// A drag is going to occur, tell the EditDomain
getEventDispatcher().dispatchNativeDragStarted(event,
GraphicalViewerImpl.this);
/*
* The mouse down that came before the dragstart, or the
* dragstart event itself, may have caused selection or
* something that needs to be painted. paints will not get
* processed during DND, so flush.
*/
flush();
}
}
public void dragFinished(DragSourceEvent event) {
getEventDispatcher().dispatchNativeDragFinished(event,
GraphicalViewerImpl.this);
}
}
/*
* The DragSource may be set to null if there are no listeners. If there
* are listeners, this should be *the* last listener because all other
* listeners are hooked in super().
*/
if (source != null)
getDragSource().addDragListener(new TheLastListener());
}
/**
* @see org.eclipse.gef.EditPartViewer#setEditDomain(org.eclipse.gef.EditDomain)
*/
public void setEditDomain(EditDomain domain) {
super.setEditDomain(domain);
// Set the new event dispatcher, even if the new domain is null. This
// will dispose
// the old event dispatcher.
getLightweightSystem().setEventDispatcher(
eventDispatcher = new DomainEventDispatcher(domain, this));
}
/**
* @see org.eclipse.gef.EditPartViewer#setRootEditPart(org.eclipse.gef.RootEditPart)
*/
public void setRootEditPart(RootEditPart editpart) {
super.setRootEditPart(editpart);
setRootFigure(((GraphicalEditPart) editpart).getFigure());
}
/**
* Sets the lightweight system's root figure.
*
* @param figure
* the root figure
*/
protected void setRootFigure(IFigure figure) {
rootFigure = figure;
getLightweightSystem().setContents(rootFigure);
}
/**
* @see org.eclipse.gef.EditPartViewer#setRouteEventsToEditDomain(boolean)
*/
public void setRouteEventsToEditDomain(boolean value) {
getEventDispatcher().setRouteEventsToEditor(value);
}
/**
* @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#unhookControl()
*/
protected void unhookControl() {
super.unhookControl();
if (lFocus != null) {
getControl().removeFocusListener(lFocus);
lFocus = null;
}
}
/**
* @see EditPartViewer#unregisterAccessibleEditPart(org.eclipse.gef.AccessibleEditPart)
*/
public void unregisterAccessibleEditPart(AccessibleEditPart acc) {
Assert.isNotNull(acc);
DomainEventDispatcher domainEventDispatcher = getEventDispatcher();
if (domainEventDispatcher != null) {
domainEventDispatcher.removeAccessible(acc);
}
}
private static class MouseWheelDelegateHandler implements MouseWheelHandler {
private static final MouseWheelHandler SINGLETON = new MouseWheelDelegateHandler();
private MouseWheelDelegateHandler() {
}
/**
* Delegates handling to the selected editpart's MouseWheelHelper.
*
* @see org.eclipse.gef.MouseWheelHandler#handleMouseWheel(org.eclipse.swt.widgets.Event,
* org.eclipse.gef.EditPartViewer)
*/
public void handleMouseWheel(Event event, EditPartViewer viewer) {
EditPart part = viewer.getFocusEditPart();
do {
MouseWheelHelper helper = (MouseWheelHelper) part
.getAdapter(MouseWheelHelper.class);
if (helper != null)
helper.handleMouseWheelScrolled(event);
part = part.getParent();
} while (event.doit && part != null);
}
}
}