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.Graphics;
29 import java.awt.Graphics2D;
30 import java.awt.Rectangle;
31 import java.awt.RenderingHints;
32 import java.awt.Toolkit;
33 import java.awt.geom.Rectangle2D;
34 import java.util.Iterator;
35 import javax.swing.JPanel;
36 import javax.swing.JScrollPane;
37 import javax.swing.JViewport;
38 import javax.swing.event.TreeSelectionEvent;
39 import javax.swing.tree.TreePath;
40 
41 import com.sun.star.accessibility.XAccessible;
42 import com.sun.star.accessibility.XAccessibleContext;
43 import com.sun.star.accessibility.XAccessibleComponent;
44 
45 import org.openoffice.accessibility.misc.Options;
46 
47 /** This canvas displays accessible objects graphically.  Each accessible
48     object with graphical representation is represented by an
49     CanvasShape object and has to be added by the
50     <member>addAccessible</member> member function.
51 
52     <p>The canvas listens to selection events of the associated JTree and
53     highlights the first selected node of that tree.</p>
54 */
55 public class Canvas
56     extends JPanel
57 {
58     // This constant can be passed to SetZoomMode to always show the whole screen.
59     public static final int WHOLE_SCREEN = -1;
60 
Canvas()61     public Canvas ()
62     {
63         super (true);
64         maShapeList = new ShapeContainer (this);
65 		maMouseObserver = new MouseObserver (this);
66         maTree = null;
67         mnHOffset = 0;
68         mnVOffset = 0;
69         mnScale = 1;
70         maLastWidgetSize = new Dimension (0,0);
71     }
72 
73 
74 
75     /** Tell the canvas which tree to use to highlight accessible
76         objects and to observe for changes in the tree structure.
77     */
SetTree(javax.swing.JTree aTree)78     public void SetTree (javax.swing.JTree aTree)
79     {
80 		if (aTree != maTree)
81 		{
82 			maTree = aTree;
83 			maShapeList.SetTree (maTree);
84 			maMouseObserver.SetTree (maTree);
85 		}
86     }
87 
88 
89 
90 
Clear()91     private void Clear ()
92     {
93 		maShapeList.Clear();
94     }
95 
96 
97 
98 
GetShapeIterator()99 	public Iterator GetShapeIterator ()
100 	{
101 		return maShapeList.GetIterator();
102 	}
103 
104 
105 
106 
paintComponent(Graphics g)107     public void paintComponent (Graphics g)
108     {
109         synchronized (g)
110         {
111             super.paintComponent (g);
112 
113             Graphics2D g2 = (Graphics2D)g;
114             if (Options.GetBoolean("Antialiasing"))
115                 g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
116                     RenderingHints.VALUE_ANTIALIAS_ON);
117             else
118                 g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
119                     RenderingHints.VALUE_ANTIALIAS_OFF);
120 
121             setupTransformation ();
122             g2.translate (mnHOffset, mnVOffset);
123             g2.scale (mnScale, mnScale);
124 
125             // Draw the screen representation to give a hint of the location of the
126             // accessible object on the screen.
127             Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
128             Rectangle2D.Double aScreen = new Rectangle2D.Double (
129                 0,
130                 0,
131                 aScreenSize.getWidth(),
132                 aScreenSize.getHeight());
133             // Fill the screen rectangle and draw a frame arround it to increase its visibility.
134             g2.setColor (new Color (250,240,230));
135             g2.fill (aScreen);
136             g2.setColor (Color.BLACK);
137             g2.draw (aScreen);
138 
139             synchronized (maShapeList)
140             {
141                 Iterator aShapeIterator = maShapeList.GetIterator();
142                 boolean bShowDescriptions = Options.GetBoolean ("ShowDescriptions");
143                 boolean bShowNames = Options.GetBoolean ("ShowNames");
144                 boolean bShowText = Options.GetBoolean ("ShowText");
145                 while (aShapeIterator.hasNext())
146                 {
147                     CanvasShape aCanvasShape =
148 						(CanvasShape)aShapeIterator.next();
149                     try
150                     {
151                         aCanvasShape.paint (
152                             g2,
153                             bShowDescriptions, bShowNames, bShowText);
154                     }
155                     catch (Exception aException)
156                     {
157                         System.err.println ("caught exception while painting a shape:"
158                             + aException);
159                         aException.printStackTrace (System.err);
160                     }
161                 }
162             }
163 
164             // Paint highlighted frame around active object as the last thing.
165             if (maActiveObject != null)
166                 maActiveObject.paint_highlight (g2);
167         }
168     }
169 
170 
171 
172 
173     /** Set up the transformation so that the graphical display can show a
174         centered representation of the whole screen.
175     */
setupTransformation()176     private void setupTransformation ()
177     {
178         // Turn off scrollbars when showing the whole screen.  Otherwise show them when needed.
179         JViewport aViewport = (JViewport)getParent();
180         JScrollPane aScrollPane = (JScrollPane)aViewport.getParent();
181         int nZoomMode = Options.GetInteger ("ZoomMode", WHOLE_SCREEN);
182         if (nZoomMode == WHOLE_SCREEN)
183         {
184             if (aScrollPane.getHorizontalScrollBarPolicy()
185                 != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
186                 aScrollPane.setHorizontalScrollBarPolicy (
187 				    JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
188             if (aScrollPane.getVerticalScrollBarPolicy()
189                 != JScrollPane.VERTICAL_SCROLLBAR_NEVER)
190                 aScrollPane.setVerticalScrollBarPolicy (
191 			        JScrollPane.VERTICAL_SCROLLBAR_NEVER);
192         }
193         else
194         {
195             if (aScrollPane.getHorizontalScrollBarPolicy()
196                 != JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)
197                 aScrollPane.setHorizontalScrollBarPolicy (
198                     JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
199             if (aScrollPane.getVerticalScrollBarPolicy()
200                 != JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED)
201                 aScrollPane.setVerticalScrollBarPolicy (
202                     JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
203         }
204 
205         Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
206         Dimension aWidgetSize = aViewport.getSize();
207         {
208             if ((aScreenSize.getWidth() > 0) && (aScreenSize.getHeight() > 0))
209             {
210                 if (nZoomMode == WHOLE_SCREEN)
211                 {
212                     // Calculate the scales that would map the screen onto the
213                     // widget in both of the coordinate axes and select the
214                     // smaller
215                     // of the two: it maps the screen onto the widget in both
216                     // axes at the same time.
217                     double nHScale = (aWidgetSize.getWidth() - 10)
218 						   / aScreenSize.getWidth();
219                     double nVScale = (aWidgetSize.getHeight() - 10)
220 						/ aScreenSize.getHeight();
221                     if (nHScale < nVScale)
222                         mnScale = nHScale;
223                     else
224                         mnScale = nVScale;
225                 }
226                 else
227                 {
228                     mnScale = nZoomMode / 100.0;
229                 }
230 
231                 // Calculate offsets that center the scaled screen inside
232                 // the widget.
233                 mnHOffset = (aWidgetSize.getWidth()
234 							 - mnScale*aScreenSize.getWidth()) / 2.0;
235                 mnVOffset = (aWidgetSize.getHeight()
236 							 - mnScale*aScreenSize.getHeight()) / 2.0;
237                 if (mnHOffset < 0)
238                     mnHOffset = 0;
239                 if (mnVOffset < 0)
240                     mnVOffset = 0;
241 
242                 setPreferredSize (new Dimension (
243                     (int)(2*mnHOffset + mnScale * aScreenSize.getWidth()),
244                     (int)(2*mnVOffset + mnScale * aScreenSize.getHeight())));
245                 revalidate ();
246             }
247             else
248             {
249                 // In case of a degenerate (not yet initialized?) screen size
250                 // use some meaningless default values.
251                 mnScale = 1;
252                 mnHOffset = 0;
253                 mnVOffset = 0;
254             }
255         }
256         maLastWidgetSize = aWidgetSize;
257     }
258 
259 
260 
HighlightObject(CanvasShape aNewActiveObject)261     protected boolean HighlightObject (CanvasShape aNewActiveObject)
262     {
263         if (aNewActiveObject != maActiveObject)
264         {
265             if (maActiveObject != null)
266                 maActiveObject.Highlight (false);
267 
268             maActiveObject = aNewActiveObject;
269             if (maActiveObject != null)
270             {
271                 /*           if (maTree != null)
272                 {
273 					TreePath aPath = new TreePath (
274 						maActiveObject.GetNode().GetPath());
275                     maTree.scrollPathToVisible (aPath);
276                     maTree.setSelectionPath (aPath);
277                     maTree.repaint ();
278                 }
279                 */
280                 maActiveObject.Highlight (true);
281             }
282             repaint ();
283             return true;
284         }
285         else
286             return false;
287     }
288 
289 
290 
291 
292     /** Called when the selection of the tree changes.  Highlight the
293         corresponding graphical representation of the object.
294     */
SelectObject(javax.swing.tree.TreeNode aNode)295     public void SelectObject (javax.swing.tree.TreeNode aNode)
296     {
297 		CanvasShape aCanvasShape = maShapeList.Get (aNode);
298 		HighlightObject (aCanvasShape);
299     }
300 
301 
302 
303 
304     private int
305         mnXAnchor,
306         mnYAnchor,
307         maResizeFlag;
308     private double
309         mnHOffset,
310         mnVOffset,
311         mnScale;
312     private CanvasShape maActiveObject;
313     private javax.swing.JTree maTree;
314     // The size of the widget at the last call of setupTransformation()
315     private Dimension maLastWidgetSize;
316 	private ShapeContainer maShapeList;
317 	private MouseObserver maMouseObserver;
318 }
319