diff options
Diffstat (limited to 'accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java')
-rw-r--r-- | accessibility/bridge/org/openoffice/java/accessibility/AccessibleTextImpl.java | 678 |
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(); + } +} |