diff options
Diffstat (limited to 'odk/examples/DevelopersGuide/Accessibility')
12 files changed, 2288 insertions, 0 deletions
diff --git a/odk/examples/DevelopersGuide/Accessibility/ConnectionTask.java b/odk/examples/DevelopersGuide/Accessibility/ConnectionTask.java new file mode 100644 index 000000000000..7bf9bdb88cd5 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/ConnectionTask.java @@ -0,0 +1,208 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.event.ActionListener; +import javax.swing.*; +import java.awt.*; +import java.util.*; + +import com.sun.star.awt.XFocusListener; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.accessibility.*; +import com.sun.star.awt.XExtendedToolkit; + + +/** This timer task tries to connect to a running Office application in regular + intervals until a connection can be successfully established. +*/ +class ConnectionTask + extends TimerTask +{ + public ConnectionTask (EventListenerProxy xListener) + { + Init (xListener); + } + + private void Init (EventListenerProxy xListener) + { + mxListener = xListener; + mbInitialized = false; + + maTimer = new java.util.Timer (); + maTimer.schedule (this, 0, mnPeriod); + } + + + /** This method is run every time the task is executed. It tries to + connect to and register the listener at an Office application. If it + can establish a connection it terminates the timer task. Otherwise it + waits until the next activation. + */ + public void run () + { + if (registerListeners()) + { + // Focus listener was successfully registered so we can cancel this task. + MessageArea.println ("\nconnected successfully to office"); + cancel (); + maTimer = null; + } + } + + + + + /** Try to register the listener. + */ + private boolean registerListeners () + { + // Get toolkit. + XExtendedToolkit xToolkit = getToolkit (); + + // Register at toolkit as focus event listener. + if (xToolkit != null) + { + xToolkit.addTopWindowListener (mxListener); + int nTopWindowCount = xToolkit.getTopWindowCount(); + try + { + com.sun.star.lang.EventObject aEvent = new com.sun.star.lang.EventObject(); + for (int i=0; i<nTopWindowCount; i++) + { + XAccessible xAccessible = (XAccessible) UnoRuntime.queryInterface( + XAccessible.class, + xToolkit.getTopWindow(i)); + XAccessibleContext xContext = xAccessible.getAccessibleContext(); + if (xContext.getAccessibleName().length() > 0) + { + // Simulate an event that leads to registration the + // listener at the window. + aEvent.Source = xToolkit.getTopWindow(i); + mxListener.windowOpened (aEvent); + } + } + } + + catch (com.sun.star.lang.IndexOutOfBoundsException aException) + { + // This exception signals that the number of top windows has + // changed since our last call to getTopWindowCount(). + } + return true; + } + else + return false; + } + + + + + /** Get the toolkit from an Office which can then be used to register + the listener. + */ + private XExtendedToolkit getToolkit () + { + XMultiServiceFactory xFactory = connectToOffice(); + + // Get toolkit. + XExtendedToolkit xToolkit = null; + try + { + if (xFactory != null) + { + xToolkit = (XExtendedToolkit) UnoRuntime.queryInterface( + XExtendedToolkit.class, + xFactory.createInstance ("stardiv.Toolkit.VCLXToolkit")); + } + } + catch (com.sun.star.uno.Exception aException) + { + MessageArea.println ("caught exception while creating extended toolkit"); + // Ignored. + } + + return xToolkit; + } + + + + + /** Connect to a running (Star|Open)Office application + */ + private XMultiServiceFactory connectToOffice () + { + // connect to a running office and get the ServiceManager + try + { + com.sun.star.uno.XComponentContext xCmpContext = null; + + // get the remote office component context + xCmpContext = com.sun.star.comp.helper.Bootstrap.bootstrap(); + if( xCmpContext != null ) + System.out.println("Connected to a running office ..."); + + // get the remote office service manager + com.sun.star.lang.XMultiComponentFactory xMCF = + xCmpContext.getServiceManager(); + + return (XMultiServiceFactory) UnoRuntime.queryInterface ( + XMultiServiceFactory.class, xMCF); + } + + catch (Exception e) + { + if ( ! mbInitialized) + MessageArea.println ("Could not connect to office"); + else + MessageArea.print ("."); + } + mbInitialized = true; + return null; + } + + /** Time in milliseconds between two attempts to connect to an Office + application. + */ + private int mnPeriod = 1000; + + private EventListenerProxy mxListener; + private boolean mbInitialized; + + /** This timer is used for the registration loop to retry to connect to + the Office until a connection can be established. + */ + private java.util.Timer maTimer; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/EventHandler.java b/odk/examples/DevelopersGuide/Accessibility/EventHandler.java new file mode 100644 index 000000000000..61395bba7d70 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/EventHandler.java @@ -0,0 +1,447 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.util.Vector; + +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.Type; +import com.sun.star.accessibility.*; + +/** Handle all the events send from accessibility objects. The events + denoting new or removed top windows are handled as well. + + It does not implement any listener interface as does the + EventListenerProxy class because it is interested only in a sub set of + the event types. +*/ +public class EventHandler +{ + public EventHandler () + { + mnTopWindowCount = 0; + maListenerProxy = new EventListenerProxy (this); + maConnectionTask = new ConnectionTask (maListenerProxy); + maObjectDisplays = new Vector (); + } + + public synchronized void addObjectDisplay (IAccessibleObjectDisplay aDisplay) + { + maObjectDisplays.add (aDisplay); + } + + + public void finalize () + { + // When it is running then cancel the timer that tries to connect to + // the Office. + if (maConnectionTask != null) + maConnectionTask.cancel(); + } + + + + public void disposing (com.sun.star.lang.EventObject aEvent) + { + // Ignored: We are not holding references to accessibility objects. + } + + + + + /** This method is called back when a new top level window has been opened. + */ + public void windowOpened (XAccessible xAccessible) + { + if (xAccessible != null) + { + // Update the counter of currently open top level windows + // observed by this object. + mnTopWindowCount += 1; + + XAccessibleContext xContext = xAccessible.getAccessibleContext(); + if (xContext != null) + { + MessageArea.println ("new top level window has accessible name " + + xContext.getAccessibleName()); + + // Register at all accessible objects of the new window. + new RegistrationThread ( + maListenerProxy, + xContext, + true, + true); + } + else + MessageArea.println ("new top level window is not accessible."); + } + else + MessageArea.println ("new top level window is not accessible."); + } + + + + + public void windowClosed (XAccessible xAccessible) + { + mnTopWindowCount -= 1; + MessageArea.println ("window closed, " + mnTopWindowCount + " still open"); + if (mnTopWindowCount == 0) + { + // This was the last window. Wait for a new connection. + MessageArea.println ("lost connection to office"); + new ConnectionTask (maListenerProxy); + } + if (xAccessible != null) + new RegistrationThread ( + maListenerProxy, + xAccessible.getAccessibleContext(), + false, + true); + } + + + + + /** Print a message that the given object just received the focus. Call + all accessible object diplays and tell them to update. + */ + private synchronized void focusGained (XAccessibleContext xContext) + { + if (xContext != null) + { + MessageArea.println ("focusGained: " + xContext.getAccessibleName() + + " with role " + + NameProvider.getRoleName (xContext.getAccessibleRole())); + + // Tell the object displays to update their views. + for (int i=0; i<maObjectDisplays.size(); i++) + { + IAccessibleObjectDisplay aDisplay = + (IAccessibleObjectDisplay)maObjectDisplays.get(i); + if (aDisplay != null) + aDisplay.setAccessibleObject (xContext); + } + + // Remember the currently focused object. + mxFocusedObject = xContext; + } + else + MessageArea.println ("focusGained: null"); + } + + + + + /** Print a message that the given object just lost the focus. Call + all accessible object diplays and tell them to update. + */ + private synchronized void focusLost (XAccessibleContext xContext) + { + if (xContext != null) + { + MessageArea.println ("focusLost: " + + xContext.getAccessibleName() + + " with role " + + NameProvider.getRoleName (xContext.getAccessibleRole())); + + // Tell the object displays to update their views. + for (int i=0; i<maObjectDisplays.size(); i++) + { + IAccessibleObjectDisplay aDisplay = + (IAccessibleObjectDisplay)maObjectDisplays.get(i); + if (aDisplay != null) + aDisplay.setAccessibleObject (null); + } + mxFocusedObject = null; + } + else + MessageArea.println ("focusLost: null"); + } + + + + + /** Handle a change of the caret position. Ignore this on all objects + but the one currently focused. + */ + private void handleCaretEvent (XAccessibleContext xContext, + long nOldPosition, long nNewPosition) + { + if (xContext == mxFocusedObject) + MessageArea.println ("caret moved from " + nOldPosition + " to " + nNewPosition); + } + + + + + /** Print a message that a state has been changed. + @param xContext + The accessible context of the object whose state has changed. + @param nOldState + When not zero then this value describes a state that has been reset. + @param nNewValue + When not zero then this value describes a state that has been set. + */ + private void handleStateChange (XAccessibleContext xContext, short nOldState, short nNewState) + { + // Determine which state has changed and what is its new value. + short nState; + boolean aNewValue; + if (nOldState >= 0) + { + nState = nOldState; + aNewValue = false; + } + else + { + nState = nNewState; + aNewValue = true; + } + + // Print a message about the changed state. + MessageArea.print ("setting state " + NameProvider.getStateName(nState) + + " to " + aNewValue); + if (xContext != null) + { + MessageArea.println (" at " + xContext.getAccessibleName() + " with role " + + NameProvider.getRoleName(xContext.getAccessibleRole())); + } + else + MessageArea.println (" at null"); + + // Further handling of some states + switch (nState) + { + case AccessibleStateType.FOCUSED: + if (aNewValue) + focusGained (xContext); + else + focusLost (xContext); + } + } + + + + + /** Handle a child event that describes the creation of removal of a + single child. + */ + private void handleChildEvent ( + XAccessibleContext aOldChild, + XAccessibleContext aNewChild) + { + if (aOldChild != null) + // Remove event listener from the child and all of its descendants. + new RegistrationThread (maListenerProxy, aOldChild, false, false); + else if (aNewChild != null) + // Add event listener to the new child and all of its descendants. + new RegistrationThread (maListenerProxy, aNewChild, true, false); + } + + + + + /** Handle the change of some visible data of an object. + */ + private void handleVisibleDataEvent (XAccessibleContext xContext) + { + // The given object may affect the visible appearance of the focused + // object even when the two are not identical when the given object + // is an ancestor of the focused object. + // In order to not check this we simply call an update on the + // focused object. + if (mxFocusedObject != null) + for (int i=0; i<maObjectDisplays.size(); i++) + { + IAccessibleObjectDisplay aDisplay = + (IAccessibleObjectDisplay)maObjectDisplays.get(i); + if (aDisplay != null) + aDisplay.updateAccessibleObject (mxFocusedObject); + } + } + + + + + /** Print some information about an event that is not handled by any + more specialized handler. + */ + private void handleGenericEvent ( + int nEventId, + Object aSource, + Object aOldValue, + Object aNewValue) + { + // Print event to message area. + MessageArea.print ("received event " + + NameProvider.getEventName (nEventId) + " from "); + XAccessibleContext xContext = objectToContext (aSource); + if (xContext != null) + MessageArea.print (xContext.getAccessibleName()); + else + MessageArea.print ("null"); + MessageArea.println (" / " + + NameProvider.getRoleName(xContext.getAccessibleRole())); + } + + + + /** This is the main method for handling accessibility events. It is + assumed that it is not called directly from the Office but from a + listener proxy that runs in a separate thread so that calls back to + the Office do not result in dead-locks. + */ + public void notifyEvent (com.sun.star.accessibility.AccessibleEventObject aEvent) + { + try // Guard against disposed objects. + { + switch (aEvent.EventId) + { + case AccessibleEventId.CHILD: + handleChildEvent ( + objectToContext (aEvent.OldValue), + objectToContext (aEvent.NewValue)); + break; + + case AccessibleEventId.STATE_CHANGED: + { + short nOldState = -1; + short nNewState = -1; + try + { + if (AnyConverter.isShort (aEvent.NewValue)) + nNewState = AnyConverter.toShort (aEvent.NewValue); + if (AnyConverter.isShort (aEvent.OldValue)) + nOldState = AnyConverter.toShort (aEvent.OldValue); + } + catch (com.sun.star.lang.IllegalArgumentException e) + {} + handleStateChange ( + objectToContext (aEvent.Source), + nOldState, + nNewState); + } + break; + + case AccessibleEventId.VISIBLE_DATA_CHANGED: + case AccessibleEventId.BOUNDRECT_CHANGED: + handleVisibleDataEvent (objectToContext (aEvent.Source)); + break; + + case AccessibleEventId.CARET_CHANGED: + try + { + handleCaretEvent ( + objectToContext (aEvent.Source), + AnyConverter.toLong(aEvent.OldValue), + AnyConverter.toLong(aEvent.NewValue)); + } + catch (com.sun.star.lang.IllegalArgumentException e) + {} + break; + + default: + handleGenericEvent (aEvent.EventId, + aEvent.Source, aEvent.OldValue, aEvent.NewValue); + break; + } + } + catch (com.sun.star.lang.DisposedException e) + {} + } + + + + + /** Convert the given object into an accessible context. The object is + interpreted as UNO Any and may contain either an XAccessible or + XAccessibleContext reference. + @return + The returned value is null when the given object can not be + converted to an XAccessibleContext reference. + */ + private XAccessibleContext objectToContext (Object aObject) + { + XAccessibleContext xContext = null; + XAccessible xAccessible = null; + try + { + xAccessible = (XAccessible)AnyConverter.toObject( + new Type(XAccessible.class), aObject); + } + catch (com.sun.star.lang.IllegalArgumentException e) + {} + if (xAccessible != null) + xContext = xAccessible.getAccessibleContext(); + else + try + { + xContext = (XAccessibleContext)AnyConverter.toObject( + new Type(XAccessibleContext.class), aObject); + } + catch (com.sun.star.lang.IllegalArgumentException e) + {} + return xContext; + } + + + + + /** The proxy that runs in a seperate thread and allows to call back to + the Office without running into dead-locks. + */ + private EventListenerProxy maListenerProxy; + + /** The currently focused object. A value of null means that no object + has the focus. + */ + private XAccessibleContext mxFocusedObject; + + /** Keep track of the currently open top windows to start a registration + loop when the last window (and the Office) is closed. + */ + private long mnTopWindowCount; + + /** A list of objects that can display accessible objects in specific + ways such as showing a graphical representation or some textual + descriptions. + */ + private Vector maObjectDisplays; + + /** The timer task that attempts in regular intervals to connect to a + running Office application. + */ + private ConnectionTask maConnectionTask; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/EventListenerProxy.java b/odk/examples/DevelopersGuide/Accessibility/EventListenerProxy.java new file mode 100644 index 000000000000..273f6146a6cc --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/EventListenerProxy.java @@ -0,0 +1,232 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleEventListener; +import com.sun.star.accessibility.AccessibleEventObject; +import com.sun.star.lang.EventObject; +import com.sun.star.awt.XTopWindowListener; +import com.sun.star.uno.UnoRuntime; + +import java.util.LinkedList; + +/** This class acts as a proxy for the simple screen reader. It waits for + two types of events: + 1. Accessibility events signal modifications concerning accessibility + objects. + 2. Top window events inform the listener about new or removed windows. + + This class exists because events had to be handled in a seperate thread + to avoid dead locks: The thread that receives an event must no call back + to the Office directly. + + Soon this should not be necessary anymore. There is now a flag which + switches between synchronous and asynchronous callbacks. + + All reveived events are eventually forwarded to the actual listener. In + this way it decouples the Office from the listener. +*/ +class EventListenerProxy + implements Runnable, XAccessibleEventListener, XTopWindowListener +{ + public EventListenerProxy (EventHandler aListener) + { + maListener = aListener; + mbAsynchron = true; + if (mbAsynchron) + { + maEventQueue = new LinkedList(); + new Thread (this, "EventListenerProxy").start(); + } + } + + private void addEvent (Runnable aEventObject) + { + if (mbAsynchron) + synchronized (maEventQueue) + { + maEventQueue.addLast (aEventObject); + // Tell the queue that there is a new event in the queue. + maEventQueue.notify(); + } + else + { + System.out.println ("running " + aEventObject); + aEventObject.run(); + System.out.println (" done"); + } + } + + + + + /** In an infinite loop, check for events to deliver, then wait on lock + (which will be notified when new events arrive) + */ + public void run () + { + while (true) + { + // Process all events that are currently in the queue. + Runnable aEvent; + do + { + synchronized (maEventQueue) + { + if (maEventQueue.size() > 0) + aEvent = (Runnable)maEventQueue.removeFirst(); + else + aEvent = null; + } + + if (aEvent != null) + { + try + { + aEvent.run(); + } + catch (Throwable aException) + { + MessageArea.println( + "Exception during event delivery: " + aException); + aException.printStackTrace(); + } + } + } + while (aEvent != null); + + // Now that the queue is empty go to sleep again. + try + { + synchronized (maEventQueue) + { + maEventQueue.wait(); + } + } + catch (Exception aException) + { + // Ignore this exception since there is not much + // that we can do about it. + } + } + } + + + public void disposing( final EventObject aEvent) + { + addEvent (new Runnable() + { + public void run() + { + maListener.disposing (aEvent); + } + } ); + } + + public void notifyEvent (final AccessibleEventObject aEvent) + { + addEvent ( + new Runnable() + { + public void run() + { + maListener.notifyEvent (aEvent); + } + } ); + } + + public void windowOpened (final com.sun.star.lang.EventObject aEvent) + { + addEvent ( + new Runnable() + { + public void run() + { + maListener.windowOpened ( + (XAccessible) UnoRuntime.queryInterface( + XAccessible.class, + aEvent.Source)); + } + } ); + } + public void windowClosing (final com.sun.star.lang.EventObject aEvent) + { + // Ignored. + } + public void windowClosed (final com.sun.star.lang.EventObject aEvent) + { + addEvent ( + new Runnable() + { + public void run() + { + maListener.windowClosed ( + (XAccessible) UnoRuntime.queryInterface( + XAccessible.class, + aEvent.Source)); + } + } ); + } + public void windowMinimized (com.sun.star.lang.EventObject aEvent) + { + // Ignored. + } + public void windowNormalized (com.sun.star.lang.EventObject aEvent) + { + // Ignored. + } + public void windowActivated (com.sun.star.lang.EventObject aEvent) + { + // Ignored. + } + public void windowDeactivated (com.sun.star.lang.EventObject aEvent) + { + // Ignored. + } + + /** The queue of event objects, LinkedList<Runnable>. + The queue object will also serve as lock for the consumer/producer type + syncronization. + */ + private LinkedList maEventQueue; + + /** This is the actual listener that the events will eventually forwarded to. + */ + private EventHandler maListener; + + /** This flag determines whether event forwarding is done asynchroniously + or synchroniously. + */ + private boolean mbAsynchron; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/GraphicalDisplay.java b/odk/examples/DevelopersGuide/Accessibility/GraphicalDisplay.java new file mode 100644 index 000000000000..37579e1c3242 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/GraphicalDisplay.java @@ -0,0 +1,189 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import javax.swing.*; +import java.awt.Dimension; +import java.awt.*; +import java.awt.geom.*; + +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.accessibility.XAccessibleComponent; + +import com.sun.star.awt.Point; +import com.sun.star.awt.Size; +import com.sun.star.uno.UnoRuntime; + + +/** Display the currently focused accessible object graphically. +*/ +public class GraphicalDisplay + extends JPanel + implements IAccessibleObjectDisplay +{ + /** Create a new graphical widget the displays some of the geometrical + information availbable from accessible objects. + */ + public GraphicalDisplay () + { + setPreferredSize (new Dimension (300,200)); + } + + + /** Paint some or all of the area of this widget with the outlines of + the currently focues object and its ancestors. + */ + public synchronized void paintComponent (Graphics g) + { + super.paintComponent (g); + + setupTransformation (); + + // Draw the screen representation to give a hint of the location of the + // accessible object on the screen. + Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize(); + // Fill the screen rectangle. + g.setColor (new Color (250,240,230)); + g.fillRect ( + (int)(mnHOffset+0.5), + (int)(mnVOffset+0.5), + (int)(mnScale*aScreenSize.getWidth()), + (int)(mnScale*aScreenSize.getHeight())); + // Draw a frame arround the screen rectangle to increase its visibility. + g.setColor (Color.BLACK); + g.drawRect ( + (int)(mnHOffset+0.5), + (int)(mnVOffset+0.5), + (int)(mnScale*aScreenSize.getWidth()), + (int)(mnScale*aScreenSize.getHeight())); + + // Now do the actual display of the accessible object. + drawAccessibleObject (g, mxContext, Color.GREEN); + } + public synchronized void paintChildren (Graphics g) + { + } + public synchronized void paintBorder (Graphics g) + { + } + + + + + /** Draw a simple representation of the given accessible object in the + specified color. + */ + public void drawAccessibleObject (Graphics g, XAccessibleContext xContext, Color aColor) + { + if (xContext != null) + { + // First draw our parent. + XAccessible xParent = xContext.getAccessibleParent(); + if (xParent != null) + drawAccessibleObject (g, xParent.getAccessibleContext(), Color.GRAY); + + // When the context supports the XAccessibleComponent interface + // then draw its outline. + XAccessibleComponent xComponent = + (XAccessibleComponent)UnoRuntime.queryInterface( + XAccessibleComponent.class, xContext); + if (xComponent != null) + { + // Get size and location on screen and transform them to fit + // everything inside this widget. + Point aLocation = xComponent.getLocationOnScreen(); + Size aSize = xComponent.getSize(); + g.setColor (aColor); + g.drawRect ( + (int)(mnHOffset + mnScale*aLocation.X+0.5), + (int)(mnVOffset + mnScale*aLocation.Y+0.5), + (int)(mnScale*aSize.Width), + (int)(mnScale*aSize.Height)); + } + } + } + + + public synchronized void setAccessibleObject (XAccessibleContext xContext) + { + mxContext = xContext; + repaint (); + } + + public synchronized void updateAccessibleObject (XAccessibleContext xContext) + { + repaint (); + } + + + /** Set up the transformation so that the graphical display can show a + centered representation of the whole screen. + */ + private void setupTransformation () + { + Dimension aScreenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension aWidgetSize = getSize(); + if ((aScreenSize.getWidth() > 0) && (aScreenSize.getHeight() > 0)) + { + // Calculate the scales that would map the screen onto the + // widget in both of the coordinate axes and select the smaller + // of the two: it maps the screen onto the widget in both axes + // at the same time. + double nHScale = (aWidgetSize.getWidth() - 10) / aScreenSize.getWidth(); + double nVScale = (aWidgetSize.getHeight() - 10) / aScreenSize.getHeight(); + if (nHScale < nVScale) + mnScale = nHScale; + else + mnScale = nVScale; + + // Calculate offsets that center the scaled screen inside the widget. + mnHOffset = (aWidgetSize.getWidth() - mnScale*aScreenSize.getWidth()) / 2.0; + mnVOffset = (aWidgetSize.getHeight() - mnScale*aScreenSize.getHeight()) / 2.0; + } + else + { + // In case of a degenerate (not yet initialized?) screen size + // use some meaningless default values. + mnScale = 1; + mnHOffset = 0; + mnVOffset = 0; + } + } + + + private XAccessibleContext mxContext; + private double mnScale; + private double mnHOffset; + private double mnVOffset; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/IAccessibleObjectDisplay.java b/odk/examples/DevelopersGuide/Accessibility/IAccessibleObjectDisplay.java new file mode 100644 index 000000000000..5e8eb3a2655c --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/IAccessibleObjectDisplay.java @@ -0,0 +1,46 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.accessibility.XAccessibleContext; + +interface IAccessibleObjectDisplay +{ + + /** Set the accessible object to display. Call this method e.g. when a + new object has been focused. + */ + public void setAccessibleObject (XAccessibleContext xContext); + + public void updateAccessibleObject (XAccessibleContext xContext); +} diff --git a/odk/examples/DevelopersGuide/Accessibility/Makefile b/odk/examples/DevelopersGuide/Accessibility/Makefile new file mode 100644 index 000000000000..6eda8233a326 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/Makefile @@ -0,0 +1,113 @@ +#************************************************************************* +# +# The Contents of this file are made available subject to the terms of +# the BSD license. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Sun Microsystems, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#************************************************************************** + +# Build the simple screen reader (SSR) described in the Developers +# Guide Accessibility chapter. + +PRJ=../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk +include $(SETTINGS)/dk.mk + +# Define non-platform/compiler specific settings +EXAMPLE_NAME=DevGuideAccessibilityExample +OUT_APP_CLASS = $(OUT_CLASS)/$(EXAMPLE_NAME) + +APP1_NAME =SSR +APP1_JAR =$(OUT_APP_CLASS)/$(APP1_NAME).jar + +JAVAFILES = \ + MessageArea.java \ + ConnectionTask.java \ + EventHandler.java \ + EventListenerProxy.java \ + GraphicalDisplay.java \ + NameProvider.java \ + IAccessibleObjectDisplay.java \ + RegistrationThread.java \ + SSR.java \ + TextualDisplay.java + +APP1_CLASSFILES = $(patsubst %.java,$(OUT_APP_CLASS)/%.class,$(JAVAFILES)) +APP1_CLASSNAMES = $(patsubst %.java,%.class,$(JAVAFILES)) \ + EventListenerProxy$(ICL)1.class \ + EventListenerProxy$(ICL)2.class \ + EventListenerProxy$(ICL)3.class \ + EventListenerProxy$(ICL)4.class + +SDK_CLASSPATH = $(subst $(EMPTYSTRING) $(PATH_SEPARATOR),$(PATH_SEPARATOR),$(CLASSPATH)\ + $(PATH_SEPARATOR)$(OUT_APP_CLASS)) + + +# Targets +.PHONY: ALL +ALL : $(EXAMPLE_NAME) + +include $(SETTINGS)/stdtarget.mk + +$(OUT_APP_CLASS)/%.class : %.java + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(OUT_APP_CLASS) $(JAVAFILES) + +$(OUT_APP_CLASS)/%.mf : + -$(MKDIR) $(subst /,$(PS),$(@D)) + @echo Main-Class: com.sun.star.lib.loader.Loader> $@ + $(ECHOLINE)>> $@ + @echo Name: com/sun/star/lib/loader/Loader.class>> $@ + @echo Application-Class: $*>> $@ + +$(APP1_JAR) : $(OUT_APP_CLASS)/$(APP1_NAME).mf $(APP1_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +cd $(subst /,$(PS),$(OUT_APP_CLASS)) && $(SDK_JAR) cvfm $(@F) $(basename $(@F)).mf $(APP1_CLASSNAMES) + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + + +$(EXAMPLE_NAME) : $(APP1_JAR) + @echo -------------------------------------------------------------------------------- + @echo Before you run this example you should start your office with at least a + @echo new empty document and you should have enabled the accessibility support. + @echo Please use the following command to execute the Simple Screen Reader example! + @echo - + @echo $(MAKE) $(APP1_NAME).run + @echo -------------------------------------------------------------------------------- + +%.run: $(OUT_APP_CLASS)/%.jar + $(SDK_JAVA) -Dcom.sun.star.lib.loader.unopath="$(OFFICE_PROGRAM_PATH)" -jar $< + +.PHONY: clean +clean : + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_CLASS)) diff --git a/odk/examples/DevelopersGuide/Accessibility/MessageArea.java b/odk/examples/DevelopersGuide/Accessibility/MessageArea.java new file mode 100644 index 000000000000..9f3280a591a1 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/MessageArea.java @@ -0,0 +1,133 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.Color; +import java.awt.Graphics; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JScrollBar; + + + +/** A message area displays text in a scrollable text widget. It is a + singleton. Other objects can access it directly to display messages. +*/ +public class MessageArea + extends JScrollPane +{ + public static synchronized MessageArea Instance () + { + if (saInstance == null) + saInstance = new MessageArea (); + return saInstance; + } + + + + + /** Create a new message area. This method is private because the class is + a singleton and may therefore not be instanciated from the outside. + */ + private MessageArea () + { + maText = new JTextArea(); + maText.setBackground (new Color (255,250,240)); + maText.setFont (new Font ("Helvetica", Font.PLAIN, 9)); + setViewportView (maText); + setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + printMessage ( + "class path is " + System.getProperty ("java.class.path") + "\n"); + } + + + + + /** Show the given string at the end of the message area and scroll to make + it visible. + */ + public static synchronized void print (String aMessage) + { + Instance().printMessage(aMessage); + } + + + + + /** Show the given string at the end of the message area and scroll to make + it visible. + */ + public static void println (String aMessage) + { + Instance().printMessage (aMessage+"\n"); + } + + + public void paintComponent (Graphics g) + { + // Synchronize with the graphics object to prevent paint problems. + // Remember that this is not done by Swing itself. + synchronized (g) + { + JScrollBar sb = getVerticalScrollBar(); + if (sb != null) + { + int nScrollBarValue = sb.getMaximum() - sb.getVisibleAmount() - 1; + sb.setValue (nScrollBarValue); + } + super.paintComponent (g); + } + } + + + + + /** Append the given string to the end of the text and scroll so that it + becomes visible. This is an internal method. Use one of the static + and public ones. + */ + private synchronized void printMessage (String aMessage) + { + maText.append (aMessage); + } + + + + + private static MessageArea saInstance = null; + private JTextArea maText; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/NameProvider.java b/odk/examples/DevelopersGuide/Accessibility/NameProvider.java new file mode 100644 index 000000000000..9eeba18f83fd --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/NameProvider.java @@ -0,0 +1,290 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.util.HashMap; +import com.sun.star.accessibility.AccessibleStateType; +import com.sun.star.accessibility.AccessibleEventId; +import com.sun.star.accessibility.AccessibleRole; +import com.sun.star.accessibility.AccessibleRelationType; + + +/** Provide names for several accessibility constants groups. +*/ +public class NameProvider +{ + /** Return the name of the specified state. + @param nStateId + Id of the state for which to return its name. This is one of + the ids listed in the <type>AccessibleStateType</const> + constants group. + @return + Returns the name of the specified state or an empty string if an + invalid / unknown state id was given. + */ + public static String getStateName (int nStateId) + { + return (String)maStateMap.get (new Integer(nStateId)); + } + + + /** Return the name of the specified event. + @param nEventId + Id of the event type for which to return its name. This is one + of the ids listed in the <type>AccessibleEventId</const> + constants group. + @return + Returns the name of the specified event type or an empty string + if an invalid / unknown event id was given. + */ + public static String getEventName (int nEventId) + { + return (String)maEventMap.get (new Integer(nEventId)); + } + + + /** Return the name of the specified role. + @param nRole + Id of the role for which to return its name. This is one of + the ids listed in the <type>AccessibleRole</const> + constants group. + @return + Returns the name of the specified role or an empty string if an + invalid / unknown role id was given. + */ + public static String getRoleName (int nRole) + { + return (String)maRoleMap.get (new Integer(nRole)); + } + + + /** Return the name of the specified relation. + @param nRelation + Id of the relation for which to return its name. This is one of + the ids listed in the <type>AccessibleRelationType</const> + constants group. + @return + Returns the name of the specified relation type or an empty + string if an invalid / unknown role id was given. + */ + public static String getRelationName (int nRelation) + { + return (String)maRelationMap.get (new Integer(nRelation)); + } + + + private static HashMap maStateMap = new HashMap(); + private static HashMap maEventMap = new HashMap(); + private static HashMap maRoleMap = new HashMap(); + private static HashMap maRelationMap = new HashMap(); + + static { + maStateMap.put (new Integer (AccessibleStateType.INVALID), "INVALID"); + maStateMap.put (new Integer (AccessibleStateType.ACTIVE), "ACTIVE"); + maStateMap.put (new Integer (AccessibleStateType.ARMED), "ARMED"); + maStateMap.put (new Integer (AccessibleStateType.BUSY), "BUSY"); + maStateMap.put (new Integer (AccessibleStateType.CHECKED), "CHECKED"); + maStateMap.put (new Integer (AccessibleStateType.DEFUNC), "DEFUNC"); + maStateMap.put (new Integer (AccessibleStateType.EDITABLE), "EDITABLE"); + maStateMap.put (new Integer (AccessibleStateType.ENABLED), "ENABLED"); + maStateMap.put (new Integer (AccessibleStateType.EXPANDABLE), "EXPANDABLE"); + maStateMap.put (new Integer (AccessibleStateType.EXPANDED), "EXPANDED"); + maStateMap.put (new Integer (AccessibleStateType.FOCUSABLE), "FOCUSABLE"); + maStateMap.put (new Integer (AccessibleStateType.FOCUSED), "FOCUSED"); + maStateMap.put (new Integer (AccessibleStateType.HORIZONTAL), "HORIZONTAL"); + maStateMap.put (new Integer (AccessibleStateType.ICONIFIED), "ICONIFIED"); + maStateMap.put (new Integer (AccessibleStateType.MODAL), "MODAL"); + maStateMap.put (new Integer (AccessibleStateType.MULTI_LINE), "MULTI_LINE"); + maStateMap.put (new Integer (AccessibleStateType.MULTI_SELECTABLE), "MULTI_SELECTABLE"); + maStateMap.put (new Integer (AccessibleStateType.OPAQUE), "OPAQUE"); + maStateMap.put (new Integer (AccessibleStateType.PRESSED), "PRESSED"); + maStateMap.put (new Integer (AccessibleStateType.RESIZABLE), "RESIZABLE"); + maStateMap.put (new Integer (AccessibleStateType.SELECTABLE), "SELECTABLE"); + maStateMap.put (new Integer (AccessibleStateType.SELECTED), "SELECTED"); + maStateMap.put (new Integer (AccessibleStateType.SENSITIVE), "SENSITIVE"); + maStateMap.put (new Integer (AccessibleStateType.SHOWING), "SHOWING"); + maStateMap.put (new Integer (AccessibleStateType.SINGLE_LINE), "SINGLE_LINE"); + maStateMap.put (new Integer (AccessibleStateType.STALE), "STALE"); + maStateMap.put (new Integer (AccessibleStateType.TRANSIENT), "TRANSIENT"); + maStateMap.put (new Integer (AccessibleStateType.VERTICAL), "VERTICAL"); + maStateMap.put (new Integer (AccessibleStateType.VISIBLE), "VISIBLE"); + maStateMap.put (new Integer (AccessibleStateType.MANAGES_DESCENDANTS), + "MANAGES_DESCENDANTS"); + // maStateMap.put (new Integer (AccessibleStateType.INCONSISTENT),"INCONSISTENT"); + + + maEventMap.put (new Integer (0), + "[UNKNOWN]"); + maEventMap.put (new Integer (AccessibleEventId.NAME_CHANGED), + "NAME_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.DESCRIPTION_CHANGED), + "DESCRIPTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.ACTION_CHANGED), + "ACTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.STATE_CHANGED), + "STATE_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.ACTIVE_DESCENDANT_CHANGED), + "ACTIVE_DESCENDANT_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.BOUNDRECT_CHANGED), + "BOUNDRECT_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CHILD), + "CHILD"); + maEventMap.put (new Integer (AccessibleEventId.INVALIDATE_ALL_CHILDREN), + "INVALIDATE_ALL_CHILDREN"); + maEventMap.put (new Integer (AccessibleEventId.SELECTION_CHANGED), + "SELECTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.VISIBLE_DATA_CHANGED), + "VISIBLE_DATA_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.VALUE_CHANGED), + "VALUE_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CONTENT_FLOWS_FROM_RELATION_CHANGED), + "CONTENT_FLOWS_FROM_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CONTENT_FLOWS_TO_RELATION_CHANGED), + "CONTENT_FLOWS_TO_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CONTROLLED_BY_RELATION_CHANGED), + "CONTROLLED_BY_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CONTROLLER_FOR_RELATION_CHANGED), + "CONTROLLER_FOR_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.LABEL_FOR_RELATION_CHANGED), + "LABEL_FOR_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.LABELED_BY_RELATION_CHANGED), + "LABELED_BY_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.MEMBER_OF_RELATION_CHANGED), + "MEMBER_OF_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.SUB_WINDOW_OF_RELATION_CHANGED), + "SUB_WINDOW_OF_RELATION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.CARET_CHANGED), + "CARET_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TEXT_SELECTION_CHANGED), + "TEXT_SELECTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TEXT_CHANGED), + "TEXT_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TEXT_ATTRIBUTE_CHANGED), + "TEXT_ATTRIBUTE_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.HYPERTEXT_CHANGED), + "HYPERTEXT_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_CAPTION_CHANGED), + "TABLE_CAPTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_COLUMN_DESCRIPTION_CHANGED), + "TABLE_COLUMN_DESCRIPTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_COLUMN_HEADER_CHANGED), + "TABLE_COLUMN_HEADER_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_MODEL_CHANGED), + "TABLE_MODEL_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_ROW_DESCRIPTION_CHANGED), + "TABLE_ROW_DESCRIPTION_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_ROW_HEADER_CHANGED), + "TABLE_ROW_HEADER_CHANGED"); + maEventMap.put (new Integer (AccessibleEventId.TABLE_SUMMARY_CHANGED), + "TABLE_SUMMARY_CHANGED"); + + maRoleMap.put (new Integer(AccessibleRole.UNKNOWN), "UNKNOWN"); + maRoleMap.put (new Integer (AccessibleRole.UNKNOWN), "UNKNOWN"); + maRoleMap.put (new Integer (AccessibleRole.ALERT), "ALERT"); + maRoleMap.put (new Integer (AccessibleRole.COLUMN_HEADER), "COLUMN_HEADER"); + maRoleMap.put (new Integer (AccessibleRole.CANVAS), "CANVAS"); + maRoleMap.put (new Integer (AccessibleRole.CHECK_BOX), "CHECK_BOX"); + maRoleMap.put (new Integer (AccessibleRole.CHECK_MENU_ITEM), "CHECK_MENU_ITEM"); + maRoleMap.put (new Integer (AccessibleRole.COLOR_CHOOSER), "COLOR_CHOOSER"); + maRoleMap.put (new Integer (AccessibleRole.COMBO_BOX), "COMBO_BOX"); + maRoleMap.put (new Integer (AccessibleRole.DESKTOP_ICON), "DESKTOP_ICON"); + maRoleMap.put (new Integer (AccessibleRole.DESKTOP_PANE), "DESKTOP_PANE"); + maRoleMap.put (new Integer (AccessibleRole.DIRECTORY_PANE), "DIRECTORY_PANE"); + maRoleMap.put (new Integer (AccessibleRole.DIALOG), "DIALOG"); + maRoleMap.put (new Integer (AccessibleRole.DOCUMENT), "DOCUMENT"); + maRoleMap.put (new Integer (AccessibleRole.EMBEDDED_OBJECT), "EMBEDDED_OBJECT"); + maRoleMap.put (new Integer (AccessibleRole.END_NOTE), "END_NOTE"); + maRoleMap.put (new Integer (AccessibleRole.FILE_CHOOSER), "FILE_CHOOSER"); + maRoleMap.put (new Integer (AccessibleRole.FILLER), "FILLER"); + maRoleMap.put (new Integer (AccessibleRole.FONT_CHOOSER), "FONT_CHOOSER"); + maRoleMap.put (new Integer (AccessibleRole.FOOTER), "FOOTER"); + maRoleMap.put (new Integer (AccessibleRole.FOOTNOTE), "FOOTNOTE"); + maRoleMap.put (new Integer (AccessibleRole.FRAME), "FRAME"); + maRoleMap.put (new Integer (AccessibleRole.GLASS_PANE), "GLASS_PANE"); + maRoleMap.put (new Integer (AccessibleRole.GRAPHIC), "GRAPHIC"); + maRoleMap.put (new Integer (AccessibleRole.GROUP_BOX), "GROUP_BOX"); + maRoleMap.put (new Integer (AccessibleRole.HEADER), "HEADER"); + maRoleMap.put (new Integer (AccessibleRole.HEADING), "HEADING"); + maRoleMap.put (new Integer (AccessibleRole.HYPER_LINK), "HYPER_LINK"); + maRoleMap.put (new Integer (AccessibleRole.ICON), "ICON"); + maRoleMap.put (new Integer (AccessibleRole.INTERNAL_FRAME), "INTERNAL_FRAME"); + maRoleMap.put (new Integer (AccessibleRole.LABEL), "LABEL"); + maRoleMap.put (new Integer (AccessibleRole.LAYERED_PANE), "LAYERED_PANE"); + maRoleMap.put (new Integer (AccessibleRole.LIST), "LIST"); + maRoleMap.put (new Integer (AccessibleRole.LIST_ITEM), "LIST_ITEM"); + maRoleMap.put (new Integer (AccessibleRole.MENU), "MENU"); + maRoleMap.put (new Integer (AccessibleRole.MENU_BAR), "MENU_BAR"); + maRoleMap.put (new Integer (AccessibleRole.MENU_ITEM), "MENU_ITEM"); + maRoleMap.put (new Integer (AccessibleRole.OPTION_PANE), "OPTION_PANE"); + maRoleMap.put (new Integer (AccessibleRole.PAGE_TAB), "PAGE_TAB"); + maRoleMap.put (new Integer (AccessibleRole.PAGE_TAB_LIST), "PAGE_TAB_LIST"); + maRoleMap.put (new Integer (AccessibleRole.PANEL), "PANEL"); + maRoleMap.put (new Integer (AccessibleRole.PARAGRAPH), "PARAGRAPH"); + maRoleMap.put (new Integer (AccessibleRole.PASSWORD_TEXT), "PASSWORD_TEXT"); + maRoleMap.put (new Integer (AccessibleRole.POPUP_MENU), "POPUP_MENU"); + maRoleMap.put (new Integer (AccessibleRole.PUSH_BUTTON), "PUSH_BUTTON"); + maRoleMap.put (new Integer (AccessibleRole.PROGRESS_BAR), "PROGRESS_BAR"); + maRoleMap.put (new Integer (AccessibleRole.RADIO_BUTTON), "RADIO_BUTTON"); + maRoleMap.put (new Integer (AccessibleRole.RADIO_MENU_ITEM), "RADIO_MENU_ITEM"); + maRoleMap.put (new Integer (AccessibleRole.ROW_HEADER), "ROW_HEADER"); + maRoleMap.put (new Integer (AccessibleRole.ROOT_PANE), "ROOT_PANE"); + maRoleMap.put (new Integer (AccessibleRole.SCROLL_BAR), "SCROLL_BAR"); + maRoleMap.put (new Integer (AccessibleRole.SCROLL_PANE), "SCROLL_PANE"); + maRoleMap.put (new Integer (AccessibleRole.SHAPE), "SHAPE"); + maRoleMap.put (new Integer (AccessibleRole.SEPARATOR), "SEPARATOR"); + maRoleMap.put (new Integer (AccessibleRole.SLIDER), "SLIDER"); + maRoleMap.put (new Integer (AccessibleRole.SPIN_BOX), "SPIN_BOX"); + maRoleMap.put (new Integer (AccessibleRole.SPLIT_PANE), "SPLIT_PANE"); + maRoleMap.put (new Integer (AccessibleRole.STATUS_BAR), "STATUS_BAR"); + maRoleMap.put (new Integer (AccessibleRole.TABLE), "TABLE"); + maRoleMap.put (new Integer (AccessibleRole.TABLE_CELL), "TABLE_CELL"); + maRoleMap.put (new Integer (AccessibleRole.TEXT), "TEXT"); + maRoleMap.put (new Integer (AccessibleRole.TEXT_FRAME), "TEXT_FRAME"); + maRoleMap.put (new Integer (AccessibleRole.TOGGLE_BUTTON), "TOGGLE_BUTTON"); + maRoleMap.put (new Integer (AccessibleRole.TOOL_BAR), "TOOL_BAR"); + maRoleMap.put (new Integer (AccessibleRole.TOOL_TIP), "TOOL_TIP"); + maRoleMap.put (new Integer (AccessibleRole.TREE), "TREE"); + maRoleMap.put (new Integer (AccessibleRole.VIEW_PORT), "VIEW_PORT"); + maRoleMap.put (new Integer (AccessibleRole.WINDOW), "WINDOW"); + + maRelationMap.put (new Integer (AccessibleRelationType.INVALID), "INVALID"); + maRelationMap.put (new Integer (AccessibleRelationType.CONTENT_FLOWS_FROM), "CONTENT_FLOWS_FROM"); + maRelationMap.put (new Integer (AccessibleRelationType.CONTENT_FLOWS_TO), "CONTENT_FLOWS_TO"); + maRelationMap.put (new Integer (AccessibleRelationType.CONTROLLED_BY), "CONTROLLED_BY"); + maRelationMap.put (new Integer (AccessibleRelationType.CONTROLLER_FOR), "CONTROLLER_FOR"); + maRelationMap.put (new Integer (AccessibleRelationType.LABEL_FOR), "LABEL_FOR"); + maRelationMap.put (new Integer (AccessibleRelationType.LABELED_BY), "LABELED_BY"); + maRelationMap.put (new Integer (AccessibleRelationType.MEMBER_OF), "MEMBER_OF"); + maRelationMap.put (new Integer (AccessibleRelationType.SUB_WINDOW_OF), "SUB_WINDOW_OF"); + } +} diff --git a/odk/examples/DevelopersGuide/Accessibility/RegistrationThread.java b/odk/examples/DevelopersGuide/Accessibility/RegistrationThread.java new file mode 100644 index 000000000000..092941b323a7 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/RegistrationThread.java @@ -0,0 +1,156 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.event.ActionListener; +import javax.swing.*; +import java.awt.*; +import java.util.*; + +import com.sun.star.awt.XTopWindowListener; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.accessibility.*; +import com.sun.star.awt.XExtendedToolkit; + +/** This class is used as a thread and registers or unregsiters a listener + given the constructor at all nodes of a tree of accessibility objects. +*/ +public class RegistrationThread + implements Runnable +{ + /** Start a new thread that adds or removes the given listener at all + accessible objects in the sub-tree rooted in the given accessible + object. + @param aListener + The listener that is added or removed. + @param xRoot + The root of the sub-tree of accessibility objects. + @param bRegister + This flag decides whether to add or remove the listener. + */ + public RegistrationThread ( + EventListenerProxy aListener, + XAccessibleContext xRoot, + boolean bRegister, + boolean bShowMessages) + { + maListener = aListener; + mxRoot = xRoot; + mbRegister = bRegister; + mbShowMessages = bShowMessages; + + if (mxRoot != null) + { + if (mbShowMessages) + MessageArea.println ("starting to register at " + mxRoot.getAccessibleName()); + new Thread (this, "RegistrationThread").start(); + } + } + + + + public void run () + { + System.out.println ("starting registration"); + long nNodeCount = traverseTree (mxRoot); + System.out.println ("ending registration"); + if (mbShowMessages) + { + if ( ! mbRegister) + MessageArea.print ("un"); + MessageArea.println ("registered at " + nNodeCount + + " objects in accessibility tree of " + mxRoot.getAccessibleName()); + } + } + + + + + /** Register this object as listener for accessibility events at all nodes + of the given tree. + @param xRoot + The root node of the tree at which to register. + */ + public long traverseTree (XAccessibleContext xRoot) + { + long nNodeCount = 0; + if (xRoot != null) + { + // Register the root node. + XAccessibleEventBroadcaster xBroadcaster = + (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( + XAccessibleEventBroadcaster.class, + xRoot); + if (xBroadcaster != null) + { + if (mbRegister) + xBroadcaster.addEventListener (maListener); + else + xBroadcaster.removeEventListener (maListener); + nNodeCount += 1; + } + + // Call this method recursively to register all sub-trees. + try + { + int nChildCount = xRoot.getAccessibleChildCount(); + for (int i=0; i<nChildCount; i++) + { + XAccessible xChild = xRoot.getAccessibleChild (i); + if (xChild != null) + nNodeCount += traverseTree (xChild.getAccessibleContext()); + } + } + catch (com.sun.star.lang.IndexOutOfBoundsException aException) + { + // The set of children has changed since our last call to + // getAccesibleChildCount(). Don't try any further on this + // sub-tree. + } + catch (com.sun.star.lang.DisposedException aException) + { + // The child has been destroyed since our last call to + // getAccesibleChildCount(). That is OK. Don't try any + // further on this sub-tree. + } + } + return nNodeCount; + } + + private EventListenerProxy maListener; + private XAccessibleContext mxRoot; + private boolean mbRegister; + private boolean mbShowMessages; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/SSR.java b/odk/examples/DevelopersGuide/Accessibility/SSR.java new file mode 100644 index 000000000000..e1830cfa2630 --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/SSR.java @@ -0,0 +1,171 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.event.ActionListener; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; +import javax.swing.*; + + +/** The simple screen reader (SSR) registers at the toolkit as focus listener + and displays information about the currently focused object. +*/ +public class SSR + implements ActionListener +{ + /** Just pass the control to the SSR class. + */ + public static void main (String args[]) + { + new SSR (); + } + + + + + /** Create a new instance of the simple screen reader. + */ + public SSR () + { + Layout (); + + // Create the event handler and tell it where to display information + // about the currently focused accessible object. + maEventHandler = new EventHandler (); + maEventHandler.addObjectDisplay (maTextualDisplay); + maEventHandler.addObjectDisplay (maGraphicalDisplay); + } + + + + + /** Setup the GUI. It is divided into three areas. The lower half is + ocupied by a message area that logs all the events received from + accessibility objects. The upper half is shared by two different + displays of the currently focused object. On left there is a textual + representation. On the right there is a graphical view of the + objects's outline. + */ + private void Layout () + { + GridBagConstraints constraints; + + JPanel aPanel = new JPanel (true); + aPanel.setLayout (new GridBagLayout()); + aPanel.setOpaque (true); + + mFrame = new JFrame ("Simple Screen Reader 0.3"); + mFrame.setContentPane(aPanel); + mFrame.setSize (600,400); + + + addComponent (new JLabel ("Focused Object:"), + 0,0, 1,1, 0,0, GridBagConstraints.WEST, GridBagConstraints.NONE); + + + maTextualDisplay = new TextualDisplay (); + addComponent (maTextualDisplay, + 0,1, 1,1, 1,1, GridBagConstraints.CENTER, GridBagConstraints.BOTH); + + maGraphicalDisplay = new GraphicalDisplay (); + addComponent (maGraphicalDisplay, + 1,0, 1,2, 1,1, GridBagConstraints.CENTER, GridBagConstraints.BOTH); + + addComponent (new JLabel ("Messages:"), + 0,2, 1,1, 0,0, GridBagConstraints.WEST, GridBagConstraints.NONE); + + addComponent (MessageArea.Instance(), + 0,3, 2,1, 1,1, GridBagConstraints.CENTER, GridBagConstraints.BOTH); + + + JButton aButton = new JButton ("Quit SSR"); + addComponent (aButton, + 0,4, 1,1, 0,0, GridBagConstraints.WEST,GridBagConstraints.NONE); + aButton.addActionListener (this); + + mFrame.show(); + } + + + + + /** Add a GUI element with the given constraints to the main window. + */ + private JComponent addComponent (JComponent aComponent, + int x, int y, int width, int height, double weightx, double weighty, + int anchor, int fill) + { + aComponent.setDoubleBuffered (false); + GridBagConstraints aConstraints = new GridBagConstraints(); + aConstraints.gridx = x; + aConstraints.gridy = y; + aConstraints.gridwidth = width; + aConstraints.gridheight = height; + aConstraints.weightx = weightx; + aConstraints.weighty = weighty; + aConstraints.anchor = anchor; + aConstraints.fill = fill; + + mFrame.getContentPane().add (aComponent, aConstraints); + + return aComponent; + } + + + + + /** This call-back handles button presses. + */ + public void actionPerformed (java.awt.event.ActionEvent e) + { + if (e.getActionCommand().equals ("Quit SSR")) + { + maEventHandler.finalize (); + System.exit(0); + } + } + + + /// The main frame that contains all other GUI elements. + private JFrame mFrame; + + /// A textutal representation of the currently focused object. + private TextualDisplay maTextualDisplay; + + /// A graphical representation of the currently focused object. + private GraphicalDisplay maGraphicalDisplay; + + /// The event handler that reacts to all the accessibility events. + private EventHandler maEventHandler; +} diff --git a/odk/examples/DevelopersGuide/Accessibility/TextualDisplay.java b/odk/examples/DevelopersGuide/Accessibility/TextualDisplay.java new file mode 100644 index 000000000000..0d8ce96d978d --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/TextualDisplay.java @@ -0,0 +1,230 @@ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Dimension; +import javax.swing.JTextArea; +import javax.swing.JScrollPane; +import java.util.Vector; + +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.accessibility.XAccessibleComponent; +import com.sun.star.accessibility.XAccessibleStateSet; + +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; + +import com.sun.star.awt.Point; +import com.sun.star.awt.Size; + +/** Display textual information for a given accessible object. This + includes the names of that object of its ancestors as well as some + information retrieved from the XAccessibleContext and + XAccessibleComponent interfaces. +*/ +class TextualDisplay + extends JScrollPane + implements IAccessibleObjectDisplay +{ + /** Create a new scroll pane that contains a text widget which display + information about given accessible objects. + */ + public TextualDisplay () + { + // Create a text widget for displaying the text information... + maText = new JTextArea (80,10); + maText.setBackground (new Color (250,240,230)); + maText.setFont (new Font ("Courier", Font.PLAIN, 11)); + + // ...and set-up the scroll pane to show this widget. + setViewportView (maText); + setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + } + + + + + /** Set the accessible object to display. Call this method e.g. when a + new object has been focused. + */ + public synchronized void setAccessibleObject (XAccessibleContext xContext) + { + // First clear the display area. + msTextContent = new String (); + + if (xContext != null) + { + String sIndentation = showParents (xContext); + showContextInfo (xContext, sIndentation); + showComponentInfo (xContext, sIndentation); + } + + maText.setText (msTextContent); + } + + + + + public synchronized void updateAccessibleObject (XAccessibleContext xContext) + { + setAccessibleObject (xContext); + } + + + + /** Show some of the information available over the given object's + XAccessibleContext interface. + */ + private void showContextInfo (XAccessibleContext xContext, String sIndentation) + { + // Show the description. + msTextContent += sIndentation + "Description: " + + xContext.getAccessibleDescription() + "\n"; + + showStates (xContext, sIndentation); + } + + + + + /** Show a list of all of the the given object's states. Use the + NameConverter class to transform the numerical state ids into human + readable names. + @param xContext + The accessible context for which to show the state names. + */ + private void showStates (XAccessibleContext xContext, String sIndentation) + { + // Get the state set object... + XAccessibleStateSet xStateSet = xContext.getAccessibleStateSet(); + // ...and retrieve an array of numerical ids. + short aStates[] = xStateSet.getStates(); + + // Iterate over the array and print the names of the states. + msTextContent += sIndentation + "States : "; + for (int i=0; i<aStates.length; i++) + { + if (i > 0) + msTextContent += ", "; + msTextContent += NameProvider.getStateName(aStates[i]); + } + msTextContent += "\n"; + } + + + + + /** When the given object supports the XAccessibleComponent interface then + show its size and location on the screen. + */ + private void showComponentInfo (XAccessibleContext xContext, String sIndentation) + { + // Try to cast the given accessible context to the + // XAccessibleComponent interface. + XAccessibleComponent xComponent = + (XAccessibleComponent)UnoRuntime.queryInterface( + XAccessibleComponent.class, xContext); + if (xComponent != null) + { + Point aLocation = xComponent.getLocationOnScreen(); + msTextContent += sIndentation + "Position : " + + aLocation.X + ", " + aLocation.Y + "\n"; + + Size aSize = xComponent.getSize(); + msTextContent += sIndentation + "Size : " + + aSize.Width + ", " + aSize.Height + "\n"; + } + } + + + + + + /** Print the names of the given object and its parents and return an + indentation string that can be used to print further information + about the object. + */ + private String showParents (XAccessibleContext xContext) + { + // Create the path from the given object to its tree's root. + Vector aPathToRoot = new Vector(); + while (xContext != null) + { + aPathToRoot.add (xContext); + // Go up the hierarchy one level to the object's parent. + try + { + XAccessible xParent = xContext.getAccessibleParent(); + if (xParent != null) + xContext = xParent.getAccessibleContext(); + else + xContext = null; + } + catch (Exception e) + { + System.err.println ("caught exception " + e + " while getting path to root"); + } + } + + // Print the path in the accessibility tree from the given context to + // the root. + String sIndentation = new String (); + for (int i=aPathToRoot.size()-1; i>=0; i--) + { + XAccessibleContext xParentContext = (XAccessibleContext)aPathToRoot.get(i); + String sParentName = xParentContext.getAccessibleName(); + if (sParentName.length() == 0) + sParentName = "<unnamed> / Role " + + NameProvider.getRoleName(xParentContext.getAccessibleRole()); + msTextContent += sIndentation + sParentName + "\n"; + sIndentation += msIndentation; + } + + return sIndentation; + } + + + + /// The text widget that is used for the actual text display. + private JTextArea maText; + + /// The indentation with which an object's child is indented. + private final String msIndentation = new String(" "); + + /// The text content displayed by this object. + private String msTextContent = new String (); +} diff --git a/odk/examples/DevelopersGuide/Accessibility/makefile.mk b/odk/examples/DevelopersGuide/Accessibility/makefile.mk new file mode 100644 index 000000000000..5efa8ee709ff --- /dev/null +++ b/odk/examples/DevelopersGuide/Accessibility/makefile.mk @@ -0,0 +1,73 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. +PRJNAME=odk +TARGET=copying + +#---------------------------------------------------------------- +.INCLUDE: settings.mk +.INCLUDE: $(PRJ)$/util$/makefile.pmk +#---------------------------------------------------------------- + +#---------------------------------------------------- +# this makefile is only used for copying the example +# files into the SDK +#---------------------------------------------------- + +ACCESSIBILITY_FILES=\ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/ConnectionTask.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/EventHandler.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/EventListenerProxy.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/GraphicalDisplay.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/IAccessibleObjectDisplay.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/Makefile \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/MessageArea.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/NameProvider.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/RegistrationThread.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/SSR.java \ + $(DESTDIRDEVGUIDEEXAMPLES)$/Accessibility$/TextualDisplay.java + +DIR_FILE_LIST= \ + $(ACCESSIBILITY_FILES) + +DIR_DIRECTORY_LIST=$(uniq $(DIR_FILE_LIST:d)) +DIR_CREATE_FLAG=$(MISC)$/devguide_accessibility_dirs_created.txt +DIR_FILE_FLAG=$(MISC)$/devguide_accessibility.txt + +#-------------------------------------------------- +# TARGETS +#-------------------------------------------------- +all : \ + $(DIR_FILE_LIST) \ + $(DIR_FILE_FLAG) + +#-------------------------------------------------- +# use global rules +#-------------------------------------------------- +.INCLUDE: $(PRJ)$/util$/odk_rules.pmk + |