1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.accessibility.awb.canvas;
25 
26 import java.awt.Color;
27 import java.awt.Dimension;
28 import java.awt.Graphics2D;
29 import java.awt.Point;
30 import java.awt.Rectangle;
31 import java.awt.geom.Point2D;
32 import java.awt.geom.Rectangle2D;
33 import java.awt.geom.AffineTransform;
34 import java.awt.geom.NoninvertibleTransformException;
35 
36 
37 import com.sun.star.accessibility.*;
38 import com.sun.star.lang.EventObject;
39 import com.sun.star.uno.UnoRuntime;
40 
41 
42 class CanvasShape implements XAccessibleEventListener
43 {
44     public final Color maHighlightColor = Color.red;
45     public final Color maSelectionColor = Color.green;
46     public final Color maFocusColor = Color.blue;
47 
CanvasShape(javax.swing.tree.TreeNode aNode, Canvas aCanvas)48     public CanvasShape (javax.swing.tree.TreeNode aNode, Canvas aCanvas)
49     {
50         maNode = aNode;
51         msName = "<no name>";
52         msDescription = "<no description>";
53         maShape = new Rectangle2D.Double (-10,-10,10,10);
54         maPosition = new Point (-10,-10);
55         maSize = new Dimension (10,10);
56         maFgColor = java.awt.Color.black;
57         maBgColor = Color.blue;
58         mnRole = -1;
59         mbHighlighted = false;
60         mbSelected = false;
61         mbFocused = false;
62         maCanvas = aCanvas;
63 
64         Update ();
65     }
66 
67 
68 
69 
getNodePath(javax.swing.tree.TreeNode node)70     public javax.swing.tree.TreePath getNodePath (javax.swing.tree.TreeNode node)
71     {
72         javax.swing.tree.TreeNode parent = node.getParent();
73         return (parent != null) ?
74             getNodePath(parent).pathByAddingChild(node) :
75             new javax.swing.tree.TreePath(node);
76     }
77 
getNodePath()78     public javax.swing.tree.TreePath getNodePath ()
79     {
80         return getNodePath(maNode);
81     }
82 
83 
84 
85     /** Update the data obtained from the <type>AccessibilityNode</type>
86         object.
87     */
Update()88     public void Update ()
89     {
90         if (maNode instanceof XAccessible) {
91             mxContext = ((XAccessible) maNode).getAccessibleContext();
92             mxComponent = (XAccessibleComponent)UnoRuntime.queryInterface(
93                 XAccessibleComponent.class, mxContext);
94         }
95 
96         if (mxContext != null)
97         {
98             msName = mxContext.getAccessibleName();
99             msDescription = mxContext.getAccessibleDescription();
100             mnRole = mxContext.getAccessibleRole();
101 
102             // Extract the selected and focused flag.
103             XAccessibleStateSet xStateSet = mxContext.getAccessibleStateSet ();
104             if (xStateSet != null)
105             {
106                 mbSelected = xStateSet.contains (AccessibleStateType.SELECTED);
107                 mbFocused = xStateSet.contains (AccessibleStateType.FOCUSED);
108             }
109         }
110 
111         UpdateGeometry ();
112 
113         if (mxComponent != null)
114         {
115             // Note: alpha values in office 0..255 have to be mapped to
116             //       255..0 in Java
117             Color aCol = new Color (mxComponent.getForeground(), true);
118             maFgColor = new Color (aCol.getRed (),
119                                    aCol.getGreen (),
120                                    aCol.getBlue (),
121                                    0xff - aCol.getAlpha ());
122             aCol = new Color (mxComponent.getBackground(), true);
123             maBgColor = new Color (aCol.getRed (),
124                                    aCol.getGreen (),
125                                    aCol.getBlue (),
126                                    0xff - aCol.getAlpha ());
127         }
128     }
129 
130 
131 
UpdateGeometry()132     public void UpdateGeometry ()
133     {
134         if (mxComponent != null)
135         {
136             com.sun.star.awt.Point aLocationOnScreen =
137                 mxComponent.getLocationOnScreen();
138             com.sun.star.awt.Size aSizeOnScreen = mxComponent.getSize();
139             maPosition = new Point (
140                 aLocationOnScreen.X,
141                 aLocationOnScreen.Y);
142             maSize = new Dimension (
143                 aSizeOnScreen.Width,
144                 aSizeOnScreen.Height);
145         }
146     }
147 
148 
149 
150     /** Paint the object into the specified canvas.  It is transformed
151         according to the specified offset and scale.
152     */
paint( Graphics2D g, boolean bShowDescription, boolean bShowName, boolean bShowText)153     public void paint (
154         Graphics2D g,
155         boolean bShowDescription,
156         boolean bShowName,
157         boolean bShowText)
158     {
159         try{
160             // Transform the object's position and size according to the
161             // specified offset and scale.
162             Point aLocation = new Point();
163             maShape = new Rectangle2D.Double (
164                 maPosition.x,
165                 maPosition.y,
166                 maSize.width,
167                 maSize.height);
168             maTransformation = g.getTransform();
169 
170             // Fill the object's bounding box with its background color if it
171             // has no children.
172             if (mxContext.getAccessibleChildCount() == 0)
173             {
174                 g.setColor (maBgColor);
175                 g.fill (maShape);
176             }
177 
178             // Remove alpha channel from color before drawing the frame.
179             Color color = maFgColor;
180             if (maFgColor.getAlpha()<128)
181                 color = new Color (maFgColor.getRed(), maFgColor.getGreen(), maFgColor.getBlue());
182             g.setColor (color);
183             g.draw (maShape);
184 
185             if (mbFocused)
186             {
187                 g.setColor (maFocusColor);
188                 for (int x=0; x<=2; x++)
189                     for (int y=0; y<=2; y++)
190                         g.fill (
191                             new Rectangle2D.Double (
192                                 maShape.x + x/2.0 * maShape.width-3,
193                                 maShape.y + y/2.0 * maShape.height-3,
194                                 6,
195                                 6));
196             }
197             if (mbSelected)
198             {
199                 g.setColor (maSelectionColor);
200                 for (int x=0; x<=2; x++)
201                     for (int y=0; y<=2; y++)
202                         g.draw (
203                             new Rectangle2D.Double (
204                                 maShape.x + x/2.0 * maShape.width-2,
205                                 maShape.y + y/2.0 * maShape.height-2,
206                                 4,
207                                 4));
208             }
209 
210             // Write the object's text OR name and description.
211             g.setColor (maFgColor);
212             if (bShowName)
213                 paintName (g);
214             if (bShowDescription)
215                 paintDescription (g);
216             if (bShowText)
217                 paintText (g);
218         }
219         catch (Exception e)
220         { // don't care
221         }
222     }
223 
224 
paint_highlight(Graphics2D g)225     public void paint_highlight (Graphics2D g)
226     {
227         if (mbHighlighted)
228             g.setColor (maHighlightColor);
229         else
230             g.setColor (maFgColor);
231         g.draw (maShape);
232     }
233 
234 
235 
236 
paintName(Graphics2D g)237     private void paintName (Graphics2D g)
238     {
239         g.drawString ("Name: " + msName,
240             (float)maShape.x+5,
241             (float)maShape.y+15);
242     }
243 
244 
245 
paintDescription(Graphics2D g)246     private void paintDescription (Graphics2D g)
247     {
248         g.drawString ("Description: " + msDescription,
249             (float)maShape.x+5,
250             (float)maShape.y+35);
251     }
252 
253 
254 
255 
paintText(Graphics2D g)256     private void paintText (Graphics2D g)
257     {
258         XAccessibleText xText = null;
259         // get XAccessibleText
260         xText = (XAccessibleText)UnoRuntime.queryInterface(
261             XAccessibleText.class, mxContext);
262 
263         // Draw every character in the text string.
264         if (xText != null)
265         {
266             String sText = xText.getText();
267             try
268             {
269                 for(int i = 0; i < sText.length(); i++)
270                 {
271                     com.sun.star.awt.Rectangle aRect =
272                         xText.getCharacterBounds(i);
273 
274                     double x = maShape.x + aRect.X;
275                     double y = maShape.y + aRect.Y + aRect.Height;
276 
277                     g.drawString (sText.substring(i, i+1), (float)x, (float)y);
278                 }
279             }
280             catch (com.sun.star.lang.IndexOutOfBoundsException e)
281             {}
282         }
283     }
284 
285 
286     /** Compute whether the specified point lies inside the object's
287         bounding box.
288     */
Contains(int x, int y)289     public boolean Contains (int x, int y)
290     {
291         Point2D aPosition = new Point2D.Double (x,y);
292         try
293         {
294             maTransformation.inverseTransform (aPosition, aPosition);
295             //            System.out.println ("transformed "+x+","+y+" to "+aPosition);
296         }
297         catch (NoninvertibleTransformException aException)
298         {
299             return false;
300         }
301         return (maShape.contains (aPosition));
302     }
303 
Highlight(boolean bFlag)304     public void Highlight (boolean bFlag)
305     {
306         mbHighlighted = bFlag;
307     }
308 
IsHighlighted()309     public boolean IsHighlighted ()
310     {
311         return mbHighlighted;
312     }
313 
GetBBox()314     public Rectangle GetBBox ()
315     {
316         return new Rectangle (maPosition, maSize);
317     }
318 
getOrigin()319     public Point getOrigin ()
320     {
321         return maPosition;
322     }
323 
GetSize()324     public Dimension GetSize ()
325     {
326         return maSize;
327     }
328 
getRole()329     public int getRole ()
330     {
331         return mnRole;
332     }
333 
getContext()334     public XAccessibleContext getContext ()
335     {
336         return mxContext;
337     }
338 
getComponent()339     public XAccessibleComponent getComponent ()
340     {
341         return mxComponent;
342     }
343 
toString()344     public String toString ()
345     {
346         return ">"+msName+", "+msDescription+" +"+maPosition.x+"+"+maPosition.y
347             +"x"+maSize.width+"x"+maSize.height+"<";
348     }
349 
350     /** */
notifyEvent(com.sun.star.accessibility.AccessibleEventObject aEvent)351     public void notifyEvent(com.sun.star.accessibility.AccessibleEventObject aEvent) {
352         try {
353             switch (aEvent.EventId) {
354                 case AccessibleEventId.BOUNDRECT_CHANGED:
355                 case AccessibleEventId.VISIBLE_DATA_CHANGED:
356                     UpdateGeometry ();
357                     maCanvas.repaint();
358                     break;
359                 default:
360                     break;
361             }
362         } catch (Exception aException) {
363             System.err.println ("caught exception while updating a shape:"
364                 + aException);
365             aException.printStackTrace (System.err);
366         }
367     }
368 
369     /** Callback for disposing events.
370     */
disposing(com.sun.star.lang.EventObject e)371     public void disposing (com.sun.star.lang.EventObject e)
372     {
373         System.out.println ("Disposing");
374     }
375 
376 
377 
378 
379     private Canvas
380         maCanvas;
381     private javax.swing.tree.TreeNode
382         maNode;
383     private XAccessibleContext
384         mxContext;
385     private XAccessibleComponent
386         mxComponent;
387     private String
388         msDescription,
389         msName;
390     private Rectangle2D.Double maShape;
391     private AffineTransform maTransformation;
392     private Point maPosition;
393     private Dimension
394         maTransformedSize,
395         maSize;
396     private Color
397         maFgColor,
398         maBgColor;
399     private boolean
400         // Highlighting objects is an internal concept.  Corresponds to selection in the tree view.
401         mbHighlighted,
402         // Set when the accessible object is selected.
403         mbSelected,
404         // Set when the accessible object is focused.
405         mbFocused;
406     private int
407         mnRole;
408 }
409