blob: 487719d6b1933bf66581efa848d36d3a22105a91 [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.draw2d;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleControlListener;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.accessibility.AccessibleListener;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
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.ui.presentations.PresentationUtil;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
/**
* The LightweightSystem is the link between SWT and Draw2d. It is the component
* that provides the ability for {@link Figure Figures} to be hosted on an SWT
* Canvas.
* <p>
* Normal procedure for using a LightweightSystem:
* <ol>
* <li>Create an SWT Canvas.
* <li>Create a LightweightSystem passing it that Canvas.
* <li>Create a Draw2d Figure and call setContents(IFigure). This Figure will be
* the top-level Figure of the Draw2d application.
* </ol>
*/
public class LightweightSystem {
private Canvas canvas;
IFigure contents;
private IFigure root;
private EventDispatcher dispatcher;
private UpdateManager manager = new DeferredUpdateManager();
private int ignoreResize;
private RAPDragTracker tracker;
/**
* Constructs a LightweightSystem on Canvas <i>c</i>.
*
* @param c
* the canvas
* @since 2.0
*/
public LightweightSystem(Canvas c) {
this();
setControl(c);
}
/**
* Constructs a LightweightSystem <b>without</b> a Canvas.
*/
public LightweightSystem() {
init();
}
/**
* Adds SWT listeners to the LightWeightSystem's Canvas. This allows for SWT
* events to be dispatched and handled by its {@link EventDispatcher}.
* <P>
* <EM>WARNING:</EM> This method should not be overridden.
*
* @since 2.0
*/
protected void addListeners() {
final EventHandler handler = createEventHandler();
canvas.getAccessible().addAccessibleListener(handler);
canvas.getAccessible().addAccessibleControlListener(handler);
canvas.addMouseListener(handler);
// UNSUPPORTED - api not implemented in RAP
// canvas.addMouseMoveListener(handler);
// canvas.addMouseTrackListener(handler);
canvas.addKeyListener(handler);
canvas.addTraverseListener(handler);
canvas.addFocusListener(handler);
canvas.addDisposeListener(handler);
// HACK: for DND in RAP
PresentationUtil.addDragListener(canvas, handler);
DragSource dragSource = new DragSource(canvas, DND.DROP_MOVE
| DND.DROP_COPY | DND.DROP_LINK);
final DragSourceListener listener = new DragSourceListener() {
public void dragStart(DragSourceEvent event) {
tracker = new RAPDragTracker(handler, canvas);
tracker.open();
}
public void dragSetData(DragSourceEvent event) {
}
public void dragFinished(DragSourceEvent event) {
if (tracker != null) {
tracker.close();
tracker = null;
}
}
};
dragSource.addDragListener(listener);
canvas.addListener(org.eclipse.draw2d.rap.swt.SWT.MouseWheel, handler);
canvas.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
LightweightSystem.this.controlResized();
}
});
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
LightweightSystem.this.paint(event.gc);
}
});
}
/**
* Resizes and revalidates the root figure when the control is resized.
*/
protected void controlResized() {
if (ignoreResize > 0)
return;
Rectangle r = new Rectangle(canvas.getClientArea());
r.setLocation(0, 0);
root.setBounds(r);
root.revalidate();
getUpdateManager().performUpdate();
}
/**
* Returns this LightwightSystem's EventDispatcher.
*
* @return the event dispatcher
* @since 2.0
*/
protected EventDispatcher getEventDispatcher() {
if (dispatcher == null)
setEventDispatcher(new SWTEventDispatcher());
return dispatcher;
}
/**
* Returns this LightweightSystem's root figure.
*
* @return the root figure
* @since 2.0
*/
public IFigure getRootFigure() {
return root;
}
/**
* Returns a new instance of this LightweightSystem's EventHandler.
*
* @return the newly created event handler
* @since 2.0
*/
protected final EventHandler createEventHandler() {
return internalCreateEventHandler();
}
/**
* Creates and returns the root figure.
*
* @return the newly created root figure
*/
protected RootFigure createRootFigure() {
RootFigure f = new RootFigure();
f.addNotify();
f.setOpaque(true);
f.setLayoutManager(new StackLayout());
return f;
}
/**
* Returns this LightweightSystem's UpdateManager.
*
* @return the update manager
* @since 2.0
*/
public UpdateManager getUpdateManager() {
return manager;
}
/**
* Initializes this LightweightSystem by setting the root figure.
*/
protected void init() {
setRootPaneFigure(createRootFigure());
}
EventHandler internalCreateEventHandler() {
return new EventHandler();
}
/**
* Invokes this LightweightSystem's {@link UpdateManager} to paint this
* LightweightSystem's Canvas and contents.
*
* @param gc
* the GC used for painting
* @since 2.0
*/
public void paint(GC gc) {
getUpdateManager().paint(gc);
}
/**
* Sets the contents of the LightweightSystem to the passed figure. This
* figure should be the top-level Figure in a Draw2d application.
*
* @param figure
* the new root figure
* @since 2.0
*/
public void setContents(IFigure figure) {
if (contents != null)
root.remove(contents);
contents = figure;
root.add(contents);
}
/**
* Sets the LightweightSystem's control to the passed Canvas.
*
* @param c
* the canvas
* @since 2.0
*/
public void setControl(Canvas c) {
if (canvas == c)
return;
canvas = c;
if ((c.getStyle() & SWT.DOUBLE_BUFFERED) != 0)
getUpdateManager().setGraphicsSource(
new NativeGraphicsSource(canvas));
else
getUpdateManager().setGraphicsSource(
new BufferedGraphicsSource(canvas));
getEventDispatcher().setControl(c);
addListeners();
// Size the root figure and contents to the current control's size
Rectangle r = new Rectangle(canvas.getClientArea());
r.setLocation(0, 0);
root.setBounds(r);
root.revalidate();
}
/**
* Sets this LightweightSystem's EventDispatcher.
*
* @param dispatcher
* the new event dispatcher
* @since 2.0
*/
public void setEventDispatcher(EventDispatcher dispatcher) {
this.dispatcher = dispatcher;
dispatcher.setRoot(root);
dispatcher.setControl(canvas);
}
void setIgnoreResize(boolean value) {
if (value)
ignoreResize++;
else
ignoreResize--;
}
/**
* Sets this LightweightSystem's root figure.
*
* @param root
* the new root figure
*/
protected void setRootPaneFigure(RootFigure root) {
getUpdateManager().setRoot(root);
this.root = root;
}
/**
* Sets this LightweightSystem's UpdateManager.
*
* @param um
* the new update manager
* @since 2.0
*/
public void setUpdateManager(UpdateManager um) {
manager = um;
manager.setRoot(root);
}
/**
* The figure at the root of the LightweightSystem. If certain properties
* (i.e. font, background/foreground color) are not set, the RootFigure will
* obtain these properties from LightweightSystem's Canvas.
*/
protected class RootFigure extends Figure {
/** @see IFigure#getBackgroundColor() */
public Color getBackgroundColor() {
if (bgColor != null)
return bgColor;
if (canvas != null)
return canvas.getBackground();
return null;
}
/** @see IFigure#getFont() */
public Font getFont() {
if (font != null)
return font;
if (canvas != null)
return canvas.getFont();
return null;
}
/** @see IFigure#getForegroundColor() */
public Color getForegroundColor() {
if (fgColor != null)
return fgColor;
if (canvas != null)
return canvas.getForeground();
return null;
}
/** @see IFigure#getUpdateManager() */
public UpdateManager getUpdateManager() {
return LightweightSystem.this.getUpdateManager();
}
/** @see IFigure#internalGetEventDispatcher() */
public EventDispatcher internalGetEventDispatcher() {
return getEventDispatcher();
}
/**
* @see IFigure#isMirrored()
*/
public boolean isMirrored() {
return (LightweightSystem.this.canvas.getStyle() & org.eclipse.draw2d.rap.swt.SWT.MIRRORED) != 0;
}
/** @see Figure#isShowing() */
public boolean isShowing() {
return true;
}
}
protected class RAPDragTracker {
public boolean cancelled;
public boolean tracking;
private final MouseMoveListener listener;
private final Widget widget;
public RAPDragTracker(final MouseMoveListener listener,
final Widget widget) {
this.listener = listener;
this.widget = widget;
}
public void open() {
Job dragJob = new Job("Drag-Job") {
protected IStatus run(IProgressMonitor monitor) {
// Run tracker until mouse up occurs or escape key pressed.
final Display display = widget.getDisplay();
cancelled = false;
tracking = true;
try {
long timeout = 0;
long refreshRate = 200;
while (tracking && !cancelled) {
if (display != null && !display.isDisposed()) {
display.syncExec(new Runnable() {
public void run() {
if (canvas.isDisposed()) {
tracking = false;
cancelled = true;
return;
}
Event ev = new Event();
ev.display = display;
Point loc = canvas.toControl(display
.getCursorLocation());
ev.type = SWT.DragDetect;
ev.widget = widget;
ev.button = 1;
ev.x = loc.x;
ev.y = loc.y;
MouseEvent me = new MouseEvent(ev);
me.stateMask = SWT.BUTTON1;
listener.mouseMove(me);
}
});
timeout += refreshRate;
if (timeout >= 60000) {
cancelled = true;
}
Thread.sleep(refreshRate);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
display.syncExec(new Runnable() {
public void run() {
close();
}
});
}
return Status.OK_STATUS;
}
};
dragJob.setSystem(true);
dragJob.schedule();
}
public void close() {
tracking = false;
}
}
/**
* Listener used to get all necessary events from the Canvas and pass them
* on to the {@link EventDispatcher}.
*/
protected class EventHandler implements MouseMoveListener, MouseListener,
AccessibleControlListener, KeyListener, TraverseListener,
FocusListener, AccessibleListener, MouseTrackListener, Listener,
DisposeListener {
/** @see FocusListener#focusGained(FocusEvent) */
public void focusGained(FocusEvent e) {
getEventDispatcher().dispatchFocusGained(e);
}
/** @see FocusListener#focusLost(FocusEvent) */
public void focusLost(FocusEvent e) {
getEventDispatcher().dispatchFocusLost(e);
}
/** @see AccessibleControlListener#getChild(AccessibleControlEvent) */
public void getChild(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getChild(e);
}
/** @see AccessibleControlListener#getChildAtPoint(AccessibleControlEvent) */
public void getChildAtPoint(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getChildAtPoint(e);
}
/** @see AccessibleControlListener#getChildCount(AccessibleControlEvent) */
public void getChildCount(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getChildCount(e);
}
/** @see AccessibleControlListener#getChildren(AccessibleControlEvent) */
public void getChildren(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getChildren(e);
}
/** @see AccessibleControlListener#getDefaultAction(AccessibleControlEvent) */
public void getDefaultAction(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getDefaultAction(e);
}
/** @see AccessibleListener#getDescription(AccessibleEvent) */
public void getDescription(AccessibleEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getDescription(e);
}
/** @see AccessibleControlListener#getFocus(AccessibleControlEvent) */
public void getFocus(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getFocus(e);
}
/** @see AccessibleListener#getHelp(AccessibleEvent) */
public void getHelp(AccessibleEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getHelp(e);
}
/** @see AccessibleListener#getKeyboardShortcut(AccessibleEvent) */
public void getKeyboardShortcut(AccessibleEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getKeyboardShortcut(e);
}
/** @see AccessibleControlListener#getLocation(AccessibleControlEvent) */
public void getLocation(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getLocation(e);
}
/** @see AccessibleListener#getName(AccessibleEvent) */
public void getName(AccessibleEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getName(e);
}
/** @see AccessibleControlListener#getRole(AccessibleControlEvent) */
public void getRole(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getRole(e);
}
/** @see AccessibleControlListener#getSelection(AccessibleControlEvent) */
public void getSelection(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getSelection(e);
}
/** @see AccessibleControlListener#getState(AccessibleControlEvent) */
public void getState(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getState(e);
}
/** @see AccessibleControlListener#getValue(AccessibleControlEvent) */
public void getValue(AccessibleControlEvent e) {
EventDispatcher.AccessibilityDispatcher ad;
ad = getEventDispatcher().getAccessibilityDispatcher();
if (ad != null)
ad.getValue(e);
}
/**
* @see Listener#handleEvent(org.eclipse.swt.widgets.Event)
* @since 3.1
*/
public void handleEvent(Event event) {
// Mouse wheel events
if (event.type == org.eclipse.draw2d.rap.swt.SWT.MouseWheel)
getEventDispatcher().dispatchMouseWheelScrolled(event);
// HACK: for DND in RAP
else if (event.type == SWT.DragDetect) {
MouseEvent me = new MouseEvent(event);
me.stateMask = SWT.BUTTON1;
getEventDispatcher().dispatchMouseMoved(me);
}
}
/** @see KeyListener#keyPressed(KeyEvent) */
public void keyPressed(KeyEvent e) {
getEventDispatcher().dispatchKeyPressed(e);
}
/** @see KeyListener#keyReleased(KeyEvent) */
public void keyReleased(KeyEvent e) {
getEventDispatcher().dispatchKeyReleased(e);
}
/** @see TraverseListener#keyTraversed(TraverseEvent) */
public void keyTraversed(TraverseEvent e) {
/*
* Doit is almost always false by default for Canvases with
* KeyListeners. Set to true to allow normal behavior. For example,
* in Dialogs ESC should close.
*/
e.doit = true;
getEventDispatcher().dispatchKeyTraversed(e);
}
/** @see MouseListener#mouseDoubleClick(MouseEvent) */
public void mouseDoubleClick(MouseEvent e) {
getEventDispatcher().dispatchMouseDoubleClicked(e);
}
/** @see MouseListener#mouseDown(MouseEvent) */
public void mouseDown(MouseEvent e) {
getEventDispatcher().dispatchMousePressed(e);
}
/** @see MouseTrackListener#mouseEnter(MouseEvent) */
public void mouseEnter(MouseEvent e) {
getEventDispatcher().dispatchMouseEntered(e);
}
/** @see MouseTrackListener#mouseExit(MouseEvent) */
public void mouseExit(MouseEvent e) {
getEventDispatcher().dispatchMouseExited(e);
}
/** @see MouseTrackListener#mouseHover(MouseEvent) */
public void mouseHover(MouseEvent e) {
getEventDispatcher().dispatchMouseHover(e);
}
/** @see MouseMoveListener#mouseMove(MouseEvent) */
public void mouseMove(MouseEvent e) {
getEventDispatcher().dispatchMouseMoved(e);
}
/** @see MouseListener#mouseUp(MouseEvent) */
public void mouseUp(MouseEvent e) {
getEventDispatcher().dispatchMouseReleased(e);
if (tracker != null) {
tracker.close();
tracker = null;
}
}
/** @see DisposeListener#widgetDisposed(DisposeEvent) */
public void widgetDisposed(DisposeEvent e) {
getUpdateManager().dispose();
}
}
}