summaryrefslogtreecommitdiff
path: root/accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java')
-rw-r--r--accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java678
1 files changed, 678 insertions, 0 deletions
diff --git a/accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java b/accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java
new file mode 100644
index 000000000000..c3bcbde2a71a
--- /dev/null
+++ b/accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java
@@ -0,0 +1,678 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package org.openoffice.java.accessibility;
+
+import com.sun.star.accessibility.*;
+import com.sun.star.awt.*;
+import com.sun.star.style.*;
+import com.sun.star.uno.*;
+
+import org.openoffice.java.accessibility.logging.*;
+
+import java.text.BreakIterator;
+import java.util.Locale;
+
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleText;
+
+import javax.swing.text.StyleConstants;
+
+/** The GenericAccessibleEditableText mapps the calls to the java AccessibleEditableText
+ * interface to the corresponding methods of the UNO XAccessibleEditableText interface.
+ */
+public class AccessibleTextImpl implements javax.accessibility.AccessibleText {
+ final static double toPointFactor = 1 / ((7 / 10) + 34.5);
+ final static String[] attributeList = {
+ "ParaAdjust", "CharBackColor", "CharWeight", "ParaFirstLineIndent",
+ "CharFontPitch", "CharHeight", "CharColor", "CharPosture",
+ "ParaLeftMargin", "ParaLineSpacing", "ParaTopMargin", "ParaBottomMargin",
+ "CharStrikeout", "CharEscapement", "ParaTabStops", "CharUnderline"
+ };
+
+ final static String[] localeAttributeList = {
+ "CharLocale", "CharLocaleAsian", "CharLocaleComplex"
+ };
+
+ XAccessibleText unoObject;
+ private javax.swing.text.TabSet tabSet = null;
+ private javax.swing.text.TabStop[] tabStops = null;
+ private static Type TextSegmentType = new Type(TextSegment.class);
+ private static Type UnoLocaleType = new Type(com.sun.star.lang.Locale.class);
+
+ /** Creates new GenericAccessibleEditableText object */
+ public AccessibleTextImpl(XAccessibleText xAccessibleText) {
+
+ if (Build.PRODUCT) {
+ unoObject = xAccessibleText;
+ } else {
+ String property = System.getProperty("AccessBridgeLogging");
+ if ((property != null) && (property.indexOf("text") != -1)) {
+ unoObject = new XAccessibleTextLog(xAccessibleText);
+ } else {
+ unoObject = xAccessibleText;
+ }
+ }
+ }
+
+ public AccessibleTextImpl() {
+ }
+
+ public static javax.accessibility.AccessibleText get(com.sun.star.uno.XInterface unoObject) {
+ try {
+ XAccessibleText unoAccessibleText = (XAccessibleText)
+ UnoRuntime.queryInterface(XAccessibleText.class, unoObject);
+ if (unoAccessibleText != null) {
+ return new AccessibleTextImpl(unoAccessibleText);
+ }
+ } catch (com.sun.star.uno.RuntimeException e) {
+ }
+ return null;
+ }
+
+ protected static Object convertTextSegment(Object any) {
+ try {
+ if (AnyConverter.isObject(any)) {
+ TextSegment ts = (TextSegment)
+ AnyConverter.toObject(TextSegmentType, any);
+ if (ts != null) {
+ // Since there is nothing like a "range" object in the JAA yet,
+ // the Object[3] is a private negotiation with the JABG
+ Object[] array = { new Integer(ts.SegmentStart),
+ new Integer(ts.SegmentEnd), ts.SegmentText };
+ return array;
+ }
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ }
+
+ return null;
+ }
+
+ /** Returns the locale object.
+ *
+ * Since switching the UI language only takes effect on the next
+ * office start, UI elements can return a cached value here - given
+ * that Java UNO initializes the default locale correctly, this is
+ * the perfect place to grab this cached values.
+ *
+ * However, since there are more sophisticated components with
+ * potentially more than one locale, we first check for the
+ * CharLocale[Asian|Complex] property.
+ */
+
+ protected java.util.Locale getLocale(int index) {
+ try {
+ com.sun.star.beans.PropertyValue[] propertyValues =
+ unoObject.getCharacterAttributes(index, localeAttributeList);
+
+ if (null != propertyValues) {
+ for (int i = 0; i < propertyValues.length; i++) {
+ com.sun.star.lang.Locale unoLocale = (com.sun.star.lang.Locale)
+ AnyConverter.toObject(UnoLocaleType, propertyValues[i]);
+ if (unoLocale != null) {
+ return new java.util.Locale(unoLocale.Language, unoLocale.Country);
+ }
+ }
+ }
+
+ return java.util.Locale.getDefault();
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return java.util.Locale.getDefault();
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ return java.util.Locale.getDefault();
+ }
+ }
+
+
+ /** Returns the string after a given index
+ *
+ * The Java word iterator has a different understanding of what
+ * a word is than the word iterator used by OOo, so we use the
+ * Java iterators to ensure maximal compatibility with Java.
+ */
+ public String getAfterIndex(int part, int index) {
+ switch (part) {
+ case AccessibleText.CHARACTER:
+ try {
+ String s = unoObject.getText();
+ return s.substring(index+1, index+2);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.WORD:
+ try {
+ String s = unoObject.getText();
+ BreakIterator words = BreakIterator.getWordInstance(getLocale(index));
+ words.setText(s);
+ int start = words.following(index);
+ if (start == BreakIterator.DONE || start >= s.length()) {
+ return null;
+ }
+ int end = words.following(start);
+ if (end == BreakIterator.DONE || end >= s.length()) {
+ return null;
+ }
+ return s.substring(start, end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.SENTENCE:
+ try {
+ String s = unoObject.getText();
+ BreakIterator sentence =
+ BreakIterator.getSentenceInstance(getLocale(index));
+ sentence.setText(s);
+ int start = sentence.following(index);
+ if (start == BreakIterator.DONE || start >= s.length()) {
+ return null;
+ }
+ int end = sentence.following(start);
+ if (end == BreakIterator.DONE || end >= s.length()) {
+ return null;
+ }
+ return s.substring(start, end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case 4:
+ try {
+ TextSegment ts = unoObject.getTextBehindIndex(index, AccessibleTextType.LINE);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ // Workaround for #104847#
+ if (index > 0 && getCharCount() == index) {
+ return getAfterIndex(part, index - 1);
+ }
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ case 5:
+ try {
+ TextSegment ts = unoObject.getTextBehindIndex(index, AccessibleTextType.ATTRIBUTE_RUN);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ default:
+ return null;
+ }
+ }
+
+ /** Returns the zero-based offset of the caret */
+ public int getCaretPosition() {
+ try {
+ return unoObject.getCaretPosition();
+ } catch (com.sun.star.uno.RuntimeException e) {
+ return -1;
+ }
+ }
+
+ /** Returns the start offset within the selected text */
+ public int getSelectionStart() {
+ try {
+ int index = unoObject.getSelectionStart();
+
+ if (index == -1) {
+ index = getCaretPosition();
+ }
+
+ return index;
+ } catch (com.sun.star.uno.RuntimeException e) {
+ return -1;
+ }
+ }
+
+ protected void setAttribute(javax.swing.text.MutableAttributeSet as,
+ com.sun.star.beans.PropertyValue property) {
+ try {
+ // Map alignment attribute
+ if (property.Name.equals("ParaAdjust")) {
+ ParagraphAdjust adjust = null;
+
+ if (property.Value instanceof ParagraphAdjust) {
+ adjust = (ParagraphAdjust) property.Value;
+ } else if (property.Value instanceof Any) {
+ adjust = (ParagraphAdjust) AnyConverter.toObject(new Type(
+ ParagraphAdjust.class), property.Value);
+ } else {
+ adjust = ParagraphAdjust.fromInt(AnyConverter.toInt(
+ property.Value));
+ }
+
+ if (adjust != null) {
+ if (adjust.equals(ParagraphAdjust.LEFT)) {
+ StyleConstants.setAlignment(as,
+ StyleConstants.ALIGN_LEFT);
+ } else if (adjust.equals(ParagraphAdjust.RIGHT)) {
+ StyleConstants.setAlignment(as,
+ StyleConstants.ALIGN_RIGHT);
+ } else if (adjust.equals(ParagraphAdjust.CENTER)) {
+ StyleConstants.setAlignment(as,
+ StyleConstants.ALIGN_CENTER);
+ } else if (adjust.equals(ParagraphAdjust.BLOCK) ||
+ adjust.equals(ParagraphAdjust.STRETCH)) {
+ StyleConstants.setAlignment(as,
+ StyleConstants.ALIGN_JUSTIFIED);
+ }
+ } else if (Build.DEBUG) {
+ System.err.println(
+ "Invalid property value for key ParaAdjust: " +
+ property.Value.getClass().getName());
+ }
+
+ // Map background color
+ } else if (property.Name.equals("CharBackColor")) {
+ StyleConstants.setBackground(as,
+ new java.awt.Color(AnyConverter.toInt(property.Value)));
+
+ // FIXME: BidiLevel
+ // Set bold attribute
+ } else if (property.Name.equals("CharWeight")) {
+ boolean isBold = AnyConverter.toFloat(property.Value) > 125;
+ StyleConstants.setBold(as, isBold);
+
+ // FIXME: Java 1.4 ComponentAttribute, ComponentElementName, ComposedTextAttribute
+ // Set FirstLineIndent attribute
+ } else if (property.Name.equals("ParaFirstLineIndent")) {
+ StyleConstants.setFirstLineIndent(as,
+ (float) (toPointFactor * AnyConverter.toInt(property.Value)));
+
+ // Set font family attribute
+ } else if (property.Name.equals("CharFontPitch")) {
+ if (AnyConverter.toShort(property.Value) == 2) {
+ StyleConstants.setFontFamily(as, "Proportional");
+ }
+
+ // Set font size attribute
+ } else if (property.Name.equals("CharHeight")) {
+ StyleConstants.setFontSize(as,
+ (int) AnyConverter.toFloat(property.Value));
+
+ // Map foreground color
+ } else if (property.Name.equals("CharColor")) {
+ StyleConstants.setForeground(as,
+ new java.awt.Color(AnyConverter.toInt(property.Value)));
+
+ // FIXME: IconAttribute, IconElementName
+ // Set italic attribute
+ } else if (property.Name.equals("CharPosture")) {
+ FontSlant fs = null;
+
+ if (property.Value instanceof FontSlant) {
+ fs = (FontSlant) property.Value;
+ } else if (property.Value instanceof Any) {
+ fs = (FontSlant) AnyConverter.toObject(new Type(
+ FontSlant.class), property.Value);
+ }
+
+ if (fs != null) {
+ StyleConstants.setItalic(as, FontSlant.ITALIC.equals(fs));
+ }
+
+ // Set left indent attribute
+ } else if (property.Name.equals("ParaLeftMargin")) {
+ StyleConstants.setLeftIndent(as,
+ (float) (toPointFactor * AnyConverter.toInt(property.Value)));
+
+ // Set right indent attribute
+ } else if (property.Name.equals("ParaRightMargin")) {
+ StyleConstants.setRightIndent(as,
+ (float) (toPointFactor * AnyConverter.toInt(property.Value)));
+ }
+ // Set line spacing attribute
+ else if (property.Name.equals("ParaLineSpacing")) {
+ LineSpacing ls = null;
+
+ if (property.Value instanceof LineSpacing) {
+ ls = (LineSpacing) property.Value;
+ } else if (property.Value instanceof Any) {
+ ls = (LineSpacing) AnyConverter.toObject(new Type(
+ LineSpacing.class), property.Value);
+ }
+
+ if (ls != null) {
+ StyleConstants.setLineSpacing(as,
+ (float) (toPointFactor * ls.Height));
+ }
+ }
+ // FIXME: Java 1.4 NameAttribute, Orientation, ResolveAttribute
+ // Set space above attribute
+ else if (property.Name.equals("ParaTopMargin")) {
+ StyleConstants.setSpaceAbove(as,
+ (float) (toPointFactor * AnyConverter.toInt(property.Value)));
+ }
+ // Set space below attribute
+ else if (property.Name.equals("ParaBottomMargin")) {
+ StyleConstants.setSpaceBelow(as,
+ (float) (toPointFactor * AnyConverter.toInt(property.Value)));
+
+ // Set strike through attribute
+ } else if (property.Name.equals("CharStrikeout")) {
+ boolean isStrikeThrough = (FontStrikeout.NONE != AnyConverter.toShort(property.Value));
+ StyleConstants.setStrikeThrough(as, isStrikeThrough);
+
+ // Set sub-/superscript attribute
+ } else if (property.Name.equals("CharEscapement")) {
+ short value = AnyConverter.toShort(property.Value);
+
+ if (value > 0) {
+ StyleConstants.setSuperscript(as, true);
+ } else if (value < 0) {
+ StyleConstants.setSubscript(as, true);
+ }
+
+ // Set tabset attribute
+ } else if (property.Name.equals("ParaTabStops")) {
+ TabStop[] unoTabStops = (TabStop[]) AnyConverter.toArray(property.Value);
+ javax.swing.text.TabStop[] tabStops = new javax.swing.text.TabStop[unoTabStops.length];
+
+ for (int index2 = 0; index2 < unoTabStops.length; index2++) {
+ float pos = (float) (toPointFactor * unoTabStops[index2].Position);
+
+ if (unoTabStops[index2].Alignment.equals(TabAlign.LEFT)) {
+ tabStops[index2] = new javax.swing.text.TabStop(pos,
+ javax.swing.text.TabStop.ALIGN_LEFT,
+ javax.swing.text.TabStop.LEAD_NONE);
+ } else if (unoTabStops[index2].Alignment.equals(
+ TabAlign.CENTER)) {
+ tabStops[index2] = new javax.swing.text.TabStop(pos,
+ javax.swing.text.TabStop.ALIGN_CENTER,
+ javax.swing.text.TabStop.LEAD_NONE);
+ } else if (unoTabStops[index2].Alignment.equals(
+ TabAlign.RIGHT)) {
+ tabStops[index2] = new javax.swing.text.TabStop(pos,
+ javax.swing.text.TabStop.ALIGN_RIGHT,
+ javax.swing.text.TabStop.LEAD_NONE);
+ } else if (unoTabStops[index2].Alignment.equals(
+ TabAlign.DECIMAL)) {
+ tabStops[index2] = new javax.swing.text.TabStop(pos,
+ javax.swing.text.TabStop.ALIGN_DECIMAL,
+ javax.swing.text.TabStop.LEAD_NONE);
+ } else {
+ tabStops[index2] = new javax.swing.text.TabStop(pos);
+ }
+ }
+
+ // Re-use tabSet object if possible to make AttributeSet.equals work
+ if ((this.tabSet == null) ||
+ !java.util.Arrays.equals(tabStops, this.tabStops)) {
+ this.tabStops = tabStops;
+ this.tabSet = new javax.swing.text.TabSet(tabStops);
+ }
+
+ StyleConstants.setTabSet(as, this.tabSet);
+
+ // Set underline attribute
+ } else if (property.Name.equals("CharUnderline")) {
+ boolean isUnderline = (FontUnderline.NONE != AnyConverter.toShort(property.Value));
+ StyleConstants.setUnderline(as, isUnderline);
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ if (Build.DEBUG) {
+ System.err.println("*** ERROR *** " + e.getClass().getName() +
+ " caught for property " + property.Name + ": " +
+ e.getMessage());
+ System.err.println(" value is of type " +
+ property.Value.getClass().getName());
+ }
+ }
+ }
+
+ /** Returns the AttributSet for a given character at a given index */
+ public javax.swing.text.AttributeSet getCharacterAttribute(int index) {
+ try {
+ com.sun.star.beans.PropertyValue[] propertyValues = unoObject.getCharacterAttributes(index,
+ attributeList);
+ javax.swing.text.SimpleAttributeSet attributeSet = new javax.swing.text.SimpleAttributeSet();
+
+ if (null != propertyValues) {
+ for (int i = 0; i < propertyValues.length; i++) {
+ setAttribute(attributeSet, propertyValues[i]);
+ }
+ }
+
+ return attributeSet;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ if ((index > 0) && (getCharCount() == index)) {
+ return getCharacterAttribute(index - 1);
+ }
+ return null;
+ }
+ }
+
+ /** Given a point in local coordinates, return the zero-based index of the character under that point */
+ public int getIndexAtPoint(java.awt.Point point) {
+ try {
+ return unoObject.getIndexAtPoint(new Point(point.x, point.y));
+ } catch (com.sun.star.uno.RuntimeException e) {
+ return -1;
+ }
+ }
+
+ /** Returns the end offset within the selected text */
+ public int getSelectionEnd() {
+ try {
+ int index = unoObject.getSelectionEnd();
+
+ if (index == -1) {
+ index = getCaretPosition();
+ }
+
+ return index;
+ } catch (com.sun.star.uno.RuntimeException e) {
+ return -1;
+ }
+ }
+
+ /** Returns the string before a given index
+ *
+ * The Java word iterator has a different understanding of what
+ * a word is than the word iterator used by OOo, so we use the
+ * Java iterators to ensure maximal compatibility with Java.
+ */
+ public java.lang.String getBeforeIndex(int part, int index) {
+ switch (part) {
+ case AccessibleText.CHARACTER:
+ try {
+ String s = unoObject.getText();
+ return s.substring(index-1, index);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.WORD:
+ try {
+ String s = unoObject.getText();
+ BreakIterator words = BreakIterator.getWordInstance(getLocale(index));
+ words.setText(s);
+ int end = words.following(index);
+ end = words.previous();
+ int start = words.previous();
+ if (start == BreakIterator.DONE) {
+ return null;
+ }
+ return s.substring(start, end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.SENTENCE:
+ try {
+ String s = unoObject.getText();
+ BreakIterator sentence =
+ BreakIterator.getSentenceInstance(getLocale(index));
+ sentence.setText(s);
+ int end = sentence.following(index);
+ end = sentence.previous();
+ int start = sentence.previous();
+ if (start == BreakIterator.DONE) {
+ return null;
+ }
+ return s.substring(start, end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case 4:
+ try {
+ TextSegment ts = unoObject.getTextBeforeIndex(index, AccessibleTextType.LINE);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ // Workaround for #104847#
+ if (index > 0 && getCharCount() == index) {
+ return getBeforeIndex(part, index - 1);
+ }
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ case 5:
+ try {
+ TextSegment ts = unoObject.getTextBeforeIndex(index, AccessibleTextType.ATTRIBUTE_RUN);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ default:
+ return null;
+ }
+ }
+
+
+ /** Returns the string at a given index
+ *
+ * The Java word iterator has a different understanding of what
+ * a word is than the word iterator used by OOo, so we use the
+ * Java iterators to ensure maximal compatibility with Java.
+ */
+ public java.lang.String getAtIndex(int part, int index) {
+ switch (part) {
+ case AccessibleText.CHARACTER:
+ try {
+ String s = unoObject.getText();
+ return s.substring(index, index + 1);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.WORD:
+ try {
+ String s = unoObject.getText();
+ BreakIterator words = BreakIterator.getWordInstance(getLocale(index));
+ words.setText(s);
+ int end = words.following(index);
+ return s.substring(words.previous(), end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case AccessibleText.SENTENCE:
+ try {
+ String s = unoObject.getText();
+ BreakIterator sentence =
+ BreakIterator.getSentenceInstance(getLocale(index));
+ sentence.setText(s);
+ int end = sentence.following(index);
+ return s.substring(sentence.previous(), end);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ case 4:
+ try {
+ TextSegment ts = unoObject.getTextAtIndex(index, AccessibleTextType.LINE);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ // Workaround for #104847#
+ if (index > 0 && getCharCount() == index) {
+ return getAtIndex(part, index - 1);
+ }
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ case 5:
+ try {
+ TextSegment ts = unoObject.getTextAtIndex(index, AccessibleTextType.ATTRIBUTE_RUN);
+ return ts.SegmentText;
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ return null;
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+
+ default:
+ return null;
+ }
+ }
+
+ /** Returns the number of characters (valid indicies) */
+ public int getCharCount() {
+ try {
+ return unoObject.getCharacterCount();
+ } catch (com.sun.star.uno.RuntimeException e) {
+ }
+
+ return 0;
+ }
+
+ /** Returns the portion of the text that is selected */
+ public java.lang.String getSelectedText() {
+ try {
+ return unoObject.getSelectedText();
+ } catch (com.sun.star.uno.RuntimeException e) {
+ }
+
+ return null;
+ }
+
+ /** Determines the bounding box of the character at the given index into the string */
+ public java.awt.Rectangle getCharacterBounds(int index) {
+ try {
+ Rectangle unoRect = unoObject.getCharacterBounds(index);
+ return new java.awt.Rectangle(unoRect.X, unoRect.Y, unoRect.Width, unoRect.Height);
+ } catch (com.sun.star.lang.IndexOutOfBoundsException e) {
+ if ((index > 0) && (getCharCount() == index)) {
+ return getCharacterBounds(index - 1);
+ }
+ } catch (com.sun.star.uno.RuntimeException e) {
+ }
+
+ return new java.awt.Rectangle();
+ }
+}