/************************************************************************* * * $RCSfile: WindowsAccessBridgeAdapter.java,v $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ package org.openoffice.accessibility; import com.sun.star.accessibility.AccessibleRole; import com.sun.star.accessibility.XAccessible; import com.sun.star.accessibility.XAccessibleContext; import com.sun.star.java.XJavaVM; import com.sun.star.uno.*; import org.openoffice.java.accessibility.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.accessibility.*; public class WindowsAccessBridgeAdapter { private static Method registerVirtualFrame; private static Method revokeVirtualFrame; private static java.util.Hashtable frameMap; protected static native byte[] getProcessID(); protected static native boolean createMapping(long jvmaccess); // On Windows all native frames must be registered to the access bridge. // Therefor the bridge exports two methods that we try to find here. protected static void attach(XComponentContext xComponentContext) { try { Class bridge = Class.forName( "com.sun.java.accessibility.AccessBridge"); Class[] parameterTypes = { javax.accessibility.Accessible.class, Integer.class }; if (bridge != null) { registerVirtualFrame = bridge.getMethod("registerVirtualFrame", parameterTypes); revokeVirtualFrame = bridge.getMethod("revokeVirtualFrame", parameterTypes); // load the native dll System.loadLibrary("java_uno_accessbridge"); Object any = xComponentContext.getValueByName( "/singletons/com.sun.star.java.theJavaVirtualMachine"); if (AnyConverter.isObject(any)) { XJavaVM xJavaVM = (XJavaVM) UnoRuntime.queryInterface(XJavaVM.class, AnyConverter.toObject(new Type(XJavaVM.class), any)); if (xJavaVM != null) { any = xJavaVM.getJavaVM(getProcessID()); if (AnyConverter.isLong(any)) { createMapping(AnyConverter.toLong(any)); frameMap = new java.util.Hashtable(); } } } } } catch (NoSuchMethodException e) { System.err.println("ERROR: incompatible AccessBridge found: " + e.getMessage()); // Forward this exception to UNO to indicate that the service will // not work correctly. throw new com.sun.star.uno.RuntimeException( "incompatible AccessBridge class: " + e.getMessage()); } catch (java.lang.SecurityException e) { System.err.println("ERROR: no access to AccessBridge: " + e.getMessage()); // Forward this exception to UNO to indicate that the service will not work correctly. throw new com.sun.star.uno.RuntimeException( "Security exception caught: " + e.getMessage()); } catch (ClassNotFoundException e) { // Forward this exception to UNO to indicate that the service will not work correctly. throw new com.sun.star.uno.RuntimeException( "ClassNotFound exception caught: " + e.getMessage()); } catch (IllegalArgumentException e) { System.err.println("IllegalArgumentException caught: " + e.getMessage()); // Forward this exception to UNO to indicate that the service will not work correctly. throw new com.sun.star.uno.RuntimeException( "IllegalArgumentException caught: " + e.getMessage()); } catch (com.sun.star.lang.IllegalArgumentException e) { System.err.println("UNO IllegalArgumentException caught: " + e.getMessage()); // Forward this exception to UNO to indicate that the service will not work correctly. throw new com.sun.star.uno.RuntimeException( "UNO IllegalArgumentException caught: " + e.getMessage()); } } protected static boolean isAttached() { return frameMap != null; } protected static Accessible getAccessibleWrapper(XAccessible xAccessible) { Accessible a = null; try { XAccessibleContext xAccessibleContext = xAccessible.getAccessibleContext(); if (xAccessibleContext != null) { switch (xAccessibleContext.getAccessibleRole()) { case AccessibleRole.LIST: a = (Accessible) AccessibleObjectFactory.getAccessibleComponent(xAccessible); if (a != null) { a = new ListProxy(a.getAccessibleContext()); } break; case AccessibleRole.MENU: Accessible tmp = (Accessible) AccessibleObjectFactory.getAccessibleComponent(xAccessible); if (tmp != null) { AccessibleContext ac = tmp.getAccessibleContext(); if (ac != null) { a = new PopupMenuProxy(ac); } } break; case AccessibleRole.TOOL_TIP: a = PopupWindow.create(xAccessible); break; default: a = (Accessible) AccessBridge.getTopWindow(xAccessible); break; } } } catch (com.sun.star.uno.RuntimeException e) { } return a; } /** Registers a native frame at the Java AccessBridge for Windows */ public static void registerTopWindow(int handle, XAccessible xAccessible) { Integer hwnd = new Integer(handle); if (!frameMap.contains(hwnd)) { if (Build.DEBUG) { System.err.println("Native frame " + hwnd + " of role " + AccessibleRoleAdapter.getAccessibleRole(xAccessible) + " has been opened"); } Accessible a = getAccessibleWrapper(xAccessible); if (a != null) { Object[] args = { a, hwnd }; frameMap.put(hwnd, a); if (Build.DEBUG) { System.err.println("registering native frame " + hwnd); } try { registerVirtualFrame.invoke(null, args); } catch (IllegalAccessException e) { System.err.println("IllegalAccessException caught: " + e.getMessage()); } catch (IllegalArgumentException e) { System.err.println("IllegalArgumentException caught: " + e.getMessage()); } catch (InvocationTargetException e) { System.err.println("InvokationTargetException caught: " + e.getMessage()); } } } } /** Revokes a native frame at the Java AccessBridge for Windows */ public static void revokeTopWindow(int handle, XAccessible xAccessible) { Integer hwnd = new Integer(handle); Accessible a = (Accessible) frameMap.remove(hwnd); if (a != null) { Object[] args = { a, hwnd }; if (Build.DEBUG) { System.err.println("revoking native frame " + hwnd); } try { revokeVirtualFrame.invoke(null, args); } catch (IllegalAccessException e) { System.err.println("IllegalAccessException caught: " + e.getMessage()); } catch (IllegalArgumentException e) { System.err.println("IllegalArgumentException caught: " + e.getMessage()); } catch (InvocationTargetException e) { System.err.println("InvokationTargetException caught: " + e.getMessage()); } } if (a instanceof PopupWindow) { PopupWindow toolTipWindow = (PopupWindow) a; toolTipWindow.removeAll(); toolTipWindow.dispose(); } } protected static class PopupMenuProxy extends AccessibleContext implements Accessible, AccessibleComponent { AccessibleContext menu; AccessibleComponent menuComponent; int x = 0; int y = 0; int width = 0; int height = 0; PopupMenuProxy(AccessibleContext ac) { menu = ac; menuComponent = menu.getAccessibleComponent(); /** calculate the bounding rectangle by iterating over the * the children. */ int x2 = 0; int y2 = 0; int count = ac.getAccessibleChildrenCount(); for (int i = 0; i < count; i++) { Accessible a = menu.getAccessibleChild(i); if (a != null) { AccessibleContext childAC = a.getAccessibleContext(); if (childAC != null) { AccessibleComponent comp = ac.getAccessibleComponent(); if (comp != null) { java.awt.Point p = comp.getLocationOnScreen(); java.awt.Dimension d = comp.getSize(); if (p != null && d != null) { if (p.x < x) { x = p.x; } if (p.y < y) { y = p.y; } if (p.x + d.width > x2) { x2 = p.x + d.width; } if (p.y + d.height > y2) { y2 = p.y + d.height; } } } } } } width = x2 - x; height = y2 - y; } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleContext getAccessibleContext() { return this; } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleComponent getAccessibleComponent() { return this; } /** Returns the AccessibleText associated with this object */ public javax.accessibility.AccessibleText getAccessibleText() { return menu.getAccessibleText(); } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleStateSet getAccessibleStateSet() { return menu.getAccessibleStateSet(); } public java.util.Locale getLocale() { return menu.getLocale(); } public int getAccessibleIndexInParent() { return -1; } public int getAccessibleChildrenCount() { return menu.getAccessibleChildrenCount(); } public javax.accessibility.Accessible getAccessibleChild(int i) { return menu.getAccessibleChild(i); } public javax.accessibility.AccessibleRole getAccessibleRole() { return javax.accessibility.AccessibleRole.POPUP_MENU; } /* * AccessibleComponent */ public void addFocusListener(java.awt.event.FocusListener fl) { menuComponent.addFocusListener(fl); } public void removeFocusListener(java.awt.event.FocusListener fl) { menuComponent.removeFocusListener(fl); } /** Returns the background color of the object */ public java.awt.Color getBackground() { return menuComponent.getBackground(); } public void setBackground(java.awt.Color c) { // Not supported by UNO accessibility API } /** Returns the foreground color of the object */ public java.awt.Color getForeground() { return menuComponent.getForeground(); } public void setForeground(java.awt.Color c) { menuComponent.setForeground(c); } public java.awt.Cursor getCursor() { return menuComponent.getCursor(); } public void setCursor(java.awt.Cursor cursor) { menuComponent.setCursor(cursor); } public java.awt.Font getFont() { return menuComponent.getFont(); } public void setFont(java.awt.Font f) { menuComponent.setFont(f); } public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { return menuComponent.getFontMetrics(f); } public boolean isEnabled() { return menuComponent.isEnabled(); } public void setEnabled(boolean b) { menuComponent.setEnabled(b); } public boolean isVisible() { return menuComponent.isVisible(); } public void setVisible(boolean b) { menuComponent.setVisible(b); } public boolean isShowing() { return menuComponent.isShowing(); } public boolean contains(java.awt.Point p) { java.awt.Dimension d = getSize(); if (Build.DEBUG) { System.err.println("PopupMenuProxy.containsPoint(" + p.x + "," + p.y + ") returns " + (((d.width >= 0) && (p.x < d.width) && (d.height >= 0) && (p.y < d.height)) ? "true" : "false")); } if ((d.width >= 0) && (p.x < d.width) && (d.height >= 0) && (p.y < d.height)) { return true; } return false; } /** Returns the location of the object on the screen. */ public java.awt.Point getLocationOnScreen() { return new java.awt.Point(x,y); } /** Gets the location of this component in the form of a point specifying the component's top-left corner */ public java.awt.Point getLocation() { // This object represents a toplevel, so this is the same as getLocationOnScreen() return getLocationOnScreen(); } /** Moves this component to a new location */ public void setLocation(java.awt.Point p) { // Not supported by UNO accessibility API } /** Gets the bounds of this component in the form of a Rectangle object */ public java.awt.Rectangle getBounds() { return new java.awt.Rectangle(x, y, width, height); } /** Moves and resizes this component to conform to the new bounding rectangle r */ public void setBounds(java.awt.Rectangle r) { // Not supported by UNO accessibility API } /** Returns the size of this component in the form of a Dimension object */ public java.awt.Dimension getSize() { return new java.awt.Dimension(width, height); } /** Resizes this component so that it has width d.width and height d.height */ public void setSize(java.awt.Dimension d) { // Not supported by UNO accessibility API } /** Returns the Accessible child, if one exists, contained at the local * coordinate Point */ public javax.accessibility.Accessible getAccessibleAt(java.awt.Point p) { java.awt.Point p2 = menuComponent.getLocationOnScreen(); return menuComponent.getAccessibleAt( new java.awt.Point(p.x + x - p2.x, p.y + y - p2.y)); } public boolean isFocusTraversable() { return menuComponent.isFocusTraversable(); } public void requestFocus() { menuComponent.requestFocus(); } } protected static class ListProxy extends AccessibleContext implements Accessible, AccessibleComponent { AccessibleContext list; AccessibleComponent listComponent; ListProxy(AccessibleContext ac) { list = ac; listComponent = list.getAccessibleComponent(); } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleContext getAccessibleContext() { return this; } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleComponent getAccessibleComponent() { return this; } /** Returns the AccessibleSelection associated with this object */ public javax.accessibility.AccessibleSelection getAccessibleSelection() { return list.getAccessibleSelection(); } /** Returns the AccessibleContext associated with this object */ public javax.accessibility.AccessibleStateSet getAccessibleStateSet() { return list.getAccessibleStateSet(); } public java.util.Locale getLocale() { return list.getLocale(); } public int getAccessibleIndexInParent() { return -1; } public int getAccessibleChildrenCount() { return list.getAccessibleChildrenCount(); } public javax.accessibility.Accessible getAccessibleChild(int i) { return list.getAccessibleChild(i); } public javax.accessibility.AccessibleRole getAccessibleRole() { return javax.accessibility.AccessibleRole.LIST; } /* * AccessibleComponent */ public void addFocusListener(java.awt.event.FocusListener fl) { listComponent.addFocusListener(fl); } public void removeFocusListener(java.awt.event.FocusListener fl) { listComponent.removeFocusListener(fl); } /** Returns the background color of the object */ public java.awt.Color getBackground() { return listComponent.getBackground(); } public void setBackground(java.awt.Color c) { // Not supported by UNO accessibility API } /** Returns the foreground color of the object */ public java.awt.Color getForeground() { return listComponent.getForeground(); } public void setForeground(java.awt.Color c) { listComponent.setForeground(c); } public java.awt.Cursor getCursor() { return listComponent.getCursor(); } public void setCursor(java.awt.Cursor cursor) { listComponent.setCursor(cursor); } public java.awt.Font getFont() { return listComponent.getFont(); } public void setFont(java.awt.Font f) { listComponent.setFont(f); } public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { return listComponent.getFontMetrics(f); } public boolean isEnabled() { return listComponent.isEnabled(); } public void setEnabled(boolean b) { listComponent.setEnabled(b); } public boolean isVisible() { return listComponent.isVisible(); } public void setVisible(boolean b) { listComponent.setVisible(b); } public boolean isShowing() { return listComponent.isShowing(); } public boolean contains(java.awt.Point p) { return listComponent.contains(p); } /** Returns the location of the object on the screen. */ public java.awt.Point getLocationOnScreen() { return listComponent.getLocationOnScreen(); } /** Gets the location of this component in the form of a point specifying * the component's top-left corner */ public java.awt.Point getLocation() { // This object represents a toplevel object, so getLocation() should // return the same as getLocationOnScreen(). return getLocationOnScreen(); } /** Moves this component to a new location */ public void setLocation(java.awt.Point p) { // Not supported by UNO accessibility API } /** Gets the bounds of this component in the form of a Rectangle object */ public java.awt.Rectangle getBounds() { java.awt.Point p = getLocationOnScreen(); java.awt.Dimension d = getSize(); return new java.awt.Rectangle(p.x, p.y, d.width, d.height); } /** Moves and resizes this component to conform to the new bounding rectangle r */ public void setBounds(java.awt.Rectangle r) { // Not supported by UNO accessibility API } /** Returns the size of this component in the form of a Dimension object */ public java.awt.Dimension getSize() { return listComponent.getSize(); } /** Resizes this component so that it has width d.width and height d.height */ public void setSize(java.awt.Dimension d) { // Not supported by UNO accessibility API } /** Returns the Accessible child, if one exists, contained at the local * coordinate Point */ public javax.accessibility.Accessible getAccessibleAt(java.awt.Point p) { return listComponent.getAccessibleAt(p); } public boolean isFocusTraversable() { return listComponent.isFocusTraversable(); } public void requestFocus() { listComponent.requestFocus(); } } }