| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.forms.widgets; |
| import java.util.Vector; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.ui.forms.events.*; |
| import org.eclipse.ui.internal.forms.widgets.FormsResources; |
| /** |
| * This is the base class for custom hyperlink widget. It is responsible for |
| * processing mouse and keyboard events, and converting them into unified |
| * hyperlink events. Subclasses are responsible for rendering the hyperlink in |
| * the client area. |
| * |
| * @since 3.0 |
| */ |
| public abstract class AbstractHyperlink extends Canvas { |
| private boolean hasFocus; |
| private Vector listeners; |
| /** |
| * Amount of the margin width around the hyperlink (default is 1). |
| */ |
| protected int marginWidth = 1; |
| /** |
| * Amount of the margin height around the hyperlink (default is 1). |
| */ |
| protected int marginHeight = 1; |
| /** |
| * Creates a new hyperlink in the provided parent. |
| * |
| * @param parent |
| * the control parent |
| * @param style |
| * the widget style |
| */ |
| public AbstractHyperlink(Composite parent, int style) { |
| super(parent, style); |
| addListener(SWT.KeyDown, new Listener() { |
| public void handleEvent(Event e) { |
| if (e.character == '\r') { |
| handleActivate(e); |
| } |
| } |
| }); |
| addPaintListener(new PaintListener() { |
| public void paintControl(PaintEvent e) { |
| paint(e); |
| } |
| }); |
| addListener(SWT.Traverse, new Listener() { |
| public void handleEvent(Event e) { |
| switch (e.detail) { |
| case SWT.TRAVERSE_PAGE_NEXT : |
| case SWT.TRAVERSE_PAGE_PREVIOUS : |
| case SWT.TRAVERSE_ARROW_NEXT : |
| case SWT.TRAVERSE_ARROW_PREVIOUS : |
| case SWT.TRAVERSE_RETURN : |
| e.doit = false; |
| return; |
| } |
| e.doit = true; |
| } |
| }); |
| Listener listener = new Listener() { |
| public void handleEvent(Event e) { |
| switch (e.type) { |
| case SWT.FocusIn : |
| hasFocus = true; |
| handleEnter(e); |
| break; |
| case SWT.FocusOut : |
| hasFocus = false; |
| handleExit(e); |
| break; |
| case SWT.DefaultSelection : |
| handleActivate(e); |
| break; |
| case SWT.MouseEnter : |
| handleEnter(e); |
| break; |
| case SWT.MouseExit : |
| handleExit(e); |
| break; |
| case SWT.MouseUp : |
| handleMouseUp(e); |
| break; |
| } |
| } |
| }; |
| addListener(SWT.MouseEnter, listener); |
| addListener(SWT.MouseExit, listener); |
| addListener(SWT.MouseUp, listener); |
| addListener(SWT.FocusIn, listener); |
| addListener(SWT.FocusOut, listener); |
| setCursor(FormsResources.getHandCursor()); |
| } |
| /** |
| * Adds the event listener to this hyperlink. |
| * |
| * @param listener |
| * the event listener to add |
| */ |
| public void addHyperlinkListener(IHyperlinkListener listener) { |
| if (listeners == null) |
| listeners = new Vector(); |
| if (!listeners.contains(listener)) |
| listeners.add(listener); |
| } |
| /** |
| * Removes the event listener from this hyperlink. |
| * |
| * @param listener |
| * the event listener to remove |
| */ |
| public void removeHyperlinkListener(IHyperlinkListener listener) { |
| if (listeners == null) |
| return; |
| listeners.remove(listener); |
| } |
| /** |
| * Returns the selection state of the control. When focus is gained, the |
| * state will be <samp>true </samp>; it will switch to <samp>false </samp> |
| * when the control looses focus. |
| * |
| * @return <code>true</code> if the widget has focus, <code>false</code> |
| * otherwise. |
| */ |
| public boolean getSelection() { |
| return hasFocus; |
| } |
| /** |
| * Called when hyperlink is entered. Subclasses that override this method |
| * must call 'super'. |
| */ |
| protected void handleEnter(Event e) { |
| redraw(); |
| if (listeners == null) |
| return; |
| int size = listeners.size(); |
| HyperlinkEvent he = new HyperlinkEvent(this, getHref(), getText(), e.stateMask); |
| for (int i = 0; i < size; i++) { |
| IHyperlinkListener listener = (IHyperlinkListener) listeners.get(i); |
| listener.linkEntered(he); |
| } |
| } |
| /** |
| * Called when hyperlink is exited. Subclasses that override this method |
| * must call 'super'. |
| */ |
| protected void handleExit(Event e) { |
| redraw(); |
| if (listeners == null) |
| return; |
| int size = listeners.size(); |
| HyperlinkEvent he = new HyperlinkEvent(this, getHref(), getText(), e.stateMask); |
| for (int i = 0; i < size; i++) { |
| IHyperlinkListener listener = (IHyperlinkListener) listeners.get(i); |
| listener.linkExited(he); |
| } |
| } |
| /** |
| * Called when hyperlink has been activated. Subclasses that override this |
| * method must call 'super'. |
| */ |
| protected void handleActivate(Event e) { |
| if (listeners == null) |
| return; |
| int size = listeners.size(); |
| setCursor(FormsResources.getBusyCursor()); |
| HyperlinkEvent he = new HyperlinkEvent(this, getHref(), getText(), e.stateMask); |
| for (int i = 0; i < size; i++) { |
| IHyperlinkListener listener = (IHyperlinkListener) listeners.get(i); |
| listener.linkActivated(he); |
| } |
| if (!isDisposed()) |
| setCursor(FormsResources.getHandCursor()); |
| } |
| /** |
| * Sets the object associated with this hyperlink. Concrete implementation |
| * of this class can use if to store text, URLs or model objects that need |
| * to be processed on hyperlink events. |
| * |
| * @param href |
| * the hyperlink object reference |
| */ |
| public void setHref(Object href) { |
| setData("href", href); |
| } |
| /** |
| * Returns the object associated with this hyperlink. |
| * |
| * @see #setHref |
| * @return the hyperlink object reference |
| */ |
| public Object getHref() { |
| return getData("href"); |
| } |
| /** |
| * Returns the textual representation of this hyperlink suitable for |
| * showing in tool tips or on the status line. |
| * |
| * @return the hyperlink text |
| */ |
| public String getText() { |
| return getToolTipText(); |
| } |
| /** |
| * Paints the hyperlink as a reaction to the provided paint event. |
| * |
| * @param e |
| * the paint event |
| */ |
| protected abstract void paintHyperlink(GC gc); |
| /** |
| * Paints the control as a reaction to the provided paint event. |
| * |
| * @param e |
| * the paint event |
| */ |
| protected void paint(PaintEvent e) { |
| GC gc = e.gc; |
| Rectangle clientArea = getClientArea(); |
| Image buffer = new Image(getDisplay(), clientArea.width, clientArea.height); |
| buffer.setBackground(getBackground()); |
| GC bufferGC = new GC(buffer, gc.getStyle()); |
| bufferGC.setBackground(getBackground()); |
| bufferGC.fillRectangle(0, 0, clientArea.width, clientArea.height); |
| paintHyperlink(bufferGC); |
| if (hasFocus) { |
| Rectangle carea = getClientArea(); |
| bufferGC.setForeground(getForeground()); |
| bufferGC.drawFocus(0, 0, carea.width, carea.height); |
| } |
| gc.drawImage(buffer, 0, 0); |
| bufferGC.dispose(); |
| buffer.dispose(); |
| } |
| private void handleMouseUp(Event e) { |
| if (e.button != 1) |
| return; |
| Point size = getSize(); |
| // Filter out mouse up events outside |
| // the link. This can happen when mouse is |
| // clicked, dragged outside the link, then |
| // released. |
| if (e.x < 0) |
| return; |
| if (e.y < 0) |
| return; |
| if (e.x >= size.x) |
| return; |
| if (e.y >= size.y) |
| return; |
| handleActivate(e); |
| } |
| } |