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")) {
|