/*******************************************************************************
* Copyright (c) 2000, 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.gef.ui.parts;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.swt.SWT;
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.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.ExclusionSearch;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.geometry.Point;
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();
getLightweightSystem().setControl((Canvas)getControl());
getControl().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);
}
}
}