/****************************************************************************
**
** Implementation of QAccessible and QAccessibleObject classes
**
** Copyright (C) 2000-2008 Trolltech ASA.  All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free Qt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
** included in the packaging of this file.  Licensees holding valid Qt
** Commercial licenses may use this file in accordance with the Qt
** Commercial License Agreement provided with the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/

#include "qaccessible.h"

#if defined(QT_ACCESSIBILITY_SUPPORT)

#include "qptrdict.h"
#include "qmetaobject.h"
#include <private/qpluginmanager_p.h>
#include "qapplication.h"
#include <stdlib.h>

/*!
    \class QAccessible qaccessible.h
    \brief The QAccessible class provides enums and static functions
    relating to accessibility.

    \ingroup misc

    Accessibility clients use implementations of the
    QAccessibleInterface to read the information an accessible object
    exposes, or to call functions to manipulate the accessible object.

\omit
    Qt provides implementations of the QAccessibleInterface for most
    widget classes in a plugin. This plugin is located in the \e
    accessibility subdirectory of the plugins installation directory.
    The default installation directory for plugins is \c INSTALL/plugins,
    where \c INSTALL is the directory where Qt was installed.  Calling
    queryAccessibleInterface( QObject *object, QAccessibleInterface
    **iface ) will ask all plugins located in this directory for an
    implementation that exposes the information for objects of the
    class of \e object.

    To make a Qt application accessible you have to distribute the
    accessibility plugin provded with Qt together with your
    application. Simply add the plugins created in
    INSTALL/plugins/accessibility to your distribution process. Use \l
    QApplication::addLibraryPath() to specify a plugin directory for
    your application, and copy the files into an \e accessibility
    subdirectory of one of those plugin directories. Qt's
    accessibility framework will load the plugins upon request and use
    the implementations provided to expose an object's accessibility
    information.
\endomit

    See the \link plugins-howto.html plugin documentation \endlink for
    more details about how to redistribute Qt plugins.
*/

/*!
    \enum QAccessible::State

    This enum type defines bitflags that can be combined to indicate
    the state of the accessible object. The values are:

    \value Normal
    \value Unavailable
    \value Selected
    \value Focused
    \value Pressed
    \value Checked
    \value Mixed
    \value ReadOnly
    \value HotTracked
    \value Default
    \value Expanded
    \value Collapsed
    \value Busy
    \value Floating
    \value Marqueed
    \value Animated
    \value Invisible
    \value Offscreen
    \value Sizeable
    \value Moveable
    \value SelfVoicing
    \value Focusable
    \value Selectable
    \value Linked
    \value Traversed
    \value MultiSelectable
    \value ExtSelectable
    \value AlertLow
    \value AlertMedium
    \value AlertHigh
    \value Protected
    \value Valid
*/

/*!
    \enum QAccessible::Event

    This enum type defines event types when the state of the
    accessible object has changed. The event types are:

    \value SoundPlayed
    \value Alert
    \value ForegroundChanged
    \value MenuStart
    \value MenuEnd
    \value PopupMenuStart
    \value PopupMenuEnd
    \value ContextHelpStart
    \value ContextHelpEnd
    \value DragDropStart
    \value DragDropEnd
    \value DialogStart
    \value DialogEnd
    \value ScrollingStart
    \value ScrollingEnd
    \value ObjectCreated
    \value ObjectDestroyed
    \value ObjectShow
    \value ObjectHide
    \value ObjectReorder
    \value Focus
    \value Selection
    \value SelectionAdd
    \value SelectionRemove
    \value SelectionWithin
    \value StateChanged
    \value LocationChanged
    \value NameChanged
    \value DescriptionChanged
    \value ValueChanged
    \value ParentChanged
    \value HelpChanged
    \value DefaultActionChanged
    \value AcceleratorChanged
    \value MenuCommand
*/

/*!
    \enum QAccessible::Role

    This enum defines a number of roles an accessible object can have.
    The roles are:

    \value NoRole
    \value TitleBar
    \value MenuBar
    \value ScrollBar
    \value Grip
    \value Sound
    \value Cursor
    \value Caret
    \value AlertMessage
    \value Window
    \value Client
    \value PopupMenu
    \value MenuItem
    \value ToolTip
    \value Application
    \value Document
    \value Pane
    \value Chart
    \value Dialog
    \value Border
    \value Grouping
    \value Separator
    \value ToolBar
    \value StatusBar
    \value Table
    \value ColumnHeader
    \value RowHeader
    \value Column
    \value Row
    \value Cell
    \value Link
    \value HelpBalloon
    \value Character
    \value List
    \value ListItem
    \value Outline
    \value OutlineItem
    \value PageTab
    \value PropertyPage
    \value Indicator
    \value Graphic
    \value StaticText
    \value EditableText
    \value PushButton
    \value CheckBox
    \value RadioButton
    \value ComboBox
    \value DropLest
    \value ProgressBar
    \value Dial
    \value HotkeyField
    \value Slider
    \value SpinBox
    \value Diagram
    \value Animation
    \value Equation
    \value ButtonDropDown
    \value ButtonMenu
    \value ButtonDropGrid
    \value Whitespace
    \value PageTabList
    \value Clock
*/

/*!
    \enum QAccessible::NavDirection

    This enum specifies which item to move to when navigating.

    \value NavUp	    sibling above
    \value NavDown	    sibling below
    \value NavLeft	    left sibling
    \value NavRight	    right sibling
    \value NavNext	    next sibling
    \value NavPrevious	    previous sibling
    \value NavFirstChild    first child
    \value NavLastChild	    last child
    \value NavFocusChild    child with focus
*/

/*!
    \enum QAccessible::Text

    This enum specifies string information that an accessible object
    returns.

    \value Name		    The name of the object
    \value Description	    A short text describing the object
    \value Value	    The value of the object
    \value Help		    A longer text giving information about how
			    to use the object
    \value DefaultAction    The default method to interact with the object
    \value Accelerator	    The keyboard shortcut that executes the
			    default action
*/

/*!
    \fn static void QAccessible::updateAccessibility( QObject *object, int control, Event reason )

    Notifies accessibility clients about a change in \a object's
    accessibility information.

    \a reason specifies the cause of the change, for example,
    ValueChange when the position of a slider has been changed. \a
    control is the ID of the child element that has changed. When \a
    control is 0, the object itself has changed.

    Call this function whenever the state of your accessible object or
    one of it's sub-elements has been changed either programmatically
    (e.g. by calling QLabel::setText()) or by user interaction.

    If there are no accessibility tools listening to this event, the
    performance penalty for calling this function is minor, but if determining
    the parameters of the call is expensive you can use isActive() to
    avoid unnecessary performance penalties if no client is listening.
*/

static QPluginManager<QAccessibleFactoryInterface> *qAccessibleManager = 0;

class AccessibleCache : public QObject, public QPtrDict<QAccessibleInterface>
{
    Q_OBJECT
public:
    AccessibleCache()
        : QPtrDict<QAccessibleInterface>(73)
    {
    }

    void addObject(QObject *object, QAccessibleInterface *iface)
    {
        insert(object, iface);
        connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(removeObject(QObject*)));
    }

public slots:
    void removeObject(QObject *object);
};

#include "qaccessible.moc"

static AccessibleCache *qAccessibleInterface = 0;
static bool cleanupAdded = FALSE;

static void qAccessibleCleanup()
{
    if ( qAccessibleInterface && qAccessibleInterface->count() && qAccessibleManager )
	qAccessibleManager->setAutoUnload( FALSE );

    delete qAccessibleInterface;
    qAccessibleInterface = 0;
    delete qAccessibleManager;
    qAccessibleManager = 0;
}

#ifdef Q_WS_MAC
QObject *QAccessible::queryAccessibleObject(QAccessibleInterface *o)
{
    if(qAccessibleInterface) {
	for(QPtrDictIterator<QAccessibleInterface> it(*qAccessibleInterface); it.current(); ++it) {
	    if(it.current() == o)
		return (QObject*)it.currentKey();
	}
    }
    return NULL;
}
#endif

void AccessibleCache::removeObject(QObject *object)
{
    if (!object)
        return;

    remove(object);
    if (!count()) {
        delete this;
        qAccessibleInterface = 0;
    }
}


/*!
    Sets \a iface to point to the implementation of the
    QAccessibleInterface for \a object, and returns \c QS_OK if
    successfull, or sets \a iface to 0 and returns \c QE_NOCOMPONENT if
    no accessibility implementation for \a object exists.

    The function uses the \link QObject::className() classname
    \endlink of \a object to find a suitable implementation. If no
    implementation for the object's class is available the function
    tries to find an implementation for the object's parent class.

    This function is called to answer an accessibility client's
    request for object information. You should never need to call this
    function yourself.
*/
QRESULT QAccessible::queryAccessibleInterface( QObject *object, QAccessibleInterface **iface )
{
    *iface = 0;
    if ( !object )
	return QE_INVALIDARG;

    if ( qAccessibleInterface ) {
	*iface = qAccessibleInterface->find( object );
	if ( *iface ) {
	    (*iface)->addRef();
	    return QS_OK;
	}
    }

    if ( !qAccessibleManager ) {
	qAccessibleManager = new QPluginManager<QAccessibleFactoryInterface>( IID_QAccessibleFactory, QApplication::libraryPaths(), "/accessible" );
	if ( !cleanupAdded ) {
	    qAddPostRoutine( qAccessibleCleanup );
	    cleanupAdded = TRUE;
	}
    }

    QInterfacePtr<QAccessibleFactoryInterface> factory = 0;
    QMetaObject *mo = object->metaObject();
    while ( mo ) {
	qAccessibleManager->queryInterface( mo->className(), &factory );
	if ( factory )
	    break;
	mo = mo->superClass();
    }
    if ( factory )
	return factory->createAccessibleInterface( mo->className(), object, iface );

    return QE_NOCOMPONENT;
}

/*!
    Returns TRUE if an accessibility implementation has been requested,
    during the runtime of the application, otherwise returns FALSE. 
    
    Use this function to prevent potentially expensive notifications via
    updateAccessibility().

    \omit
    QListView uses this function to prevent index-lookups for item based
    notifications.
    \endomit
*/
bool QAccessible::isActive()
{
    return qAccessibleManager != 0;
}

/*!
    \class QAccessibleInterface qaccessible.h
    \brief The QAccessibleInterface class defines an interface that exposes information about accessible objects.

    \ingroup misc
*/

/*!
    \fn bool QAccessibleInterface::isValid() const

    Returns TRUE if all the data necessary to use this interface
    implementation is valid (e.g. all pointers are non-null),
    otherwise returns FALSE.
*/

/*!
    \fn int QAccessibleInterface::childCount() const

    Returns the number of children that belong to this object. A child
    can provide accessibility information on it's own (e.g. a child
    widget), or be a sub-element of this accessible object.

    All objects provide this information.

    \sa queryChild()
*/

/*!
    \fn QRESULT QAccessibleInterface::queryChild( int control, QAccessibleInterface **iface ) const

    Sets \a iface to point to the implementation of the
    QAccessibleInterface for the child specified with \a control. If
    the child doesn't provide accessibility information on it's own,
    the value of \a iface is set to 0. For those elements, this
    object is responsible for exposing the child's properties.

    All objects provide this information.

    \sa childCount(), queryParent()
*/

/*!
    \fn QRESULT QAccessibleInterface::queryParent( QAccessibleInterface **iface ) const

    Sets \a iface to point to the implementation of the
    QAccessibleInterface for the parent object, or to 0 if there is
    no such implementation or object.

    All objects provide this information.

    \sa queryChild()
*/

/*!
    \fn int QAccessibleInterface::controlAt( int x, int y ) const

    Returns the ID of the child that contains the screen coordinates
    (\a x, \a y). This function returns 0 if the point is positioned
    on the object itself. If the tested point is outside the
    boundaries of the object this function returns -1.

    All visual objects provide this information.
*/

/*!
    \fn QRect QAccessibleInterface::rect( int control ) const

    Returns the location of the child specified with \a control in
    screen coordinates. This function returns the location of the
    object itself if \a control is 0.

    All visual objects provide this information.
*/

/*!
    \fn int QAccessibleInterface::navigate( NavDirection direction, int startControl ) const

    This function traverses to another object, or to a sub-element of
    the current object. \a direction specifies in which direction to
    navigate, and \a startControl specifies the start point of the
    navigation, which is either 0 if the navigation starts at the
    object itself, or an ID of one of the object's sub-elements.

    The function returns the ID of the sub-element located in the \a
    direction specified. If there is nothing in the navigated \a
    direction, this function returns -1.

    All objects support navigation.
*/

/*!
    \fn QString QAccessibleInterface::text( Text t, int control ) const

    Returns a string property \a t of the child object specified by \a
    control, or the string property of the object itself if \a control
    is 0.

    The \e Name is a string used by clients to identify, find or
    announce an accessible object for the user. All objects must have
    a name that is unique within their container.

    An accessible object's \e Description provides textual information
    about an object's visual appearance. The description is primarily
    used to provide greater context for low-vision or blind users, but
    is also used for context searching or other applications. Not all
    objects have a description. An "OK" button would not need a
    description, but a toolbutton that shows a picture of a smiley
    would.

    The \e Value of an accessible object represents visual information
    contained by the object, e.g. the text in a line edit. Usually,
    the value can be modified by the user. Not all objects have a
    value, e.g. static text labels don't, and some objects have a
    state that already is the value, e.g. toggle buttons.

    The \e Help text provides information about the function and
    usage of an accessible object. Not all objects provide this
    information.

    An accessible object's \e DefaultAction describes the object's
    primary method of manipulation, and should be a verb or a short
    phrase, e.g. "Press" for a button.

    The accelerator is a keyboard shortcut that activates the default
    action of the object. A keyboard shortcut is the underlined
    character in the text of a menu, menu item or control, and is
    either the character itself, or a combination of this character
    and a modifier key like ALT, CTRL or SHIFT. Command controls like
    tool buttons also have shortcut keys and usually display them in
    their tooltip.

    \sa role(), state(), selection()
*/

/*!
    \fn void QAccessibleInterface::setText( Text t, int control, const QString &text )

    Sets the text property \a t of the child object \a control to \a
    text. If \a control is 0, the text property of the object itself
    is set.
*/

/*!
    \fn QAccessible::Role QAccessibleInterface::role( int control ) const

    Returns the role of the object if \a control is 0, or the role of
    the object's sub-element with ID \a control. The role of an object
    is usually static. All accessible objects have a role.

    \sa text(), state(), selection()
*/

/*!
    \fn QAccessible::State QAccessibleInterface::state( int control ) const

    Returns the current state of the object if \a control is 0, or the
    state of the object's sub-element element with ID \a control. All
    objects have a state.

    \sa text(), role(), selection()
*/

/*!
    \fn QMemArray<int> QAccessibleInterface::selection() const

    Returns the list of all the element IDs that are selected.

    \sa text(), role(), state()
*/

/*!
    \fn bool QAccessibleInterface::doDefaultAction( int control )

    Calling this function performs the default action of the child
    object specified by \a control, or the default action of the
    object itself if \a control is 0.
*/

/*!
    \fn bool QAccessibleInterface::setFocus( int control )

    Gives the focus to the child object specified by \a control, or to
    the object itself if \a control is 0.

    Returns TRUE if the focus could be set; otherwise returns FALSE.
*/

/*!
    \fn bool QAccessibleInterface::setSelected( int control, bool on, bool extend )

    Sets the selection of the child object with ID \a control to \a
    on. If \a extend is TRUE, all child elements between the focused
    item and the specified child object have their selection set to \a
    on.

    Returns TRUE if the selection could be set; otherwise returns
    FALSE.

    \sa setFocus(), clearSelection()
*/

/*!
    \fn void QAccessibleInterface::clearSelection()

    Removes any selection from the object.

    \sa setSelected()
*/



/*!
    \class QAccessibleObject qaccessible.h
    \brief The QAccessibleObject class implements parts of the
    QAccessibleInterface for QObjects.

    \ingroup misc

    This class is mainly provided for convenience. All subclasses of
    the QAccessibleInterface should use this class as the base class.
*/

/*!
    Creates a QAccessibleObject for \a object.
*/
QAccessibleObject::QAccessibleObject( QObject *object )
: object_(object)
{
    if ( !qAccessibleInterface ) {
	qAccessibleInterface = new AccessibleCache;
	if ( !cleanupAdded ) {
	    qAddPostRoutine( qAccessibleCleanup );
	    cleanupAdded = TRUE;
	}
    }

    qAccessibleInterface->addObject(object, this);
}

/*!
    Destroys the QAccessibleObject.

    This only happens when a call to release() decrements the internal
    reference counter to zero.
*/
QAccessibleObject::~QAccessibleObject()
{
    if ( qAccessibleInterface ) {
	qAccessibleInterface->removeObject(object_);
	if ( !qAccessibleInterface->count() ) {
	    delete qAccessibleInterface;
	    qAccessibleInterface = 0;
	}
    }
}

/*!
    \reimp
*/
QRESULT QAccessibleObject::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
{
    *iface = 0;
    if ( uuid == IID_QAccessible )
	*iface = (QAccessibleInterface*)this;
    else if ( uuid == IID_QUnknown )
	*iface = (QUnknownInterface*)this;
    else
	return QE_NOINTERFACE;

    (*iface)->addRef();
    return QS_OK;
}

/*!
    Returns the QObject for which this QAccessibleInterface
    implementation provides information. Use isValid() to make sure
    the object pointer is safe to use.
*/
QObject *QAccessibleObject::object() const
{
#if defined(QT_CHECK_RANGE)
    if ( !isValid() )
	qWarning( "QAccessibleInterface is invalid. Crash pending..." );
#endif
    return object_;
}

/*!
    \reimp
*/
bool QAccessibleObject::isValid() const
{
    return !object_.isNull();
}

#endif