diff options
Diffstat (limited to 'accessibility/workben/org/openoffice/accessibility/awb/view/TextView.java')
-rw-r--r-- | accessibility/workben/org/openoffice/accessibility/awb/view/TextView.java | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/accessibility/workben/org/openoffice/accessibility/awb/view/TextView.java b/accessibility/workben/org/openoffice/accessibility/awb/view/TextView.java new file mode 100644 index 000000000000..4a838aa85884 --- /dev/null +++ b/accessibility/workben/org/openoffice/accessibility/awb/view/TextView.java @@ -0,0 +1,467 @@ +/************************************************************************* + * + * 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.accessibility.awb.view; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTree; +import javax.swing.tree.TreeNode; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.MutableTreeNode; + +import com.sun.star.accessibility.AccessibleEventId; +import com.sun.star.accessibility.AccessibleEventObject; +import com.sun.star.accessibility.AccessibleTextType; +import com.sun.star.accessibility.AccessibleStateType; +import com.sun.star.accessibility.TextSegment; +import com.sun.star.accessibility.XAccessibleText; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.accessibility.XAccessibleMultiLineText; +import com.sun.star.accessibility.XAccessibleStateSet; +import com.sun.star.awt.Point; +import com.sun.star.awt.Rectangle; +import com.sun.star.beans.PropertyValue; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.uno.UnoRuntime; + +import org.openoffice.accessibility.awb.view.text.CaretSpinnerModel; +import org.openoffice.accessibility.awb.view.text.TextDialogFactory; + + +public class TextView + extends ObjectView + implements ActionListener +{ + + /** Create a TextView when the given object supports the + XAccessibleText interface. + */ + static public ObjectView Create ( + ObjectViewContainer aContainer, + XAccessibleContext xContext) + { + XAccessibleText xText = (XAccessibleText)UnoRuntime.queryInterface( + XAccessibleText.class, xContext); + if (xText != null) + return new TextView (aContainer); + else + return null; + } + + + public TextView (ObjectViewContainer aContainer) + { + super (aContainer); + + ViewGridLayout aLayout = new ViewGridLayout (this); + + maTextLabel = aLayout.AddLabeledString ("Text: "); + maCharacterArrayLabel = aLayout.AddLabeledEntry ("Characters: "); + maCharacterCountLabel = aLayout.AddLabeledEntry ("Character Count: "); + maSelectionLabel = aLayout.AddLabeledEntry ("Selection: "); + maBoundsLabel = aLayout.AddLabeledEntry ("Bounds Test: "); + maCaretPositionSpinner = (JSpinner)aLayout.AddLabeledComponent ( + "Caret position:", new JSpinner()); + Dimension aSize = maCaretPositionSpinner.getSize(); + maCaretPositionSpinner.setPreferredSize (new Dimension (100,20)); + maCaretLineNoLabel = aLayout.AddLabeledEntry ("Line number at caret: "); + maCaretLineTextLabel = aLayout.AddLabeledEntry ("Text of line at caret: "); + maLineNoFromCaretPosLabel = aLayout.AddLabeledEntry ("Line number at index of caret: "); + maLineTextFromCaretPosLabel = aLayout.AddLabeledEntry ("Text of line at index of caret: "); + + JPanel aButtonPanel = new JPanel (); + aLayout.AddComponent (aButtonPanel); + + JButton aButton = new JButton ("select..."); + aButton.setFont (aLayout.GetFont()); + aButton.addActionListener (this); + aButtonPanel.add (aButton); + + aButton = new JButton ("copy..."); + aButton.setFont (aLayout.GetFont()); + aButton.addActionListener (this); + aButtonPanel.add (aButton); + + // A tree that holds the text broken down into various segments. + maTree = new JTree (); + aLayout.AddComponent (new JScrollPane ( + maTree, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + } + + + /** Additionally to the context store a reference to the + XAccessibleText interface. + */ + public void SetObject (XAccessibleContext xObject) + { + mxText = (XAccessibleText)UnoRuntime.queryInterface( + XAccessibleText.class, xObject); + maCaretSpinnerModel = new CaretSpinnerModel(mxText); + maCaretPositionSpinner.setModel (maCaretSpinnerModel); + super.SetObject (xObject); + } + + synchronized public void Destroy () + { + mxText = null; + super.Destroy(); + } + + synchronized public void Update () + { + maCaretPositionSpinner.setEnabled (mxText != null); + DefaultMutableTreeNode aRoot = new DefaultMutableTreeNode ("Text Segments"); + if (mxText == null) + { + maTextLabel.setText ("<null object>"); + maCharacterArrayLabel.setText ("<null object>"); + maCharacterCountLabel.setText ("<null object>"); + maSelectionLabel.setText ("<null object>"); + maBoundsLabel.setText ("<null object>"); + maCaretLineNoLabel.setText ("<null object>"); + maCaretLineTextLabel.setText ("<null object>"); + maLineNoFromCaretPosLabel.setText ("<null object>"); + maLineTextFromCaretPosLabel.setText ("<null object>"); + } + else + { + maTextLabel.setText (mxText.getText()); + maCharacterArrayLabel.setText (GetCharacterArray()); + maCharacterCountLabel.setText ( + Integer.toString(mxText.getCharacterCount())); + // Selection. + maSelectionLabel.setText ( + "[" + mxText.getSelectionStart() + + "," + mxText.getSelectionEnd() + + "] \"" + mxText.getSelectedText() + "\""); + + // Character bounds. + maBoundsLabel.setText (GetTextBoundsString()); + + // Caret position. + maCaretPositionSpinner.setValue (new Integer (mxText.getCaretPosition())); + + // Multi line methods. + XAccessibleMultiLineText xMultiText = (XAccessibleMultiLineText) + UnoRuntime.queryInterface( XAccessibleMultiLineText.class, mxText ); + + if( null != xMultiText ) { + try { + maCaretLineNoLabel.setText ( Integer.toString( xMultiText.getNumberOfLineWithCaret() ) ); + TextSegment ts = xMultiText.getTextAtLineWithCaret(); + maCaretLineTextLabel.setText ( "[" + ts.SegmentStart + + "," + ts.SegmentEnd + + "] \"" + ts.SegmentText + "\""); + maLineNoFromCaretPosLabel.setText ( Integer.toString( xMultiText.getLineNumberAtIndex( mxText.getCaretPosition() ) ) ); + ts = xMultiText.getTextAtLineNumber(xMultiText.getLineNumberAtIndex( mxText.getCaretPosition() ) ); + maLineTextFromCaretPosLabel.setText ( "[" + ts.SegmentStart + + "," + ts.SegmentEnd + + "] \"" + ts.SegmentText + "\""); + } catch( IndexOutOfBoundsException e) { + } + } + + // Text segments. + aRoot.add (CreateNode ("Character", AccessibleTextType.CHARACTER)); + aRoot.add (CreateNode ("Word", AccessibleTextType.WORD)); + aRoot.add (CreateNode ("Sentence", AccessibleTextType.SENTENCE)); + aRoot.add (CreateNode ("Paragraph", AccessibleTextType.PARAGRAPH)); + aRoot.add (CreateNode ("Line", AccessibleTextType.LINE)); + aRoot.add (CreateNode ("Attribute", AccessibleTextType.ATTRIBUTE_RUN)); + aRoot.add (CreateNode ("Glyph", AccessibleTextType.GLYPH)); + } + ((DefaultTreeModel)maTree.getModel()).setRoot (aRoot); + } + + public String GetTitle () + { + return ("Text"); + } + + public void notifyEvent (AccessibleEventObject aEvent) + { + System.out.println (aEvent); + switch (aEvent.EventId) + { + case AccessibleEventId.CARET_CHANGED : + maCaretSpinnerModel.Update(); + Update (); + break; + + case AccessibleEventId.TEXT_CHANGED : + case AccessibleEventId.TEXT_SELECTION_CHANGED: + Update (); + break; + } + } + + public void actionPerformed (ActionEvent aEvent) + { + String sCommand = aEvent.getActionCommand(); + if (sCommand.equals ("select...")) + TextDialogFactory.CreateSelectionDialog (mxContext); + else if (sCommand.equals ("copy...")) + TextDialogFactory.CreateCopyDialog (mxContext); + } + + + + /** Create a string that is a list of all characters returned by the + getCharacter() method. + */ + private String GetCharacterArray () + { + // Do not show more than 30 characters. + int nCharacterCount = mxText.getCharacterCount(); + int nMaxDisplayCount = 30; + + // build up string + StringBuffer aCharacterArray = new StringBuffer(); + int nIndex = 0; + try + { + while (nIndex<nCharacterCount && nIndex<nMaxDisplayCount) + { + aCharacterArray.append (mxText.getCharacter (nIndex)); + if (nIndex < nCharacterCount-1) + aCharacterArray.append (","); + nIndex ++; + } + if (nMaxDisplayCount < nCharacterCount) + aCharacterArray.append (", ..."); + } + catch (IndexOutOfBoundsException e) + { + aCharacterArray.append ("; Index Out Of Bounds at index " + nIndex); + } + + return aCharacterArray.toString(); + } + + + + /** Iterate over all characters and translate their positions + back and forth. + */ + private String GetTextBoundsString () + { + StringBuffer aBuffer = new StringBuffer (); + try + { + // Iterate over all characters in the text. + int nCount = mxText.getCharacterCount(); + for (int i=0; i<nCount; i++) + { + // Get bounds for this character. + Rectangle aBBox = mxText.getCharacterBounds (i); + + // get the character by 'clicking' into the middle of + // the bounds + Point aMiddle = new Point(); + aMiddle.X = aBBox.X + (aBBox.Width / 2) - 1; + aMiddle.Y = aBBox.Y + (aBBox.Height / 2) - 1; + int nIndex = mxText.getIndexAtPoint (aMiddle); + + // get the character, or a '#' for an illegal index + if ((nIndex >= 0) && (nIndex < mxText.getCharacter(i))) + aBuffer.append (mxText.getCharacter(nIndex)); + else + aBuffer.append ('#'); + } + } + catch (IndexOutOfBoundsException aEvent) + { + // Ignore errors. + } + + return aBuffer.toString(); + } + + + + + private final static int BEFORE = -1; + private final static int AT = 0; + private final static int BEHIND = +1; + + private MutableTreeNode CreateNode (String sTitle, short nTextType) + { + DefaultMutableTreeNode aNode = new DefaultMutableTreeNode (sTitle); + + aNode.add (CreateSegmentNode ("Before", nTextType, BEFORE)); + aNode.add (CreateSegmentNode ("At", nTextType, AT)); + aNode.add (CreateSegmentNode ("Behind", nTextType, BEHIND)); + + return aNode; + } + + private MutableTreeNode CreateSegmentNode (String sTitle, short nTextType, int nWhere) + { + TextSegment aSegment; + int nTextLength = mxText.getCharacterCount(); + DefaultMutableTreeNode aNode = new DefaultMutableTreeNode (sTitle); + for (int nIndex=0; nIndex<=nTextLength; /* empty */) + { + aSegment = GetTextSegment (nIndex, nTextType, nWhere); + DefaultMutableTreeNode aSegmentNode = new DefaultMutableTreeNode ( + new StringBuffer ( + Integer.toString (nIndex) + " -> " + + Integer.toString (aSegment.SegmentStart) + " - " + + Integer.toString (aSegment.SegmentEnd) + " : " + + aSegment.SegmentText.toString())); + aNode.add (aSegmentNode); + if (nTextType == AccessibleTextType.ATTRIBUTE_RUN) + AddAttributeNodes (aSegmentNode, aSegment); + if (aSegment.SegmentEnd > nIndex) + nIndex = aSegment.SegmentEnd; + else + nIndex ++; + } + + return aNode; + } + + + private TextSegment GetTextSegment (int nIndex, short nTextType, int nWhere) + { + TextSegment aSegment; + + try + { + switch (nWhere) + { + case BEFORE: + aSegment = mxText.getTextBeforeIndex (nIndex, nTextType); + break; + + case AT: + aSegment = mxText.getTextAtIndex (nIndex, nTextType); + break; + + case BEHIND: + aSegment = mxText.getTextBehindIndex (nIndex, nTextType); + break; + + default: + aSegment = new TextSegment(); + aSegment.SegmentText = new String ("unknown position " + nWhere); + aSegment.SegmentStart = nIndex; + aSegment.SegmentStart = nIndex+1; + break; + } + } + catch (IndexOutOfBoundsException aException) + { + aSegment = new TextSegment (); + aSegment.SegmentText = new String ("Invalid index at ") + nIndex + " : " + + aException.toString(); + aSegment.SegmentStart = nIndex; + aSegment.SegmentEnd = nIndex+1; + } + catch (IllegalArgumentException aException) + { + aSegment = new TextSegment (); + aSegment.SegmentText = new String ("Illegal argument at ") + nIndex + " : " + + aException.toString(); + aSegment.SegmentStart = nIndex; + aSegment.SegmentEnd = nIndex+1; + } + + return aSegment; + } + + + /** Add to the given node one node for every attribute of the given segment. + */ + private void AddAttributeNodes ( + DefaultMutableTreeNode aNode, + TextSegment aSegment) + { + try + { + PropertyValue[] aValues = mxText.getCharacterAttributes ( + aSegment.SegmentStart, aAttributeList); + for (int i=0; i<aValues.length; i++) + aNode.add (new DefaultMutableTreeNode ( + aValues[i].Name + ": " + aValues[i].Value)); + } + catch (IndexOutOfBoundsException aException) + { + aNode.add (new DefaultMutableTreeNode ( + "caught IndexOutOfBoundsException while retrieveing attributes")); + } + } + + private XAccessibleText mxText; + private JLabel + maTextLabel, + maCharacterArrayLabel, + maCharacterCountLabel, + maSelectionLabel, + maBoundsLabel, + maCaretLineNoLabel, + maCaretLineTextLabel, + maLineNoFromCaretPosLabel, + maLineTextFromCaretPosLabel; + + private JSpinner maCaretPositionSpinner; + private JTree maTree; + private CaretSpinnerModel maCaretSpinnerModel; + + private static String[] aAttributeList = new String[] { + "CharBackColor", + "CharColor", + "CharEscapement", + "CharHeight", + "CharPosture", + "CharStrikeout", + "CharUnderline", + "CharWeight", + "ParaAdjust", + "ParaBottomMargin", + "ParaFirstLineIndent", + "ParaLeftMargin", + "ParaLineSpacing", + "ParaRightMargin", + "ParaTabStops"}; +} |