Mercurial > projects > dwt-mac
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, <A> and </A>. 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; +//} + +}