diff dwt/widgets/Link.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 649b8e223d5a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/widgets/Link.d	Sat Aug 09 17:00:02 2008 +0200
@@ -0,0 +1,441 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ *******************************************************************************/
+module dwt.widgets.Link;
+
+import dwt.dwthelper.utils;
+
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.events.SelectionEvent;
+import dwt.events.SelectionListener;
+import dwt.graphics.Point;
+import dwt.internal.cocoa.NSRange;
+import dwt.internal.cocoa.NSRect;
+import dwt.internal.cocoa.NSScrollView;
+import dwt.internal.cocoa.NSSize;
+import dwt.internal.cocoa.NSString;
+import dwt.internal.cocoa.NSTextStorage;
+import dwt.internal.cocoa.NSTextView;
+import dwt.internal.cocoa.NSView;
+import dwt.internal.cocoa.OS;
+import dwt.internal.cocoa.SWTScrollView;
+import dwt.internal.cocoa.SWTTextView;
+
+/**
+ * Instances of this class represent a selectable
+ * user interface object that displays a text with 
+ * links.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ * 
+ * @since 3.1
+ */
+public class Link extends Control {
+    NSScrollView scrollView;
+    String text;
+    Point [] offsets;
+    Point selection;
+    String [] ids;
+    int [] mnemonics;
+    
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together 
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new instance (cannot be null)
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Link (Composite parent, int style) {
+    super (parent, style);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the control is selected by the user.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+    checkWidget ();
+    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
+    TypedListener typedListener = new TypedListener (listener);
+    addListener (DWT.Selection, typedListener);
+    addListener (DWT.DefaultSelection, typedListener);
+}
+
+bool clickOnLink(int textView, int link, int charIndex) {
+    NSString str = new NSString (link);
+    char [] buffer = new char [str.length ()];
+    str.getCharacters_ (buffer);
+    Event event = new Event ();
+    event.text = new String (buffer);
+    sendEvent (DWT.Selection, event);
+    return true;
+}
+
+public Point computeSize (int wHint, int hHint, bool changed) {
+    checkWidget ();
+    if (wHint !is DWT.DEFAULT && wHint < 0) wHint = 0;
+    if (hHint !is DWT.DEFAULT && hHint < 0) hHint = 0;
+    int width, height;
+    //TODO wrapping, wHint
+    int borderStyle = hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder;
+    NSSize borderSize = NSScrollView.frameSizeForContentSize(new NSSize(), false, false, borderStyle);
+    NSTextView widget = (NSTextView)view;
+    NSSize size = widget.textStorage().size();
+    width = (int)(size.width + borderSize.width);
+    height = (int)(size.height + borderSize.height);
+    if (wHint !is DWT.DEFAULT) width = wHint;
+    if (hHint !is DWT.DEFAULT) height = hHint;
+    int border = getBorderWidth ();
+    width += border * 2;
+    height += border * 2;
+    return new Point (width, height);
+}
+
+void createHandle () {
+    SWTScrollView scrollWidget = (SWTScrollView)new SWTScrollView().alloc();
+    scrollWidget.initWithFrame(new NSRect ());
+    scrollWidget.setDrawsBackground(false);
+    scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder);
+    scrollWidget.setTag(jniRef);
+
+    SWTTextView widget = (SWTTextView)new SWTTextView().alloc();
+    widget.initWithFrame(new NSRect());
+    widget.setEditable(false);
+    widget.setDrawsBackground(false);
+    widget.setDelegate(widget);
+    widget.setAutoresizingMask (OS.NSViewWidthSizable | OS.NSViewHeightSizable);
+    widget.setTag(jniRef);
+    widget.textContainer().setLineFragmentPadding(0);
+    
+    scrollView = scrollWidget;
+    view = widget;
+    scrollView.addSubview_(view);
+    scrollView.setDocumentView(view);
+    parent.contentView().addSubview_(scrollView);
+}
+
+void createWidget () {
+    super.createWidget ();
+    text = "";
+}
+
+String getNameText () {
+    return getText ();
+}
+
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String getText () {
+    checkWidget ();
+    return text;
+}
+
+void releaseWidget () {
+    super.releaseWidget ();
+    offsets = null;
+    ids = null;
+    mnemonics = null;
+    text = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+    checkWidget ();
+    if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (eventTable is null) return;
+    eventTable.unhook (DWT.Selection, listener);
+    eventTable.unhook (DWT.DefaultSelection, listener); 
+}
+
+String parse (String string) {
+    int length = string.length ();
+    offsets = new Point [length / 4];
+    ids = new String [length / 4];
+    mnemonics = new int [length / 4 + 1];
+    StringBuffer result = new StringBuffer ();
+    char [] buffer = new char [length];
+    string.getChars (0, string.length (), buffer, 0);
+    int index = 0, state = 0, linkIndex = 0;
+    int start = 0, tagStart = 0, linkStart = 0, endtagStart = 0, refStart = 0;
+    while (index < length) {
+        char c = Character.toLowerCase (buffer [index]);
+        switch (state) {
+            case 0: 
+                if (c is '<') {
+                    tagStart = index;
+                    state++;
+                }
+                break;
+            case 1:
+                if (c is 'a') state++;
+                break;
+            case 2:
+                switch (c) {
+                    case 'h':
+                        state = 7;
+                        break;
+                    case '>':
+                        linkStart = index  + 1;
+                        state++;
+                        break;
+                    default:
+                        if (Character.isWhitespace(c)) break;
+                        else state = 13;
+                }
+                break;
+            case 3:
+                if (c is '<') {
+                    endtagStart = index;
+                    state++;
+                }
+                break;
+            case 4:
+                state = c is '/' ? state + 1 : 3;
+                break;
+            case 5:
+                state = c is 'a' ? state + 1 : 3;
+                break;
+            case 6:
+                if (c is '>') {
+                    mnemonics [linkIndex] = parseMnemonics (buffer, start, tagStart, result);
+                    int offset = result.length ();
+                    parseMnemonics (buffer, linkStart, endtagStart, result);
+                    offsets [linkIndex] = new Point (offset, result.length () - 1);
+                    if (ids [linkIndex] is null) {
+                        ids [linkIndex] = new String (buffer, linkStart, endtagStart - linkStart);
+                    }
+                    linkIndex++;
+                    start = tagStart = linkStart = endtagStart = refStart = index + 1;
+                    state = 0;
+                } else {
+                    state = 3;
+                }
+                break;
+            case 7:
+                state = c is 'r' ? state + 1 : 0;
+                break;
+            case 8:
+                state = c is 'e' ? state + 1 : 0;
+                break;
+            case 9:
+                state = c is 'f' ? state + 1 : 0;
+                break;
+            case 10:
+                state = c is '=' ? state + 1 : 0;
+                break;
+            case 11:
+                if (c is '"') {
+                    state++;
+                    refStart = index + 1;
+                } else {
+                    state = 0;
+                }
+                break;
+            case 12:
+                if (c is '"') {
+                    ids[linkIndex] = new String (buffer, refStart, index - refStart);
+                    state = 2;
+                }
+                break;
+            case 13:
+                if (Character.isWhitespace (c)) {
+                    state = 0;
+                } else if (c is '='){
+                    state++;
+                }
+                break;
+            case 14:
+                state = c is '"' ? state + 1 : 0;
+                break;
+            case 15:
+                if (c is '"') state = 2;
+                break;
+            default:
+                state = 0;
+                break;
+        }
+        index++;
+    }
+    if (start < length) {
+        int tmp = parseMnemonics (buffer, start, tagStart, result);
+        int mnemonic = parseMnemonics (buffer, Math.max (tagStart, linkStart), length, result);
+        if (mnemonic is -1) mnemonic = tmp;
+        mnemonics [linkIndex] = mnemonic;
+    } else {
+        mnemonics [linkIndex] = -1;
+    }
+    if (offsets.length !is linkIndex) {
+        Point [] newOffsets = new Point [linkIndex];
+        System.arraycopy (offsets, 0, newOffsets, 0, linkIndex);
+        offsets = newOffsets;
+        String [] newIDs = new String [linkIndex];
+        System.arraycopy (ids, 0, newIDs, 0, linkIndex);
+        ids = newIDs;
+        int [] newMnemonics = new int [linkIndex + 1];
+        System.arraycopy (mnemonics, 0, newMnemonics, 0, linkIndex + 1);
+        mnemonics = newMnemonics;       
+    }
+    return result.toString ();
+}
+
+int parseMnemonics (char[] buffer, int start, int end, StringBuffer result) {
+    int mnemonic = -1, index = start;
+    while (index < end) {
+        if (buffer [index] is '&') {
+            if (index + 1 < end && buffer [index + 1] is '&') {
+                result.append (buffer [index]);
+                index++;
+            } else {
+                mnemonic = result.length();
+            }
+        } else {
+            result.append (buffer [index]);
+        }
+        index++;
+    }
+    return mnemonic;
+}
+
+/**
+ * Sets the receiver's text.
+ * <p>
+ * The string can contain both regular text and hyperlinks.  A hyperlink
+ * is delimited by an anchor tag, &lt;A&gt; and &lt;/A&gt;.  Within an
+ * anchor, a single HREF attribute is supported.  When a hyperlink is
+ * selected, the text field of the selection event contains either the
+ * text of the hyperlink or the value of its HREF, if one was specified.
+ * In the rare case of identical hyperlinks within the same string, the
+ * HREF tag can be used to distinguish between them.  The string may
+ * include the mnemonic character and line delimiters.
+ * </p>
+ * 
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setText (String string) {
+    checkWidget ();
+    if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (string.equals (text)) return;
+    text = string;
+    NSTextView widget = (NSTextView)view;
+    widget.setString(NSString.stringWith(parse(string)));
+    NSTextStorage textStorage = widget.textStorage();
+    NSRange range = new NSRange();
+    for (int i = 0; i < offsets.length; i++) {
+        range.location = offsets[i].x;
+        range.length = offsets[i].y - offsets[i].x + 1;
+        textStorage.addAttribute(OS.NSLinkAttributeName(), NSString.stringWith(ids[i]), range);
+    }
+}
+
+NSView topView () {
+    return scrollView;
+}
+
+//int traversalCode (int key, int theEvent) {
+//  if (offsets.length is 0) return 0;
+//  int bits = super.traversalCode (key, theEvent);
+//  if (key is 48 /* Tab */ && theEvent !is 0) {
+//      int [] modifiers = new int [1];
+//      OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, 4, null, modifiers);
+//      bool next = (modifiers [0] & OS.shiftKey) is 0;
+//      if (next && focusIndex < offsets.length - 1) {
+//          return bits & ~ DWT.TRAVERSE_TAB_NEXT;
+//      }
+//      if (!next && focusIndex > 0) {
+//          return bits & ~ DWT.TRAVERSE_TAB_PREVIOUS;
+//      }
+//  }
+//  return bits;
+//}
+
+}