1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  *   Licensed to the Apache Software Foundation (ASF) under one or more
11  *   contributor license agreements. See the NOTICE file distributed
12  *   with this work for additional information regarding copyright
13  *   ownership. The ASF licenses this file to you under the Apache
14  *   License, Version 2.0 (the "License"); you may not use this file
15  *   except in compliance with the License. You may obtain a copy of
16  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 
19 import java.awt.*;
20 import javax.swing.tree.*;
21 import java.awt.geom.Rectangle2D;
22 
23 import com.sun.star.accessibility.XAccessibleContext;
24 import com.sun.star.accessibility.XAccessibleComponent;
25 import com.sun.star.accessibility.XAccessibleText;
26 import com.sun.star.accessibility.XAccessibleStateSet;
27 import com.sun.star.accessibility.AccessibleStateType;
28 
29 class CanvasShape
30 {
31     private final Color maHighlightColor = Color.red;
32     private final Color maSelectionColor = Color.green;
33     private final Color maFocusColor = Color.blue;
34 
CanvasShape(AccTreeNode aNode)35     public CanvasShape (AccTreeNode aNode)
36     {
37         maNode = aNode;
38         mxContext = aNode.getContext();
39         msName = "name unknown";
40         msDescription = "description unknown";
41         maShape = new Rectangle2D.Double (-10,-10,10,10);
42         maPosition = new Point (-10,-10);
43         maSize = new Dimension (10,10);
44         maFgColor = java.awt.Color.black;
45         maBgColor = Color.blue;
46         mbHighlighted = false;
47         mbSelected = false;
48         mbFocused = false;
49         mxComponent = aNode.getComponent();
50 
51         update ();
52     }
53 
54 
55 
56     /** Update the data obtained from the xAccessible.
57     */
update()58     public void update ()
59     {
60         if (mxContext != null)
61         {
62             msName = mxContext.getAccessibleName();
63             msDescription = mxContext.getAccessibleDescription();
64 
65             // Extract the selected and focused flag.
66             XAccessibleStateSet xStateSet = mxContext.getAccessibleStateSet ();
67             if (xStateSet != null)
68             {
69                 mbSelected = xStateSet.contains (AccessibleStateType.SELECTED);
70                 mbFocused = xStateSet.contains (AccessibleStateType.FOCUSED);
71             }
72         }
73 
74         updateGeometry ();
75         if (mxComponent != null)
76         {
77             // Note: alpha values in office 0..255 have to be mapped to
78             //       255..0 in Java
79             Color aCol = new Color (mxComponent.getForeground(), true);
80             maFgColor = new Color (aCol.getRed (),
81                                    aCol.getGreen (),
82                                    aCol.getBlue (),
83                                    0xff - aCol.getAlpha ());
84             aCol = new Color (mxComponent.getBackground(), true);
85             maBgColor = new Color (aCol.getRed (),
86                                    aCol.getGreen (),
87                                    aCol.getBlue (),
88                                    0xff - aCol.getAlpha ());
89         }
90     }
91 
updateGeometry()92     public void updateGeometry ()
93     {
94         if (mxComponent != null)
95         {
96             com.sun.star.awt.Point aLocationOnScreen = mxComponent.getLocationOnScreen();
97             com.sun.star.awt.Size aSizeOnScreen = mxComponent.getSize();
98             maPosition = new Point (
99                 aLocationOnScreen.X,
100                 aLocationOnScreen.Y);
101             maSize = new Dimension (
102                 aSizeOnScreen.Width,
103                 aSizeOnScreen.Height);
104         }
105     }
106 
107 
108     /** Paint the object into the specified canvas.  It is transformed
109         according to the specified offset and scale.
110     */
paint(Graphics2D g, double nXOffset, double nYOffset, double nScaleFactor, boolean bShowDescription, boolean bShowName, boolean bShowText)111     public void paint (Graphics2D g,
112         double nXOffset, double nYOffset, double nScaleFactor,
113         boolean bShowDescription, boolean bShowName, boolean bShowText)
114     {
115         try{
116             // Transform the object's position and size according to the
117             // specified offset and scale.
118             maShape = new Rectangle2D.Double (
119                 maPosition.x * nScaleFactor + nXOffset,
120                 maPosition.y * nScaleFactor + nYOffset,
121                 maSize.width * nScaleFactor,
122                 maSize.height * nScaleFactor);
123 
124             // Fill the object's bounding box with its background color if it
125             // has no children.
126             if (mxContext.getAccessibleChildCount() == 0)
127             {
128                 g.setColor (maBgColor);
129                 g.fill (maShape);
130             }
131 
132             // Remove alpha channel from color before drawing the frame.
133             Color color = maFgColor;
134             if (maFgColor.getAlpha()<128)
135                 color = new Color (maFgColor.getRed(), maFgColor.getGreen(), maFgColor.getBlue());
136             g.setColor (color);
137             g.draw (maShape);
138 
139             if (mbFocused)
140             {
141                 g.setColor (maFocusColor);
142                 for (int x=0; x<=2; x++)
143                     for (int y=0; y<=2; y++)
144                         g.fill (
145                             new Rectangle2D.Double (
146                                 maShape.x + x/2.0 * maShape.width-3,
147                                 maShape.y + y/2.0 * maShape.height-3,
148                                 6,
149                                 6));
150             }
151             if (mbSelected)
152             {
153                 g.setColor (maSelectionColor);
154                 for (int x=0; x<=2; x++)
155                     for (int y=0; y<=2; y++)
156                         g.draw (
157                             new Rectangle2D.Double (
158                                 maShape.x + x/2.0 * maShape.width-2,
159                                 maShape.y + y/2.0 * maShape.height-2,
160                                 4,
161                                 4));
162             }
163 
164             // Write the object's text OR name and description.
165             g.setColor (maFgColor);
166             if (bShowName)
167                 paintName (g);
168             if (bShowDescription)
169                 paintDescription (g);
170             if (bShowText)
171                 paintText (g);
172         }
173         catch (Exception e)
174         { // don't care
175         }
176     }
177 
paint_highlight(Graphics2D g)178     public void paint_highlight (Graphics2D g)
179     {
180         if (mbHighlighted)
181             g.setColor (maHighlightColor);
182         else
183             g.setColor (maFgColor);
184         g.draw (maShape);
185     }
186 
187 
188 
189 
paintName(Graphics2D g)190     private void paintName (Graphics2D g)
191     {
192         g.drawString ("Name: " + msName,
193             (float)maShape.x+5,
194             (float)maShape.y+15);
195     }
196 
197 
198 
paintDescription(Graphics2D g)199     private void paintDescription (Graphics2D g)
200     {
201         g.drawString ("Description: " + msDescription,
202             (float)maShape.x+5,
203             (float)maShape.y+35);
204     }
205 
206 
207 
208 
paintText(Graphics2D g)209     private void paintText (Graphics2D g)
210     {
211         XAccessibleText xText = null;
212         // get XAccessibleText
213         xText = maNode.getText();
214 
215         // Draw every character in the text string.
216         if (xText != null)
217         {
218             String sText = xText.getText();
219             try
220             {
221                 for(int i = 0; i < sText.length(); i++)
222                 {
223                     com.sun.star.awt.Rectangle aRect =
224                         xText.getCharacterBounds(i);
225 
226                     double x = maShape.x + aRect.X;
227                     double y = maShape.y + aRect.Y + aRect.Height;
228 
229                     g.drawString(sText.substring(i, i+1), (float)x, (float)y);
230                 }
231             }
232             catch (com.sun.star.lang.IndexOutOfBoundsException e)
233             {}
234         }
235     }
236 
237 
238 
239 
240     /** Compute whether the specified point lies inside the object's
241         bounding box.
242     */
contains(int x, int y)243     public boolean contains (int x, int y)
244     {
245         return maShape.contains (x,y);
246     }
247 
highlight()248     public void highlight ()
249     {
250         mbHighlighted = true;
251     }
252 
unhighlight()253     public void unhighlight ()
254     {
255         mbHighlighted = false;
256     }
257 
getBBox()258     public Rectangle getBBox ()
259     {
260         return new Rectangle (maPosition, maSize);
261     }
262 
getPath()263     public TreePath getPath ()
264     {
265         return new TreePath (maNode.createPath());
266     }
267 
268     @Override
toString()269     public String toString ()
270     {
271         return ">"+msName+", "+msDescription+" +"+maPosition.x+"+"+maPosition.y
272             +"x"+maSize.width+"x"+maSize.height+"<";
273     }
274 
275     private final AccTreeNode maNode;
276     private final XAccessibleContext mxContext;
277     private final XAccessibleComponent mxComponent;
278     private String msDescription, msName;
279     private Rectangle2D.Double maShape;
280     private Point maPosition;
281     private Dimension maSize;
282     private Color maFgColor, maBgColor;
283     private boolean
284         // Highlighting objects is an internal concept.  Corresponds to selection in the tree view.
285         mbHighlighted,
286         // Set when the accessible object is selected.
287         mbSelected,
288         // Set when the accessible object is focused.
289         mbFocused;
290 }
291