Source Code Cross Referenced for AccessibleHTML.java in  » 6.0-JDK-Core » swing » javax » swing » text » html » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
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
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text.html 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package javax.swing.text.html;
0027
0028        import java.awt.*;
0029        import java.awt.event.*;
0030        import java.beans.*;
0031        import java.util.*;
0032        import javax.swing.*;
0033        import javax.swing.event.*;
0034        import javax.swing.text.*;
0035        import javax.accessibility.*;
0036        import java.text.BreakIterator;
0037
0038        /*
0039         * The AccessibleHTML class provide information about the contents 
0040         * of a HTML document to assistive technologies.
0041         * 
0042         * @version 1.21 05/05/07
0043         * @author  Lynn Monsanto
0044         */
0045        class AccessibleHTML implements  Accessible {
0046
0047            /**
0048             * The editor.
0049             */
0050            private JEditorPane editor;
0051            /**
0052             * Current model.
0053             */
0054            private Document model;
0055            /**
0056             * DocumentListener installed on the current model.
0057             */
0058            private DocumentListener docListener;
0059            /**
0060             * PropertyChangeListener installed on the editor
0061             */
0062            private PropertyChangeListener propChangeListener;
0063            /**
0064             * The root ElementInfo for the document
0065             */
0066            private ElementInfo rootElementInfo;
0067            /*
0068             * The root accessible context for the document
0069             */
0070            private RootHTMLAccessibleContext rootHTMLAccessibleContext;
0071
0072            public AccessibleHTML(JEditorPane pane) {
0073                editor = pane;
0074                propChangeListener = new PropertyChangeHandler();
0075                setDocument(editor.getDocument());
0076
0077                docListener = new DocumentHandler();
0078            }
0079
0080            /**
0081             * Sets the document.
0082             */
0083            private void setDocument(Document document) {
0084                if (model != null) {
0085                    model.removeDocumentListener(docListener);
0086                }
0087                if (editor != null) {
0088                    editor.removePropertyChangeListener(propChangeListener);
0089                }
0090                this .model = document;
0091                if (model != null) {
0092                    if (rootElementInfo != null) {
0093                        rootElementInfo.invalidate(false);
0094                    }
0095                    buildInfo();
0096                    model.addDocumentListener(docListener);
0097                } else {
0098                    rootElementInfo = null;
0099                }
0100                if (editor != null) {
0101                    editor.addPropertyChangeListener(propChangeListener);
0102                }
0103            }
0104
0105            /**
0106             * Returns the Document currently presenting information for.
0107             */
0108            private Document getDocument() {
0109                return model;
0110            }
0111
0112            /**
0113             * Returns the JEditorPane providing information for.
0114             */
0115            private JEditorPane getTextComponent() {
0116                return editor;
0117            }
0118
0119            /**
0120             * Returns the ElementInfo representing the root Element.
0121             */
0122            private ElementInfo getRootInfo() {
0123                return rootElementInfo;
0124            }
0125
0126            /**
0127             * Returns the root <code>View</code> associated with the current text
0128             * component.
0129             */
0130            private View getRootView() {
0131                return getTextComponent().getUI().getRootView(
0132                        getTextComponent());
0133            }
0134
0135            /**
0136             * Returns the bounds the root View will be rendered in.
0137             */
0138            private Rectangle getRootEditorRect() {
0139                Rectangle alloc = getTextComponent().getBounds();
0140                if ((alloc.width > 0) && (alloc.height > 0)) {
0141                    alloc.x = alloc.y = 0;
0142                    Insets insets = editor.getInsets();
0143                    alloc.x += insets.left;
0144                    alloc.y += insets.top;
0145                    alloc.width -= insets.left + insets.right;
0146                    alloc.height -= insets.top + insets.bottom;
0147                    return alloc;
0148                }
0149                return null;
0150            }
0151
0152            /**
0153             * If possible acquires a lock on the Document.  If a lock has been
0154             * obtained a key will be retured that should be passed to
0155             * <code>unlock</code>.
0156             */
0157            private Object lock() {
0158                Document document = getDocument();
0159
0160                if (document instanceof  AbstractDocument) {
0161                    ((AbstractDocument) document).readLock();
0162                    return document;
0163                }
0164                return null;
0165            }
0166
0167            /**
0168             * Releases a lock previously obtained via <code>lock</code>.
0169             */
0170            private void unlock(Object key) {
0171                if (key != null) {
0172                    ((AbstractDocument) key).readUnlock();
0173                }
0174            }
0175
0176            /**
0177             * Rebuilds the information from the current info.
0178             */
0179            private void buildInfo() {
0180                Object lock = lock();
0181
0182                try {
0183                    Document doc = getDocument();
0184                    Element root = doc.getDefaultRootElement();
0185
0186                    rootElementInfo = new ElementInfo(root);
0187                    rootElementInfo.validate();
0188                } finally {
0189                    unlock(lock);
0190                }
0191            }
0192
0193            /*
0194             * Create an ElementInfo subclass based on the passed in Element.
0195             */
0196            ElementInfo createElementInfo(Element e, ElementInfo parent) {
0197                AttributeSet attrs = e.getAttributes();
0198
0199                if (attrs != null) {
0200                    Object name = attrs
0201                            .getAttribute(StyleConstants.NameAttribute);
0202
0203                    if (name == HTML.Tag.IMG) {
0204                        return new IconElementInfo(e, parent);
0205                    } else if (name == HTML.Tag.CONTENT
0206                            || name == HTML.Tag.CAPTION) {
0207                        return new TextElementInfo(e, parent);
0208                    } else if (name == HTML.Tag.TABLE) {
0209                        return new TableElementInfo(e, parent);
0210                    }
0211                }
0212                return null;
0213            }
0214
0215            /**
0216             * Returns the root AccessibleContext for the document
0217             */
0218            public AccessibleContext getAccessibleContext() {
0219                if (rootHTMLAccessibleContext == null) {
0220                    rootHTMLAccessibleContext = new RootHTMLAccessibleContext(
0221                            rootElementInfo);
0222                }
0223                return rootHTMLAccessibleContext;
0224            }
0225
0226            /*
0227             * The roow AccessibleContext for the document
0228             */
0229            private class RootHTMLAccessibleContext extends
0230                    HTMLAccessibleContext {
0231
0232                public RootHTMLAccessibleContext(ElementInfo elementInfo) {
0233                    super (elementInfo);
0234                }
0235
0236                /**
0237                 * Gets the accessibleName property of this object.  The accessibleName
0238                 * property of an object is a localized String that designates the purpose
0239                 * of the object.  For example, the accessibleName property of a label
0240                 * or button might be the text of the label or button itself.  In the
0241                 * case of an object that doesn't display its name, the accessibleName
0242                 * should still be set.  For example, in the case of a text field used
0243                 * to enter the name of a city, the accessibleName for the en_US locale
0244                 * could be 'city.'
0245                 *
0246                 * @return the localized name of the object; null if this 
0247                 * object does not have a name
0248                 *
0249                 * @see #setAccessibleName
0250                 */
0251                public String getAccessibleName() {
0252                    if (model != null) {
0253                        return (String) model
0254                                .getProperty(Document.TitleProperty);
0255                    } else {
0256                        return null;
0257                    }
0258                }
0259
0260                /**
0261                 * Gets the accessibleDescription property of this object.  If this
0262                 * property isn't set, returns the content type of this
0263                 * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
0264                 *
0265                 * @return the localized description of the object; <code>null</code>
0266                 * 	if this object does not have a description
0267                 *
0268                 * @see #setAccessibleName
0269                 */
0270                public String getAccessibleDescription() {
0271                    return editor.getContentType();
0272                }
0273
0274                /**
0275                 * Gets the role of this object.  The role of the object is the generic
0276                 * purpose or use of the class of this object.  For example, the role
0277                 * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in 
0278                 * AccessibleRole are provided so component developers can pick from
0279                 * a set of predefined roles.  This enables assistive technologies to
0280                 * provide a consistent interface to various tweaked subclasses of 
0281                 * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
0282                 * that act like a push button) as well as distinguish between sublasses
0283                 * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
0284                 * and AccessibleRole.RADIO_BUTTON for radio buttons).
0285                 * <p>Note that the AccessibleRole class is also extensible, so 
0286                 * custom component developers can define their own AccessibleRole's
0287                 * if the set of predefined roles is inadequate.
0288                 *
0289                 * @return an instance of AccessibleRole describing the role of the object
0290                 * @see AccessibleRole
0291                 */
0292                public AccessibleRole getAccessibleRole() {
0293                    return AccessibleRole.TEXT;
0294                }
0295            }
0296
0297            /*
0298             * Base AccessibleContext class for HTML elements
0299             */
0300            protected abstract class HTMLAccessibleContext extends
0301                    AccessibleContext implements  Accessible,
0302                    AccessibleComponent {
0303
0304                protected ElementInfo elementInfo;
0305
0306                public HTMLAccessibleContext(ElementInfo elementInfo) {
0307                    this .elementInfo = elementInfo;
0308                }
0309
0310                // begin AccessibleContext implementation ...
0311                public AccessibleContext getAccessibleContext() {
0312                    return this ;
0313                }
0314
0315                /**
0316                 * Gets the state set of this object.
0317                 *
0318                 * @return an instance of AccessibleStateSet describing the states
0319                 * of the object
0320                 * @see AccessibleStateSet
0321                 */
0322                public AccessibleStateSet getAccessibleStateSet() {
0323                    AccessibleStateSet states = new AccessibleStateSet();
0324                    Component comp = getTextComponent();
0325
0326                    if (comp.isEnabled()) {
0327                        states.add(AccessibleState.ENABLED);
0328                    }
0329                    if (comp instanceof  JTextComponent
0330                            && ((JTextComponent) comp).isEditable()) {
0331
0332                        states.add(AccessibleState.EDITABLE);
0333                        states.add(AccessibleState.FOCUSABLE);
0334                    }
0335                    if (comp.isVisible()) {
0336                        states.add(AccessibleState.VISIBLE);
0337                    }
0338                    if (comp.isShowing()) {
0339                        states.add(AccessibleState.SHOWING);
0340                    }
0341                    return states;
0342                }
0343
0344                /**
0345                 * Gets the 0-based index of this object in its accessible parent.
0346                 *
0347                 * @return the 0-based index of this object in its parent; -1 if this 
0348                 * object does not have an accessible parent.
0349                 *
0350                 * @see #getAccessibleParent 
0351                 * @see #getAccessibleChildrenCount
0352                 * @see #getAccessibleChild
0353                 */
0354                public int getAccessibleIndexInParent() {
0355                    return elementInfo.getIndexInParent();
0356                }
0357
0358                /**
0359                 * Returns the number of accessible children of the object.
0360                 *
0361                 * @return the number of accessible children of the object.
0362                 */
0363                public int getAccessibleChildrenCount() {
0364                    return elementInfo.getChildCount();
0365                }
0366
0367                /**
0368                 * Returns the specified Accessible child of the object.  The Accessible
0369                 * children of an Accessible object are zero-based, so the first child 
0370                 * of an Accessible child is at index 0, the second child is at index 1,
0371                 * and so on.
0372                 *
0373                 * @param i zero-based index of child
0374                 * @return the Accessible child of the object
0375                 * @see #getAccessibleChildrenCount
0376                 */
0377                public Accessible getAccessibleChild(int i) {
0378                    ElementInfo childInfo = elementInfo.getChild(i);
0379                    if (childInfo != null && childInfo instanceof  Accessible) {
0380                        return (Accessible) childInfo;
0381                    } else {
0382                        return null;
0383                    }
0384                }
0385
0386                /** 
0387                 * Gets the locale of the component. If the component does not have a 
0388                 * locale, then the locale of its parent is returned.  
0389                 *
0390                 * @return this component's locale.  If this component does not have 
0391                 * a locale, the locale of its parent is returned.
0392                 *
0393                 * @exception IllegalComponentStateException 
0394                 * If the Component does not have its own locale and has not yet been 
0395                 * added to a containment hierarchy such that the locale can be
0396                 * determined from the containing parent. 
0397                 */
0398                public Locale getLocale() throws IllegalComponentStateException {
0399                    return editor.getLocale();
0400                }
0401
0402                // ... end AccessibleContext implementation
0403
0404                // begin AccessibleComponent implementation ...
0405                public AccessibleComponent getAccessibleComponent() {
0406                    return this ;
0407                }
0408
0409                /**
0410                 * Gets the background color of this object.
0411                 *
0412                 * @return the background color, if supported, of the object; 
0413                 * otherwise, null
0414                 * @see #setBackground
0415                 */
0416                public Color getBackground() {
0417                    return getTextComponent().getBackground();
0418                }
0419
0420                /**
0421                 * Sets the background color of this object.
0422                 *
0423                 * @param c the new Color for the background
0424                 * @see #setBackground
0425                 */
0426                public void setBackground(Color c) {
0427                    getTextComponent().setBackground(c);
0428                }
0429
0430                /**
0431                 * Gets the foreground color of this object.
0432                 *
0433                 * @return the foreground color, if supported, of the object; 
0434                 * otherwise, null
0435                 * @see #setForeground
0436                 */
0437                public Color getForeground() {
0438                    return getTextComponent().getForeground();
0439                }
0440
0441                /**
0442                 * Sets the foreground color of this object.
0443                 *
0444                 * @param c the new Color for the foreground
0445                 * @see #getForeground
0446                 */
0447                public void setForeground(Color c) {
0448                    getTextComponent().setForeground(c);
0449                }
0450
0451                /**
0452                 * Gets the Cursor of this object.
0453                 *
0454                 * @return the Cursor, if supported, of the object; otherwise, null
0455                 * @see #setCursor
0456                 */
0457                public Cursor getCursor() {
0458                    return getTextComponent().getCursor();
0459                }
0460
0461                /**
0462                 * Sets the Cursor of this object.
0463                 *
0464                 * @param c the new Cursor for the object
0465                 * @see #getCursor
0466                 */
0467                public void setCursor(Cursor cursor) {
0468                    getTextComponent().setCursor(cursor);
0469                }
0470
0471                /**
0472                 * Gets the Font of this object.
0473                 *
0474                 * @return the Font,if supported, for the object; otherwise, null
0475                 * @see #setFont
0476                 */
0477                public Font getFont() {
0478                    return getTextComponent().getFont();
0479                }
0480
0481                /**
0482                 * Sets the Font of this object.
0483                 *
0484                 * @param f the new Font for the object
0485                 * @see #getFont
0486                 */
0487                public void setFont(Font f) {
0488                    getTextComponent().setFont(f);
0489                }
0490
0491                /**
0492                 * Gets the FontMetrics of this object.
0493                 *
0494                 * @param f the Font
0495                 * @return the FontMetrics, if supported, the object; otherwise, null
0496                 * @see #getFont
0497                 */
0498                public FontMetrics getFontMetrics(Font f) {
0499                    return getTextComponent().getFontMetrics(f);
0500                }
0501
0502                /**
0503                 * Determines if the object is enabled.  Objects that are enabled
0504                 * will also have the AccessibleState.ENABLED state set in their
0505                 * AccessibleStateSets.
0506                 *
0507                 * @return true if object is enabled; otherwise, false
0508                 * @see #setEnabled
0509                 * @see AccessibleContext#getAccessibleStateSet
0510                 * @see AccessibleState#ENABLED
0511                 * @see AccessibleStateSet
0512                 */
0513                public boolean isEnabled() {
0514                    return getTextComponent().isEnabled();
0515                }
0516
0517                /**
0518                 * Sets the enabled state of the object.
0519                 *
0520                 * @param b if true, enables this object; otherwise, disables it 
0521                 * @see #isEnabled
0522                 */
0523                public void setEnabled(boolean b) {
0524                    getTextComponent().setEnabled(b);
0525                }
0526
0527                /**
0528                 * Determines if the object is visible.  Note: this means that the
0529                 * object intends to be visible; however, it may not be
0530                 * showing on the screen because one of the objects that this object
0531                 * is contained by is currently not visible.  To determine if an object
0532                 * is showing on the screen, use isShowing().
0533                 * <p>Objects that are visible will also have the 
0534                 * AccessibleState.VISIBLE state set in their AccessibleStateSets.
0535                 *
0536                 * @return true if object is visible; otherwise, false
0537                 * @see #setVisible
0538                 * @see AccessibleContext#getAccessibleStateSet
0539                 * @see AccessibleState#VISIBLE
0540                 * @see AccessibleStateSet
0541                 */
0542                public boolean isVisible() {
0543                    return getTextComponent().isVisible();
0544                }
0545
0546                /**
0547                 * Sets the visible state of the object.
0548                 *
0549                 * @param b if true, shows this object; otherwise, hides it 
0550                 * @see #isVisible
0551                 */
0552                public void setVisible(boolean b) {
0553                    getTextComponent().setVisible(b);
0554                }
0555
0556                /**
0557                 * Determines if the object is showing.  This is determined by checking
0558                 * the visibility of the object and its ancestors.
0559                 * Note: this
0560                 * will return true even if the object is obscured by another (for 
0561                 * example, it is underneath a menu that was pulled down).
0562                 *
0563                 * @return true if object is showing; otherwise, false
0564                 */
0565                public boolean isShowing() {
0566                    return getTextComponent().isShowing();
0567                }
0568
0569                /** 
0570                 * Checks whether the specified point is within this object's bounds,
0571                 * where the point's x and y coordinates are defined to be relative 
0572                 * to the coordinate system of the object. 
0573                 *
0574                 * @param p the Point relative to the coordinate system of the object
0575                 * @return true if object contains Point; otherwise false
0576                 * @see #getBounds
0577                 */
0578                public boolean contains(Point p) {
0579                    Rectangle r = getBounds();
0580                    if (r != null) {
0581                        return r.contains(p.x, p.y);
0582                    } else {
0583                        return false;
0584                    }
0585                }
0586
0587                /** 
0588                 * Returns the location of the object on the screen.
0589                 *
0590                 * @return the location of the object on screen; null if this object
0591                 * is not on the screen
0592                 * @see #getBounds
0593                 * @see #getLocation
0594                 */
0595                public Point getLocationOnScreen() {
0596                    Point editorLocation = getTextComponent()
0597                            .getLocationOnScreen();
0598                    Rectangle r = getBounds();
0599                    if (r != null) {
0600                        return new Point(editorLocation.x + r.x,
0601                                editorLocation.y + r.y);
0602                    } else {
0603                        return null;
0604                    }
0605                }
0606
0607                /** 
0608                 * Gets the location of the object relative to the parent in the form 
0609                 * of a point specifying the object's top-left corner in the screen's 
0610                 * coordinate space.
0611                 *
0612                 * @return An instance of Point representing the top-left corner of the 
0613                 * object's bounds in the coordinate space of the screen; null if
0614                 * this object or its parent are not on the screen
0615                 * @see #getBounds
0616                 * @see #getLocationOnScreen
0617                 */
0618                public Point getLocation() {
0619                    Rectangle r = getBounds();
0620                    if (r != null) {
0621                        return new Point(r.x, r.y);
0622                    } else {
0623                        return null;
0624                    }
0625                }
0626
0627                /** 
0628                 * Sets the location of the object relative to the parent.
0629                 * @param p the new position for the top-left corner
0630                 * @see #getLocation
0631                 */
0632                public void setLocation(Point p) {
0633                }
0634
0635                /** 
0636                 * Gets the bounds of this object in the form of a Rectangle object. 
0637                 * The bounds specify this object's width, height, and location
0638                 * relative to its parent. 
0639                 *
0640                 * @return A rectangle indicating this component's bounds; null if 
0641                 * this object is not on the screen.
0642                 * @see #contains
0643                 */
0644                public Rectangle getBounds() {
0645                    return elementInfo.getBounds();
0646                }
0647
0648                /** 
0649                 * Sets the bounds of this object in the form of a Rectangle object. 
0650                 * The bounds specify this object's width, height, and location
0651                 * relative to its parent.
0652                 *	
0653                 * @param r rectangle indicating this component's bounds
0654                 * @see #getBounds
0655                 */
0656                public void setBounds(Rectangle r) {
0657                }
0658
0659                /** 
0660                 * Returns the size of this object in the form of a Dimension object. 
0661                 * The height field of the Dimension object contains this object's
0662                 * height, and the width field of the Dimension object contains this 
0663                 * object's width. 
0664                 *
0665                 * @return A Dimension object that indicates the size of this component; 
0666                 * null if this object is not on the screen
0667                 * @see #setSize
0668                 */
0669                public Dimension getSize() {
0670                    Rectangle r = getBounds();
0671                    if (r != null) {
0672                        return new Dimension(r.width, r.height);
0673                    } else {
0674                        return null;
0675                    }
0676                }
0677
0678                /** 
0679                 * Resizes this object so that it has width and height. 
0680                 *	
0681                 * @param d The dimension specifying the new size of the object. 
0682                 * @see #getSize
0683                 */
0684                public void setSize(Dimension d) {
0685                    Component comp = getTextComponent();
0686                    comp.setSize(d);
0687                }
0688
0689                /**
0690                 * Returns the Accessible child, if one exists, contained at the local 
0691                 * coordinate Point.
0692                 *
0693                 * @param p The point relative to the coordinate system of this object.
0694                 * @return the Accessible, if it exists, at the specified location; 
0695                 * otherwise null
0696                 */
0697                public Accessible getAccessibleAt(Point p) {
0698                    ElementInfo innerMostElement = getElementInfoAt(
0699                            rootElementInfo, p);
0700                    if (innerMostElement instanceof  Accessible) {
0701                        return (Accessible) innerMostElement;
0702                    } else {
0703                        return null;
0704                    }
0705                }
0706
0707                private ElementInfo getElementInfoAt(ElementInfo elementInfo,
0708                        Point p) {
0709                    if (elementInfo.getBounds() == null) {
0710                        return null;
0711                    }
0712                    if (elementInfo.getChildCount() == 0
0713                            && elementInfo.getBounds().contains(p)) {
0714                        return elementInfo;
0715
0716                    } else {
0717                        if (elementInfo instanceof  TableElementInfo) {
0718                            // Handle table caption as a special case since it's the
0719                            // only table child that is not a table row.
0720                            ElementInfo captionInfo = ((TableElementInfo) elementInfo)
0721                                    .getCaptionInfo();
0722                            if (captionInfo != null) {
0723                                Rectangle bounds = captionInfo.getBounds();
0724                                if (bounds != null && bounds.contains(p)) {
0725                                    return captionInfo;
0726                                }
0727                            }
0728                        }
0729                        for (int i = 0; i < elementInfo.getChildCount(); i++) {
0730                            ElementInfo childInfo = elementInfo.getChild(i);
0731                            ElementInfo retValue = getElementInfoAt(childInfo,
0732                                    p);
0733                            if (retValue != null) {
0734                                return retValue;
0735                            }
0736                        }
0737                    }
0738                    return null;
0739                }
0740
0741                /**
0742                 * Returns whether this object can accept focus or not.   Objects that 
0743                 * can accept focus will also have the AccessibleState.FOCUSABLE state 
0744                 * set in their AccessibleStateSets.
0745                 *
0746                 * @return true if object can accept focus; otherwise false
0747                 * @see AccessibleContext#getAccessibleStateSet
0748                 * @see AccessibleState#FOCUSABLE
0749                 * @see AccessibleState#FOCUSED
0750                 * @see AccessibleStateSet
0751                 */
0752                public boolean isFocusTraversable() {
0753                    Component comp = getTextComponent();
0754                    if (comp instanceof  JTextComponent) {
0755                        if (((JTextComponent) comp).isEditable()) {
0756                            return true;
0757                        }
0758                    }
0759                    return false;
0760                }
0761
0762                /**
0763                 * Requests focus for this object.  If this object cannot accept focus,
0764                 * nothing will happen.  Otherwise, the object will attempt to take
0765                 * focus.
0766                 * @see #isFocusTraversable
0767                 */
0768                public void requestFocus() {
0769                    // TIGER - 4856191
0770                    if (!isFocusTraversable()) {
0771                        return;
0772                    }
0773
0774                    Component comp = getTextComponent();
0775                    if (comp instanceof  JTextComponent) {
0776
0777                        comp.requestFocusInWindow();
0778
0779                        try {
0780                            if (elementInfo.validateIfNecessary()) {
0781                                // set the caret position to the start of this component
0782                                Element elem = elementInfo.getElement();
0783                                ((JTextComponent) comp).setCaretPosition(elem
0784                                        .getStartOffset());
0785
0786                                // fire a AccessibleState.FOCUSED property change event
0787                                AccessibleContext ac = editor
0788                                        .getAccessibleContext();
0789                                PropertyChangeEvent pce = new PropertyChangeEvent(
0790                                        this ,
0791                                        AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
0792                                        null, AccessibleState.FOCUSED);
0793                                ac
0794                                        .firePropertyChange(
0795                                                AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
0796                                                null, pce);
0797                            }
0798                        } catch (IllegalArgumentException e) {
0799                            // don't fire property change event
0800                        }
0801                    }
0802                }
0803
0804                /**
0805                 * Adds the specified focus listener to receive focus events from this 
0806                 * component. 
0807                 *
0808                 * @param l the focus listener
0809                 * @see #removeFocusListener
0810                 */
0811                public void addFocusListener(FocusListener l) {
0812                    getTextComponent().addFocusListener(l);
0813                }
0814
0815                /**
0816                 * Removes the specified focus listener so it no longer receives focus 
0817                 * events from this component.
0818                 *
0819                 * @param l the focus listener
0820                 * @see #addFocusListener
0821                 */
0822                public void removeFocusListener(FocusListener l) {
0823                    getTextComponent().removeFocusListener(l);
0824                }
0825                // ... end AccessibleComponent implementation
0826            } // ... end HTMLAccessibleContext
0827
0828            /*
0829             * ElementInfo for text
0830             */
0831            class TextElementInfo extends ElementInfo implements  Accessible {
0832
0833                TextElementInfo(Element element, ElementInfo parent) {
0834                    super (element, parent);
0835                }
0836
0837                // begin AccessibleText implementation ...
0838                private AccessibleContext accessibleContext;
0839
0840                public AccessibleContext getAccessibleContext() {
0841                    if (accessibleContext == null) {
0842                        accessibleContext = new TextAccessibleContext(this );
0843                    }
0844                    return accessibleContext;
0845                }
0846
0847                /*
0848                 * AccessibleContext for text elements
0849                 */
0850                public class TextAccessibleContext extends
0851                        HTMLAccessibleContext implements  AccessibleText {
0852
0853                    public TextAccessibleContext(ElementInfo elementInfo) {
0854                        super (elementInfo);
0855                    }
0856
0857                    public AccessibleText getAccessibleText() {
0858                        return this ;
0859                    }
0860
0861                    /**
0862                     * Gets the accessibleName property of this object.  The accessibleName
0863                     * property of an object is a localized String that designates the purpose
0864                     * of the object.  For example, the accessibleName property of a label
0865                     * or button might be the text of the label or button itself.  In the
0866                     * case of an object that doesn't display its name, the accessibleName
0867                     * should still be set.  For example, in the case of a text field used
0868                     * to enter the name of a city, the accessibleName for the en_US locale
0869                     * could be 'city.'
0870                     *
0871                     * @return the localized name of the object; null if this 
0872                     * object does not have a name
0873                     *
0874                     * @see #setAccessibleName
0875                     */
0876                    public String getAccessibleName() {
0877                        if (model != null) {
0878                            return (String) model
0879                                    .getProperty(Document.TitleProperty);
0880                        } else {
0881                            return null;
0882                        }
0883                    }
0884
0885                    /**
0886                     * Gets the accessibleDescription property of this object.  If this
0887                     * property isn't set, returns the content type of this
0888                     * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
0889                     *
0890                     * @return the localized description of the object; <code>null</code>
0891                     * 	if this object does not have a description
0892                     *
0893                     * @see #setAccessibleName
0894                     */
0895                    public String getAccessibleDescription() {
0896                        return editor.getContentType();
0897                    }
0898
0899                    /**
0900                     * Gets the role of this object.  The role of the object is the generic
0901                     * purpose or use of the class of this object.  For example, the role
0902                     * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in 
0903                     * AccessibleRole are provided so component developers can pick from
0904                     * a set of predefined roles.  This enables assistive technologies to
0905                     * provide a consistent interface to various tweaked subclasses of 
0906                     * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
0907                     * that act like a push button) as well as distinguish between sublasses
0908                     * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
0909                     * and AccessibleRole.RADIO_BUTTON for radio buttons).
0910                     * <p>Note that the AccessibleRole class is also extensible, so 
0911                     * custom component developers can define their own AccessibleRole's
0912                     * if the set of predefined roles is inadequate.
0913                     *
0914                     * @return an instance of AccessibleRole describing the role of the object
0915                     * @see AccessibleRole
0916                     */
0917                    public AccessibleRole getAccessibleRole() {
0918                        return AccessibleRole.TEXT;
0919                    }
0920
0921                    /**
0922                     * Given a point in local coordinates, return the zero-based index
0923                     * of the character under that Point.  If the point is invalid,
0924                     * this method returns -1.
0925                     *
0926                     * @param p the Point in local coordinates
0927                     * @return the zero-based index of the character under Point p; if 
0928                     * Point is invalid returns -1.
0929                     */
0930                    public int getIndexAtPoint(Point p) {
0931                        View v = getView();
0932                        if (v != null) {
0933                            return v.viewToModel(p.x, p.y, getBounds());
0934                        } else {
0935                            return -1;
0936                        }
0937                    }
0938
0939                    /**
0940                     * Determine the bounding box of the character at the given 
0941                     * index into the string.  The bounds are returned in local
0942                     * coordinates.  If the index is invalid an empty rectangle is 
0943                     * returned.
0944                     *
0945                     * @param i the index into the String
0946                     * @return the screen coordinates of the character's the bounding box,
0947                     * if index is invalid returns an empty rectangle.
0948                     */
0949                    public Rectangle getCharacterBounds(int i) {
0950                        try {
0951                            return editor.getUI().modelToView(editor, i);
0952                        } catch (BadLocationException e) {
0953                            return null;
0954                        }
0955                    }
0956
0957                    /**
0958                     * Return the number of characters (valid indicies) 
0959                     *
0960                     * @return the number of characters
0961                     */
0962                    public int getCharCount() {
0963                        if (validateIfNecessary()) {
0964                            Element elem = elementInfo.getElement();
0965                            return elem.getEndOffset() - elem.getStartOffset();
0966                        }
0967                        return 0;
0968                    }
0969
0970                    /**
0971                     * Return the zero-based offset of the caret.
0972                     *
0973                     * Note: That to the right of the caret will have the same index
0974                     * value as the offset (the caret is between two characters).
0975                     * @return the zero-based offset of the caret.
0976                     */
0977                    public int getCaretPosition() {
0978                        View v = getView();
0979                        if (v == null) {
0980                            return -1;
0981                        }
0982                        Container c = v.getContainer();
0983                        if (c == null) {
0984                            return -1;
0985                        }
0986                        if (c instanceof  JTextComponent) {
0987                            return ((JTextComponent) c).getCaretPosition();
0988                        } else {
0989                            return -1;
0990                        }
0991                    }
0992
0993                    /**
0994                     * IndexedSegment extends Segment adding the offset into the
0995                     * the model the <code>Segment</code> was asked for.
0996                     */
0997                    private class IndexedSegment extends Segment {
0998                        /**
0999                         * Offset into the model that the position represents.
1000                         */
1001                        public int modelOffset;
1002                    }
1003
1004                    public String getAtIndex(int part, int index) {
1005                        return getAtIndex(part, index, 0);
1006                    }
1007
1008                    public String getAfterIndex(int part, int index) {
1009                        return getAtIndex(part, index, 1);
1010                    }
1011
1012                    public String getBeforeIndex(int part, int index) {
1013                        return getAtIndex(part, index, -1);
1014                    }
1015
1016                    /**
1017                     * Gets the word, sentence, or character at <code>index</code>.
1018                     * If <code>direction</code> is non-null this will find the
1019                     * next/previous word/sentence/character.
1020                     */
1021                    private String getAtIndex(int part, int index, int direction) {
1022                        if (model instanceof  AbstractDocument) {
1023                            ((AbstractDocument) model).readLock();
1024                        }
1025                        try {
1026                            if (index < 0 || index >= model.getLength()) {
1027                                return null;
1028                            }
1029                            switch (part) {
1030                            case AccessibleText.CHARACTER:
1031                                if (index + direction < model.getLength()
1032                                        && index + direction >= 0) {
1033                                    return model.getText(index + direction, 1);
1034                                }
1035                                break;
1036
1037                            case AccessibleText.WORD:
1038                            case AccessibleText.SENTENCE:
1039                                IndexedSegment seg = getSegmentAt(part, index);
1040                                if (seg != null) {
1041                                    if (direction != 0) {
1042                                        int next;
1043
1044                                        if (direction < 0) {
1045                                            next = seg.modelOffset - 1;
1046                                        } else {
1047                                            next = seg.modelOffset + direction
1048                                                    * seg.count;
1049                                        }
1050                                        if (next >= 0
1051                                                && next <= model.getLength()) {
1052                                            seg = getSegmentAt(part, next);
1053                                        } else {
1054                                            seg = null;
1055                                        }
1056                                    }
1057                                    if (seg != null) {
1058                                        return new String(seg.array,
1059                                                seg.offset, seg.count);
1060                                    }
1061                                }
1062                                break;
1063
1064                            default:
1065                                break;
1066                            }
1067                        } catch (BadLocationException e) {
1068                        } finally {
1069                            if (model instanceof  AbstractDocument) {
1070                                ((AbstractDocument) model).readUnlock();
1071                            }
1072                        }
1073                        return null;
1074                    }
1075
1076                    /*
1077                     * Returns the paragraph element for the specified index.
1078                     */
1079                    private Element getParagraphElement(int index) {
1080                        if (model instanceof  PlainDocument) {
1081                            PlainDocument sdoc = (PlainDocument) model;
1082                            return sdoc.getParagraphElement(index);
1083                        } else if (model instanceof  StyledDocument) {
1084                            StyledDocument sdoc = (StyledDocument) model;
1085                            return sdoc.getParagraphElement(index);
1086                        } else {
1087                            Element para = null;
1088                            for (para = model.getDefaultRootElement(); !para
1089                                    .isLeaf();) {
1090                                int pos = para.getElementIndex(index);
1091                                para = para.getElement(pos);
1092                            }
1093                            if (para == null) {
1094                                return null;
1095                            }
1096                            return para.getParentElement();
1097                        }
1098                    }
1099
1100                    /*
1101                     * Returns a <code>Segment</code> containing the paragraph text
1102                     * at <code>index</code>, or null if <code>index</code> isn't
1103                     * valid.
1104                     */
1105                    private IndexedSegment getParagraphElementText(int index)
1106                            throws BadLocationException {
1107                        Element para = getParagraphElement(index);
1108
1109                        if (para != null) {
1110                            IndexedSegment segment = new IndexedSegment();
1111                            try {
1112                                int length = para.getEndOffset()
1113                                        - para.getStartOffset();
1114                                model.getText(para.getStartOffset(), length,
1115                                        segment);
1116                            } catch (BadLocationException e) {
1117                                return null;
1118                            }
1119                            segment.modelOffset = para.getStartOffset();
1120                            return segment;
1121                        }
1122                        return null;
1123                    }
1124
1125                    /**
1126                     * Returns the Segment at <code>index</code> representing either
1127                     * the paragraph or sentence as identified by <code>part</code>, or
1128                     * null if a valid paragraph/sentence can't be found. The offset
1129                     * will point to the start of the word/sentence in the array, and
1130                     * the modelOffset will point to the location of the word/sentence
1131                     * in the model.
1132                     */
1133                    private IndexedSegment getSegmentAt(int part, int index)
1134                            throws BadLocationException {
1135
1136                        IndexedSegment seg = getParagraphElementText(index);
1137                        if (seg == null) {
1138                            return null;
1139                        }
1140                        BreakIterator iterator;
1141                        switch (part) {
1142                        case AccessibleText.WORD:
1143                            iterator = BreakIterator
1144                                    .getWordInstance(getLocale());
1145                            break;
1146                        case AccessibleText.SENTENCE:
1147                            iterator = BreakIterator
1148                                    .getSentenceInstance(getLocale());
1149                            break;
1150                        default:
1151                            return null;
1152                        }
1153                        seg.first();
1154                        iterator.setText(seg);
1155                        int end = iterator.following(index - seg.modelOffset
1156                                + seg.offset);
1157                        if (end == BreakIterator.DONE) {
1158                            return null;
1159                        }
1160                        if (end > seg.offset + seg.count) {
1161                            return null;
1162                        }
1163                        int begin = iterator.previous();
1164                        if (begin == BreakIterator.DONE
1165                                || begin >= seg.offset + seg.count) {
1166                            return null;
1167                        }
1168                        seg.modelOffset = seg.modelOffset + begin - seg.offset;
1169                        seg.offset = begin;
1170                        seg.count = end - begin;
1171                        return seg;
1172                    }
1173
1174                    /**
1175                     * Return the AttributeSet for a given character at a given index
1176                     *
1177                     * @param i the zero-based index into the text 
1178                     * @return the AttributeSet of the character
1179                     */
1180                    public AttributeSet getCharacterAttribute(int i) {
1181                        if (model instanceof  StyledDocument) {
1182                            StyledDocument doc = (StyledDocument) model;
1183                            Element elem = doc.getCharacterElement(i);
1184                            if (elem != null) {
1185                                return elem.getAttributes();
1186                            }
1187                        }
1188                        return null;
1189                    }
1190
1191                    /**
1192                     * Returns the start offset within the selected text.
1193                     * If there is no selection, but there is
1194                     * a caret, the start and end offsets will be the same.
1195                     *
1196                     * @return the index into the text of the start of the selection
1197                     */
1198                    public int getSelectionStart() {
1199                        return editor.getSelectionStart();
1200                    }
1201
1202                    /**
1203                     * Returns the end offset within the selected text.
1204                     * If there is no selection, but there is
1205                     * a caret, the start and end offsets will be the same.
1206                     *
1207                     * @return the index into teh text of the end of the selection
1208                     */
1209                    public int getSelectionEnd() {
1210                        return editor.getSelectionEnd();
1211                    }
1212
1213                    /**
1214                     * Returns the portion of the text that is selected. 
1215                     *
1216                     * @return the String portion of the text that is selected
1217                     */
1218                    public String getSelectedText() {
1219                        return editor.getSelectedText();
1220                    }
1221
1222                    /*
1223                     * Returns the text substring starting at the specified
1224                     * offset with the specified length.
1225                     */
1226                    private String getText(int offset, int length)
1227                            throws BadLocationException {
1228
1229                        if (model != null && model instanceof  StyledDocument) {
1230                            StyledDocument doc = (StyledDocument) model;
1231                            return model.getText(offset, length);
1232                        } else {
1233                            return null;
1234                        }
1235                    }
1236                }
1237            }
1238
1239            /*
1240             * ElementInfo for images
1241             */
1242            private class IconElementInfo extends ElementInfo implements 
1243                    Accessible {
1244
1245                private int width = -1;
1246                private int height = -1;
1247
1248                IconElementInfo(Element element, ElementInfo parent) {
1249                    super (element, parent);
1250                }
1251
1252                protected void invalidate(boolean first) {
1253                    super .invalidate(first);
1254                    width = height = -1;
1255                }
1256
1257                private int getImageSize(Object key) {
1258                    if (validateIfNecessary()) {
1259                        int size = getIntAttr(getAttributes(), key, -1);
1260
1261                        if (size == -1) {
1262                            View v = getView();
1263
1264                            size = 0;
1265                            if (v instanceof  ImageView) {
1266                                Image img = ((ImageView) v).getImage();
1267                                if (img != null) {
1268                                    if (key == HTML.Attribute.WIDTH) {
1269                                        size = img.getWidth(null);
1270                                    } else {
1271                                        size = img.getHeight(null);
1272                                    }
1273                                }
1274                            }
1275                        }
1276                        return size;
1277                    }
1278                    return 0;
1279                }
1280
1281                // begin AccessibleIcon implementation ...
1282                private AccessibleContext accessibleContext;
1283
1284                public AccessibleContext getAccessibleContext() {
1285                    if (accessibleContext == null) {
1286                        accessibleContext = new IconAccessibleContext(this );
1287                    }
1288                    return accessibleContext;
1289                }
1290
1291                /*
1292                 * AccessibleContext for images
1293                 */
1294                protected class IconAccessibleContext extends
1295                        HTMLAccessibleContext implements  AccessibleIcon {
1296
1297                    public IconAccessibleContext(ElementInfo elementInfo) {
1298                        super (elementInfo);
1299                    }
1300
1301                    /**
1302                     * Gets the accessibleName property of this object.  The accessibleName
1303                     * property of an object is a localized String that designates the purpose
1304                     * of the object.  For example, the accessibleName property of a label
1305                     * or button might be the text of the label or button itself.  In the
1306                     * case of an object that doesn't display its name, the accessibleName
1307                     * should still be set.  For example, in the case of a text field used
1308                     * to enter the name of a city, the accessibleName for the en_US locale
1309                     * could be 'city.'
1310                     *
1311                     * @return the localized name of the object; null if this 
1312                     * object does not have a name
1313                     *
1314                     * @see #setAccessibleName
1315                     */
1316                    public String getAccessibleName() {
1317                        return getAccessibleIconDescription();
1318                    }
1319
1320                    /**
1321                     * Gets the accessibleDescription property of this object.  If this
1322                     * property isn't set, returns the content type of this
1323                     * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
1324                     *
1325                     * @return the localized description of the object; <code>null</code>
1326                     * 	if this object does not have a description
1327                     *
1328                     * @see #setAccessibleName
1329                     */
1330                    public String getAccessibleDescription() {
1331                        return editor.getContentType();
1332                    }
1333
1334                    /**
1335                     * Gets the role of this object.  The role of the object is the generic
1336                     * purpose or use of the class of this object.  For example, the role
1337                     * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in 
1338                     * AccessibleRole are provided so component developers can pick from
1339                     * a set of predefined roles.  This enables assistive technologies to
1340                     * provide a consistent interface to various tweaked subclasses of 
1341                     * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1342                     * that act like a push button) as well as distinguish between sublasses
1343                     * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1344                     * and AccessibleRole.RADIO_BUTTON for radio buttons).
1345                     * <p>Note that the AccessibleRole class is also extensible, so 
1346                     * custom component developers can define their own AccessibleRole's
1347                     * if the set of predefined roles is inadequate.
1348                     *
1349                     * @return an instance of AccessibleRole describing the role of the object
1350                     * @see AccessibleRole
1351                     */
1352                    public AccessibleRole getAccessibleRole() {
1353                        return AccessibleRole.ICON;
1354                    }
1355
1356                    public AccessibleIcon[] getAccessibleIcon() {
1357                        AccessibleIcon[] icons = new AccessibleIcon[1];
1358                        icons[0] = this ;
1359                        return icons;
1360                    }
1361
1362                    /**
1363                     * Gets the description of the icon.  This is meant to be a brief
1364                     * textual description of the object.  For example, it might be
1365                     * presented to a blind user to give an indication of the purpose
1366                     * of the icon.
1367                     *
1368                     * @return the description of the icon
1369                     */
1370                    public String getAccessibleIconDescription() {
1371                        return ((ImageView) getView()).getAltText();
1372                    }
1373
1374                    /**
1375                     * Sets the description of the icon.  This is meant to be a brief
1376                     * textual description of the object.  For example, it might be
1377                     * presented to a blind user to give an indication of the purpose
1378                     * of the icon.
1379                     *
1380                     * @param description the description of the icon
1381                     */
1382                    public void setAccessibleIconDescription(String description) {
1383                    }
1384
1385                    /**
1386                     * Gets the width of the icon
1387                     *
1388                     * @return the width of the icon.
1389                     */
1390                    public int getAccessibleIconWidth() {
1391                        if (width == -1) {
1392                            width = getImageSize(HTML.Attribute.WIDTH);
1393                        }
1394                        return width;
1395                    }
1396
1397                    /**
1398                     * Gets the height of the icon
1399                     *
1400                     * @return the height of the icon.
1401                     */
1402                    public int getAccessibleIconHeight() {
1403                        if (height == -1) {
1404                            height = getImageSize(HTML.Attribute.HEIGHT);
1405                        }
1406                        return height;
1407                    }
1408                }
1409                // ... end AccessibleIconImplementation
1410            }
1411
1412            /**
1413             * TableElementInfo encapsulates information about a HTML.Tag.TABLE.
1414             * To make access fast it crates a grid containing the children to
1415             * allow for access by row, column. TableElementInfo will contain
1416             * TableRowElementInfos, which will contain TableCellElementInfos.
1417             * Any time one of the rows or columns becomes invalid the table is
1418             * invalidated.  This is because any time one of the child attributes
1419             * changes the size of the grid may have changed.
1420             */
1421            private class TableElementInfo extends ElementInfo implements 
1422                    Accessible {
1423
1424                protected ElementInfo caption;
1425
1426                /**
1427                 * Allocation of the table by row x column. There may be holes (eg 
1428                 * nulls) depending upon the html, any cell that has a rowspan/colspan
1429                 * > 1 will be contained multiple times in the grid.
1430                 */
1431                private TableCellElementInfo[][] grid;
1432
1433                TableElementInfo(Element e, ElementInfo parent) {
1434                    super (e, parent);
1435                }
1436
1437                public ElementInfo getCaptionInfo() {
1438                    return caption;
1439                }
1440
1441                /**
1442                 * Overriden to update the grid when validating.
1443                 */
1444                protected void validate() {
1445                    super .validate();
1446                    updateGrid();
1447                }
1448
1449                /**
1450                 * Overriden to only alloc instances of TableRowElementInfos.
1451                 */
1452                protected void loadChildren(Element e) {
1453
1454                    for (int counter = 0; counter < e.getElementCount(); counter++) {
1455                        Element child = e.getElement(counter);
1456                        AttributeSet attrs = child.getAttributes();
1457
1458                        if (attrs.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.TR) {
1459                            addChild(new TableRowElementInfo(child, this ,
1460                                    counter));
1461
1462                        } else if (attrs
1463                                .getAttribute(StyleConstants.NameAttribute) == HTML.Tag.CAPTION) {
1464                            // Handle captions as a special case since all other
1465                            // children are table rows.
1466                            caption = createElementInfo(child, this );
1467                        }
1468                    }
1469                }
1470
1471                /**
1472                 * Updates the grid.
1473                 */
1474                private void updateGrid() {
1475                    // Determine the max row/col count.
1476                    int delta = 0;
1477                    int maxCols = 0;
1478                    int rows = 0;
1479                    for (int counter = 0; counter < getChildCount(); counter++) {
1480                        TableRowElementInfo row = getRow(counter);
1481                        int prev = 0;
1482                        for (int y = 0; y < delta; y++) {
1483                            prev = Math.max(prev, getRow(counter - y - 1)
1484                                    .getColumnCount(y + 2));
1485                        }
1486                        delta = Math.max(row.getRowCount(), delta);
1487                        delta--;
1488                        maxCols = Math
1489                                .max(maxCols, row.getColumnCount() + prev);
1490                    }
1491                    rows = getChildCount() + delta;
1492
1493                    // Alloc
1494                    grid = new TableCellElementInfo[rows][];
1495                    for (int counter = 0; counter < rows; counter++) {
1496                        grid[counter] = new TableCellElementInfo[maxCols];
1497                    }
1498                    // Update
1499                    for (int counter = 0; counter < rows; counter++) {
1500                        getRow(counter).updateGrid(counter);
1501                    }
1502                }
1503
1504                /**
1505                 * Returns the TableCellElementInfo at the specified index.
1506                 */
1507                public TableRowElementInfo getRow(int index) {
1508                    return (TableRowElementInfo) getChild(index);
1509                }
1510
1511                /**
1512                 * Returns the TableCellElementInfo by row and column.
1513                 */
1514                public TableCellElementInfo getCell(int r, int c) {
1515                    if (validateIfNecessary() && r < grid.length
1516                            && c < grid[0].length) {
1517                        return grid[r][c];
1518                    }
1519                    return null;
1520                }
1521
1522                /**
1523                 * Returns the rowspan of the specified entry.
1524                 */
1525                public int getRowExtentAt(int r, int c) {
1526                    TableCellElementInfo cell = getCell(r, c);
1527
1528                    if (cell != null) {
1529                        int rows = cell.getRowCount();
1530                        int delta = 1;
1531
1532                        while ((r - delta) >= 0 && grid[r - delta][c] == cell) {
1533                            delta++;
1534                        }
1535                        return rows - delta + 1;
1536                    }
1537                    return 0;
1538                }
1539
1540                /**
1541                 * Returns the colspan of the specified entry.
1542                 */
1543                public int getColumnExtentAt(int r, int c) {
1544                    TableCellElementInfo cell = getCell(r, c);
1545
1546                    if (cell != null) {
1547                        int cols = cell.getColumnCount();
1548                        int delta = 1;
1549
1550                        while ((c - delta) >= 0 && grid[r][c - delta] == cell) {
1551                            delta++;
1552                        }
1553                        return cols - delta + 1;
1554                    }
1555                    return 0;
1556                }
1557
1558                /**
1559                 * Returns the number of rows in the table.
1560                 */
1561                public int getRowCount() {
1562                    if (validateIfNecessary()) {
1563                        return grid.length;
1564                    }
1565                    return 0;
1566                }
1567
1568                /**
1569                 * Returns the number of columns in the table.
1570                 */
1571                public int getColumnCount() {
1572                    if (validateIfNecessary() && grid.length > 0) {
1573                        return grid[0].length;
1574                    }
1575                    return 0;
1576                }
1577
1578                // begin AccessibleTable implementation ...
1579                private AccessibleContext accessibleContext;
1580
1581                public AccessibleContext getAccessibleContext() {
1582                    if (accessibleContext == null) {
1583                        accessibleContext = new TableAccessibleContext(this );
1584                    }
1585                    return accessibleContext;
1586                }
1587
1588                /*
1589                 * AccessibleContext for tables
1590                 */
1591                public class TableAccessibleContext extends
1592                        HTMLAccessibleContext implements  AccessibleTable {
1593
1594                    private AccessibleHeadersTable rowHeadersTable;
1595
1596                    public TableAccessibleContext(ElementInfo elementInfo) {
1597                        super (elementInfo);
1598                    }
1599
1600                    /**
1601                     * Gets the accessibleName property of this object.  The accessibleName
1602                     * property of an object is a localized String that designates the purpose
1603                     * of the object.  For example, the accessibleName property of a label
1604                     * or button might be the text of the label or button itself.  In the
1605                     * case of an object that doesn't display its name, the accessibleName
1606                     * should still be set.  For example, in the case of a text field used
1607                     * to enter the name of a city, the accessibleName for the en_US locale
1608                     * could be 'city.'
1609                     *
1610                     * @return the localized name of the object; null if this 
1611                     * object does not have a name
1612                     *
1613                     * @see #setAccessibleName
1614                     */
1615                    public String getAccessibleName() {
1616                        // return the role of the object
1617                        return getAccessibleRole().toString();
1618                    }
1619
1620                    /**
1621                     * Gets the accessibleDescription property of this object.  If this
1622                     * property isn't set, returns the content type of this
1623                     * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
1624                     *
1625                     * @return the localized description of the object; <code>null</code>
1626                     * 	if this object does not have a description
1627                     *
1628                     * @see #setAccessibleName
1629                     */
1630                    public String getAccessibleDescription() {
1631                        return editor.getContentType();
1632                    }
1633
1634                    /**
1635                     * Gets the role of this object.  The role of the object is the generic
1636                     * purpose or use of the class of this object.  For example, the role
1637                     * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in 
1638                     * AccessibleRole are provided so component developers can pick from
1639                     * a set of predefined roles.  This enables assistive technologies to
1640                     * provide a consistent interface to various tweaked subclasses of 
1641                     * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1642                     * that act like a push button) as well as distinguish between sublasses
1643                     * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1644                     * and AccessibleRole.RADIO_BUTTON for radio buttons).
1645                     * <p>Note that the AccessibleRole class is also extensible, so 
1646                     * custom component developers can define their own AccessibleRole's
1647                     * if the set of predefined roles is inadequate.
1648                     *
1649                     * @return an instance of AccessibleRole describing the role of the object
1650                     * @see AccessibleRole
1651                     */
1652                    public AccessibleRole getAccessibleRole() {
1653                        return AccessibleRole.TABLE;
1654                    }
1655
1656                    /**
1657                     * Gets the 0-based index of this object in its accessible parent.
1658                     *
1659                     * @return the 0-based index of this object in its parent; -1 if this 
1660                     * object does not have an accessible parent.
1661                     *
1662                     * @see #getAccessibleParent 
1663                     * @see #getAccessibleChildrenCount
1664                     * @gsee #getAccessibleChild
1665                     */
1666                    public int getAccessibleIndexInParent() {
1667                        return elementInfo.getIndexInParent();
1668                    }
1669
1670                    /**
1671                     * Returns the number of accessible children of the object.
1672                     *
1673                     * @return the number of accessible children of the object.
1674                     */
1675                    public int getAccessibleChildrenCount() {
1676                        return ((TableElementInfo) elementInfo).getRowCount()
1677                                * ((TableElementInfo) elementInfo)
1678                                        .getColumnCount();
1679                    }
1680
1681                    /**
1682                     * Returns the specified Accessible child of the object.  The Accessible
1683                     * children of an Accessible object are zero-based, so the first child 
1684                     * of an Accessible child is at index 0, the second child is at index 1,
1685                     * and so on.
1686                     *
1687                     * @param i zero-based index of child
1688                     * @return the Accessible child of the object
1689                     * @see #getAccessibleChildrenCount
1690                     */
1691                    public Accessible getAccessibleChild(int i) {
1692                        int rowCount = ((TableElementInfo) elementInfo)
1693                                .getRowCount();
1694                        int columnCount = ((TableElementInfo) elementInfo)
1695                                .getColumnCount();
1696                        int r = i / rowCount;
1697                        int c = i % columnCount;
1698                        if (r < 0 || r >= rowCount || c < 0 || c >= columnCount) {
1699                            return null;
1700                        } else {
1701                            return getAccessibleAt(r, c);
1702                        }
1703                    }
1704
1705                    public AccessibleTable getAccessibleTable() {
1706                        return this ;
1707                    }
1708
1709                    /**
1710                     * Returns the caption for the table.
1711                     *
1712                     * @return the caption for the table
1713                     */
1714                    public Accessible getAccessibleCaption() {
1715                        ElementInfo captionInfo = getCaptionInfo();
1716                        if (captionInfo instanceof  Accessible) {
1717                            return (Accessible) caption;
1718                        } else {
1719                            return null;
1720                        }
1721                    }
1722
1723                    /**
1724                     * Sets the caption for the table.
1725                     *
1726                     * @param a the caption for the table
1727                     */
1728                    public void setAccessibleCaption(Accessible a) {
1729                    }
1730
1731                    /**
1732                     * Returns the summary description of the table.
1733                     * 
1734                     * @return the summary description of the table
1735                     */
1736                    public Accessible getAccessibleSummary() {
1737                        return null;
1738                    }
1739
1740                    /**
1741                     * Sets the summary description of the table
1742                     *
1743                     * @param a the summary description of the table
1744                     */
1745                    public void setAccessibleSummary(Accessible a) {
1746                    }
1747
1748                    /**
1749                     * Returns the number of rows in the table.
1750                     *
1751                     * @return the number of rows in the table
1752                     */
1753                    public int getAccessibleRowCount() {
1754                        return ((TableElementInfo) elementInfo).getRowCount();
1755                    }
1756
1757                    /**
1758                     * Returns the number of columns in the table.
1759                     *
1760                     * @return the number of columns in the table
1761                     */
1762                    public int getAccessibleColumnCount() {
1763                        return ((TableElementInfo) elementInfo)
1764                                .getColumnCount();
1765                    }
1766
1767                    /**
1768                     * Returns the Accessible at a specified row and column
1769                     * in the table.
1770                     *
1771                     * @param r zero-based row of the table
1772                     * @param c zero-based column of the table
1773                     * @return the Accessible at the specified row and column
1774                     */
1775                    public Accessible getAccessibleAt(int r, int c) {
1776                        TableCellElementInfo cellInfo = getCell(r, c);
1777                        if (cellInfo != null) {
1778                            return cellInfo.getAccessible();
1779                        } else {
1780                            return null;
1781                        }
1782                    }
1783
1784                    /**
1785                     * Returns the number of rows occupied by the Accessible at
1786                     * a specified row and column in the table.
1787                     *
1788                     * @return the number of rows occupied by the Accessible at a
1789                     * given specified (row, column)
1790                     */
1791                    public int getAccessibleRowExtentAt(int r, int c) {
1792                        return ((TableElementInfo) elementInfo).getRowExtentAt(
1793                                r, c);
1794                    }
1795
1796                    /**
1797                     * Returns the number of columns occupied by the Accessible at
1798                     * a specified row and column in the table.
1799                     *
1800                     * @return the number of columns occupied by the Accessible at a
1801                     * given specified row and column
1802                     */
1803                    public int getAccessibleColumnExtentAt(int r, int c) {
1804                        return ((TableElementInfo) elementInfo)
1805                                .getColumnExtentAt(r, c);
1806                    }
1807
1808                    /**
1809                     * Returns the row headers as an AccessibleTable.
1810                     *
1811                     * @return an AccessibleTable representing the row
1812                     * headers
1813                     */
1814                    public AccessibleTable getAccessibleRowHeader() {
1815                        return rowHeadersTable;
1816                    }
1817
1818                    /**
1819                     * Sets the row headers.
1820                     *
1821                     * @param table an AccessibleTable representing the
1822                     * row headers
1823                     */
1824                    public void setAccessibleRowHeader(AccessibleTable table) {
1825                    }
1826
1827                    /**
1828                     * Returns the column headers as an AccessibleTable.
1829                     *
1830                     * @return an AccessibleTable representing the column
1831                     * headers
1832                     */
1833                    public AccessibleTable getAccessibleColumnHeader() {
1834                        return null;
1835                    }
1836
1837                    /**
1838                     * Sets the column headers.
1839                     *
1840                     * @param table an AccessibleTable representing the
1841                     * column headers
1842                     */
1843                    public void setAccessibleColumnHeader(AccessibleTable table) {
1844                    }
1845
1846                    /**
1847                     * Returns the description of the specified row in the table.
1848                     *
1849                     * @param r zero-based row of the table
1850                     * @return the description of the row
1851                     */
1852                    public Accessible getAccessibleRowDescription(int r) {
1853                        return null;
1854                    }
1855
1856                    /**
1857                     * Sets the description text of the specified row of the table.
1858                     *
1859                     * @param r zero-based row of the table
1860                     * @param a the description of the row
1861                     */
1862                    public void setAccessibleRowDescription(int r, Accessible a) {
1863                    }
1864
1865                    /**
1866                     * Returns the description text of the specified column in the table.
1867                     *
1868                     * @param c zero-based column of the table
1869                     * @return the text description of the column
1870                     */
1871                    public Accessible getAccessibleColumnDescription(int c) {
1872                        return null;
1873                    }
1874
1875                    /**
1876                     * Sets the description text of the specified column in the table.
1877                     *
1878                     * @param c zero-based column of the table
1879                     * @param a the text description of the column
1880                     */
1881                    public void setAccessibleColumnDescription(int c,
1882                            Accessible a) {
1883                    }
1884
1885                    /**
1886                     * Returns a boolean value indicating whether the accessible at
1887                     * a specified row and column is selected.
1888                     *
1889                     * @param r zero-based row of the table
1890                     * @param c zero-based column of the table
1891                     * @return the boolean value true if the accessible at the
1892                     * row and column is selected. Otherwise, the boolean value 
1893                     * false
1894                     */
1895                    public boolean isAccessibleSelected(int r, int c) {
1896                        if (validateIfNecessary()) {
1897                            if (r < 0 || r >= getAccessibleRowCount() || c < 0
1898                                    || c >= getAccessibleColumnCount()) {
1899                                return false;
1900                            }
1901                            TableCellElementInfo cell = getCell(r, c);
1902                            if (cell != null) {
1903                                Element elem = cell.getElement();
1904                                int start = elem.getStartOffset();
1905                                int end = elem.getEndOffset();
1906                                return start >= editor.getSelectionStart()
1907                                        && end <= editor.getSelectionEnd();
1908                            }
1909                        }
1910                        return false;
1911                    }
1912
1913                    /**
1914                     * Returns a boolean value indicating whether the specified row
1915                     * is selected.
1916                     *
1917                     * @param r zero-based row of the table
1918                     * @return the boolean value true if the specified row is selected.
1919                     * Otherwise, false.
1920                     */
1921                    public boolean isAccessibleRowSelected(int r) {
1922                        if (validateIfNecessary()) {
1923                            if (r < 0 || r >= getAccessibleRowCount()) {
1924                                return false;
1925                            }
1926                            int nColumns = getAccessibleColumnCount();
1927
1928                            TableCellElementInfo startCell = getCell(r, 0);
1929                            if (startCell == null) {
1930                                return false;
1931                            }
1932                            int start = startCell.getElement().getStartOffset();
1933
1934                            TableCellElementInfo endCell = getCell(r,
1935                                    nColumns - 1);
1936                            if (endCell == null) {
1937                                return false;
1938                            }
1939                            int end = endCell.getElement().getEndOffset();
1940
1941                            return start >= editor.getSelectionStart()
1942                                    && end <= editor.getSelectionEnd();
1943                        }
1944                        return false;
1945                    }
1946
1947                    /**
1948                     * Returns a boolean value indicating whether the specified column
1949                     * is selected.
1950                     *
1951                     * @param r zero-based column of the table
1952                     * @return the boolean value true if the specified column is selected.
1953                     * Otherwise, false.
1954                     */
1955                    public boolean isAccessibleColumnSelected(int c) {
1956                        if (validateIfNecessary()) {
1957                            if (c < 0 || c >= getAccessibleColumnCount()) {
1958                                return false;
1959                            }
1960                            int nRows = getAccessibleRowCount();
1961
1962                            TableCellElementInfo startCell = getCell(0, c);
1963                            if (startCell == null) {
1964                                return false;
1965                            }
1966                            int start = startCell.getElement().getStartOffset();
1967
1968                            TableCellElementInfo endCell = getCell(nRows - 1, c);
1969                            if (endCell == null) {
1970                                return false;
1971                            }
1972                            int end = endCell.getElement().getEndOffset();
1973                            return start >= editor.getSelectionStart()
1974                                    && end <= editor.getSelectionEnd();
1975                        }
1976                        return false;
1977                    }
1978
1979                    /**
1980                     * Returns the selected rows in a table.
1981                     *
1982                     * @return an array of selected rows where each element is a
1983                     * zero-based row of the table
1984                     */
1985                    public int[] getSelectedAccessibleRows() {
1986                        if (validateIfNecessary()) {
1987                            int nRows = getAccessibleRowCount();
1988                            Vector vec = new Vector();
1989
1990                            for (int i = 0; i < nRows; i++) {
1991                                if (isAccessibleRowSelected(i)) {
1992                                    vec.addElement(new Integer(i));
1993                                }
1994                            }
1995                            int retval[] = new int[vec.size()];
1996                            for (int i = 0; i < retval.length; i++) {
1997                                retval[i] = ((Integer) vec.elementAt(i))
1998                                        .intValue();
1999                            }
2000                            return retval;
2001                        }
2002                        return new int[0];
2003                    }
2004
2005                    /**
2006                     * Returns the selected columns in a table.
2007                     *
2008                     * @return an array of selected columns where each element is a
2009                     * zero-based column of the table
2010                     */
2011                    public int[] getSelectedAccessibleColumns() {
2012                        if (validateIfNecessary()) {
2013                            int nColumns = getAccessibleRowCount();
2014                            Vector vec = new Vector();
2015
2016                            for (int i = 0; i < nColumns; i++) {
2017                                if (isAccessibleColumnSelected(i)) {
2018                                    vec.addElement(new Integer(i));
2019                                }
2020                            }
2021                            int retval[] = new int[vec.size()];
2022                            for (int i = 0; i < retval.length; i++) {
2023                                retval[i] = ((Integer) vec.elementAt(i))
2024                                        .intValue();
2025                            }
2026                            return retval;
2027                        }
2028                        return new int[0];
2029                    }
2030
2031                    // begin AccessibleExtendedTable implementation -------------
2032
2033                    /**
2034                     * Returns the row number of an index in the table.
2035                     *
2036                     * @param index the zero-based index in the table
2037                     * @return the zero-based row of the table if one exists;
2038                     * otherwise -1.
2039                     */
2040                    public int getAccessibleRow(int index) {
2041                        if (validateIfNecessary()) {
2042                            int numCells = getAccessibleColumnCount()
2043                                    * getAccessibleRowCount();
2044                            if (index >= numCells) {
2045                                return -1;
2046                            } else {
2047                                return index / getAccessibleColumnCount();
2048                            }
2049                        }
2050                        return -1;
2051                    }
2052
2053                    /**
2054                     * Returns the column number of an index in the table.
2055                     *
2056                     * @param index the zero-based index in the table
2057                     * @return the zero-based column of the table if one exists;
2058                     * otherwise -1.
2059                     */
2060                    public int getAccessibleColumn(int index) {
2061                        if (validateIfNecessary()) {
2062                            int numCells = getAccessibleColumnCount()
2063                                    * getAccessibleRowCount();
2064                            if (index >= numCells) {
2065                                return -1;
2066                            } else {
2067                                return index % getAccessibleColumnCount();
2068                            }
2069                        }
2070                        return -1;
2071                    }
2072
2073                    /**
2074                     * Returns the index at a row and column in the table.
2075                     *
2076                     * @param r zero-based row of the table
2077                     * @param c zero-based column of the table
2078                     * @return the zero-based index in the table if one exists;
2079                     * otherwise -1.
2080                     */
2081                    public int getAccessibleIndex(int r, int c) {
2082                        if (validateIfNecessary()) {
2083                            if (r >= getAccessibleRowCount()
2084                                    || c >= getAccessibleColumnCount()) {
2085                                return -1;
2086                            } else {
2087                                return r * getAccessibleColumnCount() + c;
2088                            }
2089                        }
2090                        return -1;
2091                    }
2092
2093                    /**
2094                     * Returns the row header at a row in a table.
2095                     * @param r zero-based row of the table
2096                     *
2097                     * @return a String representing the row header
2098                     * if one exists; otherwise null.
2099                     */
2100                    public String getAccessibleRowHeader(int r) {
2101                        if (validateIfNecessary()) {
2102                            TableCellElementInfo cellInfo = getCell(r, 0);
2103                            if (cellInfo.isHeaderCell()) {
2104                                View v = cellInfo.getView();
2105                                if (v != null && model != null) {
2106                                    try {
2107                                        return model.getText(
2108                                                v.getStartOffset(), v
2109                                                        .getEndOffset()
2110                                                        - v.getStartOffset());
2111                                    } catch (BadLocationException e) {
2112                                        return null;
2113                                    }
2114                                }
2115                            }
2116                        }
2117                        return null;
2118                    }
2119
2120                    /**
2121                     * Returns the column header at a column in a table.
2122                     * @param c zero-based column of the table
2123                     *
2124                     * @return a String representing the column header
2125                     * if one exists; otherwise null.
2126                     */
2127                    public String getAccessibleColumnHeader(int c) {
2128                        if (validateIfNecessary()) {
2129                            TableCellElementInfo cellInfo = getCell(0, c);
2130                            if (cellInfo.isHeaderCell()) {
2131                                View v = cellInfo.getView();
2132                                if (v != null && model != null) {
2133                                    try {
2134                                        return model.getText(
2135                                                v.getStartOffset(), v
2136                                                        .getEndOffset()
2137                                                        - v.getStartOffset());
2138                                    } catch (BadLocationException e) {
2139                                        return null;
2140                                    }
2141                                }
2142                            }
2143                        }
2144                        return null;
2145                    }
2146
2147                    public void addRowHeader(TableCellElementInfo cellInfo,
2148                            int rowNumber) {
2149                        if (rowHeadersTable == null) {
2150                            rowHeadersTable = new AccessibleHeadersTable();
2151                        }
2152                        rowHeadersTable.addHeader(cellInfo, rowNumber);
2153                    }
2154
2155                    // end of AccessibleExtendedTable implementation ------------
2156
2157                    protected class AccessibleHeadersTable implements 
2158                            AccessibleTable {
2159
2160                        // Header information is modeled as a Hashtable of
2161                        // ArrayLists where each Hashtable entry represents
2162                        // a row containing one or more headers.
2163                        private Hashtable headers = new Hashtable();
2164                        private int rowCount = 0;
2165                        private int columnCount = 0;
2166
2167                        public void addHeader(TableCellElementInfo cellInfo,
2168                                int rowNumber) {
2169                            Integer rowInteger = new Integer(rowNumber);
2170                            ArrayList list = (ArrayList) headers
2171                                    .get(rowInteger);
2172                            if (list == null) {
2173                                list = new ArrayList();
2174                                headers.put(rowInteger, list);
2175                            }
2176                            list.add(cellInfo);
2177                        }
2178
2179                        /**
2180                         * Returns the caption for the table.
2181                         *
2182                         * @return the caption for the table
2183                         */
2184                        public Accessible getAccessibleCaption() {
2185                            return null;
2186                        }
2187
2188                        /**
2189                         * Sets the caption for the table.
2190                         *
2191                         * @param a the caption for the table
2192                         */
2193                        public void setAccessibleCaption(Accessible a) {
2194                        }
2195
2196                        /**
2197                         * Returns the summary description of the table.
2198                         * 
2199                         * @return the summary description of the table
2200                         */
2201                        public Accessible getAccessibleSummary() {
2202                            return null;
2203                        }
2204
2205                        /**
2206                         * Sets the summary description of the table
2207                         *
2208                         * @param a the summary description of the table
2209                         */
2210                        public void setAccessibleSummary(Accessible a) {
2211                        }
2212
2213                        /**
2214                         * Returns the number of rows in the table.
2215                         *
2216                         * @return the number of rows in the table
2217                         */
2218                        public int getAccessibleRowCount() {
2219                            return rowCount;
2220                        }
2221
2222                        /**
2223                         * Returns the number of columns in the table.
2224                         *
2225                         * @return the number of columns in the table
2226                         */
2227                        public int getAccessibleColumnCount() {
2228                            return columnCount;
2229                        }
2230
2231                        private TableCellElementInfo getElementInfoAt(int r,
2232                                int c) {
2233                            ArrayList list = (ArrayList) headers
2234                                    .get(new Integer(r));
2235                            if (list != null) {
2236                                return (TableCellElementInfo) list.get(c);
2237                            } else {
2238                                return null;
2239                            }
2240                        }
2241
2242                        /**
2243                         * Returns the Accessible at a specified row and column
2244                         * in the table.
2245                         *
2246                         * @param r zero-based row of the table
2247                         * @param c zero-based column of the table
2248                         * @return the Accessible at the specified row and column
2249                         */
2250                        public Accessible getAccessibleAt(int r, int c) {
2251                            ElementInfo elementInfo = getElementInfoAt(r, c);
2252                            if (elementInfo instanceof  Accessible) {
2253                                return (Accessible) elementInfo;
2254                            } else {
2255                                return null;
2256                            }
2257                        }
2258
2259                        /**
2260                         * Returns the number of rows occupied by the Accessible at
2261                         * a specified row and column in the table.
2262                         *
2263                         * @return the number of rows occupied by the Accessible at a
2264                         * given specified (row, column)
2265                         */
2266                        public int getAccessibleRowExtentAt(int r, int c) {
2267                            TableCellElementInfo elementInfo = getElementInfoAt(
2268                                    r, c);
2269                            if (elementInfo != null) {
2270                                return elementInfo.getRowCount();
2271                            } else {
2272                                return 0;
2273                            }
2274                        }
2275
2276                        /**
2277                         * Returns the number of columns occupied by the Accessible at
2278                         * a specified row and column in the table.
2279                         *
2280                         * @return the number of columns occupied by the Accessible at a
2281                         * given specified row and column
2282                         */
2283                        public int getAccessibleColumnExtentAt(int r, int c) {
2284                            TableCellElementInfo elementInfo = getElementInfoAt(
2285                                    r, c);
2286                            if (elementInfo != null) {
2287                                return elementInfo.getRowCount();
2288                            } else {
2289                                return 0;
2290                            }
2291                        }
2292
2293                        /**
2294                         * Returns the row headers as an AccessibleTable.
2295                         *
2296                         * @return an AccessibleTable representing the row
2297                         * headers
2298                         */
2299                        public AccessibleTable getAccessibleRowHeader() {
2300                            return null;
2301                        }
2302
2303                        /**
2304                         * Sets the row headers.
2305                         *
2306                         * @param table an AccessibleTable representing the
2307                         * row headers
2308                         */
2309                        public void setAccessibleRowHeader(AccessibleTable table) {
2310                        }
2311
2312                        /**
2313                         * Returns the column headers as an AccessibleTable.
2314                         *
2315                         * @return an AccessibleTable representing the column
2316                         * headers
2317                         */
2318                        public AccessibleTable getAccessibleColumnHeader() {
2319                            return null;
2320                        }
2321
2322                        /**
2323                         * Sets the column headers.
2324                         *
2325                         * @param table an AccessibleTable representing the
2326                         * column headers
2327                         */
2328                        public void setAccessibleColumnHeader(
2329                                AccessibleTable table) {
2330                        }
2331
2332                        /**
2333                         * Returns the description of the specified row in the table.
2334                         *
2335                         * @param r zero-based row of the table
2336                         * @return the description of the row
2337                         */
2338                        public Accessible getAccessibleRowDescription(int r) {
2339                            return null;
2340                        }
2341
2342                        /**
2343                         * Sets the description text of the specified row of the table.
2344                         *
2345                         * @param r zero-based row of the table
2346                         * @param a the description of the row
2347                         */
2348                        public void setAccessibleRowDescription(int r,
2349                                Accessible a) {
2350                        }
2351
2352                        /**
2353                         * Returns the description text of the specified column in the table.
2354                         *
2355                         * @param c zero-based column of the table
2356                         * @return the text description of the column
2357                         */
2358                        public Accessible getAccessibleColumnDescription(int c) {
2359                            return null;
2360                        }
2361
2362                        /**
2363                         * Sets the description text of the specified column in the table.
2364                         *
2365                         * @param c zero-based column of the table
2366                         * @param a the text description of the column
2367                         */
2368                        public void setAccessibleColumnDescription(int c,
2369                                Accessible a) {
2370                        }
2371
2372                        /**
2373                         * Returns a boolean value indicating whether the accessible at
2374                         * a specified row and column is selected.
2375                         *
2376                         * @param r zero-based row of the table
2377                         * @param c zero-based column of the table
2378                         * @return the boolean value true if the accessible at the
2379                         * row and column is selected. Otherwise, the boolean value 
2380                         * false
2381                         */
2382                        public boolean isAccessibleSelected(int r, int c) {
2383                            return false;
2384                        }
2385
2386                        /**
2387                         * Returns a boolean value indicating whether the specified row
2388                         * is selected.
2389                         *
2390                         * @param r zero-based row of the table
2391                         * @return the boolean value true if the specified row is selected.
2392                         * Otherwise, false.
2393                         */
2394                        public boolean isAccessibleRowSelected(int r) {
2395                            return false;
2396                        }
2397
2398                        /**
2399                         * Returns a boolean value indicating whether the specified column
2400                         * is selected.
2401                         *
2402                         * @param r zero-based column of the table
2403                         * @return the boolean value true if the specified column is selected.
2404                         * Otherwise, false.
2405                         */
2406                        public boolean isAccessibleColumnSelected(int c) {
2407                            return false;
2408                        }
2409
2410                        /**
2411                         * Returns the selected rows in a table.
2412                         *
2413                         * @return an array of selected rows where each element is a
2414                         * zero-based row of the table
2415                         */
2416                        public int[] getSelectedAccessibleRows() {
2417                            return new int[0];
2418                        }
2419
2420                        /**
2421                         * Returns the selected columns in a table.
2422                         *
2423                         * @return an array of selected columns where each element is a
2424                         * zero-based column of the table
2425                         */
2426                        public int[] getSelectedAccessibleColumns() {
2427                            return new int[0];
2428                        }
2429                    }
2430                } // ... end AccessibleHeadersTable
2431
2432                /*
2433                 * ElementInfo for table rows
2434                 */
2435                private class TableRowElementInfo extends ElementInfo {
2436
2437                    private TableElementInfo parent;
2438                    private int rowNumber;
2439
2440                    TableRowElementInfo(Element e, TableElementInfo parent,
2441                            int rowNumber) {
2442                        super (e, parent);
2443                        this .parent = parent;
2444                        this .rowNumber = rowNumber;
2445                    }
2446
2447                    protected void loadChildren(Element e) {
2448                        for (int x = 0; x < e.getElementCount(); x++) {
2449                            AttributeSet attrs = e.getElement(x)
2450                                    .getAttributes();
2451
2452                            if (attrs
2453                                    .getAttribute(StyleConstants.NameAttribute) == HTML.Tag.TH) {
2454                                TableCellElementInfo headerElementInfo = new TableCellElementInfo(
2455                                        e.getElement(x), this , true);
2456                                addChild(headerElementInfo);
2457
2458                                AccessibleTable at = parent
2459                                        .getAccessibleContext()
2460                                        .getAccessibleTable();
2461                                TableAccessibleContext tableElement = (TableAccessibleContext) at;
2462                                tableElement.addRowHeader(headerElementInfo,
2463                                        rowNumber);
2464
2465                            } else if (attrs
2466                                    .getAttribute(StyleConstants.NameAttribute) == HTML.Tag.TD) {
2467                                addChild(new TableCellElementInfo(e
2468                                        .getElement(x), this , false));
2469                            }
2470                        }
2471                    }
2472
2473                    /**
2474                     * Returns the max of the rowspans of the cells in this row.
2475                     */
2476                    public int getRowCount() {
2477                        int rowCount = 1;
2478                        if (validateIfNecessary()) {
2479                            for (int counter = 0; counter < getChildCount(); counter++) {
2480
2481                                TableCellElementInfo cell = (TableCellElementInfo) getChild(counter);
2482
2483                                if (cell.validateIfNecessary()) {
2484                                    rowCount = Math.max(rowCount, cell
2485                                            .getRowCount());
2486                                }
2487                            }
2488                        }
2489                        return rowCount;
2490                    }
2491
2492                    /**
2493                     * Returns the sum of the column spans of the individual
2494                     * cells in this row.
2495                     */
2496                    public int getColumnCount() {
2497                        int colCount = 0;
2498                        if (validateIfNecessary()) {
2499                            for (int counter = 0; counter < getChildCount(); counter++) {
2500                                TableCellElementInfo cell = (TableCellElementInfo) getChild(counter);
2501
2502                                if (cell.validateIfNecessary()) {
2503                                    colCount += cell.getColumnCount();
2504                                }
2505                            }
2506                        }
2507                        return colCount;
2508                    }
2509
2510                    /**
2511                     * Overriden to invalidate the table as well as
2512                     * TableRowElementInfo.
2513                     */
2514                    protected void invalidate(boolean first) {
2515                        super .invalidate(first);
2516                        getParent().invalidate(true);
2517                    }
2518
2519                    /**
2520                     * Places the TableCellElementInfos for this element in
2521                     * the grid.
2522                     */
2523                    private void updateGrid(int row) {
2524                        if (validateIfNecessary()) {
2525                            boolean emptyRow = false;
2526
2527                            while (!emptyRow) {
2528                                for (int counter = 0; counter < grid[row].length; counter++) {
2529                                    if (grid[row][counter] == null) {
2530                                        emptyRow = true;
2531                                        break;
2532                                    }
2533                                }
2534                                if (!emptyRow) {
2535                                    row++;
2536                                }
2537                            }
2538                            for (int col = 0, counter = 0; counter < getChildCount(); counter++) {
2539                                TableCellElementInfo cell = (TableCellElementInfo) getChild(counter);
2540
2541                                while (grid[row][col] != null) {
2542                                    col++;
2543                                }
2544                                for (int rowCount = cell.getRowCount() - 1; rowCount >= 0; rowCount--) {
2545                                    for (int colCount = cell.getColumnCount() - 1; colCount >= 0; colCount--) {
2546                                        grid[row + rowCount][col + colCount] = cell;
2547                                    }
2548                                }
2549                                col += cell.getColumnCount();
2550                            }
2551                        }
2552                    }
2553
2554                    /**
2555                     * Returns the column count of the number of columns that have
2556                     * a rowcount >= rowspan.
2557                     */
2558                    private int getColumnCount(int rowspan) {
2559                        if (validateIfNecessary()) {
2560                            int cols = 0;
2561                            for (int counter = 0; counter < getChildCount(); counter++) {
2562                                TableCellElementInfo cell = (TableCellElementInfo) getChild(counter);
2563
2564                                if (cell.getRowCount() >= rowspan) {
2565                                    cols += cell.getColumnCount();
2566                                }
2567                            }
2568                            return cols;
2569                        }
2570                        return 0;
2571                    }
2572                }
2573
2574                /**
2575                 * TableCellElementInfo is used to represents the cells of
2576                 * the table.
2577                 */
2578                private class TableCellElementInfo extends ElementInfo {
2579
2580                    private Accessible accessible;
2581                    private boolean isHeaderCell;
2582
2583                    TableCellElementInfo(Element e, ElementInfo parent) {
2584                        super (e, parent);
2585                        this .isHeaderCell = false;
2586                    }
2587
2588                    TableCellElementInfo(Element e, ElementInfo parent,
2589                            boolean isHeaderCell) {
2590                        super (e, parent);
2591                        this .isHeaderCell = isHeaderCell;
2592                    }
2593
2594                    /*
2595                     * Returns whether this table cell is a header
2596                     */
2597                    public boolean isHeaderCell() {
2598                        return this .isHeaderCell;
2599                    }
2600
2601                    /*
2602                     * Returns the Accessible representing this table cell
2603                     */
2604                    public Accessible getAccessible() {
2605                        accessible = null;
2606                        getAccessible(this );
2607                        return accessible;
2608                    }
2609
2610                    /*
2611                     * Gets the outermost Accessible in the table cell
2612                     */
2613                    private void getAccessible(ElementInfo elementInfo) {
2614                        if (elementInfo instanceof  Accessible) {
2615                            accessible = (Accessible) elementInfo;
2616                            return;
2617                        } else {
2618                            for (int i = 0; i < elementInfo.getChildCount(); i++) {
2619                                getAccessible(elementInfo.getChild(i));
2620                            }
2621                        }
2622                    }
2623
2624                    /**
2625                     * Returns the rowspan attribute.
2626                     */
2627                    public int getRowCount() {
2628                        if (validateIfNecessary()) {
2629                            return Math.max(1, getIntAttr(getAttributes(),
2630                                    HTML.Attribute.ROWSPAN, 1));
2631                        }
2632                        return 0;
2633                    }
2634
2635                    /**
2636                     * Returns the colspan attribute.
2637                     */
2638                    public int getColumnCount() {
2639                        if (validateIfNecessary()) {
2640                            return Math.max(1, getIntAttr(getAttributes(),
2641                                    HTML.Attribute.COLSPAN, 1));
2642                        }
2643                        return 0;
2644                    }
2645
2646                    /**
2647                     * Overriden to invalidate the TableRowElementInfo as well as
2648                     * the TableCellElementInfo.
2649                     */
2650                    protected void invalidate(boolean first) {
2651                        super .invalidate(first);
2652                        getParent().invalidate(true);
2653                    }
2654                }
2655            }
2656
2657            /**
2658             * ElementInfo provides a slim down view of an Element.  Each ElementInfo
2659             * can have any number of child ElementInfos that are not necessarily
2660             * direct children of the Element. As the Document changes various 
2661             * ElementInfos become invalidated. Before accessing a particular portion
2662             * of an ElementInfo you should make sure it is valid by invoking
2663             * <code>validateIfNecessary</code>, this will return true if
2664             * successful, on the other hand a false return value indicates the
2665             * ElementInfo is not valid and can never become valid again (usually
2666             * the result of the Element the ElementInfo encapsulates being removed).
2667             */
2668            private class ElementInfo {
2669
2670                /**
2671                 * The children of this ElementInfo.
2672                 */
2673                private ArrayList children;
2674                /**
2675                 * The Element this ElementInfo is providing information for.
2676                 */
2677                private Element element;
2678                /**
2679                 * The parent ElementInfo, will be null for the root.
2680                 */
2681                private ElementInfo parent;
2682                /**
2683                 * Indicates the validity of the ElementInfo.
2684                 */
2685                private boolean isValid;
2686                /**
2687                 * Indicates if the ElementInfo can become valid.
2688                 */
2689                private boolean canBeValid;
2690
2691                /**
2692                 * Creates the root ElementInfo.
2693                 */
2694                ElementInfo(Element element) {
2695                    this (element, null);
2696                }
2697
2698                /**
2699                 * Creates an ElementInfo representing <code>element</code> with
2700                 * the specified parent.
2701                 */
2702                ElementInfo(Element element, ElementInfo parent) {
2703                    this .element = element;
2704                    this .parent = parent;
2705                    isValid = false;
2706                    canBeValid = true;
2707                }
2708
2709                /**
2710                 * Validates the receiver. This recreates the children as well. This
2711                 * will be invoked within a <code>readLock</code>. If this is overriden
2712                 * it MUST invoke supers implementation first!
2713                 */
2714                protected void validate() {
2715                    isValid = true;
2716                    loadChildren(getElement());
2717                }
2718
2719                /**
2720                 * Recreates the direct children of <code>info</code>.
2721                 */
2722                protected void loadChildren(Element parent) {
2723                    if (!parent.isLeaf()) {
2724                        for (int counter = 0, maxCounter = parent
2725                                .getElementCount(); counter < maxCounter; counter++) {
2726                            Element e = parent.getElement(counter);
2727                            ElementInfo childInfo = createElementInfo(e, this );
2728
2729                            if (childInfo != null) {
2730                                addChild(childInfo);
2731                            } else {
2732                                loadChildren(e);
2733                            }
2734                        }
2735                    }
2736                }
2737
2738                /**
2739                 * Returns the index of the child in the parent, or -1 for the
2740                 * root or if the parent isn't valid.
2741                 */
2742                public int getIndexInParent() {
2743                    if (parent == null || !parent.isValid()) {
2744                        return -1;
2745                    }
2746                    return parent.indexOf(this );
2747                }
2748
2749                /**
2750                 * Returns the Element this <code>ElementInfo</code> represents.
2751                 */
2752                public Element getElement() {
2753                    return element;
2754                }
2755
2756                /**
2757                 * Returns the parent of this Element, or null for the root.
2758                 */
2759                public ElementInfo getParent() {
2760                    return parent;
2761                }
2762
2763                /**
2764                 * Returns the index of the specified child, or -1 if
2765                 * <code>child</code> isn't a valid child.
2766                 */
2767                public int indexOf(ElementInfo child) {
2768                    ArrayList children = this .children;
2769
2770                    if (children != null) {
2771                        return children.indexOf(child);
2772                    }
2773                    return -1;
2774                }
2775
2776                /**
2777                 * Returns the child ElementInfo at <code>index</code>, or null
2778                 * if <code>index</code> isn't a valid index.
2779                 */
2780                public ElementInfo getChild(int index) {
2781                    if (validateIfNecessary()) {
2782                        ArrayList children = this .children;
2783
2784                        if (children != null && index >= 0
2785                                && index < children.size()) {
2786                            return (ElementInfo) children.get(index);
2787                        }
2788                    }
2789                    return null;
2790                }
2791
2792                /**
2793                 * Returns the number of children the ElementInfo contains.
2794                 */
2795                public int getChildCount() {
2796                    validateIfNecessary();
2797                    return (children == null) ? 0 : children.size();
2798                }
2799
2800                /**
2801                 * Adds a new child to this ElementInfo.
2802                 */
2803                protected void addChild(ElementInfo child) {
2804                    if (children == null) {
2805                        children = new ArrayList();
2806                    }
2807                    children.add(child);
2808                }
2809
2810                /**
2811                 * Returns the View corresponding to this ElementInfo, or null
2812                 * if the ElementInfo can't be validated.
2813                 */
2814                protected View getView() {
2815                    if (!validateIfNecessary()) {
2816                        return null;
2817                    }
2818                    Object lock = lock();
2819                    try {
2820                        View rootView = getRootView();
2821                        Element e = getElement();
2822                        int start = e.getStartOffset();
2823
2824                        if (rootView != null) {
2825                            return getView(rootView, e, start);
2826                        }
2827                        return null;
2828                    } finally {
2829                        unlock(lock);
2830                    }
2831                }
2832
2833                /**
2834                 * Returns the Bounds for this ElementInfo, or null
2835                 * if the ElementInfo can't be validated.
2836                 */
2837                public Rectangle getBounds() {
2838                    if (!validateIfNecessary()) {
2839                        return null;
2840                    }
2841                    Object lock = lock();
2842                    try {
2843                        Rectangle bounds = getRootEditorRect();
2844                        View rootView = getRootView();
2845                        Element e = getElement();
2846
2847                        if (bounds != null && rootView != null) {
2848                            try {
2849                                return rootView.modelToView(e.getStartOffset(),
2850                                        Position.Bias.Forward,
2851                                        e.getEndOffset(),
2852                                        Position.Bias.Backward, bounds)
2853                                        .getBounds();
2854                            } catch (BadLocationException ble) {
2855                            }
2856                        }
2857                    } finally {
2858                        unlock(lock);
2859                    }
2860                    return null;
2861                }
2862
2863                /**
2864                 * Returns true if this ElementInfo is valid.
2865                 */
2866                protected boolean isValid() {
2867                    return isValid;
2868                }
2869
2870                /**
2871                 * Returns the AttributeSet associated with the Element, this will
2872                 * return null if the ElementInfo can't be validated.
2873                 */
2874                protected AttributeSet getAttributes() {
2875                    if (validateIfNecessary()) {
2876                        return getElement().getAttributes();
2877                    }
2878                    return null;
2879                }
2880
2881                /**
2882                 * Returns the AttributeSet associated with the View that is
2883                 * representing this Element, this will
2884                 * return null if the ElementInfo can't be validated.
2885                 */
2886                protected AttributeSet getViewAttributes() {
2887                    if (validateIfNecessary()) {
2888                        View view = getView();
2889
2890                        if (view != null) {
2891                            return view.getElement().getAttributes();
2892                        }
2893                        return getElement().getAttributes();
2894                    }
2895                    return null;
2896                }
2897
2898                /**
2899                 * Convenience method for getting an integer attribute from the passed
2900                 * in AttributeSet.
2901                 */
2902                protected int getIntAttr(AttributeSet attrs, Object key,
2903                        int deflt) {
2904                    if (attrs != null && attrs.isDefined(key)) {
2905                        int i;
2906                        String val = (String) attrs.getAttribute(key);
2907                        if (val == null) {
2908                            i = deflt;
2909                        } else {
2910                            try {
2911                                i = Math.max(0, Integer.parseInt(val));
2912                            } catch (NumberFormatException x) {
2913                                i = deflt;
2914                            }
2915                        }
2916                        return i;
2917                    }
2918                    return deflt;
2919                }
2920
2921                /**
2922                 * Validates the ElementInfo if necessary.  Some ElementInfos may
2923                 * never be valid again.  You should check <code>isValid</code> before
2924                 * using one.  This will reload the children and invoke
2925                 * <code>validate</code> if the ElementInfo is invalid and can become
2926                 * valid again. This will return true if the receiver is valid.
2927                 */
2928                protected boolean validateIfNecessary() {
2929                    if (!isValid() && canBeValid) {
2930                        children = null;
2931                        Object lock = lock();
2932
2933                        try {
2934                            validate();
2935                        } finally {
2936                            unlock(lock);
2937                        }
2938                    }
2939                    return isValid();
2940                }
2941
2942                /**
2943                 * Invalidates the ElementInfo. Subclasses should override this
2944                 * if they need to reset state once invalid.
2945                 */
2946                protected void invalidate(boolean first) {
2947                    if (!isValid()) {
2948                        if (canBeValid && !first) {
2949                            canBeValid = false;
2950                        }
2951                        return;
2952                    }
2953                    isValid = false;
2954                    canBeValid = first;
2955                    if (children != null) {
2956                        for (int counter = 0; counter < children.size(); counter++) {
2957                            ((ElementInfo) children.get(counter))
2958                                    .invalidate(false);
2959                        }
2960                        children = null;
2961                    }
2962                }
2963
2964                private View getView(View parent, Element e, int start) {
2965                    if (parent.getElement() == e) {
2966                        return parent;
2967                    }
2968                    int index = parent.getViewIndex(start,
2969                            Position.Bias.Forward);
2970
2971                    if (index != -1 && index < parent.getViewCount()) {
2972                        return getView(parent.getView(index), e, start);
2973                    }
2974                    return null;
2975                }
2976
2977                private int getClosestInfoIndex(int index) {
2978                    for (int counter = 0; counter < getChildCount(); counter++) {
2979                        ElementInfo info = getChild(counter);
2980
2981                        if (index < info.getElement().getEndOffset()
2982                                || index == info.getElement().getStartOffset()) {
2983                            return counter;
2984                        }
2985                    }
2986                    return -1;
2987                }
2988
2989                private void update(DocumentEvent e) {
2990                    if (!isValid()) {
2991                        return;
2992                    }
2993                    ElementInfo parent = getParent();
2994                    Element element = getElement();
2995
2996                    do {
2997                        DocumentEvent.ElementChange ec = e.getChange(element);
2998                        if (ec != null) {
2999                            if (element == getElement()) {
3000                                // One of our children changed.
3001                                invalidate(true);
3002                            } else if (parent != null) {
3003                                parent.invalidate(parent == getRootInfo());
3004                            }
3005                            return;
3006                        }
3007                        element = element.getParentElement();
3008                    } while (parent != null && element != null
3009                            && element != parent.getElement());
3010
3011                    if (getChildCount() > 0) {
3012                        Element elem = getElement();
3013                        int pos = e.getOffset();
3014                        int index0 = getClosestInfoIndex(pos);
3015                        if (index0 == -1
3016                                && e.getType() == DocumentEvent.EventType.REMOVE
3017                                && pos >= elem.getEndOffset()) {
3018                            // Event beyond our offsets. We may have represented this,
3019                            // that is the remove may have removed one of our child
3020                            // Elements that represented this, so, we should foward
3021                            // to last element.
3022                            index0 = getChildCount() - 1;
3023                        }
3024                        ElementInfo info = (index0 >= 0) ? getChild(index0)
3025                                : null;
3026                        if (info != null
3027                                && (info.getElement().getStartOffset() == pos)
3028                                && (pos > 0)) {
3029                            // If at a boundary, forward the event to the previous
3030                            // ElementInfo too.
3031                            index0 = Math.max(index0 - 1, 0);
3032                        }
3033                        int index1;
3034                        if (e.getType() != DocumentEvent.EventType.REMOVE) {
3035                            index1 = getClosestInfoIndex(pos + e.getLength());
3036                            if (index1 < 0) {
3037                                index1 = getChildCount() - 1;
3038                            }
3039                        } else {
3040                            index1 = index0;
3041                            // A remove may result in empty elements.
3042                            while ((index1 + 1) < getChildCount()
3043                                    && getChild(index1 + 1).getElement()
3044                                            .getEndOffset() == getChild(
3045                                            index1 + 1).getElement()
3046                                            .getStartOffset()) {
3047                                index1++;
3048                            }
3049                        }
3050                        index0 = Math.max(index0, 0);
3051                        // The check for isValid is here as in the process of
3052                        // forwarding update our child may invalidate us.
3053                        for (int i = index0; i <= index1 && isValid(); i++) {
3054                            getChild(i).update(e);
3055                        }
3056                    }
3057                }
3058            }
3059
3060            /**
3061             * DocumentListener installed on the current Document.  Will invoke
3062             * <code>update</code> on the <code>RootInfo</code> in response to
3063             * any event.
3064             */
3065            private class DocumentHandler implements  DocumentListener {
3066                public void insertUpdate(DocumentEvent e) {
3067                    getRootInfo().update(e);
3068                }
3069
3070                public void removeUpdate(DocumentEvent e) {
3071                    getRootInfo().update(e);
3072                }
3073
3074                public void changedUpdate(DocumentEvent e) {
3075                    getRootInfo().update(e);
3076                }
3077            }
3078
3079            /*
3080             * PropertyChangeListener installed on the editor. 
3081             */
3082            private class PropertyChangeHandler implements 
3083                    PropertyChangeListener {
3084                public void propertyChange(PropertyChangeEvent evt) {
3085                    if (evt.getPropertyName().equals("document")) {
3086                        // handle the document change
3087                        setDocument(editor.getDocument());
3088                    }
3089                }
3090            }
3091        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.