summaryrefslogtreecommitdiffstats
path: root/toolkit/test/accessibility/AccessibleTextHandler.java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /toolkit/test/accessibility/AccessibleTextHandler.java
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/test/accessibility/AccessibleTextHandler.java')
-rw-r--r--toolkit/test/accessibility/AccessibleTextHandler.java821
1 files changed, 821 insertions, 0 deletions
diff --git a/toolkit/test/accessibility/AccessibleTextHandler.java b/toolkit/test/accessibility/AccessibleTextHandler.java
new file mode 100644
index 000000000..714bcb591
--- /dev/null
+++ b/toolkit/test/accessibility/AccessibleTextHandler.java
@@ -0,0 +1,821 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JColorChooser;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.text.JTextComponent;
+
+import com.sun.star.accessibility.AccessibleTextType;
+import com.sun.star.accessibility.TextSegment;
+import com.sun.star.accessibility.XAccessibleContext;
+import com.sun.star.accessibility.XAccessibleEditableText;
+import com.sun.star.accessibility.XAccessibleText;
+import com.sun.star.awt.Point;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.lang.IndexOutOfBoundsException;
+import com.sun.star.uno.UnoRuntime;
+
+
+class AccessibleTextHandler extends NodeHandler
+{
+ @Override
+ public NodeHandler createHandler (XAccessibleContext xContext)
+ {
+ XAccessibleText xText = UnoRuntime.queryInterface (
+ XAccessibleText.class, xContext);
+ if (xText != null)
+ return new AccessibleTextHandler (xText);
+ else
+ return null;
+ }
+
+ public AccessibleTextHandler ()
+ {
+ }
+
+ private AccessibleTextHandler (XAccessibleText xText)
+ {
+ if (xText != null)
+ maChildList.setSize (8);
+ }
+
+ @Override
+ public AccessibleTreeNode createChild (AccessibleTreeNode aParent, int nIndex)
+ {
+ AccessibleTreeNode aChild = null;
+ XAccessibleText xText = null;
+ if (aParent instanceof AccTreeNode)
+ xText = ((AccTreeNode)aParent).getText();
+
+ try
+ {
+ if( xText != null )
+ {
+ switch( nIndex )
+ {
+ case 0:
+ aChild = new StringNode (xText.getText(), aParent);
+ break;
+ case 1:
+ aChild = new StringNode ("# chars: " + xText.getCharacterCount(), aParent);
+ break;
+ case 2:
+ aChild = new StringNode (characters( xText ), aParent);
+ break;
+ case 3:
+ aChild = new StringNode ("selection: "
+ + "[" + xText.getSelectionStart()
+ + "," + xText.getSelectionEnd()
+ + "] \"" + xText.getSelectedText() + "\"",
+ aParent);
+ break;
+ case 4:
+ aChild = new StringNode ("getCaretPosition: " + xText.getCaretPosition(), aParent);
+ break;
+ case 5:
+ {
+ VectorNode aVec = new VectorNode("portions", aParent);
+ aChild = aVec;
+ aVec.addChild(
+ textAtIndexNode( xText, "Character",
+ AccessibleTextType.CHARACTER,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Word",
+ AccessibleTextType.WORD,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Sentence",
+ AccessibleTextType.SENTENCE,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Paragraph",
+ AccessibleTextType.PARAGRAPH,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Line",
+ AccessibleTextType.LINE,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Attribute",
+ AccessibleTextType.ATTRIBUTE_RUN,
+ aParent ) );
+ aVec.addChild(
+ textAtIndexNode( xText, "Glyph",
+ AccessibleTextType.GLYPH,
+ aParent ) );
+ }
+ break;
+ case 6:
+ aChild = new StringNode (bounds( xText ), aParent);
+ break;
+ case 7:
+ aChild = getAttributes( xText, aParent );
+ break;
+ default:
+ aChild = new StringNode ("unknown child index " + nIndex, aParent);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ // Return empty child.
+ }
+
+ return aChild;
+ }
+
+
+ private String textAtIndexNodeString(
+ int nStart, int nEnd,
+ String sWord, String sBefore, String sBehind)
+ {
+ return "[" + nStart + "," + nEnd + "] "
+ + "\"" + sWord + "\" \t"
+ + "(" + sBefore + "," + sBehind + ")";
+ }
+
+ /** Create a text node that lists all strings of a particular text type
+ */
+ private AccessibleTreeNode textAtIndexNode(
+ XAccessibleText xText,
+ String sName,
+ short nTextType,
+ AccessibleTreeNode aParent)
+ {
+ VectorNode aNode = new VectorNode (sName, aParent);
+
+ // get word at all positions;
+ // for nicer display, compare current word to previous one and
+ // make a new node for every interval, not for every word
+ int nLength = xText.getCharacterCount();
+ if( nLength > 0 )
+ {
+ try
+ {
+ // sWord + nStart mark the current word
+ // make a node as soon as a new one is found; close the last
+ // one at the end
+ TextSegment sWord = xText.getTextAtIndex(0, nTextType);
+ TextSegment sBefore = xText.getTextBeforeIndex(0, nTextType);
+ TextSegment sBehind = xText.getTextBehindIndex(0, nTextType);
+ int nStart = 0;
+ for(int i = 1; i < nLength; i++)
+ {
+ TextSegment sTmp = xText.getTextAtIndex(i, nTextType);
+ TextSegment sTBef = xText.getTextBeforeIndex(i, nTextType);
+ TextSegment sTBeh = xText.getTextBehindIndex(i, nTextType);
+ if( ! ( sTmp.equals( sWord ) && sTBef.equals( sBefore ) &&
+ sTBeh.equals( sBehind ) ) )
+ {
+ aNode.addChild (new StringNode (textAtIndexNodeString(
+ nStart, i,
+ sWord.SegmentText, sBefore.SegmentText, sBehind.SegmentText), aNode));
+ sWord = sTmp;
+ sBefore = sTBef;
+ sBehind = sTBeh;
+ nStart = i;
+ }
+
+ // don't generate more than 50 children.
+ if (aNode.getChildCount() > 50)
+ {
+ sWord.SegmentText = "...";
+ break;
+ }
+ }
+ aNode.addChild (new StringNode (textAtIndexNodeString(
+ nStart, nLength,
+ sWord.SegmentText, sBefore.SegmentText, sBehind.SegmentText), aNode));
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ aNode.addChild (new StringNode (e.toString(), aNode));
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ aNode.addChild (new StringNode (e.toString(), aNode));
+ }
+ }
+
+ return aNode;
+ }
+
+
+
+ /** getCharacter (display as array string) */
+ private String characters(XAccessibleText xText)
+ {
+ // get count (max. 30)
+ int nChars = xText.getCharacterCount();
+ if( nChars > 30 )
+ nChars = 30;
+
+ // build up string
+ StringBuffer aChars = new StringBuffer();
+ try
+ {
+ aChars.append( '[' );
+ for( int i = 0; i < nChars; i++)
+ {
+ aChars.append( xText.getCharacter(i) );
+ aChars.append( ',' );
+ }
+ if( nChars > 0)
+ {
+ if( nChars == xText.getCharacterCount() )
+ aChars.deleteCharAt( aChars.length() - 1 );
+ else
+ aChars.append( "..." );
+ }
+ aChars.append( ']' );
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ aChars.append( " ERROR " );
+ }
+
+ // return result
+ return "getCharacters: " + aChars;
+ }
+
+
+ /** iterate over characters, and translate their positions
+ * back and forth */
+ private String bounds( XAccessibleText xText )
+ {
+ StringBuffer aBuffer = new StringBuffer( "bounds: " );
+ try
+ {
+ // iterate over characters
+ int nCount = xText.getCharacterCount();
+ for(int i = 0; i < nCount; i++ )
+ {
+ // get bounds for this character
+ Rectangle aRect = xText.getCharacterBounds( i );
+
+ // get the character by 'clicking' into the middle of
+ // the bounds
+ Point aMiddle = new Point();
+ aMiddle.X = aRect.X + (aRect.Width / 2) - 1;
+ aMiddle.Y = aRect.Y + (aRect.Height / 2 ) - 1;
+ int nIndex = xText.getIndexAtPoint( aMiddle );
+
+ // get the character, or a '#' for an illegal index
+ if( (nIndex >= 0) && (nIndex < xText.getCharacter(i)) )
+ aBuffer.append( xText.getCharacter(nIndex) );
+ else
+ aBuffer.append( '#' );
+ }
+ }
+ catch( IndexOutOfBoundsException e )
+ { } // ignore errors
+
+ return aBuffer.toString();
+ }
+
+
+ private AccessibleTreeNode getAttributes( XAccessibleText xText,
+ AccessibleTreeNode aParent)
+ {
+ String[] aAttributeList = new String[] {
+ "CharBackColor",
+ "CharColor",
+ "CharEscapement",
+ "CharHeight",
+ "CharPosture",
+ "CharStrikeout",
+ "CharUnderline",
+ "CharWeight",
+ "ParaAdjust",
+ "ParaBottomMargin",
+ "ParaFirstLineIndent",
+ "ParaLeftMargin",
+ "ParaLineSpacing",
+ "ParaRightMargin",
+ "ParaTabStops"};
+
+ AccessibleTreeNode aRet;
+
+ try
+ {
+ VectorNode aPortions = new VectorNode ("getAttributes", aParent);
+
+ int nIndex = 0;
+ int nLength = xText.getCharacterCount();
+ while( nIndex < nLength )
+ {
+ // get attribute run
+ String aPortion = null;
+ try
+ {
+ aPortion = xText.getTextAtIndex(
+ nIndex, AccessibleTextType.ATTRIBUTE_RUN).SegmentText;
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e)
+ {
+ aPortion = "";
+ }
+
+ // get attributes and make node with attribute children
+ PropertyValue[] aValues = xText.getCharacterAttributes(nIndex, aAttributeList);
+ VectorNode aAttrs = new VectorNode (aPortion, aPortions);
+ for( int i = 0; i < aValues.length; i++ )
+ {
+ new StringNode( aValues[i].Name + ": " + aValues[i].Value,
+ aAttrs );
+ }
+
+ // get next portion, but advance at least one
+ nIndex += (aPortion.length() > 0) ? aPortion.length() : 1;
+ }
+
+ aRet = aPortions;
+ }
+ catch( UnknownPropertyException e )
+ {
+ aRet = new StringNode( "Exception caught:" + e, aParent );
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ aRet = new StringNode( "Exception caught:" + e, aParent );
+ }
+
+ return aRet;
+ }
+
+
+ private static String[] aTextActions =
+ new String[] { "select...", "copy..." };
+ private static String[] aEditableTextActions =
+ new String[] { "select...", "copy...",
+ "cut...", "paste...", "edit...", "format..." };
+
+ @Override
+ public String[] getActions (AccessibleTreeNode aNode)
+ {
+ XAccessibleEditableText xEText = null;
+ if (aNode instanceof AccTreeNode)
+ xEText = ((AccTreeNode)aNode).getEditText ();
+
+ return (xEText == null) ? aTextActions : aEditableTextActions;
+ }
+
+ @Override
+ public void performAction (AccessibleTreeNode aNode, int nIndex)
+ {
+ if ( ! (aNode instanceof AccTreeNode))
+ return;
+
+ AccTreeNode aATNode = (AccTreeNode)aNode;
+ TextActionDialog aDialog = null;
+
+ // create proper dialog
+ switch( nIndex )
+ {
+ case 0:
+ aDialog = new TextActionDialog( aATNode,
+ "Select range:",
+ "select" )
+ {
+ @Override
+ boolean action(
+ JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException
+ {
+ return aNode.getText().setSelection(
+ getSelectionStart(),
+ getSelectionEnd() );
+ }
+ };
+ break;
+ case 1:
+ aDialog = new TextActionDialog( aATNode,
+ "Select range and copy:",
+ "copy" )
+ {
+ @Override
+ boolean action(
+ JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException
+ {
+ return aNode.getText().copyText(
+ getSelectionStart(),
+ getSelectionEnd() );
+ }
+ };
+ break;
+ case 2:
+ aDialog = new TextActionDialog( aATNode,
+ "Select range and cut:",
+ "cut" )
+ {
+ @Override
+ boolean action(
+ JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException
+ {
+ return aNode.getEditText().cutText(
+ getSelectionStart(),
+ getSelectionEnd() );
+ }
+ };
+ break;
+ case 3:
+ aDialog = new TextActionDialog( aATNode,
+ "Place Caret and paste:",
+ "paste" )
+ {
+ @Override
+ boolean action(
+ JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException
+ {
+ return aNode.getEditText().pasteText(
+ aText.getCaretPosition() );
+ }
+ };
+ break;
+ case 4:
+ aDialog = new TextEditDialog( aATNode, "Edit text:",
+ "edit" );
+ break;
+ case 5:
+ aDialog = new TextAttributeDialog( aATNode );
+ break;
+ }
+
+ if( aDialog != null )
+ aDialog.setVisible(true);
+ }
+
+}
+
+/**
+ * Display a dialog with a text field and a pair of cancel/do-it buttons
+ */
+abstract class TextActionDialog extends JDialog
+ implements ActionListener
+{
+ private AccTreeNode aNode;
+ JTextArea aText;
+ private String sName;
+ private JCheckBox aIndexToggle;
+
+ public TextActionDialog( AccTreeNode aNd,
+ String sExplanation,
+ String sButtonText )
+ {
+ super( AccessibilityWorkBench.Instance() );
+
+ aNode = aNd;
+ sName = sButtonText;
+ init( sExplanation, aNode.getText().getText(), sButtonText );
+ setSize( 350, 225 );
+ }
+
+ /** build dialog */
+ protected void init( String sExplanation,
+ String sText,
+ String sButtonText )
+ {
+ setTitle( sName );
+
+ // vertical stacking of the elements
+ Container aContent = getContentPane();
+
+ // label with explanation
+ if( sExplanation.length() > 0 )
+ aContent.add( new JLabel( sExplanation ), BorderLayout.NORTH );
+
+ // the text field
+ aText = new JTextArea();
+ aText.setText( sText );
+ aText.setColumns( Math.min( Math.max( 40, sText.length() ), 20 ) );
+ aText.setRows( sText.length() / 40 + 1 );
+ aText.setLineWrap( true );
+ aText.setEditable( false );
+ aContent.add( aText, BorderLayout.CENTER );
+
+ JPanel aButtons = new JPanel();
+ aButtons.setLayout( new FlowLayout() );
+ aIndexToggle = new JCheckBox( "reverse selection" );
+ aButtons.add( aIndexToggle );
+ JButton aActionButton = new JButton( sButtonText );
+ aActionButton.setActionCommand( "Action" );
+ aActionButton.addActionListener( this );
+ aButtons.add( aActionButton );
+ JButton aCancelButton = new JButton( "cancel" );
+ aCancelButton.setActionCommand( "Cancel" );
+ aCancelButton.addActionListener( this );
+ aButtons.add( aCancelButton );
+
+ // add Panel with buttons
+ aContent.add( aButtons, BorderLayout.SOUTH );
+ }
+
+ private void cancel()
+ {
+ setVisible(false);
+ dispose();
+ }
+
+ private void action()
+ {
+ String sError = null;
+ try
+ {
+ boolean bSuccess = action( aText, aNode );
+ if( !bSuccess )
+ sError = "Can't execute";
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ sError = "Index out of bounds";
+ }
+
+ if( sError != null )
+ JOptionPane.showMessageDialog( AccessibilityWorkBench.Instance(),
+ sError, sName,
+ JOptionPane.ERROR_MESSAGE);
+
+ cancel();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ String sCommand = e.getActionCommand();
+
+ if( "Cancel".equals( sCommand ) )
+ cancel();
+ else if( "Action".equals( sCommand ) )
+ action();
+ }
+
+
+ int getSelectionStart() { return getSelection(true); }
+ int getSelectionEnd() { return getSelection(false); }
+ private int getSelection(boolean bStart)
+ {
+ return ( bStart ^ aIndexToggle.isSelected() )
+ ? aText.getSelectionStart() : aText.getSelectionEnd();
+ }
+
+
+
+ /** override this for dialog-specific action */
+ abstract boolean action( JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException;
+}
+
+
+class TextEditDialog extends TextActionDialog
+{
+ public TextEditDialog( AccTreeNode aNode,
+ String sExplanation,
+ String sButtonText )
+ {
+ super( aNode, sExplanation, sButtonText );
+ }
+
+ @Override
+ protected void init( String sExplanation,
+ String sText,
+ String sButtonText )
+ {
+ super.init( sExplanation, sText, sButtonText );
+ aText.setEditable( true );
+ }
+
+
+ /** edit the text */
+ @Override
+ boolean action( JTextComponent aText, AccTreeNode aNode )
+ {
+ // is this text editable? if not, fudge you and return
+ XAccessibleEditableText xEdit = aNode.getEditText();
+ return ( xEdit == null ) ? false :
+ updateText( xEdit, aText.getText() );
+ }
+
+
+ /** update the text */
+ private boolean updateText( XAccessibleEditableText xEdit, String sNew )
+ {
+ String sOld = xEdit.getText();
+
+ // false alarm? Early out if no change was done!
+ if( sOld.equals( sNew ) )
+ return false;
+
+ // get the minimum length of both strings
+ int nMinLength = sOld.length();
+ if( sNew.length() < nMinLength )
+ nMinLength = sNew.length();
+
+ // count equal characters from front and end
+ int nFront = 0;
+ while( (nFront < nMinLength) &&
+ (sNew.charAt(nFront) == sOld.charAt(nFront)) ) {
+ nFront++;
+ }
+ int nBack = 0;
+ while( (nBack < nMinLength) &&
+ ( sNew.charAt(sNew.length()-nBack-1) ==
+ sOld.charAt(sOld.length()-nBack-1) ) ) {
+ nBack++;
+ }
+ if( nFront + nBack > nMinLength )
+ nBack = nMinLength - nFront;
+
+ // so... the first nFront and the last nBack characters
+ // are the same. Change the others!
+ String sDel = sOld.substring( nFront, sOld.length() - nBack );
+ String sIns = sNew.substring( nFront, sNew.length() - nBack );
+
+ System.out.println("edit text: " +
+ sOld.substring(0, nFront) +
+ " [ " + sDel + " -> " + sIns + " ] " +
+ sOld.substring(sOld.length() - nBack) );
+
+ boolean bRet = false;
+ try
+ {
+ // edit the text, and use
+ // (set|insert|delete|replace)Text as needed
+ if( nFront+nBack == 0 )
+ bRet = xEdit.setText( sIns );
+ else if( sDel.length() == 0 )
+ bRet = xEdit.insertText( sIns, nFront );
+ else if( sIns.length() == 0 )
+ bRet = xEdit.deleteText( nFront, sOld.length()-nBack );
+ else
+ bRet = xEdit.replaceText(nFront, sOld.length()-nBack,sIns);
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ bRet = false;
+ }
+
+ return bRet;
+ }
+}
+
+
+class TextAttributeDialog extends TextActionDialog
+{
+ public TextAttributeDialog(
+ AccTreeNode aNode )
+ {
+ super( aNode, "Choose attributes, select text, and press 'Set':",
+ "set" );
+ }
+
+ private JCheckBox aBold, aUnderline, aItalics;
+ private Color aForeground, aBackground;
+
+ @Override
+ protected void init( String sExplanation,
+ String sText,
+ String sButtonText )
+ {
+ super.init( sExplanation, sText, sButtonText );
+
+ aForeground = Color.black;
+ aBackground = Color.white;
+
+ JPanel aAttr = new JPanel();
+ aAttr.setLayout( new BoxLayout( aAttr, BoxLayout.Y_AXIS ) );
+
+ aBold = new JCheckBox( "bold" );
+ aUnderline = new JCheckBox( "underline" );
+ aItalics = new JCheckBox( "italics" );
+
+ JButton aForeButton = new JButton("Foreground", new ColorIcon(true));
+ aForeButton.addActionListener( new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ aForeground = JColorChooser.showDialog(
+ TextAttributeDialog.this,
+ "Select Foreground Color",
+ aForeground);
+ }
+ } );
+
+ JButton aBackButton = new JButton("Background", new ColorIcon(false));
+ aBackButton.addActionListener( new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ aBackground = JColorChooser.showDialog(
+ TextAttributeDialog.this,
+ "Select Background Color",
+ aBackground);
+ }
+ } );
+
+ aAttr.add( aBold );
+ aAttr.add( aUnderline );
+ aAttr.add( aItalics );
+ aAttr.add( aForeButton );
+ aAttr.add( aBackButton );
+
+ getContentPane().add( aAttr, BorderLayout.WEST );
+ }
+
+
+ private class ColorIcon implements Icon
+ {
+ private boolean bForeground;
+ private static final int nHeight = 16;
+ private static final int nWidth = 16;
+
+ public ColorIcon(boolean bWhich) { bForeground = bWhich; }
+ public int getIconHeight() { return nHeight; }
+ public int getIconWidth() { return nWidth; }
+ public void paintIcon(Component c, Graphics g, int x, int y)
+ {
+ g.setColor( getColor() );
+ g.fillRect( x, y, nHeight, nWidth );
+ g.setColor( c.getForeground() );
+ g.drawRect( x, y, nHeight, nWidth );
+ }
+ Color getColor()
+ {
+ return bForeground ? aForeground : aBackground;
+ }
+ }
+
+
+
+ /** edit the text */
+ @Override
+ boolean action( JTextComponent aText, AccTreeNode aNode )
+ throws IndexOutOfBoundsException
+ {
+ // is this text editable? if not, fudge you and return
+ XAccessibleEditableText xEdit = aNode.getEditText();
+ boolean bSuccess = false;
+ if( xEdit != null )
+ {
+ PropertyValue[] aSequence = new PropertyValue[6];
+ aSequence[0] = new PropertyValue();
+ aSequence[0].Name = "CharWeight";
+ aSequence[0].Value = Integer.valueOf( aBold.isSelected() ? 150 : 100 );
+ aSequence[1] = new PropertyValue();
+ aSequence[1].Name = "CharUnderline";
+ aSequence[1].Value = Integer.valueOf( aUnderline.isSelected() ? 1 : 0 );
+ aSequence[2] = new PropertyValue();
+ aSequence[2].Name = "CharBackColor";
+ aSequence[2].Value = Integer.valueOf( aBackground.getRGB() );
+ aSequence[3] = new PropertyValue();
+ aSequence[3].Name = "CharColor";
+ aSequence[3].Value = Integer.valueOf( aForeground.getRGB() );
+ aSequence[4] = new PropertyValue();
+ aSequence[4].Name = "CharPosture";
+ aSequence[4].Value = Integer.valueOf( aItalics.isSelected() ? 1 : 0 );
+ aSequence[5] = new PropertyValue();
+ aSequence[5].Name = "CharBackTransparent";
+ aSequence[5].Value = Boolean.FALSE;
+
+ bSuccess = xEdit.setAttributes( getSelectionStart(),
+ getSelectionEnd(),
+ aSequence );
+ }
+ return bSuccess;
+ }
+
+}