Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4370001

Accessibility does not work inside appletviewer or plugin window

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 1.4.0
    • 1.1.8
    • client-libs
    • beta
    • x86
    • windows_nt
    • Verified

      the object.
         */
        public void setSize(Dimension d)
        {
          _component.setSize(d);
        }

        /**
         * Returns the Accessible child, if one exists, contained at the local
         * coordinate Point.
         *
         * @param p The point defining the top-left corner of the Accessible,
         * given in the coordinate space of the object's parent.
         * @return the Accessible, if it exists, at the specified location;
         * else null
         */
        public Accessible getAccessibleAt(Point p)
        {
          Component c = _component;

          if (c instanceof Accessible)
          {
            AccessibleContext ac = ((Accessible) c).getAccessibleContext();
            if (ac != null)
            {
              AccessibleComponent acmp;
              Point location;
              int nchildren = ac.getAccessibleChildrenCount();
              for (int i=0; i < nchildren; i++)
              {
                Accessible a = ac.getAccessibleChild(i);
                if (a != null)
                {
                  ac = a.getAccessibleContext();
                  if (ac != null)
                  {
                    acmp = ac.getAccessibleComponent();
                    if ((acmp != null) && (acmp.isShowing()))
                    {
                      location = acmp.getLocation();
                      Point np = new Point(p.x - location.x,
                                           p.y - location.y);
                      if (acmp.contains(np)){
                        return a;
                      }
                    }
                  }
                }
              }
            }

            return (Accessible) c;
          }
          else
          {
            Component ret = c;

            if (!c.contains(p.x,p.y))
            {
              ret = null;
            }
            else if (c instanceof Container)
            {
              Container cnt = (Container) c;
              int ncomponents = cnt.getComponentCount();
              for (int i=0; i < ncomponents; i++)
              {
                Component comp = cnt.getComponent(i);
                if (comp.isShowing())
                {
                  Point location = comp.getLocation();

                  if (comp.contains(p.x-location.x, p.y-location.y))
                  {
                    ret = comp;
                  }
                }
              }
            }

            if (ret instanceof Accessible)
            {
              return (Accessible) ret;
            }
          }

          return null;
        }

        /**
         * Returns whether this object can accept focus or not.
         *
         * @return true if object can accept focus; otherwise false
         */
        public boolean isFocusTraversable()
        {
          return _component.isFocusTraversable();
        }

        /**
         * Requests focus for this object.
         */
        public void requestFocus()
        {
          _component.requestFocus();
        }

        /**
         * Adds the specified focus listener to receive focus events from this
         * component.
         *
         * @param l the focus listener
         */
        public void addFocusListener(FocusListener l)
        {
          _component.addFocusListener(l);
        }

        /**
         * Removes the specified focus listener so it no longer receives focus
         * events from this component.
         *
         * @param l the focus listener
         */
        public void removeFocusListener(FocusListener l)
        {
          _component.removeFocusListener(l);
        }

        /**
         * Returns the component this accessibility is bound to.
         */
        protected Component getComponent()
        {
          return _component;
        }

        /**
         * Fire PropertyChange listener, if one is registered,
         * when children added/removed.
         */
        private class AccessibleContainerHandler implements ContainerListener
        {
          //
          // =-= FSB The Accessibility API states that when Accessible children
          // are added or removed we should send an ACCESSIBLE_CHILD_PROPERTY
          // event with the Accessible child as the old or new parameter. For
          // some reason we have to send the AccessibleContext of the
          // Accessible child and not the Accessible object itself.
          //
          public void componentAdded(ContainerEvent e)
          {
            Component c = e.getChild();
            if (c instanceof Accessible)
            {
              firePropertyChange(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
                                 null, ((Accessible)c).getAccessibleContext());
            }
          }

          public void componentRemoved(ContainerEvent e)
          {
            Component c = e.getChild();
            if (c instanceof Accessible)
            {
              firePropertyChange(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
                                 ((Accessible)c).getAccessibleContext(), null);
            }
          }
        }

        private void _firePropertyChange(boolean on, Object state)
        {
          firePropertyChange(ACCESSIBLE_STATE_PROPERTY,
                             on ? state : null,
                             on ? null : state);
        }


        private Component _component;
        private ContainerListener _accessibleContainerHandler;
      }
      (Review ID: 109493)
      ======================================================================


      Name: mt13159 Date: 09/11/2000


      Accessibility support is not working for components created inside the AppletViewer or Plug-in frame. The following test case illustrates the problem. It creates two JLists: one inside the AppletViewer frame and one in a separate frame. If you run this applet in AppletViewer or Plug-in with the Accessibility bridge and a screen reader, the screen reader will only read the JList in the separate frame.

      import java.awt.BorderLayout;
      import javax.swing.JApplet;
      import javax.swing.JFrame;
      import javax.swing.JList;
      import javax.swing.JScrollPane;

      public class AccessBug extends JApplet
      {
          static final String[] _ITEMS = {"item 1", "item 2",
                                          "item 3", "item 4"};

          public void init()
          {
              JList list = new JList(_ITEMS);
              getContentPane().setLayout(new BorderLayout());
              getContentPane().add(BorderLayout.CENTER,
                                   new JScrollPane(list));
          }

          private JFrame _frame;

          public void start()
          {
              _frame = new JFrame();
              JList list = new JList(_ITEMS);
              _frame.getContentPane().setLayout(new BorderLayout());
              _frame.getContentPane().add(BorderLayout.CENTER,
                                          new JScrollPane(list));

              _frame.setBounds(110, 0, 100,140);
              _frame.setVisible(true);
          }

          public void stop()
          {
              _frame.setVisible(false);
          }
      }


      The problem is that the AppletViewer and Plug-in frames do not implement the Accessible interface, making it impossible for accessibility to work with any components inside them.
      The fix is to implement Accessible on the following classes:
      sun.applet.AppletViewer
      sun.applet.AppletViewerPanel
      sun.plugin.AppletViewer

      Our accessibility team has suggested this be fixed with the following code. On each of the above classes, add "implements Accessible" to the class declaration, and add the following code:

          private AccessibleContext _accessibleContext;
          public AccessibleContext getAccessibleContext()
          {
              if (_accessibleContext == null)
              {
                  _accessibleContext = new Access();
              }
          
              return _accessibleContext;
          }
          
          private class Access extends AccessibleComponentImpl
          {
              public Access()
              {
                  super(AppletViewerPanel.this);
              }
          
              public AccessibleRole getAccessibleRole()
              {
                  return AccessibleRole.FRAME;
              }
          }

      The AccessibleRole should be PANEL for AppletViewerPanel. AccessibleComponentImpl is defined as follows:

      package sun.applet;

      import java.awt.Color;
      import java.awt.Component;
      import java.awt.Container;
      import java.awt.Cursor;
      import java.awt.Dimension;
      import java.awt.Font;
      import java.awt.FontMetrics;
      import java.awt.Point;
      import java.awt.Rectangle;

      import java.awt.event.ContainerEvent;
      import java.awt.event.ContainerListener;
      import java.awt.event.FocusListener;

      import java.util.Locale;

      import javax.accessibility.Accessible;
      import javax.accessibility.AccessibleComponent;
      import javax.accessibility.AccessibleContext;
      import javax.accessibility.AccessibleSelection;
      import javax.accessibility.AccessibleRole;
      import javax.accessibility.AccessibleState;
      import javax.accessibility.AccessibleStateSet;


      /**
       * AccessibleContext implementation for Components.
       */
      public class AccessibleComponentImpl extends AccessibleContext
                                         implements AccessibleComponent
      {
        public AccessibleComponentImpl(Component component)
        {
            _component = component;

            // add the container listener that fires the
            // accessible child events in the constructor just to be safe
            if (_component instanceof Container)
            {
              _accessibleContainerHandler = new AccessibleContainerHandler();

              ((Container) _component).
                 addContainerListener(_accessibleContainerHandler);
            }
        }

        // AccessibleContext methods
        //

        /**
         * Get the role of this object.
         *
         * @return an instance of AccessibleRole describing the role of the
         * object
         * @see AccessibleRole
         */
        public AccessibleRole getAccessibleRole()
        {
          return AccessibleRole.AWT_COMPONENT;
        }

        /**
         * Get the state of this object.
         *
         * @return an instance of AccessibleStateSet containing the current
         * state set of the object
         * @see AccessibleState
         */
        public AccessibleStateSet getAccessibleStateSet()
        {
          Component c = _component;

          AccessibleStateSet states = new AccessibleStateSet();
          if (c.isEnabled())
            states.add(AccessibleState.ENABLED);

          if (c.isFocusTraversable())
            states.add(AccessibleState.FOCUSABLE);

          if (c.isVisible())
          {
            states.add(AccessibleState.VISIBLE);

            if (c.isShowing())
              states.add(AccessibleState.SHOWING);
          }

          if (c instanceof Accessible)
          {
            AccessibleContext ac = ((Accessible) c).getAccessibleContext();
            if (ac != null)
            {
              Accessible ap = ac.getAccessibleParent();
              if (ap != null)
              {
                AccessibleContext pac = ap.getAccessibleContext();
                if (pac != null)
                {
                  AccessibleSelection as = pac.getAccessibleSelection();
                  if (as != null)
                  {
                    states.add(AccessibleState.SELECTABLE);
                    int i = ac.getAccessibleIndexInParent();
                    if (i >= 0)
                    {
                      if (as.isAccessibleChildSelected(i))
                      {
                        states.add(AccessibleState.SELECTED);
                      }
                    }
                  }
                }
              }
            }
          }

          return states;
        }

        /**
         * Get the Accessible parent of this object. If the parent of this
         * object implements Accessible, this method should simply return
         * getParent().
         *
         * @return the Accessible parent of this object -- can be null if this
         * object does not have an Accessible parent
         */
        public Accessible getAccessibleParent()
        {
          if (accessibleParent != null)
          {
            return accessibleParent;
          }
          else
          {
            Component parent = _component.getParent();
            if (parent instanceof Accessible)
            {
              return (Accessible) parent;
            }
          }

          return null;
        }


        /**
         * Get the index of this object in its accessible parent.
         *
         * @return the index of this object in its parent; -1 if this
         * object does not have an accessible parent.
         * @see #getAccessibleParent
         */
        public int getAccessibleIndexInParent()
        {
          Component c = _component;
          int index = -1;
          Container parent = c.getParent();

          if (parent instanceof Accessible)
          {
            Component ca[] = parent.getComponents();
            for (int i = 0; i < ca.length; i++)
            {
              if (ca[i] instanceof Accessible)
                index++;

              if (c == ca[i])
                return index;
            }
          }

          return -1;
        }

        /**
         * Returns the number of accessible children in the object. If all
         * of the children of this object implement Accessible, than this
         * method should return the number of children of this object.
         *
         * @return the number of accessible children in the object.
         */
        public int getAccessibleChildrenCount()
        {
          Component c = _component;
          int count = 0;
          if (c instanceof Container)
          {
            Component[] children = ((Container) c).getComponents();
            for (int i = 0; i < children.length; i++)
            {
              if (children[i] instanceof Accessible)
              {
                count++;
              }
            }
          }

          return count;

        }

        /**
         * Return the nth Accessible child of the object.
         *
         * @param i zero-based index of child
         * @return the nth Accessible child of the object
         */
        public Accessible getAccessibleChild(int i)
        {
          Component c = _component;
          if (c instanceof Container)
          {
            Component[] children = ((Container) c).getComponents();
            int count = 0;
            for (int j = 0; j < children.length; j++)
            {
              Component child = children[j];
              if (child instanceof Accessible)
              {
                if (count == i)
                {
                  return (Accessible) child;
                }
                else
                {
                  count++;
                }
              }
            }
          }

          return null;
        }

        /**
         * Return the locale of this object.
         *
         * @return the locale of this object
         */
        public Locale getLocale()
        {
          return _component.getLocale();
        }

        /**
         * Get the AccessibleComponent associated with this object if one
         * exists. Otherwise return null.
         *
         * @return the component
         */
        public AccessibleComponent getAccessibleComponent()
        {
          return this;
        }


        // AccessibleComponent methods
        //
        /**
         * Get the background color of this object.
         *
         * @return the background color, if supported, of the object;
         * otherwise, null
         */
        public Color getBackground()
        {
          return _component.getBackground();
        }

        /**
         * Set the background color of this object.
         */
        public void setBackground(Color c)
        {
          _component.setBackground(c);
        }

        /**
         * Get the foreground color of this object.
         *
         * @return the foreground color, if supported, of the object;
         * otherwise, null
         */
        public Color getForeground()
        {
          return _component.getForeground();
        }

        /**
         * Set the foreground color of this object.
         *
         * @param c the new Color for the foreground
         */
        public void setForeground(Color c)
        {
          _component.setForeground(c);
        }

        /**
         * Get the Cursor of this object.
         *
         * @return the Cursor, if supported, of the object; otherwise, null
         */
        public Cursor getCursor()
        {
          // =-=AEW Hack to get "Monkey" utility to work with JDK 1.1.8
          Cursor cursor = _component.getCursor();
          if (cursor == null)
            cursor = Cursor.getDefaultCursor();
          return cursor;
          // return _component.getCursor();
        }

        /**
         * Set the Cursor of this object.
         *
         * @param c the new Cursor for the object
         */
        public void setCursor(Cursor cursor)
        {
          _component.setCursor(cursor);
        }

        /**
         * Get the Font of this object.
         *
         * @return the Font,if supported, for the object; otherwise, null
         */
        public Font getFont()
        {
          return _component.getFont();
        }

        /**
         * Set the Font of this object.
         *
         * @param f the new Font for the object
         */
        public void setFont(Font f)
        {
          _component.setFont(f);
        }

        /**
         * Get the FontMetrics of this object.
         *
         * @param f the Font
         * @return the FontMetrics, if supported, the object; otherwise, null
         * @see #getFont
         */
        public FontMetrics getFontMetrics(Font f)
        {
          return _component.getFontMetrics(f);
        }

        /**
         * Determine if the object is enabled.
         *
         * @return true if object is enabled; otherwise, false
         */
        public boolean isEnabled()
        {
          return _component.isEnabled();
        }

        /**
         * Set the enabled state of the object.
         *
         * @param b if true, enables this object; otherwise, disables it
         */
        public void setEnabled(boolean b)
        {
          boolean old = isEnabled();
          _component.setEnabled(b);
          if (b != old)
            _firePropertyChange(b, AccessibleState.ENABLED);
        }

        /**
         * Determine if the object is visible. Note: this means that the
         * object intends to be visible; however, it may not in fact be
         * showing on the screen because one of the objects that this object
         * is contained by is not visible. To determine if an object is
         * showing on the screen, use isShowing().
         *
         * @return true if object is visible; otherwise, false
         */
        public boolean isVisible()
        {
          return _component.isVisible();
        }

        /**
         * Set the visible state of the object.
         *
         * @param b if true, shows this object; otherwise, hides it
         */
        public void setVisible(boolean b)
        {
          boolean old = isVisible();
          _component.setVisible(b);
          if (b != old)
            _firePropertyChange(b, AccessibleState.VISIBLE);
        }

        /**
         * Determine if the object is showing. This is determined by checking
         * the visibility of the object and ancestors of the object. Note:
         * this will return true even if the object is obscured by another
         * (for example, it happens to be underneath a menu that was pulled
         * down).
         *
         * @return true if object is showing; otherwise, false
         */
        public boolean isShowing()
        {
          return _component.isShowing();
        }

        /**
         * Checks whether the specified point is within this object's bounds,
         * where the point's x and y coordinates are defined to be relative to
         * the coordinate system of the object.
         *
         * @param p the Point relative to the coordinate system of the object
         * @return true if object contains Point; otherwise false
         */
        public boolean contains(Point p)
        {
          return _component.contains(p);
        }

        /**
         * Returns the location of the object on the screen.
         *
         * @return location of object on screen -- can be null if this object
         * is not on the screen
         */
        public Point getLocationOnScreen()
        {
          if (_component.isShowing())
          {
            return _component.getLocationOnScreen();
          }
          else
          {
            return null;
          }
        }

        /**
         * Gets the location of the object relative to the parent in the form
         * of a point specifying the object's top-left corner in the screen's
         * coordinate space.
         *
         * @return An instance of Point representing the top-left corner of
         * the objects's bounds in the coordinate space of the screen; null if
         * this object or its parent are not on the screen
         */
        public Point getLocation()
        {
          return _component.getLocation();
        }

        /**
         * Sets the location of the object relative to the parent.
         */
        public void setLocation(Point p)
        {
          _component.setLocation(p);
        }

        /**
         * Gets the bounds of this object in the form of a Rectangle object.
         * The bounds specify this object's width, height, and location
         * relative to its parent.
         *
         * @return A rectangle indicating this component's bounds; null if
         * this object is not on the screen.
         */
        public Rectangle getBounds()
        {
          return _component.getBounds();
        }

        /**
         * Sets the bounds of this object in the form of a Rectangle object.
         * The bounds specify this object's width, height, and location
         * relative to its parent.
         *
         * @param A rectangle indicating this component's bounds
         */
        public void setBounds(Rectangle r)
        {
          _component.setBounds(r);
        }

        /**
         * Returns the size of this object in the form of a Dimension object.
         * The height field of the Dimension object contains this objects's
         * height, and the width field of the Dimension object contains this
         * object's width.
         *
         * @return A Dimension object that indicates the size of this
         * component; null if this object is not on the screen
         */
        public Dimension getSize()
        {
          return _component.getSize();
        }

        /**
         * Resizes this object so that it has width width and height.
         *
         * @param d - The dimension specifying the new size of

            lmonsantsunw Lynn Monsanto (Inactive)
            mthakore Mayank Thakore (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: