1*cdf0e10cSrcweir 2*cdf0e10cSrcweir import com.sun.star.accessibility.AccessibleTextType; 3*cdf0e10cSrcweir import com.sun.star.accessibility.TextSegment; 4*cdf0e10cSrcweir import com.sun.star.accessibility.XAccessibleContext; 5*cdf0e10cSrcweir import com.sun.star.accessibility.XAccessibleText; 6*cdf0e10cSrcweir import com.sun.star.accessibility.XAccessibleEditableText; 7*cdf0e10cSrcweir 8*cdf0e10cSrcweir import com.sun.star.awt.Rectangle; 9*cdf0e10cSrcweir import com.sun.star.awt.Point; 10*cdf0e10cSrcweir import com.sun.star.uno.UnoRuntime; 11*cdf0e10cSrcweir import com.sun.star.lang.IndexOutOfBoundsException; 12*cdf0e10cSrcweir import com.sun.star.beans.PropertyValue; 13*cdf0e10cSrcweir 14*cdf0e10cSrcweir import java.util.Vector; 15*cdf0e10cSrcweir import java.awt.Container; 16*cdf0e10cSrcweir import java.awt.FlowLayout; 17*cdf0e10cSrcweir import java.awt.BorderLayout; 18*cdf0e10cSrcweir import java.awt.Color; 19*cdf0e10cSrcweir import java.awt.Component; 20*cdf0e10cSrcweir import java.awt.Graphics; 21*cdf0e10cSrcweir import java.awt.event.ActionListener; 22*cdf0e10cSrcweir import java.awt.event.ActionEvent; 23*cdf0e10cSrcweir import javax.swing.JDialog; 24*cdf0e10cSrcweir import javax.swing.JButton; 25*cdf0e10cSrcweir import javax.swing.JPanel; 26*cdf0e10cSrcweir import javax.swing.JLabel; 27*cdf0e10cSrcweir import javax.swing.Icon; 28*cdf0e10cSrcweir import javax.swing.JTextArea; 29*cdf0e10cSrcweir import javax.swing.JOptionPane; 30*cdf0e10cSrcweir import javax.swing.JCheckBox; 31*cdf0e10cSrcweir import javax.swing.JColorChooser; 32*cdf0e10cSrcweir import javax.swing.BoxLayout; 33*cdf0e10cSrcweir import javax.swing.text.JTextComponent; 34*cdf0e10cSrcweir 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir class AccessibleTextHandler extends NodeHandler 37*cdf0e10cSrcweir { 38*cdf0e10cSrcweir public NodeHandler createHandler (XAccessibleContext xContext) 39*cdf0e10cSrcweir { 40*cdf0e10cSrcweir XAccessibleText xText = (XAccessibleText) UnoRuntime.queryInterface ( 41*cdf0e10cSrcweir XAccessibleText.class, xContext); 42*cdf0e10cSrcweir if (xText != null) 43*cdf0e10cSrcweir return new AccessibleTextHandler (xText); 44*cdf0e10cSrcweir else 45*cdf0e10cSrcweir return null; 46*cdf0e10cSrcweir } 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir public AccessibleTextHandler () 49*cdf0e10cSrcweir { 50*cdf0e10cSrcweir } 51*cdf0e10cSrcweir 52*cdf0e10cSrcweir public AccessibleTextHandler (XAccessibleText xText) 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir if (xText != null) 55*cdf0e10cSrcweir maChildList.setSize (8); 56*cdf0e10cSrcweir } 57*cdf0e10cSrcweir 58*cdf0e10cSrcweir public AccessibleTreeNode createChild (AccessibleTreeNode aParent, int nIndex) 59*cdf0e10cSrcweir { 60*cdf0e10cSrcweir AccessibleTreeNode aChild = null; 61*cdf0e10cSrcweir XAccessibleText xText = null; 62*cdf0e10cSrcweir if (aParent instanceof AccTreeNode) 63*cdf0e10cSrcweir xText = ((AccTreeNode)aParent).getText(); 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir try 66*cdf0e10cSrcweir { 67*cdf0e10cSrcweir if( xText != null ) 68*cdf0e10cSrcweir { 69*cdf0e10cSrcweir switch( nIndex ) 70*cdf0e10cSrcweir { 71*cdf0e10cSrcweir case 0: 72*cdf0e10cSrcweir aChild = new StringNode (xText.getText(), aParent); 73*cdf0e10cSrcweir break; 74*cdf0e10cSrcweir case 1: 75*cdf0e10cSrcweir aChild = new StringNode ("# chars: " + xText.getCharacterCount(), aParent); 76*cdf0e10cSrcweir break; 77*cdf0e10cSrcweir case 2: 78*cdf0e10cSrcweir aChild = new StringNode (characters( xText ), aParent); 79*cdf0e10cSrcweir break; 80*cdf0e10cSrcweir case 3: 81*cdf0e10cSrcweir aChild = new StringNode ("selection: " 82*cdf0e10cSrcweir + "[" + xText.getSelectionStart() 83*cdf0e10cSrcweir + "," + xText.getSelectionEnd() 84*cdf0e10cSrcweir + "] \"" + xText.getSelectedText() + "\"", 85*cdf0e10cSrcweir aParent); 86*cdf0e10cSrcweir break; 87*cdf0e10cSrcweir case 4: 88*cdf0e10cSrcweir aChild = new StringNode ("getCaretPosition: " + xText.getCaretPosition(), aParent); 89*cdf0e10cSrcweir break; 90*cdf0e10cSrcweir case 5: 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir VectorNode aVec = new VectorNode("portions", aParent); 93*cdf0e10cSrcweir aChild = aVec; 94*cdf0e10cSrcweir aVec.addChild( 95*cdf0e10cSrcweir textAtIndexNode( xText, "Character", 96*cdf0e10cSrcweir AccessibleTextType.CHARACTER, 97*cdf0e10cSrcweir aParent ) ); 98*cdf0e10cSrcweir aVec.addChild( 99*cdf0e10cSrcweir textAtIndexNode( xText, "Word", 100*cdf0e10cSrcweir AccessibleTextType.WORD, 101*cdf0e10cSrcweir aParent ) ); 102*cdf0e10cSrcweir aVec.addChild( 103*cdf0e10cSrcweir textAtIndexNode( xText, "Sentence", 104*cdf0e10cSrcweir AccessibleTextType.SENTENCE, 105*cdf0e10cSrcweir aParent ) ); 106*cdf0e10cSrcweir aVec.addChild( 107*cdf0e10cSrcweir textAtIndexNode( xText, "Paragraph", 108*cdf0e10cSrcweir AccessibleTextType.PARAGRAPH, 109*cdf0e10cSrcweir aParent ) ); 110*cdf0e10cSrcweir aVec.addChild( 111*cdf0e10cSrcweir textAtIndexNode( xText, "Line", 112*cdf0e10cSrcweir AccessibleTextType.LINE, 113*cdf0e10cSrcweir aParent ) ); 114*cdf0e10cSrcweir aVec.addChild( 115*cdf0e10cSrcweir textAtIndexNode( xText, "Attribute", 116*cdf0e10cSrcweir AccessibleTextType.ATTRIBUTE_RUN, 117*cdf0e10cSrcweir aParent ) ); 118*cdf0e10cSrcweir aVec.addChild( 119*cdf0e10cSrcweir textAtIndexNode( xText, "Glyph", 120*cdf0e10cSrcweir AccessibleTextType.GLYPH, 121*cdf0e10cSrcweir aParent ) ); 122*cdf0e10cSrcweir } 123*cdf0e10cSrcweir break; 124*cdf0e10cSrcweir case 6: 125*cdf0e10cSrcweir aChild = new StringNode (bounds( xText ), aParent); 126*cdf0e10cSrcweir break; 127*cdf0e10cSrcweir case 7: 128*cdf0e10cSrcweir aChild = getAttributes( xText, aParent ); 129*cdf0e10cSrcweir break; 130*cdf0e10cSrcweir default: 131*cdf0e10cSrcweir aChild = new StringNode ("unknown child index " + nIndex, aParent); 132*cdf0e10cSrcweir } 133*cdf0e10cSrcweir } 134*cdf0e10cSrcweir } 135*cdf0e10cSrcweir catch (Exception e) 136*cdf0e10cSrcweir { 137*cdf0e10cSrcweir // Return empty child. 138*cdf0e10cSrcweir } 139*cdf0e10cSrcweir 140*cdf0e10cSrcweir return aChild; 141*cdf0e10cSrcweir } 142*cdf0e10cSrcweir 143*cdf0e10cSrcweir 144*cdf0e10cSrcweir private String textAtIndexNodeString( 145*cdf0e10cSrcweir int nStart, int nEnd, 146*cdf0e10cSrcweir String sWord, String sBefore, String sBehind) 147*cdf0e10cSrcweir { 148*cdf0e10cSrcweir return "[" + nStart + "," + nEnd + "] " 149*cdf0e10cSrcweir + "\"" + sWord + "\" \t" 150*cdf0e10cSrcweir + "(" + sBefore + "," 151*cdf0e10cSrcweir + "" + sBehind + ")"; 152*cdf0e10cSrcweir } 153*cdf0e10cSrcweir 154*cdf0e10cSrcweir /** Create a text node that lists all strings of a particular text type 155*cdf0e10cSrcweir */ 156*cdf0e10cSrcweir private AccessibleTreeNode textAtIndexNode( 157*cdf0e10cSrcweir XAccessibleText xText, 158*cdf0e10cSrcweir String sName, 159*cdf0e10cSrcweir short nTextType, 160*cdf0e10cSrcweir AccessibleTreeNode aParent) 161*cdf0e10cSrcweir { 162*cdf0e10cSrcweir VectorNode aNode = new VectorNode (sName, aParent); 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir // get word at all positions; 165*cdf0e10cSrcweir // for nicer display, compare current word to previous one and 166*cdf0e10cSrcweir // make a new node for every interval, not for every word 167*cdf0e10cSrcweir int nLength = xText.getCharacterCount(); 168*cdf0e10cSrcweir if( nLength > 0 ) 169*cdf0e10cSrcweir { 170*cdf0e10cSrcweir try 171*cdf0e10cSrcweir { 172*cdf0e10cSrcweir // sWord + nStart mark the current word 173*cdf0e10cSrcweir // make a node as soon as a new one is found; close the last 174*cdf0e10cSrcweir // one at the end 175*cdf0e10cSrcweir TextSegment sWord = xText.getTextAtIndex(0, nTextType); 176*cdf0e10cSrcweir TextSegment sBefore = xText.getTextBeforeIndex(0, nTextType); 177*cdf0e10cSrcweir TextSegment sBehind = xText.getTextBehindIndex(0, nTextType); 178*cdf0e10cSrcweir int nStart = 0; 179*cdf0e10cSrcweir for(int i = 1; i < nLength; i++) 180*cdf0e10cSrcweir { 181*cdf0e10cSrcweir TextSegment sTmp = xText.getTextAtIndex(i, nTextType); 182*cdf0e10cSrcweir TextSegment sTBef = xText.getTextBeforeIndex(i, nTextType); 183*cdf0e10cSrcweir TextSegment sTBeh = xText.getTextBehindIndex(i, nTextType); 184*cdf0e10cSrcweir if( ! ( sTmp.equals( sWord ) && sTBef.equals( sBefore ) && 185*cdf0e10cSrcweir sTBeh.equals( sBehind ) ) ) 186*cdf0e10cSrcweir { 187*cdf0e10cSrcweir aNode.addChild (new StringNode (textAtIndexNodeString( 188*cdf0e10cSrcweir nStart, i, 189*cdf0e10cSrcweir sWord.SegmentText, sBefore.SegmentText, sBehind.SegmentText), aNode)); 190*cdf0e10cSrcweir sWord = sTmp; 191*cdf0e10cSrcweir sBefore = sTBef; 192*cdf0e10cSrcweir sBehind = sTBeh; 193*cdf0e10cSrcweir nStart = i; 194*cdf0e10cSrcweir } 195*cdf0e10cSrcweir 196*cdf0e10cSrcweir // don't generate more than 50 children. 197*cdf0e10cSrcweir if (aNode.getChildCount() > 50) 198*cdf0e10cSrcweir { 199*cdf0e10cSrcweir sWord.SegmentText = "..."; 200*cdf0e10cSrcweir break; 201*cdf0e10cSrcweir } 202*cdf0e10cSrcweir } 203*cdf0e10cSrcweir aNode.addChild (new StringNode (textAtIndexNodeString( 204*cdf0e10cSrcweir nStart, nLength, 205*cdf0e10cSrcweir sWord.SegmentText, sBefore.SegmentText, sBehind.SegmentText), aNode)); 206*cdf0e10cSrcweir } 207*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 208*cdf0e10cSrcweir { 209*cdf0e10cSrcweir aNode.addChild (new StringNode (e.toString(), aNode)); 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir catch (com.sun.star.lang.IllegalArgumentException e) 212*cdf0e10cSrcweir { 213*cdf0e10cSrcweir aNode.addChild (new StringNode (e.toString(), aNode)); 214*cdf0e10cSrcweir } 215*cdf0e10cSrcweir } 216*cdf0e10cSrcweir 217*cdf0e10cSrcweir return aNode; 218*cdf0e10cSrcweir } 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir /** getCharacter (display as array string) */ 223*cdf0e10cSrcweir private String characters(XAccessibleText xText) 224*cdf0e10cSrcweir { 225*cdf0e10cSrcweir // get count (max. 30) 226*cdf0e10cSrcweir int nChars = xText.getCharacterCount(); 227*cdf0e10cSrcweir if( nChars > 30 ) 228*cdf0e10cSrcweir nChars = 30; 229*cdf0e10cSrcweir 230*cdf0e10cSrcweir // build up string 231*cdf0e10cSrcweir StringBuffer aChars = new StringBuffer(); 232*cdf0e10cSrcweir try 233*cdf0e10cSrcweir { 234*cdf0e10cSrcweir aChars.append( "[" ); 235*cdf0e10cSrcweir for( int i = 0; i < nChars; i++) 236*cdf0e10cSrcweir { 237*cdf0e10cSrcweir aChars.append( xText.getCharacter(i) ); 238*cdf0e10cSrcweir aChars.append( "," ); 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir if( nChars > 0) 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir if( nChars == xText.getCharacterCount() ) 243*cdf0e10cSrcweir aChars.deleteCharAt( aChars.length() - 1 ); 244*cdf0e10cSrcweir else 245*cdf0e10cSrcweir aChars.append( "..." ); 246*cdf0e10cSrcweir } 247*cdf0e10cSrcweir aChars.append( "]" ); 248*cdf0e10cSrcweir } 249*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 250*cdf0e10cSrcweir { 251*cdf0e10cSrcweir aChars.append( " ERROR " ); 252*cdf0e10cSrcweir } 253*cdf0e10cSrcweir 254*cdf0e10cSrcweir // return result 255*cdf0e10cSrcweir return "getCharacters: " + aChars; 256*cdf0e10cSrcweir } 257*cdf0e10cSrcweir 258*cdf0e10cSrcweir 259*cdf0e10cSrcweir /** iterate over characters, and translate their positions 260*cdf0e10cSrcweir * back and forth */ 261*cdf0e10cSrcweir private String bounds( XAccessibleText xText ) 262*cdf0e10cSrcweir { 263*cdf0e10cSrcweir StringBuffer aBuffer = new StringBuffer( "bounds: " ); 264*cdf0e10cSrcweir try 265*cdf0e10cSrcweir { 266*cdf0e10cSrcweir // iterate over characters 267*cdf0e10cSrcweir int nCount = xText.getCharacterCount(); 268*cdf0e10cSrcweir for(int i = 0; i < nCount; i++ ) 269*cdf0e10cSrcweir { 270*cdf0e10cSrcweir // get bounds for this character 271*cdf0e10cSrcweir Rectangle aRect = xText.getCharacterBounds( i ); 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // get the character by 'clicking' into the middle of 274*cdf0e10cSrcweir // the bounds 275*cdf0e10cSrcweir Point aMiddle = new Point(); 276*cdf0e10cSrcweir aMiddle.X = aRect.X + (aRect.Width / 2) - 1; 277*cdf0e10cSrcweir aMiddle.Y = aRect.Y + (aRect.Height / 2 ) - 1; 278*cdf0e10cSrcweir int nIndex = xText.getIndexAtPoint( aMiddle ); 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir // get the character, or a '#' for an illegal index 281*cdf0e10cSrcweir if( (nIndex >= 0) && (nIndex < xText.getCharacter(i)) ) 282*cdf0e10cSrcweir aBuffer.append( xText.getCharacter(nIndex) ); 283*cdf0e10cSrcweir else 284*cdf0e10cSrcweir aBuffer.append( '#' ); 285*cdf0e10cSrcweir } 286*cdf0e10cSrcweir } 287*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 288*cdf0e10cSrcweir { ; } // ignore errors 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir return aBuffer.toString(); 291*cdf0e10cSrcweir } 292*cdf0e10cSrcweir 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir private AccessibleTreeNode getAttributes( XAccessibleText xText, 295*cdf0e10cSrcweir AccessibleTreeNode aParent) 296*cdf0e10cSrcweir { 297*cdf0e10cSrcweir String[] aAttributeList = new String[] { 298*cdf0e10cSrcweir "CharBackColor", 299*cdf0e10cSrcweir "CharColor", 300*cdf0e10cSrcweir "CharEscapement", 301*cdf0e10cSrcweir "CharHeight", 302*cdf0e10cSrcweir "CharPosture", 303*cdf0e10cSrcweir "CharStrikeout", 304*cdf0e10cSrcweir "CharUnderline", 305*cdf0e10cSrcweir "CharWeight", 306*cdf0e10cSrcweir "ParaAdjust", 307*cdf0e10cSrcweir "ParaBottomMargin", 308*cdf0e10cSrcweir "ParaFirstLineIndent", 309*cdf0e10cSrcweir "ParaLeftMargin", 310*cdf0e10cSrcweir "ParaLineSpacing", 311*cdf0e10cSrcweir "ParaRightMargin", 312*cdf0e10cSrcweir "ParaTabStops"}; 313*cdf0e10cSrcweir 314*cdf0e10cSrcweir AccessibleTreeNode aRet; 315*cdf0e10cSrcweir 316*cdf0e10cSrcweir try 317*cdf0e10cSrcweir { 318*cdf0e10cSrcweir VectorNode aPortions = new VectorNode ("getAttributes", aParent); 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir int nIndex = 0; 321*cdf0e10cSrcweir int nLength = xText.getCharacterCount(); 322*cdf0e10cSrcweir while( nIndex < nLength ) 323*cdf0e10cSrcweir { 324*cdf0e10cSrcweir // get attribute run 325*cdf0e10cSrcweir String aPortion = null; 326*cdf0e10cSrcweir try 327*cdf0e10cSrcweir { 328*cdf0e10cSrcweir aPortion = xText.getTextAtIndex( 329*cdf0e10cSrcweir nIndex, AccessibleTextType.ATTRIBUTE_RUN).SegmentText; 330*cdf0e10cSrcweir } 331*cdf0e10cSrcweir catch(com.sun.star.lang.IllegalArgumentException e) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir aPortion = new String (""); 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir 336*cdf0e10cSrcweir // get attributes and make node with attribute children 337*cdf0e10cSrcweir PropertyValue[] aValues = xText.getCharacterAttributes(nIndex, aAttributeList); 338*cdf0e10cSrcweir VectorNode aAttrs = new VectorNode (aPortion, aPortions); 339*cdf0e10cSrcweir for( int i = 0; i < aValues.length; i++ ) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir new StringNode( aValues[i].Name + ": " + aValues[i].Value, 342*cdf0e10cSrcweir aAttrs ); 343*cdf0e10cSrcweir } 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir // get next portion, but advance at least one 346*cdf0e10cSrcweir nIndex += (aPortion.length() > 0) ? aPortion.length() : 1; 347*cdf0e10cSrcweir } 348*cdf0e10cSrcweir 349*cdf0e10cSrcweir aRet = aPortions; 350*cdf0e10cSrcweir } 351*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 352*cdf0e10cSrcweir { 353*cdf0e10cSrcweir aRet = new StringNode( "Exception caught:" + e, aParent ); 354*cdf0e10cSrcweir } 355*cdf0e10cSrcweir 356*cdf0e10cSrcweir return aRet; 357*cdf0e10cSrcweir } 358*cdf0e10cSrcweir 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir static String[] aTextActions = 361*cdf0e10cSrcweir new String[] { "select...", "copy..." }; 362*cdf0e10cSrcweir static String[] aEditableTextActions = 363*cdf0e10cSrcweir new String[] { "select...", "copy...", 364*cdf0e10cSrcweir "cut...", "paste...", "edit...", "format..." }; 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir public String[] getActions (AccessibleTreeNode aNode) 367*cdf0e10cSrcweir { 368*cdf0e10cSrcweir XAccessibleEditableText xEText = null; 369*cdf0e10cSrcweir if (aNode instanceof AccTreeNode) 370*cdf0e10cSrcweir xEText = ((AccTreeNode)aNode).getEditText (); 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir return (xEText == null) ? aTextActions : aEditableTextActions; 373*cdf0e10cSrcweir } 374*cdf0e10cSrcweir 375*cdf0e10cSrcweir public void performAction (AccessibleTreeNode aNode, int nIndex) 376*cdf0e10cSrcweir { 377*cdf0e10cSrcweir if ( ! (aNode instanceof AccTreeNode)) 378*cdf0e10cSrcweir return; 379*cdf0e10cSrcweir 380*cdf0e10cSrcweir AccTreeNode aATNode = (AccTreeNode)aNode; 381*cdf0e10cSrcweir TextActionDialog aDialog = null; 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir // create proper dialog 384*cdf0e10cSrcweir switch( nIndex ) 385*cdf0e10cSrcweir { 386*cdf0e10cSrcweir case 0: 387*cdf0e10cSrcweir aDialog = new TextActionDialog( aATNode, 388*cdf0e10cSrcweir "Select range:", 389*cdf0e10cSrcweir "select" ) 390*cdf0e10cSrcweir { 391*cdf0e10cSrcweir boolean action( 392*cdf0e10cSrcweir JTextComponent aText, AccTreeNode aNode ) 393*cdf0e10cSrcweir throws IndexOutOfBoundsException 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir return aNode.getText().setSelection( 396*cdf0e10cSrcweir getSelectionStart(), 397*cdf0e10cSrcweir getSelectionEnd() ); 398*cdf0e10cSrcweir } 399*cdf0e10cSrcweir }; 400*cdf0e10cSrcweir break; 401*cdf0e10cSrcweir case 1: 402*cdf0e10cSrcweir aDialog = new TextActionDialog( aATNode, 403*cdf0e10cSrcweir "Select range and copy:", 404*cdf0e10cSrcweir "copy" ) 405*cdf0e10cSrcweir { 406*cdf0e10cSrcweir boolean action( 407*cdf0e10cSrcweir JTextComponent aText, AccTreeNode aNode ) 408*cdf0e10cSrcweir throws IndexOutOfBoundsException 409*cdf0e10cSrcweir { 410*cdf0e10cSrcweir return aNode.getText().copyText( 411*cdf0e10cSrcweir getSelectionStart(), 412*cdf0e10cSrcweir getSelectionEnd() ); 413*cdf0e10cSrcweir } 414*cdf0e10cSrcweir }; 415*cdf0e10cSrcweir break; 416*cdf0e10cSrcweir case 2: 417*cdf0e10cSrcweir aDialog = new TextActionDialog( aATNode, 418*cdf0e10cSrcweir "Select range and cut:", 419*cdf0e10cSrcweir "cut" ) 420*cdf0e10cSrcweir { 421*cdf0e10cSrcweir boolean action( 422*cdf0e10cSrcweir JTextComponent aText, AccTreeNode aNode ) 423*cdf0e10cSrcweir throws IndexOutOfBoundsException 424*cdf0e10cSrcweir { 425*cdf0e10cSrcweir return aNode.getEditText().cutText( 426*cdf0e10cSrcweir getSelectionStart(), 427*cdf0e10cSrcweir getSelectionEnd() ); 428*cdf0e10cSrcweir } 429*cdf0e10cSrcweir }; 430*cdf0e10cSrcweir break; 431*cdf0e10cSrcweir case 3: 432*cdf0e10cSrcweir aDialog = new TextActionDialog( aATNode, 433*cdf0e10cSrcweir "Place Caret and paste:", 434*cdf0e10cSrcweir "paste" ) 435*cdf0e10cSrcweir { 436*cdf0e10cSrcweir boolean action( 437*cdf0e10cSrcweir JTextComponent aText, AccTreeNode aNode ) 438*cdf0e10cSrcweir throws IndexOutOfBoundsException 439*cdf0e10cSrcweir { 440*cdf0e10cSrcweir return aNode.getEditText().pasteText( 441*cdf0e10cSrcweir aText.getCaretPosition() ); 442*cdf0e10cSrcweir } 443*cdf0e10cSrcweir }; 444*cdf0e10cSrcweir break; 445*cdf0e10cSrcweir case 4: 446*cdf0e10cSrcweir aDialog = new TextEditDialog( aATNode, "Edit text:", 447*cdf0e10cSrcweir "edit" ); 448*cdf0e10cSrcweir break; 449*cdf0e10cSrcweir case 5: 450*cdf0e10cSrcweir aDialog = new TextAttributeDialog( aATNode ); 451*cdf0e10cSrcweir break; 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir 454*cdf0e10cSrcweir if( aDialog != null ) 455*cdf0e10cSrcweir aDialog.show(); 456*cdf0e10cSrcweir } 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir } 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir /** 461*cdf0e10cSrcweir * Display a dialog with a text field and a pair of cancel/do-it buttons 462*cdf0e10cSrcweir */ 463*cdf0e10cSrcweir class TextActionDialog extends JDialog 464*cdf0e10cSrcweir implements ActionListener 465*cdf0e10cSrcweir { 466*cdf0e10cSrcweir AccTreeNode aNode; 467*cdf0e10cSrcweir JTextArea aText; 468*cdf0e10cSrcweir String sName; 469*cdf0e10cSrcweir JCheckBox aIndexToggle; 470*cdf0e10cSrcweir 471*cdf0e10cSrcweir public TextActionDialog( AccTreeNode aNd, 472*cdf0e10cSrcweir String sExplanation, 473*cdf0e10cSrcweir String sButtonText ) 474*cdf0e10cSrcweir { 475*cdf0e10cSrcweir super( AccessibilityWorkBench.Instance() ); 476*cdf0e10cSrcweir 477*cdf0e10cSrcweir aNode = aNd; 478*cdf0e10cSrcweir sName = sButtonText; 479*cdf0e10cSrcweir init( sExplanation, aNode.getText().getText(), sButtonText ); 480*cdf0e10cSrcweir // setSize( getPreferredSize() ); 481*cdf0e10cSrcweir setSize( 350, 225 ); 482*cdf0e10cSrcweir } 483*cdf0e10cSrcweir 484*cdf0e10cSrcweir /** build dialog */ 485*cdf0e10cSrcweir protected void init( String sExplanation, 486*cdf0e10cSrcweir String sText, 487*cdf0e10cSrcweir String sButtonText ) 488*cdf0e10cSrcweir { 489*cdf0e10cSrcweir setTitle( sName ); 490*cdf0e10cSrcweir 491*cdf0e10cSrcweir // vertical stacking of the elements 492*cdf0e10cSrcweir Container aContent = getContentPane(); 493*cdf0e10cSrcweir // aContent.setLayout( new BorderLayout() ); 494*cdf0e10cSrcweir 495*cdf0e10cSrcweir // label with explanation 496*cdf0e10cSrcweir if( sExplanation.length() > 0 ) 497*cdf0e10cSrcweir aContent.add( new JLabel( sExplanation ), BorderLayout.NORTH ); 498*cdf0e10cSrcweir 499*cdf0e10cSrcweir // the text field 500*cdf0e10cSrcweir aText = new JTextArea(); 501*cdf0e10cSrcweir aText.setText( sText ); 502*cdf0e10cSrcweir aText.setColumns( Math.min( Math.max( 40, sText.length() ), 20 ) ); 503*cdf0e10cSrcweir aText.setRows( sText.length() / 40 + 1 ); 504*cdf0e10cSrcweir aText.setLineWrap( true ); 505*cdf0e10cSrcweir aText.setEditable( false ); 506*cdf0e10cSrcweir aContent.add( aText, BorderLayout.CENTER ); 507*cdf0e10cSrcweir 508*cdf0e10cSrcweir JPanel aButtons = new JPanel(); 509*cdf0e10cSrcweir aButtons.setLayout( new FlowLayout() ); 510*cdf0e10cSrcweir aIndexToggle = new JCheckBox( "reverse selection" ); 511*cdf0e10cSrcweir aButtons.add( aIndexToggle ); 512*cdf0e10cSrcweir JButton aActionButton = new JButton( sButtonText ); 513*cdf0e10cSrcweir aActionButton.setActionCommand( "Action" ); 514*cdf0e10cSrcweir aActionButton.addActionListener( this ); 515*cdf0e10cSrcweir aButtons.add( aActionButton ); 516*cdf0e10cSrcweir JButton aCancelButton = new JButton( "cancel" ); 517*cdf0e10cSrcweir aCancelButton.setActionCommand( "Cancel" ); 518*cdf0e10cSrcweir aCancelButton.addActionListener( this ); 519*cdf0e10cSrcweir aButtons.add( aCancelButton ); 520*cdf0e10cSrcweir 521*cdf0e10cSrcweir // add Panel with buttons 522*cdf0e10cSrcweir aContent.add( aButtons, BorderLayout.SOUTH ); 523*cdf0e10cSrcweir } 524*cdf0e10cSrcweir 525*cdf0e10cSrcweir void cancel() 526*cdf0e10cSrcweir { 527*cdf0e10cSrcweir hide(); 528*cdf0e10cSrcweir dispose(); 529*cdf0e10cSrcweir } 530*cdf0e10cSrcweir 531*cdf0e10cSrcweir void action() 532*cdf0e10cSrcweir { 533*cdf0e10cSrcweir String sError = null; 534*cdf0e10cSrcweir try 535*cdf0e10cSrcweir { 536*cdf0e10cSrcweir boolean bSuccess = action( aText, aNode ); 537*cdf0e10cSrcweir if( !bSuccess ) 538*cdf0e10cSrcweir sError = "Can't execute"; 539*cdf0e10cSrcweir } 540*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 541*cdf0e10cSrcweir { 542*cdf0e10cSrcweir sError = "Index out of bounds"; 543*cdf0e10cSrcweir } 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir if( sError != null ) 546*cdf0e10cSrcweir JOptionPane.showMessageDialog( AccessibilityWorkBench.Instance(), 547*cdf0e10cSrcweir sError, sName, 548*cdf0e10cSrcweir JOptionPane.ERROR_MESSAGE); 549*cdf0e10cSrcweir 550*cdf0e10cSrcweir cancel(); 551*cdf0e10cSrcweir } 552*cdf0e10cSrcweir 553*cdf0e10cSrcweir public void actionPerformed(ActionEvent e) 554*cdf0e10cSrcweir { 555*cdf0e10cSrcweir String sCommand = e.getActionCommand(); 556*cdf0e10cSrcweir 557*cdf0e10cSrcweir if( "Cancel".equals( sCommand ) ) 558*cdf0e10cSrcweir cancel(); 559*cdf0e10cSrcweir else if( "Action".equals( sCommand ) ) 560*cdf0e10cSrcweir action(); 561*cdf0e10cSrcweir } 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir 564*cdf0e10cSrcweir int getSelectionStart() { return getSelection(true); } 565*cdf0e10cSrcweir int getSelectionEnd() { return getSelection(false); } 566*cdf0e10cSrcweir int getSelection(boolean bStart) 567*cdf0e10cSrcweir { 568*cdf0e10cSrcweir return ( bStart ^ aIndexToggle.isSelected() ) 569*cdf0e10cSrcweir ? aText.getSelectionStart() : aText.getSelectionEnd(); 570*cdf0e10cSrcweir } 571*cdf0e10cSrcweir 572*cdf0e10cSrcweir 573*cdf0e10cSrcweir 574*cdf0e10cSrcweir /** override this for dialog-specific action */ 575*cdf0e10cSrcweir boolean action( JTextComponent aText, AccTreeNode aNode ) 576*cdf0e10cSrcweir throws IndexOutOfBoundsException 577*cdf0e10cSrcweir { 578*cdf0e10cSrcweir return false; 579*cdf0e10cSrcweir } 580*cdf0e10cSrcweir } 581*cdf0e10cSrcweir 582*cdf0e10cSrcweir 583*cdf0e10cSrcweir class TextEditDialog extends TextActionDialog 584*cdf0e10cSrcweir { 585*cdf0e10cSrcweir public TextEditDialog( AccTreeNode aNode, 586*cdf0e10cSrcweir String sExplanation, 587*cdf0e10cSrcweir String sButtonText ) 588*cdf0e10cSrcweir { 589*cdf0e10cSrcweir super( aNode, sExplanation, sButtonText ); 590*cdf0e10cSrcweir } 591*cdf0e10cSrcweir 592*cdf0e10cSrcweir protected void init( String sExplanation, 593*cdf0e10cSrcweir String sText, 594*cdf0e10cSrcweir String sButtonText ) 595*cdf0e10cSrcweir { 596*cdf0e10cSrcweir super.init( sExplanation, sText, sButtonText ); 597*cdf0e10cSrcweir aText.setEditable( true ); 598*cdf0e10cSrcweir } 599*cdf0e10cSrcweir 600*cdf0e10cSrcweir 601*cdf0e10cSrcweir /** edit the text */ 602*cdf0e10cSrcweir boolean action( JTextComponent aText, AccTreeNode aNode ) 603*cdf0e10cSrcweir { 604*cdf0e10cSrcweir // is this text editable? if not, fudge you and return 605*cdf0e10cSrcweir XAccessibleEditableText xEdit = aNode.getEditText(); 606*cdf0e10cSrcweir return ( xEdit == null ) ? false : 607*cdf0e10cSrcweir updateText( xEdit, aText.getText() ); 608*cdf0e10cSrcweir } 609*cdf0e10cSrcweir 610*cdf0e10cSrcweir 611*cdf0e10cSrcweir /** update the text */ 612*cdf0e10cSrcweir boolean updateText( XAccessibleEditableText xEdit, String sNew ) 613*cdf0e10cSrcweir { 614*cdf0e10cSrcweir String sOld = xEdit.getText(); 615*cdf0e10cSrcweir 616*cdf0e10cSrcweir // false alarm? Early out if no change was done! 617*cdf0e10cSrcweir if( sOld.equals( sNew ) ) 618*cdf0e10cSrcweir return false; 619*cdf0e10cSrcweir 620*cdf0e10cSrcweir // get the minimum length of both strings 621*cdf0e10cSrcweir int nMinLength = sOld.length(); 622*cdf0e10cSrcweir if( sNew.length() < nMinLength ) 623*cdf0e10cSrcweir nMinLength = sNew.length(); 624*cdf0e10cSrcweir 625*cdf0e10cSrcweir // count equal characters from front and end 626*cdf0e10cSrcweir int nFront = 0; 627*cdf0e10cSrcweir while( (nFront < nMinLength) && 628*cdf0e10cSrcweir (sNew.charAt(nFront) == sOld.charAt(nFront)) ) 629*cdf0e10cSrcweir nFront++; 630*cdf0e10cSrcweir int nBack = 0; 631*cdf0e10cSrcweir while( (nBack < nMinLength) && 632*cdf0e10cSrcweir ( sNew.charAt(sNew.length()-nBack-1) == 633*cdf0e10cSrcweir sOld.charAt(sOld.length()-nBack-1) ) ) 634*cdf0e10cSrcweir nBack++; 635*cdf0e10cSrcweir if( nFront + nBack > nMinLength ) 636*cdf0e10cSrcweir nBack = nMinLength - nFront; 637*cdf0e10cSrcweir 638*cdf0e10cSrcweir // so... the first nFront and the last nBack characters 639*cdf0e10cSrcweir // are the same. Change the others! 640*cdf0e10cSrcweir String sDel = sOld.substring( nFront, sOld.length() - nBack ); 641*cdf0e10cSrcweir String sIns = sNew.substring( nFront, sNew.length() - nBack ); 642*cdf0e10cSrcweir 643*cdf0e10cSrcweir System.out.println("edit text: " + 644*cdf0e10cSrcweir sOld.substring(0, nFront) + 645*cdf0e10cSrcweir " [ " + sDel + " -> " + sIns + " ] " + 646*cdf0e10cSrcweir sOld.substring(sOld.length() - nBack) ); 647*cdf0e10cSrcweir 648*cdf0e10cSrcweir boolean bRet = false; 649*cdf0e10cSrcweir try 650*cdf0e10cSrcweir { 651*cdf0e10cSrcweir // edit the text, and use 652*cdf0e10cSrcweir // (set|insert|delete|replace)Text as needed 653*cdf0e10cSrcweir if( nFront+nBack == 0 ) 654*cdf0e10cSrcweir bRet = xEdit.setText( sIns ); 655*cdf0e10cSrcweir else if( sDel.length() == 0 ) 656*cdf0e10cSrcweir bRet = xEdit.insertText( sIns, nFront ); 657*cdf0e10cSrcweir else if( sIns.length() == 0 ) 658*cdf0e10cSrcweir bRet = xEdit.deleteText( nFront, sOld.length()-nBack ); 659*cdf0e10cSrcweir else 660*cdf0e10cSrcweir bRet = xEdit.replaceText(nFront, sOld.length()-nBack,sIns); 661*cdf0e10cSrcweir } 662*cdf0e10cSrcweir catch( IndexOutOfBoundsException e ) 663*cdf0e10cSrcweir { 664*cdf0e10cSrcweir bRet = false; 665*cdf0e10cSrcweir } 666*cdf0e10cSrcweir 667*cdf0e10cSrcweir return bRet; 668*cdf0e10cSrcweir } 669*cdf0e10cSrcweir } 670*cdf0e10cSrcweir 671*cdf0e10cSrcweir 672*cdf0e10cSrcweir class TextAttributeDialog extends TextActionDialog 673*cdf0e10cSrcweir { 674*cdf0e10cSrcweir public TextAttributeDialog( 675*cdf0e10cSrcweir AccTreeNode aNode ) 676*cdf0e10cSrcweir { 677*cdf0e10cSrcweir super( aNode, "Choose attributes, select text, and press 'Set':", 678*cdf0e10cSrcweir "set" ); 679*cdf0e10cSrcweir } 680*cdf0e10cSrcweir 681*cdf0e10cSrcweir private JCheckBox aBold, aUnderline, aItalics; 682*cdf0e10cSrcweir private Color aForeground, aBackground; 683*cdf0e10cSrcweir 684*cdf0e10cSrcweir protected void init( String sExplanation, 685*cdf0e10cSrcweir String sText, 686*cdf0e10cSrcweir String sButtonText ) 687*cdf0e10cSrcweir { 688*cdf0e10cSrcweir super.init( sExplanation, sText, sButtonText ); 689*cdf0e10cSrcweir 690*cdf0e10cSrcweir aForeground = Color.black; 691*cdf0e10cSrcweir aBackground = Color.white; 692*cdf0e10cSrcweir 693*cdf0e10cSrcweir JPanel aAttr = new JPanel(); 694*cdf0e10cSrcweir aAttr.setLayout( new BoxLayout( aAttr, BoxLayout.Y_AXIS ) ); 695*cdf0e10cSrcweir 696*cdf0e10cSrcweir aBold = new JCheckBox( "bold" ); 697*cdf0e10cSrcweir aUnderline = new JCheckBox( "underline" ); 698*cdf0e10cSrcweir aItalics = new JCheckBox( "italics" ); 699*cdf0e10cSrcweir 700*cdf0e10cSrcweir JButton aForeButton = new JButton("Foreground", new ColorIcon(true)); 701*cdf0e10cSrcweir aForeButton.addActionListener( new ActionListener() { 702*cdf0e10cSrcweir public void actionPerformed(ActionEvent e) 703*cdf0e10cSrcweir { 704*cdf0e10cSrcweir aForeground = JColorChooser.showDialog( 705*cdf0e10cSrcweir TextAttributeDialog.this, 706*cdf0e10cSrcweir "Select Foreground Color", 707*cdf0e10cSrcweir aForeground); 708*cdf0e10cSrcweir } 709*cdf0e10cSrcweir } ); 710*cdf0e10cSrcweir 711*cdf0e10cSrcweir JButton aBackButton = new JButton("Background", new ColorIcon(false)); 712*cdf0e10cSrcweir aBackButton.addActionListener( new ActionListener() { 713*cdf0e10cSrcweir public void actionPerformed(ActionEvent e) 714*cdf0e10cSrcweir { 715*cdf0e10cSrcweir aBackground = JColorChooser.showDialog( 716*cdf0e10cSrcweir TextAttributeDialog.this, 717*cdf0e10cSrcweir "Select Background Color", 718*cdf0e10cSrcweir aBackground); 719*cdf0e10cSrcweir } 720*cdf0e10cSrcweir } ); 721*cdf0e10cSrcweir 722*cdf0e10cSrcweir aAttr.add( aBold ); 723*cdf0e10cSrcweir aAttr.add( aUnderline ); 724*cdf0e10cSrcweir aAttr.add( aItalics ); 725*cdf0e10cSrcweir aAttr.add( aForeButton ); 726*cdf0e10cSrcweir aAttr.add( aBackButton ); 727*cdf0e10cSrcweir 728*cdf0e10cSrcweir getContentPane().add( aAttr, BorderLayout.WEST ); 729*cdf0e10cSrcweir } 730*cdf0e10cSrcweir 731*cdf0e10cSrcweir 732*cdf0e10cSrcweir class ColorIcon implements Icon 733*cdf0e10cSrcweir { 734*cdf0e10cSrcweir boolean bForeground; 735*cdf0e10cSrcweir static final int nHeight = 16; 736*cdf0e10cSrcweir static final int nWidth = 16; 737*cdf0e10cSrcweir 738*cdf0e10cSrcweir public ColorIcon(boolean bWhich) { bForeground = bWhich; } 739*cdf0e10cSrcweir public int getIconHeight() { return nHeight; } 740*cdf0e10cSrcweir public int getIconWidth() { return nWidth; } 741*cdf0e10cSrcweir public void paintIcon(Component c, Graphics g, int x, int y) 742*cdf0e10cSrcweir { 743*cdf0e10cSrcweir g.setColor( getColor() ); 744*cdf0e10cSrcweir g.fillRect( x, y, nHeight, nWidth ); 745*cdf0e10cSrcweir g.setColor( c.getForeground() ); 746*cdf0e10cSrcweir g.drawRect( x, y, nHeight, nWidth ); 747*cdf0e10cSrcweir } 748*cdf0e10cSrcweir Color getColor() 749*cdf0e10cSrcweir { 750*cdf0e10cSrcweir return bForeground ? aForeground : aBackground; 751*cdf0e10cSrcweir } 752*cdf0e10cSrcweir } 753*cdf0e10cSrcweir 754*cdf0e10cSrcweir 755*cdf0e10cSrcweir 756*cdf0e10cSrcweir /** edit the text */ 757*cdf0e10cSrcweir boolean action( JTextComponent aText, AccTreeNode aNode ) 758*cdf0e10cSrcweir throws IndexOutOfBoundsException 759*cdf0e10cSrcweir { 760*cdf0e10cSrcweir // is this text editable? if not, fudge you and return 761*cdf0e10cSrcweir XAccessibleEditableText xEdit = aNode.getEditText(); 762*cdf0e10cSrcweir boolean bSuccess = false; 763*cdf0e10cSrcweir if( xEdit != null ) 764*cdf0e10cSrcweir { 765*cdf0e10cSrcweir PropertyValue[] aSequence = new PropertyValue[6]; 766*cdf0e10cSrcweir aSequence[0] = new PropertyValue(); 767*cdf0e10cSrcweir aSequence[0].Name = "CharWeight"; 768*cdf0e10cSrcweir aSequence[0].Value = new Integer( aBold.isSelected() ? 150 : 100 ); 769*cdf0e10cSrcweir aSequence[1] = new PropertyValue(); 770*cdf0e10cSrcweir aSequence[1].Name = "CharUnderline"; 771*cdf0e10cSrcweir aSequence[1].Value = new Integer( aUnderline.isSelected() ? 1 : 0 ); 772*cdf0e10cSrcweir aSequence[2] = new PropertyValue(); 773*cdf0e10cSrcweir aSequence[2].Name = "CharBackColor"; 774*cdf0e10cSrcweir aSequence[2].Value = new Integer( aBackground.getRGB() ); 775*cdf0e10cSrcweir aSequence[3] = new PropertyValue(); 776*cdf0e10cSrcweir aSequence[3].Name = "CharColor"; 777*cdf0e10cSrcweir aSequence[3].Value = new Integer( aForeground.getRGB() ); 778*cdf0e10cSrcweir aSequence[4] = new PropertyValue(); 779*cdf0e10cSrcweir aSequence[4].Name = "CharPosture"; 780*cdf0e10cSrcweir aSequence[4].Value = new Integer( aItalics.isSelected() ? 1 : 0 ); 781*cdf0e10cSrcweir aSequence[5] = new PropertyValue(); 782*cdf0e10cSrcweir aSequence[5].Name = "CharBackTransparent"; 783*cdf0e10cSrcweir aSequence[5].Value = new Boolean( false ); 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir bSuccess = xEdit.setAttributes( getSelectionStart(), 786*cdf0e10cSrcweir getSelectionEnd(), 787*cdf0e10cSrcweir aSequence ); 788*cdf0e10cSrcweir } 789*cdf0e10cSrcweir return bSuccess; 790*cdf0e10cSrcweir } 791*cdf0e10cSrcweir 792*cdf0e10cSrcweir } 793