/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the 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 (""); maCharacterArrayLabel.setText (""); maCharacterCountLabel.setText (""); maSelectionLabel.setText (""); maBoundsLabel.setText (""); maCaretLineNoLabel.setText (""); maCaretLineTextLabel.setText (""); maLineNoFromCaretPosLabel.setText (""); maLineTextFromCaretPosLabel.setText (""); } 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= 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