/******************************************************************************* * 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); } } }