Mercurial > projects > dwt2
annotate org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/widgets/Link.d @ 120:536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
===D2===
* added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements
used these templates to work with strict type storage rules of dmd-2.053
* com.ibm.icu now also compilable with D2, but not tested yet
* small fixes
Snippet288 - shared data is in TLS
===Phobos===
* fixed critical bugs in Phobos implemention
completely incorrect segfault prone fromStringz (Linux's port ruthless killer)
terrible, incorrect StringBuffer realization (StyledText killer)
* fixed small bugs as well
Snippet72 - misprint in the snippet
* implemented missed functionality for Phobos
ByteArrayOutputStream implemented (image loading available)
formatting correctly works for all DWT's cases
As a result, folowing snippets now works with Phobos (Snippet### - what is fixed):
Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting
Snippet48, 282 - crash on image loading
Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText
Snippet244 - hang-up
===Tango===
* few changes for the latest Tango trunc-r5661
* few small performance improvments
===General===
* implMissing-s for only one version changed to implMissingInTango/InPhobos
* incorrect calls to Format in toString-s fixed
* fixed loading \uXXXX characters in ResourceBundle
* added good UTF-8 support for StyledText, TextLayout (Win32) and friends
UTF functions revised and tested. It is now in java.nonstandard.*Utf modules
StyledText and TextLayout (Win32) modules revised for UTF-8 support
* removed small diferences in most identical files in *.swt.* folders
*.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32
now 179 of 576 (~31%) files in *.swt.* folders are fully identical
* Win32: snippets now have right subsystem, pretty icons and native system style controls
* small fixes in snippets
Snippet44 - it's not Snippet44
Snippet212 - functions work with different images and offsets arrays
Win32: Snippet282 - crash on close if the button has an image
Snippet293 - setGrayed is commented
and others
Win32: As a result, folowing snippets now works
Snippet68 - color doesn't change
Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above)
Snippet193 - no tabel headers
author | Denis Shelomovskij <verylonglogin.reg@gmail.com> |
---|---|
date | Sat, 09 Jul 2011 15:50:20 +0300 |
parents | c01d033c633a |
children |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.widgets.Link; | |
14 | |
15 | |
16 import org.eclipse.swt.SWT; | |
17 import org.eclipse.swt.SWTException; | |
18 import org.eclipse.swt.accessibility.ACC; | |
19 import org.eclipse.swt.accessibility.Accessible; | |
20 import org.eclipse.swt.accessibility.AccessibleAdapter; | |
21 import org.eclipse.swt.accessibility.AccessibleControlAdapter; | |
22 import org.eclipse.swt.accessibility.AccessibleControlEvent; | |
23 import org.eclipse.swt.accessibility.AccessibleEvent; | |
24 import org.eclipse.swt.events.SelectionEvent; | |
25 import org.eclipse.swt.events.SelectionListener; | |
26 import org.eclipse.swt.graphics.Color; | |
27 import org.eclipse.swt.graphics.Font; | |
28 import org.eclipse.swt.graphics.GC; | |
29 import org.eclipse.swt.graphics.GCData; | |
30 import org.eclipse.swt.graphics.Point; | |
31 import org.eclipse.swt.graphics.RGB; | |
32 import org.eclipse.swt.graphics.Rectangle; | |
33 import org.eclipse.swt.graphics.TextLayout; | |
34 import org.eclipse.swt.graphics.TextStyle; | |
35 import org.eclipse.swt.internal.gtk.OS; | |
36 | |
37 import org.eclipse.swt.graphics.Cursor; | |
38 import org.eclipse.swt.widgets.Control; | |
39 import org.eclipse.swt.widgets.Composite; | |
40 import org.eclipse.swt.widgets.TypedListener; | |
41 import org.eclipse.swt.widgets.Event; | |
42 import java.lang.all; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
43 import java.nonstandard.UnsafeUtf; |
25 | 44 |
45 | |
46 /** | |
47 * Instances of this class represent a selectable | |
48 * user interface object that displays a text with | |
49 * links. | |
50 * <p> | |
51 * <dl> | |
52 * <dt><b>Styles:</b></dt> | |
53 * <dd>(none)</dd> | |
54 * <dt><b>Events:</b></dt> | |
55 * <dd>Selection</dd> | |
56 * </dl> | |
57 * <p> | |
58 * IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
59 * </p> | |
60 * | |
61 * @see <a href="http://www.eclipse.org/swt/snippets/#link">Link snippets</a> | |
62 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> | |
63 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
64 * | |
65 * @since 3.1 | |
66 */ | |
67 public class Link : Control { | |
68 | |
69 alias Control.computeSize computeSize; | |
70 alias Control.fixStyle fixStyle; | |
71 alias Control.setBounds setBounds; | |
72 | |
73 String text; | |
74 TextLayout layout; | |
75 Color linkColor, disabledColor; | |
76 Point [] offsets; | |
77 Point selection; | |
78 String [] ids; | |
79 int [] mnemonics; | |
80 int focusIndex; | |
81 | |
82 static RGB LINK_FOREGROUND; | |
83 static RGB LINK_DISABLED_FOREGROUND; | |
84 | |
85 static void static_this(){ | |
86 if( LINK_FOREGROUND is null ){ | |
87 LINK_FOREGROUND = new RGB (0, 51, 153); | |
88 } | |
89 if( LINK_DISABLED_FOREGROUND is null ){ | |
90 LINK_DISABLED_FOREGROUND = new RGB (172, 168, 153); | |
91 } | |
92 } | |
93 | |
94 /** | |
95 * Constructs a new instance of this class given its parent | |
96 * and a style value describing its behavior and appearance. | |
97 * <p> | |
98 * The style value is either one of the style constants defined in | |
99 * class <code>SWT</code> which is applicable to instances of this | |
100 * class, or must be built by <em>bitwise OR</em>'ing together | |
101 * (that is, using the <code>int</code> "|" operator) two or more | |
102 * of those <code>SWT</code> style constants. The class description | |
103 * lists the style constants that are applicable to the class. | |
104 * Style bits are also inherited from superclasses. | |
105 * </p> | |
106 * | |
107 * @param parent a composite control which will be the parent of the new instance (cannot be null) | |
108 * @param style the style of control to construct | |
109 * | |
110 * @exception IllegalArgumentException <ul> | |
111 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
112 * </ul> | |
113 * @exception SWTException <ul> | |
114 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
115 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
116 * </ul> | |
117 * | |
118 * @see Widget#checkSubclass | |
119 * @see Widget#getStyle | |
120 */ | |
121 public this (Composite parent, int style) { | |
122 static_this(); | |
123 super (parent, style); | |
124 } | |
125 | |
126 /** | |
127 * Adds the listener to the collection of listeners who will | |
128 * be notified when the control is selected by the user, by sending | |
129 * it one of the messages defined in the <code>SelectionListener</code> | |
130 * interface. | |
131 * <p> | |
132 * <code>widgetSelected</code> is called when the control is selected by the user. | |
133 * <code>widgetDefaultSelected</code> is not called. | |
134 * </p> | |
135 * | |
136 * @param listener the listener which should be notified | |
137 * | |
138 * @exception IllegalArgumentException <ul> | |
139 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
140 * </ul> | |
141 * @exception SWTException <ul> | |
142 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
143 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
144 * </ul> | |
145 * | |
146 * @see SelectionListener | |
147 * @see #removeSelectionListener | |
148 * @see SelectionEvent | |
149 */ | |
150 public void addSelectionListener (SelectionListener listener) { | |
151 checkWidget (); | |
152 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
153 TypedListener typedListener = new TypedListener (listener); | |
154 addListener (SWT.Selection, typedListener); | |
155 addListener (SWT.DefaultSelection, typedListener); | |
156 } | |
157 | |
158 public override Point computeSize (int wHint, int hHint, bool changed) { | |
159 checkWidget (); | |
160 if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0; | |
161 if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0; | |
162 int width, height; | |
163 int layoutWidth = layout.getWidth (); | |
164 //TEMPORARY CODE | |
165 if (wHint is 0) { | |
166 layout.setWidth (1); | |
167 Rectangle rect = layout.getBounds (); | |
168 width = 0; | |
169 height = rect.height; | |
170 } else { | |
171 layout.setWidth (wHint); | |
172 Rectangle rect = layout.getBounds (); | |
173 width = rect.width; | |
174 height = rect.height; | |
175 } | |
176 layout.setWidth (layoutWidth); | |
177 if (wHint !is SWT.DEFAULT) width = wHint; | |
178 if (hHint !is SWT.DEFAULT) height = hHint; | |
179 int border = getBorderWidth (); | |
180 width += border * 2; | |
181 height += border * 2; | |
182 return new Point (width, height); | |
183 } | |
184 | |
185 override void createHandle(int index) { | |
186 state |= HANDLE | THEME_BACKGROUND; | |
187 handle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null); | |
188 if (handle is null) SWT.error (SWT.ERROR_NO_HANDLES); | |
189 OS.gtk_fixed_set_has_window (handle, true); | |
190 OS.GTK_WIDGET_SET_FLAGS (handle, OS.GTK_CAN_FOCUS); | |
191 layout = new TextLayout (display); | |
192 layout.setOrientation((style & SWT.RIGHT_TO_LEFT) !is 0? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT); | |
193 linkColor = new Color (display, LINK_FOREGROUND); | |
194 disabledColor = new Color (display, LINK_DISABLED_FOREGROUND); | |
195 offsets = null; | |
196 ids = null; | |
197 mnemonics = null; | |
198 selection = new Point (-1, -1); | |
199 focusIndex = -1; | |
200 } | |
201 | |
202 override void createWidget (int index) { | |
203 super.createWidget (index); | |
204 layout.setFont (getFont ()); | |
205 text = ""; | |
206 initAccessible (); | |
207 } | |
208 | |
209 override void enableWidget (bool enabled) { | |
210 super.enableWidget (enabled); | |
211 if (isDisposed ()) return; | |
212 TextStyle linkStyle = new TextStyle (null, enabled ? linkColor : disabledColor, null); | |
213 linkStyle.underline = true; | |
214 for (int i = 0; i < offsets.length; i++) { | |
215 Point point = offsets [i]; | |
216 layout.setStyle (linkStyle, point.x, point.y); | |
217 } | |
218 redraw (); | |
219 } | |
220 | |
221 override void fixStyle () { | |
222 fixStyle (handle); | |
223 } | |
224 | |
225 void initAccessible () { | |
226 Accessible accessible = getAccessible (); | |
227 accessible.addAccessibleListener (new class () AccessibleAdapter { | |
228 public void getName (AccessibleEvent e) { | |
229 e.result = parse (text); | |
230 } | |
231 }); | |
232 | |
233 accessible.addAccessibleControlListener (new class () AccessibleControlAdapter { | |
234 public void getChildAtPoint (AccessibleControlEvent e) { | |
235 e.childID = ACC.CHILDID_SELF; | |
236 } | |
237 | |
238 public void getLocation (AccessibleControlEvent e) { | |
239 Rectangle rect = display.map (getParent (), null, getBounds ()); | |
240 e.x = rect.x; | |
241 e.y = rect.y; | |
242 e.width = rect.width; | |
243 e.height = rect.height; | |
244 } | |
245 | |
246 public void getChildCount (AccessibleControlEvent e) { | |
247 e.detail = 0; | |
248 } | |
249 | |
250 public void getRole (AccessibleControlEvent e) { | |
251 e.detail = ACC.ROLE_LINK; | |
252 } | |
253 | |
254 public void getState (AccessibleControlEvent e) { | |
255 e.detail = ACC.STATE_FOCUSABLE; | |
256 if (hasFocus ()) e.detail |= ACC.STATE_FOCUSED; | |
257 } | |
258 | |
259 public void getDefaultAction (AccessibleControlEvent e) { | |
260 e.result = SWT.getMessage ("SWT_Press"); //$NON-NLS-1$ | |
261 } | |
262 | |
263 public void getSelection (AccessibleControlEvent e) { | |
264 if (hasFocus ()) e.childID = ACC.CHILDID_SELF; | |
265 } | |
266 | |
267 public void getFocus (AccessibleControlEvent e) { | |
268 if (hasFocus ()) e.childID = ACC.CHILDID_SELF; | |
269 } | |
270 }); | |
271 } | |
272 | |
273 override String getNameText () { | |
274 return getText (); | |
275 } | |
276 | |
277 Rectangle [] getRectangles (int linkIndex) { | |
278 int lineCount = layout.getLineCount (); | |
279 Rectangle [] rects = new Rectangle [lineCount]; | |
280 int [] lineOffsets = layout.getLineOffsets (); | |
281 Point point = offsets [linkIndex]; | |
282 int lineStart = 1; | |
283 while (point.x > lineOffsets [lineStart]) lineStart++; | |
284 int lineEnd = 1; | |
285 while (point.y > lineOffsets [lineEnd]) lineEnd++; | |
286 int index = 0; | |
287 if (lineStart is lineEnd) { | |
288 rects [index++] = layout.getBounds (point.x, point.y); | |
289 } else { | |
290 rects [index++] = layout.getBounds (point.x, lineOffsets [lineStart]-1); | |
291 rects [index++] = layout.getBounds (lineOffsets [lineEnd-1], point.y); | |
292 if (lineEnd - lineStart > 1) { | |
293 for (int i = lineStart; i < lineEnd - 1; i++) { | |
294 rects [index++] = layout.getLineBounds (i); | |
295 } | |
296 } | |
297 } | |
298 if (rects.length !is index) { | |
299 Rectangle [] tmp = new Rectangle [index]; | |
300 System.arraycopy (rects, 0, tmp, 0, index); | |
301 rects = tmp; | |
302 } | |
303 return rects; | |
304 } | |
305 | |
306 int getClientWidth () { | |
307 return (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (handle); | |
308 } | |
309 | |
310 /** | |
311 * Returns the receiver's text, which will be an empty | |
312 * string if it has never been set. | |
313 * | |
314 * @return the receiver's text | |
315 * | |
316 * @exception SWTException <ul> | |
317 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
318 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
319 * </ul> | |
320 */ | |
321 public String getText () { | |
322 checkWidget (); | |
323 return text; | |
324 } | |
325 | |
326 override int gtk_button_press_event (GtkWidget* widget, GdkEventButton* gdkEvent) { | |
327 int /*long*/ result = super.gtk_button_press_event (widget, gdkEvent); | |
328 if (result !is 0) return result; | |
329 if (gdkEvent.button is 1 && gdkEvent.type is OS.GDK_BUTTON_PRESS) { | |
330 if (focusIndex !is -1) setFocus (); | |
331 int x = cast(int) gdkEvent.x; | |
332 int y = cast(int) gdkEvent.y; | |
333 if ((style & SWT.MIRRORED) !is 0) x = getClientWidth () - x; | |
334 int offset = layout.getOffset (x, y, null); | |
335 int oldSelectionX = selection.x; | |
336 int oldSelectionY = selection.y; | |
337 selection.x = offset; | |
338 selection.y = -1; | |
339 if (oldSelectionX !is -1 && oldSelectionY !is -1) { | |
340 if (oldSelectionX > oldSelectionY) { | |
341 int temp = oldSelectionX; | |
342 oldSelectionX = oldSelectionY; | |
343 oldSelectionY = temp; | |
344 } | |
345 Rectangle rect = layout.getBounds (oldSelectionX, oldSelectionY); | |
346 redraw (rect.x, rect.y, rect.width, rect.height, false); | |
347 } | |
348 for (int j = 0; j < offsets.length; j++) { | |
349 Rectangle [] rects = getRectangles (j); | |
350 for (int i = 0; i < rects.length; i++) { | |
351 Rectangle rect = rects [i]; | |
352 if (rect.contains (x, y)) { | |
353 focusIndex = j; | |
354 redraw (); | |
355 return result; | |
356 } | |
357 } | |
358 } | |
359 } | |
360 return result; | |
361 } | |
362 | |
363 override int /*long*/ gtk_button_release_event (GtkWidget* widget, GdkEventButton* gdkEvent) { | |
364 int /*long*/ result = super.gtk_button_release_event (widget, gdkEvent); | |
365 if (result !is 0) return result; | |
366 if (focusIndex is -1) return result; | |
367 if (gdkEvent.button is 1) { | |
368 int x = cast(int) gdkEvent.x; | |
369 int y = cast(int) gdkEvent.y; | |
370 if ((style & SWT.MIRRORED) !is 0) x = getClientWidth () - x; | |
371 Rectangle [] rects = getRectangles (focusIndex); | |
372 for (int i = 0; i < rects.length; i++) { | |
373 Rectangle rect = rects [i]; | |
374 if (rect.contains (x, y)) { | |
375 Event ev = new Event (); | |
376 ev.text = ids [focusIndex]; | |
377 sendEvent (SWT.Selection, ev); | |
378 return result; | |
379 } | |
380 } | |
381 } | |
382 return result; | |
383 } | |
384 | |
385 override int /*long*/ gtk_event_after (GtkWidget* widget, GdkEvent* event) { | |
386 int /*long*/ result = super.gtk_event_after (widget, event); | |
387 switch (event.type) { | |
388 case OS.GDK_FOCUS_CHANGE: | |
389 redraw (); | |
390 break; | |
391 default: | |
392 } | |
393 return result; | |
394 } | |
395 | |
396 override int /*long*/ gtk_expose_event (GtkWidget* widget, GdkEventExpose* gdkEvent) { | |
397 if ((state & OBSCURED) !is 0) return 0; | |
398 GCData data = new GCData (); | |
399 data.damageRgn = gdkEvent.region; | |
400 GC gc = GC.gtk_new (this, data); | |
401 OS.gdk_gc_set_clip_region (gc.handle, gdkEvent.region); | |
402 int selStart = selection.x; | |
403 int selEnd = selection.y; | |
404 if (selStart > selEnd) { | |
405 selStart = selection.y; | |
406 selEnd = selection.x; | |
407 } | |
408 // temporary code to disable text selection | |
409 selStart = selEnd = -1; | |
410 if ((state & DISABLED) !is 0) gc.setForeground (disabledColor); | |
411 layout.draw (gc, 0, 0, selStart, selEnd, null, null); | |
412 if (hasFocus () && focusIndex !is -1) { | |
413 Rectangle [] rects = getRectangles (focusIndex); | |
414 for (int i = 0; i < rects.length; i++) { | |
415 Rectangle rect = rects [i]; | |
416 gc.drawFocus (rect.x, rect.y, rect.width, rect.height); | |
417 } | |
418 } | |
419 if (hooks (SWT.Paint) || filters (SWT.Paint)) { | |
420 Event event = new Event (); | |
421 event.count = gdkEvent.count; | |
422 event.x = gdkEvent.area.x; | |
423 event.y = gdkEvent.area.y; | |
424 event.width = gdkEvent.area.width; | |
425 event.height = gdkEvent.area.height; | |
426 if ((style & SWT.MIRRORED) !is 0) event.x = getClientWidth () - event.width - event.x; | |
427 event.gc = gc; | |
428 sendEvent (SWT.Paint, event); | |
429 event.gc = null; | |
430 } | |
431 gc.dispose (); | |
432 return 0; | |
433 } | |
434 | |
435 override int /*long*/ gtk_key_press_event (GtkWidget* widget, GdkEventKey* gdkEvent) { | |
436 int /*long*/ result = super.gtk_key_press_event (widget, gdkEvent); | |
437 if (result !is 0) return result; | |
438 if (focusIndex is -1) return result; | |
439 switch (gdkEvent.keyval) { | |
440 case OS.GDK_Return: | |
441 case OS.GDK_KP_Enter: | |
442 case OS.GDK_space: | |
443 Event event = new Event (); | |
444 event.text = ids [focusIndex]; | |
445 sendEvent (SWT.Selection, event); | |
446 break; | |
447 case OS.GDK_Tab: | |
448 if (focusIndex < offsets.length - 1) { | |
449 focusIndex++; | |
450 redraw (); | |
451 } | |
452 break; | |
453 case OS.GDK_ISO_Left_Tab: | |
454 if (focusIndex > 0) { | |
455 focusIndex--; | |
456 redraw (); | |
457 } | |
458 break; | |
459 default: | |
460 } | |
461 return result; | |
462 } | |
463 | |
464 override int /*long*/ gtk_motion_notify_event (GtkWidget* widget, GdkEventMotion* gdkEvent) { | |
465 int /*long*/ result = super.gtk_motion_notify_event (widget, gdkEvent); | |
466 if (result !is 0) return result; | |
467 int x = cast(int) gdkEvent.x; | |
468 int y = cast(int) gdkEvent.y; | |
469 if ((style & SWT.MIRRORED) !is 0) x = getClientWidth () - x; | |
470 if ((gdkEvent.state & OS.GDK_BUTTON1_MASK) !is 0) { | |
471 int oldSelection = selection.y; | |
472 selection.y = layout.getOffset (x, y, null); | |
473 if (selection.y !is oldSelection) { | |
474 int newSelection = selection.y; | |
475 if (oldSelection > newSelection) { | |
476 int temp = oldSelection; | |
477 oldSelection = newSelection; | |
478 newSelection = temp; | |
479 } | |
480 Rectangle rect = layout.getBounds (oldSelection, newSelection); | |
481 redraw (rect.x, rect.y, rect.width, rect.height, false); | |
482 } | |
483 } else { | |
484 for (int j = 0; j < offsets.length; j++) { | |
485 Rectangle [] rects = getRectangles (j); | |
486 for (int i = 0; i < rects.length; i++) { | |
487 Rectangle rect = rects [i]; | |
488 if (rect.contains (x, y)) { | |
489 setCursor (display.getSystemCursor (SWT.CURSOR_HAND)); | |
490 return result; | |
491 } | |
492 } | |
493 } | |
494 setCursor (null); | |
495 } | |
496 return result; | |
497 } | |
498 | |
499 override void releaseWidget () { | |
500 super.releaseWidget (); | |
501 if (layout !is null) layout.dispose (); | |
502 layout = null; | |
503 if (linkColor !is null) linkColor.dispose (); | |
504 linkColor = null; | |
505 if (disabledColor !is null) disabledColor.dispose (); | |
506 disabledColor = null; | |
507 offsets = null; | |
508 ids = null; | |
509 mnemonics = null; | |
510 text = null; | |
511 } | |
512 | |
513 /** | |
514 * Removes the listener from the collection of listeners who will | |
515 * be notified when the control is selected by the user. | |
516 * | |
517 * @param listener the listener which should no longer be notified | |
518 * | |
519 * @exception IllegalArgumentException <ul> | |
520 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
521 * </ul> | |
522 * @exception SWTException <ul> | |
523 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
524 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
525 * </ul> | |
526 * | |
527 * @see SelectionListener | |
528 * @see #addSelectionListener | |
529 */ | |
530 public void removeSelectionListener (SelectionListener listener) { | |
531 checkWidget (); | |
532 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
533 if (eventTable is null) return; | |
534 eventTable.unhook (SWT.Selection, listener); | |
535 eventTable.unhook (SWT.DefaultSelection, listener); | |
536 } | |
537 | |
538 String parse (String string) { | |
539 int length_ = string.length; | |
540 offsets = new Point[]( length_ / 4 ); | |
541 ids = new String[]( length_ / 4 ); | |
542 mnemonics = new int[] ( length_ / 4 + 1 ); | |
543 StringBuffer result = new StringBuffer (); | |
544 char [] buffer = string.dup; | |
545 | |
546 int index = 0, state = 0, linkIndex = 0; | |
547 int start = 0, tagStart = 0, linkStart = 0, endtagStart = 0, refStart = 0; | |
548 while (index < length_) { | |
549 int increment; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
550 dchar c = Character.toLowerCase (buffer.dcharAt (index, increment)); |
25 | 551 |
552 switch (state) { | |
553 case 0: | |
554 if (c is '<') { | |
555 tagStart = index; | |
556 state++; | |
557 } | |
558 break; | |
559 case 1: | |
560 if (c is 'a') state++; | |
561 break; | |
562 case 2: | |
563 switch (c) { | |
564 case 'h': | |
565 state = 7; | |
566 break; | |
567 case '>': | |
568 linkStart = index + 1; | |
569 state++; | |
570 break; | |
571 default: | |
51 | 572 if (Character.isWhitespace(c)) break; |
25 | 573 else state = 13; |
574 } | |
575 break; | |
576 case 3: | |
577 if (c is '<') { | |
578 endtagStart = index; | |
579 state++; | |
580 } | |
581 break; | |
582 case 4: | |
583 state = c is '/' ? state + 1 : 3; | |
584 break; | |
585 case 5: | |
586 state = c is 'a' ? state + 1 : 3; | |
587 break; | |
588 case 6: | |
589 if (c is '>') { | |
590 mnemonics [linkIndex] = parseMnemonics (buffer, start, tagStart, result); | |
591 int offset = result.length (); | |
592 parseMnemonics (buffer, linkStart, endtagStart, result); | |
593 offsets [linkIndex] = new Point (offset, result.length () - 1); | |
594 if (ids [linkIndex] is null) { | |
51 | 595 ids [linkIndex] = buffer[ linkStart .. endtagStart ]._idup(); |
25 | 596 } |
597 linkIndex++; | |
598 start = tagStart = linkStart = endtagStart = refStart = index + 1; | |
599 state = 0; | |
600 } else { | |
601 state = 3; | |
602 } | |
603 break; | |
604 case 7: | |
605 state = c is 'r' ? state + 1 : 0; | |
606 break; | |
607 case 8: | |
608 state = c is 'e' ? state + 1 : 0; | |
609 break; | |
610 case 9: | |
611 state = c is 'f' ? state + 1 : 0; | |
612 break; | |
613 case 10: | |
614 state = c is '=' ? state + 1 : 0; | |
615 break; | |
616 case 11: | |
617 if (c is '"') { | |
618 state++; | |
619 refStart = index + 1; | |
620 } else { | |
621 state = 0; | |
622 } | |
623 break; | |
624 case 12: | |
625 if (c is '"') { | |
51 | 626 ids[linkIndex] = buffer[ refStart .. index ]._idup(); |
25 | 627 state = 2; |
628 } | |
629 break; | |
630 case 13: | |
51 | 631 if (Character.isWhitespace (c)) { |
25 | 632 state = 0; |
633 } else if (c is '='){ | |
634 state++; | |
635 } | |
636 break; | |
637 case 14: | |
638 state = c is '"' ? state + 1 : 0; | |
639 break; | |
640 case 15: | |
641 if (c is '"') state = 2; | |
642 break; | |
643 default: | |
644 state = 0; | |
645 break; | |
646 } | |
647 index+=increment; | |
648 } | |
649 if (start < length_) { | |
650 int tmp = parseMnemonics (buffer, start, tagStart, result); | |
651 int mnemonic = parseMnemonics (buffer, Math.max (tagStart, linkStart), length_, result); | |
652 if (mnemonic is -1) mnemonic = tmp; | |
653 mnemonics [linkIndex] = mnemonic; | |
654 } else { | |
655 mnemonics [linkIndex] = -1; | |
656 } | |
657 if (offsets.length !is linkIndex) { | |
658 Point [] newOffsets = new Point [linkIndex]; | |
659 System.arraycopy (offsets, 0, newOffsets, 0, linkIndex); | |
660 offsets = newOffsets; | |
661 String [] newIDs = new String [linkIndex]; | |
662 System.arraycopy (ids, 0, newIDs, 0, linkIndex); | |
663 ids = newIDs; | |
664 int [] newMnemonics = new int [linkIndex + 1]; | |
665 System.arraycopy (mnemonics, 0, newMnemonics, 0, linkIndex + 1); | |
666 mnemonics = newMnemonics; | |
667 } | |
668 return result.toString (); | |
669 } | |
670 | |
671 int parseMnemonics (char[] buffer, int start, int end, StringBuffer result) { | |
672 int mnemonic = -1, index = start; | |
673 while (index < end) { | |
674 int incr = 1; | |
675 if ( buffer[index] is '&') { | |
676 if (index + 1 < end && buffer [index + 1] is '&') { | |
677 result.append (buffer [index]); | |
678 index++; | |
679 } else { | |
680 mnemonic = result.length(); | |
681 } | |
682 } else { | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
683 result.append (buffer.dcharAsStringAt(index, incr)); |
25 | 684 } |
685 index+=incr; | |
686 } | |
687 return mnemonic; | |
688 } | |
689 | |
690 override int setBounds(int x, int y, int width, int height, bool move, bool resize) { | |
691 int result = super.setBounds (x, y, width,height, move, resize); | |
692 if ((result & RESIZED) !is 0) { | |
693 layout.setWidth (width > 0 ? width : -1); | |
694 redraw (); | |
695 } | |
696 return result; | |
697 } | |
698 | |
699 override void setFontDescription (PangoFontDescription* font) { | |
700 super.setFontDescription (font); | |
701 layout.setFont (Font.gtk_new (display, font)); | |
702 } | |
703 | |
704 /** | |
705 * Sets the receiver's text. | |
706 * <p> | |
707 * The string can contain both regular text and hyperlinks. A hyperlink | |
708 * is delimited by an anchor tag, <A> and </A>. Within an | |
709 * anchor, a single HREF attribute is supported. When a hyperlink is | |
710 * selected, the text field of the selection event contains either the | |
711 * text of the hyperlink or the value of its HREF, if one was specified. | |
712 * In the rare case of identical hyperlinks within the same string, the | |
713 * HREF tag can be used to distinguish between them. The string may | |
714 * include the mnemonic character and line delimiters. | |
715 * </p> | |
716 * | |
717 * @param string the new text | |
718 * | |
719 * @exception SWTException <ul> | |
720 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
721 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
722 * </ul> | |
723 */ | |
724 public void setText (String string) { | |
725 checkWidget (); | |
726 // SWT extension: allow null for zero length string | |
727 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT); | |
728 if (string.equals(text)) return; | |
729 text = string; | |
730 layout.setText (parse (string)); | |
731 focusIndex = offsets.length > 0 ? 0 : -1; | |
732 selection.x = selection.y = -1; | |
733 bool enabled = (state & DISABLED) is 0; | |
734 TextStyle linkStyle = new TextStyle (null, enabled ? linkColor : disabledColor, null); | |
735 linkStyle.underline = true; | |
736 int [] bidiSegments = new int [offsets.length*2]; | |
737 for (int i = 0; i < offsets.length; i++) { | |
738 Point point = offsets [i]; | |
739 layout.setStyle (linkStyle, point.x, point.y); | |
740 bidiSegments[i*2] = point.x; | |
741 bidiSegments[i*2+1] = point.y+1; | |
742 } | |
743 layout.setSegments (bidiSegments); | |
744 TextStyle mnemonicStyle = new TextStyle (null, null, null); | |
745 mnemonicStyle.underline = true; | |
746 for (int i = 0; i < mnemonics.length; i++) { | |
747 int mnemonic = mnemonics [i]; | |
748 if (mnemonic !is -1) { | |
749 layout.setStyle (mnemonicStyle, mnemonic, mnemonic); | |
750 } | |
751 } | |
752 redraw (); | |
753 } | |
754 | |
755 override void showWidget () { | |
756 super.showWidget (); | |
757 fixStyle (handle); | |
758 } | |
759 | |
760 override int traversalCode (int key, GdkEventKey* event) { | |
761 if (offsets.length is 0) return 0; | |
762 int bits = super.traversalCode (key, event); | |
763 if (key is OS.GDK_Tab && focusIndex < offsets.length - 1) { | |
764 return bits & ~SWT.TRAVERSE_TAB_NEXT; | |
765 } | |
766 if (key is OS.GDK_ISO_Left_Tab && focusIndex > 0) { | |
767 return bits & ~SWT.TRAVERSE_TAB_PREVIOUS; | |
768 } | |
769 return bits; | |
770 } | |
771 } |