comparison org.eclipse.ui.forms/src/org/eclipse/ui/internal/forms/widgets/FormTextModel.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children dbfb303e8fb0
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 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.ui.internal.forms.widgets.FormTextModel;
14
15 import org.eclipse.ui.internal.forms.widgets.Paragraph;
16 import org.eclipse.ui.internal.forms.widgets.IFocusSelectable;
17 import org.eclipse.ui.internal.forms.widgets.ParagraphSegment;
18 import org.eclipse.ui.internal.forms.widgets.IHyperlinkSegment;
19 import org.eclipse.ui.internal.forms.widgets.ControlSegment;
20 import org.eclipse.ui.internal.forms.widgets.ImageSegment;
21 import org.eclipse.ui.internal.forms.widgets.ObjectSegment;
22 import org.eclipse.ui.internal.forms.widgets.SWTUtil;
23
24 import org.eclipse.swt.SWT;
25 import org.eclipse.ui.forms.HyperlinkSettings;
26
27 import java.lang.all;
28 import java.util.Set;
29 import java.io.InputStream;
30
31 static import tango.text.xml.Document;
32 static import tango.io.device.Array;
33
34 public class FormTextModel {
35 // private static const DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
36 // .newInstance();
37
38 alias tango.text.xml.Document.Document!(char) Document;
39 alias Document.NodeImpl Node;
40
41 private bool whitespaceNormalized = true;
42
43 private Vector paragraphs;
44
45 private IFocusSelectable[] selectableSegments;
46
47 private int selectedSegmentIndex = -1;
48
49 private int savedSelectedLinkIndex = -1;
50
51 private HyperlinkSettings hyperlinkSettings;
52
53 public static const String BOLD_FONT_ID = "f.____bold"; //$NON-NLS-1$
54
55 //private static final int TEXT_ONLY_LINK = 1;
56
57 //private static final int IMG_ONLY_LINK = 2;
58
59 //private static final int TEXT_AND_IMAGES_LINK = 3;
60
61 public this() {
62 reset();
63 }
64
65 /*
66 * @see ITextModel#getParagraphs()
67 */
68 public Paragraph[] getParagraphs() {
69 if (paragraphs is null)
70 return new Paragraph[0];
71 return arraycast!(Paragraph)(paragraphs
72 .toArray());
73 }
74
75 public String getAccessibleText() {
76 if (paragraphs is null)
77 return ""; //$NON-NLS-1$
78 StringBuffer sbuf = new StringBuffer();
79 for (int i = 0; i < paragraphs.size(); i++) {
80 Paragraph paragraph = cast(Paragraph) paragraphs.get(i);
81 String text = paragraph.getAccessibleText();
82 sbuf.append(text);
83 }
84 return sbuf.toString();
85 }
86
87 /*
88 * @see ITextModel#parse(String)
89 */
90 public void parseTaggedText(String taggedText, bool expandURLs) {
91 if (taggedText is null) {
92 reset();
93 return;
94 }
95 _parseTaggedText(taggedText, expandURLs);
96 }
97
98 public void parseInputStream(InputStream is_, bool expandURLs) {
99 auto buf = new tango.io.device.Array.Array( 1024 );
100 {
101 int l;
102 byte[1024] a = void;
103 while((l = is_.read(a)) > 0 ){
104 buf.append( a[ 0 .. l ] );
105 }
106 }
107 _parseTaggedText( cast(char[]) buf.slice(), expandURLs );
108 // documentBuilderFactory.setNamespaceAware(true);
109 // documentBuilderFactory.setIgnoringComments(true);
110 //
111 // reset();
112 // try {
113 // DocumentBuilder parser = documentBuilderFactory
114 // .newDocumentBuilder();
115 // InputSource source = new InputSource(is_);
116 // Document doc = parser.parse(source);
117 // processDocument(doc, expandURLs);
118 // } catch (ParserConfigurationException e) {
119 // SWT.error(SWT.ERROR_INVALID_ARGUMENT, e);
120 // } catch (SAXException e) {
121 // SWT.error(SWT.ERROR_INVALID_ARGUMENT, e);
122 // } catch (IOException e) {
123 // SWT.error(SWT.ERROR_IO, e);
124 // }
125 }
126 private void _parseTaggedText( char[] text, bool expandURLs ){
127 reset();
128 // try {
129 // auto doc = tango.text.xml.Document.Document!(char)();
130 // doc.parse(text);
131 // processDocument(doc, expandURLs);
132 // } catch (XmlException e) {
133 // SWT.error(SWT.ERROR_INVALID_ARGUMENT, e);
134 // } catch (IOException e) {
135 // SWT.error(SWT.ERROR_IO, e);
136 // }
137 }
138
139 // private void processDocument(tango.text.xml.Document.Document!(char) doc, bool expandURLs) {
140 // auto root = doc.query.root.dup;
141 // auto children = root.childs.dup;
142 // processSubnodes(paragraphs, children, expandURLs);
143 // }
144
145 /+ private void processSubnodes(Vector plist, NodeList children, bool expandURLs) {
146 //o for (int i = 0; i < children.getLength(); i++) {
147 //o Node child = children.item(i);
148 foreach( child; children ){
149 //o if (child.getNodeType() is Node.TEXT_NODE) {
150 if (child.type is XmlNodeType.Data) {
151 // Make an implicit paragraph
152 String text = getSingleNodeText(child);
153 if ( !isIgnorableWhiteSpace(text, true)) {
154 Paragraph p = new Paragraph(true);
155 // p.parseRegularText(text, expandURLs, true,
156 // getHyperlinkSettings(), null);
157 // plist.add(p);
158 // }
159 // } else if (child.getNodeType() is Node.ELEMENT_NODE) {
160 // String tag = child.getNodeName().toLowerCase();
161 // if (tag.equals("p")) { //$NON-NLS-1$
162 // Paragraph p = processParagraph(child, expandURLs);
163 // if (p !is null)
164 // plist.add(p);
165 // } else if (tag.equals("li")) { //$NON-NLS-1$
166 // Paragraph p = processListItem(child, expandURLs);
167 // if (p !is null)
168 // plist.add(p);
169 }
170 }
171 }
172 }+/
173 /++
174
175 private Paragraph processParagraph(Node paragraph, bool expandURLs) {
176 NodeList children = paragraph.getChildNodes();
177 NamedNodeMap atts = paragraph.getAttributes();
178 Node addSpaceAtt = atts.getNamedItem("addVerticalSpace"); //$NON-NLS-1$
179 bool addSpace = true;
180
181 if (addSpaceAtt is null)
182 addSpaceAtt = atts.getNamedItem("vspace"); //$NON-NLS-1$
183
184 if (addSpaceAtt !is null) {
185 String value = addSpaceAtt.getNodeValue();
186 addSpace = value.equalsIgnoreCase("true"); //$NON-NLS-1$
187 }
188 Paragraph p = new Paragraph(addSpace);
189
190 processSegments(p, children, expandURLs);
191 return p;
192 }
193
194 private Paragraph processListItem(Node listItem, bool expandURLs) {
195 NodeList children = listItem.getChildNodes();
196 NamedNodeMap atts = listItem.getAttributes();
197 Node addSpaceAtt = atts.getNamedItem("addVerticalSpace");//$NON-NLS-1$
198 Node styleAtt = atts.getNamedItem("style");//$NON-NLS-1$
199 Node valueAtt = atts.getNamedItem("value");//$NON-NLS-1$
200 Node indentAtt = atts.getNamedItem("indent");//$NON-NLS-1$
201 Node bindentAtt = atts.getNamedItem("bindent");//$NON-NLS-1$
202 int style = BulletParagraph.CIRCLE;
203 int indent = -1;
204 int bindent = -1;
205 String text = null;
206 bool addSpace = true;
207
208 if (addSpaceAtt !is null) {
209 String value = addSpaceAtt.getNodeValue();
210 addSpace = value.equalsIgnoreCase("true"); //$NON-NLS-1$
211 }
212 if (styleAtt !is null) {
213 String value = styleAtt.getNodeValue();
214 if (value.equalsIgnoreCase("text")) { //$NON-NLS-1$
215 style = BulletParagraph.TEXT;
216 } else if (value.equalsIgnoreCase("image")) { //$NON-NLS-1$
217 style = BulletParagraph.IMAGE;
218 } else if (value.equalsIgnoreCase("bullet")) { //$NON-NLS-1$
219 style = BulletParagraph.CIRCLE;
220 }
221 }
222 if (valueAtt !is null) {
223 text = valueAtt.getNodeValue();
224 if (style is BulletParagraph.IMAGE)
225 text = "i." + text; //$NON-NLS-1$
226 }
227 if (indentAtt !is null) {
228 String value = indentAtt.getNodeValue();
229 try {
230 indent = Integer.parseInt(value);
231 } catch (NumberFormatException e) {
232 }
233 }
234 if (bindentAtt !is null) {
235 String value = bindentAtt.getNodeValue();
236 try {
237 bindent = Integer.parseInt(value);
238 } catch (NumberFormatException e) {
239 }
240 }
241
242 BulletParagraph p = new BulletParagraph(addSpace);
243 p.setIndent(indent);
244 p.setBulletIndent(bindent);
245 p.setBulletStyle(style);
246 p.setBulletText(text);
247
248 processSegments(p, children, expandURLs);
249 return p;
250 }
251
252 private void processSegments(Paragraph p, NodeList children,
253 bool expandURLs) {
254 for (int i = 0; i < children.getLength(); i++) {
255 Node child = children.item(i);
256 ParagraphSegment segment = null;
257
258 if (child.getNodeType() is Node.TEXT_NODE) {
259 String value = getSingleNodeText(child);
260
261 if (value !is null && !isIgnorableWhiteSpace(value, false)) {
262 p.parseRegularText(value, expandURLs, true,
263 getHyperlinkSettings(), null);
264 }
265 } else if (child.getNodeType() is Node.ELEMENT_NODE) {
266 String name = child.getNodeName();
267 if (name.equalsIgnoreCase("img")) { //$NON-NLS-1$
268 segment = processImageSegment(child);
269 } else if (name.equalsIgnoreCase("a")) { //$NON-NLS-1$
270 segment = processHyperlinkSegment(child,
271 getHyperlinkSettings());
272 } else if (name.equalsIgnoreCase("span")) { //$NON-NLS-1$
273 processTextSegment(p, expandURLs, child);
274 } else if (name.equalsIgnoreCase("b")) { //$NON-NLS-1$
275 String text = getNodeText(child);
276 String fontId = BOLD_FONT_ID;
277 p.parseRegularText(text, expandURLs, true,
278 getHyperlinkSettings(), fontId);
279 } else if (name.equalsIgnoreCase("br")) { //$NON-NLS-1$
280 segment = new BreakSegment();
281 } else if (name.equalsIgnoreCase("control")) { //$NON-NLS-1$
282 segment = processControlSegment(child);
283 }
284 }
285 if (segment !is null) {
286 p.addSegment(segment);
287 }
288 }
289 }
290 ++/
291 private bool isIgnorableWhiteSpace(String text, bool ignoreSpaces) {
292 for (int i = 0; i < text.length; i++) {
293 char c = text.charAt(i);
294 if (ignoreSpaces && c is ' ')
295 continue;
296 if (c is '\n' || c is '\r' || c is '\f')
297 continue;
298 return false;
299 }
300 return true;
301 }
302 /++
303 private ImageSegment processImageSegment(Node image) {
304 ImageSegment segment = new ImageSegment();
305 processObjectSegment(segment, image, "i."); //$NON-NLS-1$
306 return segment;
307 }
308
309 private ControlSegment processControlSegment(Node control) {
310 ControlSegment segment = new ControlSegment();
311 processObjectSegment(segment, control, "o."); //$NON-NLS-1$
312 Node fill = control.getAttributes().getNamedItem("fill"); //$NON-NLS-1$
313 if (fill !is null) {
314 String value = fill.getNodeValue();
315 bool doFill = value.equalsIgnoreCase("true"); //$NON-NLS-1$
316 segment.setFill(doFill);
317 }
318 try {
319 Node width = control.getAttributes().getNamedItem("width"); //$NON-NLS-1$
320 if (width !is null) {
321 String value = width.getNodeValue();
322 int doWidth = Integer.parseInt(value);
323 segment.setWidth(doWidth);
324 }
325 Node height = control.getAttributes().getNamedItem("height"); //$NON-NLS-1$
326 if (height !is null) {
327 String value = height.getNodeValue();
328 int doHeight = Integer.parseInt(value);
329 segment.setHeight(doHeight);
330 }
331 }
332 catch (NumberFormatException e) {
333 // ignore invalid width or height
334 }
335 return segment;
336 }
337
338 private void processObjectSegment(ObjectSegment segment, Node object, String prefix) {
339 NamedNodeMap atts = object.getAttributes();
340 Node id = atts.getNamedItem("href"); //$NON-NLS-1$
341 Node align_ = atts.getNamedItem("align"); //$NON-NLS-1$
342 if (id !is null) {
343 String value = id.getNodeValue();
344 segment.setObjectId(prefix + value);
345 }
346 if (align_ !is null) {
347 String value = align_.getNodeValue().toLowerCase();
348 if (value.equals("top")) //$NON-NLS-1$
349 segment.setVerticalAlignment(ImageSegment.TOP);
350 else if (value.equals("middle")) //$NON-NLS-1$
351 segment.setVerticalAlignment(ImageSegment.MIDDLE);
352 else if (value.equals("bottom")) //$NON-NLS-1$
353 segment.setVerticalAlignment(ImageSegment.BOTTOM);
354 }
355 }
356 ++/
357 private void appendText(String value, StringBuffer buf, int[] spaceCounter) {
358 if (!whitespaceNormalized)
359 buf.append(value);
360 else {
361 for (int j = 0; j < value.length; j++) {
362 char c = value.charAt(j);
363 if (c is ' ' || c is '\t') {
364 // space
365 if (++spaceCounter[0] is 1) {
366 buf.append(c);
367 }
368 } else if (c is '\n' || c is '\r' || c is '\f') {
369 // new line
370 if (++spaceCounter[0] is 1) {
371 buf.append(' ');
372 }
373 } else {
374 // other characters
375 spaceCounter[0] = 0;
376 buf.append(c);
377 }
378 }
379 }
380 }
381
382 private String getNormalizedText(String text) {
383 int[] spaceCounter = new int[1];
384 StringBuffer buf = new StringBuffer();
385
386 if (text is null)
387 return null;
388 appendText(text, buf, spaceCounter);
389 return buf.toString();
390 }
391
392 private String getSingleNodeText(tango.text.xml.Document.Document!(char).NodeImpl node) {
393 return getNormalizedText(node.value());
394 }
395 /++
396
397 private String getNodeText(Node node) {
398 NodeList children = node.getChildNodes();
399 StringBuffer buf = new StringBuffer();
400 int[] spaceCounter = new int[1];
401
402 for (int i = 0; i < children.getLength(); i++) {
403 Node child = children.item(i);
404 if (child.getNodeType() is Node.TEXT_NODE) {
405 String value = child.getNodeValue();
406 appendText(value, buf, spaceCounter);
407 }
408 }
409 return buf.toString().trim();
410 }
411
412 private ParagraphSegment processHyperlinkSegment(Node link,
413 HyperlinkSettings settings) {
414 NamedNodeMap atts = link.getAttributes();
415 String href = null;
416 bool wrapAllowed = true;
417 String boldFontId = null;
418
419 Node hrefAtt = atts.getNamedItem("href"); //$NON-NLS-1$
420 if (hrefAtt !is null) {
421 href = hrefAtt.getNodeValue();
422 }
423 Node boldAtt = atts.getNamedItem("bold"); //$NON-NLS-1$
424 if (boldAtt !is null) {
425 boldFontId = BOLD_FONT_ID;
426 }
427 Node nowrap = atts.getNamedItem("nowrap"); //$NON-NLS-1$
428 if (nowrap !is null) {
429 String value = nowrap.getNodeValue();
430 if (value !is null && value.equalsIgnoreCase("true")) //$NON-NLS-1$
431 wrapAllowed = false;
432 }
433 Object status = checkChildren(link);
434 if ( auto child = cast(Node)status ) {
435 ImageHyperlinkSegment segment = new ImageHyperlinkSegment();
436 segment.setHref(href);
437 segment.setWordWrapAllowed(wrapAllowed);
438 Node alt = child.getAttributes().getNamedItem("alt"); //$NON-NLS-1$
439 if (alt !is null)
440 segment.setTooltipText(alt.getNodeValue());
441 Node text = child.getAttributes().getNamedItem("text"); //$NON-NLS-1$
442 if (text !is null)
443 segment.setText(text.getNodeValue());
444 processObjectSegment(segment, child, "i."); //$NON-NLS-1$
445 return segment;
446 } else if ( auto textObj = cast(ArrayWrapperString)status ) {
447 String text = textObj.array;
448 TextHyperlinkSegment segment = new TextHyperlinkSegment(text,
449 settings, null);
450 segment.setHref(href);
451 segment.setFontId(boldFontId);
452 Node alt = atts.getNamedItem("alt"); //$NON-NLS-1$
453 if (alt !is null)
454 segment.setTooltipText(alt.getNodeValue());
455 segment.setWordWrapAllowed(wrapAllowed);
456 return segment;
457 } else {
458 AggregateHyperlinkSegment parent = new AggregateHyperlinkSegment();
459 parent.setHref(href);
460 NodeList children = link.getChildNodes();
461 for (int i = 0; i < children.getLength(); i++) {
462 Node child = children.item(i);
463 if (child.getNodeType() is Node.TEXT_NODE) {
464 String value = child.getNodeValue();
465 TextHyperlinkSegment ts = new TextHyperlinkSegment(
466 getNormalizedText(value), settings, null);
467 Node alt = atts.getNamedItem("alt"); //$NON-NLS-1$
468 if (alt !is null)
469 ts.setTooltipText(alt.getNodeValue());
470 ts.setWordWrapAllowed(wrapAllowed);
471 parent.add(ts);
472 } else if (child.getNodeType() is Node.ELEMENT_NODE) {
473 String name = child.getNodeName();
474 if (name.equalsIgnoreCase("img")) { //$NON-NLS-1$
475 ImageHyperlinkSegment is_ = new ImageHyperlinkSegment();
476 processObjectSegment(is_, child, "i."); //$NON-NLS-1$
477 Node alt = child.getAttributes().getNamedItem("alt"); //$NON-NLS-1$
478 if (alt !is null)
479 is_.setTooltipText(alt.getNodeValue());
480 parent.add(is_);
481 is_.setWordWrapAllowed(wrapAllowed);
482 }
483 }
484 }
485 return parent;
486 }
487 }
488
489 private Object checkChildren(Node node) {
490 bool text = false;
491 Node imgNode = null;
492 //int status = 0;
493
494 NodeList children = node.getChildNodes();
495 for (int i = 0; i < children.getLength(); i++) {
496 Node child = children.item(i);
497 if (child.getNodeType() is Node.TEXT_NODE)
498 text = true;
499 else if (child.getNodeType() is Node.ELEMENT_NODE
500 && child.getNodeName().equalsIgnoreCase("img")) { //$NON-NLS-1$
501 imgNode = child;
502 }
503 }
504 if (text && imgNode is null)
505 return getNodeText(node);
506 else if (!text && imgNode !is null)
507 return imgNode;
508 else return null;
509 }
510
511 private void processTextSegment(Paragraph p, bool expandURLs,
512 Node textNode) {
513 String text = getNodeText(textNode);
514
515 NamedNodeMap atts = textNode.getAttributes();
516 Node font = atts.getNamedItem("font"); //$NON-NLS-1$
517 Node color = atts.getNamedItem("color"); //$NON-NLS-1$
518 bool wrapAllowed=true;
519 Node nowrap = atts.getNamedItem("nowrap"); //$NON-NLS-1$
520 if (nowrap !is null) {
521 String value = nowrap.getNodeValue();
522 if (value !is null && value.equalsIgnoreCase("true")) //$NON-NLS-1$
523 wrapAllowed = false;
524 }
525 String fontId = null;
526 String colorId = null;
527 if (font !is null) {
528 fontId = "f." + font.getNodeValue(); //$NON-NLS-1$
529 }
530 if (color !is null) {
531 colorId = "c." + color.getNodeValue(); //$NON-NLS-1$
532 }
533 p.parseRegularText(text, expandURLs, wrapAllowed, getHyperlinkSettings(), fontId,
534 colorId);
535 }
536 ++/
537 public void parseRegularText(String regularText, bool convertURLs) {
538 reset();
539
540 if (regularText is null)
541 return;
542
543 regularText = getNormalizedText(regularText);
544
545 Paragraph p = new Paragraph(true);
546 paragraphs.add(p);
547 int pstart = 0;
548
549 for (int i = 0; i < regularText.length; i++) {
550 char c = regularText.charAt(i);
551 if (p is null) {
552 p = new Paragraph(true);
553 paragraphs.add(p);
554 }
555 if (c is '\n') {
556 String text = regularText.substring(pstart, i);
557 pstart = i + 1;
558 p.parseRegularText(text, convertURLs, true, getHyperlinkSettings(),
559 null);
560 p = null;
561 }
562 }
563 if (p !is null) {
564 // no new line
565 String text = regularText.substring(pstart);
566 p.parseRegularText(text, convertURLs, true, getHyperlinkSettings(), null);
567 }
568 }
569
570 public HyperlinkSettings getHyperlinkSettings() {
571 // #132723 cannot have null settings
572 if (hyperlinkSettings is null)
573 hyperlinkSettings = new HyperlinkSettings(SWTUtil.getStandardDisplay());
574 return hyperlinkSettings;
575 }
576
577 public void setHyperlinkSettings(HyperlinkSettings settings) {
578 this.hyperlinkSettings = settings;
579 }
580
581 private void reset() {
582 if (paragraphs is null)
583 paragraphs = new Vector;
584 paragraphs.clear();
585 selectedSegmentIndex = -1;
586 savedSelectedLinkIndex = -1;
587 selectableSegments = null;
588 }
589
590 IFocusSelectable[] getFocusSelectableSegments() {
591 if (selectableSegments !is null || paragraphs is null)
592 return selectableSegments;
593 Vector result = new Vector();
594 for (int i = 0; i < paragraphs.size(); i++) {
595 Paragraph p = cast(Paragraph) paragraphs.get(i);
596 ParagraphSegment[] segments = p.getSegments();
597 for (int j = 0; j < segments.length; j++) {
598 if (null !is cast(IFocusSelectable)segments[j] )
599 result.add(segments[j]);
600 }
601 }
602 selectableSegments = arraycast!(IFocusSelectable)(result.toArray());
603 return selectableSegments;
604 }
605
606 public IHyperlinkSegment getHyperlink(int index) {
607 IFocusSelectable[] selectables = getFocusSelectableSegments();
608 if (selectables.length>index) {
609 IFocusSelectable link = selectables[index];
610 if (auto l = cast(IHyperlinkSegment)link )
611 return l;
612 }
613 return null;
614 }
615
616 public IHyperlinkSegment findHyperlinkAt(int x, int y) {
617 IFocusSelectable[] selectables = getFocusSelectableSegments();
618 for (int i = 0; i < selectables.length; i++) {
619 IFocusSelectable segment = selectables[i];
620 if ( auto link = cast(IHyperlinkSegment)segment ) {
621 if (link.contains(x, y))
622 return link;
623 }
624 }
625 return null;
626 }
627
628 public int getHyperlinkCount() {
629 return getFocusSelectableSegments().length;
630 }
631
632 public int indexOf(IHyperlinkSegment link) {
633 IFocusSelectable[] selectables = getFocusSelectableSegments();
634 for (int i = 0; i < selectables.length; i++) {
635 IFocusSelectable segment = selectables[i];
636 if (auto l = cast(IHyperlinkSegment)segment ) {
637 if (link is l)
638 return i;
639 }
640 }
641 return -1;
642 }
643
644 public ParagraphSegment findSegmentAt(int x, int y) {
645 for (int i = 0; i < paragraphs.size(); i++) {
646 Paragraph p = cast(Paragraph) paragraphs.get(i);
647 ParagraphSegment segment = p.findSegmentAt(x, y);
648 if (segment !is null)
649 return segment;
650 }
651 return null;
652 }
653
654 public void clearCache(String fontId) {
655 for (int i = 0; i < paragraphs.size(); i++) {
656 Paragraph p = cast(Paragraph) paragraphs.get(i);
657 p.clearCache(fontId);
658 }
659 }
660
661 public IFocusSelectable getSelectedSegment() {
662 if (selectableSegments is null || selectedSegmentIndex is -1)
663 return null;
664 return selectableSegments[selectedSegmentIndex];
665 }
666
667 public int getSelectedSegmentIndex() {
668 return selectedSegmentIndex;
669 }
670
671 public bool linkExists(IHyperlinkSegment link) {
672 if (selectableSegments is null)
673 return false;
674 for (int i=0; i<selectableSegments.length; i++) {
675 if (selectableSegments[i] is link)
676 return true;
677 }
678 return false;
679 }
680
681 public bool traverseFocusSelectableObjects(bool next) {
682 IFocusSelectable[] selectables = getFocusSelectableSegments();
683 if (selectables is null)
684 return false;
685 int size = selectables.length;
686 if (next) {
687 selectedSegmentIndex++;
688 } else
689 selectedSegmentIndex--;
690
691 if (selectedSegmentIndex < 0 || selectedSegmentIndex > size - 1) {
692 selectedSegmentIndex = -1;
693 }
694 return selectedSegmentIndex !is -1;
695 }
696
697 public IFocusSelectable getNextFocusSegment(bool next) {
698 IFocusSelectable[] selectables = getFocusSelectableSegments();
699 if (selectables is null)
700 return null;
701 int nextIndex = next?selectedSegmentIndex+1:selectedSegmentIndex-1;
702
703 if (nextIndex < 0 || nextIndex > selectables.length - 1) {
704 return null;
705 }
706 return selectables[nextIndex];
707 }
708
709 public bool restoreSavedLink() {
710 if (savedSelectedLinkIndex !is -1) {
711 selectedSegmentIndex = savedSelectedLinkIndex;
712 return true;
713 }
714 return false;
715 }
716
717 public void selectLink(IHyperlinkSegment link) {
718 if (link is null) {
719 savedSelectedLinkIndex = selectedSegmentIndex;
720 selectedSegmentIndex = -1;
721 }
722 else {
723 select(link);
724
725 }
726 }
727
728 public void select(IFocusSelectable selectable) {
729 IFocusSelectable[] selectables = getFocusSelectableSegments();
730 selectedSegmentIndex = -1;
731 if (selectables is null)
732 return;
733 for (int i = 0; i < selectables.length; i++) {
734 if ((cast(Object)selectables[i]).opEquals(cast(Object)selectable)) {
735 selectedSegmentIndex = i;
736 break;
737 }
738 }
739 }
740
741 public bool hasFocusSegments() {
742 IFocusSelectable[] segments = getFocusSelectableSegments();
743 if (segments.length > 0)
744 return true;
745 return false;
746 }
747
748 public void dispose() {
749 paragraphs = null;
750 selectedSegmentIndex = -1;
751 savedSelectedLinkIndex = -1;
752 selectableSegments = null;
753 }
754
755 /**
756 * @return Returns the whitespaceNormalized.
757 */
758 public bool isWhitespaceNormalized() {
759 return whitespaceNormalized;
760 }
761
762 /**
763 * @param whitespaceNormalized
764 * The whitespaceNormalized to set.
765 */
766 public void setWhitespaceNormalized(bool whitespaceNormalized) {
767 this.whitespaceNormalized = whitespaceNormalized;
768 }
769 }