comparison dwtx/ui/internal/forms/widgets/FormTextModel.d @ 75:5d489b9f966c

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