Branch libreoffice-5-0-4
[LibreOffice.git] / toolkit / test / accessibility / Canvas.java
blobc254ed62c5e8af579c017f8e04970db9b9bdc8c1
1 /*
2 * This file is part of the LibreOffice project.
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/.
8 * This file incorporates work covered by the following license notice:
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 .
19 import java.awt.Color;
20 import java.awt.Dimension;
21 import java.awt.Graphics;
22 import java.awt.Graphics2D;
23 import java.awt.Rectangle;
24 import java.awt.RenderingHints;
25 import java.awt.Toolkit;
26 import java.awt.event.InputEvent;
27 import java.awt.event.MouseEvent;
28 import java.awt.event.MouseListener;
29 import java.awt.event.MouseMotionListener;
30 import java.awt.geom.Rectangle2D;
31 import java.util.ArrayList;
32 import java.util.List;
34 import javax.swing.JPanel;
35 import javax.swing.JScrollPane;
36 import javax.swing.JTree;
37 import javax.swing.JViewport;
38 import javax.swing.event.TreeSelectionListener;
39 import javax.swing.tree.TreePath;
41 /** This canvas displays accessible objects graphically. Each accessible
42 object with graphical representation is represented by an
43 CanvasShape object and has to be added by the
44 <member>addAccessible</member> member function.
46 <p>The canvas listens to selection events of the associated JTree and
47 highlights the first selected node of that tree.</p>
49 class Canvas
50 extends JPanel
51 implements MouseListener, MouseMotionListener, TreeSelectionListener//, Scrollable
53 // This constant can be passed to SetZoomMode to always show the whole screen.
54 public static final int WHOLE_SCREEN = -1;
56 public Canvas ()
58 super (true);
59 maObjects = new java.util.HashMap<AccTreeNode, CanvasShape> ();
60 maNodes = new ArrayList<AccTreeNode> ();
61 maObjectList = new ArrayList<CanvasShape> ();
62 addMouseListener (this);
63 addMouseMotionListener (this);
64 maBoundingBox = new Rectangle (0,0,100,100);
65 maTree = null;
66 mnHOffset = 0;
67 mnVOffset = 0;
68 mnScale = 1;
69 setShowText(false);
70 setShowDescriptions (true);
71 setShowNames (true);
72 setAntialiasing (true);
75 /** Tell the canvas which tree view to use to highlight accessible
76 objects.
78 public void setTree (JTree aTree)
80 if (maTree != null)
81 maTree.removeTreeSelectionListener (this);
82 maTree = aTree;
83 if (maTree != null)
84 maTree.addTreeSelectionListener (this);
90 public void addNode (AccTreeNode aNode)
92 if (maNodes.indexOf (aNode) == -1)
94 maNodes.add (aNode);
96 CanvasShape aObject = maObjects.get (aNode);
97 if (aObject == null)
99 aObject = new CanvasShape (aNode);
100 // Update bounding box that includes all objects.
101 if (maObjects.isEmpty())
102 maBoundingBox = aObject.getBBox();
103 else
104 maBoundingBox = maBoundingBox.union (aObject.getBBox());
106 maObjects.put (aNode, aObject);
107 maObjectList.add (aObject);
110 repaint ();
114 public void removeNode (AccTreeNode aNode)
116 int i = maNodes.indexOf (aNode);
117 if( i != -1 )
119 CanvasShape aObject = maObjects.get(aNode);
120 maObjectList.remove (aObject);
121 maObjects.remove (aNode);
122 maNodes.remove (aNode);
123 repaint ();
127 public void updateNode (AccTreeNode aNode)
129 int i = maNodes.indexOf (aNode);
130 if (i != -1)
132 CanvasShape aObject = maObjects.get(aNode);
133 if (aObject != null)
134 aObject.update();
138 public void updateNodeGeometry (AccTreeNode aNode)
140 CanvasShape aObject = maObjects.get(aNode);
141 if (aObject != null)
142 aObject.updateGeometry();
145 public void clear ()
147 while (maNodes.size() > 0) {
148 removeNode (maNodes.get(0));
150 maNodes.clear();
151 maObjects.clear();
152 maObjectList.clear();
155 public boolean getShowDescriptions ()
157 return Options.GetBoolean ("ShowDescriptions");
160 public void setShowDescriptions (boolean bNewValue)
162 Options.SetBoolean ("ShowDescriptions", bNewValue);
163 repaint ();
166 public boolean getShowNames ()
168 return Options.GetBoolean ("ShowNames");
171 public void setShowNames (boolean bNewValue)
173 Options.SetBoolean ("ShowNames", bNewValue);
174 repaint ();
177 public boolean getAntialiasing ()
179 return Options.GetBoolean ("Antialiasing");
182 public void setAntialiasing (boolean bNewValue)
184 Options.SetBoolean ("Antialiasing", bNewValue);
185 repaint ();
188 public boolean getShowText ()
190 return Options.GetBoolean ("ShowText");
193 private void setShowText (boolean bNewValue)
195 Options.SetBoolean ("ShowText", bNewValue);
196 repaint ();
199 public void setZoomMode (int nZoomMode)
201 Options.SetInteger ("ZoomMode", nZoomMode);
202 repaint ();
205 private int getZoomMode ()
207 return Options.GetInteger ("ZoomMode", WHOLE_SCREEN);
211 @Override
212 public void paintComponent (Graphics g)
214 synchronized (g)
216 super.paintComponent (g);
218 Graphics2D g2 = (Graphics2D)g;
219 if (getAntialiasing())
220 g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
221 RenderingHints.VALUE_ANTIALIAS_ON);
222 else
223 g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
224 RenderingHints.VALUE_ANTIALIAS_OFF);
226 setupTransformation ();
228 // Draw the screen representation to give a hint of the location of the
229 // accessible object on the screen.
230 Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
231 Rectangle2D.Double aScreen = new Rectangle2D.Double (
232 mnHOffset,
233 mnVOffset,
234 mnScale*aScreenSize.getWidth(),
235 mnScale*aScreenSize.getHeight());
236 // Fill the screen rectangle and draw a frame around it to increase its visibility.
237 g2.setColor (new Color (250,240,230));
238 g2.fill (aScreen);
239 g2.setColor (Color.BLACK);
240 g2.draw (aScreen);
242 synchronized (maObjectList)
244 int nCount = maObjectList.size();
245 boolean bShowDescriptions = getShowDescriptions();
246 boolean bShowNames = getShowNames();
247 boolean bShowText = getShowText();
248 for (int i=0; i<nCount; i++)
250 CanvasShape aCanvasShape = maObjectList.get(i);
251 aCanvasShape.paint (
253 mnHOffset, mnVOffset, mnScale,
254 bShowDescriptions, bShowNames, bShowText);
258 // Paint highlighted frame around active object as the last thing.
259 if (maActiveObject != null)
260 maActiveObject.paint_highlight (
261 g2);
268 /** Set up the transformation so that the graphical display can show a
269 centered representation of the whole screen.
271 private void setupTransformation ()
273 // Turn off scrollbars when showing the whole screen. Otherwise show them when needed.
274 JViewport aViewport = (JViewport)getParent();
275 JScrollPane aScrollPane = (JScrollPane)aViewport.getParent();
276 int nZoomMode = getZoomMode();
277 if (nZoomMode == WHOLE_SCREEN)
279 if (aScrollPane.getHorizontalScrollBarPolicy()
280 != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
281 aScrollPane.setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
282 if (aScrollPane.getVerticalScrollBarPolicy()
283 != JScrollPane.VERTICAL_SCROLLBAR_NEVER)
284 aScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_NEVER);
286 else
288 if (aScrollPane.getHorizontalScrollBarPolicy()
289 != JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)
290 aScrollPane.setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
291 if (aScrollPane.getVerticalScrollBarPolicy()
292 != JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED)
293 aScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
296 Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
297 Dimension aWidgetSize = aViewport.getSize();
299 if ((aScreenSize.getWidth() > 0) && (aScreenSize.getHeight() > 0))
301 if (nZoomMode == WHOLE_SCREEN)
303 // Calculate the scales that would map the screen onto the
304 // widget in both of the coordinate axes and select the
305 // smaller
306 // of the two: it maps the screen onto the widget in both
307 // axes at the same time.
308 double nHScale = (aWidgetSize.getWidth() - 10) / aScreenSize.getWidth();
309 double nVScale = (aWidgetSize.getHeight() - 10) / aScreenSize.getHeight();
310 if (nHScale < nVScale)
311 mnScale = nHScale;
312 else
313 mnScale = nVScale;
315 else
317 mnScale = nZoomMode / 100.0;
320 // Calculate offsets that center the scaled screen inside the widget.
321 mnHOffset = (aWidgetSize.getWidth() - mnScale*aScreenSize.getWidth()) / 2.0;
322 mnVOffset = (aWidgetSize.getHeight() - mnScale*aScreenSize.getHeight()) / 2.0;
323 if (mnHOffset < 0)
324 mnHOffset = 0;
325 if (mnVOffset < 0)
326 mnVOffset = 0;
328 setPreferredSize (new Dimension (
329 (int)(2*mnHOffset + mnScale * aScreenSize.getWidth()),
330 (int)(2*mnVOffset + mnScale * aScreenSize.getHeight())));
331 revalidate ();
333 else
335 // In case of a degenerate (not yet initialized?) screen size
336 // use some meaningless default values.
337 mnScale = 1;
338 mnHOffset = 0;
339 mnVOffset = 0;
346 /** Call getAccessibleAt to determine accessible object under mouse.
348 public void mouseClicked (MouseEvent e)
352 public void mousePressed (MouseEvent e)
354 CanvasShape aObjectUnderMouse = FindCanvasShapeUnderMouse (e);
355 highlightObject (aObjectUnderMouse);
356 if ((e.getModifiers() & InputEvent.CTRL_MASK) != 0)
358 maTree.expandPath (aObjectUnderMouse.getPath());
362 public void mouseReleased (MouseEvent e)
366 public void mouseEntered (MouseEvent e)
370 public void mouseExited (MouseEvent e)
372 // Deselect currently active object.
373 if (maActiveObject != null)
375 maActiveObject.unhighlight ();
376 maActiveObject = null;
377 repaint ();
381 public void mouseDragged (MouseEvent e)
385 public void mouseMoved (MouseEvent e)
387 if ((e.getModifiers() & InputEvent.SHIFT_MASK) != 0)
388 highlightObject (FindCanvasShapeUnderMouse (e));
391 private CanvasShape FindCanvasShapeUnderMouse (MouseEvent e)
393 CanvasShape aObjectUnderMouse = null;
394 int nCount = maObjectList.size();
395 for (int i=nCount-1; i>=0; --i)
397 CanvasShape aObject = maObjectList.get(i);
398 if (aObject != null)
399 if (aObject.contains (e.getX(),e.getY()))
401 aObjectUnderMouse = aObject;
402 break;
405 return aObjectUnderMouse;
408 private boolean highlightObject (CanvasShape aNewActiveObject)
410 if (aNewActiveObject != maActiveObject)
412 if (maActiveObject != null)
413 maActiveObject.unhighlight();
415 maActiveObject = aNewActiveObject;
416 if (maActiveObject != null)
418 if (maTree != null)
420 maTree.scrollPathToVisible (maActiveObject.getPath());
421 maTree.setSelectionPath (maActiveObject.getPath());
422 maTree.repaint ();
424 maActiveObject.highlight ();
425 repaint ();
427 return true;
429 else
430 return false;
433 /** Called when the selection of the tree changes. Highlight the
434 corresponding graphical representation of the first selected object.
436 public void valueChanged (javax.swing.event.TreeSelectionEvent event)
438 TreePath aPath = event.getPath();
439 Object aObject = aPath.getLastPathComponent();
440 if (aObject instanceof AccTreeNode)
442 CanvasShape aCanvasShape = maObjects.get (aObject);
443 if (highlightObject (aCanvasShape))
444 repaint();
448 private double
449 mnHOffset,
450 mnVOffset,
451 mnScale;
452 private CanvasShape
453 maActiveObject;
454 private final java.util.HashMap<AccTreeNode, CanvasShape>
455 maObjects;
456 private final List<CanvasShape>
457 maObjectList;
458 private final List<AccTreeNode>
459 maNodes;
460 private Rectangle
461 maBoundingBox;
462 private JTree
463 maTree;