Source Code Cross Referenced for FormText.java in  » IDE-Eclipse » ui » org » eclipse » ui » forms » widgets » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » ui » org.eclipse.ui.forms.widgets 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.ui.forms.widgets;
0011:
0012:        import java.io.InputStream;
0013:        import java.util.ArrayList;
0014:        import java.util.Enumeration;
0015:        import java.util.Hashtable;
0016:
0017:        import org.eclipse.core.runtime.ListenerList;
0018:        import org.eclipse.swt.SWT;
0019:        import org.eclipse.swt.SWTException;
0020:        import org.eclipse.swt.accessibility.ACC;
0021:        import org.eclipse.swt.accessibility.Accessible;
0022:        import org.eclipse.swt.accessibility.AccessibleAdapter;
0023:        import org.eclipse.swt.accessibility.AccessibleControlAdapter;
0024:        import org.eclipse.swt.accessibility.AccessibleControlEvent;
0025:        import org.eclipse.swt.accessibility.AccessibleEvent;
0026:        import org.eclipse.swt.custom.ScrolledComposite;
0027:        import org.eclipse.swt.dnd.Clipboard;
0028:        import org.eclipse.swt.dnd.TextTransfer;
0029:        import org.eclipse.swt.dnd.Transfer;
0030:        import org.eclipse.swt.events.DisposeEvent;
0031:        import org.eclipse.swt.events.DisposeListener;
0032:        import org.eclipse.swt.events.FocusEvent;
0033:        import org.eclipse.swt.events.FocusListener;
0034:        import org.eclipse.swt.events.MenuEvent;
0035:        import org.eclipse.swt.events.MenuListener;
0036:        import org.eclipse.swt.events.MouseEvent;
0037:        import org.eclipse.swt.events.MouseListener;
0038:        import org.eclipse.swt.events.MouseMoveListener;
0039:        import org.eclipse.swt.events.MouseTrackListener;
0040:        import org.eclipse.swt.events.PaintEvent;
0041:        import org.eclipse.swt.events.PaintListener;
0042:        import org.eclipse.swt.events.SelectionAdapter;
0043:        import org.eclipse.swt.events.SelectionEvent;
0044:        import org.eclipse.swt.events.SelectionListener;
0045:        import org.eclipse.swt.graphics.Color;
0046:        import org.eclipse.swt.graphics.Font;
0047:        import org.eclipse.swt.graphics.FontMetrics;
0048:        import org.eclipse.swt.graphics.GC;
0049:        import org.eclipse.swt.graphics.Image;
0050:        import org.eclipse.swt.graphics.Point;
0051:        import org.eclipse.swt.graphics.Rectangle;
0052:        import org.eclipse.swt.widgets.Canvas;
0053:        import org.eclipse.swt.widgets.Composite;
0054:        import org.eclipse.swt.widgets.Control;
0055:        import org.eclipse.swt.widgets.Event;
0056:        import org.eclipse.swt.widgets.Layout;
0057:        import org.eclipse.swt.widgets.Listener;
0058:        import org.eclipse.swt.widgets.Menu;
0059:        import org.eclipse.swt.widgets.MenuItem;
0060:        import org.eclipse.swt.widgets.TypedListener;
0061:        import org.eclipse.ui.forms.HyperlinkSettings;
0062:        import org.eclipse.ui.forms.events.HyperlinkEvent;
0063:        import org.eclipse.ui.forms.events.IHyperlinkListener;
0064:        import org.eclipse.ui.internal.forms.Messages;
0065:        import org.eclipse.ui.internal.forms.widgets.ControlSegment;
0066:        import org.eclipse.ui.internal.forms.widgets.FormTextModel;
0067:        import org.eclipse.ui.internal.forms.widgets.FormUtil;
0068:        import org.eclipse.ui.internal.forms.widgets.IFocusSelectable;
0069:        import org.eclipse.ui.internal.forms.widgets.IHyperlinkSegment;
0070:        import org.eclipse.ui.internal.forms.widgets.ImageSegment;
0071:        import org.eclipse.ui.internal.forms.widgets.Locator;
0072:        import org.eclipse.ui.internal.forms.widgets.Paragraph;
0073:        import org.eclipse.ui.internal.forms.widgets.ParagraphSegment;
0074:        import org.eclipse.ui.internal.forms.widgets.SelectionData;
0075:        import org.eclipse.ui.internal.forms.widgets.TextSegment;
0076:
0077:        /**
0078:         * This class is a read-only text control that is capable of rendering wrapped
0079:         * text. Text can be rendered as-is or by parsing the formatting XML tags.
0080:         * Independently, words that start with http:// can be converted into hyperlinks
0081:         * on the fly.
0082:         * <p>
0083:         * When configured to use formatting XML, the control requires the root element
0084:         * <code>form</code> to be used. The following tags can be children of the
0085:         * <code>form</code> element:
0086:         * </p>
0087:         * <ul>
0088:         * <li><b>p </b>- for defining paragraphs. The following attributes are
0089:         * allowed:
0090:         * <ul>
0091:         * <li><b>vspace </b>- if set to 'false', no vertical space will be added
0092:         * (default is 'true')</li>
0093:         * </ul>
0094:         * </li>
0095:         * <li><b>li </b>- for defining list items. The following attributes are
0096:         * allowed:
0097:         * <ul>
0098:         * <li><b>vspace </b>- the same as with the <b>p </b> tag</li>
0099:         * <li><b>style </b>- could be 'bullet' (default), 'text' and 'image'</li>
0100:         * <li><b>value </b>- not used for 'bullet'. For text, it is the value of the
0101:         * text that is rendered as a bullet. For image, it is the href of the image to
0102:         * be rendered as a bullet.</li>
0103:         * <li><b>indent </b>- the number of pixels to indent the text in the list item
0104:         * </li>
0105:         * <li><b>bindent </b>- the number of pixels to indent the bullet itself</li>
0106:         * </ul>
0107:         * </li>
0108:         * </ul>
0109:         * <p>
0110:         * Text in paragraphs and list items will be wrapped according to the width of
0111:         * the control. The following tags can appear as children of either <b>p </b> or
0112:         * <b>li </b> elements:
0113:         * <ul>
0114:         * <li><b>img </b>- to render an image. Element accepts attribute 'href' that
0115:         * is a key to the <code>Image</code> set using 'setImage' method. Vertical
0116:         * position of image relative to surrounding text is optionally controlled by
0117:         * the attribute <b>align</b> that can have values <b>top</b>, <b>middle</b>
0118:         * and <b>bottom</b></li>
0119:         * <li><b>a </b>- to render a hyperlink. Element accepts attribute 'href' that
0120:         * will be provided to the hyperlink listeners via HyperlinkEvent object. The
0121:         * element also accepts 'nowrap' attribute (default is false). When set to
0122:         * 'true', the hyperlink will not be wrapped. Hyperlinks automatically created
0123:         * when 'http://' is encountered in text are not wrapped.</li>
0124:         * <li><b>b </b>- the enclosed text will use bold font.</li>
0125:         * <li><b>br </b>- forced line break (no attributes).</li>
0126:         * <li><b>span </b>- the enclosed text will have the color and font specified
0127:         * in the element attributes. Color is provided using 'color' attribute and is a
0128:         * key to the Color object set by 'setColor' method. Font is provided using
0129:         * 'font' attribute and is a key to the Font object set by 'setFont' method. As with
0130:         * hyperlinks, it is possible to block wrapping by setting 'nowrap' to true
0131:         * (false by default).
0132:         * </li>
0133:         * <li><b>control (new in 3.1)</b> - to place a control that is a child of the
0134:         * text control. Element accepts attribute 'href' that is a key to the Control
0135:         * object set using 'setControl' method. Optionally, attribute 'fill' can be set
0136:         * to <code>true</code> to make the control fill the entire width of the text.
0137:         * Form text is not responsible for creating or disposing controls, it only
0138:         * places them relative to the surrounding text. Similar to <b>img</b>,
0139:         * vertical position of the control can be set using the <b>align</b>
0140:         * attribute. In addition, <b>width</b> and <b>height</b> attributes can
0141:         * be used to force the dimensions of the control. If not used,
0142:         * the preferred control size will be used.
0143:         * </ul>
0144:         * <p>
0145:         * None of the elements can nest. For example, you cannot have <b>b </b> inside
0146:         * a <b>span </b>. This was done to keep everything simple and transparent.
0147:         * Since 3.1, an exception to this rule has been added to support nesting images
0148:         * and text inside the hyperlink tag (<b>a</b>). Image enclosed in the
0149:         * hyperlink tag acts as a hyperlink, can be clicked on and can accept and
0150:         * render selection focus. When both text and image is enclosed, selection and
0151:         * rendering will affect both as a single hyperlink.
0152:         * </p>
0153:         * <p>
0154:         * Since 3.1, it is possible to select text. Text selection can be
0155:         * programmatically accessed and also copied to clipboard. Non-textual objects
0156:         * (images, controls etc.) in the selection range are ignored.
0157:         * <p>
0158:         * Care should be taken when using this control. Form text is not an HTML
0159:         * browser and should not be treated as such. If you need complex formatting
0160:         * capabilities, use Browser widget. If you need editing capabilities and
0161:         * font/color styles of text segments is all you need, use StyleText widget.
0162:         * Finally, if all you need is to wrap text, use SWT Label widget and create it
0163:         * with SWT.WRAP style.
0164:         * 
0165:         * @see FormToolkit
0166:         * @see TableWrapLayout
0167:         * @since 3.0
0168:         */
0169:        public class FormText extends Canvas {
0170:            /**
0171:             * The object ID to be used when registering action to handle URL hyperlinks
0172:             * (those that should result in opening the web browser). Value is
0173:             * "urlHandler".
0174:             */
0175:            public static final String URL_HANDLER_ID = "urlHandler"; //$NON-NLS-1$
0176:
0177:            /**
0178:             * Value of the horizontal margin (default is 0).
0179:             */
0180:            public int marginWidth = 0;
0181:
0182:            /**
0183:             * Value of tue vertical margin (default is 1).
0184:             */
0185:            public int marginHeight = 1;
0186:
0187:            // private fields
0188:            //TODO We should remove the dependency on Platform
0189:            private static final boolean DEBUG_TEXT = false;//"true".equalsIgnoreCase(Platform.getDebugOption(FormUtil.DEBUG_TEXT));
0190:            private static final boolean DEBUG_TEXTSIZE = false;//"true".equalsIgnoreCase(Platform.getDebugOption(FormUtil.DEBUG_TEXTSIZE));
0191:
0192:            private static final boolean DEBUG_FOCUS = false;//"true".equalsIgnoreCase(Platform.getDebugOption(FormUtil.DEBUG_FOCUS));	
0193:
0194:            private boolean hasFocus;
0195:
0196:            private boolean paragraphsSeparated = true;
0197:
0198:            private FormTextModel model;
0199:
0200:            private ListenerList listeners;
0201:
0202:            private Hashtable resourceTable = new Hashtable();
0203:
0204:            private IHyperlinkSegment entered;
0205:
0206:            private IHyperlinkSegment armed;
0207:
0208:            private boolean mouseFocus = false;
0209:
0210:            private boolean controlFocusTransfer = false;
0211:
0212:            private boolean inSelection = false;
0213:
0214:            private SelectionData selData;
0215:
0216:            private static final String INTERNAL_MENU = "__internal_menu__"; //$NON-NLS-1$
0217:
0218:            private static final String CONTROL_KEY = "__segment__"; //$NON-NLS-1$
0219:
0220:            private class FormTextLayout extends Layout implements 
0221:                    ILayoutExtension {
0222:                public FormTextLayout() {
0223:                }
0224:
0225:                public int computeMaximumWidth(Composite parent, boolean changed) {
0226:                    return computeSize(parent, SWT.DEFAULT, SWT.DEFAULT,
0227:                            changed).x;
0228:                }
0229:
0230:                public int computeMinimumWidth(Composite parent, boolean changed) {
0231:                    return computeSize(parent, 5, SWT.DEFAULT, true).x;
0232:                }
0233:
0234:                /*
0235:                 * @see Layout#computeSize(Composite, int, int, boolean)
0236:                 */
0237:                public Point computeSize(Composite composite, int wHint,
0238:                        int hHint, boolean changed) {
0239:                    long start = 0;
0240:
0241:                    if (DEBUG_TEXT)
0242:                        start = System.currentTimeMillis();
0243:                    int innerWidth = wHint;
0244:                    if (innerWidth != SWT.DEFAULT)
0245:                        innerWidth -= marginWidth * 2;
0246:                    Point textSize = computeTextSize(innerWidth);
0247:                    int textWidth = textSize.x + 2 * marginWidth;
0248:                    int textHeight = textSize.y + 2 * marginHeight;
0249:                    Point result = new Point(textWidth, textHeight);
0250:                    if (DEBUG_TEXT) {
0251:                        long stop = System.currentTimeMillis();
0252:                        System.out
0253:                                .println("FormText computeSize: " + (stop - start) //$NON-NLS-1$
0254:                                        + "ms"); //$NON-NLS-1$
0255:                    }
0256:                    if (DEBUG_TEXTSIZE) {
0257:                        System.out
0258:                                .println("FormText (" + model.getAccessibleText() + "), computeSize: wHint=" + wHint + ", result=" + result); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0259:                    }
0260:                    return result;
0261:                }
0262:
0263:                private Point computeTextSize(int wHint) {
0264:                    Paragraph[] paragraphs = model.getParagraphs();
0265:                    GC gc = new GC(FormText.this );
0266:                    gc.setFont(getFont());
0267:                    Locator loc = new Locator();
0268:                    int width = wHint != SWT.DEFAULT ? wHint : 0;
0269:                    FontMetrics fm = gc.getFontMetrics();
0270:                    int lineHeight = fm.getHeight();
0271:                    boolean selectableInTheLastRow = false;
0272:                    for (int i = 0; i < paragraphs.length; i++) {
0273:                        Paragraph p = paragraphs[i];
0274:                        if (i > 0 && getParagraphsSeparated()
0275:                                && p.getAddVerticalSpace())
0276:                            loc.y += getParagraphSpacing(lineHeight);
0277:                        loc.rowHeight = 0;
0278:                        loc.indent = p.getIndent();
0279:                        loc.x = p.getIndent();
0280:                        ParagraphSegment[] segments = p.getSegments();
0281:                        if (segments.length > 0) {
0282:                            selectableInTheLastRow = false;
0283:                            int pwidth = 0;
0284:                            for (int j = 0; j < segments.length; j++) {
0285:                                ParagraphSegment segment = segments[j];
0286:                                segment.advanceLocator(gc, wHint, loc,
0287:                                        resourceTable, false);
0288:                                if (wHint != SWT.DEFAULT) {
0289:                                    width = Math.max(width, loc.width);
0290:                                } else {
0291:                                    pwidth += loc.width;
0292:                                }
0293:                                if (segment instanceof  IFocusSelectable)
0294:                                    selectableInTheLastRow = true;
0295:                            }
0296:                            if (wHint == SWT.DEFAULT)
0297:                                width = Math.max(width, pwidth);
0298:                            loc.y += loc.rowHeight;
0299:                        } else {
0300:                            // empty new line
0301:                            loc.y += lineHeight;
0302:                        }
0303:                    }
0304:                    gc.dispose();
0305:                    if (selectableInTheLastRow)
0306:                        loc.y += 1;
0307:                    return new Point(width, loc.y);
0308:                }
0309:
0310:                protected void layout(Composite composite, boolean flushCache) {
0311:                    long start = 0;
0312:
0313:                    if (DEBUG_TEXT) {
0314:                        start = System.currentTimeMillis();
0315:                    }
0316:                    selData = null;
0317:                    Rectangle carea = composite.getClientArea();
0318:                    if (DEBUG_TEXTSIZE) {
0319:                        System.out
0320:                                .println("FormText layout (" + model.getAccessibleText() + "), carea=" + carea); //$NON-NLS-1$ //$NON-NLS-2$
0321:                    }
0322:                    GC gc = new GC(composite);
0323:                    gc.setFont(getFont());
0324:                    ensureBoldFontPresent(getFont());
0325:                    gc.setForeground(getForeground());
0326:                    gc.setBackground(getBackground());
0327:
0328:                    Locator loc = new Locator();
0329:                    loc.marginWidth = marginWidth;
0330:                    loc.marginHeight = marginHeight;
0331:                    loc.x = marginWidth;
0332:                    loc.y = marginHeight;
0333:                    FontMetrics fm = gc.getFontMetrics();
0334:                    int lineHeight = fm.getHeight();
0335:
0336:                    Paragraph[] paragraphs = model.getParagraphs();
0337:                    IHyperlinkSegment selectedLink = getSelectedLink();
0338:                    for (int i = 0; i < paragraphs.length; i++) {
0339:                        Paragraph p = paragraphs[i];
0340:                        if (i > 0 && paragraphsSeparated
0341:                                && p.getAddVerticalSpace())
0342:                            loc.y += getParagraphSpacing(lineHeight);
0343:                        loc.indent = p.getIndent();
0344:                        loc.resetCaret();
0345:                        loc.rowHeight = 0;
0346:                        p.layout(gc, carea.width, loc, lineHeight,
0347:                                resourceTable, selectedLink);
0348:                    }
0349:                    gc.dispose();
0350:                    if (DEBUG_TEXT) {
0351:                        long stop = System.currentTimeMillis();
0352:                        System.out
0353:                                .println("FormText.layout: " + (stop - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
0354:                    }
0355:                }
0356:            }
0357:
0358:            /**
0359:             * Contructs a new form text widget in the provided parent and using the
0360:             * styles.
0361:             * 
0362:             * @param parent
0363:             *            form text parent control
0364:             * @param style
0365:             *            the widget style
0366:             */
0367:            public FormText(Composite parent, int style) {
0368:                super (parent, SWT.NO_BACKGROUND | SWT.WRAP | style);
0369:                setLayout(new FormTextLayout());
0370:                model = new FormTextModel();
0371:                addDisposeListener(new DisposeListener() {
0372:                    public void widgetDisposed(DisposeEvent e) {
0373:                        model.dispose();
0374:                        disposeResourceTable(true);
0375:                    }
0376:                });
0377:                addPaintListener(new PaintListener() {
0378:                    public void paintControl(PaintEvent e) {
0379:                        paint(e);
0380:                    }
0381:                });
0382:                addListener(SWT.KeyDown, new Listener() {
0383:                    public void handleEvent(Event e) {
0384:                        if (e.character == '\r') {
0385:                            activateSelectedLink();
0386:                            return;
0387:                        }
0388:                    }
0389:                });
0390:                addListener(SWT.Traverse, new Listener() {
0391:                    public void handleEvent(Event e) {
0392:                        if (DEBUG_FOCUS)
0393:                            System.out.println("Traversal: " + e); //$NON-NLS-1$
0394:                        switch (e.detail) {
0395:                        case SWT.TRAVERSE_PAGE_NEXT:
0396:                        case SWT.TRAVERSE_PAGE_PREVIOUS:
0397:                        case SWT.TRAVERSE_ARROW_NEXT:
0398:                        case SWT.TRAVERSE_ARROW_PREVIOUS:
0399:                            e.doit = false;
0400:                            return;
0401:                        }
0402:                        if (!model.hasFocusSegments()) {
0403:                            e.doit = true;
0404:                            return;
0405:                        }
0406:                        if (e.detail == SWT.TRAVERSE_TAB_NEXT)
0407:                            e.doit = advance(true);
0408:                        else if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)
0409:                            e.doit = advance(false);
0410:                        else if (e.detail != SWT.TRAVERSE_RETURN)
0411:                            e.doit = true;
0412:                    }
0413:                });
0414:                addFocusListener(new FocusListener() {
0415:                    public void focusGained(FocusEvent e) {
0416:                        if (!hasFocus) {
0417:                            hasFocus = true;
0418:                            if (DEBUG_FOCUS) {
0419:                                System.out.println("FormText: focus gained"); //$NON-NLS-1$
0420:                            }
0421:                            if (!mouseFocus && !controlFocusTransfer) {
0422:                                handleFocusChange();
0423:                            }
0424:                        }
0425:                    }
0426:
0427:                    public void focusLost(FocusEvent e) {
0428:                        if (DEBUG_FOCUS) {
0429:                            System.out.println("FormText: focus lost"); //$NON-NLS-1$
0430:                        }
0431:                        if (hasFocus) {
0432:                            hasFocus = false;
0433:                            if (!controlFocusTransfer)
0434:                                handleFocusChange();
0435:                        }
0436:                    }
0437:                });
0438:                addMouseListener(new MouseListener() {
0439:                    public void mouseDoubleClick(MouseEvent e) {
0440:                    }
0441:
0442:                    public void mouseDown(MouseEvent e) {
0443:                        // select a link
0444:                        handleMouseClick(e, true);
0445:                    }
0446:
0447:                    public void mouseUp(MouseEvent e) {
0448:                        // activate a link
0449:                        handleMouseClick(e, false);
0450:                    }
0451:                });
0452:                addMouseTrackListener(new MouseTrackListener() {
0453:                    public void mouseEnter(MouseEvent e) {
0454:                        handleMouseMove(e);
0455:                    }
0456:
0457:                    public void mouseExit(MouseEvent e) {
0458:                        if (entered != null) {
0459:                            exitLink(entered, e.stateMask);
0460:                            paintLinkHover(entered, false);
0461:                            entered = null;
0462:                            setCursor(null);
0463:                        }
0464:                    }
0465:
0466:                    public void mouseHover(MouseEvent e) {
0467:                        handleMouseHover(e);
0468:                    }
0469:                });
0470:                addMouseMoveListener(new MouseMoveListener() {
0471:                    public void mouseMove(MouseEvent e) {
0472:                        handleMouseMove(e);
0473:                    }
0474:                });
0475:                initAccessible();
0476:                ensureBoldFontPresent(getFont());
0477:                createMenu();
0478:                // we will handle traversal of controls, if any
0479:                setTabList(new Control[] {});
0480:            }
0481:
0482:            /**
0483:             * Test for focus.
0484:             * 
0485:             * @return <samp>true </samp> if the widget has focus.
0486:             */
0487:            public boolean getFocus() {
0488:                return hasFocus;
0489:            }
0490:
0491:            /**
0492:             * Test if the widget is currently processing the text it is about to
0493:             * render.
0494:             * 
0495:             * @return <samp>true </samp> if the widget is still loading the text,
0496:             *         <samp>false </samp> otherwise.
0497:             * @deprecated not used any more - returns <code>false</code>
0498:             */
0499:            public boolean isLoading() {
0500:                return false;
0501:            }
0502:
0503:            /**
0504:             * Returns the text that will be shown in the control while the real content
0505:             * is loading.
0506:             * 
0507:             * @return loading text message
0508:             * @deprecated loading text is not used since 3.1
0509:             */
0510:            public String getLoadingText() {
0511:                return null;
0512:            }
0513:
0514:            /**
0515:             * Sets the text that will be shown in the control while the real content is
0516:             * loading. This is significant when content to render is loaded from the
0517:             * input stream that was created from a remote URL, and the time to load the
0518:             * entire content is nontrivial.
0519:             * 
0520:             * @param loadingText
0521:             *            loading text message
0522:             * @deprecated use setText(loadingText, false, false);
0523:             */
0524:            public void setLoadingText(String loadingText) {
0525:                setText(loadingText, false, false);
0526:            }
0527:
0528:            /**
0529:             * If paragraphs are separated, spacing will be added between them.
0530:             * Otherwise, new paragraphs will simply start on a new line with no
0531:             * spacing.
0532:             * 
0533:             * @param value
0534:             *            <samp>true </samp> if paragraphs are separated, </samp> false
0535:             *            </samp> otherwise.
0536:             */
0537:            public void setParagraphsSeparated(boolean value) {
0538:                paragraphsSeparated = value;
0539:            }
0540:
0541:            /**
0542:             * Tests if there is some inter-paragraph spacing.
0543:             * 
0544:             * @return <samp>true </samp> if paragraphs are separated, <samp>false
0545:             *         </samp> otherwise.
0546:             */
0547:            public boolean getParagraphsSeparated() {
0548:                return paragraphsSeparated;
0549:            }
0550:
0551:            /**
0552:             * Registers the image referenced by the provided key.
0553:             * <p>
0554:             * For <samp>img </samp> tags, an object of a type <samp>Image </samp> must
0555:             * be registered using the key equivalent to the value of the <samp>href
0556:             * </samp> attribute used in the tag.
0557:             * 
0558:             * @param key
0559:             *            unique key that matches the value of the <samp>href </samp>
0560:             *            attribute.
0561:             * @param image
0562:             *            an object of a type <samp>Image </samp>.
0563:             */
0564:            public void setImage(String key, Image image) {
0565:                resourceTable.put("i." + key, image); //$NON-NLS-1$
0566:            }
0567:
0568:            /**
0569:             * Registers the color referenced by the provided key.
0570:             * <p>
0571:             * For <samp>span </samp> tags, an object of a type <samp>Color </samp> must
0572:             * be registered using the key equivalent to the value of the <samp>color
0573:             * </samp> attribute.
0574:             * 
0575:             * @param key
0576:             *            unique key that matches the value of the <samp>color </samp>
0577:             *            attribute.
0578:             * @param color
0579:             *            an object of the type <samp>Color </samp> or <samp>null</samp>
0580:             *            if the key needs to be cleared.
0581:             */
0582:            public void setColor(String key, Color color) {
0583:                String fullKey = "c." + key; //$NON-NLS-1$
0584:                if (color == null)
0585:                    resourceTable.remove(fullKey);
0586:                else
0587:                    resourceTable.put(fullKey, color);
0588:            }
0589:
0590:            /**
0591:             * Registers the font referenced by the provided key.
0592:             * <p>
0593:             * For <samp>span </samp> tags, an object of a type <samp>Font </samp> must
0594:             * be registered using the key equivalent to the value of the <samp>font
0595:             * </samp> attribute.
0596:             * 
0597:             * @param key
0598:             *            unique key that matches the value of the <samp>font </samp>
0599:             *            attribute.
0600:             * @param font
0601:             *            an object of the type <samp>Font </samp> or <samp>null</samp>
0602:             *            if the key needs to be cleared.
0603:             */
0604:            public void setFont(String key, Font font) {
0605:                String fullKey = "f." + key; //$NON-NLS-1$
0606:                if (font == null)
0607:                    resourceTable.remove(fullKey);
0608:                else
0609:                    resourceTable.put(fullKey, font);
0610:                model.clearCache(fullKey);
0611:            }
0612:
0613:            /**
0614:             * Registers the control referenced by the provided key.
0615:             * <p>
0616:             * For <samp>control</samp> tags, an object of a type <samp>Control</samp>
0617:             * must be registered using the key equivalent to the value of the
0618:             * <samp>control</samp> attribute.
0619:             * 
0620:             * @param key
0621:             *            unique key that matches the value of the <samp>control</samp>
0622:             *            attribute.
0623:             * @param control
0624:             *            an object of the type <samp>Control</samp> or <samp>null</samp>
0625:             *            if the existing control at the specified key needs to be
0626:             *            removed.
0627:             * @since 3.1
0628:             */
0629:            public void setControl(String key, Control control) {
0630:                String fullKey = "o." + key; //$NON-NLS-1$
0631:                if (control == null)
0632:                    resourceTable.remove(fullKey);
0633:                else
0634:                    resourceTable.put(fullKey, control);
0635:            }
0636:
0637:            /**
0638:             * Sets the font to use to render the default text (text that does not have
0639:             * special font property assigned). Bold font will be constructed from this
0640:             * font.
0641:             * 
0642:             * @param font
0643:             *            the default font to use
0644:             */
0645:            public void setFont(Font font) {
0646:                super .setFont(font);
0647:                model.clearCache(null);
0648:                Font boldFont = (Font) resourceTable
0649:                        .get(FormTextModel.BOLD_FONT_ID);
0650:                if (boldFont != null) {
0651:                    boldFont.dispose();
0652:                    resourceTable.remove(FormTextModel.BOLD_FONT_ID);
0653:                }
0654:                ensureBoldFontPresent(getFont());
0655:            }
0656:
0657:            /**
0658:             * Sets the provided text. Text can be rendered as-is, or by parsing the
0659:             * formatting tags. Optionally, sections of text starting with http:// will
0660:             * be converted to hyperlinks.
0661:             * 
0662:             * @param text
0663:             *            the text to render
0664:             * @param parseTags
0665:             *            if <samp>true </samp>, formatting tags will be parsed.
0666:             *            Otherwise, text will be rendered as-is.
0667:             * @param expandURLs
0668:             *            if <samp>true </samp>, URLs found in the untagged text will be
0669:             *            converted into hyperlinks.
0670:             */
0671:            public void setText(String text, boolean parseTags,
0672:                    boolean expandURLs) {
0673:                disposeResourceTable(false);
0674:                entered = null;
0675:                if (parseTags)
0676:                    model.parseTaggedText(text, expandURLs);
0677:                else
0678:                    model.parseRegularText(text, expandURLs);
0679:                hookControlSegmentFocus();
0680:                layout();
0681:                redraw();
0682:            }
0683:
0684:            /**
0685:             * Sets the contents of the stream. Optionally, URLs in untagged text can be
0686:             * converted into hyperlinks. The caller is responsible for closing the
0687:             * stream.
0688:             * 
0689:             * @param is
0690:             *            stream to render
0691:             * @param expandURLs
0692:             *            if <samp>true </samp>, URLs found in untagged text will be
0693:             *            converted into hyperlinks.
0694:             */
0695:            public void setContents(InputStream is, boolean expandURLs) {
0696:                entered = null;
0697:                disposeResourceTable(false);
0698:                model.parseInputStream(is, expandURLs);
0699:                hookControlSegmentFocus();
0700:                layout();
0701:                redraw();
0702:            }
0703:
0704:            private void hookControlSegmentFocus() {
0705:                Paragraph[] paragraphs = model.getParagraphs();
0706:                if (paragraphs == null)
0707:                    return;
0708:                Listener listener = new Listener() {
0709:                    public void handleEvent(Event e) {
0710:                        switch (e.type) {
0711:                        case SWT.FocusIn:
0712:                            if (!controlFocusTransfer)
0713:                                syncControlSegmentFocus((Control) e.widget);
0714:                            break;
0715:                        case SWT.Traverse:
0716:                            if (DEBUG_FOCUS)
0717:                                System.out.println("Control traversal: " + e); //$NON-NLS-1$
0718:                            switch (e.detail) {
0719:                            case SWT.TRAVERSE_PAGE_NEXT:
0720:                            case SWT.TRAVERSE_PAGE_PREVIOUS:
0721:                            case SWT.TRAVERSE_ARROW_NEXT:
0722:                            case SWT.TRAVERSE_ARROW_PREVIOUS:
0723:                                e.doit = false;
0724:                                return;
0725:                            }
0726:                            Control c = (Control) e.widget;
0727:                            ControlSegment segment = (ControlSegment) c
0728:                                    .getData(CONTROL_KEY);
0729:                            if (e.detail == SWT.TRAVERSE_TAB_NEXT)
0730:                                e.doit = advanceControl(c, segment, true);
0731:                            else if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)
0732:                                e.doit = advanceControl(c, segment, false);
0733:                            if (!e.doit)
0734:                                e.detail = SWT.TRAVERSE_NONE;
0735:                            break;
0736:                        }
0737:                    }
0738:                };
0739:                for (int i = 0; i < paragraphs.length; i++) {
0740:                    Paragraph p = paragraphs[i];
0741:                    ParagraphSegment[] segments = p.getSegments();
0742:                    for (int j = 0; j < segments.length; j++) {
0743:                        if (segments[j] instanceof  ControlSegment) {
0744:                            ControlSegment cs = (ControlSegment) segments[j];
0745:                            Control c = cs.getControl(resourceTable);
0746:                            if (c != null) {
0747:                                if (c.getData(CONTROL_KEY) == null) {
0748:                                    // first time - hook
0749:                                    c.setData(CONTROL_KEY, cs);
0750:                                    attachTraverseListener(c, listener);
0751:                                }
0752:                            }
0753:                        }
0754:                    }
0755:                }
0756:            }
0757:
0758:            private void attachTraverseListener(Control c, Listener listener) {
0759:                if (c instanceof  Composite) {
0760:                    Composite parent = (Composite) c;
0761:                    Control[] children = parent.getChildren();
0762:                    for (int i = 0; i < children.length; i++) {
0763:                        attachTraverseListener(children[i], listener);
0764:                    }
0765:                    if (c instanceof  Canvas) {
0766:                        // If Canvas, the control iteself can accept
0767:                        // traverse events and should be monitored
0768:                        c.addListener(SWT.Traverse, listener);
0769:                        c.addListener(SWT.FocusIn, listener);
0770:                    }
0771:                } else {
0772:                    c.addListener(SWT.Traverse, listener);
0773:                    c.addListener(SWT.FocusIn, listener);
0774:                }
0775:            }
0776:
0777:            /**
0778:             * If we click on the control randomly, our internal book-keeping will be
0779:             * off. We need to update the model and mark the control segment and
0780:             * currently selected. Hyperlink that may have had focus must also be
0781:             * exited.
0782:             * 
0783:             * @param control
0784:             *            the control that got focus
0785:             */
0786:            private void syncControlSegmentFocus(Control control) {
0787:                ControlSegment cs = null;
0788:
0789:                while (control != null) {
0790:                    cs = (ControlSegment) control.getData(CONTROL_KEY);
0791:                    if (cs != null)
0792:                        break;
0793:                    control = control.getParent();
0794:                }
0795:                if (cs == null)
0796:                    return;
0797:                IFocusSelectable current = model.getSelectedSegment();
0798:                // If the model and the control match, all is well
0799:                if (current == cs)
0800:                    return;
0801:                IHyperlinkSegment oldLink = null;
0802:                if (current != null && current instanceof  IHyperlinkSegment) {
0803:                    oldLink = (IHyperlinkSegment) current;
0804:                    exitLink(oldLink, SWT.NULL);
0805:                }
0806:                if (DEBUG_FOCUS)
0807:                    System.out
0808:                            .println("Sync control: " + cs + ", oldLink=" + oldLink); //$NON-NLS-1$ //$NON-NLS-2$
0809:                model.select(cs);
0810:                if (oldLink != null)
0811:                    paintFocusTransfer(oldLink, null);
0812:                // getAccessible().setFocus(model.getSelectedSegmentIndex());
0813:            }
0814:
0815:            private boolean advanceControl(Control c, ControlSegment segment,
0816:                    boolean next) {
0817:                Composite parent = c.getParent();
0818:                if (parent == this ) {
0819:                    // segment-level control
0820:                    IFocusSelectable nextSegment = model
0821:                            .getNextFocusSegment(next);
0822:                    if (nextSegment != null) {
0823:                        controlFocusTransfer = true;
0824:                        super .forceFocus();
0825:                        controlFocusTransfer = false;
0826:                        model.select(segment);
0827:                        return advance(next);
0828:                    }
0829:                    // nowhere to go
0830:                    return setFocusToNextSibling(this , next);
0831:                }
0832:                if (setFocusToNextSibling(c, next))
0833:                    return true;
0834:                // still here - must go one level up
0835:                segment = (ControlSegment) parent.getData(CONTROL_KEY);
0836:                return advanceControl(parent, segment, next);
0837:            }
0838:
0839:            private boolean setFocusToNextSibling(Control c, boolean next) {
0840:                Composite parent = c.getParent();
0841:                Control[] children = parent.getTabList();
0842:                for (int i = 0; i < children.length; i++) {
0843:                    Control child = children[i];
0844:                    if (child == c) {
0845:                        // here
0846:                        if (next) {
0847:                            for (int j = i + 1; j < children.length; j++) {
0848:                                Control nc = children[j];
0849:                                if (nc.setFocus())
0850:                                    return false;
0851:                            }
0852:                        } else {
0853:                            for (int j = i - 1; j >= 0; j--) {
0854:                                Control pc = children[j];
0855:                                if (pc.setFocus())
0856:                                    return false;
0857:                            }
0858:                        }
0859:                    }
0860:                }
0861:                return false;
0862:            }
0863:
0864:            /**
0865:             * Controls whether whitespace inside paragraph and list items is
0866:             * normalized. Note that the new value will not affect the current text in
0867:             * the control, only subsequent calls to <code>setText</code> or
0868:             * <code>setContents</code>.
0869:             * <p>
0870:             * If normalized:
0871:             * <ul>
0872:             * <li>all white space characters will be condensed into at most one when
0873:             * between words.</li>
0874:             * <li>new line characters will be ignored and replaced with one white
0875:             * space character</li>
0876:             * <li>white space characters after the opening tags and before the closing
0877:             * tags will be trimmed</li>
0878:             * 
0879:             * @param value
0880:             *            <code>true</code> if whitespace is normalized,
0881:             *            <code>false</code> otherwise.
0882:             */
0883:            public void setWhitespaceNormalized(boolean value) {
0884:                model.setWhitespaceNormalized(value);
0885:            }
0886:
0887:            /**
0888:             * Tests whether whitespace inside paragraph and list item is normalized.
0889:             * 
0890:             * @see #setWhitespaceNormalized(boolean)
0891:             * @return <code>true</code> if whitespace is normalized,
0892:             *         <code>false</code> otherwise.
0893:             */
0894:            public boolean isWhitespaceNormalized() {
0895:                return model.isWhitespaceNormalized();
0896:            }
0897:
0898:            /**
0899:             * Disposes the internal menu if created and sets the menu provided as a
0900:             * parameter.
0901:             * 
0902:             * @param menu
0903:             *            the menu to associate with this text control
0904:             */
0905:            public void setMenu(Menu menu) {
0906:                Menu currentMenu = super .getMenu();
0907:                if (currentMenu != null
0908:                        && INTERNAL_MENU.equals(currentMenu.getData())) {
0909:                    // internal menu set
0910:                    if (menu != null) {
0911:                        currentMenu.dispose();
0912:                        super .setMenu(menu);
0913:                    }
0914:                } else
0915:                    super .setMenu(menu);
0916:            }
0917:
0918:            private void createMenu() {
0919:                Menu menu = new Menu(this );
0920:                final MenuItem copyItem = new MenuItem(menu, SWT.PUSH);
0921:                copyItem.setText(Messages.FormText_copy);
0922:
0923:                SelectionListener listener = new SelectionAdapter() {
0924:                    public void widgetSelected(SelectionEvent e) {
0925:                        if (e.widget == copyItem) {
0926:                            copy();
0927:                        }
0928:                    }
0929:                };
0930:                copyItem.addSelectionListener(listener);
0931:                menu.addMenuListener(new MenuListener() {
0932:                    public void menuShown(MenuEvent e) {
0933:                        copyItem.setEnabled(canCopy());
0934:                    }
0935:
0936:                    public void menuHidden(MenuEvent e) {
0937:                    }
0938:                });
0939:                menu.setData(INTERNAL_MENU);
0940:                super .setMenu(menu);
0941:            }
0942:
0943:            /**
0944:             * Returns the hyperlink settings that are in effect for this control.
0945:             * 
0946:             * @return current hyperlinks settings
0947:             */
0948:            public HyperlinkSettings getHyperlinkSettings() {
0949:                return model.getHyperlinkSettings();
0950:            }
0951:
0952:            /**
0953:             * Sets the hyperlink settings to be used for this control. Settings will
0954:             * affect things like hyperlink color, rendering style, cursor etc.
0955:             * 
0956:             * @param settings
0957:             *            hyperlink settings for this control
0958:             */
0959:            public void setHyperlinkSettings(HyperlinkSettings settings) {
0960:                model.setHyperlinkSettings(settings);
0961:            }
0962:
0963:            /**
0964:             * Adds a listener that will handle hyperlink events.
0965:             * 
0966:             * @param listener
0967:             *            the listener to add
0968:             */
0969:            public void addHyperlinkListener(IHyperlinkListener listener) {
0970:                if (listeners == null)
0971:                    listeners = new ListenerList();
0972:                listeners.add(listener);
0973:            }
0974:
0975:            /**
0976:             * Removes the hyperlink listener.
0977:             * 
0978:             * @param listener
0979:             *            the listener to remove
0980:             */
0981:            public void removeHyperlinkListener(IHyperlinkListener listener) {
0982:                if (listeners == null)
0983:                    return;
0984:                listeners.remove(listener);
0985:            }
0986:
0987:            /**
0988:             * Adds a selection listener. A Selection event is sent by the widget when
0989:             * the selection has changed.
0990:             * <p>
0991:             * <code>widgetDefaultSelected</code> is not called for FormText.
0992:             * </p>
0993:             * 
0994:             * @param listener
0995:             *            the listener
0996:             * @exception SWTException
0997:             *                <ul>
0998:             *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
0999:             *                disposed</li>
1000:             *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1001:             *                thread that created the receiver</li>
1002:             *                </ul>
1003:             * @exception IllegalArgumentException
1004:             *                <ul>
1005:             *                <li>ERROR_NULL_ARGUMENT when listener is null</li>
1006:             *                </ul>
1007:             * @since 3.1
1008:             */
1009:            public void addSelectionListener(SelectionListener listener) {
1010:                checkWidget();
1011:                if (listener == null) {
1012:                    SWT.error(SWT.ERROR_NULL_ARGUMENT);
1013:                }
1014:                TypedListener typedListener = new TypedListener(listener);
1015:                addListener(SWT.Selection, typedListener);
1016:            }
1017:
1018:            /**
1019:             * Removes the specified selection listener.
1020:             * <p>
1021:             * 
1022:             * @param listener
1023:             *            the listener
1024:             * @exception SWTException
1025:             *                <ul>
1026:             *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1027:             *                disposed</li>
1028:             *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1029:             *                thread that created the receiver</li>
1030:             *                </ul>
1031:             * @exception IllegalArgumentException
1032:             *                <ul>
1033:             *                <li>ERROR_NULL_ARGUMENT when listener is null</li>
1034:             *                </ul>
1035:             * @since 3.1
1036:             */
1037:            public void removeSelectionListener(SelectionListener listener) {
1038:                checkWidget();
1039:                if (listener == null) {
1040:                    SWT.error(SWT.ERROR_NULL_ARGUMENT);
1041:                }
1042:                removeListener(SWT.Selection, listener);
1043:            }
1044:
1045:            /**
1046:             * Returns the selected text.
1047:             * <p>
1048:             * 
1049:             * @return selected text, or an empty String if there is no selection.
1050:             * @exception SWTException
1051:             *                <ul>
1052:             *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1053:             *                disposed</li>
1054:             *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1055:             *                thread that created the receiver</li>
1056:             *                </ul>
1057:             * @since 3.1
1058:             */
1059:
1060:            public String getSelectionText() {
1061:                checkWidget();
1062:                if (selData != null)
1063:                    return selData.getSelectionText();
1064:                return ""; //$NON-NLS-1$
1065:            }
1066:
1067:            /**
1068:             * Tests if the text is selected and can be copied into the clipboard.
1069:             * 
1070:             * @return <code>true</code> if the selected text can be copied into the
1071:             *         clipboard, <code>false</code> otherwise.
1072:             * @since 3.1
1073:             */
1074:            public boolean canCopy() {
1075:                return selData != null && selData.canCopy();
1076:            }
1077:
1078:            /**
1079:             * Copies the selected text into the clipboard. Does nothing if no text is
1080:             * selected or the text cannot be copied for any other reason.
1081:             * 
1082:             * @since 3.1
1083:             */
1084:
1085:            public void copy() {
1086:                if (!canCopy())
1087:                    return;
1088:                Clipboard clipboard = new Clipboard(getDisplay());
1089:                Object[] o = new Object[] { getSelectionText() };
1090:                Transfer[] t = new Transfer[] { TextTransfer.getInstance() };
1091:                clipboard.setContents(o, t);
1092:                clipboard.dispose();
1093:            }
1094:
1095:            /**
1096:             * Returns the reference of the hyperlink that currently has keyboard focus,
1097:             * or <code>null</code> if there are no hyperlinks in the receiver or no
1098:             * hyperlink has focus at the moment.
1099:             * 
1100:             * @return href of the selected hyperlink or <code>null</code> if none
1101:             *         selected.
1102:             * @since 3.1
1103:             */
1104:            public Object getSelectedLinkHref() {
1105:                IHyperlinkSegment link = getSelectedLink();
1106:                return link != null ? link.getHref() : null;
1107:            }
1108:
1109:            /**
1110:             * Returns the text of the hyperlink that currently has keyboard focus, or
1111:             * <code>null</code> if there are no hyperlinks in the receiver or no
1112:             * hyperlink has focus at the moment.
1113:             * 
1114:             * @return text of the selected hyperlink or <code>null</code> if none
1115:             *         selected.
1116:             * @since 3.1
1117:             */
1118:            public String getSelectedLinkText() {
1119:                IHyperlinkSegment link = getSelectedLink();
1120:                return link != null ? link.getText() : null;
1121:            }
1122:
1123:            private IHyperlinkSegment getSelectedLink() {
1124:                IFocusSelectable segment = model.getSelectedSegment();
1125:                if (segment != null && segment instanceof  IHyperlinkSegment)
1126:                    return (IHyperlinkSegment) segment;
1127:                return null;
1128:            }
1129:
1130:            private void initAccessible() {
1131:                Accessible accessible = getAccessible();
1132:                accessible.addAccessibleListener(new AccessibleAdapter() {
1133:                    public void getName(AccessibleEvent e) {
1134:                        if (e.childID == ACC.CHILDID_SELF)
1135:                            e.result = model.getAccessibleText();
1136:                        else {
1137:                            int linkCount = model.getHyperlinkCount();
1138:                            if (e.childID >= 0 && e.childID < linkCount) {
1139:                                IHyperlinkSegment link = model
1140:                                        .getHyperlink(e.childID);
1141:                                e.result = link.getText();
1142:                            }
1143:                        }
1144:                    }
1145:
1146:                    public void getHelp(AccessibleEvent e) {
1147:                        e.result = getToolTipText();
1148:                        int linkCount = model.getHyperlinkCount();
1149:                        if (e.result == null && e.childID >= 0
1150:                                && e.childID < linkCount) {
1151:                            IHyperlinkSegment link = model
1152:                                    .getHyperlink(e.childID);
1153:                            e.result = link.getText();
1154:                        }
1155:                    }
1156:                });
1157:                accessible
1158:                        .addAccessibleControlListener(new AccessibleControlAdapter() {
1159:                            public void getChildAtPoint(AccessibleControlEvent e) {
1160:                                Point pt = toControl(new Point(e.x, e.y));
1161:                                IHyperlinkSegment link = model.findHyperlinkAt(
1162:                                        pt.x, pt.y);
1163:                                if (link != null)
1164:                                    e.childID = model.indexOf(link);
1165:                                else
1166:                                    e.childID = ACC.CHILDID_SELF;
1167:                            }
1168:
1169:                            public void getLocation(AccessibleControlEvent e) {
1170:                                Rectangle location = null;
1171:                                if (e.childID != ACC.CHILDID_SELF
1172:                                        && e.childID != ACC.CHILDID_NONE) {
1173:                                    int index = e.childID;
1174:                                    IHyperlinkSegment link = model
1175:                                            .getHyperlink(index);
1176:                                    if (link != null) {
1177:                                        location = link.getBounds();
1178:                                    }
1179:                                }
1180:                                if (location == null) {
1181:                                    location = getBounds();
1182:                                }
1183:                                Point pt = toDisplay(new Point(location.x,
1184:                                        location.y));
1185:                                e.x = pt.x;
1186:                                e.y = pt.y;
1187:                                e.width = location.width;
1188:                                e.height = location.height;
1189:                            }
1190:
1191:                            public void getFocus(AccessibleControlEvent e) {
1192:                                int childID = ACC.CHILDID_NONE;
1193:
1194:                                if (isFocusControl()) {
1195:                                    int selectedIndex = model
1196:                                            .getSelectedSegmentIndex();
1197:                                    if (selectedIndex == -1) {
1198:                                        childID = ACC.CHILDID_SELF;
1199:                                    } else {
1200:                                        childID = selectedIndex;
1201:                                    }
1202:                                }
1203:                                e.childID = childID;
1204:                            }
1205:
1206:                            public void getDefaultAction(
1207:                                    AccessibleControlEvent e) {
1208:                                if (model.getHyperlinkCount() > 0) {
1209:                                    e.result = SWT.getMessage("SWT_Press"); //$NON-NLS-1$
1210:                                }
1211:                            }
1212:
1213:                            public void getChildCount(AccessibleControlEvent e) {
1214:                                e.detail = model.getHyperlinkCount();
1215:                            }
1216:
1217:                            public void getRole(AccessibleControlEvent e) {
1218:                                int role = 0;
1219:                                int childID = e.childID;
1220:                                int linkCount = model.getHyperlinkCount();
1221:                                if (childID == ACC.CHILDID_SELF) {
1222:                                    if (linkCount > 0) {
1223:                                        role = ACC.ROLE_LINK;
1224:                                    } else {
1225:                                        role = ACC.ROLE_TEXT;
1226:                                    }
1227:                                } else if (childID >= 0 && childID < linkCount) {
1228:                                    role = ACC.ROLE_LINK;
1229:                                }
1230:                                e.detail = role;
1231:                            }
1232:
1233:                            public void getSelection(AccessibleControlEvent e) {
1234:                                int selectedIndex = model
1235:                                        .getSelectedSegmentIndex();
1236:                                e.childID = (selectedIndex == -1) ? ACC.CHILDID_NONE
1237:                                        : selectedIndex;
1238:                            }
1239:
1240:                            public void getState(AccessibleControlEvent e) {
1241:                                int linkCount = model.getHyperlinkCount();
1242:                                int selectedIndex = model
1243:                                        .getSelectedSegmentIndex();
1244:                                int state = 0;
1245:                                int childID = e.childID;
1246:                                if (childID == ACC.CHILDID_SELF) {
1247:                                    state = ACC.STATE_NORMAL;
1248:                                } else if (childID >= 0 && childID < linkCount) {
1249:                                    state = ACC.STATE_SELECTABLE;
1250:                                    if (isFocusControl()) {
1251:                                        state |= ACC.STATE_FOCUSABLE;
1252:                                    }
1253:                                    if (selectedIndex == childID) {
1254:                                        state |= ACC.STATE_SELECTED;
1255:                                        if (isFocusControl()) {
1256:                                            state |= ACC.STATE_FOCUSED;
1257:                                        }
1258:                                    }
1259:                                }
1260:                                state |= ACC.STATE_READONLY;
1261:                                e.detail = state;
1262:                            }
1263:
1264:                            public void getChildren(AccessibleControlEvent e) {
1265:                                int linkCount = model.getHyperlinkCount();
1266:                                Object[] children = new Object[linkCount];
1267:                                for (int i = 0; i < linkCount; i++) {
1268:                                    children[i] = new Integer(i);
1269:                                }
1270:                                e.children = children;
1271:                            }
1272:
1273:                            public void getValue(AccessibleControlEvent e) {
1274:                                // e.result = model.getAccessibleText();
1275:                            }
1276:                        });
1277:            }
1278:
1279:            private void startSelection(MouseEvent e) {
1280:                inSelection = true;
1281:                selData = new SelectionData(e);
1282:                redraw();
1283:                Form form = FormUtil.getForm(this );
1284:                if (form != null)
1285:                    form.setSelectionText(this );
1286:            }
1287:
1288:            private void endSelection(MouseEvent e) {
1289:                inSelection = false;
1290:                if (selData != null) {
1291:                    if (!selData.isEnclosed())
1292:                        selData = null;
1293:                    else
1294:                        computeSelection();
1295:                }
1296:                notifySelectionChanged();
1297:            }
1298:
1299:            private void computeSelection() {
1300:                GC gc = new GC(this );
1301:                Paragraph[] paragraphs = model.getParagraphs();
1302:                IHyperlinkSegment selectedLink = getSelectedLink();
1303:                if (getDisplay().getFocusControl() != this )
1304:                    selectedLink = null;
1305:                for (int i = 0; i < paragraphs.length; i++) {
1306:                    Paragraph p = paragraphs[i];
1307:                    if (i > 0)
1308:                        selData.markNewLine();
1309:                    p
1310:                            .computeSelection(gc, resourceTable, selectedLink,
1311:                                    selData);
1312:                }
1313:                gc.dispose();
1314:            }
1315:
1316:            void clearSelection() {
1317:                selData = null;
1318:                if (!isDisposed()) {
1319:                    redraw();
1320:                    notifySelectionChanged();
1321:                }
1322:            }
1323:
1324:            private void notifySelectionChanged() {
1325:                Event event = new Event();
1326:                event.widget = this ;
1327:                event.display = this .getDisplay();
1328:                event.type = SWT.Selection;
1329:                notifyListeners(SWT.Selection, event);
1330:                getAccessible().selectionChanged();
1331:            }
1332:
1333:            private void handleDrag(MouseEvent e) {
1334:                if (selData != null) {
1335:                    ScrolledComposite scomp = FormUtil
1336:                            .getScrolledComposite(this );
1337:                    if (scomp != null) {
1338:                        FormUtil.ensureVisible(scomp, this , e);
1339:                    }
1340:                    selData.update(e);
1341:                    redraw();
1342:                }
1343:            }
1344:
1345:            private void handleMouseClick(MouseEvent e, boolean down) {
1346:                if (DEBUG_FOCUS)
1347:                    System.out.println("FormText: mouse click(" + down + ")"); //$NON-NLS-1$ //$NON-NLS-2$
1348:                if (down) {
1349:                    // select a hyperlink
1350:                    mouseFocus = true;
1351:                    IHyperlinkSegment segmentUnder = model.findHyperlinkAt(e.x,
1352:                            e.y);
1353:                    if (segmentUnder != null) {
1354:                        IHyperlinkSegment oldLink = getSelectedLink();
1355:                        if (getDisplay().getFocusControl() != this ) {
1356:                            setFocus();
1357:                        }
1358:                        model.selectLink(segmentUnder);
1359:                        enterLink(segmentUnder, e.stateMask);
1360:                        paintFocusTransfer(oldLink, segmentUnder);
1361:                    }
1362:                    if (e.button == 1) {
1363:                        startSelection(e);
1364:                        armed = segmentUnder;
1365:                    } else {
1366:                    }
1367:                } else {
1368:                    if (e.button == 1) {
1369:                        endSelection(e);
1370:                        IHyperlinkSegment segmentUnder = model.findHyperlinkAt(
1371:                                e.x, e.y);
1372:                        if (segmentUnder != null && armed == segmentUnder
1373:                                && selData == null) {
1374:                            activateLink(segmentUnder, e.stateMask);
1375:                            armed = null;
1376:                        }
1377:                    }
1378:                    mouseFocus = false;
1379:                }
1380:            }
1381:
1382:            private void handleMouseHover(MouseEvent e) {
1383:            }
1384:
1385:            private void updateTooltipText(ParagraphSegment segment) {
1386:                String tooltipText = null;
1387:                if (segment != null) {
1388:                    tooltipText = segment.getTooltipText();
1389:                }
1390:                String currentTooltipText = getToolTipText();
1391:
1392:                if ((currentTooltipText != null && tooltipText == null)
1393:                        || (currentTooltipText == null && tooltipText != null))
1394:                    setToolTipText(tooltipText);
1395:            }
1396:
1397:            private void handleMouseMove(MouseEvent e) {
1398:                if (inSelection) {
1399:                    handleDrag(e);
1400:                    return;
1401:                }
1402:                ParagraphSegment segmentUnder = model.findSegmentAt(e.x, e.y);
1403:                updateTooltipText(segmentUnder);
1404:                if (segmentUnder == null) {
1405:                    if (entered != null) {
1406:                        exitLink(entered, e.stateMask);
1407:                        paintLinkHover(entered, false);
1408:                        entered = null;
1409:                    }
1410:                    setCursor(null);
1411:                } else {
1412:                    if (segmentUnder instanceof  IHyperlinkSegment) {
1413:                        IHyperlinkSegment linkUnder = (IHyperlinkSegment) segmentUnder;
1414:                        if (entered != null && linkUnder != entered) {
1415:                            // Special case: links are so close that there are 0 pixels between.
1416:                            // Must exit the link before entering the next one.
1417:                            exitLink(entered, e.stateMask);
1418:                            paintLinkHover(entered, false);
1419:                            entered = null;
1420:                        }
1421:                        if (entered == null) {
1422:                            entered = linkUnder;
1423:                            enterLink(linkUnder, e.stateMask);
1424:                            paintLinkHover(entered, true);
1425:                            setCursor(model.getHyperlinkSettings()
1426:                                    .getHyperlinkCursor());
1427:                        }
1428:                    } else {
1429:                        if (entered != null) {
1430:                            exitLink(entered, e.stateMask);
1431:                            paintLinkHover(entered, false);
1432:                            entered = null;
1433:                        }
1434:                        if (segmentUnder instanceof  TextSegment)
1435:                            setCursor(model.getHyperlinkSettings()
1436:                                    .getTextCursor());
1437:                        else
1438:                            setCursor(null);
1439:                    }
1440:                }
1441:            }
1442:
1443:            private boolean advance(boolean next) {
1444:                if (DEBUG_FOCUS)
1445:                    System.out.println("Advance: next=" + next); //$NON-NLS-1$
1446:                IFocusSelectable current = model.getSelectedSegment();
1447:                if (current != null && current instanceof  IHyperlinkSegment)
1448:                    exitLink((IHyperlinkSegment) current, SWT.NULL);
1449:                IFocusSelectable newSegment = null;
1450:                boolean valid = false;
1451:                // get the next segment that can accept focus. Links
1452:                // can always accept focus but controls may not
1453:                while (!valid) {
1454:                    if (!model.traverseFocusSelectableObjects(next))
1455:                        break;
1456:                    newSegment = model.getSelectedSegment();
1457:                    if (newSegment == null)
1458:                        break;
1459:                    valid = setControlFocus(next, newSegment);
1460:                }
1461:                IHyperlinkSegment newLink = newSegment instanceof  IHyperlinkSegment ? (IHyperlinkSegment) newSegment
1462:                        : null;
1463:                if (valid)
1464:                    enterLink(newLink, SWT.NULL);
1465:                IHyperlinkSegment oldLink = current instanceof  IHyperlinkSegment ? (IHyperlinkSegment) current
1466:                        : null;
1467:                if (oldLink != null || newLink != null)
1468:                    paintFocusTransfer(oldLink, newLink);
1469:                if (newLink != null)
1470:                    ensureVisible(newLink);
1471:                if (newLink != null)
1472:                    getAccessible().setFocus(model.getSelectedSegmentIndex());
1473:                return !valid;
1474:            }
1475:
1476:            private boolean setControlFocus(boolean next,
1477:                    IFocusSelectable selectable) {
1478:                controlFocusTransfer = true;
1479:                boolean result = selectable.setFocus(resourceTable, next);
1480:                controlFocusTransfer = false;
1481:                return result;
1482:            }
1483:
1484:            private void handleFocusChange() {
1485:                if (DEBUG_FOCUS) {
1486:                    System.out
1487:                            .println("Handle focus change: hasFocus=" + hasFocus //$NON-NLS-1$
1488:                                    + ", mouseFocus=" + mouseFocus); //$NON-NLS-1$
1489:                }
1490:                if (hasFocus) {
1491:                    boolean advance = true;
1492:                    if (!mouseFocus) {
1493:                        // if (model.restoreSavedLink() == false)
1494:                        boolean valid = false;
1495:                        IFocusSelectable selectable = null;
1496:                        while (!valid) {
1497:                            if (!model.traverseFocusSelectableObjects(advance))
1498:                                break;
1499:                            selectable = model.getSelectedSegment();
1500:                            if (selectable == null)
1501:                                break;
1502:                            valid = setControlFocus(advance, selectable);
1503:                        }
1504:                        if (selectable == null)
1505:                            setFocusToNextSibling(this , true);
1506:                        else
1507:                            ensureVisible(selectable);
1508:                        if (selectable instanceof  IHyperlinkSegment) {
1509:                            enterLink((IHyperlinkSegment) selectable, SWT.NULL);
1510:                            paintFocusTransfer(null,
1511:                                    (IHyperlinkSegment) selectable);
1512:                        }
1513:                    }
1514:                } else {
1515:                    paintFocusTransfer(getSelectedLink(), null);
1516:                    model.selectLink(null);
1517:                }
1518:            }
1519:
1520:            private void enterLink(IHyperlinkSegment link, int stateMask) {
1521:                if (link == null || listeners == null)
1522:                    return;
1523:                int size = listeners.size();
1524:                HyperlinkEvent he = new HyperlinkEvent(this , link.getHref(),
1525:                        link.getText(), stateMask);
1526:                Object[] listenerList = listeners.getListeners();
1527:                for (int i = 0; i < size; i++) {
1528:                    IHyperlinkListener listener = (IHyperlinkListener) listenerList[i];
1529:                    listener.linkEntered(he);
1530:                }
1531:            }
1532:
1533:            private void exitLink(IHyperlinkSegment link, int stateMask) {
1534:                if (link == null || listeners == null)
1535:                    return;
1536:                int size = listeners.size();
1537:                HyperlinkEvent he = new HyperlinkEvent(this , link.getHref(),
1538:                        link.getText(), stateMask);
1539:                Object[] listenerList = listeners.getListeners();
1540:                for (int i = 0; i < size; i++) {
1541:                    IHyperlinkListener listener = (IHyperlinkListener) listenerList[i];
1542:                    listener.linkExited(he);
1543:                }
1544:            }
1545:
1546:            private void paintLinkHover(IHyperlinkSegment link, boolean hover) {
1547:                GC gc = new GC(this );
1548:                HyperlinkSettings settings = getHyperlinkSettings();
1549:                Color newFg = hover ? settings.getActiveForeground() : settings
1550:                        .getForeground();
1551:                if (newFg != null)
1552:                    gc.setForeground(newFg);
1553:                gc.setBackground(getBackground());
1554:                gc.setFont(getFont());
1555:                boolean selected = (link == getSelectedLink());
1556:                ((ParagraphSegment) link).paint(gc, hover, resourceTable,
1557:                        selected, selData, null);
1558:                gc.dispose();
1559:            }
1560:
1561:            private void activateSelectedLink() {
1562:                IHyperlinkSegment link = getSelectedLink();
1563:                if (link != null)
1564:                    activateLink(link, SWT.NULL);
1565:            }
1566:
1567:            private void activateLink(IHyperlinkSegment link, int stateMask) {
1568:                setCursor(model.getHyperlinkSettings().getBusyCursor());
1569:                if (listeners != null) {
1570:                    int size = listeners.size();
1571:                    HyperlinkEvent e = new HyperlinkEvent(this , link.getHref(),
1572:                            link.getText(), stateMask);
1573:                    Object[] listenerList = listeners.getListeners();
1574:                    for (int i = 0; i < size; i++) {
1575:                        IHyperlinkListener listener = (IHyperlinkListener) listenerList[i];
1576:                        listener.linkActivated(e);
1577:                    }
1578:                }
1579:                if (!isDisposed() && model.linkExists(link)) {
1580:                    setCursor(model.getHyperlinkSettings().getHyperlinkCursor());
1581:                }
1582:            }
1583:
1584:            private void ensureBoldFontPresent(Font regularFont) {
1585:                Font boldFont = (Font) resourceTable
1586:                        .get(FormTextModel.BOLD_FONT_ID);
1587:                if (boldFont != null)
1588:                    return;
1589:                boldFont = FormUtil.createBoldFont(getDisplay(), regularFont);
1590:                resourceTable.put(FormTextModel.BOLD_FONT_ID, boldFont);
1591:            }
1592:
1593:            private void paint(PaintEvent e) {
1594:                GC gc = e.gc;
1595:                gc.setFont(getFont());
1596:                ensureBoldFontPresent(getFont());
1597:                gc.setForeground(getForeground());
1598:                gc.setBackground(getBackground());
1599:                repaint(gc, e.x, e.y, e.width, e.height);
1600:            }
1601:
1602:            private void repaint(GC gc, int x, int y, int width, int height) {
1603:                Image textBuffer = new Image(getDisplay(), width, height);
1604:                Color bg = getBackground();
1605:                Color fg = getForeground();
1606:                if (!getEnabled()) {
1607:                    bg = getDisplay().getSystemColor(
1608:                            SWT.COLOR_WIDGET_BACKGROUND);
1609:                    fg = getDisplay().getSystemColor(
1610:                            SWT.COLOR_WIDGET_NORMAL_SHADOW);
1611:                }
1612:                GC textGC = new GC(textBuffer, gc.getStyle());
1613:                textGC.setForeground(fg);
1614:                textGC.setBackground(bg);
1615:                textGC.setFont(getFont());
1616:                textGC.fillRectangle(0, 0, width, height);
1617:                Rectangle repaintRegion = new Rectangle(x, y, width, height);
1618:
1619:                Paragraph[] paragraphs = model.getParagraphs();
1620:                IHyperlinkSegment selectedLink = getSelectedLink();
1621:                if (getDisplay().getFocusControl() != this )
1622:                    selectedLink = null;
1623:                for (int i = 0; i < paragraphs.length; i++) {
1624:                    Paragraph p = paragraphs[i];
1625:                    p.paint(textGC, repaintRegion, resourceTable, selectedLink,
1626:                            selData);
1627:                }
1628:                textGC.dispose();
1629:                gc.drawImage(textBuffer, x, y);
1630:                textBuffer.dispose();
1631:            }
1632:
1633:            private int getParagraphSpacing(int lineHeight) {
1634:                return lineHeight / 2;
1635:            }
1636:
1637:            private void paintFocusTransfer(IHyperlinkSegment oldLink,
1638:                    IHyperlinkSegment newLink) {
1639:                GC gc = new GC(this );
1640:                Color bg = getBackground();
1641:                Color fg = getForeground();
1642:                gc.setFont(getFont());
1643:                if (oldLink != null) {
1644:                    gc.setBackground(bg);
1645:                    gc.setForeground(fg);
1646:                    oldLink.paintFocus(gc, bg, fg, false, null);
1647:                }
1648:                if (newLink != null) {
1649:                    // ensureVisible(newLink);
1650:                    gc.setBackground(bg);
1651:                    gc.setForeground(fg);
1652:                    newLink.paintFocus(gc, bg, fg, true, null);
1653:                }
1654:                gc.dispose();
1655:            }
1656:
1657:            private void ensureVisible(IFocusSelectable segment) {
1658:                if (mouseFocus) {
1659:                    mouseFocus = false;
1660:                    return;
1661:                }
1662:                if (segment == null)
1663:                    return;
1664:                Rectangle bounds = segment.getBounds();
1665:                ScrolledComposite scomp = FormUtil.getScrolledComposite(this );
1666:                if (scomp == null)
1667:                    return;
1668:                Point origin = FormUtil.getControlLocation(scomp, this );
1669:                origin.x += bounds.x;
1670:                origin.y += bounds.y;
1671:                FormUtil.ensureVisible(scomp, origin, new Point(bounds.width,
1672:                        bounds.height));
1673:            }
1674:
1675:            /**
1676:             * Overrides the method by fully trusting the layout manager (computed width
1677:             * or height may be larger than the provider width or height hints). Callers
1678:             * should be prepared that the computed width is larger than the provided
1679:             * wHint.
1680:             * 
1681:             * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
1682:             */
1683:            public Point computeSize(int wHint, int hHint, boolean changed) {
1684:                checkWidget();
1685:                Point size;
1686:                FormTextLayout layout = (FormTextLayout) getLayout();
1687:                if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
1688:                    size = layout.computeSize(this , wHint, hHint, changed);
1689:                } else {
1690:                    size = new Point(wHint, hHint);
1691:                }
1692:                Rectangle trim = computeTrim(0, 0, size.x, size.y);
1693:                if (DEBUG_TEXTSIZE)
1694:                    System.out.println("FormText Computed size: " + trim); //$NON-NLS-1$
1695:                return new Point(trim.width, trim.height);
1696:            }
1697:
1698:            private void disposeResourceTable(boolean disposeBoldFont) {
1699:                if (disposeBoldFont) {
1700:                    Font boldFont = (Font) resourceTable
1701:                            .get(FormTextModel.BOLD_FONT_ID);
1702:                    if (boldFont != null) {
1703:                        boldFont.dispose();
1704:                        resourceTable.remove(FormTextModel.BOLD_FONT_ID);
1705:                    }
1706:                }
1707:                ArrayList imagesToRemove = new ArrayList();
1708:                for (Enumeration enm = resourceTable.keys(); enm
1709:                        .hasMoreElements();) {
1710:                    String key = (String) enm.nextElement();
1711:                    if (key.startsWith(ImageSegment.SEL_IMAGE_PREFIX)) {
1712:                        Object obj = resourceTable.get(key);
1713:                        if (obj instanceof  Image) {
1714:                            Image image = (Image) obj;
1715:                            if (!image.isDisposed()) {
1716:                                image.dispose();
1717:                                imagesToRemove.add(key);
1718:                            }
1719:                        }
1720:                    }
1721:                }
1722:                for (int i = 0; i < imagesToRemove.size(); i++) {
1723:                    resourceTable.remove(imagesToRemove.get(i));
1724:                }
1725:            }
1726:
1727:            /*
1728:             * (non-Javadoc)
1729:             * 
1730:             * @see org.eclipse.swt.widgets.Control#setEnabled(boolean)
1731:             */
1732:            public void setEnabled(boolean enabled) {
1733:                super .setEnabled(enabled);
1734:                redraw();
1735:            }
1736:
1737:            /* (non-Javadoc)
1738:             * @see org.eclipse.swt.widgets.Control#setFocus()
1739:             */
1740:            public boolean setFocus() {
1741:                FormUtil.setFocusScrollingEnabled(this , false);
1742:                boolean result = super .setFocus();
1743:                FormUtil.setFocusScrollingEnabled(this , true);
1744:                return result;
1745:            }
1746:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.