< prev index next >

src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java

Print this page




 107      */
 108     private Document getDocument() {
 109         return model;
 110     }
 111 
 112     /**
 113      * Returns the JEditorPane providing information for.
 114      */
 115     private JEditorPane getTextComponent() {
 116         return editor;
 117     }
 118 
 119     /**
 120      * Returns the ElementInfo representing the root Element.
 121      */
 122     private ElementInfo getRootInfo() {
 123         return rootElementInfo;
 124     }
 125 
 126     /**
 127      * Returns the root <code>View</code> associated with the current text
 128      * component.
 129      */
 130     private View getRootView() {
 131         return getTextComponent().getUI().getRootView(getTextComponent());
 132     }
 133 
 134     /**
 135      * Returns the bounds the root View will be rendered in.
 136      */
 137     private Rectangle getRootEditorRect() {
 138         Rectangle alloc = getTextComponent().getBounds();
 139         if ((alloc.width > 0) && (alloc.height > 0)) {
 140             alloc.x = alloc.y = 0;
 141             Insets insets = editor.getInsets();
 142             alloc.x += insets.left;
 143             alloc.y += insets.top;
 144             alloc.width -= insets.left + insets.right;
 145             alloc.height -= insets.top + insets.bottom;
 146             return alloc;
 147         }
 148         return null;
 149     }
 150 
 151     /**
 152      * If possible acquires a lock on the Document.  If a lock has been
 153      * obtained a key will be retured that should be passed to
 154      * <code>unlock</code>.
 155      */
 156     private Object lock() {
 157         Document document = getDocument();
 158 
 159         if (document instanceof AbstractDocument) {
 160             ((AbstractDocument)document).readLock();
 161             return document;
 162         }
 163         return null;
 164     }
 165 
 166     /**
 167      * Releases a lock previously obtained via <code>lock</code>.
 168      */
 169     private void unlock(Object key) {
 170         if (key != null) {
 171             ((AbstractDocument)key).readUnlock();
 172         }
 173     }
 174 
 175     /**
 176      * Rebuilds the information from the current info.
 177      */
 178     private void buildInfo() {
 179         Object lock = lock();
 180 
 181         try {
 182             Document doc = getDocument();
 183             Element root = doc.getDefaultRootElement();
 184 
 185             rootElementInfo = new ElementInfo(root);
 186             rootElementInfo.validate();
 187         } finally {


 240          * should still be set.  For example, in the case of a text field used
 241          * to enter the name of a city, the accessibleName for the en_US locale
 242          * could be 'city.'
 243          *
 244          * @return the localized name of the object; null if this
 245          * object does not have a name
 246          *
 247          * @see #setAccessibleName
 248          */
 249         public String getAccessibleName() {
 250             if (model != null) {
 251                 return (String)model.getProperty(Document.TitleProperty);
 252             } else {
 253                 return null;
 254             }
 255         }
 256 
 257         /**
 258          * Gets the accessibleDescription property of this object.  If this
 259          * property isn't set, returns the content type of this
 260          * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
 261          *
 262          * @return the localized description of the object; <code>null</code>
 263          *      if this object does not have a description
 264          *
 265          * @see #setAccessibleName
 266          */
 267         public String getAccessibleDescription() {
 268             return editor.getContentType();
 269         }
 270 
 271         /**
 272          * Gets the role of this object.  The role of the object is the generic
 273          * purpose or use of the class of this object.  For example, the role
 274          * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
 275          * AccessibleRole are provided so component developers can pick from
 276          * a set of predefined roles.  This enables assistive technologies to
 277          * provide a consistent interface to various tweaked subclasses of
 278          * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
 279          * that act like a push button) as well as distinguish between subclasses
 280          * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
 281          * and AccessibleRole.RADIO_BUTTON for radio buttons).
 282          * <p>Note that the AccessibleRole class is also extensible, so


 857              * should still be set.  For example, in the case of a text field used
 858              * to enter the name of a city, the accessibleName for the en_US locale
 859              * could be 'city.'
 860              *
 861              * @return the localized name of the object; null if this
 862              * object does not have a name
 863              *
 864              * @see #setAccessibleName
 865              */
 866             public String getAccessibleName() {
 867                 if (model != null) {
 868                     return (String)model.getProperty(Document.TitleProperty);
 869                 } else {
 870                     return null;
 871                 }
 872             }
 873 
 874             /**
 875              * Gets the accessibleDescription property of this object.  If this
 876              * property isn't set, returns the content type of this
 877              * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
 878              *
 879              * @return the localized description of the object; <code>null</code>
 880              *  if this object does not have a description
 881              *
 882              * @see #setAccessibleName
 883              */
 884             public String getAccessibleDescription() {
 885                 return editor.getContentType();
 886             }
 887 
 888             /**
 889              * Gets the role of this object.  The role of the object is the generic
 890              * purpose or use of the class of this object.  For example, the role
 891              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
 892              * AccessibleRole are provided so component developers can pick from
 893              * a set of predefined roles.  This enables assistive technologies to
 894              * provide a consistent interface to various tweaked subclasses of
 895              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
 896              * that act like a push button) as well as distinguish between subclasses
 897              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
 898              * and AccessibleRole.RADIO_BUTTON for radio buttons).
 899              * <p>Note that the AccessibleRole class is also extensible, so


 965              * @return the zero-based offset of the caret.
 966              */
 967             public int getCaretPosition() {
 968                 View v = getView();
 969                 if (v == null) {
 970                     return -1;
 971                 }
 972                 Container c = v.getContainer();
 973                 if (c == null) {
 974                     return -1;
 975                 }
 976                 if (c instanceof JTextComponent) {
 977                     return ((JTextComponent)c).getCaretPosition();
 978                 } else {
 979                     return -1;
 980                 }
 981             }
 982 
 983             /**
 984              * IndexedSegment extends Segment adding the offset into the
 985              * the model the <code>Segment</code> was asked for.
 986              */
 987             private class IndexedSegment extends Segment {
 988                 /**
 989                  * Offset into the model that the position represents.
 990                  */
 991                 public int modelOffset;
 992             }
 993 
 994             public String getAtIndex(int part, int index) {
 995                 return getAtIndex(part, index, 0);
 996             }
 997 
 998 
 999             public String getAfterIndex(int part, int index) {
1000                 return getAtIndex(part, index, 1);
1001             }
1002 
1003             public String getBeforeIndex(int part, int index) {
1004                 return getAtIndex(part, index, -1);
1005             }
1006 
1007             /**
1008              * Gets the word, sentence, or character at <code>index</code>.
1009              * If <code>direction</code> is non-null this will find the
1010              * next/previous word/sentence/character.
1011              */
1012             private String getAtIndex(int part, int index, int direction) {
1013                 if (model instanceof AbstractDocument) {
1014                     ((AbstractDocument)model).readLock();
1015                 }
1016                 try {
1017                     if (index < 0 || index >= model.getLength()) {
1018                         return null;
1019                     }
1020                     switch (part) {
1021                     case AccessibleText.CHARACTER:
1022                         if (index + direction < model.getLength() &&
1023                             index + direction >= 0) {
1024                             return model.getText(index + direction, 1);
1025                         }
1026                         break;
1027 
1028 
1029                     case AccessibleText.WORD:


1073                 if (model instanceof PlainDocument ) {
1074                     PlainDocument sdoc = (PlainDocument)model;
1075                     return sdoc.getParagraphElement(index);
1076                 } else if (model instanceof StyledDocument) {
1077                     StyledDocument sdoc = (StyledDocument)model;
1078                     return sdoc.getParagraphElement(index);
1079                 } else {
1080                     Element para;
1081                     for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) {
1082                         int pos = para.getElementIndex(index);
1083                         para = para.getElement(pos);
1084                     }
1085                     if (para == null) {
1086                         return null;
1087                     }
1088                     return para.getParentElement();
1089                 }
1090             }
1091 
1092             /*
1093              * Returns a <code>Segment</code> containing the paragraph text
1094              * at <code>index</code>, or null if <code>index</code> isn't
1095              * valid.
1096              */
1097             private IndexedSegment getParagraphElementText(int index)
1098                 throws BadLocationException {
1099                 Element para = getParagraphElement(index);
1100 
1101 
1102                 if (para != null) {
1103                     IndexedSegment segment = new IndexedSegment();
1104                     try {
1105                         int length = para.getEndOffset() - para.getStartOffset();
1106                         model.getText(para.getStartOffset(), length, segment);
1107                     } catch (BadLocationException e) {
1108                         return null;
1109                     }
1110                     segment.modelOffset = para.getStartOffset();
1111                     return segment;
1112                 }
1113                 return null;
1114             }
1115 
1116 
1117             /**
1118              * Returns the Segment at <code>index</code> representing either
1119              * the paragraph or sentence as identified by <code>part</code>, or
1120              * null if a valid paragraph/sentence can't be found. The offset
1121              * will point to the start of the word/sentence in the array, and
1122              * the modelOffset will point to the location of the word/sentence
1123              * in the model.
1124              */
1125             private IndexedSegment getSegmentAt(int part, int index)
1126                 throws BadLocationException {
1127 
1128                 IndexedSegment seg = getParagraphElementText(index);
1129                 if (seg == null) {
1130                     return null;
1131                 }
1132                 BreakIterator iterator;
1133                 switch (part) {
1134                 case AccessibleText.WORD:
1135                     iterator = BreakIterator.getWordInstance(getLocale());
1136                     break;
1137                 case AccessibleText.SENTENCE:
1138                     iterator = BreakIterator.getSentenceInstance(getLocale());
1139                     break;


1292              * property of an object is a localized String that designates the purpose
1293              * of the object.  For example, the accessibleName property of a label
1294              * or button might be the text of the label or button itself.  In the
1295              * case of an object that doesn't display its name, the accessibleName
1296              * should still be set.  For example, in the case of a text field used
1297              * to enter the name of a city, the accessibleName for the en_US locale
1298              * could be 'city.'
1299              *
1300              * @return the localized name of the object; null if this
1301              * object does not have a name
1302              *
1303              * @see #setAccessibleName
1304              */
1305             public String getAccessibleName() {
1306                 return getAccessibleIconDescription();
1307             }
1308 
1309             /**
1310              * Gets the accessibleDescription property of this object.  If this
1311              * property isn't set, returns the content type of this
1312              * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
1313              *
1314              * @return the localized description of the object; <code>null</code>
1315              *  if this object does not have a description
1316              *
1317              * @see #setAccessibleName
1318              */
1319             public String getAccessibleDescription() {
1320                 return editor.getContentType();
1321             }
1322 
1323             /**
1324              * Gets the role of this object.  The role of the object is the generic
1325              * purpose or use of the class of this object.  For example, the role
1326              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
1327              * AccessibleRole are provided so component developers can pick from
1328              * a set of predefined roles.  This enables assistive technologies to
1329              * provide a consistent interface to various tweaked subclasses of
1330              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1331              * that act like a push button) as well as distinguish between subclasses
1332              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1333              * and AccessibleRole.RADIO_BUTTON for radio buttons).
1334              * <p>Note that the AccessibleRole class is also extensible, so


1593              * of the object.  For example, the accessibleName property of a label
1594              * or button might be the text of the label or button itself.  In the
1595              * case of an object that doesn't display its name, the accessibleName
1596              * should still be set.  For example, in the case of a text field used
1597              * to enter the name of a city, the accessibleName for the en_US locale
1598              * could be 'city.'
1599              *
1600              * @return the localized name of the object; null if this
1601              * object does not have a name
1602              *
1603              * @see #setAccessibleName
1604              */
1605             public String getAccessibleName() {
1606                 // return the role of the object
1607                 return getAccessibleRole().toString();
1608             }
1609 
1610             /**
1611              * Gets the accessibleDescription property of this object.  If this
1612              * property isn't set, returns the content type of this
1613              * <code>JEditorPane</code> instead (e.g. "plain/text", "html/text").
1614              *
1615              * @return the localized description of the object; <code>null</code>
1616              *  if this object does not have a description
1617              *
1618              * @see #setAccessibleName
1619              */
1620             public String getAccessibleDescription() {
1621                 return editor.getContentType();
1622             }
1623 
1624             /**
1625              * Gets the role of this object.  The role of the object is the generic
1626              * purpose or use of the class of this object.  For example, the role
1627              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
1628              * AccessibleRole are provided so component developers can pick from
1629              * a set of predefined roles.  This enables assistive technologies to
1630              * provide a consistent interface to various tweaked subclasses of
1631              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1632              * that act like a push button) as well as distinguish between subclasses
1633              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1634              * and AccessibleRole.RADIO_BUTTON for radio buttons).
1635              * <p>Note that the AccessibleRole class is also extensible, so


2617             }
2618 
2619             /**
2620              * Overriden to invalidate the TableRowElementInfo as well as
2621              * the TableCellElementInfo.
2622              */
2623             protected void invalidate(boolean first) {
2624                 super.invalidate(first);
2625                 getParent().invalidate(true);
2626             }
2627         }
2628     }
2629 
2630 
2631     /**
2632      * ElementInfo provides a slim down view of an Element.  Each ElementInfo
2633      * can have any number of child ElementInfos that are not necessarily
2634      * direct children of the Element. As the Document changes various
2635      * ElementInfos become invalidated. Before accessing a particular portion
2636      * of an ElementInfo you should make sure it is valid by invoking
2637      * <code>validateIfNecessary</code>, this will return true if
2638      * successful, on the other hand a false return value indicates the
2639      * ElementInfo is not valid and can never become valid again (usually
2640      * the result of the Element the ElementInfo encapsulates being removed).
2641      */
2642     private class ElementInfo {
2643 
2644         /**
2645          * The children of this ElementInfo.
2646          */
2647         private ArrayList<ElementInfo> children;
2648         /**
2649          * The Element this ElementInfo is providing information for.
2650          */
2651         private Element element;
2652         /**
2653          * The parent ElementInfo, will be null for the root.
2654          */
2655         private ElementInfo parent;
2656         /**
2657          * Indicates the validity of the ElementInfo.
2658          */
2659         private boolean isValid;
2660         /**
2661          * Indicates if the ElementInfo can become valid.
2662          */
2663         private boolean canBeValid;
2664 
2665 
2666         /**
2667          * Creates the root ElementInfo.
2668          */
2669         ElementInfo(Element element) {
2670             this(element, null);
2671         }
2672 
2673         /**
2674          * Creates an ElementInfo representing <code>element</code> with
2675          * the specified parent.
2676          */
2677         ElementInfo(Element element, ElementInfo parent) {
2678             this.element = element;
2679             this.parent = parent;
2680             isValid = false;
2681             canBeValid = true;
2682         }
2683 
2684         /**
2685          * Validates the receiver. This recreates the children as well. This
2686          * will be invoked within a <code>readLock</code>. If this is overriden
2687          * it MUST invoke supers implementation first!
2688          */
2689         protected void validate() {
2690             isValid = true;
2691             loadChildren(getElement());
2692         }
2693 
2694         /**
2695          * Recreates the direct children of <code>info</code>.
2696          */
2697         protected void loadChildren(Element parent) {
2698             if (!parent.isLeaf()) {
2699                 for (int counter = 0, maxCounter = parent.getElementCount();
2700                     counter < maxCounter; counter++) {
2701                     Element e = parent.getElement(counter);
2702                     ElementInfo childInfo = createElementInfo(e, this);
2703 
2704                     if (childInfo != null) {
2705                         addChild(childInfo);
2706                     }
2707                     else {
2708                         loadChildren(e);
2709                     }
2710                 }
2711             }
2712         }
2713 
2714         /**
2715          * Returns the index of the child in the parent, or -1 for the
2716          * root or if the parent isn't valid.
2717          */
2718         public int getIndexInParent() {
2719             if (parent == null || !parent.isValid()) {
2720                 return -1;
2721             }
2722             return parent.indexOf(this);
2723         }
2724 
2725         /**
2726          * Returns the Element this <code>ElementInfo</code> represents.
2727          */
2728         public Element getElement() {
2729             return element;
2730         }
2731 
2732         /**
2733          * Returns the parent of this Element, or null for the root.
2734          */
2735         public ElementInfo getParent() {
2736             return parent;
2737         }
2738 
2739         /**
2740          * Returns the index of the specified child, or -1 if
2741          * <code>child</code> isn't a valid child.
2742          */
2743         public int indexOf(ElementInfo child) {
2744             ArrayList<ElementInfo> children = this.children;
2745 
2746             if (children != null) {
2747                 return children.indexOf(child);
2748             }
2749             return -1;
2750         }
2751 
2752         /**
2753          * Returns the child ElementInfo at <code>index</code>, or null
2754          * if <code>index</code> isn't a valid index.
2755          */
2756         public ElementInfo getChild(int index) {
2757             if (validateIfNecessary()) {
2758                 ArrayList<ElementInfo> children = this.children;
2759 
2760                 if (children != null && index >= 0 &&
2761                                         index < children.size()) {
2762                     return children.get(index);
2763                 }
2764             }
2765             return null;
2766         }
2767 
2768         /**
2769          * Returns the number of children the ElementInfo contains.
2770          */
2771         public int getChildCount() {
2772             validateIfNecessary();
2773             return (children == null) ? 0 : children.size();
2774         }


2878             if (attrs != null && attrs.isDefined(key)) {
2879                 int i;
2880                 String val = (String)attrs.getAttribute(key);
2881                 if (val == null) {
2882                     i = deflt;
2883                 }
2884                 else {
2885                     try {
2886                         i = Math.max(0, Integer.parseInt(val));
2887                     } catch (NumberFormatException x) {
2888                         i = deflt;
2889                     }
2890                 }
2891                 return i;
2892             }
2893             return deflt;
2894         }
2895 
2896         /**
2897          * Validates the ElementInfo if necessary.  Some ElementInfos may
2898          * never be valid again.  You should check <code>isValid</code> before
2899          * using one.  This will reload the children and invoke
2900          * <code>validate</code> if the ElementInfo is invalid and can become
2901          * valid again. This will return true if the receiver is valid.
2902          */
2903         protected boolean validateIfNecessary() {
2904             if (!isValid() && canBeValid) {
2905                 children = null;
2906                 Object lock = lock();
2907 
2908                 try {
2909                     validate();
2910                 } finally {
2911                     unlock(lock);
2912                 }
2913             }
2914             return isValid();
2915         }
2916 
2917         /**
2918          * Invalidates the ElementInfo. Subclasses should override this
2919          * if they need to reset state once invalid.
2920          */


3013                     index1 = index0;
3014                     // A remove may result in empty elements.
3015                     while ((index1 + 1) < getChildCount() &&
3016                            getChild(index1 + 1).getElement().getEndOffset() ==
3017                            getChild(index1 + 1).getElement().getStartOffset()){
3018                         index1++;
3019                     }
3020                 }
3021                 index0 = Math.max(index0, 0);
3022                 // The check for isValid is here as in the process of
3023                 // forwarding update our child may invalidate us.
3024                 for (int i = index0; i <= index1 && isValid(); i++) {
3025                     getChild(i).update(e);
3026                 }
3027             }
3028         }
3029     }
3030 
3031     /**
3032      * DocumentListener installed on the current Document.  Will invoke
3033      * <code>update</code> on the <code>RootInfo</code> in response to
3034      * any event.
3035      */
3036     private class DocumentHandler implements DocumentListener {
3037         public void insertUpdate(DocumentEvent e) {
3038             getRootInfo().update(e);
3039         }
3040         public void removeUpdate(DocumentEvent e) {
3041             getRootInfo().update(e);
3042         }
3043         public void changedUpdate(DocumentEvent e) {
3044             getRootInfo().update(e);
3045         }
3046     }
3047 
3048     /*
3049      * PropertyChangeListener installed on the editor.
3050      */
3051     private class PropertyChangeHandler implements PropertyChangeListener {
3052         public void propertyChange(PropertyChangeEvent evt) {
3053             if (evt.getPropertyName().equals("document")) {


 107      */
 108     private Document getDocument() {
 109         return model;
 110     }
 111 
 112     /**
 113      * Returns the JEditorPane providing information for.
 114      */
 115     private JEditorPane getTextComponent() {
 116         return editor;
 117     }
 118 
 119     /**
 120      * Returns the ElementInfo representing the root Element.
 121      */
 122     private ElementInfo getRootInfo() {
 123         return rootElementInfo;
 124     }
 125 
 126     /**
 127      * Returns the root {@code View} associated with the current text
 128      * component.
 129      */
 130     private View getRootView() {
 131         return getTextComponent().getUI().getRootView(getTextComponent());
 132     }
 133 
 134     /**
 135      * Returns the bounds the root View will be rendered in.
 136      */
 137     private Rectangle getRootEditorRect() {
 138         Rectangle alloc = getTextComponent().getBounds();
 139         if ((alloc.width > 0) && (alloc.height > 0)) {
 140             alloc.x = alloc.y = 0;
 141             Insets insets = editor.getInsets();
 142             alloc.x += insets.left;
 143             alloc.y += insets.top;
 144             alloc.width -= insets.left + insets.right;
 145             alloc.height -= insets.top + insets.bottom;
 146             return alloc;
 147         }
 148         return null;
 149     }
 150 
 151     /**
 152      * If possible acquires a lock on the Document.  If a lock has been
 153      * obtained a key will be retured that should be passed to
 154      * {@code unlock}.
 155      */
 156     private Object lock() {
 157         Document document = getDocument();
 158 
 159         if (document instanceof AbstractDocument) {
 160             ((AbstractDocument)document).readLock();
 161             return document;
 162         }
 163         return null;
 164     }
 165 
 166     /**
 167      * Releases a lock previously obtained via {@code lock}.
 168      */
 169     private void unlock(Object key) {
 170         if (key != null) {
 171             ((AbstractDocument)key).readUnlock();
 172         }
 173     }
 174 
 175     /**
 176      * Rebuilds the information from the current info.
 177      */
 178     private void buildInfo() {
 179         Object lock = lock();
 180 
 181         try {
 182             Document doc = getDocument();
 183             Element root = doc.getDefaultRootElement();
 184 
 185             rootElementInfo = new ElementInfo(root);
 186             rootElementInfo.validate();
 187         } finally {


 240          * should still be set.  For example, in the case of a text field used
 241          * to enter the name of a city, the accessibleName for the en_US locale
 242          * could be 'city.'
 243          *
 244          * @return the localized name of the object; null if this
 245          * object does not have a name
 246          *
 247          * @see #setAccessibleName
 248          */
 249         public String getAccessibleName() {
 250             if (model != null) {
 251                 return (String)model.getProperty(Document.TitleProperty);
 252             } else {
 253                 return null;
 254             }
 255         }
 256 
 257         /**
 258          * Gets the accessibleDescription property of this object.  If this
 259          * property isn't set, returns the content type of this
 260          * {@code JEditorPane} instead (e.g. "plain/text", "html/text").
 261          *
 262          * @return the localized description of the object; {@code null}
 263          *      if this object does not have a description
 264          *
 265          * @see #setAccessibleName
 266          */
 267         public String getAccessibleDescription() {
 268             return editor.getContentType();
 269         }
 270 
 271         /**
 272          * Gets the role of this object.  The role of the object is the generic
 273          * purpose or use of the class of this object.  For example, the role
 274          * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
 275          * AccessibleRole are provided so component developers can pick from
 276          * a set of predefined roles.  This enables assistive technologies to
 277          * provide a consistent interface to various tweaked subclasses of
 278          * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
 279          * that act like a push button) as well as distinguish between subclasses
 280          * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
 281          * and AccessibleRole.RADIO_BUTTON for radio buttons).
 282          * <p>Note that the AccessibleRole class is also extensible, so


 857              * should still be set.  For example, in the case of a text field used
 858              * to enter the name of a city, the accessibleName for the en_US locale
 859              * could be 'city.'
 860              *
 861              * @return the localized name of the object; null if this
 862              * object does not have a name
 863              *
 864              * @see #setAccessibleName
 865              */
 866             public String getAccessibleName() {
 867                 if (model != null) {
 868                     return (String)model.getProperty(Document.TitleProperty);
 869                 } else {
 870                     return null;
 871                 }
 872             }
 873 
 874             /**
 875              * Gets the accessibleDescription property of this object.  If this
 876              * property isn't set, returns the content type of this
 877              * {@code JEditorPane} instead (e.g. "plain/text", "html/text").
 878              *
 879              * @return the localized description of the object; {@code null}
 880              *  if this object does not have a description
 881              *
 882              * @see #setAccessibleName
 883              */
 884             public String getAccessibleDescription() {
 885                 return editor.getContentType();
 886             }
 887 
 888             /**
 889              * Gets the role of this object.  The role of the object is the generic
 890              * purpose or use of the class of this object.  For example, the role
 891              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
 892              * AccessibleRole are provided so component developers can pick from
 893              * a set of predefined roles.  This enables assistive technologies to
 894              * provide a consistent interface to various tweaked subclasses of
 895              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
 896              * that act like a push button) as well as distinguish between subclasses
 897              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
 898              * and AccessibleRole.RADIO_BUTTON for radio buttons).
 899              * <p>Note that the AccessibleRole class is also extensible, so


 965              * @return the zero-based offset of the caret.
 966              */
 967             public int getCaretPosition() {
 968                 View v = getView();
 969                 if (v == null) {
 970                     return -1;
 971                 }
 972                 Container c = v.getContainer();
 973                 if (c == null) {
 974                     return -1;
 975                 }
 976                 if (c instanceof JTextComponent) {
 977                     return ((JTextComponent)c).getCaretPosition();
 978                 } else {
 979                     return -1;
 980                 }
 981             }
 982 
 983             /**
 984              * IndexedSegment extends Segment adding the offset into the
 985              * the model the {@code Segment} was asked for.
 986              */
 987             private class IndexedSegment extends Segment {
 988                 /**
 989                  * Offset into the model that the position represents.
 990                  */
 991                 public int modelOffset;
 992             }
 993 
 994             public String getAtIndex(int part, int index) {
 995                 return getAtIndex(part, index, 0);
 996             }
 997 
 998 
 999             public String getAfterIndex(int part, int index) {
1000                 return getAtIndex(part, index, 1);
1001             }
1002 
1003             public String getBeforeIndex(int part, int index) {
1004                 return getAtIndex(part, index, -1);
1005             }
1006 
1007             /**
1008              * Gets the word, sentence, or character at {@code index}.
1009              * If {@code direction} is non-null this will find the
1010              * next/previous word/sentence/character.
1011              */
1012             private String getAtIndex(int part, int index, int direction) {
1013                 if (model instanceof AbstractDocument) {
1014                     ((AbstractDocument)model).readLock();
1015                 }
1016                 try {
1017                     if (index < 0 || index >= model.getLength()) {
1018                         return null;
1019                     }
1020                     switch (part) {
1021                     case AccessibleText.CHARACTER:
1022                         if (index + direction < model.getLength() &&
1023                             index + direction >= 0) {
1024                             return model.getText(index + direction, 1);
1025                         }
1026                         break;
1027 
1028 
1029                     case AccessibleText.WORD:


1073                 if (model instanceof PlainDocument ) {
1074                     PlainDocument sdoc = (PlainDocument)model;
1075                     return sdoc.getParagraphElement(index);
1076                 } else if (model instanceof StyledDocument) {
1077                     StyledDocument sdoc = (StyledDocument)model;
1078                     return sdoc.getParagraphElement(index);
1079                 } else {
1080                     Element para;
1081                     for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) {
1082                         int pos = para.getElementIndex(index);
1083                         para = para.getElement(pos);
1084                     }
1085                     if (para == null) {
1086                         return null;
1087                     }
1088                     return para.getParentElement();
1089                 }
1090             }
1091 
1092             /*
1093              * Returns a {@code Segment} containing the paragraph text
1094              * at {@code index}, or null if {@code index} isn't
1095              * valid.
1096              */
1097             private IndexedSegment getParagraphElementText(int index)
1098                 throws BadLocationException {
1099                 Element para = getParagraphElement(index);
1100 
1101 
1102                 if (para != null) {
1103                     IndexedSegment segment = new IndexedSegment();
1104                     try {
1105                         int length = para.getEndOffset() - para.getStartOffset();
1106                         model.getText(para.getStartOffset(), length, segment);
1107                     } catch (BadLocationException e) {
1108                         return null;
1109                     }
1110                     segment.modelOffset = para.getStartOffset();
1111                     return segment;
1112                 }
1113                 return null;
1114             }
1115 
1116 
1117             /**
1118              * Returns the Segment at {@code index} representing either
1119              * the paragraph or sentence as identified by {@code part}, or
1120              * null if a valid paragraph/sentence can't be found. The offset
1121              * will point to the start of the word/sentence in the array, and
1122              * the modelOffset will point to the location of the word/sentence
1123              * in the model.
1124              */
1125             private IndexedSegment getSegmentAt(int part, int index)
1126                 throws BadLocationException {
1127 
1128                 IndexedSegment seg = getParagraphElementText(index);
1129                 if (seg == null) {
1130                     return null;
1131                 }
1132                 BreakIterator iterator;
1133                 switch (part) {
1134                 case AccessibleText.WORD:
1135                     iterator = BreakIterator.getWordInstance(getLocale());
1136                     break;
1137                 case AccessibleText.SENTENCE:
1138                     iterator = BreakIterator.getSentenceInstance(getLocale());
1139                     break;


1292              * property of an object is a localized String that designates the purpose
1293              * of the object.  For example, the accessibleName property of a label
1294              * or button might be the text of the label or button itself.  In the
1295              * case of an object that doesn't display its name, the accessibleName
1296              * should still be set.  For example, in the case of a text field used
1297              * to enter the name of a city, the accessibleName for the en_US locale
1298              * could be 'city.'
1299              *
1300              * @return the localized name of the object; null if this
1301              * object does not have a name
1302              *
1303              * @see #setAccessibleName
1304              */
1305             public String getAccessibleName() {
1306                 return getAccessibleIconDescription();
1307             }
1308 
1309             /**
1310              * Gets the accessibleDescription property of this object.  If this
1311              * property isn't set, returns the content type of this
1312              * {@code JEditorPane} instead (e.g. "plain/text", "html/text").
1313              *
1314              * @return the localized description of the object; {@code null}
1315              *  if this object does not have a description
1316              *
1317              * @see #setAccessibleName
1318              */
1319             public String getAccessibleDescription() {
1320                 return editor.getContentType();
1321             }
1322 
1323             /**
1324              * Gets the role of this object.  The role of the object is the generic
1325              * purpose or use of the class of this object.  For example, the role
1326              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
1327              * AccessibleRole are provided so component developers can pick from
1328              * a set of predefined roles.  This enables assistive technologies to
1329              * provide a consistent interface to various tweaked subclasses of
1330              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1331              * that act like a push button) as well as distinguish between subclasses
1332              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1333              * and AccessibleRole.RADIO_BUTTON for radio buttons).
1334              * <p>Note that the AccessibleRole class is also extensible, so


1593              * of the object.  For example, the accessibleName property of a label
1594              * or button might be the text of the label or button itself.  In the
1595              * case of an object that doesn't display its name, the accessibleName
1596              * should still be set.  For example, in the case of a text field used
1597              * to enter the name of a city, the accessibleName for the en_US locale
1598              * could be 'city.'
1599              *
1600              * @return the localized name of the object; null if this
1601              * object does not have a name
1602              *
1603              * @see #setAccessibleName
1604              */
1605             public String getAccessibleName() {
1606                 // return the role of the object
1607                 return getAccessibleRole().toString();
1608             }
1609 
1610             /**
1611              * Gets the accessibleDescription property of this object.  If this
1612              * property isn't set, returns the content type of this
1613              * {@code JEditorPane} instead (e.g. "plain/text", "html/text").
1614              *
1615              * @return the localized description of the object; {@code null}
1616              *  if this object does not have a description
1617              *
1618              * @see #setAccessibleName
1619              */
1620             public String getAccessibleDescription() {
1621                 return editor.getContentType();
1622             }
1623 
1624             /**
1625              * Gets the role of this object.  The role of the object is the generic
1626              * purpose or use of the class of this object.  For example, the role
1627              * of a push button is AccessibleRole.PUSH_BUTTON.  The roles in
1628              * AccessibleRole are provided so component developers can pick from
1629              * a set of predefined roles.  This enables assistive technologies to
1630              * provide a consistent interface to various tweaked subclasses of
1631              * components (e.g., use AccessibleRole.PUSH_BUTTON for all components
1632              * that act like a push button) as well as distinguish between subclasses
1633              * that behave differently (e.g., AccessibleRole.CHECK_BOX for check boxes
1634              * and AccessibleRole.RADIO_BUTTON for radio buttons).
1635              * <p>Note that the AccessibleRole class is also extensible, so


2617             }
2618 
2619             /**
2620              * Overriden to invalidate the TableRowElementInfo as well as
2621              * the TableCellElementInfo.
2622              */
2623             protected void invalidate(boolean first) {
2624                 super.invalidate(first);
2625                 getParent().invalidate(true);
2626             }
2627         }
2628     }
2629 
2630 
2631     /**
2632      * ElementInfo provides a slim down view of an Element.  Each ElementInfo
2633      * can have any number of child ElementInfos that are not necessarily
2634      * direct children of the Element. As the Document changes various
2635      * ElementInfos become invalidated. Before accessing a particular portion
2636      * of an ElementInfo you should make sure it is valid by invoking
2637      * {@code validateIfNecessary}, this will return true if
2638      * successful, on the other hand a false return value indicates the
2639      * ElementInfo is not valid and can never become valid again (usually
2640      * the result of the Element the ElementInfo encapsulates being removed).
2641      */
2642     private class ElementInfo {
2643 
2644         /**
2645          * The children of this ElementInfo.
2646          */
2647         private ArrayList<ElementInfo> children;
2648         /**
2649          * The Element this ElementInfo is providing information for.
2650          */
2651         private Element element;
2652         /**
2653          * The parent ElementInfo, will be null for the root.
2654          */
2655         private ElementInfo parent;
2656         /**
2657          * Indicates the validity of the ElementInfo.
2658          */
2659         private boolean isValid;
2660         /**
2661          * Indicates if the ElementInfo can become valid.
2662          */
2663         private boolean canBeValid;
2664 
2665 
2666         /**
2667          * Creates the root ElementInfo.
2668          */
2669         ElementInfo(Element element) {
2670             this(element, null);
2671         }
2672 
2673         /**
2674          * Creates an ElementInfo representing {@code element} with
2675          * the specified parent.
2676          */
2677         ElementInfo(Element element, ElementInfo parent) {
2678             this.element = element;
2679             this.parent = parent;
2680             isValid = false;
2681             canBeValid = true;
2682         }
2683 
2684         /**
2685          * Validates the receiver. This recreates the children as well. This
2686          * will be invoked within a {@code readLock}. If this is overriden
2687          * it MUST invoke supers implementation first!
2688          */
2689         protected void validate() {
2690             isValid = true;
2691             loadChildren(getElement());
2692         }
2693 
2694         /**
2695          * Recreates the direct children of {@code info}.
2696          */
2697         protected void loadChildren(Element parent) {
2698             if (!parent.isLeaf()) {
2699                 for (int counter = 0, maxCounter = parent.getElementCount();
2700                     counter < maxCounter; counter++) {
2701                     Element e = parent.getElement(counter);
2702                     ElementInfo childInfo = createElementInfo(e, this);
2703 
2704                     if (childInfo != null) {
2705                         addChild(childInfo);
2706                     }
2707                     else {
2708                         loadChildren(e);
2709                     }
2710                 }
2711             }
2712         }
2713 
2714         /**
2715          * Returns the index of the child in the parent, or -1 for the
2716          * root or if the parent isn't valid.
2717          */
2718         public int getIndexInParent() {
2719             if (parent == null || !parent.isValid()) {
2720                 return -1;
2721             }
2722             return parent.indexOf(this);
2723         }
2724 
2725         /**
2726          * Returns the Element this {@code ElementInfo} represents.
2727          */
2728         public Element getElement() {
2729             return element;
2730         }
2731 
2732         /**
2733          * Returns the parent of this Element, or null for the root.
2734          */
2735         public ElementInfo getParent() {
2736             return parent;
2737         }
2738 
2739         /**
2740          * Returns the index of the specified child, or -1 if
2741          * {@code child} isn't a valid child.
2742          */
2743         public int indexOf(ElementInfo child) {
2744             ArrayList<ElementInfo> children = this.children;
2745 
2746             if (children != null) {
2747                 return children.indexOf(child);
2748             }
2749             return -1;
2750         }
2751 
2752         /**
2753          * Returns the child ElementInfo at {@code index}, or null
2754          * if {@code index} isn't a valid index.
2755          */
2756         public ElementInfo getChild(int index) {
2757             if (validateIfNecessary()) {
2758                 ArrayList<ElementInfo> children = this.children;
2759 
2760                 if (children != null && index >= 0 &&
2761                                         index < children.size()) {
2762                     return children.get(index);
2763                 }
2764             }
2765             return null;
2766         }
2767 
2768         /**
2769          * Returns the number of children the ElementInfo contains.
2770          */
2771         public int getChildCount() {
2772             validateIfNecessary();
2773             return (children == null) ? 0 : children.size();
2774         }


2878             if (attrs != null && attrs.isDefined(key)) {
2879                 int i;
2880                 String val = (String)attrs.getAttribute(key);
2881                 if (val == null) {
2882                     i = deflt;
2883                 }
2884                 else {
2885                     try {
2886                         i = Math.max(0, Integer.parseInt(val));
2887                     } catch (NumberFormatException x) {
2888                         i = deflt;
2889                     }
2890                 }
2891                 return i;
2892             }
2893             return deflt;
2894         }
2895 
2896         /**
2897          * Validates the ElementInfo if necessary.  Some ElementInfos may
2898          * never be valid again.  You should check {@code isValid} before
2899          * using one.  This will reload the children and invoke
2900          * {@code validate} if the ElementInfo is invalid and can become
2901          * valid again. This will return true if the receiver is valid.
2902          */
2903         protected boolean validateIfNecessary() {
2904             if (!isValid() && canBeValid) {
2905                 children = null;
2906                 Object lock = lock();
2907 
2908                 try {
2909                     validate();
2910                 } finally {
2911                     unlock(lock);
2912                 }
2913             }
2914             return isValid();
2915         }
2916 
2917         /**
2918          * Invalidates the ElementInfo. Subclasses should override this
2919          * if they need to reset state once invalid.
2920          */


3013                     index1 = index0;
3014                     // A remove may result in empty elements.
3015                     while ((index1 + 1) < getChildCount() &&
3016                            getChild(index1 + 1).getElement().getEndOffset() ==
3017                            getChild(index1 + 1).getElement().getStartOffset()){
3018                         index1++;
3019                     }
3020                 }
3021                 index0 = Math.max(index0, 0);
3022                 // The check for isValid is here as in the process of
3023                 // forwarding update our child may invalidate us.
3024                 for (int i = index0; i <= index1 && isValid(); i++) {
3025                     getChild(i).update(e);
3026                 }
3027             }
3028         }
3029     }
3030 
3031     /**
3032      * DocumentListener installed on the current Document.  Will invoke
3033      * {@code update} on the {@code RootInfo} in response to
3034      * any event.
3035      */
3036     private class DocumentHandler implements DocumentListener {
3037         public void insertUpdate(DocumentEvent e) {
3038             getRootInfo().update(e);
3039         }
3040         public void removeUpdate(DocumentEvent e) {
3041             getRootInfo().update(e);
3042         }
3043         public void changedUpdate(DocumentEvent e) {
3044             getRootInfo().update(e);
3045         }
3046     }
3047 
3048     /*
3049      * PropertyChangeListener installed on the editor.
3050      */
3051     private class PropertyChangeHandler implements PropertyChangeListener {
3052         public void propertyChange(PropertyChangeEvent evt) {
3053             if (evt.getPropertyName().equals("document")) {
< prev index next >